Угловая структура проекта для корпоративных проектов - PullRequest
3 голосов
/ 08 июля 2019

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

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

Мой вопрос больше касается использования модулей в крупном корпоративном приложении.

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

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

ОБНОВЛЕНИЕ Я получил много хороших ответов здесь.Я считаю, что все подчеркивали общие моменты модуля по функциям и дополнительные модули для ядра, общие (и ресурсы, которые Брайан упомянул).Я также собираюсь переместить мои представления маршрутизации в соответствующую папку их функций, а не в папку «виды», которую я использую в настоящее время.После прочтения ответов ниже, папка «views» может оказаться сложной для управления по мере роста приложения.

Кто-то также предложил мне прочитать о том, что делает Nrwl, и поэтому я сделал это и был заинтригован.их использование библиотек отдельно от приложения. Nrwl MonoRepo Pattern Book (Бесплатно) .У них было много полезных советов, которые шли параллельно тому, что все здесь говорили, с добавлением абстрагирования общих функций на разных платформах в библиотеки.Поскольку я уверен, что приложение, которое я создаю, потребует нацеливания на мобильные устройства за пределами веб-мира, это также показалось хорошей идеей.

Спасибо всем, кто нашел время, чтобы ответить очень подробно.

Ответы [ 4 ]

3 голосов
/ 08 июля 2019

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

обычно у меня будет что-то вроде:

app/
  core/
    ... core stuff like nav bars and single use components or core services...
  app-shared/ (prefix it!!!!)
    ... shared app utilities like tables, accordions, validators, form helpers, pipes etc ...
  resource1/ <- represents some backend resource usually
    resource1.model <- the models
    resource1-model.service <- API interaction layer, single http calls
    resource1-domain.service <- abstraction for everything I can do with this resource (think combinations of multiple model service calls or model service calls with common defaults)
    views/
      ... here we have all the components (data views, forms etc) that concern only this resource and the needed view services ...
  ... rinse repeat for all app resources ...
  feature1/ <- this is an application feature that combines multiple resources or possibly only uses a single resource. this is pretty much primarily a page of your app
    feature1-application.service <- this combines the various resources needed for this feature
    feature1-container.component <- the prime container for this feature. does the service layer interactions and holds the views of this feature or the needed resource views
    views/ <- maybe not needed depending on the feature
      ... here is where we have components and view services that are part of this feature that combine multiple resources, these can contain resource views if needed ...
  ... rinse repeat for all app features ...

notes:

  1. служба модели - это взаимодействие API исключительно для одного ресурса, они вызывают одно-единственное действие в API-интерфейсе
  2. доменные службы принимают службы модели и делают их полезными и простыми для разработчика,Может быть внедрен тесно связанный сервис модели субресурсов.
  3. прикладные сервисы объединяют несколько доменных сервисов
  4. сервисы представления берут данные из домена или службы приложения и создают модель представления для конкретного представления (ПОЖАЛУЙСТАникогда не передавайте бэкэнд-модель прямо в шаблон !! вы будете ненавидеть себя, если / когда эта бэкэнд-модель подвергнется рефакторингу ... в связи с этим шаблоны будут максимально простыми, насколько это возможно для человека. Не используйте сложное выражение шаблонаопределив, должна ли кнопка отображаться, создайте модель представления со свойством «showButton» и назначьте ее там!)
  5. ресурсы обычно не будут иметь маршрутизации, если только это не похоже на маршрутизируемый модал, если вы в этомТакие вещи.функции - это действительно структура вашего приложения с маршрутизацией, основной сегмент будет указывать на основной контейнер, и тогда представления будут дочерними (если необходимо), но они будут использовать представления ресурсов.
  6. , если вы делаетеэто верно, теоретически вы должны быть в состоянии поднять свои ресурсы прямо в другое приложение, которое использует тот же ресурс (с некоторым стилем, конечно).
  7. причина, по которой вам могут не понадобиться какие-либо вложенные представления в функции, заключается впотому что контейнера может быть достаточно.Предположим, у вас есть учительский ресурс с компонентом списка данных и школьный ресурс с компонентом представления данных, и вам нужна функция, которая показывает их рядом, контейнеру здесь просто нужно расположить эти два представления ресурса и облегчить любое взаимодействие между ними с помощьюфункция приложения службы.Контейнеры не отображают данные или не имеют UX, они просто содержат представления, которые делают эти вещи.
  8. Вы также часто получаете отдельные ресурсы, чтобы ваши функции лучше соответствовали вашей истинной структуре приложения, а такжеобеспечить гибкость для добавления в будущем дополнительных ресурсов к функции.
  9. Тесно связанный вид ресурсов может в конечном итоге оказаться в другом представлении ресурсов в случае общего подресурса.Подумайте, если есть ресурс тегов, который имеет специальную форму множественного выбора автозаполнения.Это тесно связанный общий подресурс, который может появляться в нескольких других ресурсах, поэтому для простоты он, конечно, может оказаться в представлении ресурсов, хотя обычно они представляют собой один ресурс на представление ресурсов.
  10. НАИБОЛЕЕ ВАЖНО: когдавы начинаете сборку, во многом это будет выглядеть так, как будто вы просто создаете странные сквозные переходы к другим сервисам (т. е. ваш домен может выглядеть так, будто он просто оборачивает вашу модель, а ваше приложение может выглядеть так, как будто он оборачивает ваши домены), но какприложение растет, и вы будете благодарны за то, что сделали одноразовые инвестиции в создание этих слоев.Что я узнал о корпоративной среде разработки, так это о том, что требования меняются почти каждый день, и бизнес никогда не может быть полностью уверен в том, чего он хочет, пока не увидит его в действии.Эти уровни абстракции обеспечивают гибкость, необходимую для быстрого реагирования на изменяющиеся обстоятельства, в то же время имея простую рассуждение о базе кода.
