Presentation from Nodejsday.it Verona in 2019.
Timeline :
1. DDD scoping of our service
2. Software architecture (SOLID principles, Clean architecture)
3. Make our service observable (logging, monitoring, alerting)
4. Monitor key performance metrics and avoid bottleneck
5. Make it ready for Kubernetes (Stateless, Docker, Probes)
1. Key principles for a Node.js application in 2019
Designing Node.js applications for scalability, observability,
maintainability and K8S deployability
Olivier Loverde
CTO @Innovorder
PS: We’re HIRING! ✌
2. ● Passionate about software engineering and
architecture
● Former Cedexis (sold >100M€ to Citrix)
● Currently CTO @Innovorder: foodtech startup
based in Paris who has raised 10M€+ (20 people in
engineering team)
● Hobbies include microelectronics & biohacking
About me
@loverdeolivier
3. Timeline
1. DDD scoping of our service
2. Software architecture (SOLID principles, Clean architecture)
3. Make our service observable (logging, monitoring, alerting)
4. Monitor key performance metrics and avoid bottleneck
5. Make it ready for Kubernetes (Stateless, Docker, Probes)
5. A way of identifying your domains
It provides in a couple of days a way to
collaboratively design an architecture :
● Domain events
● Domain definition
● Functional areas (i.e: Bounded Context)
● Relation between domains
6.
7. Event Storming
1. Share knowledge and identify domain events
2. Think in terms of processes onward and backward
3. Identify domain boundaries
4. Classify domain type
5. Find domain relationship
8. Identify your domain using DDD
1. Core domain - Most of the focus should be spent here
Most important assets. These are the functional areas that make your competitive advantage.
2. Supportive domain
Too specific to buy, but not differentiating enough to build any competitive advantage.
3. Generic domain
They can be reused across many industries. It's not a good time investment to build your own.
11. Key Principle #1 - Summary
1. Use Event Storming for defining your domains
2. Classify your service into kind of domains (core, supportive or generic?)
3. Find the relationships between your domains
14. SOLID Principles
1. Single responsibility principle
2. Open / Closed principle : open for extension, closed for modification
3. Liskov substitution principle
4. Interface segregation principle
5. Dependency Injection Principle
15. SOLID Principles - Sorted by importance (from Robert C. Martin)
1. Single responsibility principle
2. Dependency Injection Principle
3. Open / Closed principle : open for extension, closed for modification
4. Liskov substitution principle
5. Interface segregation principle
18. SOLID - Single responsibility principle
A class should have only one responsibility.
19.
20.
21.
22.
23.
24.
25. SOLID - Open-closed principle
Software entities should be open for extension, but
closed for modification.
26.
27.
28.
29. SOLID - Liskov Substitution principle
A subclass should behave in such a way that It will
NOT cause problems when used instead of the
superclass.
30.
31.
32. SOLID - Interface Segregation principle
Clients should not be forced to depend upon
interfaces that they don’t use.
You should have many small interfaces in your
software.
37. Inversify.js
1. Allow JavaScript developers to write code that adheres to the SOLID principles.
2. Facilitate and encourage the adherence to the best OOP and IoC practices.
3. Add as little runtime overhead as possible.
41. What are we trying to achieve ?
● Avoiding module coupling
● Avoiding having pieces of business logic everywhere
● Doing tests properly
● Stop creating technical debt and having patches everywhere
● Create a maintainable system that grows nicely over the time
42. The dependency rule: This rule says that source code dependencies can only point inwards.
Robert C. Martin (Uncle Bob), 2012
43. OK - What’s the real implementation
looks like?
44. Folder structure
1. Stop using Controllers, Routes, Models folders
2. Use a layer-based folder structure :
○ src /
■ application/
● Use cases of your application.
■ domain/
● Models and repositories.
■ infrastructure/
● Communication with what is outside your application, like the database,
external services, etc.
● Interface such as http, amqp, etc.
45. Index.ts
1. Create an IoC container (using Inversify for instance)
2. Load each module into the container: application and infrastructure
3. Start your infrastructure (local connections, expose interfaces)
46. Clean architecture benefits
1. Respect SOLID principle
2. Each layer are fully testable
3. The dependency rule ensures a stable kernel
4. We keep the framework outside where they can do little harm
5. IoC reduces code coupling and increases maintainability
48. Node.js observability
1. We need to store, aggregate, process, graph and do alerts on our metrics
2. We need to be able to store custom metrics if needed
3. We need to store, view and query our logs in real-time
4. Metrics should be updated in real-time too
5. The system should be scalable and handle thousands of metrics and
services
50. Node.js observability
1. You expose a /metrics endpoint inside your Node.js application
2. The endpoint should not be exposed to Internet (private network only)
3. You can use NPM packages such as “prom-client” for doing it:
52. Monitor key perf metrics and avoid bottleneck
● Finding memory leaks:
○ Single process can have a maximum heap of 1.5 GB
○ In the V8 runtime, full garbage collection stops the program execution.
● KPIs
○ Process Heap Size
○ Time consumed for garbage collection
○ Counters for full garbage collection cycles (All heap)
○ Counters for incremental garbage collection cycles (Subset of heap)
○ Released memory after garbage collection
53. Monitor key perf metrics and avoid bottleneck
● The Event Loop
○ We want to avoid “event loop lag”
● Common causes
○ Long-running synchronous processes
○ An incremental increase in tasks per loop
● KPIs
○ Slowest Event Handling (Max Latency)
○ Fastest Event Handling (Min Latency)
○ Average Event Loop Latency
55. Node.js in K8S
● Requirements:
○ Stateless application (i.e: no local state defined in our application)
○ Configuration management system and secret management (vault?)
○ A docker container encapsulate our application (i.e: no difference
between instances of our application)
○ Liveness and readiness probes
○ A working Kubernetes cluster (you can use Minikube for local dev)
56. Node.js in K8S - Docker part - Be aware of vulnerabilities!
58. Node.js in K8S - Docker part
● Use node-alpine version : lean and secure root image for node
● Use LTS version for node
● Principle of privileges minimisation (no root user please)
59. Node.js in K8S - Probes part
● We must implement two dedicated endpoints:
○ /readiness
■ K8S uses this endpoint to know if service is ready to receive traffic
○ /liveness
■ K8S uses this endpoint to know if service needs to be restarted
● Theses endpoints are defined in the YAML manifest of the service
60. Example of liveness and readiness probes definition
Any code greater than or
equal to 200 and less than
400 indicates success.