Microservices explained by the example of Seneca




Deutsche Version
Navigation with Esc, und
![johannes](images/johannes.png) ### [Johannes Hoppe](http://JohannesHoppe.de)
## Agenda
  •  Introduction   Microservice Architectures
  •  Presentation  Seneca - a Micro-Services toolkit for Node.js
  •   Some notes   Docker - an open platform for distributed apps
### Microservices ![img](images/micro-service-architecture.png)

1

### 1 application = 1 process
  • Monolith:  code is preferably centralized at one place
  • Technologies:  one stack (e.g. MSSQL / C# / HTML5 / JavaScript)
  • More features:  more LOC
  • Documentation:  operations manual is required
  • Deployment:  all at once, downtimes
  • Multitier architecture
         generalization own frameworks (bad idea!)
#### ... I worked on a lot of monolithic applications! And this is not bad at all, but...
## Time to Market!





etc. are using microservices
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. Martin Fowler

n

### 1 application = n services
  • Components:  small services, loose coupling
  • Technologies:  multiple technology stacks are possible
  • More features:  if possible, introduced by a new service
  • Documentation:  (implicitely) via RESTful APIs
  • Deployment:  every service on its own

?

Wait! That smells like # SOA (__s__ervice-__o__riented __a__rchitecture)
# SOA ### +the best of the web
  • e.g.
  • HTTP / REST / WebHooks / WebSockets - no SOAP!
  • maybe NoSQL
  • CI, DevOps, Cloud, Docker,

µ


*

fewer code per service

*

~ 100 LOC



[says Fred George](http://livestream.com/websummit/DeveloperStage2013/videos/33534085)
![img](images/logo-seneca.png)
### Before not __asynchronous__, no loose coupling ```js contenteditable // app.js var discountService = require('./discount-service.js'); var customerId = 121; var result = discountService.calculateDiscount(customerId); console.log('Discount for customer:', result.discount, '%'); ```
```js contenteditable // discount-service.js module.exports = { // returns applicable discount in % calculateDiscount: function(customerId) { return { discount: (customerId _LT_ 100) ? 10 : 5 } } }; ``` [Demo](https://github.com/JohannesHoppe/Presentations2015/tree/gh-pages/Microservices-Seneca/example/01_OrderWithDiscount)
### Installation
```cmd contenteditable cmd white $ npm install seneca $ node var seneca = require('seneca')(); ```
# ???
## ```javascript contenteditable if (customer.Id == 1) { /* :-( */ } else if (customer.Id == 2 _AMP__AMP_ customer.FirstName == 'Hans') { /* :-( */ } else { /* :-( */ } ```
# !
Example ### Discount for customer
Message from CheckoutService: ```javascript contenteditable { command: 'discount', customer: { /* customer */ }, products: [ { /* product1 */ }, { /* product2 */ } ] } ```
###### Example ### Discount Service
Is reacting on messages with the pattern ```javascript contenteditable { command: 'discount' } ``` It ignores all other messages.
###### Example ### Discount Service
Is reacting on messages with the pattern ```javascript contenteditable { command: 'discount', customer: { customerId: 2 } } ``` The more specific pattern is preferred.
### Patterns + Actions seneca.add(pattern, action): __asynchronous__ ```js contenteditable // app.js var seneca = require('seneca')(); seneca.use('./discount-service.js'); var customerId = 121; seneca.act({ role: 'discount-service', cmd: 'calculateDiscount', customerId: customerId }, function (e, result) { console.log('Discount for customer:', result.discount, '%'); }); ``` ```js contenteditable // discount-service.js module.exports = function() { // returns applicable discount in % var calculateDiscount = function(args, done) { done(null, { discount: (args.customerId _LT_ 100) ? 10 : 5 }); }; this.add({ role: 'discount-service', cmd: 'calculateDiscount' }, calculateDiscount); }; ``` [Demo2](https://github.com/JohannesHoppe/Presentations2015/tree/gh-pages/Microservices-Seneca/example/02_OrderWithDiscount_actions)
### Tests like a breeze ```js contenteditable var assert = require('should'), seneca = require('seneca'); describe('discount-service', function () { it('should give older customers a 10% discount', function (done) { seneca({ errhandler: done }) .use('../discount-service.js') .act('role:discount-service, cmd:calculateDiscount, customerId: 5', function (err, result) { result.discount.should.equal(10); done(); }); }); }); ```
### seneca-transport µservice starts here ```js contenteditable // act as a server seneca.listen(); // act as a client seneca.client(); ```
[Demo3](https://github.com/JohannesHoppe/Presentations2015/tree/gh-pages/Microservices-Seneca/example/03_OrderWithDiscount_microservices)
```cmd $ curl http://localhost:7777/act --data "{ \"role\": \"discount-service\", \"cmd\": \"calculateDiscount\", \"customerId\": 5 }" ```
## Seneca in a nutshell * [use-plugin](https://github.com/rjrodger/use-plugin) replaces require() * actions == pattern matching == JSON serializable * easy wiring

[Beginner's Guide to Seneca.js](http://jakepruitt.com/2015/02/09/beginners-guide-to-seneca-js.html)
### Tips * [seneca-web](https://github.com/rjrodger/seneca-web) URL routes for [express](http://expressjs.com/) * [chairo](https://github.com/hapijs/chairo) full integration into [hapi](https://github.com/hapijs/hapi) * [plugins](http://senecajs.org/plugins.html), plugins, plugins
![img](images/logo-docker-color.png)
### Docker Client on  
### Docker Client on   [Boot2Docker](https://docs.docker.com/installation/windows/)
#### Node.js OnBuild Docker Image ``` # Dockerfile FROM node:0.10.35-onbuild EXPOSE 3000 ``` ```cmd style=font-size:1em $ boot2docker start $ docker build --tag="app-server" . $ docker run -it --rm --name my-microservice app-server ```
[OnBuild Docker Image](https://github.com/docker-library/node/blob/master/0.10/onbuild/Dockerfile) | [build](https://docs.docker.com/reference/commandline/cli/#build) | [run](https://docs.docker.com/reference/commandline/cli/#run)
## Downloads ![tools](images/icon_file.png) #### [github.com/JohannesHoppe/Presentations2015](https://github.com/JohannesHoppe/Presentations2015/)
## Thank you!
*  [johanneshoppe.de](http://johanneshoppe.de) *  [@JohannesHoppe](https://twitter.com/JohannesHoppe) *  [Johannes.Hoppe](https://www.facebook.com/johannes.hoppe)

Created by Johannes Hoppe | Print PDF