Законы программирования

Автор оригинала: Коллектив авторов
  • Перевод

Законы, теории, принципы и закономерности, полезные для разработчиков


Введение


Перевод репозитория github.com/dwmkerr/hacker-laws

При обсуждениях, связанных с разработкой ПО, люди часто говорят о различных законах. В данном репозитории хранятся ссылки и описания некоторых из наиболее известных из них.

Здесь содержатся объяснения некоторых законов, принципов и закономерностей, но нет никакой агитации в их пользу. Применять их или нет – это всегда вопрос спорный, и всё зависит от того, над чем вы работаете.

Законы


Закон Амдала


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

Приведём пример. Если программа состоит из двух частей – части А, которую необходимо исполнять на одном процессоре, и части Б, которую можно распараллелить, видно, что преимущества добавления нескольких процессоров к исполняющей программу системе ограничены. Потенциально это может сильно ускорить часть Б – но скорость части А не изменится.

На следующей диаграмме показаны примеры потенциального прироста скорости:



Как видно, даже если 50% программы можно распараллелить, преимущества от добавления более 10 отдельных процессоров будут незначительными. Если программу можно распараллелить на 95%, улучшения будут заметны даже после добавления тысячи процессоров.

С замедлением закона Мура и ускорения процессоров параллелизация становится ключом к улучшению эффективности. Прекрасным примером будет программирование графики – современное программирование на основе шейдеров позволяет отрисовывать фрагменты изображения параллельно, поэтому в современных графических картах можно встретить тысячи процессорных ядер (GPU или шейдерных модулей).

Теория разбитых окон


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

Эту теорию применяли к разработке ПО, предполагая, что плохое качество кода (или т.н. "технический долг") может вызвать ощущение того, что все попытки улучшить качество будут проигнорированы или недооценены, что приведёт к появлению нового плохого кода. Этот эффект развивается каскадно, из-за чего качество со временем ухудшается.

Закон Брукса


Добавление дополнительного человеческого ресурса к опаздывающему проекту задерживает его выход ещё больше.


Закон Брукса говорит о том, что во многих случаях попытки ускорить выпуск проекта, который и так опаздывает, путём добавления к нему дополнительных людей, приводят к тому, что проект выпускают ещё позже, чем могли бы. Однако Брукс подчёркивает, что это чрезмерное упрощение проблемы. Рассуждает он следующим образом: учитывая затраты на время, необходимое на ввод в строй новых ресурсов, и на общение людей между собой, в краткосрочной перспективе скорость развития проекта падает. Также многие задачи могут не подлежать разделению, то есть, их не получается легко распределить между ресурсами, количество которых увеличили, поэтому потенциальное увеличение скорости оказывается не таким значительным.

Распространённая присказка «девять женщин не могут родить ребёнка за один месяц» относится к закону Брукса, в частности потому, что некоторые виды работ нельзя разделить или распараллелить.

Это главная тема книги «Мифический человеко-месяц».

Закон Конвея


Закон Конвея говорит о том, что технические ограничения проектируемой системы будут отражать структуру организации. Его часто вспоминают при попытке улучшить работу организации. Закон говорит, что если организация структурирована на множество мелких, не связанных между собой модулей, то и созданная ею программа будет такой же. Если организация будет построена вокруг вертикалей, опирающихся на определённые особенности или услуги, то и её ПО будет отражать этот факт.

Закон Каннингема


Лучший способ найти правильный ответ в интернете — не задать вопрос, а разместить заведомо неправильный ответ.


Стивен Макгиди говорит, что в начале 1980-х Уорд Каннингем дал ему совет: «Лучший способ найти правильный ответ в Интернете — не задать вопрос, а разместить заведомо неправильный ответ». Макгиди назвал это «законом Каннингема», хотя сам Каннингем отрицает его авторство и говорит, что его «неверно цитируют». Хотя изначально фраза относилась к общению в Usenet, с тех пор закон использовали для описания работы и других сообществ (Wikipedia, Reddit, Twitter, Facebook).

Число Данбара


Число Данбара — ограничение на количество постоянных социальных связей, которые человек может поддерживать. Имеются в виду связи, предполагающие знание отличительных черт конкретного индивида, связь с которым необходимо поддерживать, его характера, а также социального положения, и его связей с другими людьми.

Точное число таких связей неизвестно. Сам Данбар предполагал, что человек с комфортом может поддерживать не более 150 таких связей. Он описывал его в более социальном контексте: «Количество людей, к которым вы не постесняетесь присоединиться без приглашения, чтобы вместе выпить, если вы случайно столкнётесь с ними в баре». Обычно оценки такого числа разнятся от 100 до 250.

Как и стабильные взаимоотношения между людьми, поддержка взаимоотношения программиста с кодом требует затрат сил. Сталкиваясь с крупными и сложными проектами или с владением множества мелких, мы полагаемся на определённые соглашения, политики и модели процедур. Число Данбара важно учитывать не только при росте количества сотрудников, но и при определении масштабов работы команды или того момента, когда системе стоит обзавестись вспомогательными инструментами для моделирования и автоматизации логистики. В инженерном контексте, это число проектов (или нормализованная сложность одного проекта), для которого вы бы уверенно вошли в группу поддержки кода.