3 голосов
/ 08 июля 2019

Прежде всего, я пытаюсь использовать LIFT Guidelines при структурировании приложения:

  • Расположение нашего кода простое
  • Идентифицируйте код с первого взгляда
  • Flatструктура, пока мы можем
  • Старайтесь оставаться СУХИМ (не повторяйте себя)

Тогда моя структура папок будет выглядеть следующим образом:

app/
  core/
    models/             // All models
    not-found/          // A core feature (not-found component for example)
    ...
    core.module.ts
  feature1/             // Feature 1 folder
    sub-feature1-1/     // A sub feature for the feature 1
    sub-feature1-2/     // A sub feature for the feature 1
    feature1.service.ts
    feature1.module.ts
  feature2/             // Feature 2 folder
    sub-feature2-1/     // A sub feature for the feature 2
    sub-feature2-2/     // A sub feature for the feature 2
    feature1.service.ts
    feature1.module.ts
  shared/
    card/               // A shared feature (card component for example)
    ...
    shared.module.ts
  app-routing.module.ts
  app.component.html
  app.component.scss
  app.component.spec.ts
  app.component.ts
  app.module.ts

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

3 голосов
/ 08 июля 2019

Прежде всего: я создал несколько приложений Enterprise, используя Angular, и видел вещи, которые работают, и вещи, которые я хотел бы никогда не пробовать.Хорошая новость заключается в том, что инструменты рефакторинга / dev настолько хороши в наши дни, что вы можете переключать структуру проекта в середине проекта, когда обнаружите, что он стал неуправляемым.Единственная плохая новость: это создаст кошмары слияния, которые проверит ваш git-fu.

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

Главное, чего следует избегать, - это иметь излишне сложную структуру папок, котораяна самом деле не отражает структуру вашего приложения.Например, если у вас есть раздел управления профилями, не помещайте его в /dashboard/user/components/profile/edit или что-то подобное, если только он фактически не имитирует структуру вашего приложения.Это кажется очевидным, но люди делают это постоянно, и это делает ваш код менее доступным для обнаружения.Я думаю, что это подпадает под концепцию LIFT :

Do структурировать приложение так, чтобы вы могли быстро находить код, быстро идентифицировать код,сохраните самую плоскую структуру, какую только можете, и попытайтесь быть СУХОЙ.

Do определите структуру, чтобы следовать этим четырем основным рекомендациям, перечисленным в порядке важности.

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

Далее следует упомянуть о сохранении структуры плоских папок.возможно:

Do сохранять структуру плоской папки как можно дольше.

Рассмотрим создание подпапок, когда папка достигает семиили больше файлов.

Попробуйте настроить IDE для скрытия отвлекающих, не относящихся к делу файлов, таких как сгенерированные файлы .js и .js.map.

Почему? Никто не хочет искать файл по семи уровням папок.Плоская структура легко сканируется.

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

Относительно модуля на компонент:

Do создать модуль NgModule для каждой области функций.

Почему? NgModules облегчают ленивую загрузку маршрутизируемых функций.

Почему? NgModules упрощают изоляцию, тестирование и повторное использование функций.

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

Последнее замечание: будьте готовы к изменениям.Вы и ваши коллеги можете потратить неделю на планирование структуры вашего проекта, но только после того, как вы начнете использовать его, вы почувствуете, что это неправильно.Трудно сделать все на 100% правильно с первой попытки.Проще медленно повторять, пока не достигнете чего-то, что почти идеально.

Мои проекты обычно выглядят примерно так:

app/
| core/ 
| | constants/         // Keep all constants in a single place and avoid magic IDs/strings.
| | |-http-status-codes.enum.ts
| | guards/            // I like to group my guards in a single place
| | http-interceptors/ // Same with interceptors
| | pipes/             // Some pipes might be section-specific but they are usually core
| | services/          // Core services. Utilities, error handling, etc.
| | |-error-handler.service.ts
| | validators/
| section1/
| | models/
| | sub1/              // I try not to nest too deeply
| | |-sub1.component.ts|html|css|spec.ts
| |-section1-routing.module.ts // Routing by section
| |-section1.component.ts|html|css|spec.ts
| |-section1.module.ts  // Module per section for lazy loading, etc.
| |-section1.service.ts // Section-specific service
| shared/
| | models/
| | app-modal-dialog/
| | my-awesome-widget/
| | some-custom-input/
|-app.component.ts|html|css|spec.ts
|-app.module.ts
|-app-routing.module.ts
assets/             // Static content
environments/
|-environment.x.ts  // Stripe public keys, etc.

Опять же - это вполне соответствует руководству по стилю .

3 голосов
/ 08 июля 2019

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

Это хорошая идея, чтобы у отдельного модуля маршрутизации было много видов.

// barrel 
import { firstComponent, .... ,lastComponent } from './components'; 

const routs = [ ... ];

export class FeatureRoutingModule { 
    const static components = [
       firstComponent,
             .
             .
             .
       lastComponent
    ]
};

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

import { FeatureRoutingModule } from './freature-rotuing.module';
@NgModule({
  imports: [
    SharedModule, // if you have one
    FeatureRoutingModule
  ],
  declarations: [FeatureRoutingModule.components]
  })
  export class FeatureModule { }

Я надеюсь, что это поможет вам лучше организовать ваш код, Удачи.

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