Tips for Hiring Angular Developers: Essential Skills and Knowledge to Seek

Angular is a popular choice for web development teams aiming to build high-performance, dynamic single-page applications due to its scalable architecture. However, finding a skilled Angular developer is more challenging than it seems. Although many developers apply for these roles, the true success of a development project hinges on finding an exceptional Angular developer who adheres to best practices, uses advanced techniques, and meets stringent coding standards.

This article outlines the essential abilities and expertise that a top-notch Angular developer should possess. By grasping these key aspects of Google’s renowned front-end framework, you’ll be well-prepared to interview potential candidates and recruit the most talented individuals who strive to elevate your codebase to new heights.

TL;DR

High-quality Angular candidates will be those who:

  • Know the core functions of Angular.
  • Design before they start to code.
  • Understand Angular application lifecycles.
  • Have a solid knowledge of reactive programming.
  • Know what state is and how to use it.
  • Are skilled in and supportive of automated testing.
  • Stay informed about the latest Angular releases.

Note: This guide focuses on the latest Angular versions, which are no longer referred to as AngularJS. The name “Angular” has been used since Angular 2. If you’re seeking developers for the maintenance or upgrade of a legacy AngularJS web application project (the 1.x branch), refer to our guide on How to Hire a Great AngularJS Developer.

Grasping the Fundamentals of Angular

The Angular framework relies on TypeScript, and all code written within an application is converted into JavaScript. TypeScript is essentially a superset of JavaScript that compiles to plain JavaScript. Angular code is represented by this superset.

Many developers learn Angular but may lack a thorough grasp of fundamental concepts essential to JavaScript, TypeScript, HTML, or CSS. If these foundational elements are weak, developers may resort to inappropriate workarounds, potentially increasing a project’s technical debt.

Therefore, it’s crucial to assess the candidate’s knowledge of HTML5 and CSS3. While an Angular developer doesn’t need to be an expert in HTML or CSS, especially if another team member specializes in these areas, they should be well-versed in key concepts such as:

  • Flexbox
  • SCSS variables
  • The distinction between a span and a div
  • Significant classes in CSS
  • Attributes

Proficiency in JavaScript and TypeScript, along with a solid understanding of HTML and CSS, are crucial for Angular developers.

Tweet

Prioritizing Design in Development

A well-designed system is the cornerstone of a robust application architecture. When interviewing candidates, inquire about their design process and compare their approach to these optimal considerations:

  • Where will the code be placed? Is a new library or module necessary?
  • What are the inputs and outputs?
  • Should reusable components or directives be implemented?
  • How will the state be managed? (This will be covered in more detail in the State Management section below.)
  • Where will the business logic reside—specifically, within which service?
  • Can specific components be shared across libraries to effectively create a UI design system?

The specific details of a particular design are less critical than whether the candidate has a habit of engaging in the design process. Designs are fluid and subject to change, so for most applications, documentation can be as simple as a whiteboard sketch unless formal documentation is required. Later in the development cycle, the developer can use tools to generate technical documentation from the code, clarifying how all components interact.

Understanding Angular Application Lifecycles

During the interview, question candidates about their understanding of the Angular component lifecycle. Their response should encompass three key lifecycle hooks: ngOnInit, ngOnChanges, and ngOnDestroy. These hooks are triggered at specific points in a component’s existence: ngOnInit at initialization, ngOnDestroy when the component is destroyed, and ngOnChanges when an attribute is modified. It’s important to note that ngOnChanges can occur before ngOnInit if an attribute is assigned before the component is fully initialized.

Candidates demonstrating familiarity with ngDoCheck, ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, and ngAfterViewChecked possess a comprehensive understanding of component change detection hooks, giving them an advantage.

A relevant follow-up question concerning any of these hooks would be: “When does this change detection occur?”

