BLOG

| By Codeit | September 28, 2026
Angular Code Smells

Angular Code Smells: What to Look for During Code Review

Code reviews are not only about finding bugs. They are also a good opportunity to catch patterns that can make an Angular application harder to maintain, test, and understand.

Here are some common Angular code smells worth looking for during a code review.

 

1. Too Much Logic in Components

 

A component should mainly handle UI-related responsibilities. If it contains complex business logic, API handling, transformations, and state management all together, it can quickly become difficult to maintain.

 

Code smell:

save(): void {

    // validation

    // data transformation

    // API call

    // state updates

    // error handling

}

Better: Move business logic into services, facades, or dedicated state-management layers where appropriate.

 

2. Large Components

 

A component with hundreds of lines and many responsibilities is usually a sign that it could be split.

 

During review, look for:

  • Multiple unrelated responsibilities
  • Large lifecycle methods
  • Many private helper methods
  • Complex template conditions
  • Repeated logic

If a component is difficult to understand as a whole, it is probably doing too much.

 

3. Repeated Logic

 

Duplicated logic makes code harder to maintain and increases the risk of inconsistent fixes.

During code review, look for the same business rules, conditions, calculations, or transformations repeated across multiple components or services. When the same logic appears in several places, consider extracting it into a shared utility, service, or reusable method.

The goal is to keep each piece of business logic in one clear, maintainable place.

 

4. Unnecessary subscribe() for One-Time Actions

 

Not every observable operation needs to be subscribed to directly in the component.

When a subscription is only used to trigger an operation, consider whether the service can handle the observable internally instead. This keeps subscription logic out of the UI layer and allows components to focus on user interaction and presentation.

The goal is to keep components focused on presentation and user interaction.

 

5. Overusing subscribe()

 

Having many manual subscriptions can make components harder to read and can introduce memory-leak risks.

 

Instead of:

 

this.service.data$.subscribe(data => {

     this.data = data;

});

 

consider whether Angular's template mechanisms or signals can handle the data directly.

For subscriptions that are necessary, make sure their lifecycle is properly managed.

 

6. Complex Templates

 

Templates can become difficult to understand when they contain deeply nested conditions or repeated expressions.

 

Code smell:

 

When conditions become complicated, consider exposing a clearly named computed value:

readonly isSaveDisabled = computed(

     () => !this.formValid() || this.isReadOnly() || this.loading()

);

 

This makes the template easier to read and review.

 

7. Incorrect or Excessive Change Detection Work

 

Be careful with methods called directly from templates:

 

{{ calculateSomething() }}

 

If the method performs expensive work, it may run more often than expected.

 

Depending on the situation, consider:

  • Signals/computed values
  • Pipes
  • Memoized values
  • Preparing data before rendering

 

The important question during review is:

 

"Does this calculation really need to happen during every change-detection cycle?"

 

8. Using 'any' Everywhere

 

'any' can hide problems instead of solving them.

function handleData(data: any) { }

Prefer meaningful types or interfaces:

function handleData(data: Customer) {}

Strong typing makes refactoring safer and makes the code easier to understand.

 

9. Nested Subscriptions

 

This pattern is usually a warning sign:

 

this.userService.getUser().subscribe(user => {

    this.orderService.getOrders(user.id).subscribe(orders => {

        ...

    });

});

 

Nested subscriptions can make asynchronous flows difficult to follow.

Depending on the use case, operators such as switchMap, combineLatest, or forkJoin can make the flow clearer.

 

10. Forms With Scattered Validation Logic

 

When form validation is spread across multiple methods and components, it becomes difficult to determine why a form is invalid.

 

During review, check:

 

  • Where validators are defined
  • Where validity is updated
  • Whether errors are cleared consistently
  • Whether business validation is mixed with UI validation

 

Keep form-related responsibilities predictable and centralized where possible.

 

11. Magic Strings

 

Code like this:

 

if (processType === 'STANDARD') {}

 

can become error-prone when the same values are used throughout the application.

Consider constants or enums where appropriate:

 

if (processType === ProcessType.STANDARD) {}

 

This also makes refactoring easier.

 

12. Comments Explaining Bad Code

 

A comment should explain why, not compensate for code that is difficult to understand.

If you find yourself writing:

 

// We need to do this because...

 

for a complicated block, first ask whether the code itself can be simplified or extracted into a well-named

method.

 

Good naming often removes the need for comments.

 

A Simple Code Review Checklist

 

When reviewing Angular code, ask:

  • Is the component doing too much?
  • Is business logic in the right layer?
  • Is there duplicated logic?
  • Are subscriptions handled safely?
  • Are templates simple and readable?
  • Are signals/computed values used where they improve clarity?
  • Is the code strongly typed?
  • Are forms and validation easy to follow?
  • Are there unnecessary change-detection calculations?
  • Can another developer understand this code without extra explanation?

 

Final Thought

 

Not every code smell means the code is wrong. Context matters.

The goal of a code review is not to make every piece of Angular code look identical. It is to identify patterns that could make the code harder to maintain, test, or extend.

A good review asks a simple question:

 

“Will this code still be easy to understand when we need to change it six months from now?”

 

A good Angular code review isn't about making the code look cleaner. It's about improving the boundaries, ownership, coupling, and behavior of the system so that the next change is cheaper than the last one.