Программирование
Не пишите повторно используемый код
Эта статья о том, как избежать распространенной ловушки программирования и, как это ни парадоксально, это также руководство о том, как добиться повторного использования кода, не прилагая никаких усилий для этого.
Повторно используемый (Reusable) код часто является целью как для разработчиков, так и для руководителей. Директора и вице-президенты много раз говорили мне, что у нас есть «проблема повторного использования», и нам нужно больше кода, который можно использовать повторно. Принцип DRY (не повторяйтесь) часто используется для объяснения того, что нужно писать переиспользуемый код. Но по моему опыту, некоторые из наиболее опасных и сложных в сопровождении участков кодов были написаны как раз с учетом повторного использования кода.
Я не пишу повторно используемый код и активно отговариваю от этого других разработчиков. Это не означает, что мой код нельзя использовать повторно. На самом деле, мой код во многих случая используется и повторно. Эта статья о том, как избежать распространенной ловушки программирования и, как это ни парадоксально, это также руководство о том, как добиться повторного использования кода, не прилагая никаких усилий для этого.
Переиспользование кода — результат
Повторное использование не проблема — это результат. Мне никогда не удавалось определить «проблему повторного использования» или получить подробности о ней от тех, кто считает, что она существует. Я полагаю, что когда люди говорят, что у них есть «проблема повторного использования», на самом деле у них проблема с низкой производительностью или высокой стоимостью поддержки. По иронии судьбы, попытка принудительного повторного использования кода, скорее всего, усугубит обе эти проблемы. Вполне возможно, что низкая производительность и большие проблемы с обслуживанием вызваны принудительным повторным использованием кода.
Я считаю, что причина, по которой так много разработчиков и руководителей выступают за повторное переиспользование, заключается в том, что они видели успешные кодовые базы, которые содержат значительное количество повторно используемого кода. Отсюда делается ложное предположение, что код изначально был написан для повторного использования. Но это, вероятно, не то, что произошло. Создание переиспользуемого кода является побочным эффектом написания лаконичного кода, решающего четко определенную и конкретную проблему.
Повторное использование — предположение о будущем
Код никогда не должен писаться для повторного использования. Это в корне плохая идея. Фундаментальная проблема с написанием повторно используемого кода заключается в том, что нет шаблона или определения того, как это делать. Повторное использование — это следствие, а не шаблон проектирования. Код, который написан для повторного использования, обычно будет написан с предположениями о будущем и/или он будет написан с конфигурациями, чтобы его поведение могло измениться для решения нескольких вариантов использования. Оба эти подхода являются антипаттернами.
Предположения о будущем, которое вы не можете контролировать, редко срабатывают. Даже если у вас есть опыт решения проблемы и хорошо продуманные представления о будущем. Вы не можете контролировать внешние влияния, которые будут определять будущее. Компании постоянно реорганизуются, команды распадаются или объединяются, появляется новое руководство, часто очень самоуверенное руководство. На сцену выходят новые технологии, и компании адаптируют свои бизнес-цели к постоянно меняющемуся окружающему миру. Если вы посмотрите на кодовую базу, которая используется в компании более года, вы, вероятно, найдете и мертвый код, и конфигурации, которые были предназначены для использования в будущем, но так и не были реализованы.
Написание кода с конфигурациями часто является самым опасным и вредоносным кодом, который только можно представить. Часто достигается некоторый уровень переиспользования через силу, что одновременно снижает производительность и усложняет поддержку. Конфигурируемый код подвержен ошибкам, поскольку он создает несколько точек отказа и может быть трудно понять, какие конфигурации допустимы. Конфигурируемый код сложно поддерживать, поскольку необходимо учитывать каждый вариант использования. Это особенно вредно, так как разработчики часто могут творчески подходить к использованию кода и часто неправильно использовать код непреднамеренным образом. Вероятным результатом такого повторного использования кода является классический «спагетти-код», в котором улучшение или исправление ошибки приводит к появлению одной или нескольких новых ошибок. Это часто приводит к созданию кодовой базы, в которую разработчики и руководители боятся вносить изменения.
Пишите простой код, а он уже будет переиспользуемым
Код должен быть написан для решения небольшой и конкретной проблемы. Чем меньше и конкретнее проблема, тем лучше. Это приведет к легкому сопровождению кода, который может развиваться по мере развития проблемы, которую он решает. Этот тип кода прост для понимания, и разработчикам трудно творчески и непреднамеренно использовать его не по назначению.
Переиспользование кода происходит при повторном возникновении проблемы. Когда проблема возникает снова, код можно повторно использовать для ее решения. Если проблема не возникает снова, код все еще необходим для решения старой проблемы. Таким образом, нет необходимости прилагать какие-либо усилия для определения, случится проблема второй раз или нет. Разработчикам и руководителям нужно сосредоточиться только на понимании проблемы и написании простого и лаконичного кода для решения этой конкретной задачи. Повторное использование кода будет происходить естественным образом по мере повторного возникновения проблем.
Не создавая повторно используемый код, вы будете удивлены тем, сколько повторного использования кода вы создадите.
Практический пример: Spring Framework
Исходники: https://github.com/spring-projects/spring-framework
Вот десять наиболее повторно используемых классов в кодовой базе Spring Framework, определяемых операторами импорта.
- 1,279 Assert.java
- 491 StringUtils.java
- 403 Лог.java
- 365 LogFactory.java
- 289 ObjectUtils.java
- 299 ClassUtils.java
- 252 HttpHeaders.java
- 222 CollectionUtils.java
- 204 MethodParameter.java
- 197 MediaType.java
Каждый из этих классов решает небольшую и специфическую задачу. Большинство конструкторов и методов просты и принимают только один или меньше аргументов. Ни один из этих классов не делает предположений о будущем Spring Framework. Ни один из этих классов нельзя настроить таким образом, чтобы они могли решать несколько вариантов. Каждый класс решает проблему, которая повторяется в кодовой базе.