Five boxes with arrows pointing down appear on the left. They are all green except for the fourth, which is blue and has a bracket expanding into five more boxes pointing down that appear on the right (the first is white, while the rest are blue). From top to bottom, the left boxes read: "constructor, ngOnChanges, ngOnInit, ngDoCheck, and ngOnDestroy." The arrow from "constructor" to "ngOnChanges" is labeled "Component has bound inputs," and there is an additional arrow pointing from "constructor" to "ngOnInit" labeled "Component does not have bound inputs." The arrow from "ngOnChanges" to "ngOnInit" is labeled "First run," and there is an additional arrow pointing from "ngOnChange" to "ngDoCheck" labeled "Not first run." A white box with the text "1+ data-bound input properties change" appears to the top left of "ngOnChanges" and points to it. The right boxes, from top to bottom, read: "First time called?, ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, and ngAfterViewChecked." The arrow from "First time called?" to "ngAfterContentInit" is labeled "Yes," and there is an additional arrow pointing from "First time called?" to "ngAfterContentChecked" labeled "No." The arrow from "ngAfterContentChecked" to "ngAfterViewInit" is labeled "First time called," and an additional arrow points from "ngAfterContentChecked" to "ngAfterViewChecked" labeled "Not first time called."
An overview of Angular component lifecycles.

The provider lifecycle, with its sole hook ngOnDestroy, is less commonly discussed. This hook is activated only when the provider is linked at the component level, leading to its destruction alongside the component. If the provider is provided at the root or module level, it will never get destroyed.

The constructor of a provider is executed when the provider is first utilized, implying that it might never be called. Testing your candidate’s awareness of this possibility is crucial, as it represents a frequent source of bugs in real-world applications.

Mastering Reactive Programming

Reactive programming is often the most challenging aspect of Angular development to grasp. Many beginners gravitate toward a procedural approach, viewing it as more intuitive and straightforward, much like following a recipe.

However, reactive programming centers around responding to events beyond our control, events that might occur unpredictably. While we navigate such scenarios daily—for instance, braking when a car in front of us halts abruptly—many developers struggle to apply this reactive mindset to programming.

However, reactivity underpins the entire functionality of an Angular app. Consider these examples within the context of an Angular shopping application:

  • Upon user login, the shopping cart icon updates to reflect the item count, and menu options personalize.
  • Navigating to a product category triggers an update, displaying products relevant to the selection.
  • Adding a product to the cart modifies the shopping cart icon to reflect the updated item count.
  • If an item becomes out of stock (as detected through a listener monitoring real-time inventory levels from the back end), the page UI dynamically reflects this change.

It’s crucial to understand that these updates happen seamlessly without requiring a page refresh. During the interview, request that the candidate describe their experience implementing reactive programming in a previous project. Be wary of solutions involving page refreshes or manual calls to ChangeDetectorRef.detectChanges() for component refreshes, as these might indicate a lack of depth in their understanding.

Novice developers might encounter situations where their Angular code doesn’t execute as expected. Experienced Angular developers recognize a common culprit: the absence of a subscription on an Observable, a fundamental object type in reactive programming. A subscription is essential for triggering back-end calls or other reactions.

Subscriptions can be created in two ways: utilizing the async pipe or the subscribe method. However, it’s important to remember that manual subscriptions (using the subscribe method) necessitate manual destruction of the Observable (although there are exceptions where this happens automatically). Developers can destroy Observables through various methods:

  • Employing the async pipe whenever possible (this automatically destroys the Observable when the component is no longer required).
  • Manually unsubscribing via the unsubscribe method on an Observable at the end of the component’s lifecycle (ngOnDestroy).
  • Opting for a more declarative approach by utilizing the takeUntil operator within the pipe operator and employing a subject (e.g., destroy$). In this scenario, the subject emits destroy$.next() at the end of the component’s lifecycle (ngOnDestroy). Once the destroy event is received, the takeUntil operator ceases to accept events from its associated Observable, preventing further triggering of its subscriber logic. For a practical example, refer to the takeUntil operator in section 2. Similar behavior can be achieved using the take and takeWhile operators.
  • With the adoption of the Ivy compiler in Angular applications, annotations can be leveraged. Libraries like The until-destroy library or third-party solutions like SubSink simplify the process of unsubscribing from observables upon component destruction.

