Designing Scalable Angular Apps: Pages, Containers and Views

栏目: IT技术 · 发布时间: 5年前

内容简介:Angular is one of the popular front-end frameworks for building single-page applications. Working with more than a dozen Angular projects, one common pitfall I have seen is that the focus for unit tests dries up over time.Another problem that appears most

Terminology and a methodology that would help you build a scalable Angular application.

Angular is one of the popular front-end frameworks for building single-page applications. Working with more than a dozen Angular projects, one common pitfall I have seen is that the focus for unit tests dries up over time.

Another problem that appears most is the increase of coupling in components, services, and state management. It’s no brainer that these symptoms are ticking time bombs unless we address them at their earliest.

Designing Scalable Angular Apps: Pages, Containers and Views

There could be many reasons underlying these issues. But in this article, I would like to talk about one thing that mostly slips through our fingers. It’s no other than how we use Angular components within the project.

Test Your Project is Structured Correctly with Bit.dev

Before moving forward, I’d like to share a trick I’ve found to test if my components are indeed independent — because, as you know, a modular codebase is a scalable codebase.

I use Bit.dev , a cloud component hub, to publish (and document) Angular components from whatever codebase I’m working on, to a shared component collection (on Bit.dev ).

Designing Scalable Angular Apps: Pages, Containers and Views
Exploring published components on Bit.dev

Bit tracks your components dependencies to help you isolate components and ensure each component is published as an autonomous and independent Lego piece. It lets you know which components are coupled and if there are any dependency issues (all that, before publishing them to the Bit’s registry).

After each component gets published, it can be examined in Bit’s playground, rendered in an isolated environment, completely decoupled from its “origin codebase” — so you know how it looks and behaves in environments different from yours.

This way you kill two birds with one stone:

  1. You have a way to test your project is structured correctly
  2. You get to publish independent components so that you and your team may reuse them in other projects/repositories.

Pitfalls with Angular Components

With Angular, we can structure the components in a hierarchy. One common approach is to structure these components is as follows.

my-app
├── src
│   ├── App
│       ├── shared
│           ├── shared_component_1
│       ├── component_1
│           ├── sub_component_1
│               ├── sub_component_1.html
│               ├── sub_component_1.ts
│               ├── sub_component_1.spec.ts
│               ├── sub_component_1.scss
│           ├── sub_component_2
│               ├── sub_component_2.html
│               ├── sub_component_2.ts
│               ├── sub_component_2.spec.ts
│               ├── sub_component_2.scss
│       ├── component_2
│           ├── component_2.html
│           ├── component_2.ts
│           ├── component_2.spec.ts
│           ├── component_2.scss
│       ├── component_3
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

The philosophy behind this structure is that each component is self-contained and relates to business functionality. Each component has sub-components most of the time. If there are components reusable between any parent components, they are placed under shared.

So if you look at the project folder structure, it closely assembles the dependencies as a tree. In this structure, any parent component knows about its child components or any related shared component, but not the other way around.

One of the fundamental problems I see with this structure is that the responsibilities of the parent and child components are not divided. Even if you define some guidelines, it might not reflect in the code structure leading to inconsistencies over time.

As a result, developers find it difficult to unit test these components due to dependencies with other components, services, shared states &, etc. If any Angular project comes to this stage, it’s a clear indication of increased coupling.

So what are we missing here? How can we stop the issue from occurring?

Pages, Containers, and Views

To address the issue mentioned above, we need to identify the root cause of the problem. We can see that not every component is the same. Some are parent components, and some are children, and some are shared.

But what’s the difference between a parent and a child? Is it only just composition and dependency direction? To address these questions, we need to define a precise terminology that everyone understands, divide their responsibilities, and structure the project accordingly.

In this article, I’m going to present a terminology that you can use to divide Angular components. The three categories of components are called Pages, Containers, and Views.

my-app
├── src
│   ├── App
│       ├── view_components
│           ├── view_component_1
│           ├── view_component_2
│           ├── view_component_3
│           ├── view_component_4
│           ├── view_component_5
│       ├── container_components
│           ├── container_component_1
│           ├── container_component_2
│           ├── container_component_3
│       ├── page_components
│           ├── page_component_1
│           ├── page_component_2
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

To give an overview, the Page Component has Container components as children. Then each Container component has View components as children (Pages -> Containers -> Views). To help you understand the structure, I will be explaining the different roles of each component type going from inside out.

View Components

View components are UI components that comprise the visual elements. They are dumb components that accept data from outside and triggers events for actions like button click. These custom components are typically a composition of UI elements, from libraries like ng-bootstrap or Angular Material created for business functionality.

We can unit test these View components easily to test the actions and visualization of data since they don’t have any direct dependencies with services or external states.

Container Components

Container components are the components that bind, View components, services, and state management together to deliver business functionality.

The Container components use the services to fetch data from backend and bind them to the View components. They also listen to the events coming from View components and update the state of each View components and communicates with the backend.

As you see, Container components are the hub of connecting things, dealing with business logic, delegating the presentation to View components.

Page Components

Page components are the components that define the layout of a page based on URL paths. For instance, you can compose a page component with a header, footer, and an area in the middle. So basically, you can define a Page component for each parent route. Inside each Page component, you can place your Container components. In some instances, you can place View components directly inside the Page components, when the view components don’t need any dynamic behavior.

By using Page components, it will help the Container components to know less bout the fixed layout of a page and focus more on dynamic component placement based on business logic. It will also help to reduce the depth of Container components to reuse the layout across different routes.

Looking at the Big Picture

When developing a new feature, without having a classification for Angular components, a developer needs to think about the hierarchy of the component structure and how each sub-component manages state, visualization of data &, etc. Besides, the developer also needs to decide which sub-components are meant for reuse to place under shared components. These decisions are tougher to take and could lead to many inconsistencies.

As you have seen in this article, when we divide the components to have different component types with responsibilities, the message is evident across the development team. The decisions that each developer needs to take is less regarding components. For example, it is easier for them to decide on creating View components and Container components since the responsibilities are clear. They have less complexity in reusing a View component between multiple containers since the dependencies are less.

Besides, with the component responsibility separation, you can increase the unit test coverage across all the View components. You can also use unique strategies to unit test, Container, Page components, and Services.

Also, use the component types combined with other best practices like state management with ngrx-store , unit testing, we can avoid the majority of the issues that affect the maintainability in Angular applications.


以上所述就是小编给大家介绍的《Designing Scalable Angular Apps: Pages, Containers and Views》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++编程风格

C++编程风格

卡吉尔 / 聂雪军 / 机械工业出版社发行室 / 2007-1 / 25.00元

本书描述C++语言中较深层次的程序设计思想和使用方法,包含大量软件工程概念和设计模式,重点介绍大规模编程相关的内容,例如增加代码的可读性、可维护性、可扩展性以及执行效率等的方法。本书的示例代码都是从实际程序中抽取出来的,融人了作者的实际开发经验。讲解如何正确地编写代码以及避开一些常见的误区和陷阱,并给出了许多实用的编程规则,可快速提升读者的C++编程功力。   本书描述平实,示例丰富,适合有......一起来看看 《C++编程风格》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具