Закон Голла


Работающая сложная система обязательно произошла от работавшей простой системы. Сложная система, разработанная с нуля, никогда не работает, и её невозможно исправить так, чтобы она заработала. Нужно начать заново, с простой работающей системы.


Закон Голла говорит о том, что попытки разработать очень сложную систему наверняка провалятся. Системы высокой сложности редко создают за один присест – они эволюционируют из более простых.

Классический пример – всемирная сеть. В текущем состоянии это система высокой сложности. Однако изначально её определили как простой способ обмена контентом между институтами. Она очень успешно справилась с этими целями и эволюционировала, превратившись со временем в более сложную.

Закон Гудхарта


Любая наблюдаемая статистическая закономерность склонна разрушаться, как только на неё оказывается давление с целью управления ею.


Также часто формулируется как:
Когда мерило становится целью, оно перестаёт быть хорошим мерилом.
Мэрилин Стратерн


Закон утверждает, что оптимизация на основе определённых мер может привести к обесцениванию этих мер. Слишком избирательные измерения (KPI), вслепую применяемые к процессу, приводят к искажениям. Люди стремятся оптимизировать процесс локально, «обманывая» систему с тем, чтобы удовлетворить определённой метрике, вместо того, чтобы обращать внимание на глобальный результат их действий.

Примеры:

  • Тесты без утверждений удовлетворяют ожиданиям по покрытию кода, несмотря на то, что такая метрика создавалась для того, чтобы программа была хорошо проверена.
  • Оценка эффективности разработчика на основе количества строк, внесённых в проект, приводит к неоправданному раздуванию кода.

Бритва Хэнлона


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

Закон Хофстадера


На выполнение задачи всегда уходит больше времени, чем ожидаешь, даже если ты принял во внимание закон Хофстадера.

Вы могли встречать упоминания этого закона, разбираясь с оценками временных затрат на проект. В области разработки ПО кажется трюизмом тот факт, что мы не очень хорошо способны точно оценить время, которое уйдёт на завершение проекта.

Цитата из книги "Гёдель, Эшер, Бах: эта бесконечная гирлянда".

Закон Хатбера


Улучшение эквивалентно разрушению.

Этот закон утверждает, что улучшение одной части системы ведёт к разрушению других частей, или прячет иные типы разрушения, что в целом приводит к деградации системы по сравнению с текущим её состоянием.

К примеру, уменьшение времени отклика в определённой части системы может привести к увеличению её пропускной способности, и, как следствие, к проблемам с ёмкостью где-то на пути потока запросов, что может повлиять на другую подсистему.

Цикл шумихи и закон Амара


Мы склонны переоценивать влияние технологии в краткосрочной перспективе и недооценивать его в долгосрочной.

Цикл шумихи – визуализация восторгов и развития технологии со временем, изначально построенная компанией Gartner. Лучше всего иллюстрируется графиком:


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

Вкратце цикл утверждает, что вокруг новой технологии и её потенциальных последствий обычно возникает фонтан восторгов. Команды часто быстро увлекаются этими технологиями и часто испытывают разочарование полученными результатами. Возможно, это происходит потому, что технология ещё недостаточно развита, или способы её применения ещё не продуманы. По прошествии определённого времени возможности технологии увеличиваются, и количество практических применений растёт, после чего команды, наконец, могут становиться продуктивными.

Закон Хирама


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


Закон Хирама постулирует, что если у вашего API достаточно много пользователей, для любой из возможных особенностей поведения вашей системы (даже не описанной в публичном контракте) найдётся зависящий от него пользователь. Тривиальным примером могут быть нефункциональные особенности API, типа времени отклика. Более тонкий пример – потребители, полагающиеся на определение типа ошибки посредством применения к её описанию функции regex. Даже если в публичном контракте ничего не сказано по поводу содержания сообщения, и подразумевается, что пользователи должны использовать код ошибки, некоторые из них могут решить использовать сообщение, и изменение сообщения сломает API для этих пользователей.

Закон Кернигана


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


Закон Кернигана назван в честь Брайана Кернигана и взят из книги, написанной им и Плогером: «Элементы стиля программирования».

Все знают, что отладка кода в два раза тяжелее, чем его написание. Поэтому если вы прилагаете все умственные усилия, когда пишете код, как вы собираетесь его отлаживать?

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

Закон Меткалфа


В теории сетей полезность сети растёт примерно как квадрат количества её пользователей.

Закон основывается на количестве возможных попарных связей внутри системы, и тесно связан с законом Рида. Одлыжко и другие утверждали, что законы Рида и Меткалфа преувеличивают ценность системы, не учитывая ограничения человеческих возможностей понимания сети; см. число Данбара.

Закон Мура


Количество транзисторов, размещаемых на кристалле интегральной схемы, удваивается примерно каждые 24 месяца.

Предсказание Мура, которое часто используют для демонстрации огромной скорости улучшения технологий производства полупроводников и чипов, оказалось удивительно точным, и работало с 1970-х по конец 2000-х. В последние годы тренд немного изменился, в частности, из-за физических ограничений миниатюризации компонентов. Однако прогресс распараллеливания и потенциально революционные изменения в полупроводниковой технологии и квантовых компьютеров могут означать, что закон Мура может и следующие несколько десятилетий оставаться верным.

Закон Мёрфи


Всё, что может пойти не так, пойдёт не так.

Закон Мёрфи, за авторством Эдварда А. Мерфи, постулирует, что всё, что может пойти не так, обязательно пойдёт не так.

Эту поговорку часто используют разработчики. Иногда неожиданные вещи происходят во время разработки, тестирования или даже в продакшене. Его можно связать с чаще употребляемым в Британии законом подлости [собственно, и в России он тоже известен / прим. перев.]:
Если что-то может пойти не так, это случится, причём в наихудший из возможных моментов.

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

Бритва Оккама


Не следует множить сущее без необходимости.

Бритва Оккама утверждает, что из нескольких возможных решений наиболее вероятным будет решение, содержащее наименьшее количество концепций и предположений. Это решение будет простейшим и будет решать только заданную проблему, не вводя случайных сложностей и возможных негативных последствий.

Закон Паркинсона


Работа заполняет время, отпущенное на неё.

В оригинальном контексте закон был основан на изучении бюрократизма. Пессимистически его можно применить к разработке ПО, предположив, что команда будет работать неэффективно, пока не начнёт приближаться срок сдачи проекта, а затем будет торопиться, чтобы сдать его в срок, из-за чего конкретная дата окончания оказывается довольно произвольной.

Если скомбинировать его с законом Хофстадера, получится ещё более пессимистичный взгляд: работа будет расширяться, пока не заполнит всё время, необходимое на её завершение, и всё равно займёт больше, чем ожидалось.

Эффект преждевременной оптимизации


Преждевременная оптимизация – корень всех зол.

В работе Дональда Кнута «Структурированное программирование с GoTo» он писал: «Программисты тратят огромное количество времени на размышления и волнения по поводу скорости выполнения некритичных частей программ, и попытки сделать их эффективнее оказывают сильный негативный эффект, если задуматься об их отладке и поддержке. Нам нужно забывать о малозначимой эффективности 97% времени: преждевременная оптимизация – корень всех зол. Однако в критических важных 3% случаев мы не должны упускать наши возможности».

Однако преждевременную оптимизацию также можно описать, как попытку оптимизировать что-то до того, как мы поймём, что нам нужно сделать.

Закон Патта


В технологическом секторе доминируют два типа людей: те, кто разбирается в том, что они не контролируют, и те, кто контролирует то, в чём они не разбираются.


За законом Патта часто следует заключение Патта:
В любой технической иерархии со временем вырабатывается инверсия компетентности.

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

Однако стоит подчеркнуть, что подобные законы являются очень грубым обобщением, и могут быть применимыми к одним типам организаций, и не применимыми к другим.

Закон Рида


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

Этот закон основан на теории графов, где полезность масштабируется как число возможных подгрупп, растущее быстрее, чем количество участников или возможных попарных связей. Одлыжко и другие утверждали, что законы Рида и Меткалфа преувеличивают ценность системы, не учитывая ограничения человеческих возможностей понимания сети; см. число Данбара.

Закон сохранения сложности (Закон Теслера)


Закон утверждает, что у системы существует определённая сложность, уменьшить которую нельзя.

Часть сложности системы может возникнуть ненамеренно. Она является результатом плохой структуры, ошибок или неудачного моделирования решаемой задачи. Ненамеренную сложность можно уменьшить или устранить. Однако некоторые виды сложности являются неотъемлемым следствием сложностей самой задачи. Эту сложность можно переместить, но не устранить.

Один из интересных элементов этого закона – предположение о том, что даже при упрощении всей системы её внутренняя сложность не уменьшается, а переходит на пользователя, которому приходится сложнее себя вести.

Закон протекающих абстракций


Все нетривиальные абстракции до определенного предела подвержены протеканию.

Этот закон утверждает, что абстракции, которые обычно используются в IT для упрощения работы со сложными системами, в определённых ситуациях дают «протечку», пропуская наверх элементы лежащих в их основе систем, из-за чего абстракция начинает вести себя непредсказуемо.

Примером может служить загрузка файла и чтение его содержимого. API файловой системы – это абстракция систем ядра более низкого уровня, которые сами являются абстракцией физических процессов, связанных с изменением данных на магнитной пластине (или в флэш-памяти SSD). В большинстве случаев абстракция, представляющая файл в виде потока двоичных данных, будет работать. Однако последовательное чтение данных с магнитного диска будет идти быстрее, чем случайный доступ к ним, но при этом у SSD таких проблем не будет. Нужно понимать детали, лежащие в глубине, чтобы обрабатывать эти случаи (к примеру, индексные файлы баз данных структурируются, чтобы уменьшить время случайного доступа), когда абстракция даёт «протечку» деталей реализации, о которых нужно знать разработчику.

