This tutorial is intended to create a simple Angular app which drives a “common issue in OOP paradigm” which is code duplication and hidden patterns usually found in real world that can be solved using Inversion of Control techniques and allowing us to perform declarative programming.

Resources (what this article is about):

The App

The app should load a list of users (authors) in its home page.

(authors) in its home page. If a list element is clicked a dialog should be presented

That dialog should have a brief[1] about the selected user and two buttons

One button should close the dialog

Other button should load user specific ‘post page’

Clicking on an user from ‘South Elvis’ will trigger a random exception

Exception should be cached, an error dialog[2] should be presented

Post page should render selected user’s specific posts

[1] User dialog format/content isn’t part of tutorial’s scope

[2] Error dialog format/content isn’t part of tutorial’s scope

Rules

Each time we perform an ajax request we must show a loading dialog

All ajax request should be stored for cache purposes

Technical details

Users (writers) resource is placed here: https://jsonplaceholder.typicode.com/users

Posts resource is placed here: https://jsonplaceholder.typicode.com/posts

Let’s start

You can follow these instructions, step by step.

Prepare your workspace

$ git clone https://github.com/k1r0s/angular2-srp-showcase.git

$ git checkout normal-oop

$ npm install

Run the code

$ npm start

browse localhost:4200

Read the code

Okay so lets start by opening src/app/components/writers/writers.component.ts . This component has the following responsibilities:

Invoke a service to fetch users

Render users list

Listen clicks on users list

Invoke a service to store users request result and the selected user to be loaded on ‘posts screen’

Invoke a service to build a dialog to render selected user

Handle an exception if selected user is from ‘South Elvis’

Now lets look over src/app/components/user-posts/user-posts.component.ts . This one has the following responsibilities:

Grab selected user from cache

Invoke a service to fetch user’s specific posts

Render a post list

Invoke a service to store posts request result for that specific user

Common OOP drives repetition:

Let’s see the code at https://github.com/k1r0s/angular2-srp-showcase/blob/normal-oop/src/app/components/writers/writers.component.ts#L41

Most of times a method body that should describe a business action is entangled with code that does not describe at all that action. Like opening a dialog, capturing exceptions, subscribe to close events, etc.

In OOP we try to separate concerns by declaring entities (classes) that group actions (methods) that describe what business wants to happen and where (domain speaking). Methods describe how things should be fulfited.

A common issue in OOP paradigm is that, to replicate a behavior, code must be replicated too. Sometimes class extension isn’t enough because your behavior doesn’t always occur in the same spot or you simply don’t have enough time to change whole app arquitecture. For example, a log service has to be invoked at the end of some method calls printing method’s arguments and result but that implementation isn’t important at all in terms of domain problem meaning that code is polluting your app. Can you deal with logs calls with class extension? nope.

What about projects with 12 developers coding the same behavior with different implementation? That’s hidden patterns. For example when a developer is used to add a feature similar or identical a previous one most of them will seek that previous implementation on the code base to look ‘how to deal with the same problem’ or simply paste that code in their feature changing some variables related with the context of that specific screen or feature, while some developers will implement their own code to solve the same problem. We don’t care about which implementation is the best. Different implementations for the same problem drives bugs, code is harder to mantain, etc. An easy solution to deal with this are interface definition that all developers must agree. But still duplication spreads.

Authentication, Ajax resolution, UX action invocation, exception handling… almost anything that isn’t related with business logic its likely to be invoked in several places and that implementations can pollute your domain logic.

Examples

Lets back to writers component

What is really doing writers.component.ts at setup ?

Reading the code we may conclude that:

Is reading from cache if resource was already fulfilled (if so list is assigned) and all steps below are skipped

If that cache is empty: We must show a loading dialog[2] and we fetch users resource

Then we should store that resource on cache by calling a service

Then we should hide loading dialog

Then we should asign the list to be rendered by the component

Many concerns take place as this code gets executed. In terms of domain this is simply fetch and render users list. There are a few domain rules that apply on this, catch resources, show a loading dialog while requesting a resource…

That behavior also gets replicated on user-posts.component.ts . But on this case there is a domain concern before: grab the selected user from cache.

There is a way to code that implementation abstracting us from component’s specific domain? Yes!

We already defined some interfaces that writers.component.ts and user-posts.component.ts share: LoadingDialog, ResourceContainer<T>, LoadingDialog, CacheContainer . We also assure that there are no hidden patterns.

Both components have to fetch some resource when created

Both components have to show a loading dialog at anytime

Both have to write/read from cache something

Hence we can achieve this on both components: