In this series we look at some of the rules in Angular's Style Guide that might need clarification or alteration as we grow our applications and our understanding 🧠 of the framework.
📐 The Rule in Question: Symbols and file names
The Angular Style Guide defines this rule as follows:
Do use consistent names for all assets named after what they represent.
Do use upper camel case for class names.
Do match the name of the symbol to the name of the file.
Do append the symbol name with the conventional suffix (such as Component, Directive, Module, Pipe, or Service) for a thing of that type.
Do give the filename the conventional suffix (such as .component.ts, .directive.ts, .module.ts, .pipe.ts, or .service.ts) for a file of that type.
💡 Positive Observations: Conventions are Convenient
The web framework Ruby on Rails popularized the idea of Convention over Configuration, and while there aren't any naming conventions in Angular that replace configuration, using conventions is still important 😉.
In Angular's case the conventions aren't to help the framework - instead they help the developers.
Even when using a pattern like micro frontends, we could end up with a large code base (or maybe multiple projects managed by Nx).
Naming conventions with our files and Typescript types help us manage complexity in projects 🏗.
The conventions recommended by this rule of the style guide are also pretty easy to follow.
A component that lists users would have a file name of users-list.component.ts
and a class name of UsersListComponent
.
Other developers on our team, will quickly be able to understand the purpose of this file and class - we've encoded helpful information, in the file and class name, that we can trust because of the established project conventions.
If we instead named the file all-users.ts
and the class name UsersComp
, we lose the ability to quickly and easily identify that the file and class are connected, or even what the purpose of each are:
- Does
all-users.ts
contain a service or a component? - Is
UsersComp
a component class type or something that can be "compared"?
If the project also contains classes ending in *Component
, we could become even more confused 😵 - why was UsersComp
used in the first place 🤷🏾♀️?
Since services and components fill distinct roles (business logic vs rendering state into markup), we want their purpose to be clear, with a convention we can trust.
👓 What Needs Clarification: Projects Can Have Conventions Beyond the Framework
The "Symbols and file names" rule mentions the following types of things:
- .component.ts,
- .directive.ts,
- .module.ts,
- .pipe.ts
- .service.ts
This is no surprise, as these are all the types that Angular gives us to interact with the framework.
While still following the core idea of the style guide rule, we should not read it so literally. There are always going to be more types of things in our projects than what Angular provides with the framework!
If we are already using file and type names to encode helpful and trustworthy information into our code, we should extend these conventions beyond Angular's types.
Let's look at a couple of examples we will likely encounter as our applications grow ...
Models And Schemas
Angular is pretty hands-off when it comes to managing data, so it's up to us to clearly separate how we represent data inside and outside our application.
Schemas are a good way to represent the data of our application at the boundaries. This is often JSON exchanged with an API. Schemas are structured data only 🤔, they have no methods or functions.
user.schema.ts
interface UserSchema {
readonly id: string;
readonly firstName: string;
readonly lastName: string;
readonly email: string;
}
Models represent the data of our application at the interior. They protect against being changed into an inconsistent state and expose methods to enrich the data to match how our application operates 😮:
user.model.ts
class User implements UserSchema {
get fullName(): string { return `${this.firstName} ${this.lastName}`; }
constructor(
public readonly id: string,
public readonly firstName: string,
public readonly lastName: string,
public readonly email: string) { }
}
Container Components, Presentation Components, and Presenters
If we consider adopting the Model, View, Presenter pattern in our application architecture, we will end up with several new types not mentioned in Angular's style guide.
Container components "supply a data flow for presentation" and "translate component-specific events to application state commands or actions to put it in Redux/NgRx Store terms".
Presentational components "present application state to the user" and "Change application state triggered by user interaction".
Presenters are services that contain "behavioural logic and complex presentational logic" extracted from our Presentational components.
Here's an example of the file and type names we might have using this pattern:
- Container component
-
UsersContainerComponent
,users.container.ts
-
- Presentational component
-
UsersUiComponent
,users-ui.component.ts
-
- Presenter service
-
UsersPresenter
,users.presenter.ts
-
State Management Libraries
We can also find examples of non-Angular types when using state management libraries.
Akita uses "Stores" and "Queries"
- Users store
-
UsersStore
,users.store.ts
-
- Users query
-
UsersQuery
,users.query.ts
-
NgRx uses "Actions", "Reducers", "Stores", and "Selectors". NgRx
- Users action
-
LoadUsersAction
,users-store/actions.ts
-
- Users secltor
-
selectActiveUsers
,users-store/selectors.ts
-
Each of these libraries might have their own conventions or conventions created by the community.
✨ Conclusion
The main takeaway for all of us is to use type names that are consistent with our team, organization, or project 🤗.
Notice how many of the names of the above types don't fall into any of the categories supplied by Angular.
Angular is focused mainly on helping us convert application state into a user interface, but there will always be parts of our application not related to creating HTML 🧐.
For these types, we have an opportunity...
We should develop our own conventions, and the most important part is not that the conventions match the Angular style guide, but that they are consistently applied 👍🏿.
That said, aligning as much as possible with the Angular style guide makes our projects more consistent with the larger Angular community, which makes them more understandable and familiar to new developers joining our team.
It's probably best not to name a component that displays users a
UserCollectionDisplayer
, even if it's a consistently applied convention in our project.
We can still use .component.ts
, .pipe.ts
, .service.ts
but let's not be so dogmatic about it 😎, and explore conventions for "Symbols and file names" that work best for the functionality and complexity of our projects.
As always, thanks for reading 🙏!
❓ Questions
What are your thoughts on the conventions detailed by the "Symbols and file names" rule?
Can deviations or additions to Angular's style guide be in alignment with it's all-in-one, framework focused ethos?
Have you already adopted any custom naming conventions in your Angular projects?
Do you have some recommendations new symbol and file names that the community could adopt?
Leave a comment below!
Normally, I'm blogging about Kentico, a content management system I love to use.
We've put together a list over on Kentico's GitHub account of developer resources. Go check it out!
If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:
Or my Kentico blog series:
Top comments (0)