Приведённый пример может усложниться при добавлении новых абстракций. ОС Linux позволяет получать доступ к файлам по сети, однако они видны локально, как «обычные». Эта абстракция даст «протечку» в случае проблем с сетью. Если разработчик будет относиться к ним, как к «нормальным», не учитывая того, что они подвержены проблемам с задержками и отказам в сети, его решение будет неоптимальным и глючным.

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

Примеры: медленный запуск Photoshop. С этой проблемой я столкнулся в прошлом. Photoshop очень медленно запускался, иногда на это уходило несколько минут. Судя по всему, проблема была в том, что при запуске он считывает информацию о текущем принтере по умолчанию. Но если этот принтер был сетевым, на это могло уйти чрезвычайно много времени. Абстракция, согласно которой сетевой принтер аналогичен локальному, причиняла пользователем проблемы в случае плохой связи.

Закон тривиальности


Закон утверждает, что группы тратят гораздо больше времени и внимания на обсуждения косметических или тривиальных проблем, чем на серьёзные и обширные.

Обычно приводится в пример работа комитета, одобряющего планы ядерной электростанции, который большую часть времени обсуждает структуру велопарковки, чем более важные вопросы проекта самой станции. Бывает сложно внести ценный вклад в обсуждение очень больших и сложных тем, не имея за плечами объёмных знаний по этому вопросу. Однако людям хочется, чтобы их отмечали за внесение ценных замечаний. Отсюда происходит тенденция концентрации на небольших деталях, о которых легко рассуждать, но которые не обязательно важны для проекта в целом.

Вымышленный пример, приведённый выше, породил термин «эффект велосарая», описывающий потерю времени на обсуждение тривиальных деталей. Существует похожий термин «стрижка яков», описывающий, казалось бы, не связанную с проектом активность, являющуюся частью длинной цепи необходимых подготовительных этапов.

Философия Unix


Философия Unix состоит в том, что компоненты ПО должны быть небольшими и концентрироваться на том, чтобы хорошо выполнять одну конкретную задачу. Это облегчает процесс построения систем путём набора из небольших, простых и хорошо определённых модулей, вместо того, чтобы использовать крупные, сложные, многофункциональные программы.

Современные практики, вроде «архитектуры микросервисов», можно считать применением этой философии – сервисы мелкие, сконцентрированы на выполнении одной конкретной задачи, что позволяет составлять сложное поведение из простых строительных блоков.

Модель Spotify


Подход к структуре команды и организации, который продвигает Spotify. По этой модели команды организуются вокруг функций программ, а не вокруг технологий.

Также модель продвигает концепции племён, гильдий, филиалов – других компонентов организационной структуры.

Закон Уодлера


В проектировании любого языка общее время, потраченное на обсуждение особенности из этого списка, пропорционально двойке в степени номера позиции этой особенности в списке.
0. Семантика.
1. Синтаксис.
2. Лексический синтаксис.
3. Лексический синтаксис комментариев.

То есть, на каждый час, потраченный на семантику, приходится 8 часов, потраченных на синтаксис комментариев.

Как и закон тривиальности, закон Уодлера постулирует, что при проектировании языка количество времени, потраченное на структуры языка, непропорционально велико по сравнению с важностью этих структур.

Закон Уитона


Не будь козлом.

Этот сжатый, простой и всеобъемлющий закон, сформулированный Уилом Уитаном, направлен на увеличение гармонии и уважения в рамках профессиональной организации. Его можно применять в разговорах с коллегами, при проведении экспертной оценки кода, поиске возражений против других точек зрения, в критике, и в целом, в профессиональном общении людей.

Принципы


Принципы чаще всего связаны с советами по проектированию программ.

Принцип Дилберта


В компаниях существует тенденция к повышению некомпетентных сотрудников до менеджеров с целью устранить их от рабочего процесса.

Управленческая концепция, разработанная Скоттом Адамсом (создателем комиксов про Дилберта), вдохновлённая принципом Питера. Согласно принципу Дилберта, сотрудников, которых нельзя было считать компетентными, повышают до управленцев, чтобы ограничить возможный урон компании. Впервые Адамс объяснил этот принцип в статье для Wall Street Journal в 1995 году, а потом подробно описал его в книге 1996 года «Принцип Дилберта».

Принцип Парето (правило 80/20)


По большей части в жизни всё распределяется неравномерно.

Принцип Парето утверждает, что в некоторых случаях за большую часть результатов отвечает меньшая часть вложений:

  • 80% программы можно написать за 20% времени (и на самые сложные 20% уходят остальные 80% времени).
  • 20% усилий дают 80% результата.
  • 20% работы создают 80% прибыли.
  • 20% ошибок приводят к 80% падений программы.
  • 20% функций используется 80% времени.

