Пишите код, который легко удалять, а не дополнять

Автор оригинала: tef
  • Перевод
image«Всякая строка кода рождается без причины, продолжается в слабости и удаляется случайно», — Жан-Поль Сартр программирует на ANSI C.

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

Чем больше у вашего API пользователей, тем больше кода приходится переписывать для введения новых изменений. Верно и обратное: чем больше вы полагаетесь на сторонний API, тем больше проблем испытываете когда он изменяется. Упорядочивание взаимодействия и взаимосвязей разных частей кода является серьезной проблемой в больших системах. И по мере развития проекта, растет и масштаб этой проблемы.

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

Я говорю о том, что если уж мы так хотим считать количество строк кода, нам следует смотреть на них не как на «произведенные строки», но как на «потраченные строки», — Э. Дейкстра, рукопись 1036.

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

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

Шаг 0: Не пишите код


Количество строк кода само по себе мало о чем говорит, а вот эффект от 50, 500, 5 000, 10 000, 25 000 строк и т. д. отличается существенно. Монолит размером в миллион строк попортит вам больше нервов, чем структура в 10 тыс. строк. Если же говорить о времени, деньгах и усилиях, которые вам придется потратить на его замену, то здесь разница будет ощущаться гораздо сильнее.
Чем больше у вас кода, тем сложнее от него избавиться. Тем не менее, сохранение одной строчки кода не дает никаких результатов само по себе. Как бы то ни было, удалять проще всего такой код, от которого вы успели отказаться еще до того, как приняться за его написание.

Шаг 1: Пользуйтесь копипастой


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

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

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

Шаг 2: Не пользуйтесь копипастой


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

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

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

Шаг 3: Пишите больше boilerplate-кода


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

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

Шаг 4: Не пишите boilerplate-код


Бойлерплейты лучше всего работают, когда предполагается, что библиотеки будут соответствовать самым разным вкусам разработчиков, но иногда такой подход приводит к чрезмерной избыточности. Тогда наступает время поместить вашу гибкую библиотеку внутрь другой, которая обладает своими взглядами на правила, схемы и состояния. Создание простых в использовании API заключается в превращении вашего boilerplate в библиотеку. И это не такая уж и редкость, как вы могли бы подумать. В качестве примера можно привести один из самых популярных и любимых http-клиентов для Python, requests, который успешно справляется с предоставлением простого интерфейса, работая на основе более избыточной библиотеки urllib3. Requests позволяет пользоваться многими типовыми схемами работы с http, скрывая большинство подробностей от глаз пользователя. В то же время urllib3 выполняет конвейеризацию, управление соединением и ничего от пользователя не прячет.

Дело здесь не столько в том, чтобы скрывать какие-то подробности, помещая одну библиотеку внутрь другой, сколько в разделении ответственности: requests можно сравнить с турагентством, которое дает на выбор путевки для популярных в мире http путешествий, тогда как urllib3 нужна, чтобы удостовериться, что у вас есть все необходимое, чтобы это путешествие прошло как надо.

Нет, я не призываю вас немедленно пойти и создать директории /protocol/ и /policy/. Однако, возможно, это станет необходимостью, ведь вы наверняка захотите содержать вашу util-директорию свободной от всякой бизнес-логики и при этом продолжать работать над созданием своего тандема библиотек. Вы вполне можете работать над ними параллельно, не дожидаясь, пока работа над базовой библиотекой будет завершена.

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

Разграничение ответственности позволяет нам порадовать некоторых пользователей, не перекрывая кислород другим. Деление на уровни легче всего делать, когда у вас изначально есть хороший API, однако написание хорошего API поверх плохого едва ли придется вам по вкусу. Хорошие API проектируются с учетом того, как их будут видеть пользователи (т. е. программисты), и создание иерархии в этом смысле означает понимание того, что вы не можете угодить всем одновременно.

Смысл разделения кода на уровни состоит не столько в том, чтобы написать код, который вы впоследствии сможете удалить, сколько в том, чтобы сделать трудноудаляемый код приятным в использовании (не загрязнять его бизнес-логикой).

Шаг 5: Напишите большой блок кода


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

Бизнес-логика — это бесконечная серия пограничных случаев, а также быстрых и грязных трюков. И это нормально. Меня это устраивает. Другие стили вроде «игрового кода» и «кода основателя» представляют собой то же самое: попытка срезать на поворотах, чтобы сэкономить значительное количество времени.

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

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

Нет, я не предлагаю вам писать одну и ту же ерунду по десять раз, пытаясь исправить все ее ошибки. Я говорю о другом. Как сказал когда-то Алан Перлис: «Все должно создаваться сверху вниз, за исключением первого раза». Не бойтесь совершать новые ошибки, брать на себя новые риски и пусть медленно, но верно, с помощью итерации продвигаться вперед.

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

Шаг 6: Делите код на части


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

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

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

К сожалению, некоторые проблемы оказываются связанны друг с другом теснее, и их бывает сложнее отделить от других. Несмотря на принцип одной ответственности, который гласит, что «каждый модуль должен решать только одну сложную проблему», на деле гораздо важнее, чтобы «решением каждой сложной проблемы занимался только один модуль». В случаях, когда модуль занимается сразу двумя вещами, это происходит, потому что изменение одной части требует изменения другой. Работать с одним ужасным, но простым в плане интерфейса компонентом часто бывает проще, чем с двумя компонентами, требующими тщательной координации друг с другом.
«Я не стану пытаться сейчас точнее определить материал, подпадающий под это краткое описание [«слабая связанность»]; возможно, я никогда не сумею дать этому внятное определение. Однако я знаю, когда вижу, и кодовая база, рассматриваемая в этом деле, не такая». — Судья Верховного суда США Стьюарт.

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

В продуктах Microsoft Windows, к примеру, для этих целей используются внешние и внутренние API. Внешние API привязаны к жизненному циклу десктопных программ, а внутренний — к ядру, на основе которого они работают. Скрытие этих API дает Microsoft гибкие возможности по внесению в систему изменений без какой-либо опасности сломать кучу программ в результате этой деятельности.

HTTP также содержит примеры слабой связанности: добавление кэша перед HTTP сервером, перемещение изображений в CDN, в результате которого изменяются лишь ссылки на них. Ни тот, ни другой механизм не ломают ваш браузер. Другой пример слабой связанности — применяемые в HTTP коды ошибок. Общие для серверов по всему вебу проблемы имеют свой уникальный идентификатор. Когда вы получаете 400 ошибку, вы знаете, что выполнение тех же операции, которые к ней привели, никак не изменит ситуацию. А вот в случае с 500 ошибкой повторная перезагрузка страницы может все изменить. HTTP-клиенты могут обрабатывать множество ошибок, избавляя программистов от необходимости делать это самостоятельно.

Следует учитывать, как ваше ПО будет обрабатывать ошибки, когда вы будете раскладывать его на более малые части. И, конечно же, об этом тоже легче говорить, чем делать.
«Я решил, хоть и с большой неохотой, использовать LATEX».— Джоуи Армстронг. Создание распределенных систем, надежно работающих при наличии в них программных ошибок. 2003 г.

Erlang/OTP весьма уникален в плане способа обработки ошибок, который называется «деревья контроля». Говоря в общих чертах, каждых процесс в Эрланг-системах запускается и наблюдается супервизором. Когда процесс сталкивается с проблемой, он прекращает свою работу, после чего сразу же перезапускается супервизором. Что же касается самих супервизоров, то они запускаются начальным процессом, который также осуществляет их перезапуск, когда со сбоем сталкиваются уже они.

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

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

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

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

Вместо UUIDs, IMAP генерирует уникальный токен для идентификации каждого сообщения. Последний также может измениться прямо во время выполнения другой операции. Многие операции можно поделить на части. Потребовалось 25 лет для изобретения способа, который позволял бы надежно перемещать электронные письма из одной папки в другую. И, конечно, нельзя не отметить применения в нем весьма специфичных кодировок UTF-7 и base64.Нет, я ничего не выдумываю.

