The Page Pattern
By: Georgi Parlakov
Tags: Front End Development, Angular, Business Logic, Separation Of Concerns, Rules

Photo by Simon Rae on Unsplash

The Page Pattern

Separating the 💸business and ✨UI logic problem in Angular.

This article aims to give you a tool to help keep those 💸business and ✨UI concerns separate. It’s the result of a year’s worth of experimentation in a couple of teams I worked with. It might seem unnatural and complex at first, but then again isn’t everything new like that?

We will introduce a pattern that is extreme in its approach on the one hand and very straightforward to apply on the other.

Optimize for the case that the software we write will change and evolve!

There are 2 problems:

We want to separate 💸business logic from ✨user interface logic! But that requires a lot of thought effort, which leads to the second problem. People just want to deliver their feature/fix their bug and go home! And not be constantly worrying: “Where do I put this logic?”

Why are these a problem?

1. Why does 💸business logic need to be separate from ✨user interface logic?

Let’s start with what each is. Think of a select list or a dropdown or a select combo box:

we’d like to keep all instances of this look and feel the same (✨UI)

every instance will show different stuff (business)

In such a fairly low-level concept, it’s trivial to see how 💸business and ✨UI logic need to be separate. Every list will contain different entities people, addresses, orders, etc., but we’d like all of the app’s dropdown-s to look and feel the same for the user’s sake.

We slip into mixing our 💸business and ✨ UI logic when we get to more complex scenarios and get all kinds of pressure! Take your pick: I want to finish faster! I want to make it clever and future proof and reusable as f..k! My boss wants me to finish this by tonight! We promised we would deliver this sprint! All this is true and real.

What is also true and real is your future self having to maintain the code you write today. Help it and separate your 💸business logic from the ✨UI.

Because business requirements evolve — add new payment method — 💸 business concern!

concern! Because users say — hey this wizard/form/whatever looks cool and feels natural and makes my life easy, make the other page look the same — ✨ UI concern!

concern! Because users say — refresh the data on this grid after adding a row — 💸business concern!

Any of those listed above requirements become really hard or near impossible to implement if we have all our logic in the ✨UI part — the Component. Then look and behavior become inseparable. Implementing such requirements are the bread and butter of what we do — evolving software to meet the user’s needs! Ideally, we would have a perfect understanding of what the users need, how to present it and when to update it! We do not! That’s why any living software has issues, bugs, enhancements.

So, let’s optimize for the case that our software will change and evolve!

2. We don’t want to think!

We, the people, need a clear set of rules as to what/how/where/when!

But G, you might say, wait a minute! I’m a smart developer, I don’t need rules! I create the rules in code!

I know, how you feel, I’ve felt the same way. The rules thing can come across insulting. Bear with me, I’ll explain.

It turns out that our brain wants to spend as little energy as possible. It’s a survival and evolutionary thing. The brain does not want to think about the same things every time and looks for the repeatable pattern to memorize and offload to the second system which automates the boring tasks. Think of tying your shoelaces, buttoning a button, washing the dishes, writing code(?!). You don’t want to constantly be thinking about these things — you’ve got more important things to worry about! Where do I go on vacation? Do I need a new car, and can I afford it? The big rocks!

OK, enough about that! Let’s say for the sake of argument that you agree with me that people need a clear set of rules to make their life bearable. Se here’s my list:

Know your 💸business logic from your ✨UI logic! Keep ’em separated!

Simple! Right?

But, G, how exactly do I do that?!

One set of rules that can give you that is the Redux pattern (NgRx).

Or you can implement the Page pattern.

Introducing the Page pattern

A “Page” is what the user interacts with, in one scrollable screen.

Can the user see or click on it? - then its a ✨ UI concern — put it in the Component! - else it goes in the 💸 Page!

It’s not necessarily one component, though one component will often need to be the container of this “Page”! It’s not one route, it can be many, though the container component would probably have one route taking users to it.

The “Page” is the 💸business entity:

the user profile page

the reservation page

the cat owner’s page

the billing page

the landing page

The “Page” (1) owns the data (💸business concern!) and it (2) requires the user input and the data render to be done on the ✨UI level:

The “Page” expects to get notified about user’s input and intent: onDeleteAccount , onDeleteConfirm , onDeleteCancel . Also "Page" wants to know when user enters and leaves its domain: onPageEnter and onPageLeave .

The “Page” owns multi-step, 💸 business logic (BL), processes, like the delete user account with a confirmation dialog step:

How do you know what to put in it? By asking: Can the user see or click on it?

then its a ✨ UI concern — put it in the Component!

else it goes in the 💸 Page!

That’s a bit extreme, I know. The idea is to make the decision as to what to put where simple! Thus we take care of both the 1. Know your 💸BL and your ✨ UI! and 2. Keep ’em separated!

Examples in code!

For example, let’s say that we have a grid of bills:

the bills are displayed on a grid with columns: status(paid/due), name (electricity home, water home, water at mum’s), due date, provider

the bill can be drilled into for details

the bill can be selected

multiple bills can be selected

bill can be paid

bill can be hidden (some bills you don’t want to see — take care of by someone else)

The ✨UI would be the grid, the check-boxes on the rows representing the selection, the buttons pay and hide. Let’s create a component for that:

And then we have our BillsPaymentPage that takes care of fulfilling user’s intent, which was communicated by the ✨UI layer:

But why?

Why don’t I just put everything in the component and be done with it? This all looks too complex, too much repetition, too much! What did we gain by separating all this?

Software lives, breathes, and changes and we gained the ability to evolve it. To illustrate that, let’s imagine what happens next in our little scenario:

Change request — Add payment method!

That would make the BillPaymentPage present a new step with a list of payment methods before showing the confirmation dialog. No need to change the ✨UI around that. And we have the "multi-payment-method" logic all in our BillPaymentPage where we can extract it away in case we'd like to use it in another "Page".

Change request — Use the same confirmation dialog on the logout button!

Our confirmation dialog knows only what it needs and can be easily placed in as many places as needed! No bills-payment-page-specific logic in it!

Bug — After hide the data does not refresh.

It only affects 💸business logic so we can write a unit test, and then fix the bug, making sure we see no more of that!

How about Angular Services?

That’s a good question — why not use what the framework has provided? We can. Go right ahead. It can be used just as easy as the “Page” would. It is standard and well-known, which is a good thing for the people using it! It has a few downsides too. Very often these services start as entity specific request proxies ( UserService , BillsService ) and then become page-specific. What I mean is a situation similar to:

I have a change request for the BillsPaymentPage

I see the BillsService does the HTTP requesting of the Bill entity

does the HTTP requesting of the entity I’ll just put my implementation in the BillsService

Soon the BillsService becomes the BillsPaymentPageService , but the name remains the same

becomes the , but the name remains the same repeat from the top for another developer for a different page

now the BillsService is one giant ball of mud and no one can figure it out, let alone try to refactor or reuse any of its logic

And then the Page:

it has a name that explains what it is responsible for from the start

for from the start it owns the data — cache it or not and it can reliably do so because it is the single source of truth

the — cache it or not and it can reliably do so because it is the single source of truth no one will mistake the BillsOverviewPage responsibility with the BillsPaymentPage

To summarize