Here’s how Angular made me understand code better

Who's afraid of the big-bad Angular? Certainly not our Krešimir, who thoroughly explained what a significant impact Angular had on his programming journey and helped him to enhance his coding skills.

Reading Time10 minutes

Even though my career is now focused on software development, that’s not how it started. I come from a technical background and I studied Power Engineering in college. I really didn’t have a lot of coding experience prior to trying it out and coding experience prior to learning on my own through W3Schools, Codecademy, and similar resources amongst many YouTube videos. With that in mind, let me describe how Angular made me a better software developer.

“Too many options will make a tyrant of us all.”

This is a quote from Matthew McConaughey, and I heard it once and it left an impression on me. It’s no secret that today, with so many JavaScript frameworks, there’s an ongoing joke that a new framework is devised daily. Sure, there are some pros and cons to each and every one of them, but is there really a necessity to, as the joke says, invent a new one on a daily basis?

In this sea of frameworks, libraries, and tools, three of them stand out: Angular, Vue, and React.

Each of these frameworks offers something different, a way to organize your code, and some of them allow more freedom in it than others.

I have tried Vue and React, but the one I had the most experience with is Angular.

My coding roadmap

Coding has been a hard journey for me. 

I never understood Object-Oriented Programming (OOP) until I actually started working with Angular. Javascript itself is not a very intuitive language, with many caveats to understand and traps you can get caught in. But as the saying goes, iron is forged while it’s hot, so even with my hot-headed character, I still managed to get the hang of the concepts of OOP and design patterns while working with Angular.

At the beginning of my journey, I found the simplicity of React very pleasing. 

It gave me a sense of confidence as there is a relatively small learning curve to get started. However, I have been compelled to use Angular throughout my career. It would be an understatement to say it was a challenging experience. The learning curve is insanely steep (like learning reactive programming with RxJS), the concepts are hard to understand (Typescript itself, at the time, a new way of programming with classes inside JavaScript, different design patterns like observer and/or publisher/subscriber pattern) and there’s a lot of boilerplate. Suffice it to say I would’ve been the first in line to criticize it and defend the simplicity of React.

However, after a few years of using it, trying the ecosystem it comes with out of the box, and actually participating in using React (and recently Vue), I have come to a realization:

Angular is actually not that scary.

This is a simple example of code that I have learned to apply while using Angular (even though it’s applicable in any general Typescript code) - so let’s start with some models and set default values to their properties.

Any entity stored in a database most likely has these fields applied (probably a deleted field as well in case of soft deletion):

export abstract class Resource {
  constructor(
    public id: number = 0,
    public createdAt: Date = new Date(),
    public updatedAt: Date = new Date()
  ) {}
}

Here’s a list is some form of paginated data modeled similarly to something like this:

export abstract class List<T> {
  constructor(public data: Array<T>, public total: number) {}
}

Also, a generic API service looks something like this:

export abstract class APIService {
  protected protocol: 'http' | 'https' = isDevMode() ? 'http' : 'https';
  protected domain = 'localhost';
  protected port = 9229;
  protected baseURL: string;

  constructor(endpoint = '') {
    this.baseURL = `${this.protocol}://${this.domain}:${this.port}/api/${endpoint}`;
  }
  }

So, let’s continue with creating an abstract resource service using the generic API service:

export abstract class ResourceService<T extends Resource> extends APIService {
  constructor(private HTTPClient: HttpClient, endpoint = '') {
    super(endpoint);
  }

  post(
    payload: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>
  ): Observable<T> {
    return this.HTTPClient.post<T>(this.baseURL, payload);
  }

  get(id: number): Observable<T> {
    return this.HTTPClient.get<T>(`${this.baseURL}/${id}`);
  }

  getAll(): Observable<Array<T>> {
    return this.HTTPClient.get<Array<T>>(this.baseURL);
  }

  getList(): Observable<List<T>> {
    return this.HTTPClient.get<List<T>>(`${this.baseURL}/list`);
  }

  update(id: number, payload: T): Observable<T> {
    return this.HTTPClient.put<T>(`${this.baseURL}/${id}`, payload);
  }

  patch(
    id: number,
    payload: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>
  ): Observable<T> {
    return this.HTTPClient.patch<T>(`${this.baseURL}/${id}`, payload);
  }

  delete(id: number): Observable<T> {
    return this.HTTPClient.delete<T>(`${this.baseURL}/${id}`);
  }
}

Now, let’s finalize these abstract models on a real example:

export class Todo extends Resource {
  constructor(
    public userId: number = 0,
    public title: string = '',
    public completed: boolean = false
  ) {
    super();
  }
}

This Todo’s appropriate service is created (with Angular’s decorator to provide/register the service metadata) in the following manner:

@Injectable({
  providedIn: 'root',
})
export class TodosService extends ResourceService<Todo> {
  constructor(HTTPClient: HttpClient) {
    super(HTTPClient, 'todos');
  }

  getTodos(): Observable<Array<Todo>> {
    return this.getAll();
  }
}

Through Typescript your IDE is now type-safe because you have provided the model data through your generic resource service class. That means your methods now inform you that the return type is of Observable Todo type - be it a single, all, or a list form of the response.

Enforcement of structure

I pointed out that there is something pleasing about being able to write code freely, or maybe it’s better to say, to organize it freely. I do agree, and in programming, I think it’s a little too ambitious to get to that point.

When a large group of individuals collaborate on a project, there should be standards, norms, and ways to write and format code; and we should all try to follow them. This is all a tool and a way for us to standardize the usage and simplify the debugging process if/when it comes to it.

Compared to other tools, Angular actually might seem like a framework that overshadows the other ones. I personally wouldn’t say that using it enforces structure per se, but it definitely encourages it. If we strive to apply such rules and guidelines for code formatting and organization, it would be great to have a framework that provides tools that do many of those things for you.

There’s a concept in Angular called a module. From a file point of view, a module is nothing more than a taxonomical way to organize code. However, in the abstraction context of the framework, alongside the default organization benefits, it offers features such as:

  • component sharing,
  • directives,
  • services, 
  • route guards, 
  • route resolvers, 
  • lazy loading, and much more.

Angular doesn’t stop you from cramming every component, directive, service, and otherwise into one module. But that’s practically like saying you should write your code in one file. It doesn’t make much sense, does it? It would make code readability and debugging, I would say, a horrible experience.

TypeScript is a first-class citizen

Google has made TypeScript the default language of the Angular framework. As opposed to many other tools, Vue and React included, it is a prerequisite for writing code. It’s not an opt-in feature like it is in Vue and React.

I believe that this inherently makes it a much more “serious” tool than its counterparts. Angular has also implemented the very popular observer pattern library named RxJS into its framework. It is being used in many cases throughout the framework; from custom state management through services, state management libraries like NgRx, form builder and management of validation of data, route state changes, HTTP calls, and much more. 

RxJS is absolutely an integral part of the framework and probably the scariest as well as the hardest thing to truly comprehend (I still sometimes have issues with it).

Alongside many of the features of TypeScript and RxJS, Angular also encourages proper OOP structure and applying design principles to code where applicable. Even though I had little coding experience prior to using it, it gave me a goal and enough help to understand concepts like dependency injection pattern (which it uses under the hood for services), observer and/or publisher/subscriber pattern, singleton pattern, and similar.

It also has a really elegant and detailed unit testing suite through Karma and Jasmine. Angular offers a proper debugging tool for testing where you can intuitively set breakpoints in your test to see if you wrote the test wrong or if the code under test is at fault.

In time, I have come to realize that writing good code is not just writing something to make it work but to make it readable so that the next person can understand it easier.

Writing good code feels good, it makes you feel proud that you created something that’s readable to practically anyone. 

There is a popular saying by Bruce Lee: “Simplicity is key to brilliance”. So, if you are able to write code that someone will have little to no trouble understanding, you have done your job well.

Unfortunately, such seriousness, a steep learning curve, and many prerequisites come with a price. Angular is much less popular than React and for a good reason. It’s very hard to get into and dig through the sea of its documentation. For example, I had to participate in late-night conversations with random people on Angular Discord servers to help myself understand it better.

However, I always keep in mind that, as the project develops, and the more people participate in its development, the more chaotic it becomes. And here is where Angular absolutely “shines”, precisely because it is that complicated and challenging, so everyone will inherently strive to follow the guidelines it offers and its best practices.

I am sure that most software developers have experienced that feeling when reading someone else’s code - when they’re wondering what it’s doing, having little or no tools to properly debug the problem, and just stumbling in the dark with the only method they had left in their arsenal; trial and error. In the end, trying to log out the variable and see if changing or removing it made the problem go away might be a solution too.

This is why Angular can be a perfect solution. It’s very difficult to make something work in Angular in a simple way, and it’s even hard to get to the famous Hello world! message. But as you become more familiar with it, the class-based boilerplate becomes second nature. Then the ideas and design patterns start emerging and you reach a higher level of problem-solving skills.

Hey, you! What do you think?

They say knowledge has power only if you pass it on - we hope our blog post gave you valuable insight.

If you want to share your opinion on working with the Angular framework or need our help with your projects, feel free to contact us

We'd love to hear what you have to say!