В 1940-х американский инженер румынского происхождения Джозеф Джуран, которого часто называют отцом управления качеством, начал применять принцип Парето к проблемам качества.

Также этот принцип известен, как правило 80/20, закон важнейшего малого, принцип дефицита факторов.

Примеры: в 2002 году Microsoft сообщила, что после исправления 20% наиболее часто встречающихся ошибок, будет исправлено 80% связанных с ними проблем и падений Windows и Office.

Принцип Питера


В иерархической системе у каждого индивидуума есть тенденция подниматься до уровня своей некомпетентности.


Управленческая концепция, созданная Лоуренсом Джонстоном Питером, отмечает тот факт, что людей, хорошо справляющихся с работой, повышают до тех пор, пока они не попадают на уровень, на котором уже не справляются («уровень некомпетентности»). Поскольку они забрались достаточно высоко, их уже с меньшей вероятностью уволят (если только они не сотворят какой-то полной ерунды), поэтому они будут оставаться на этой позиции, для которой им не хватает необходимых умений, поскольку их навыки поведения в организации не обязательно совпадают с навыками, необходимыми для успешной работы на данной должности.

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

Принцип надёжности (закон Постела)


Консервативно относитесь к своей деятельности, и либерально ко вкладам других.

Этот принцип часто применяют к разработке серверных приложений. Согласно ему, данные, отправляемые вами другим, должны быть как можно меньшего размера и как можно лучше соответствовать стандарту, однако вы сами должны принимать на вход и не совсем стандартизированные данные, если у вас получится их обработать.

Цель принципа – создание надёжных систем, способных переварить плохо оформленные данные, смысл которых всё же можно понять. Однако у приёма нестандартных данных на вход могут быть последствия, связанные с нарушением безопасности, в особенности, если приём таких данных не было хорошо протестирован.

Со временем практика приёма нестандартных данных может привести к тому, что протоколы перестанут развиваться, поскольку те, кто реализуют обмен данными, начнут полагаться на либеральность программ, создавая новые функции.

SOLID


Акроним, обозначающий следующие 5 принципов:

S: The Single Responsibility Principle [Принцип единственной ответственности]
O: The Open/Closed Principle [Принцип открытости/закрытости]
L: The Liskov Substitution Principle [Принцип подстановки Барбары Лисков]
I: The Interface Segregation Principle [Принцип разделения интерфейса]
D: The Dependency Inversion Principle [Принцип инверсии зависимостей]

Они представляют собой ключевые принципы объектно-ориентированного программирования. Подобные принципы проектирования должны помогать разработчикам создавать системы, которые легче поддерживать.

Принцип единственной ответственности


Каждый объект должен иметь одну ответственность и эта ответственность должна быть полностью инкапсулирована в класс.

Первый из принципов SOLID. Принцип утверждает, что каждый модуль или класс должен делать только одну вещь. На практике это значит, что небольшое единственное изменение функции программы должно потребовать изменения только в одном компоненте. К примеру, для изменения процедуры проверки пароля на сложность программу нужно исправить всего в одном месте.

Теоретически это придаёт коду надёжности и упрощает его изменение. То, что у изменяемого компонента имеется единственная ответственность, должно означать, что будет проще тестировать это изменение. Изменение компонента проверки пароля на сложность из предыдущего примера должно повлиять только на функции, связанные со сложностью пароля. Гораздо труднее рассуждать о том, на что повлияет изменение компонента со множеством ответственностей.

Принцип открытости/закрытости


Программные сущности должны быть открыты для расширения, но закрыты для изменения.

Второй из принципов SOLID. Принцип утверждает, что сущности (классы, модули, функции и т. п.) должны позволять расширять их поведение, но делать так, чтобы их текущее поведение изменить было нельзя.

Гипотетический пример: представим себе модуль, способный превратить документ в разметке Markdown в документ в разметке HTML. Если модуль можно расширить так, чтобы он научился обрабатывать новые возможности формата Markdown, не изменяя его внутренних функций, тогда модуль открыт для расширения. Если в модуле нельзя изменить обработку текущих функций Markdown, тогда модуль закрыт для изменения.

Принцип особенно тесно связан с объектно-ориентированным программированием, где можно проектировать объекты простые для расширения, но не стоит проектировать объекты, внутренности которых будут неожиданным образом меняться.

Принцип подстановки Барбары Лисков


Должна быть возможность заменить тип на подтип, не ломая систему.

Третий из принципов SOLID. Принцип утверждает, что если компонент зависит от типа, тогда должна быть возможность использовать подтипы этого типа так, чтобы система не отказалась работать или не требовала подробностей этого подтипа.

К примеру, у нас есть метод, читающий XML-документ из структуры, обозначающей файл. Если метод использует базовый тип file, тогда в функции должна быть возможность использовать всё, что происходит от файла. Если file поддерживает обратный поиск, и XML-парсер использует эту функцию, но производный тип «сетевой файл» отказывается работать с обратным поиском, то «сетевой файл» нарушает этот принцип.

