Предыстория:
... в одном проекте (как всегда, я - о НЕтривиальныхЪ эмбеддедЪ системахЪ) понадобилось написать свой "класс" двухсвязного списка.
Написали.
Достаточно долго Использовали.
Всё было хорошо.
...
Пока, однажды, не уволился автор, написавший этот "класс"...
...А на его место, "на поддержку и сопровождение", не пришёл молодой программист.
Но - смышлёный и способный (без сарказма говорю!).
...
Далее - пойдёт не в духе "работает? НЕ ТРОГАЙ!".
Короче.
Первоначальным толчком к "лазанью и копанию в коде", послужила инициатива по "оптимизации".
Кому-то запала идея, что можно "ещё чуток" ускорить работу кода, использующего упомянутые двухсвязные списки, если принять во внимание, что, в большинстве случаев, не надо "всякие там предусловия проверять". Типа - программисты же - не совсем дурачки и не будут в качестве "this" NULL в "метод" списка подсовывать... Или удалять элемент NULL из списка...
...Или удалять уже ранее удалённый элемент...
Ведь - правда же?
...
Короче, ПРЕДУСЛОВИЯ были в "методах" этого "класса" двухсвязного списка пересмотрены ОЧЕНЬ ТЩАТЕЛЬНО.
... И честно проверены не одной парой глаз...
... и "на пальцах" "мозговым штурмом" совместным обсуждением утверждена правильность логики работы каждого из "методов"...

А тесты стали выдавать "непрохождение".

Что вызвало некоторое замешательство у народа. Типа, "где там можно было напортачить"?

Естественно, что головы всех работников повернулись одновременно в сторону нового сотрудника и все дружно и хором спросили: "Ты шо-то менял в предусловиях и основной логике методов?"
Тот, естественно (и - ЧЕСТНО!) ответил: "НЕТ!"

Не поверили.

Стали в шесть пар глаз на проекционном экране смотреть и, чуть ли, не пальцем по строчкам водить и вслух хором прочитывать строки кода и, останавливаясь, переглядываясь и хором утверждаясь в верности понятого, убеждаться, что "всё правильно".
Далее, не смотря на то, что diff, В ЭТИХ ЧАСТЯХ МЕТОДОВ, никаких расхождений не нашёл (а в возвращаемых результатах методов И ТАК ВСЁ ОЧЕВИДНО(sic!!!)), прогнали сборку и запуск тестов.

Тесты не прошли.

Все хором почесали затылки и уставились на список соответствия ожидаемых и фактических результатов в тестах.

И тут меня, как "торкнуло". Я смотрю на код и спрашиваю: "А почему ты возвращаемые значения (логического типа) поменял в некоторых "методах" на противоположные?"
Человек отвечает: "Дык - неправильно же по смыслу было!"
"- Почему?! Объясняй."

И тут выяснилось полное соответствие одному из законов Мерфи. То есть, когда уже кажется, что всё разжёвано до конца и ничего не может быть понято НЕ ВЕРНО, обязательно найдётся хотя бы один и работников, кто поймёт всё совершенно не так.

Проиллюстрирую на примере операций добавления и удаления элемента в/из списка.

Все операции возвращали булевское значение, как успех/неуспех операции. То есть, если элемент успешно добавлялся/удалялся в/из списка - истина, если что-то пошло не так - ложь.
Что могло помешать успешности? Понятно, что проверялись аргументы (список и указатель на элемент - на непустоту). Кроме того, была ещё проверка на уже содержание данного элемента в данном списке. Это было "место изменения сознания" номер раз.
При удалении элемента - так же - проверялись аргументы и НАЛИЧИЕ этого элемента в данном списке. Это было место номер два.
В указанных двух местах человек поменял значение возвращаемого логического значения на противоположное.

То есть, автор первоначального варианта методов списка и молодой программист подразумевали РАЗНЫЙ СМЫСЛ УСПЕШНОСТИ ВЫПОЛНЕНИЯ ОПЕРАЦИЙ:

На добавлении элемента в список:
Автор: элемент, который пытаются добавить в список - уже содержится в нём. Значит, была какая-то ошибка во внешнем коде, потому, что такого случиться не должно было (там есть метод для проверки принадлежности элементам списка, его нужно было использовать) - ВОЗВРАТИТЬ "ЛОЖЬ"!
Молодой программист: элемент, который пытаются добавить в список - уже содержится в нём - ВОЗВРАТИТЬ "ИСТИНА"!

На удалении элемента из списка:
Автор: элемент, который пытаются удалить из списка, не содержится в нём. Значит, была какая-то ошибка во внешнем коде, потому, что такого случиться не должно было (там есть метод для проверки принадлежности элементам списка, его нужно было использовать) - ВОЗВРАТИТЬ "ЛОЖЬ"!
Молодой программист: элемент, который пытаются удалить из списка, не содержится в нём. Значит, работа уже сделана - ВОЗВРАТИТЬ "ИСТИНА"!

То есть Автор списка подразумевал "расширенное состояние" не только списка, а молодой программист размышлял об успешности исполнения конкретной операции для данного элемента.

А - действительно, КУДА включать проверку того, содержит ли данный список данный объект?
Вызывать снаружи?
Или - организовывать в виде части предусловия внутри метода списка?
Или такой выбор - таки - будет частью проектного решения для конкретной системы?

Как вы думаете?

(Меня не интересует конкретность реализаций в разных системах и библиотеках, используемых вами в ваших программах! Меня интересует, как бы ВЫ решили эту "маленькую и незначительную проблемку"?)