Code Consistency With Examples & Services Framework
Maintaining consistent coding guidelines across medium to large organisation is always a very challenging task and making sure that those are followed properly is an another ball game. Although for small startups with team less than ~15, this information can reside in one person's mind (Founder/CTO) :).
So, how can we make sure that consistent set of coding principles are followed? In my opinion, the solution lies in making it easier for the developers to follow those guidelines. The next obvious question is that how can we do that??
We will talk about code examples and service templates/chassis and how these two approaches can help us achieve our goal!
Code Examples
We should have specific code examples in the guidelines rather than generic coding principles and philosophy.
Let's see below a sample coding guidelines of a hypothetical organisation
1. Be explicit rather than implicit:
Being explicit means being concrete and specific instead of
abstract and general.
It also means not to hide the behaviour of a function.
2. Consistent logging structure:
- Make sure to use only allowed fields as part of any log
statement
- Do not create custom logger objects
.
. <More guidelines>
.
As you can see from the above example, the author of the above guidelines has left many things to the reader's interpretation. The guidelines were shared but they were not made specific with good and bad examples.
Let's see an improved version (examples credit ) of the above mentioned guidelines
1. Be explicit rather than implicit (https://miguelgfierro.com/blog/2018/python-pro-tips-understanding-explicit-is-better-than-implicit/):?
- Being explicit means being concrete and specific instead of
abstract and general.
- It also means not to hide the behavior of a function.
<Bad Example>
def read(filename):
? ? # code for reading a csv or json
? ? # depending on the file extension
<Good Example>
def read_csv(filename):
? ? # code for reading a csv
def read_json(filename):
? ? # code for reading a json
2. Consistent logging structure
- Make sure to use only allowed fields as part of any
log statement.
<Bad Example>
import custom_log from custom_created_log_module
def read_csv(filename):
custom_log(custom_message_field=f'Reading CSV from file {filename}')
<Good Example>
import log from org_wide_common_log_module
def read_csv(filename):
# Here, 'message' is an allowed field to be used in logging
log.debug(message=f'Reading CSV from file {filename}')
# perform operation on file
.
. <More guidelines>
.
As we can see from the above guidelines, it becomes simpler for the developers to follow it as there are concrete examples and it leaves no room for interpretation.
Is coding guidelines sufficient or can we do better?
Coding guidelines go a long way to write consistent code but in the end they are just guidelines! No matter how much well they are written, you would still need to invest considerable time in enforcing those guidelines on a consistent basis during code review process and by using static code checkers like Sonar .
Q. What if we can reduce the amount of code written and at the same standardised common use-cases?
Whenever you create a new micro service, there is always an additional burden of writing the plumbing code i.e infrastructure connectivity, service discovery for a downstream service, logging, observability etc. (I have copied the meaning of "plumbing" from Pete Hodgson's excellent blog on Service Templates and Service Chassis). These necessary logics are needed to make sure that the service works smoothly in a micro service environment.?
But does every team need to write the same piece of logic again and again? As you have guessed it, there is no need for every team to write the same piece of logic again. So the solution is to create and use a common runtime framework which provides all these necessary non-business (plumbing code) centric functionality so that the business related micro services can focus entirely on the business logic!
In the next section, we will talk about service template and service chassis and how it can help ease the life of developers?
领英推荐
What is a service template?
Service template is a ready to use "Hello World" micro service which any team can use?to create a new micro service. On other words, it can be a sample git repo which anyone can clone to create their new service. This repo can have the necessary docker files, folder structure, rest clients etc. Simple enough!
The limitation with this approach is that it becomes increasingly difficult to keep the clone services up to date with the changes in the original sample repo and very quickly, teams will start drifting away from the original cloned version and would start creating their own optimisation.?
What next? We can overcome this limitation of drifting way by creating a common framework and a set of smaller libraries. These libraries can be injected into any service at the time of creation and can be updated with simple version upgrade.
In the below example, we have created a common framework having all the basic functionalities like logging, service discovery, health check and metric etc. Other optional libraries like caching and queue handler can be exposed separately since every service might not need them.
This method of creating a broad set of independent functionalities into framework and libraries is called Service Chassis or Service Framework.
Does this approach has any limitations?
Now comes another big question, does it makes sense for your org. to invest engineering bandwidth into this??
If you are a startup and you have not yet achieved product market fit or you have achieved market fit but still have not decided to split your monolith then it doesn't make sense to create a service template and/or service chassis. Having a common service template would only help when you are planning to move towards micro services else it would be an additional overhead.?
On the other hand, if your startup has necessary bank balance for the next couple of years and has achieved product market fit and is planning towards breaking the monolith then it is the best time to invest bandwidth in such a framework.
What if your company is already huge and has micro service architecture but has not yet created services framework?
In this scenario, it becomes tricky. The best way here would be to start small and make sure new services are built using this new services framework. The goal here would be to bring in adoption and that can only come if we can make the transition smoother and writing code 10x simpler for the developer. For the rest of the services, start by targeting less critical services and slowly moving towards critical services. We should not target for creating a full blown framework in the beginning. Adoption is the key and keep iterating based on the feedback.
Hope this blog would have given you useful insight on code governance, coding guidelines and services chassis/templates.
For further reading, you can refer below resources.