Node.js Application Architecture without magic 🇵🇱 🇬🇧 2-3 days
About
Node.js provides more freedom compared to traditional enterprise ecosystems.
Although some individuals are attempting to transform Node.js into a framework-heavy enterprise platform, there is an alternative approach.
In this course we will learn how to build highly composable, type-safe and testable systems without a typical
enterprise framework magic.
If you have an aversion to magic or wish to unlearn years of practices such as using:
- Dependency Injection containers
- Class-based programming
- ORMs
- Technology-driven architectures
- Magical conventions
- @Transactional dandruff
- new Date() spread all over the place
- Handwritten DTOs
- Import mocking frameworks
- Reflection and metaprogramming magic
This course is for you.
The alternative to heavy enterprise frameworks is not Wild Wild West or building a custom framework.
The real alternative is to embrace the true nature of JS/TS, make full use of the good parts and never get prisoned in another heavy framework again.
What will I learn?
- Compose your building blocks with multiple composition roots and manual dependency injection
- Make full use of extremly composable functions instead of less composable classes
- Write type-safe DB access code that stays in sync with DB schemas and prevents you from mistakes
- Parse don’t validate your input and output data to be liberal in what you accept and strict in what you produce
- Organise your code around features, not technology layers
- Handle DB transactions without magic
- Program in a language, not in a framework
- Test with high ROI with smart testing strategies
- Make code testable and don’t let more than one invocation of new Date() sneak into your code
- Start your app in full in-memory mode by default
- Separate write model and read model
- Master transferrable skills that will outlive your enterprise framework du jour
Agenda
Engineering techniques and principles
- Minimal dependencies
- Curried functions over classes
- Parse don’t validate
- Robustness principle
- Full in-memory mode by default
- Feature-driven architecture
- Composition over convention
- End-to-end type safety
- Programming in a language, not in a framework
- Feature-flag driven development
Architectural building blocks and concepts
- Pipes and filters (express.js middleware and handlers)
- Ports and adapters
- Routers/controllers (express.js)
- Application services
- Repositories
- Error handlers
- Domain types and tiny types
- Input and output parsers
- DTOs for free
- Composition roots
- Write model vs read model
- External read model (view model) vs internal read model
- Application scope and request scope
Testing strategies
- Unit of behavior tests (mocha)
- Integration tests (mocha)
- Component tests (supertest)
- Testing without mocks
- Testing difficult dependencies (time, id generation)
- Data cleanup strategy
Integration with a SQL database
- DB migrations
- Type generation from DB schema
- Verifying repository contract
- SQL query builder
- Handling DB transactions
Type-safety
- Type-safe config (zod)
- Type-safe DB queries (kysely)
- Type-safe input and output (zod)
- Type-safe dependency injection
- Type-safe API paths (static-path)