1 of 21

How TDD helps you build modular Angular apps

Full-stack engineer

matejchalk

matejchalk

Matěj Chalk

@

2 of 21

How can this be prevented?

Drowning in tech debt?

  • large portions of code are considered legacy
  • adding features is harder than before, mostly fixing bugs
  • fixing a bug causes other unexpected bugs
  • refactoring is too scary, developers are scared to touch existing code
  • senior developers are burned out
  • onboarding process is slow

3 of 21

Modular architecture design

  • as engineers, our job is to solve problems
  • to solve complex problems, break them down into simple problems

4 of 21

Unit tests and TDD

  • unit tests
    • bottom-up approach to testing
    • fast to write, fast to run
  • test-driven development (TDD)
    • design code with testability in mind
    • ability to write tests before implementation (TDD cycle)
    • increases effort in initial phases, reduces effort in later phases

5 of 21

Example of TDD flow

  1. design function signature without implementing

  • prepare unit tests

  • implement function (tests go from failing to passing)

6 of 21

Selective unit testing

  • Selective Unit Testing - Costs and Benefits by Steve Sanderson
  • unit testing is most beneficial for complex logic
    • algorithms - parsing, formatting, transformations, filtering, …
    • pure functions are ideal
  • unit testing code with many dependencies requires a lot of mocking
    • side-effects (e.g. API requests, DOM interaction), integration layers (e.g. adapters, wrappers), ...
    • dependencies increase maintenance effort

7 of 21

😊 String formatting

8 of 21

😊 Regular expressions

9 of 21

😊 Object transformations

10 of 21

😒 Wrapper service for HttpClient (1)

11 of 21

😒 Wrapper service for HttpClient (2)

12 of 21

Decision tree for unit testing

13 of 21

Tips for writing good unit tests

  • a good test works as documentation
    • describes behaviour
    • automatic proof (unlike other doc formats)
  • each unit test should be independent of others
  • forget DRY principle (Don’t Repeat Yourself)
  • stick to KISS principle (Keep It Simple, Stupid)

14 of 21

github.com/matejchalk/tdd-demo

Demo time!

15 of 21

Nx workspace

  • “smart, extensible build framework” by Nrwl
  • minimal learning curve for Angular developers
  • modern tech stack
    • Jest > Karma/Jasmine
    • ESLint > TSLint
    • Cypress > Protractor
  • first-class support for multiple FE/BE frameworks within same monorepo
    • e.g. Angular + Nest.js, React + Express, Next.js, Gatsby, ...

$ npx create-nx-workspace

16 of 21

Nx workspace (continued)

  • organizes reusable code into libraries (modular architecture)
  • manages dependency graph
    • automatic constraints (workspace lint rules)
    • optimized CI (only affected apps/libs)

17 of 21

Storybook

  • tool for building UI components in isolation
  • document use cases as stories
  • highly extensible with addons

$ npm i -D @nrwl/storybook

$ nx g @nrwl/angular:storybook-configuration

18 of 21

github.com/matejchalk/tdd-demo

Demo time!

19 of 21

Other tips to increase code quality

  • don’t start implementing straight away
    • first analyze the problem and design your solution
  • think hard about naming
    • “There are only two hard things in Computer Science: cache invalidation and naming things.”
    • names tend to stick around, so pick a good one (self-documenting)
    • be consistent to avoid confusion (no synonyms, consider a glossary)
  • make a habit of breaking up large source modules into smaller ones - before it’s too late!
    • agree on a max value for LOC in your project (lint rule)

20 of 21

Summary

  • tech debt can be effectively managed by modularizing app architecture
    • well-worn idea, but still hard to achieve without guidance
  • selective unit testing imposes useful constraints re: maintainability
    • deconstructing into small isolated modules
    • separation of concerns (e.g. business logic vs UI rendering)
    • single responsibility principle
  • tools like Nx help maintain a clean dependency graph
    • avoid circular dependencies
    • loose coupling, clear relationships
  • tools like Storybook help isolate UI concerns from app logic
    • “smart” vs “dumb” (aka presentational) components

21 of 21

Full-stack engineer

matejchalk

matejchalk

Matěj Chalk

Q&A

@