Принцип особенно тесно связан с объектно-ориентированным программированием, где иерархии типов нужно очень тщательно моделировать, чтобы избежать путаницы для пользователя системы.

Принцип разделения интерфейса


Программные сущности не должны зависеть от методов, которые они не используют.

Четвёртый из принципов SOLID. Принцип утверждает, потребители компонента не должны зависеть от функций компонента, которые он не использует.

К примеру, у нас есть метод, читающий XML-документ из структуры, обозначающей файл. Ему нужно только считывать байты, двигаясь вперёд или назад по файлу. Если этот метод придётся обновлять из-за изменений не связанной с ним особенности файловой структуры (к примеру, из-за обновления модели разграничения доступа, представляющей безопасность файла), тогда этот принцип будет нарушен. Файлу лучше реализовать интерфейс «потока с возможностью поиска», а XML-методу – его использовать.

Принцип особенно тесно связан с объектно-ориентированным программированием, где интерфейсы, иерархии и абстрактные типы используются для минимизации связей между компонентами. Этот принцип заставляет использовать "утиная типизация", методология, устраняющая явные интерфейсы.

Принцип инверсии зависимостей


Модули верхних уровней не должны зависеть от модулей нижних уровней.

Пятый из принципов SOLID. Принцип утверждает, что управляющие компоненты высших уровней не должны знать деталей реализации их зависимостей.

К примеру, у нас есть программа, читающая метаданные с веб-сайта. Предположительно, её главному компоненту должен быть известен компонент, скачивающий контент веб-страницы, и компонент, считывающий метаданные. Если мы учтём принцип инверсии зависимостей, то главный компонент будет зависеть только от абстрактного компонента, получающего байтовые данные, а он в свою очередь от абстрактного компонента, способного читать метаданные из потока байтов. Главный компонент ничего не будет знать про TCP/IP, HTTP, HTML и т.п.

Принцип довольно сложный, поскольку он инвертирует ожидаемую зависимость в системе. На практике он также означает, что отдельный управляющий компонент должен гарантировать правильную реализацию абстрактных типов (в предыдущем примере что-то должно поставлять модулю чтения метаданных компонент для скачивания файла по HTTP и для чтения данных из тэга meta HTML).

Принцип «не повторяйся» [Don’t repeat yourself]


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

Принцип Don’t repeat yourself, или DRY, помогает разработчикам уменьшить повторяемость кода и держать информацию в одном месте. Он был упомянут в 1999 году Энди Хантом и Дэйвом Томасом в их книге «Прагматичный программист».

Противоположностью принципа DRY [англ. сухой] должен быть принцип WET [англ. мокрый] – «пишите всё дважды» [Write Everything Twice] или «нам нравится печатать» [We Enjoy Typing].

На практике, если одна и та же информация дублируется у вас в двух или более местах, используйте принцип DRY, сливая их в одно место и повторно используя по необходимости.

Принцип KISS


Keep it simple, stupid [Не усложняй, дурик]

Принцип KISS говорит, что большинство систем работают лучше, если их не усложнять; следовательно, простота должна быть ключевой целью в разработке, а ненужной сложности нужно избегать. Зародился он в военно-морском флоте США в 1960, и фразу приписывают авиаконструктору Кларенсу Джонсону.

Лучше всего представить его на примере, когда Джонсон выдал команде инженеров-проектировщиков небольшой набор инструментов, и поручил им разработать самолёт так, чтобы его в поле в боевых условиях мог починить средний механик при помощи только этого набора. Здесь stupid обозначает взаимоотношение между тем, как ломаются вещи, и сложностью доступных инструментов для их ремонта, а не умственные способности инженеров.

YAGNI


Акроним для You Ain't Gonna Need It [вам это не понадобится].
Всегда реализуйте функции только тогда, когда они вам реально нужны, а не тогда, когда вам кажется, что они вам понадобятся в будущем.

Автор техники экстремального программирования (XP) и книги «Установленное экстремальное программирование» Рон Джеффрис предполагает, что разработчики должны заниматься реализацией только такой функциональности, которая нужна прямо сейчас, и не пытаться предсказывать будущее, реализуя функциональность, которая может понадобиться позже.

Следование этому принципу должно уменьшить количество неиспользуемого кода в базе, а также траты сил и времени на функциональность, не приносящую пользы.

Заблуждения распределённых вычислений


Также известны, как заблуждения сетевых вычислений. Это список предположений, касающихся распределённых вычислений, способных привести к отказам в работе ПО. Это следующие предположения:

  1. Сеть надёжна.
  2. Задержка нулевая.
  3. Пропускная способность бесконечна.
  4. Сеть безопасна.
  5. Топология не меняется.
  6. Администратор только один.
  7. Стоимость пересылки нулевая.
  8. Сеть однородна.

Первые четыре перечислили Билл Джой и Том Лион в 1991 году, а Джеймс Гослинг впервые классифицировал их как «Заблуждения сетевых вычислений». Питер Дойч добавил 5, 6 и 7-е заблуждение. В конце 90-х Гослинг добавил 8-е.

