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

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

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

Папка по типу / домену

├── javascript
│ ├── user.js ← — — feature #3
│ ├── order.js ← — — feature #2
| └── gig.js ← — — feature #1
├── css
│ ├── user.scss ← — — feature #3
│ ├── order.scss ← — — feature #2
│ └── gig.scss ← — — feature #1
├── spec
│ ├── user.js ← — — feature #3
│ ├── order.js ← — — feature #2
│ └── gig.js ← — — feature #1
├── images
│ └── user_default.jpg ← — — feature #3

Чтобы работать с этой структурой, вам придется работать с 3 разными большими папками. В крупномасштабном приложении это создает ряд проблем:

  • Не масштабируемый - как только вы ограничите структуру папок одним типом, этот тип может легко превысить разумное количество файлов и станет трудным в обслуживании - в крупномасштабных приложениях вы можете легко закончить управление 100 различными css / js / файлы любого типа.
  • Не модульный - с помощью таких сборщиков модулей, как webpack, browserify и т. д., мы можем создавать модули / файлы меньшего размера и использовать их в различных областях нашего кода.
  • Сложно работать. Допустим, вы хотите удалить объект. Если функция связана и записана внутри большого файла, ее сложнее удалить или даже провести рефакторинг.
  • Приводит к большим файлам - поскольку такая структура не поощряет модульный код, мы имеем тенденцию получать большие файлы в монолитном стиле, которые сложно реорганизовать и с которыми трудно работать.
  • Склонность к конфликтам - в больших приложениях у вас есть большие группы, которые в рамках такой архитектуры могут работать с одними и теми же файлами, что приводит к путанице, конфликтам и гораздо большему общению, чем необходимо.

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

Папка по функциям

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

├── gig ← — — feature #1
│ ├── gig.js
│ ├── gig.scss
│ ├── gig.spec.js
│ └── index.js
├── order ← — — feature #2
│ ├── index.js
│ ├── order.js
│ ├── order.scss
│ └── order.spec.js
└── user ← — — feature #3
├── index.js
├── user.js
├── user.scss
├── user.spec.js
└── user_card ← — — feature #4
├── index.js
├── user_card.js
├── user_card.scss
├── user_card.spec.js
└── user_default.jpg
└── user_default.jpg

Преимущества такой конструкции:

  • Высокомодульный - модульный код - это код, который легко поддерживать.
  • Архитектура по продукту. Если мы разделим код на основе функций, нам будет легко владеть / делиться / разделять код между разными командами. Таким образом, наш код не только отражает крупномасштабное клиентское веб-приложение, он также отражает большие команды, группы и т. Д.
  • Легко реорганизовать - поскольку наш код написан небольшими фрагментами, в будущем его будет проще реорганизовать. Хороший код - это код, который в будущем можно будет реорганизовать. Плохой код - это код, который мы не можем рефакторировать, и его нужно будет переписать с нуля.
  • Дружественность к команде - поскольку у нас много разработчиков из разных команд, нам нужно, чтобы они работали в относительно изолированных средах без каких-либо конфликтов кода.
  • Сократите ненужное общение - очень маловероятно, что разные команды будут работать с одними и теми же файлами или изменять одни и те же функции или модули, поскольку структура папок побуждает разработчиков писать автономный модульный код.

Как и во всем, у этой структуры есть свои минусы:

  • Сложнее научиться - легко сделать структурные ошибки, когда ваше приложение не ограничено типами - когда у вас есть 2, 3 или 4 основные папки для работы, легче понять, где разместить ваши недавно созданные файлы.
  • Вложенный ад - вы можете легко найти свое приложение, содержащее 20 уровней папок, поэтому вам всегда нужно быть уверенным, что вы создаете свое приложение как можно более плоским, даже с папкой по структуре функций.

Как давать названия папкам / файлам

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

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

Пример из реальной жизни

Так что давайте попробуем учиться на собственном примере. Здесь у нас есть различные примеры, которые помогут нам понять, как мы принимаем во внимание различные проблемы с этой структурой папок:

  1. Поток данных (redux - где мы создаем модуль, подключаемся или реагируем)
  2. Компонент и подкомпоненты
  3. Написание тестов
  4. Укладка
  5. Многоразовые / общие компоненты
  6. Плоская конструкция, избегайте вложенного ада

Пример №1: приложение для проверки

Нашим первым примером является приложение обзора Fiverr - мы используем его на странице пользователя и на странице Gig.

Как видите, мы можем подключиться к redux store из любой точки нашего приложения. Наше приложение обращается к глобальным файлам, таким как index.js и reviews.scss.

  1. ReviewList - это место, где мы собираем наше приложение, где мы можем подключиться к redux и экспортировать большую часть нашего приложения.
  2. В будущем, когда сложность нашего продукта вырастет, мы сможем добавить новые функции - в данном случае папку с redux connect, module и т. Д.

Вот наш пример структуры:

├── LoadMoreButton.js
├── LoadMoreButton.scss
├── ReviewList.js ← Here we construct the app
├── ReviewList.scss
├── ReviewList.spec.js
├── index.js ← Here we simply import ReviewList component and export
├── module.js ← LoadMoreButton fetch side effect is here
├── module.spec.js
├── review_list_header
│ ├── Filter.js
│ ├── Filter.spec.js
│ ├── ReviewListHeader.js
│ ├── ReviewListHeader.scss
│ └── index.js
├── single_review
│ ├── NoReview.js ← NoReview can be its own folder sibling to SingleReview (#6)
│ ├── NoReview.scss
│ ├── NoReview.spec.js
│ ├── PreviewImage.js
│ ├── PreviewImage.scss
│ ├── PreviewImage.spec.js
│ ├── SingleReview.js
│ ├── SingleReview.scss
│ ├── SingleReview.spec.js
│ └── index.js
└── user_rating ← Big enough to be its own folder
├── UserRating.js
├── UserRating.scss
├── UserRating.spec.js
└── index.js

У нас есть гибкость в отношении структуры нашего приложения, но у нас есть некоторые рекомендации. Например:

  1. Мы должны убедиться, что наша структура настолько плоская, насколько это имеет смысл - вот почему мы не всегда создаем новую папку.
  2. Мы должны создать папку для нашего компонента, когда это имеет смысл, например когда компонент имеет некоторую сложность, когда ожидается рост продукта или когда у нас есть более одного компонента под компонентом (например, у review_list_header есть Filter и ReviewListHeader, поэтому мы создали папку для review_list_header).
  3. Вы можете создать новую папку, если в противном случае у вас будет слишком много файлов, но снова создание папки для каждых 2–3 файлов может быть бессмысленным, поэтому это должно иметь смысл в структуре вашего приложения.
  4. Если у вашего компонента есть проблема, например, подключение к хранилищу redux, вы можете создать новую папку.
  5. Руководствуйтесь здравым смыслом - если в вашей корневой папке слишком много файлов, сгруппируйте их вместе на основе структуры DOM / продукта.
  6. NoReview может быть отдельным родственником по папке для SingleReview, но, с точки зрения продукта, noReview - это единый обзор, который позволяет нам сгруппировать эти два вместе и избегать создания другой папки.

Пример № 2: настройки платежного аккаунта

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

Резюме

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