Your first domain
Now we have a working and tested application. It is time to re-organize the codebase. In this tutorial, we will cover how to split the application into domains.
What is a domain
Before starting, let's try to define what a domain is. There's no a unique and universal definition of a domain, but we can say that a domain is a part of the application that is responsible for a specific feature. It contains all the necessary components, services, and logic to implement the feature.
But let's make some examples:
- In a blog application, you can have a domain for the posts and another domain for the users. In this context, the posts domain will contain all the components and the logic to manage the posts, like the list of posts, the post detail, the post creation, and so on. The users domain will contain all the components and the logic to manage the current users and which users can see other users' posts.
- In an e-commerce application, you can have a domain for the products and another one for the cart. The products domain will contain all the components and the logic to manage the products, like the list of products, the product detail, the product search, and so on. The cart domain will contain all the components and the logic to manage the cart, like the list of products in the cart, the cart total, the cart checkout, and so on.
NB: When you split the application into domains, there's no an unique way: it really depends on your business logic and requirements. So, the above list is just an example.
The quote
domain
Our application is simple, but for the sake of this tutorial, we will move part of the current code into a domain. Our goal is to move all logics and components related to the quote into a folder.
Let's start by creating a file at this location: src/domains/quotes/domain.ts
. In this file we will define our class and expose a method to get a random quote.
So, if a component invokes fetchNewQuote
, the domain will emit:
- the
FetchingNewQuote
event. - the
NewQuoteFetched
event when the quote is correctly fetched. - or the
QuoteErrorFetched
event if there's an error.
Our component can listen a domain event. Let's create a file at this location: src/domains/quotes/components/Quote.tsx
.
With QuoteComponent
we are able to refresh the quote independently from the rest of the application. It completely decouples the quote logic from the button: we can trigger this logic from any component.
Now, let's create a file for the button at this location: src/domains/quotes/components/RefreshQuoteButton.tsx
.
The RefreshQuoteButton
component is a button that invokes the fetchNewQuote
method of the QuoteDomain
class. The click on the button will fire FetchingNewQuote
event, so the QuoteComponent
will render the loading component. When the quote is fetched, the NewQuoteFetched
event is fired, and the QuoteComponent
will render the quote, or the QuoteErrorFetched
event is fired, and the QuoteComponent
will render the error message.
In this way, we decoupled the quote logic from the UI.
The application
We have all pieces in place. Now it is time to put them together.
Let's update the src/Main.tsx
file.
What we are missing is the domain instantiation. Let's update the src/index.tsx
file.
NB: You should update the tests/index.test.ts
file as well.
Conclusion
The Main
component is now very simple: it just renders the QuoteComponent
and the RefreshQuoteButton
. The responsibility are segregated:
- the
QuoteDomain
class implements the main logic to fetch the quote. - the
RefreshQuoteButton
component controls when the quote is refreshed, invoking the domain. - the
QuoteComponent
component renders the appropriate component, listening to domain events. - the
Main
component is to render the UI and decides where to put the quote and the button.
Amazing! We segregated rgw business logic from the UI logic. This is a good practice to make the codebase more maintainable and scalable.