Привет, Хабр! Наши коллеги из beeline cloud подкинули интересную статью для перевода про разработку на PHP, плохие практики и не только. Это история о том, как правила чистого кода могут подорвать его фактическое качество. Материал содержит много рассуждений на эту тему и будет полезен всем, кто только начинает свой путь в разработке. Приятного чтения! Недавно я искал новую работу, тщательно просеивая море вакансий, каждая из которых стремилась привлечь к себе внимание и побудить кандидата отправить резюме. В потоке бесчисленных и одинаковых объявлений одно предложение действительно выделялось. Оно было написано как-то иначе. По-особенному, без всего этого рекламно-продающего посыла. Компания искала не просто разработчика, ей нужен был настоящий мастер своего дела. «Мы ценим чистый код», — заявляли они. На краткий миг я испытал искреннюю радость. Но, как всегда, уже в следующем абзаце обнаружился подвох: «Каждый класс, который мы пишем, ограничивается сотней строк». Для понимания, мой основной язык — PHP, а вакансия предназначалась как раз для PHP-разработчиков. И здесь я бы хотел заметить, что определить на глаз оптимальный размер класса не так уж просто. Каждый язык программирования имеет свои нюансы и особенности. Существуют слабо типизированные и сильно типизированные языки. Одни поддерживают многопоточность, другие — однопоточные. Список можно продолжать еще долго. Кроме того, существуют еще и стандарты. Уже почти десять лет я не сталкивался с Java, но, если я правильно помню, там принято помещать открывающую скобку в конец строки. В PHP же принято выносить эту скобку в отдельную строку. Вот простой пример: На первый взгляд, эти фрагменты несут одинаковую функциональность. Но, если следовать стандартам кодирования обоих языков, версия для PHP окажется длиннее, чем ее аналог для Java. И это даже без учета дополнительных строк, таких как импорты, комментарии и пропуски строк для улучшения читаемости — все это способствует увеличению длины класса. Вы скажете, что к длине класса такие вещи не имеют отношения. Но кому-то может всерьез показаться, что раз уж пустые строчки есть в файле, их тоже надо учитывать. Что случится, если связать разработчику руки строгим правилом — не более ста строк кода на файл? Давайте посмотрим на возможные результаты. Определение функции в PHP, по стандарту, требует не менее четырех строк — одна для заголовка функции, две для открывающей и закрывающей скобок, и, по крайней мере, еще одна смысловая строка в теле. Если количество строк ограничено, возникает соблазн сэкономить место за счет написания избыточно сложных функций. Кроме того, можно запросто свалиться в пропасть сомнительных стратегий, подходов и методов. Вы спросите, каких? Вот мой «любимый» способ сэкономить место в файле: длиннющие и чрезмерно сложные выражения в одну строку. Приведу здесь фрагмент из моей интеграционной библиотеки. Это часть класса, отвечающего за создание и управление доступом к удаленным ресурсам: Для понимания контекста, Address в моей системе предусматривает такие параметры, как {id} в https://example.com/articles/{id}. Код проверяет, содержит ли экземпляр Address допустимые параметры. Здесь есть весьма понятный PHPDoc (кстати, он еще в процессе разработки), а сам код прост в освоении. Он перебирает все указанные имена и проверяет, что каждое из них существует и является корректным. В противном случае возвращается false. Если оператор if не выдаст true, то на выходе тоже будет true. А для экономии места я мог бы написать вместо этого такой код: Ура, мы сэкономили 5 строчек! Зацикленность на длине класса попросту контрпродуктивна. Вместо того, чтобы направить свою энергию на создание высококачественных компонентов, разработчики считают строки и придумывают костыли, чтобы уложиться в отведенные рамки. Хотя кто-то может возразить, что процесс подсчета строк можно автоматизировать, это обоюдоострый меч. Автоматизация может непроизвольно поспособствовать развитию дурной практики, поскольку разработчику наверняка захочется перехитрить систему. Даже если она призвана обеспечить соблюдение лучших практик на свете, это будет вечная игра в кошки-мышки; разработчики будут придумывать новые способы обхода действующих правил, чтобы сэкономить время. При этом не стоит забывать, что автоматизация должна либо каким-то образом срабатывать отдельно, либо быть частью конвейера CI/CD. Так или иначе, у разработчиков не будет мгновенной обратной связи по соответствию кода внутренним стандартам, а это еще один камень в огород производительности их труда. Принудительное разбиение классов на составные части иногда может привести к непреднамеренному созданию того, что я люблю называть «крысиным королем»: клубка из крошечных классов, которые не могут жить друг без друга. Это, пожалуй, самая распространенная проблема, и она требует к себе пристального внимания. При наличии одного исчерпывающего класса пользователям необходимо знать только об этом классе. Однако если разбить его на множество мелких, тесно связанных между собой классов, пользователям придется знать о них всех. Это удобно, потому что каждый компонент можно заменить. Это оправдано, но только в том случае, если вы на самом деле планируете что-то заменять. Джон Оустерхаут обращает на это внимание в разговоре о старой системе обработки ввода-вывода в Java. Чтобы эффективно считывать сериализованные объекты из файла, раньше приходилось инстанцировать три вложенных объекта. При этом с первыми двумя практически никогда не нужно было взаимодействовать в явном виде. Эта проблема часто возникает из-за злоупотребления принципом единой ответственности. Попытка разбить большой класс на множество мелких может привести к созданию классов, которые сами по себе бесполезны. Установление жесткого ограничения на длину класса может еще сильнее подтолкнуть к такой архитектуре. Подсчет строк в классе сложно качественно отслеживать. Кроме того, он фактически ничего не говорит о качестве самого кода, только о его длине. Безусловно, большое количество строк может послужить своеобразным маркером — сигналом к тому, что код нуждается в рефакторинге. Однако решения о рефакторинге, основанные только на длине, должны приниматься с осторожностью. Возьмем в качестве примера класс Model в Laravel. Он насчитывает более 2,4 тыс. строк кода. Несмотря на то, что это может показаться огромным объемом, он намеренно спроектирован таким образом. Такой подход гарантирует, что разработчики смогут extend'нуть базовый класс Model, и вуаля, их собственная модель работает без лишних усилий. При написании кода в первую очередь следует обращать внимание на его удобство, а не на длину. Старайтесь делать вещи, с которыми пользователь будет работать чаще всего, как можно проще. Эта статья написана под влиянием моего личного опыта и книги Джона Оустерхаута «Философия проектирования программного обеспечения». Эта книга посвящена глубокому изучению вопросов создания хорошего кода и является обязательной к прочтению для всех, кто всерьез занимается разработкой программного обеспечения. beeline cloud — secure cloud provider. Разрабатываем облачные решения, чтобы вы предоставляли клиентам лучшие сервисы. Больше материалов о разработке читайте здесь: От AxonIQ до микросервисов: через грабли к звездам Перевели крупный холдинг с монолита на микросервисы и сразу увидели улучшения Зачем выбирать архитектуру фронтенда: советы от опытного разработчика Стоит ли переходить с монолита на микросервисы: опыт разработчика в финтехе