Группу инженеров вдохновляли процессы, происходившие в то время в Sun Microsystems.

Эти заблуждения стоит тщательно учитывать при разработке надёжного кода. Каждое из заблуждений может привести к неправильной логике, не способной справиться с реальностью и сложностью распределённых систем.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 21

    +3
    За что минусы-то, нормальная статья
      +5
      Лично мне кажется, что первый минус ставится автоматом.
        +2

        Есть предположение, что минус кто-то оставил за перевод переведённого материала:
        Уважаемый Вячеслав Голованов (SLY_G) указал источник -


        Перевод репозитория github.com/dwmkerr/hacker-laws

        Вроде всё правильно, но почему-то не захотел упомянуть, что эта подборка переведена на несколько языков, включая русский (Alena Batitskaya solarrust).
        Такие публикации вызывают у меня двойственные чувства. Вроде, человек старалсо, переводил. А с другой стороны — зачем? Популяризовать материал? Или популяризовать себя — пиарюсь (есть же спец. тег для этого)?
        В общем, если бы меня кто-то пригласил в НЛО (или я бы умел сам себя приглашать), и появилось право ставить плюсы/минусы, то от меня бы тоже минус прилетел.
        Боюсь вот только, что за честное мнение, мне самому что-нибудь прилетит...

        0
        Расскажите про «стрижку яков»
          +6
          Надо съездить за продуктами, но у машины спустило колесо, насос в гараже, а там лампочка перегорела, а в шкафу с лампочками дверца заедает — пошёл искать баллон со смазкой.
          В итоге ищу баллон со смазкой, чтобы съездить за продуктами.
            0
            Отличный пример, типа «толочь воду в ступе...»
              0
              Как же без видео?

              www.youtube.com/watch?v=IzdxX8qC37s
                +4
                Блин, гифка, залитая на ютуб. Вот уж где изврат.
                Вот нормальное видео:
            0
            Интересные законы. Многие можно также хорошо отнести и к другим сферам разработки, а не только к программированию.

            Например, мне понравился закон Хирама:
            При достижении достаточного количества пользователей API уже неважно, какие его особенности вы обещали всем: для любой из возможных особенностей поведения вашей системы найдётся зависящий от неё пользователь


            который можно было бы отнести на любой, в том числе и физический продукт: т.е. при достаточном количестве проданных экземпляров данного продукта, всегда найдется пользователь для любой из фич данного продукта. Причем даже для той, о которой не разработчик не думал. Например, вообразим, что Google Home можно прибивать гвозди — и найдутся же те, кто это в реале делал!
              +3
              Преждевременная оптимизация – корень всех зол.

              Я конечно не програмист, но как-то не могу согласится с этим утверждением. Не раз и не два встречался на проектах с ситуацией типа:
              Лид: Ребята сегодня начинаем писать вот этот сложный модуль/отчет. Он не сколько сложный по бизнесу, сколько ресурсоёмкий потому что работает с множеством объектов. Понятно?
              Команда: Понятно-понятно, идем пилить.

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

              Короче к чему я веду, конечно не надо морочить голову над тем как сразу заставить сайт грузится 3 мс, вместо скажем 3 сек. Но и иметь хотя бы приблизительное представление о том, что и как быстро будет работать, что выбрать правильный подход надо.
                +2

                Всё верно, в названии и есть "преждевременная". В описанном случае разработчики знали о нагрузке, но сделали криво, а значит задача не выполнена.

                  +8

                  У них, похоже, абстракция протекла..

                    0
                    Можно процитировать фаулера в тему:

                    С рефакторингом обычно связан вопрос о его влиянии на производительность программы. С целью облегчить понимание работы программы часто осуществляется модификация, приводящая к замедлению выполнения программы. Это важный момент. Я не принадлежу к той школе, которая пренебрегает производительностью в пользу чистоты проекта или в надежде на рост мощности аппаратной части.Программное обеспечение отвергалось как слишком медленное, а более быстрые машины устанавливают свои правила игры. Рефакторинг, несомненно, заставляет программу выполняться медленнее, но при этом делает ее более податливой для настройки производительности. Секрет создания быстрых программ, если только они не предназначены для работы в жестком режиме реального времени, состоит в том, чтобы сначала написать программу, которую можно настраивать, а затем настроить ее так, чтобы достичь приемлемой скорости.

                    Мне известны три подхода к написанию быстрых программ. Наиболее трудный из них связан с ресурсами времени и часто применяется в системах с жесткими требованиями к выполнению в режиме реального времени.В этой ситуации при декомпозиции проекта каждому компоненту выделяется бюджет ресурсов — по времени и памяти. Компонент не должен выйти за рамки своего бюджета, хотя разрешен механизм обмена временными ресурсами. Такой механизм жестко сосредоточен на соблюдении времени выполнения. Это важно в таких системах, как, например, кардиостимуляторы, в которых данные, полученные с опозданием, всегда ошибочны.Данная технология избыточна в системах другого типа, например в корпоративных информационных системах, с которыми я обычно работаю.

                    Второй подход предполагает постоянное внимание. В этом случае каждый программист в любой момент времени делает все от него зависящее, чтобы поддерживать высокую производительность программы. Это распространенный и интуитивно привлекательный подход, однако он не так хорош на деле. Модификация, повышающая производительность, обычно затрудняет работу с программой. Это замедляет создание программы. На это можно было бы пойти, если бы в результате получалось более быстрое программное обеспечение, но обычно этого не происходит. Повышающие скорость усовершенствования разбросаны по всей программе, и каждое из них касается только узкой функции, выполняемой программой.С производительностью связано то интересное обстоятельство, что при анализе большинства программ обнаруживается, что большая часть времени расходуется небольшой частью кода. Если в равной мере оптимизировать весь код, то окажется, что 90% оптимизации произведено впустую, потому что оптимизировался код, который выполняется не слишком часто. Время, ушедшее на ускорение программы, и время, потерянное из-за ее непонятности — все это израсходовано напрасно.

                    Третий подход к повышению производительности программы основан как раз на этой статистике. Он предполагает создание программы с достаточным разложением ее на компоненты без оглядки на достигаемую производительность вплоть до этапа оптимизации производительности, который обычно наступает на довольно поздней стадии разработки и на котором осуществляется особая процедура настройки программы.Начинается все с запуска программы под профайлером, контролирующим программу и сообщающим, где расходуются время и память. Благодаря этому можно обнаружить тот небольшой участок программы, в котором находятся узкие места производительности. На этих узких местах сосредоточиваются усилия, и осуществляется та же самая оптимизация, которая была бы применена при подходе с постоянным вниманием.Но благодаря тому, что внимание сосредоточено на выявленных узких местах, удается достичь больших результатов при значительно меньших затратах труда. Но даже в этой ситуации необходима бдительность. Как и при проведении рефакторинга, изменения следует вносить небольшими порциями, каждый раз компилируя, тестируя и запуская профайлер. Если производительность не увеличилась, изменениям дается обратный ход.Процесс поиска и ликвидации узких мест продолжается до достижения производительности, которая удовлетворяет пользователей. Мак-Коннелл [McConnell] подробно рассказывает об этой технологии.Хорошее разделение программы на компоненты способствует оптимизации такого рода в двух отношениях. Во-первых, благодаря ему появляется время, которое можно потратить на оптимизацию. Имея хорошо структурированный код, можно быстрее добавлять новые функции и выиграть время для того, чтобы заняться производительностью. (Профилирование гарантирует, что это время не будет потрачено зря.) Во-вторых, хорошо структурированная программа обеспечивает более высокое разрешение для анализа производительности. Профайлер указывает на более мелкие фрагменты кода, которые легче настроить.Благодаря большей понятности кода легче осуществить выбор возможных вариантов и разобраться в том, какого рода настройка может оказаться действенной.

                    Я пришел к выводу, что рефакторинг позволяет мне писать программы быстрее. На некоторое время он делает программы более медленными, но облегчает настройку программ на этапе оптимизации. В конечном счете достигается большой выигрыш.
                    +2
                    … в начале 1980-х Уорд Каннингем дал ему совет: «Лучший способ найти правильный ответ в Интернете...

                    А ведь точно, еще Ленин что-то там говорил о цитатах из Интернета

                      +1
                      Так Каннингем и не говорил про интернет, там был Usenet, появившийся как раз в 1980. Про Интернет уже потом перефразировали и приписали ему.
                      +1
                      В технологическом секторе доминируют два типа людей: те, кто разбирается в том, что они не контролируют, и те, кто контролирует то, в чём они не разбираются.

                      Чем то коррелирует с принципом Питера
                      «В иерархической системе каждый индивидуум имеет тенденцию подняться до уровня своей некомпетентности»
                        0

                        Сразу пришел в голову первый закон Ома: схема без питания не работает.
                        Вот о чём статья, догадался я.

                          0
                          А мне первое правило механики: не мешай механизму работать.
                          0
                          Бритва Хэнлона — на самом деле Бритва Хайнлайна.
                            +4
                            Я бы еще добавил «Парадокс Блаба» в список.
                            Его сущность состоит в том, что программист, знающий некоторый язык («Блаб»), «думает на Блабе» — выражает решение любой задачи в средствах Блаба, а имеющиеся в более мощном языке дополнительные средства в его глазах ничего не стоят, так как он не умеет их применять. Только когда программист по каким-то внешним, дополнительным причинам изучит более мощный язык, он получит возможность смотреть на Блаб «сверху вниз» и увидит его ограниченность. Таким образом, ограниченность Блаба сама по себе не может стать стимулом для изучения более мощного языка, так как для осознания этой ограниченности необходимо уже знать такой язык.
                              0
                              kiss — милая аббревиатура для фразы про «дурика»)

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое