Умные программисты пишут STUPID-код

в 13:00, , рубрики: ruvds_перевод, solid, stupid, принципы проектирования, шаблоны проектирования
Умные программисты пишут STUPID-код, ведь они понимают, что неожиданно возникшая сложность может привести к провалу проекта.

Умные программисты пишут STUPID-код - 1

▍ Страдание

На момент написания этой статьи на моих часах 21:30.

Этим утром я проснулся в хорошем, оптимистичном настроении, рассчитывая на прекрасный день, но теперь вымотан.

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

Если конкретнее, при написании или поддержке кода мы склонны постоянно попадать в ловушку случайной сложности. Я наблюдал это с первого дня попадания в эту отрасль, и эта тема стала основной темой моей презентации, посвящённой техническому долгу (Purging the Technical Debt by Using Static Code Analysis Tools на YouTube).

На появление во мне любви к разработке ПО чрезвычайно сильно повлиял Фредерик Брукс, написавший сборник эссе под названием Мифический человеко-месяц.

В этой книге Брукс проливает свет на два типа сложности, очень хорошо вербализованных Эдрианом Колье в его блоге The Morning Paper постом No Silver Bullet — essence and accident in software engineering:

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

▍ Допущение

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

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

Но в то же время мы и увлекающиеся существа.

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

И мы умные.

Мы очень умные.

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

▍ Предложение

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

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

Например, если вы хотите улучшить качество кода, то выбираете придерживаться принципов программирования SOLID. Я согласен с принципами и идеями SOLID. Лично я считаю, что резюмировать их основу можно как корректную реализацию объектно-ориентированного программирования со стремлением правильно делать правильные вещи. Однако когда я занимался консалтингом, то заметил, что многие люди восхваляют принципы SOLID, не уделяя внимания их ценностям, что часто приводит к созданию хрупкого кода (по перечисленным выше причинам). Когда я просил их сформулировать своими словами то, что они по-настоящему понимают в SOLID, то обычно получал неполные, неструктурированные, неуверенные ответы. Возможно, так получалось потому, что большинство принципов немного абстрактно.

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

А как насчёт такого предложения: что, если мы используем свой «ум», чтобы просто писать STUPID-код. Код, настолько STUPID, что если бы компилятор мог генерировать эмоции, то вы бы увидели слёзы, льющиеся с монитора, а колонки воспроизвели бы звук громких аплодисментов. [Прим. пер.: stupid в переводе с английского — «глупый».]

Так что же я вам предлагаю? Что это за STUPID?

Ну, это довольно просто. Первая буква и расшифровывается как simple [«простой»].

▍ S расшифровывается как SIMPLE

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

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

И ниже я расскажу о том, как метод STUPID продвигает адаптивность интуитивно понятным образом.

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

Помните популярную аббревиатуру KISS? Keep it simple, STUPID.

▍ T означает TESTABLE («тестируемый»)

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

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

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

Пишите простой (SIMPLE) и тестируемый код (TESTABLE). Это уже достаточно хорошее направление, позволяющее придерживаться agile-программирования.

▍ U означает Ubiquitous («повсеместный»)

Эта идея была изложена Эриком Эвансом в его новаторской книге Domain-Driven Design: Tackling Complexity in the Heart of Software. Это один из моих любимых аспектов, которые необходимо учитывать при программировании.

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

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

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

Это неожиданная сложность, и она очень неприятна.

Предпринимайте усилия к тому, чтобы сохранять во всей кодовой базе один язык. Если вы выберете язык предметной области, тем лучше. При обсуждении X с клиентом убедитесь, что это тот самый X, который присутствует в коде. Чётко и осознанно именуйте объекты (классы, методы, свойства, типы, модули и так далее.)

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

▍ P означает Proper («чистый»)

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

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

Баланс этой пользы всегда должен быть положительным.

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

Недавно на работе один и тот же разработчик писал мне во время пул-реквеста одни и те же комментарии: "Код плохо отформатирован. После фигурной скобки должно быть два пробела."

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

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

▍ I означает Incremental («инкрементный»)

Однажды я услышал фразу Кента Бека, запечатлевшуюся в моей памяти:

Заставь это работать. Сделай это правильно. Сделай это быстрым.

Недавно я дал себе разрешение добавить в этот список ещё один пункт.

Сделай это лучше.

Или на каждой итерации, или в каждый возможный момент, даже оптимизировав свой код до невозможности, позволь себе поразмыслить о том, как сделать его лучше. Возможно, лучше тестируемым? Или лучше портируемым на другие платформы? Что бы в вашем понимании ни делало его лучше, возьмите на себя ответственность сделать его таким.

Мы не пишем ПО с нуля. Для создания ПО, точно так же, как для и сборки пазла, нужно время и инкрементные усилия. Инкрементность может возникнуть из-за изменений в требованиях или же из-за новой фичи или исправления ошибки.

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

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

Не спешите.

Двигайтесь медленно, чтобы завершать быстрее.

▍ D означает Decoupled («несвязный»)

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

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

Отвязывайте зависимости от системы. В прошлом я освоил архитектурный шаблон Entity-Control-Boundary, основанный на гексагональной архитектуре.

Мне он нравится.

Настолько сильно, что при помощи этой методики я разработал Cloudgenda. Я соло-разработчик этого SaaS-проекта и уверен, что могу быстро и непрерывно повышать ценность системы для клиентов благодаря тому, что ни одна из зависимостей не связана напрямую с внешними сервисами. На самом деле, каждая зависимость открыта и обрабатывается через объект Port and Adapter и реализуется с инъецированием зависимостей через конфигурацию. Благодаря этому, я могу очень легко тестировать свою кодовую базу и при желании рефакторить. К тому же с ней приятно работать.

Всё это рука об руку идёт с буквой D из принципов SOLID, которая расшифровывается как Dependency Inversion Principle (принцип инверсии зависимостей). Но этот принцип также можно применить к изолированию таблиц баз данных при их денормализации. Или когда вы правильно используете парадигму объектно-ориентированности, выбирая в некоторых случаях композицию вместо наследования. Мы можем назвать это «логическим изолированием», но преимущества этого такие же, как и при «физическом изолировании».

▍ В заключение

На моих часах уже 23:30, и я уже достаточно устал, чтобы идти спать.

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

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

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

Умные программисты пишут STUPID-код - 2

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

Вы умны. А умные программисты пишут STUPID-код, потому что это умный способ писать код.

Автор:
ru_vds

Источник

  1. dasha:

    замечательный текст) все так понятно и в то же время красиво написано

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js