I’m currently working on a big application that has been built up using microservices. The application is composed of small(ish) apps that compose the application. The idea is that these small apps work together to create the final application.
This greatly limits the complexity of the application, by separating it into small parts – divide and conquer. These parts can live on their own, or have some parts in common.
So we have some actual apps, which have user interfaces and a back-end, and then we have some “helper” apps (let’s call them components) that serve mainly as a service for the other apps.
We’re setting things up so that actually every app can be accessed by the other apps. This makes that adding a new app sometimes means that we just go “shopping” in the components, and possibly in the other apps. The actual work for the new app is then relatively limited.
How do we start with a new app?
I have given away the answer a bit already, but I worked out a “cookbook recipe” to implement a new app in a growing application. I am supposing that the functional analysis has been done already. Also, I don’t talk about database structures etc to keep the post lighter. Here are the steps:
Analyze the data that will be needed.
Find out if the data is already available in other (external) data sources. Try to find 1 single source of truth for your data. There is a good chance that the data already exists somewhere in your application, so you can access it from there.
Sometimes you may want to extend an existing app to provide this additional data. That is better than copying the data in your little database and start all over again. Reuse is key!
Analyze what is left. This should be the data that is specific for your service. If this is not the case: rinse and repeat!
Analyze the functionality
Find out if the new functionality already (partially) exists in other services or components. Same story: reuse.
What is left should again be specific for this service. If this is not the case: rinse and repeat!
Describe where and how you’re going to implement this functionality.
Create the necessary REST services
Describe the resources that you need. These will be the URIs for your REST services.
Describe the needed functionality. This will become the verbs for your services.
Create an initial Swagger file that contains these descriptions. This will help you later in the process to verify if you covered everything. Make sure that you only add resources and functionality that you need. For example: if you don’t want to be able to DELETE all your customers, then don’t provide a DELETE /api/Customers. Keep the YAGNI principle in mind.
Analyze the UX
Verify if you can cover all the data needs for the pages (or screens) that you want to create. The Swagger file that we just created will be of great help for this. Verify that you can cover all the needs, and that no more is in the Swagger file than is needed. Otherwise you’ll be implementing too much.
Verify if there are reusable UX components. For example if you’re using Angular, then there are some good chances that the way to input a data / time / customer / … have been standardized already, and that there is a library of standard “UX components” that you can use. If all is well there is a repository with all the reusable components.
Verify if some of the UX functionality that you need can be created as a reusable component. In that case: describe it in the repository and implement it.
Notice that so far we haven’t implemented anything yet. These steps may seem a lot of overhead, but in the end all that we’re doing here is promoting reuse at different levels. This means that now we know
- which components we should modify
- which components must be created
so we can work as a team to implement this new functionality in time.
Implement the REST interfaces
We have the Swagger files in place, and they have been verified against the UX. So now is the time to implement them. Or not?
First create some simple stub implementations. Once these are ready another team can start working on the UI while in parallel we create the REST services. This also forces us to think about the APIs first, so we know what we’re building.
Once the stubs are in place start by creating your unit tests (you knew this was coming!), implement the REST services one by one and unit test them. Once a service is ready use a tool like Postman, Fiddler, SoapUi, … Make sure that you can run all the tests automated, so you can run them as much as needed with very little effort.
Implement the UX
Once the REST stubs are ready UX can start using them. This doesn’t mean that we can’t do some useful work before, but having the stubs will allow us to implement the features completely, knowing that the back-end implementation will follow.
Use the UX components that we have found before as Lego blocks in your pages, reusing as much as possible.
And again: write unit tests (for example for Angular you can use https://angular.github.io/protractor/#/ or another testiong framework of your choice) and make them pass. When your functionality is ready; test it completely and make sure that everything works as expected.
Now you can move on to the next user story!
Perform integration tests
Run all the automated tests that have been created so far. If you extended other services then run their automated tests as well, making sure that all the tests pass.
Find out if some of the functional scenarios can be automated by using tools like Selenium. Scripting the tests will save you a lot of manual work afterwards. And yes I know, when the UI changes you’ll need to adapt your scripted tests, but in most of the cases these changes won’t be dramatic and you’ll benefit from the automated UI tests more than they cost you.
So now what is left is testing those scenario’s that you couldn’t automate. Don’t forget this step, you may miss some important problems.
So now you can merge your code and hope for the best. QA should take it from here.
There is always tension between QA and DEV because as a DEV we try to make sure that QA doesn’t find any bugs. As QA we know that DEV tried to write the code as perfect as possible and still we’ll need to find some bugs. This should be a positive tension!
We can see that in this whole flow development is not the main part. There is some preparatory work involved (sometimes referred to as technical analysis ), and there is a lot of testing involved. This guarantees that we don’t rewrite stuff, and that what we write is as good as possible. It should be easy to see that this saves a lot of work. Most of the preparatory work is usually done by an application architect, and then overseen by a lead developer.
This is of course just a framework that you’ll need to fill in for your own needs. Creating some flowchart may help visualize this for your team and your project leader.