Русский
Русский
English
Статистика
Реклама

Организация кода

Перевод Хватит организовывать код по типу файлов

06.06.2021 12:22:20 | Автор: admin

Какой самый популярный стиль организации кода вы встречали в корпоративных кодовых базах? Лично я чаще всего видел решение, подразумевающее группировку всех файлов по их типу. Таким образом, к примеру, в системе MVC все контроллеры, все сервисы, все репозитории, все POJO и так далее находятся вместе. Давайте назовем такое решение "стековым" стилем организации кода.

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

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

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

Неправильная абстракция

Люди не читают код по назначению файлов и классов. Никто никогда не говорит: "покажите мне весь API проекта" или "продемонстрируйте мне все запросы, отправляемые решением". Люди читают код, полагаясь на его смысл и роль. Как в системе управления гостиницами, например, люди отдельно думают о номерах, гостях, ценах и так далее.

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

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

Нарушения связи

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

Проблема этого аргумента в том, что он фокусируется на разделении, но полностью игнорирует потребность в связи между определёнными структурами. Допуская, что все файлы и классы определённого типа в такой системе расположены вместе, справедливо ли будет сказать, что их взаимная связь, как структур одинакового назначения, но разного смысла, нас устраивает? Положено ли все же, к примеру, контроллерам, находиться отдельно от своих классов и репозиториев? Можем ли мы позволить, скажем, всем репозиториям быть сильно зависимыми друг от друга, но отделенными от уровня сервисов? Очевидный ответ - НЕТ! Такой код стал бы хрестоматийным куском г*вна. Рефакторинг такой системы на более мелкие решения был бы абсолютным кошмаром, потому что вам пришлось бы отделить друг от друга все классы на каждом уровне стека. Это убивает основную цель использования стиля MVC.

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

Трудно менять

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

В "смысловом" стиле, если вы что-то меняете, вы вносите изменения только в пределах одной логической границы. Это облегчает внесение изменений, поскольку, меняя только один объект, мы работаем только в очень небольшой части кодовой базы.

Ограничивает выбор дизайна

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

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


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

Подробнее..

Как не закопаться в рефакторинге на фронте. Советы новичку

13.08.2020 22:14:38 | Автор: admin
С тех пор как вам доверяют не только кодить под строгим контролем, но и принимать даже минимальные решения, вы становитесь в полной мере ответственны за будущее проекта. В том числе, за стоимость его последующей поддержки. Имея опыт с действительно долгосрочными историями, мы собрали несколько советов о том, как не стрелять в ноги себе, своим коллегам и тем, кто придет на проект после вас.
Бывалым наши советы могут показаться очевидными. А вот новичкам настоятельно рекомендуем к прочтению. Потратьте время на воплощение этих идей в своих проектах, чтобы потом не тратить еще больше на бесконечный рефакторинг.
Сходные идеи можно высказать практически в любой сфере разработки, но мы будем говорить о них на примере проектов на React-е.

image



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

Задумайтесь о типизации


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

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

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

Разделите код на блоки, выделите логику


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

Очень наглядно польза от этого принципа была видна на проекте с большими формами, о котором мы недавно писали (http://personeltest.ru/aways/habr.com/ru/company/maxilect/blog/511322/). В том проекте проверки в блоках и видимость этих блоков изначально были связаны между собой. Но когда мы собрали всю связь полей в одном месте, отслеживать изменения логики стало гораздо легче. А главное мы смогли переиспользовать код в новом похожем проекте.

Единого стандарта на структуру проекта не существует тут придется опираться на свои знания. Есть два подхода, которые могли бы подойти для многих проектов: File Type First и Feature First.
Чтобы нащупать отправную точку для поиска структуры, удобной именно в вашем случае, рекомендуем обратиться к документации. Там обычно описаны best practice. Например, React и Redux в документации предлагают стандарты организации логики и файловой структуры проекта. При наличии определенного опыта можно экспериментировать и отклоняться от стандартов, если это позволяет обойти какие-то ограничения для конкретного проекта, но для большинства случаев в этом нет необходимости. И, конечно, не стоит забывать о таких базовых принципах, как SOLID. Неплохая статья о том, как применять эти принципы в React-е: http://personeltest.ru/aways/habr.com/ru/company/ruvds/blog/428079/. Хорошая статья о чистой архитектуре: http://personeltest.ru/aways/habr.com/ru/post/499078/.

По организации кодовой базы в React и связанным с этим вопросам есть неплохая, хоть и давно не обновляемая, подборка материалов: https://github.com/markerikson/react-redux-links/blob/master/project-structure.md.

Сформулируйте соглашение о коде


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

Придерживайтесь выбранной парадигмы


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

Помните о тестах


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

Отдельно хочется отметить интеграционные и end-to-end тесты.
Интеграционные тесты необходимо запускать каждый раз после исправления багов или добавления новых фич, чтобы убедиться, что корректировки ни на что не повлияли. Мы на своих проектах стараемся запускать их автоматом, когда заливаем результаты своей работы (мы это реализовали через hook). Не отработали тесты не стоит заливать изменения в проект. Сначала надо все поправить.

Но интеграционные тесты касаются только фронтенда. End-to-end тесты более медленные и проверяют взаимодействие приложения со всеми зависимыми элементами. Эти тесты имитируют действия пользователя. Тут мы ничего не мокируем, а действительно ждем ответов бэкенда и проверяем взаимодействия внутри всей экосистемы проекта, используя Cypress (в качестве аналога можем порекомендовать также Puppeteer).

Думайте перед обновлением, но не отказывайтесь от него


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

Обновления стоит воспринимать, как часть естественного порядка вещей. Но перед сменой библиотеки или обновлением фреймворка всегда необходимо проводить исследование. Подойдет ли вам новая версия? Как вообще организовать переход? И конечно, планировать все нужно заранее.
Обновления крайне сложны, если на проекте нет тестов. Даже маленькая библиотека по работе с датами может затрагивать самые разные части проекта, а ее обновление ведет за собой полное регрессионное тестирование. С ростом проекта это нельзя будет сделать качественно, имея в арсенале только ручные тесты.

А хорошо ли вы делаете сейчас?


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

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

Быть может, у вас есть свои советы? Оставляйте в комментариях!

P.S. Мы публикуем наши статьи на нескольких площадках Рунета. Подписывайтесь на наши страницы в VK, FB, Instagram или Telegram-канал, чтобы узнавать обо всех наших публикациях и других новостях компании Maxilect.

P.P.S. Заглавная картинка с прошедшего недавно архитектурного конкурса Playhouse Competition.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru