Как писать код? Технологии древних цивилизаций, или все новое — это хорошо забытое старое

Все современные технологии — это развитие и доведение до ума (или маразма) древних идей. За последнее время не придумали ничего нового — все, что мы видим, было придумано тысячи лет назад. Не является исключением и программирование, которое в сути своей является переводом с языка условностей технического задания или заявки пользователя в формализованный и абсолютно точный язык математической логики. А логику придумали (по крайней мере первыми опубликовались в ведущих научных журналах) еще древние греки.

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. Не стоит уходить в шатдаун, испытывая сложность с пониманием задачи. Иногда просто начало работы над ней уже помогает включить мозг. И не стоит забывать о том, что сложные моменты в ходе отладки могут упрощаться. 

43 Comments

  1. gubanoff

    (0) Всегда рекомендую читать классику — «Совершенный код» С. Макконнелл. Там написано все и подробно.

    Не хочется обижать авторов статей, но они освещают только малый процент того, что есть в «совершенном коде».

    Reply
  2. starik-2005

    (1) так я, например, постоянно предлагаю Макконнелла читать всем и каждому. Моя статья тут совершенно о другом — о том, что нужно знать программисту, чтобы вообще иметь возможность писать программы. Ну и о том, что совершенного кода написано не так много, что лучше написать не такой совершенный, но работающий код, чем не написать никакого кода )))

    Reply
  3. pm74

    Отсюда прямо следует, что данное условие эквивалентно следующему:

    (А ИЛИ Ц) И (А И Б ИЛИ Ц И Д)

    ну неправильно же , исправьтесь

    (А И Б) И (Ц И Д) ИЛИ НЕ Ц И (А И Б) ИЛИ НЕ А И (Ц И Д)

    и

    (А ИЛИ Ц) И (А И Б ИЛИ Ц И Д)

    не эквивалентны

    Reply
  4. starik-2005

    (3) не эквивалентны в двух случаях из 16-ти. Может Вы предложите, как сократить это выражение?

    Reply
  5. pm74

    (4) ну например

    Ц И Д И (НЕ А ИЛИ Б) ИЛИ НЕ Ц И А И Б

    или

    (НЕ Ц ИЛИ Д) И (НЕ А ИЛИ Б) И (Ц И Д ИЛИ А И Б)

    наверняка есть и получше варианты

    Reply
  6. pm74

    Просто оставлю здесь

    ВЫБРАТЬ
    ИСТИНА КАК БУЛЕВО
    ПОМЕСТИТЬ ИСТИНАЛОЖЬ
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ
    ЛОЖЬ
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ИСТИНАЛОЖЬ.БУЛЕВО КАК А,
    ИСТИНАЛОЖЬ2.БУЛЕВО КАК Б,
    ИСТИНАЛОЖЬ3.БУЛЕВО КАК Ц,
    ИСТИНАЛОЖЬ4.БУЛЕВО КАК Д
    ПОМЕСТИТЬ СОЧЕТАНИЯ
    ИЗ
    ИСТИНАЛОЖЬ КАК ИСТИНАЛОЖЬ,
    ИСТИНАЛОЖЬ КАК ИСТИНАЛОЖЬ2,
    ИСТИНАЛОЖЬ КАК ИСТИНАЛОЖЬ3,
    ИСТИНАЛОЖЬ КАК ИСТИНАЛОЖЬ4
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    А,Б,Ц,Д,
    ((А И Б) И (Ц И Д)) ИЛИ  (( А = Ложь ) И (Ц И Д)) ИЛИ ((А И Б) И (Ц = Ложь)) КАК Шаблон,
    (А И Б) И (Ц И Д) ИЛИ НЕ Ц И (А И Б) ИЛИ НЕ А И (Ц И Д) КАК Выражение1,
    (А ИЛИ Ц) И (А И Б ИЛИ Ц И Д) КАК Выражение2,
    Ц И Д  И (НЕ А ИЛИ Б) ИЛИ НЕ Ц И А И Б  КАК Выражение3
    ПОМЕСТИТЬ ПРОВЕРКА
    ИЗ
    СОЧЕТАНИЯ КАК С
    ;
    ВЫБРАТЬ
    А,Б,Ц,Д,
    Шаблон = Выражение1 Проверка1,
    Шаблон = Выражение2 Проверка2,
    Шаблон = Выражение3 Проверка3
    Из   ПРОВЕРКА КАК П
    
    

    Показать

    Reply
  7. starik-2005

    (5) как вариант! Полезно иногда понимать, что где-то ошибаешься.

    Reply
  8. pm74

    (7) может кто нибудь заморочится и напишет обработку на тему алгоритма Квайна-МакКлоски

    Reply
  9. starik-2005

    (8) кстати, очень интересная тема. Постараюсь нарисовать ее в ближайшее время.

    Reply
  10. Painted

    2.4.1. Слона надо есть по кусочкам.

    Если задача пугает громоздкостью и/или сложностью, разбейте ее на более простые подзадачи. И разбивайте до тех пор, пока они не станут простыми и легко реализуемыми.

    Reply
  11. FreeFin

    Frustra fit per plura quod potest fieri per pauciora

    Но почему почти никто не задумывается, что достаточное не всегда правильное? Привычка, так принято и иначе нельзя? Всего лишь вопрос, а почему нельзя? Потому что «Оккам так сказал»?

    Reply
  12. logarifm
    2. Любое высказывание или истинно, или ложно — третьего не дано.

    В терминах 1С еще Или НЕОПРЕДЕЛЕНо 🙂

    Reply
  13. qwinter

    (12) Только в случае если оно существует)))

    Reply
  14. ADirks

    (11) потому что правильное не всегда правильно

    Reply
  15. starik-2005

    (12)

    В терминах 1С еще Или НЕОПРЕДЕЛЕНо 🙂

    Результат логической операции не может быть неопределен. Или может? )))

    Reply
  16. starik-2005

    (11) всегда есть смысл предметно поговорить об этом. Но для этого нужно какой-то пример разобрать. У Вас есть пример?

    Reply
  17. Jokemas

    Хорошая статья. Порадовало упоминание создателя «Соло на клавиатуре» =)).

    Reply
  18. capitan

    У некоторых программистов бывает еще так:

    Reply
  19. ADirks

    (15) В Булевой алгебре не может, т.к. эта алгебра определена на множестве {Истина, Ложь}

    А в SQL может, т.к. там множество {Истина, Ложь, Null}

    Reply
  20. morin

    Спасибо автору за статью.

    Процентов 80 работы программиста — это не написание кода, а его чтение (изучение чужого кода, отладка, изучение документации). У программистов 1С эта доля может доходить до 98 процентов.

    Может кто-нибудь поделится, как читать код (опыт, методики, инструменты)?

    Но, думаю, это тема для отдельной статьи.

    Reply
  21. Артано

    Спасибо за внесенную лепту. А также, за своеобразный пинок меня, чтобы я продолжил публикации ))

    Reply
  22. 1c-intelligence

    Кайф. И сказать нечего.

    Reply
  23. zqzq

    (2) Кстати, по поводу Совершенного кода, в оригинале название книги «Code Complete», совсем другой нюанс смысла.

    Reply
  24. awk

    Про логику порадовало

    С. Н. Виноградов, А. Ф. Кузьмин

    Логика

    УЧЕБНИК ДЛЯ СРЕДНЕЙ ШКОЛЫ СССР

    *** 1954 ***

    https://sheba.spb.ru/shkola/logika-vinograd1954.htm

    очень рекомендую….

    Я правда читал для вузов, вышеприведенный попроще…

    Reply
  25. rwn_driver

    Можно ещё почитать занимательную логику или Рэймонд М. Смаллиан «Как же называется эта книга?».

    Reply
  26. starik-2005

    (20)

    Но, думаю, это тема для …

    Кстати, хорошая идея. Попробую изложить свое видение данной проблемы в эти выходные.

    Reply
  27. genayo

    (26) Обязательно пишите, вроде неплохо получается 🙂

    Reply
  28. Painted

    (24)

    УЧЕБНИК ДЛЯ СРЕДНЕЙ ШКОЛЫ СССР

    *** 1954 ***

    Сорри, немного оффтопа. О вечном.

    Недавно с удивлением узнал, что мой ребенок учит дифференциалы по Фихтенгольцу. По которому в свое время учился я и, секундочку, моя мама. ))

    Reply
  29. awk

    (28)

    Фихтенгольцу

    Тут оказалось, что учебники 40-50 гораздо более понятны и адекватнее современных. Энтузиасты взялись за переиздание. Кто использует говорят эффект потрясающий, школьники которые считались в школе безнадежно тупыми — выбиваются в уверенные хорошисты (но это по слухам — не проверял сам).

    Reply
  30. vasilev2015

    Хочу поблагодарить Сергея за поддержку статьи про логику и математику

    Reply
  31. TABEZI1234

    (18) про меня

    Reply
  32. TABEZI1234

    не понял, это сарказм был в статье?

    Reply
  33. TABEZI1234

    Процентов 80 работы программиста — это не написание кода, а его чтение (изучение чужого кода, отладка, изучение документации). У программистов 1С эта доля может доходить до 98 процентов.

    Может кто-нибудь поделится, как читать код (опыт, методики, инструменты)?

    Но, думаю, это тема для отдельной статьи. —Согласен

    Reply
  34. kote

    (23) не-а, как раз перевод «совершенный» тут самое то — «совершенный» оно от «свершился -> завершился»..

    Завершенный, законченный, самодостаточный — как раз это значение у «complete».. а просто перевод «завершенный» — лишен смысла, который в самой книге.

    Reply
  35. 3vs

    «2. Любое высказывание или истинно, или ложно — третьего не дано.»

    А как же Троичная логика?

    ru.wikipedia.org/wiki/Троичная_логика

    Перечень значений нечёткой трёхзначной логики с двумя чёткими и с одним нечётким значением помимо «истинно» и «ложно» включает также третье значение, которое нечётко и трактуется как «не определено» или «неизвестно», или, в простонародье, х.з.

    Примерами значений нечёткой трёхзначной логики с одним чётким и с двумя нечёткими значениями являются: («меньше», «равно», «больше»), («уклон влево», «прямо», «уклон вправо») и другие.

    Примерами значений нечёткой трёхзначной логики с тремя нечёткими значениями, к которым сводится очень большое количество практических народнохозяйственных задач, являются: («меньше», «равно, в допустимых пределах», «больше»), («уклон влево», «прямо, в допустимых пределах», «уклон вправо»), («холодно», «прохладно», «жарко») и другие.

    Reply
  36. ВикторП
  37. Perfolenta

    (36) да, были люди в наше время… богатыри, не мы…

    Reply
  38. Crazy_Max

    (34)

    не-а, как раз перевод «совершенный» тут самое то — «совершенный» оно от «свершился -> завершился»…

    (34)

    Тогда нужно акцентировать внимание на букве «Ё» в слове «совершённый». А вообще, я бы перевёл название во что-то вроде «Конечный код». В любом случае название «Совершенный код» несёт практически противоположный смысл, чем тот, который вкладывал Макконнелл.

    Reply
  39. Crazy_Max

    (28)

    дифференциалы по Фихтенгольцу

    Это не тот Фихтенгольц, который еще и по программированию учебники писал? Я, будучи школьником, изучал по нему Паскаль в 10-м классе, а в 11-й класс пошел в другую школу. Там препод посмотрел на книжку, по которой я учился, затем указал мне на лучший компьютер в классе и попросил, чтобы я не мешал ему на уроках.

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

    Reply
  40. starik-2005

    (38)

    я бы перевёл название во что-то вроде «Конечный код»

    «Конченный код» ))) Типа писал его совсем конченный программер )))

    Reply
  41. Crazy_Max

    Ну уж кто чего видит…

    Reply
  42. Rustig
    пусть идет учиться не на очередной сертификат, а на курс логики.

    для улучшения собственных навыков программирования идеально подходит парное программирование с более опытным наставником

    понравилась мысль про «глаза боятся — руки делают». спасибо!

    Reply
  43. starik-2005

    (42) этим мыслям тысячи лет)))

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *