13 KiB
13 KiB
Angular Code Guidelines
- Use modern Angular patterns and current framework conventions.
- Prefer standalone components, directives and pipes for new code.
- Avoid introducing
NgModuleunless the existing project architecture requires it. - Keep components small and focused.
- Keep templates simple.
- Move complex logic out of templates.
- Keep business logic out of components where practical.
- Prefer services, facades or dedicated domain logic for non-trivial behavior.
- Avoid god components and god services.
- Keep dependencies explicit.
- Prefer composition over inheritance.
- Avoid unnecessary abstractions.
- Avoid unnecessary wrapper components.
- Follow the existing project architecture unless there is a strong reason to change it.
Components
- Use
ChangeDetectionStrategy.OnPushunless there is a concrete reason not to. - Prefer signal-based state for local component state.
- Prefer
computedfor derived state. - Prefer
effectonly for actual side effects. - Do not use
effectas a replacement for normal data flow. - Keep component state minimal.
- Avoid duplicating derived state.
- Prefer immutable state updates.
- Avoid direct mutation of shared state.
- Keep inputs and outputs strongly typed.
- Prefer signal-based inputs and outputs when consistent with the project.
- Avoid unnecessary two-way binding.
- Avoid unnecessary component-to-component coupling.
- Prefer explicit data flow from parent to child and explicit events upward.
- Do not expose internal component state unnecessarily.
- Use lifecycle hooks only when required.
- Avoid complex initialization logic inside constructors.
Templates
- Keep expressions short and readable.
- Do not execute expensive methods from templates.
- Avoid function calls in templates when their result can be derived or cached.
- Avoid complex conditions directly in markup.
- Prefer derived state in TypeScript over repeated template expressions.
- Use Angular control flow syntax such as
@if,@forand@switchfor new code. - Always provide stable tracking for repeated collections.
- Avoid deeply nested template structures.
- Split large templates into focused components when it improves maintainability.
- Avoid unnecessary DOM elements.
- Use semantic HTML.
- Prefer native HTML behavior before custom implementations.
- Keep accessibility in mind when choosing elements and interactions.
Signals and State
- Prefer signals for local and synchronous reactive state.
- Prefer
computedfor derived values. - Keep signals private when external mutation is not intended.
- Expose readonly state where practical.
- Avoid storing values that can be derived from existing state.
- Avoid circular signal dependencies.
- Avoid side effects inside
computed. - Keep effects small and deterministic.
- Clean up resources created by effects.
- Do not use global state unless multiple unrelated parts of the application genuinely need it.
- Do not introduce a state-management library without a clear requirement.
RxJS
- Use RxJS for asynchronous streams, events and complex reactive flows.
- Do not use RxJS when simple synchronous signals are sufficient.
- Prefer declarative observable pipelines.
- Avoid nested
subscribe. - Avoid manual subscriptions where
async, signals or framework helpers are sufficient. - Prefer
takeUntilDestroyedor equivalent Angular lifecycle integration for manual subscriptions. - Always consider subscription lifetime.
- Avoid memory leaks from unmanaged subscriptions.
- Use the correct flattening operator for the required semantics.
- Do not use
switchMap,mergeMap,concatMaporexhaustMapinterchangeably. - Avoid unnecessary
Subjectusage. - Prefer exposing observables instead of exposing mutable subjects.
- Prefer
BehaviorSubjectonly when a current value is actually required. - Avoid excessive observable chains for simple state.
- Avoid converting repeatedly between signals and observables without need.
Dependency Injection
- Prefer Angular dependency injection for application services.
- Keep injected dependencies minimal.
- Avoid service locator patterns.
- Prefer
inject()where it improves readability and is consistent with the project. - Do not inject services that are not used.
- Scope services intentionally.
- Prefer application-wide singletons only for truly shared stateless or coordinated state.
- Avoid storing request-specific or component-specific mutable state in root services.
- Use injection tokens for configuration or abstractions where appropriate.
- Do not create interfaces only to satisfy dependency injection when no abstraction is needed.
Services
- Keep services focused on a clear responsibility.
- Avoid large catch-all services.
- Separate API access, domain logic and UI state where practical.
- Avoid leaking transport models throughout the application.
- Do not expose mutable internal state directly.
- Prefer readonly APIs for state consumers.
- Avoid hidden side effects.
- Keep service methods predictable.
- Do not use services merely to move poorly structured component code elsewhere.
HTTP and APIs
- Keep API access centralized and strongly typed.
- Prefer dedicated API clients or data-access services.
- Do not use
anyfor API responses. - Treat all server responses as untrusted at runtime.
- Validate external data when the contract is security- or correctness-critical.
- Keep DTOs separate from domain models when their responsibilities differ.
- Avoid duplicate API calls.
- Cache only when the invalidation strategy is clear.
- Avoid manual URL string construction when typed helpers or centralized endpoints are available.
- Use interceptors only for cross-cutting concerns.
- Do not put unrelated business logic into HTTP interceptors.
- Handle cancellation where appropriate.
- Handle expected error states explicitly.
Forms
- Prefer reactive forms for non-trivial forms.
- Keep forms strongly typed.
- Avoid untyped forms.
- Keep validation rules centralized and reusable where practical.
- Validate on both client and server where required.
- Never treat client-side validation as a security boundary.
- Keep form state separate from domain state when useful.
- Avoid large components that combine layout, validation, persistence and business logic.
- Display validation errors consistently.
- Preserve user input when recoverable errors occur.
Routing
- Keep route definitions explicit and predictable.
- Prefer lazy loading for larger feature areas.
- Avoid loading large feature bundles eagerly without need.
- Use route guards only for navigation behavior, not as a security boundary.
- Authorization must still be enforced on the backend.
- Keep resolvers focused.
- Avoid expensive work during navigation unless required.
- Keep route parameters strongly typed at application boundaries where practical.
- Do not rely on client-side routing state for sensitive authorization decisions.
Performance
- Use
OnPush. - Use stable tracking in loops.
- Avoid unnecessary change detection triggers.
- Avoid repeated expensive template calculations.
- Avoid unnecessary subscriptions.
- Avoid unnecessary DOM rendering.
- Lazy-load large features and heavy dependencies where appropriate.
- Avoid large initial bundles.
- Avoid importing full libraries when only a small part is required.
- Avoid unnecessary deep cloning.
- Avoid unnecessary object and array recreation in hot paths.
- Keep state updates targeted.
- Avoid unnecessary global state updates.
- Measure bundle size and runtime performance before micro-optimizing.
- Prefer architectural improvements over template-level micro-optimizations.
Security
- Treat all external data as untrusted.
- Never bypass Angular sanitization without a verified reason.
- Avoid direct DOM manipulation.
- Avoid
innerHTMLwith untrusted content. - Avoid
bypassSecurityTrust*unless explicitly required and the input is fully controlled. - Never expose secrets in frontend code.
- Never store sensitive credentials in the Angular application.
- Do not rely on frontend checks for authorization.
- Enforce authentication and authorization on the backend.
- Avoid leaking sensitive information through logs or error messages.
- Use secure cookie or token handling according to the application's authentication architecture.
- Avoid storing sensitive tokens in insecure browser storage without a deliberate security decision.
- Do not disable security controls for convenience.
DOM and Browser APIs
- Prefer Angular APIs and declarative templates over direct DOM manipulation.
- Use
Renderer2only when direct rendering abstraction is actually needed. - Avoid accessing globals directly when it harms testability or SSR compatibility.
- Consider SSR and hydration compatibility for browser-specific code.
- Guard access to
window,document,localStorageand similar browser-only APIs when SSR is supported. - Clean up event listeners, observers and timers.
- Avoid layout thrashing in performance-sensitive code.
Accessibility
- Use semantic HTML.
- Preserve keyboard navigation.
- Ensure interactive elements are actually interactive elements.
- Do not replace buttons with clickable
divelements. - Provide labels for form controls.
- Maintain visible focus behavior.
- Use ARIA only when native HTML semantics are insufficient.
- Avoid unnecessary custom widgets.
- Keep accessible names and states synchronized with UI state.
Styling
- Keep styles scoped and predictable.
- Avoid unnecessary global CSS.
- Follow the project's styling strategy consistently.
- Avoid excessive specificity.
- Avoid
!importantunless there is a concrete reason. - Prefer reusable design tokens and shared styles over duplicated magic values.
- Keep component styles focused on component concerns.
- Avoid styling based on fragile DOM structure.
- Do not mix multiple styling approaches without need.
Testing
- Test behavior, not implementation details.
- Prefer focused component tests.
- Test critical user interactions.
- Test services and domain logic independently where useful.
- Avoid brittle tests coupled to internal structure.
- Avoid excessive mocking.
- Mock external boundaries rather than internal implementation details.
- Keep tests deterministic.
- Avoid time-dependent tests without controlled clocks.
- Avoid network-dependent tests without proper isolation.
- Keep test setup minimal and readable.
- Update tests when refactoring changes structure but not behavior.
Architecture
- Keep UI, application, domain and data-access concerns separated where practical.
- Organize code by feature rather than by technical file type when it improves cohesion.
- Avoid circular dependencies.
- Avoid cross-feature imports without a clear contract.
- Keep shared code genuinely shared.
- Do not move feature-specific logic into generic shared modules.
- Avoid dumping unrelated helpers into global utility files.
- Keep public APIs of feature areas small.
- Avoid exposing internal implementation details across feature boundaries.
- Prefer local ownership of state and logic.
Code Quality
- Use strict TypeScript settings.
- Avoid
any. - Avoid unnecessary type assertions.
- Avoid non-null assertions unless safety is guaranteed.
- Prefer modern, readable syntax.
- Use descriptive names.
- Avoid vague names such as
data,item,valueortempwhen better names exist. - Remove dead code.
- Remove unused imports and dependencies.
- Remove commented-out code instead of keeping it in source files.
- Do not add comments unless the user explicitly requests them.
- Treat Angular, TypeScript and lint warnings seriously.
- Do not suppress diagnostics without a concrete reason.
- Prefer correctness, security and maintainability over cleverness.
Dependency Rules
- Prefer Angular and browser platform capabilities before adding third-party libraries.
- Do not add dependencies without a clear benefit.
- Avoid libraries that duplicate existing framework functionality.
- Avoid abandoned or poorly maintained packages.
- Keep Angular package versions aligned.
- Do not mix incompatible Angular package versions.
- Respect the existing lockfile and package manager.
- Avoid unrelated dependency upgrades.
Performance Priority
Prioritize Angular performance work in this order:
- Application architecture
- Network and API behavior
- Bundle size and lazy loading
- State architecture
- Change detection
- Rendering and DOM complexity
- RxJS and subscription behavior
- Memory allocations
- CPU micro-optimizations
Never optimize based purely on assumptions.
Safety Rule
- Angular frontend code is never a security boundary.
- Client-side validation, guards, hidden controls and disabled UI elements do not replace backend enforcement.
- Do not bypass Angular's built-in security mechanisms without a verified and explicit reason.
- Prefer safe framework defaults over custom low-level behavior.