SlideShare a Scribd company logo
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! ✌
● 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
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)
Key Principle #1
Define the role of our service using DDD
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
Node.js Service - Best practices in 2019
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
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.
Understand relations between your domains
Upstream VS downstream
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
Key Principle #2
Skeleton for our service - Software Architecture
The SOLID principles
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
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
SOLID principles in Typescript
Node.js Service - Best practices in 2019
SOLID - Single responsibility principle
A class should have only one responsibility.
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
SOLID - Open-closed principle
Software entities should be open for extension, but
closed for modification.
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
SOLID - Liskov Substitution principle
A subclass should behave in such a way that It will
NOT cause problems when used instead of the
superclass.
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
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.
Node.js Service - Best practices in 2019
Node.js Service - Best practices in 2019
Dependency injection tool in Typescript
https://github.com/inversify/InversifyJS
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.
Implementing the clean architecture
Node.js Service - Best practices in 2019
Robert C. Martin (Uncle Bob), 2012
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
The dependency rule: This rule says that source code dependencies can only point inwards.
Robert C. Martin (Uncle Bob), 2012
OK - What’s the real implementation
looks like?
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.
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)
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
Key Principle #3
Observability
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
© Matias
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:
Key Principle #4
Performance bottleneck analysis and tracking
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
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
Key Principle #5
Automated deployment with Kubernetes
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)
Node.js in K8S - Docker part - Be aware of vulnerabilities!
Node.js in K8S - Docker part - Example
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)
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
Example of liveness and readiness probes definition
Any code greater than or
equal to 200 and less than
400 indicates success.
Deployment & ConfigMap K8S YAML example
Node.js Service - Best practices in 2019
Thank you ! ✌

More Related Content

Node.js Service - Best practices in 2019

  • 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)
  • 4. Key Principle #1 Define the role of our service using DDD
  • 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
  • 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
  • 12. Key Principle #2 Skeleton for our service - Software Architecture
  • 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
  • 16. SOLID principles in Typescript
  • 18. SOLID - Single responsibility principle A class should have only one responsibility.
  • 25. SOLID - Open-closed principle Software entities should be open for extension, but closed for modification.
  • 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.
  • 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.
  • 35. Dependency injection tool in Typescript
  • 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.
  • 38. Implementing the clean architecture
  • 40. Robert C. Martin (Uncle Bob), 2012
  • 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:
  • 51. Key Principle #4 Performance bottleneck analysis and tracking
  • 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
  • 54. Key Principle #5 Automated deployment with Kubernetes
  • 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!
  • 57. Node.js in K8S - Docker part - Example
  • 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.
  • 61. Deployment & ConfigMap K8S YAML example
  • 63. Thank you !