Распространенной проблемой среди программных проектов является все более растущее время для поддержки и добавления новых функций. Баланс между добавлением новых функций и исправлением ошибок со временем меняется. В совершенно новом проекте все сводится к реализации новых идей, но со временем код замедляет нас. Это связано со всеми (небольшими) решениями, которые были приняты на протяжении всего проекта: сложный эффект.

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

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

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

Степень 1 процента¹

За 110 лет британские велосипедисты ни разу не выиграли Тур де Франс. Их результаты и репутация стали настолько плохими, что один из ведущих производителей велосипедов отказался продавать им велосипеды, потому что они боялись плохой огласки. В какой-то момент британцы решили нанять Дэйва Брейлсфорда. Тех, кто придерживался стратегии, он назвал: «агрегирование маржинальной прибыли». Он посмотрел на все аспекты езды на велосипеде и попытался улучшить все только на 1%. Поначалу было мало что замечать, но после 5 лет незначительных улучшений результаты начали усугубляться. Британские велосипедисты «внезапно» завоевали 60% всех золотых медалей на Олимпийских играх 2008 года, установили 9 олимпийских рекордов и 7 мировых рекордов и выиграли Тур де Франс 5 раз за 6 лет. За десять лет они выиграли 178 чемпионатов мира и 66 золотых медалей Олимпийских или Паралимпийских игр.

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

Теория разбитого окна³

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

Так в чем же дело? Это всего лишь разбитое окно. Однако именно здесь начинает проявляться сложный эффект. Люди, идущие по ночам, могут подумать, что не так уж и плохо нанести какие-то граффити на здание, ведь это все равно не используется, верно? Окно уже разбито, насколько оно может быть плохим? Но теперь, с разбитым окном и граффити на стенах, вероятно, не займет много времени, пока другое окно будет разбито, будет добавлено больше граффити, и это может даже открыть двери для скваттеров, чтобы занять здание. Чем хуже внешний вид здания, тем больше неприятностей оно вызовет, люди могут и вовсе начать избегать этой улицы. В других магазинах на улице меньше покупателей, и они тоже могут уйти! Затем со временем все становится все хуже и хуже; это тоже сложный эффект.

Программное обеспечение для компаундирования

То же самое происходит с программными приложениями. Нас поручают работать над проектом, который находится в ужасном состоянии; трудно читать, непроверено и сложно изменить. Если нам нужно исправить мелкую ошибку, мы, как правило, чувствуем, что это слишком много, чтобы исправить ее. Исправление может занять 15 минут, но очистка и тестирование - остаток дня, если не больше. Так что соблазнительно применить исправление без тестирования и забыть о правиле бойскаутов: оставить код в лучшем состоянии, чем вы его нашли.

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

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

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

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

Альберт Эйнштейн однажды сказал:

«Сложные проценты - восьмое чудо света. Тот, кто понимает это, зарабатывает… тот, кто не… платит ».

Вы хотите заплатить за это, будучи непродуктивным, разочарованным и стоящим компании денег? Или вы, возможно, хотите заработать, работая продуктивно, счастливо и экономя деньги компании?

Разорвав круг вредных привычек и последовательно применяя хорошие, мы можем позволить сложному эффекту работать в нашу пользу. Делайте небольшие улучшения каждый день, чтобы со временем это усилилось. Точно так же, как это сделал Дэйв Брейлсфорд, когда помог британским велосипедистам выиграть множество гонок и установить новые мировые рекорды. «Совокупность маржинальных выгод» - вот все, что он сделал.

Японцы назвали бы этот подход: Кайдзено:

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

Плато скрытого потенциала

Конечно, преимущества такого подхода не всегда очевидны с самого начала. Это называется «плато скрытого потенциала».

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

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

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

С чего начать

Читаемость

Именование важно. Дайте классам, функциям и переменным хорошие имена. Будьте ясны и точны. Сделайте так, чтобы намерение выпрыгнуло наружу. Это также относится к концепциям более высокого уровня, таким как пакеты, модули и службы. Другое название этого: «Кричащая архитектура» ⁵. Это просто означает, что просто глядя на архитектуру, становится ясно, какова ее цель. Обязательно переименуйте любой текст, имя или заголовок, которые не понятны сразу, как только вы с ними столкнетесь. Сделайте код читаемым как книгу.

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

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

Расширяемость

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

Тестирование

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

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

Заключение

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

Источники

1 Атомные привычки - Джеймс Клир
2 Комплексный эффект - Даррен Харди
3 https://en.wikipedia.org/wiki/Broken_windows_theory
4 https: //en.wikipedia .org / wiki / Кайдзен
5 Чистая архитектура - Дядя Боб