Another potential challenge in reactive programming stems from memory leaks and redundant back-end calls. Inquire whether candidates are aware of these issues and how they would typically address them. Memory leaks can arise from neglecting to unsubscribe from Observables, as highlighted earlier. The problem of multiple back-end calls due to multiple subscriptions on a single back-end call can be mitigated by sharing the Observable.

Understanding and Managing State

All single-page applications rely on a state, which is maintained on the front end. But what exactly constitutes a state? Simply put, it encompasses all the variables that define the current user experience. This could include details of the authenticated user, like name and profile picture URL, the selected menu item, or displayed lists, such as shopping cart contents.

In Angular applications, there are three primary types of front-end state:

StateScope
ApplicationGeneral information available to the entire application such as authenticated users, user roles, menu items, or a user’s shopping basket. Anything that changes in this state will change for the whole application.
ModuleInformation available to the entire module where a service is used. Every time a developer reuses a module with providers, it creates a new instance of each provider. The state will never be destroyed and will only be created the first time a given provider is used.
ComponentInformation available to a certain component. Components are the smallest parts of an application. An Angular application can have multiple component states, but they will only be accessible through each component. The state will be created when the component is created and destroyed when the component is destroyed.

A strong understanding of state, including when to load and reload it, is a critical skill to seek in Angular developers. Evaluating code samples from candidates provides valuable insight into their state management practices. When a candidate utilizes a library for state management, pay attention to the following:

  • The use of NgRx, Akita, NgXs, or similar state management libraries.
  • The presence of notifications for effects, action, reducer, store, and selector in the relevant code.

Let’s examine the general flow of application state in NgRx, which shares similarities with Akita and other libraries, as an example:

A white "Selector" box on the top left points down to a green "Component" box on the bottom left, which points right to a white, layered "Action" box. The "Action" box points up to a white, layered "Reducer" box and right (with a dotted arrow) to a white, layered "Effects" box. The "Reducer" box points up to a blue "Store" box, which points left to the "Selector" box. On the bottom right, the "Effects" box points left (with a dotted arrow) to the "Action" box and up to a green "Service" box. The "Service" box points down to the "Effects" box and up to a green cylinder stack. The green cylinder stack points down to the "Service" box.

When developers implement their own state management using services, assessing their proficiency can be more nuanced. Look for:

  • References to keywords like state or effect.
  • Code segments that react to specific actions, such as a text change on Screen B triggered by the user clicking Button A.

Interview Questions About State

Code review alone might not reveal everything about a candidate’s understanding of state. Here are some questions to gauge their depth of knowledge:

  • How and where have you implemented state in your projects? This open-ended question allows candidates to elaborate on their experience with state management.
  • How do you determine whether a library is necessary for a particular project? Candidates who understand that state management libraries aren’t always necessary demonstrate good judgment.
  • How would you structure and utilize a state management system, including deciding what data to store and where? Be wary of candidates who suggest storing everything in the global application state, as this indicates a lack of awareness of the potential drawbacks.

Skilled developers understand the nuances of different state types and avoid these pitfalls:

  • State data relevant only to a single component should be isolated to prevent unintended modification or corruption by other components.
  • Excessively nested data within the store hinders readability and maintainability, making debugging and data exchange cumbersome.
  • Changes within a form should be reflected in the global state only upon saving, preventing other parts of the application from consuming and potentially misinterpreting invalid or incomplete data.

Failing to manage state effectively can lead to a disorganized and difficult-to-maintain global store, making it challenging to pinpoint the source of issues.

Recognizing the Importance of Automated Testing

Automated testing is as critical as code quality in Angular web application development. One of its primary purposes is to document the codebase. A well-structured test suite should clearly communicate the business logic and expected UI flows to new developers joining the team. Additionally, automated testing helps identify and address bugs early in the development lifecycle.

