Эта статья была первоначально опубликована на https://www.blog.duomly.com/how-to-create-frontend-project-structure-that-scales-and-is-easy-to-maintain/

Введение в структуру внешнего интерфейса

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

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

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

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

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

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

React.js не дает много информации о структуре базы кода, как, например, Angular. Кроме того, установка дополнительных библиотек и плагинов, необходимых для приложения React.js, таких как Redux или React-Router, требует изменения исходной структуры для лучшей ремонтопригодности и масштабируемости. И как всегда, лучше сделать это в начале разработки, чтобы потом пытаться изменить, когда дедлайн близок.

Понимание потока приложения

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

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

На изображении я проиллюстрировал, что произошло в приложении React.js с Redux и React-Router в фоновом режиме. Как видите, когда пользователь взаимодействует с приложением, маршрутизатор показывает пользователю определенный вид с компонентами. Каждое представление может иметь более одного компонента.

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

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

Если мы знаем, как это работает, мы можем поговорить о шаблонах, используемых при разработке, а затем я расскажу вам о трех подходах к структурам папок в приложениях React.js.

Что такое плоская структура?

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

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

└── src
 ├── api
 │ ├── api.js
 │ ├── posts.js 
 │ ├── comments.js 
 ├── components
 │ ├── PostComponent.js
 │ ├── CommentComponent.js 
 ├── shared
 │ ├── ButtonComponent.js
 │ ├── ModalComponent.js
 ├── containers 
 │ ├── PostListContainer.js
 │ ├── CommentListContainer.js 
 |── actions
 │ ├── PostActions.js
 │ ├── CommentActions.js 
 ├── reducers
 │ ├── PostReducers.js
 │ ├── CommentReducers.js 
 |── App.js
 |── store.js

Давайте рассмотрим папки, которые у нас есть в корневом файле приложения, на примере плоской структуры.

Первая папка — api, где мы создаем код, отвечающий за вызовы API приложения. Внутри папки мы разделили код на файлы для конкретной функции.

Следующая папка — это папка components, куда мы без логики помещаем презентационные компоненты, в нашем случае это PostComponent и CommentComponent.

Как и в любом приложении, во всем приложении используются общие компоненты, поэтому общая папка оказывается полезной. Здесь мы можем разместить все повторно используемые компоненты, такие как кнопки.

Затем идет папка Containers. Контейнеры в React.js — это компоненты, которые могут состоять из других компонентов и логики. В нашем примере PostListContainer будет иметь внутри PostComponent.

Далее у нас есть две папки из Redux, actions и reducers, и в каждой из папок мы размещаем файлы action и reducer в соответствии с функциональностью.

Файлы App.js и store.js помещаются в корневой файл нашего приложения.

Плюсы плоской конструкции

Теперь давайте посмотрим на преимущества плоской структуры проекта:
— понятная структура кода, которая помогает облегчить процесс адаптации новых разработчиков;
— более легкая и быстрая разработка без продвинутого структура;

Минусы плоской конструкции

Плоская структура файлов в React.js также имеет некоторые недостатки:
— нет отдельной папки для всего файла Redux, они как бы везде в приложении;
— если проект разрастается, может быть трудно найти определенный файл, в случае дебюта или поддержки старого кода;
— при добавлении новой функции нам нужно изменить много папок, и мы должны работать со всей корневой папкой;

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

Что такое доменно-ориентированное проектирование (DDD)?

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

Давайте углубимся в предметно-ориентированный дизайн во фронтенд-разработке. Чтобы управлять сложностью приложения с помощью Domain-Driven Design, мы должны поместить нашу модель предметной области в контекст.

Чтобы начать организовывать наше приложение в соответствии с принципами Domain-Driven Design, мы должны организовать наши домены. Стоит помнить, что нет одного способа сделать это. Давайте снова возьмем в качестве примера блог-платформу, и в традиционной реализации структура папок будет выглядеть так.

└── src
 ├── redux
 │ ├── store.js
 │ ├── actions
 │ │ ├── PostActions.js 
 │ │ ├── CommentActions.js 
 │ ├── reducers 
 │ │ ├── PostReducer.js 
 │ │ ├── CommentReducer.js 
 │ │ ├── index.js 
 ├── components
 │ ├── PostComponent.js
 │ ├── PostsListComponent.js 
 │ ├── CommentComponent.js 
 │ ├── CommentsListComponent.js
 ├── containers 
 │ ├── PostContainer.js
 │ ├── CommentContainer.js 
 |── App.js

Если бы мы попытались изменить структуру папок приложений с помощью Domain-Driven Design, нам нужно было бы различать домены, и в этом случае я бы разделил его на приложение, публикацию, комментарий.

В этом случае структура папок для нашего приложения React.js будет выглядеть немного иначе.

└── src
 ├── app
 │ ├── App.js
 │ ├── reducers.js
 ├── post
 │ ├── PostComponent.js
 │ ├── PostContainer.js 
 │ ├── PostReducer.js 
 │ ├── PostActions.js
 │ ├── PostsListComponent.js 
 ├── comment 
 │ ├── CommentComponent.js
 │ ├── CommentContainer.js 
 │ ├── CommentReducer.js 
 │ ├── CommentActions.js
 │ ├── CommentsListComponent.js 

Как видно на примере выше, теперь хорошо видно, какие домены у нас есть во всем приложении, и в данном случае добавление новых доменов — это добавление новой директории.

Это очень удобно, потому что все, даже файлы редукса, помещаются как часть определенной папки домена.

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

└── src
 ├── app
 │ ├── App.js
 │ ├── reducers.js
 │ ├── shared
 │ │ ├── ButtonComponent.js
 │ │ ├── ModalComponent.js
 ├── post
 │ ├── PostComponent.js
 │ ├── PostContainer.js 
 │ ├── PostReducer.js 
 │ ├── PostActions.js
 │ ├── PostsListComponent.js 
 ├── comment 
 │ ├── CommentComponent.js
 │ ├── CommentContainer.js 
 │ ├── CommentReducer.js 
 │ ├── CommentActions.js
 │ ├── CommentsListComponent.js 

Еще один вопрос, на который необходимо ответить в данном случае, касается тестов. Где мы должны разместить тестовые файлы в такой структуре папок?

Есть два варианта: один — поместить тестовые файлы в основные папки домена, другой — создать отдельную папку для тестов. Я бы выбрал первый вариант, так как, на мой взгляд, так проще найти файлы.

Этот подход также известен как структура, основанная на функциях.

Плюсы ДДД

Давайте взглянем на плюсы использования Domain-Driven Design в структуре папок внешнего интерфейса.

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

Минусы ДДД

Помимо всех замечательных вещей, которые DDD привносит в проект, есть и некоторые недостатки, о которых было бы неплохо упомянуть:

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

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

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

Что такое разделенная структура состояния просмотра

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

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

└── src
 ├── api
 │ ├── api.js
 │ ├── posts.js 
 │ ├── comments.js 
 ├── components
 │ ├── PostComponent.js
 │ ├── CommentComponent.js 
 ├── shared
 │ ├── ButtonComponent.js
 │ ├── ModalComponent.js
 ├── containers 
 │ ├── PostListContainer.js
 │ ├── CommentListContainer.js 
 |── redux
 | |── store.js 
 | |── middleware.js 
 │ ├── post
 │ │ ├── PostActions.js 
 │ │ ├── PostReducers.js
 │ ├── comment
 │ │ ├── CommentActions.js
 │ │ ├── CommentReducers.js 
 |── App.js

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

Плюсы разделенной структуры состояния просмотра

Давайте рассмотрим преимущества использования разделенной структуры папок с состоянием просмотра в приложении React.js.

Весь код Redux помещается в одно место, поэтому рефакторинг довольно прост, особенно когда файлы сгруппированы по фиче внутри папки redux;
Легко найти определенную часть состояния;
Ведение приложение не сложное, а также создавать новые фичи просто, потому что достаточно добавить одну папку на весь функционал редукса;

Минусы разделенной структуры представления и состояния

Давайте разберемся с недостатками этого подхода.

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

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

Вывод

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

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

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

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

Спасибо, что читаете,
Анна из Дуомли