Для сравнения: как файловая система, так и база данных представляют собой гораздо лучшие примеры удаленного хранилища. Файловая система предлагает фиксированный набор операций, однако набор объектов, над которыми вы можете их производить, велик и весьма разнообразен. Может показаться, что интерфейс SQL обладает более широкими по сравнению с файловой системой возможностями. Тем не менее, он использует ту же схему работы: есть некоторое количество операций для работы с набором данных и огромное количество строк, над которыми эти операции проводятся. И хотя вы не всегда можете сделать замену одной базы на другую, найти решения, которые работали бы с SQL гораздо проще, чем аналогичные решения для любого кустарного языка запросов.

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

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

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

Слабосвязанный код совсем необязательно легко удалить, однако заменить его или внести в него изменения всегда значительно легче.

Шаг 7: Продолжайте писать код


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

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

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

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

Feature flag — непросто параметр командной строки. Это способ разделения feature-релизов от объединяемых ветвей или от основного кода. Возможность поменять свое решение прямо во время работы программы становиться все более важным в условиях, когда выпуск нового ПО может занимать часы, дни или недели. Спросите любого главного инженера по отказоустойчивости, и он скажет вам, что если система «будит» вас посреди ночи, значит она определенно должна предусматривать внесение изменений по ходу работы.

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

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

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

image
PayOnline
0,00
Система электронных платежей
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

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

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

    +11
    Раз уж упомянули Сартра, то я упомяну и Экзюпери: "Как видно, совершенство достигается не тогда, когда уже нечего прибавить, но когда уже ничего нельзя отнять."
      +11
      Пожалуй, что это лучшая статья о программировании за начало этого года на Хабре.
        +1
        Напоминает известный манифест http://macode.ru.
          +3
          Эта статья скорее противоположность этому популистскому призыву.
          –4
          Вроде начали за здравие — а закончили за упокой) Местами странные рекомендации; пишите код — не пишите код, копипастите — не копипастите.
          Но в целом направление верное — меньше кода, более простой код и меньше зависимостей(в том числе и от библиотек).
            +4
            Не писать код — предельный случай стремления писать мало кода.
            Наконец, 8-й шаг: когда-то я был программистом...
              0
              В том-то и дело. Можете всегда игнорировать тех, кто даёт совет применимый всегда ( :) ).
              В разных ситуациях наилучшими могут оказываться противоположные действия. К сожалению многие у нас любят догмы.
              +7
              Посыл статьи — напишите кое как, потом исправляйте, а потом удалите к х… м ))
                +2
                Руководство по ремонту дома от Tom Smykowski.
                Шаг 0. Не делайте ремонт.
                Шаг 1. Используйте самые дешевые материалы.
                Шаг 2. Теперь переделайте все, используя дорогие материалы.
                Шаг 3. Сделайте все быстро и тяп-ляп.
                Шаг 4. Теперь все сломайте и переделайте как надо.
                Шаг 5. Сделайте настил на пол из цельного куска ДСП.
                Шаг 6. Отдерите настил, распилите на доски и прибейте их по отдельности.
                Шаг 7. Заготовьте краску и доски для будущего ремонта.
                Как-то так.
                Не понятна основная идея: зачем мне два раза писать один и тот же код — сначала плохо, а затем хорошо, если я сразу в состоянии сделать хорошо? И да, рефакторить код время от времени необходимо, удаляя лишнее. Это не для кого не секрет. Только зачем это делать со всем написанным кодом?
                  +3
                  Только зачем это делать со всем написанным кодом?

                  Никто не требует делать это со всем написанным кодом.

                  Так, в самом начале 2 пункта указано, когда его (пункт) применять:
                  Как только вы заметите, что скопипастили какую-то часть программы достаточное количество раз, значит, возможно, пришло время написать на ее основе функцию.

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

                    Насколько я помню это из Рефакторинга от Фаулера.

                    Скопировал 1 раз норм, если 2 раза то выдели метод.
                      0
                      Написать лапшу а потом рефакторить тоже от Фаулера, а вообще тут от него вся статья.
                        0
                        Может я не верно понял Фаулера, но по моему мнению, он не говорил пишите лапшу. Он давал советы что делать с лапшой и как определить лапша или уже блюдо.

                        Но тогда я не понимаю зачем писать статью которая цитирует то же, но как бы с другой стороны. И упуская некоторые вещи?
                          0
                          Да, советы вполне в стиле Фаулера.
                          Насчет причин… они могут быть разными.
                          Возможно, автор не читал Фаулера.
                          Возможно, автор не помнит, что именно он прочел.
                          Возможно, автор просто осознал, что именно он делал уже 3\5\7\42 лет, и решил поделиться этим.
                          Возможно, автор захотел написать отличную статью, путем (относительно) простого рерайта.
                          Возможно, автор захотел добавить связности в книгу Фаулера. В ней, как правило, описываются типовые ситуации и пошаговый способ излечения. В статье же есть некая общая нить, как код из одного состояния переходит в другой.
                            0
                            > Может я не верно понял Фаулера, но по моему мнению, он не говорил пишите лапшу.
                            Вообще это от Бека если быть точным, спустя годы многое выветрилось из головы, поэтому я помню только что читал об этом в первый раз именно в книге Фаулера. Фаулер же говорил что можно брать более менее приемлимое решение и писать его. По мере написания становятся очевидны какие то просчеты и тогда можно используя рефакторинг устранить их.

                            > Но тогда я не понимаю зачем писать статью которая цитирует то же, но как бы с другой стороны. И упуская некоторые вещи?
                            Здесь я с вами согласен, несмотря на то что в статье есть хорошие советы, в целом это перефразированное вырезанное содержание книг типо Рефакторинга(первых 40%) и Совершенного кода.
                      +6
                      Мне кажется, это по-другому переформулированные правила agile, которые позволяют избежать преждевременной фиксации API и библиотек, что в свою очередь приводит к over-инжинирингу. Сначала надо написать код, который покажет нам как он будет использоваться в реальности — потом переписать его в соответствии с этим знанием. Не оформлять в библиотеку код до того, как мы поймем, что он нужен в библиотеке. Ну и так далее.

                      С ремонтом, когда делаешь сам первый раз, оно почти так всегда и получается. Сначала делаешь как умеешь и как получится, потом, поняв технологию и нюансы, переделываешь как надо. Покупаешь самые дешевые материалы чтобы сэкономить, потом понимаешь, в чем засада и что тебе точно нужно — и выбираешь дорогой материал по его параметрам, а не по цене. Ну и так далее.
                        +1
                        Ну да, вцелом тезис понятный, но многое спорно. Если удается выделить функциональную единицу, почему бы ее сразу не оформить ввиде отдельного модуля, компонента или библиотеки? Изначально сделанный дизайн системы (в соответствии с правилами слабой связанности и делегирования ответственности) и правильно выбранные абстракции упрощают разработку, тестирование и поддержку кода. И ничего не вижу плохого в том, что дизайн и код будут эволюционировать. Главное всегда уметь выявить зависимости, чтобы знать какой код затронет каждое изменение (поэтому я и не пишу на языках с динамической типизацией). Оверинжиниринг случается не из-за модульного дизайна, а когда люди пытаются абстрагироваться от решаемой задачи, поставив свой модуль как саму цель, а не как часть конкретного решения. И тогда да — появляется куча ненужных методов «на будуще» и абстракций для «расширения функционала».

                        С ремонтом подразумевается, что ты профессиональный мастер и что далеко не первый дом делаешь. А переделывать приходится когда резко меняются функциональные реквизиты клиента (теперь это будет не дом, а гараж), либо когда этих изменений накапливается такое большое количество, что старый дизайн системы уже не имеет смысла. И тогда созревает новый релиз 2.0, который пишется фактически с нуля, учитывая новые реквизиты. И да, старая ветка идет в помойку. Практически вся.
                          0
                          Если удается выделить функциональную единицу, то это совершенно не означает, что она кому-то понадобится еще и что тот API, который будет для нее создан (а обычно это первый-второй пришедший в голову интерфейс, позволяющий более-менее эффективно решить задачу) будет помогать тем, кто будет это дело использовать.

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

                          Кроме того, если код достаточно сложен и его много, то сколько не проектируй, выделить и предусмотреть все потенциальные зависимости очень сложно, не говоря уже о тех местах, которые надо будет расширить. Тем более, если код старый, то часто бывает, что слабая связанность и делегирование во времена его создания не сильно ценились его создателями, и теперь мы имеем дело с тем что имеем, а переписать/отрефакторить миллион строк кода, которые являются технологическим ядром компании, нельзя. Статическая типизация тут меняет не много, я пишу на С++, куда уж статичнее?
                      0
                      Промахнулся
                        0
                        Чтобы легко удалять код, надо писать его как можно более понятно и просто. Тогда в проекте не будут появляться магические места вида «тут водятся драконы», о которых никто не знает зачем они и как работают, поэтому не рискуют трогать. Скучно, но правда.

                        А статья рассчитана на «вау-импульс» и учит плохому.
                          +2
                          Статья учит тому, что можно умеренно отходить от правил ради экономии, если ты строго понимаешь что ты делаешь.
                          Черт, я могу написать метод на 50 строк и никто не умрет. Потом через недельку порежу на парочку до 20 строк. Или не порежу, если дедлайн и времени на рефакторнг и ревью нет. Если это модуль который в условиях активного изменения и может вообще улететь, то там еще и сам код будет попахивать. Но это не значит что можно писать как в опенкарт контроллеры из одного метода на тысячу строк и говорить что "Мы true MVC".

                          Собственно статья и пытается провести эту грань, где "немного попахивает" это нормально, и экономия, а где оно уже не немного, и вообще ахтунг, и технический долг будет стоить кучу рессурсов потом. Но соглашусь что статья несколько корява, и доносит мысль с трудом.
                            +1
                            Субъективно. Зависит от сферы работы программиста. Наверное, если это какой-нибудь бизнес-софт и надо сделать «сейчас или никогда» — то такой подход приемлим. Но вы будете не рады, если придётся жить с этим кодом дальше.

                            > дедлайн и времени на рефакторнг и ревью нет
                            Хреновый менеджемент.
                              +1
                              От сферы зависят лишь детали.
                              Технический долг это долг и есть.
                              И работать с ним нужно как с финансовым.
                              Да, он сложно детерминируется, его сложно оформить простыми четкими цифрами, но это долг.
                              Плохо быть "в долгах как в шелках". Но разумное использование кредитов дает нехилое плече для развития.
                              Также и тут. Быстрое прототипирование может ускорить проектирование, ускорить разработку, начать тестирование функционала раньше и т.п. Что в совокупности даст огромный профит, который уже можно тратить на возврат долга (рефакторинг).
                              Это работает в любой области.
                              Даже если ты пишешь прошивку для марсианского ровера, ты можешь в глубокой альфе наговнокодить, если это будет РАЗУМНО, и позволит потом отрефакторить, а не переписывать с нуля потратив еще больше усилий ведь нужно сохранять совместимость.

                              оффтоп:
                              сейчас в оффлайне с бывшим партнером идет жесткий файт за ключевого клиента. Мой основной козырь это неограниченный (по сравнению с конкурентом) кредитный ресурс позволяющий кредитовать клиентов и т.п. Я очень надеюсь что это будет фатальный аргумент)
                              оффтоп2: недавно столкнулся с проблемой, что когда наполняли портфолио по ИТ-проектам, то у нас была большая проблема по лоуэнд проектам. Вроде как их по количеству больше всех, но и смертность у них выше, большинство не проживают и двух лет. Конечно еще фактор того, что дешевые клиенты экономят на всём, и многие не хочется показывать и говорить "это сделали мы", но тем не менее. Под жирные вещи сразу нашлись проекты на которые договоренности не запрещали ставить свои копирайты, а на мелочи пришлось думать. Это я к тому что мне не будет стыдно за говнокод под капотом тех мелких проектов которые уже умерли. И именно об этом и статья. Делай рефакторинг когда он нужен, и не более.
                            +1
                            Ничего вы не понимаете в ипотека-стайл кодинге
                            0
                            https://www.youtube.com/watch?v=csyL9EC0S0c

                            Небольшая лекция на EMF2012 от автора статьи.

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

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