During interviews, pose these three testing-related questions to potential Angular developers:

  • What is your perspective on testing in software development? Candidates who downplay the importance of automated testing should be treated with caution. While not everyone embraces test-driven development (TDD), dismissing the value of automated testing suggests potential challenges with manual testing overhead and, more importantly, increased risk of end-user downtime due to regressions introduced by code changes.
  • What aspects of an application do you prioritize when writing tests? A strong Angular developer should prioritize testing core business logic over trivial functionalities like field value assignments or achieving arbitrary code coverage metrics (e.g., 85% coverage).
  • In your experience, is it more common to have a higher number of E2E tests or unit tests, and why? Angular applications, being front-end applications, can benefit from both unit and end-to-end (E2E) tests. A well-balanced test suite usually comprises numerous unit tests and fewer E2E tests. Unit tests are concise, making them quick to write and execute. Conversely, E2E tests are more extensive and time-consuming. Keep in mind that opinions vary among developers regarding the ideal ratio of unit to E2E tests. Ultimately, the appropriate balance depends on the complexity of the application being tested, and even then, there’s room for debate.
A flowchart starts on the top left, with a split light blue and green box. The light blue portion has the text "What are your thoughts on testing?" and the green portion has the text "Does the candidate care about automated testing?" From the green portion, a "No" arrow points right to a dark blue box that says "Candidate does not have suitable testing skills" and a "Yes" arrow points down to another split box. The second box's light blue portion has the text "What do you focus on when testing?" and the green portion has the text "Does the candidate focus on testing key business logic (going beyond code coverage percentages)?" From the green portion, a "No" arrow points right to a dark blue box that says "Candidate may not have suitable testing skills" and a "Yes" arrow points down to another split box. The third box's light blue portion has the text "Are there usually more E2E tests or more unit tests? Why?" and the green portion has the text "Does the candidate understand the importance and purpose of both unit and end-to-end testing?" From the green portion, a "No" arrow points up and right to the dark blue box that says "Candidate may not have suitable testing skills" and a "Yes" arrow points right to a dark blue box that says "Candidate has suitable testing skills."
A guide to testing interview questions for Angular developers.

Familiarizing Yourself with Angular Testing Frameworks

Angular developers have several testing frameworks at their disposal. Unit testing can be performed using Jest or a combination of Jasmine and Karma. Familiarity with Jasmine and Karma is expected of any Angular developer. Jest, known for its speed and advanced testing features, is also gaining popularity.

Protractor, the default tool included in the Angular CLI, is the standard framework for E2E testing in Angular applications. An alternative is Cypress, a promising E2E testing framework offering a wide range of features.

Ensure that the candidate possesses in-depth knowledge of at least one unit testing framework and one E2E testing framework.

Staying Abreast of Angular Releases

While pragmatic reasons might prevent developers from always using the latest version of Angular in development, a good Angular developer stays informed about the Angular release schedule. This awareness enables them to adapt to changes and transition smoothly when necessary. To assess this, ask candidates about their familiarity with the release strategy of Angular. Angular typically has a major release every six months, usually around February and May. Each version receives six months of “active support” followed by 12 months of “long-term support”. This relatively short support timeline emphasizes the importance of keeping up-to-date with the latest developments.

To further gauge their knowledge, research the latest Angular version and inquire about the advantages of its new features. For instance, when Angular 14 was released, relevant questions could have included those about:

  • Standalone components, which minimize the need for Angular modules. These standalone components are not declared within any existing NgModule and manage their dependencies independently. As a result, they can be directly depended upon without requiring an intermediary NgModule.
  • Typed forms, another significant update in Angular 14, which made strict typing the default for Angular Reactive Forms. This enhancement ensures that values within FormControls, FormGroups, and FormArrays are type-safe across the entire API, resulting in more robust forms, especially for complex, deeply nested scenarios.

Assembling a Top-Tier Angular Team

The specific skills and knowledge most important in an Angular developer will vary based on the project and team dynamics. However, a firm grasp of the fundamental concepts outlined in this article equips hiring managers to actively and effectively participate in the hiring process, even during technical evaluations.

The Toptal Engineering Blog expresses gratitude to Ramazan Yıldız for his valuable contributions in reviewing the technical content and diagrams presented in this article.

Licensed under CC BY-NC-SA 4.0