The logic for domain models in Angular apps is often split between the client and the server. The server contains the persistent store, typically a database, and contains the logic for managing it. In the case of a SQL database, for example, the required logic would include opening connections to the database server, executing SQL queries, and processing the results so they can be sent to the client.
You don’t want the client-side code accessing the data store directly—doing so would create a tight coupling between the client and the data store that would complicate unit testing and make it difficult to change the data store without also making changes to the client code.
By using the server to mediate access to the data store, you prevent tight coupling. The logic on the client is responsible for getting the data to and from the server and is unaware of the details of how that data is stored or accessed behind the scenes.
This approach can work well and is the foundation of RESTful web services, which use the nature of HTTP requests to perform CRUD operations on data.
NOTE: REST is a style of API rather than a well-defined specification, and there is disagreement about what exactly makes a web service RESTful. One point of contention is that purists do not consider web services that return JSON to be RESTful. Like any disagreement about an architectural pattern, the reasons for the disagreement are arbitrary and dull and not at all worth worrying about. As far as I am concerned, JSON services are RESTful, and I treat them as such in this Website.
In a RESTful web service, the operation that is being requested is expressed through a combination of the HTTP method and the URL. So, for example, imagine a URL like this one:
There is no standard URL specification for a RESTful web service, but the idea is to make the URL self-explanatory, such that it is obvious what the URL refers to. In this case, it is obvious that there is a collection of data objects called people and that the URL refers to the specific object within that collection whose identity is bob.
The URL identifies the data object that I want to operate on, and the HTTP method specifies what operation I want to be performed, as described in the following Table.
|GET||Retrieves the data object specified by the URL|
|PUT||Updates the data object specified by the URL|
|POST||Creates a new data object, typically using form data values as the data fields|
|DELETE||Deletes the data object specified by the URL|
You don’t have to use the HTTP methods to perform the operations I describe in the table. A common variation is that the POST method is often used to serve double duty and will update an object if one exists and create one if not, meaning that the PUT method isn’t used.
Common Design Pitfalls
In this section, I describe the three most common design pitfalls that I encounter in Angular projects. These are not coding errors but rather problems with the overall shape of the web app that prevent the project team from getting the benefits that Angular and the MVC pattern can provide.
Putting the Logic in the Wrong Place
The most common problem is logically put into the wrong component such that it undermines the MVC separation of concerns. Here are the three most common varieties of this problem:
- Putting business logic in templates, rather than in components
- Putting domain logic in components, rather than in the model
- Putting data store logic in the client model when using a RESTful service
These are tricky issues because they take a while to manifest themselves as problems. The application still runs, but it will become harder to enhance and maintain over time. In the case of the third variety, the problem will become apparent only when the datastore is changed (which rarely happens until a project is mature and has grown beyond its initial user projections).
Knowing where to put logic becomes second nature as you get more experience in Angular development, but here are the three rules:
- Template logic should prepare data only for display and never modify the model.
- Component logic should never directly create, update, or delete data from the model.
- The templates and components should never directly access the data store.
If you keep these in mind as you develop, you’ll head off the most common problems.
Adopting the Data Store Data Format
The next problem arises when the development team builds an application that depends on the quirks of the server-side data store. In a well-designed Angular application that gets its data from a RESTful service, it is the job of the server to hide the data store implementation details and present the client with data in a suitable data format that favors simplicity in the client. Decide how the client needs to represent dates, for example, and then ensure you use that format within the data store—and if the data store can’t support that format natively, then it is the job of the server to perform the translation.
Just Enough Knowledge to Cause Trouble
Angular is a complex framework that can be bewildering until you get used to it. There are lots of different building blocks available, and they can be combined in different ways to achieve similar results. This makes Angular development flexible and means you will develop your own style of problem-solving by creating combinations of features that suit your project and working style.
Becoming proficient in Angular takes time. The temptation is to jump into creating your own projects before understanding how the different parts of Angular fit together. You might produce something that works without really understanding why it works, and that’s a recipe for disaster when you need to make changes. My advice is to go slow and take the time to understand all the features that Angular provides. By all means, start creating projects early, but make sure you really understand how they work and be prepared to make changes as you find better ways of achieving the results you require.