"Нужно ли выражать в коде его проектные требования (контракты) и
как лучше всего это делать ?"
Ответ на вопрос кажется очевидным — нужно.
Например, для примитивов синхронизации, таких как критические секции,
делаются вещи вроде scoped_guard, заставляющие клиента автоматически
соблюдать соответствующие принципы захвата-освобождения (RAII).
А как быть, когда классы имеют нетривиальную семантику использования,
когда имеют зависимости от результатов работы других классов или
когда их корректное применение вообще допустимо в некотором сильно
ограниченном диапазоне сценариев ?
Приведу реальный пример.
У меня есть набор классов для обработки некоторой базы данных, причем эти
классы спроектированы с расчетом на использование в многопроцессорных системах.
Каждый поток выполняет свою ветку обработки, выбирая задания из специального
кругового буфера, один раз за круг потоки синхронизируются барьером и
происходит общая обработка информации, либо выход из цикла.
Несмотря на то, что программный интерфейс отдельно взятого класса простой,
на их совместное использование налагается много неочевидных ограничений — в
круговом буфере должно быть столько же задач-барьеров, сколько рабочих потоков,
доступ к общим данным можно делать только из callback-обработчика, который
срабатывает каждый раз при наполнении барьера потоками, и так далее.
Как наилучшим образом выразить данные требования в коде, сохраняя ясность и
не теряя в эффективности ?