"The dirty secret of the microservices movement is the heavy operational burden of service provisioning, discovery and interface specification. For many applications, e.g. those with logically grouped activities or that require single-tenant deployment, microservices are a “bridge too far.” In-place refactoring of monolithic applications with service-oriented architecture presents a 3rd-way between monoliths and microservices. OpenAPI provides the API specification and the supporting tooling ecosystem to define sensible service boundaries at the API-layer, substantially de-risking monolith refactors. We present a “war story”, targeted at software architects and developers, detailing the design and implementation considerations that allowed us to use OpenAPI to “break” our monolithic code-base into sensible services to support our life-sciences partners."
WSO2's API Vision: Unifying Control, Empowering Developers
LF_APIStrat17_Breaking a Monolith: In-Place Refactoring with Service-Oriented Architecture at a Life-Sciences Startup
1. Breaking a Monolith
In-Place Refactoring with Service-Oriented Architecture
at a Life-Sciences Startup
Ryan M Harrison, PhD
Head of Engineering
BioBright
12. 12
Code: 2016
exports.lastActions = function(req, res) { // data query for lastActions, ember data model
console.log("req: ", req.query);
var user = req.query.user; // get user
var x1 = Math.floor(req.query.x[0]); // get start of time range
var x2 = Math.floor(req.query.x[1]); // end of time range
coknexions[req.lab]('data') // query from data table on users lab
.whereIn('source', user) // query source
.whereBetween("x",[x1, x2]) // query range
.orderBy('x', 'desc') // oldest to newest
.then(function(r){ // results in r
res.json({lastActions:r}); // send in form expected by ember
});
};
13. 13
Self-reflection
exports.lastActions = function(req, res) {
console.log("req: ", req.query);
var user = req.query.user;
var x1 = Math.floor(req.query.x[0]);
var x2 = Math.floor(req.query.x[1]);
coknexions[req.lab]('data')
.whereIn('source', user)
.whereBetween("x",[x1, x2])
.orderBy('x', 'desc')
.then(function(r){
res.json({lastActions:r});
});
};
No documentation
14. 14
Self-reflection
exports.lastActions = function(req, res) {
console.log("req: ", req.query);
var user = req.query.user;
var x1 = Math.floor(req.query.x[0]);
var x2 = Math.floor(req.query.x[1]);
coknexions[req.lab]('data')
.whereIn('source', user)
.whereBetween("x",[x1, x2])
.orderBy('x', 'desc')
.then(function(r){
res.json({lastActions:r});
});
};
Minimal logging
15. 15
Self-reflection
exports.lastActions = function(req, res) {
console.log("req: ", req.query);
var user = req.query.user;
var x1 = Math.floor(req.query.x[0]);
var x2 = Math.floor(req.query.x[1]);
coknexions[req.lab]('data')
.whereIn('source', user)
.whereBetween("x",[x1, x2])
.orderBy('x', 'desc')
.then(function(r){
res.json({lastActions:r});
});
};
No input specification
(or validation)
No output specification
16. 16
Self-reflection
exports.lastActions = function(req, res) {
console.log("req: ", req.query);
var user = req.query.user;
var x1 = Math.floor(req.query.x[0]);
var x2 = Math.floor(req.query.x[1]);
coknexions[req.lab]('data')
.whereIn('source', user)
.whereBetween("x",[x1, x2])
.orderBy('x', 'desc')
.then(function(r){
res.json({lastActions:r});
});
};
Inadequate interface to DB layer
20. 20
Not tall enough
Dev portal
Monitoring
On demand infra scaling
Continuous Integration
Continuous Deployment
21. 21
Glide paths
API spec → API docs → Dev portal
Logging → Monitoring
Infra → On demand infra scaling
Testing → Continuous Integration
Deployment → Continuous Deployment
35. 35
Summary
API spec Borrow OpenAPI
Logging Borrow + Buy Bunyan +
CloudWatch
Infra Borrow Terraform
Testing Borrow Dredd
Deployment Buy ElasticBeanStalk or
ECS
36. 36
1:1 Service : Swagger controller
1:1 Service : CloudWatch log group
1:1 Service : Terraform Module
1:1 Service : Repo (or Container)
Service Oriented Architecture