Angular EnterpriseAngular Enterprise

Bad practices to avoid in Angular

  • Courses
  • 13 practices
  • 4 min read
Bad practices to avoid when developing with the Angular framework

Here we have gathered a list of bad practices to avoid when you are developing an Angular application. Before starting a new project it's highly recommended to make a similar list based on your previous experience: it will help you learn from past lessons and avoid making the same mistakes again and again.

  • deeply nested logic structures (if/else blocks, nested subscribe calls, nested templates) make the code hard to read, test and maintain. Prefer early returns, small functions, RxJS operators or computed signals.
  • lack of a clear design pattern such as container/presentational components results in a codebase that is hard to read, debug, test and maintain. Also called smart/dumb components, this pattern should be used everywhere in the app.
  • lack of application monitoring and error tracking at the beginning of the project such as Sentry. It results in tons of bugs the day you install it and then you have to work for months in order to rid the app of all those bugs.
  • lack of pure functions: developers are used to writing impure functions which change the state of the component variables inside the function, this results in side effects and functions that are not testable. It's harder to write pure functions but it results in code that is easier to maintain.
  • lack of simple typings for objects, functions, inputs and outputs: developers sometimes use any instead. If in addition you don't have unit tests then your code is very vulnerable to errors.
  • lack of readonly and DeepReadonly typings results in unsafe code and possible mutation of any attribute in the codebase, functions will potentially have side effects.
  • lack of a clear pattern for overriding the existing theme. A clear convention should be used, for instance if you want to customize Angular Material there are many different cases to know (theme variables, overlay components, regular components...). Recent versions of Angular Material expose design tokens and overrides Sass mixins for this purpose: prefer them to overriding internal CSS classes.
  • lack of splitting into lazy-loaded features (lazy routes with loadComponent/loadChildren, or lazy modules in older applications) results in a big main bundle, but it also makes the app more and more coupled and later it becomes almost impossible to split the codebase.
  • wrong usage of NgRx: the global store should be used only for certain types of entities which are shared, hydrated, available, retrieved or impacted (the SHARI principle). That's also why new solutions emerged (ComponentStore, then SignalStore and plain Angular signals) in order to give developers the ability to store data in a local state instead of the global NgRx store.
  • usage of ::ng-deep without :host affects the CSS of the other components and breaks the style isolation principle. The way to avoid that is to use :host ::ng-deep or, even better, CSS variables to override the style as explained in our best practices guide. Those errors are also due to the fact that Angular Material renders part of some components outside of them, in a detached overlay panel which pops on top of the view, for instance when a mat-select is open.
  • accumulation of circular dependencies warnings will make your app less and less maintainable. Each time you detect a circular dependency it's recommended to take the time to fix it.
  • using combineLatest in an NgRx effect to read the store triggers unexpected actions each time one of the sources emits. It is strongly advised to use concatLatestFrom (from @ngrx/operators) or withLatestFrom in order to be sure that you are not going to listen to future events.
  • usage of the deprecated Sass @import rule in each component produces a lot of duplicated code, use @use and @forward instead.

Up next

Learn more about Angular