1. Математика - гимнастика ума.
Как ни крути, но программирование - это математика. Не та математика, где диффуры и прочие пространства Минковского, а вполне себе простая описательная математика функций преобразования одного в другое. Умные люди придумали такое понятие, как "Дискретная математика", которая рассматривает графы и логические утверждения, которые обозваны в ней "Дискретными структурами". Графы - это всего лишь узлы и связи между ними. Они не так часто используются в "обычном" программировании, как логические утверждения, но тоже имеют место быть. Графы имеют несколько видов, для них существует целый класс алгоритмов, позволяющий найти какие-то оптимальные значения связей между узлами, упорядочить их и всякое такое прочее - о них мы тут говорить не будем. А вот о логических утверждениях стоит поговорить более развернуто.
1.1. Логика - раздел математики.
Про логику в научных журналах одним из первых начал писать еще Аристотель, а все программирование, по большому счету, - это присваивание и ветвление. Вот как раз логику программисту знать необходимо.
Итак, просто вспомнить заради приведу тут основные логические операторы и законы:
И - логическое умножение. Приоритет высокий.
ИЛИ - логическое сложение. Приоритет низкий.
НЕ - отрицание. Приоритет высочайший.
В выражении "А = Б И Ц ИЛИ Д И НЕ Ж" сначала будет вычислено "НЕ Ж", за ним все "И", и уже после, в самом конце, будет вычислено "ИЛИ".
Также существуют логические преобразования, которые помогут вам упрощать логические выражения. Они исходят из законов логики, сформулированных на заре цивилизации.
Законы логики.
1. Никакое высказывание не может быть истинным и ложным одновременно.
Тут все просто: выражение "Х = 1 И Х <> 1" всегда ложно.
2. Любое высказывание или истинно, или ложно - третьего не дано.
Ну с этим все должно быть ясно. При этом основные ошибки в программировании кроются как раз в сложных логических выражениях, которые или истины, или ложны но разработчик не знает, когда они истинны, а когда - ложны. Они просто сложны для него, )))
3. Утверждение истинно, а контрутверждение ложно.
Тут тоже все достаточно просто: "(А = Б) = НЕ (А <> Б)".
4. Силлогизм.
Классика: "Всякий человек смертен. Сократ - человек, следовательно он смертен". Примитивный пример может быть таким: "(А = Б И Б = Ц) = (А = Ц)".
Исходя из этих законов существуют преобразования логических выражений (не забываем про приоритеты):
НЕ (А ИЛИ Б) = НЕ А И НЕ Б
НЕ (А И Б) = НЕ А ИЛИ НЕ Б
А И (Б ИЛИ Ц) = А И Б ИЛИ А И Ц
А ИЛИ Б И Ц = (А ИЛИ Б) И (А ИЛИ Ц)
А ИЛИ А И Б = А
А И (А ИЛИ Б) = А
Интереса заради можно разобрать такое вот выражение, приведенное в этой вот публикации.
((ПН И ПНП) И (РН И РНП)) ИЛИ (( ПН = Ложь ) И (РН И РНП)) ИЛИ ((ПН И ПНП) И (РН = Ложь))
Преобразуем это выражение, убрав константы:
(А И Б) И (Ц И Д) ИЛИ НЕ Ц И (А И Б) ИЛИ НЕ А И (Ц И Д)
Тут условие будет истинным в следующих случаях: 1. А = Б = Ц = Д = ИСТИНА. 2. А или Ц = ЛОЖЬ, Б = Д = ИСТИНА. При том А может быть ЛОЖЬ только тогда, когда Ц = Д = ИСТИНА, а Ц может быть ЛОЖЬ только когда А = Б = ИСТИНА.
Отсюда можно сделать вывод, что если А И Б = ИСТИНА, то нас не интересует Ц И Д, и, соответственно, наоборот. Отсюда прямо следует, что данное условие эквивалентно следующему:
(А ИЛИ Ц) И (А И Б ИЛИ Ц И Д)
Какая логика преобразований тут использовалась? Из первоначального условия ясно, что (А И Б) И (Ц И Д) - это основное условие, при этом если А ИЛИ Ц неистинны, то для А становится бессмысленно Б, а для Ц - Д. В итоге у нас должно быть истинным одно из А или Ц. Так и запишем: А ИЛИ Ц. А дальше уже мы можем А И Б логически сложить с Ц И Д, т.к. у нас или А, или Ц истинно. При ложности А будет проверяться только истинность Ц и Д, а для ложности Ц - только А и Б. Если А и Ц ложны, то и само условие тоже будет ложно.
2. Принципы древних.
В комментариях к уже приведенной статье я отметил, что древние люди сформулировали достаточное число принципов, которые могут быть применены и к программированию тоже. Давайте пройдемся по ним.
2.1. Не стоит плодить сущности без необходимости
Данный принцип сформулировал Уильям Оккам, живший в XIII-XIV веках. Суть его в том, что если что-то можно объяснить без привлечения дополнительных сущностей, то привлекать эти сущности не нужно. Истоки же редуцирования (т.е. минимизации и упрощения) в логике сокрыты во глубине веков, а бритву и Оккама первым, если мне не изменяет память, скрестил Лейбниц (в действительности он не Оккама с ней скрестил, а номинализм, "протагонистом" которого был Оккам).
Давайте соотнесем это с программированием. В данном случае суть проста: не нужно делать лишнего. Т.е. лишних переменных, функций, процедур, действий. Лишнее обычно образуется не из задачи, как таковой, а из подзадачи, когда локальный творец не видит всего творения. Избежать лишних сущностей позволит хорошо проработанная архитектура решения. Исходя прямо из формулировки принципа, можно определить, что система, содержащая минимальное достаточное количество элементов будет лучше системы, в которой элементов будет больше.
При этом нужно понимать, что качели эффективности программного кода могут прямо зависеть от количества сущностей. И минимальное их количество может быть неэффективным, Например, если попытаться снизить количество потребляемой памяти, то время разработки и зачастую производительность такого экономного по памяти решения будут обычно хуже, чем у решения, не особо ограничивающего использование памяти, например, для кеширования часто используемых значений. Также запрос в цикле, обрабатывающий по одному элементу данных, будет обычно хуже, чем обработка массовой выборки (если, конечно, вы не обрабатываете только один элемент).
Но в большинстве других случаев стоит разобраться, нужны ли нам те или иные переменные, функции, процедуры, модули, документы, регистры, справочники, ПВХ или иные какие объекты. Следует стараться использовать уже имеющееся, и если этого действительно не хватает для реализации задачи, плодить новую сущность, предварительно посоветовавшись с архитектором (скрам с его покером планирования тут однозначно рулит).
2.2 Лучшее - враг хорошего.
Данный принцип любит употреблять некий В.В.Шахиджанян. И он тут вполне прав, т.к. нет пределу совершенству. Есть мнение, что люди, сидящие на сайтах знакомств так привыкают к тому, что найдется что-то лучше, что не особо хранят имеющиеся отношения, предполагая, что всегда найдется как минимум не хуже. И в этом что-то есть!
Если говорить о программировании, то этот принцип призывает к балансу сущностей без необходимости и работающего решения. Можно сколь угодно долго сокращать логическое выражение, но если оно работает, то не стоит грызть землю в поисках лучшего варианта - его может и не быть, кстати.
Отсюда как бы мораль: если есть работающий без ошибок механизм - не стоит перерабатывать его только исходя из понимания, что можно сделать лучше. Т.е. любя работающая программа лучше идеального ее проекта. Да, тезис спорный, но в ситуации быстрой разработки он оправдан.
2.3. Все гениальное - просто.
Так Йозеф Геббельс перефразировал слова Леонардо да Винчи. И если выкинуть из объяснения чего-либо все лишнее, то получится как раз простое и достаточное этого чего-либо объяснение. Другими словами, это предельный вариант принципа Оккама.
С точки зрения программирования, данный принцип должен сдерживать сложность, нарастающую в ходе проекта по созданию программного продукта. Если сложность получающейся системы высокая, то где-то у разработчиков проблемы. Сложность - это, фактически, совокупность возможных связей между компонентами системы. Понятно, что чем больше компонентов в системе, тем больше возможных связей между ними может быть образовано. Для достижения гениальности нужно и уменьшать количество компонетов, и пресекать лишние между ними связи.
2.4. Глаза боятся - руки делают.
В словаре народной фразеологии данное понятие отражено весьма полно:
Не надо слишком драматично воспринимать предстоящую работу, преувеличивать ее трудность: как бы тяжело ни казалось, если постоянно что-то делать - результат обязательно приходит. Выражение часто употребляется как самоутешение или при желании приободрить других.
Для разработчиков программного обеспечения данное выражение должно быть крайне полезно, т.к. сложность, с которой приходится работать, бывает весьма высока. Это как раз следствие того, что большинство программных продуктов (особенно на 1С) не представляют из себя образчиков гениальности - в них полно лишних сущностей, но это цена компромисса между работающим ПО и сферическим в вакууме ТЗ, которое никто и никогда не будет писать.
3. Мораль.
Исходя из вышесказанного могу подытожить следующим образом:
1. Разработчик должен знать о том, что логические выражения можно и нужно преобразовать так, чтобы в них не было ничего лишнего - ведь логические выражения - это и есть программирование. И если разработчик не может этого сделать, то пусть идет учиться не на очередной сертификат, а на курс логики.
2. Разработчик не должен придумывать кучу регистров, справочников, их реквизитов и прочего для решения своей задачи, если только задача не может быть решена без этого. И лучше подумать вместе с архитектором о том, как этого избежать. А если избежать не получается, то подумать и о том, как это можно будет использовать в будущих задачах.
3. Не стоит тратить множество времени на идеальное ТЗ - оно все равно скорее всего не будет идеальным, но полностью отказываться от раздумий на тему того, как это сделать, тоже не стоит.
4. Не стоит усложнять задачу. Иногда, если отвлечься, приходит неплохое и достаточно простое решение.
5. Не стоит уходить в шатдаун, испытывая сложность с пониманием задачи. Иногда просто начало работы над ней уже помогает включить мозг. И не стоит забывать о том, что сложные моменты в ходе отладки могут упрощаться.