Skip to content

The Code Templates for Basil CLI 🌿

License

Notifications You must be signed in to change notification settings

gardenbed/basil-templates

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Build Status Build Status Build Status Build Status Build Status Build Status

Basil Templates 🌿

This repository includes code templates for miscellaneous programming languages and technologies. Basil CLI uses these templates for creating new projects.

IDL

Interface Description Language or Interface Definition Language is a formal language for defining interfaces between components. It also allows defining data types for input and output parameters and validating such data types. By adopting an IDL (gRPC, Thrift, etc.) you can specify well-defined and strongly-typed interfaces for your services.

Slicing Domain

When it comes to organizing your service code into different packages or modules, there are generally two approaches. You can slice your domain either horizontally or vertically.

Horizontally

This approach is also known as layered architecture, onion architecture, etc. In this approach, you will slice your service into horizontal layers (packages or modules). Each layer is focused on handling one aspect of a request. For a request to be fulfilled, it should go through all layers from top to bottom (or outside to inside). Layers are abstracted away from each other using interfaces. Each layer only depends on the layer below and the flow between layers is one-way from top to bottom (or outside to inside).

Typically, we have the following layers:

Layer Description
Entity Your domain-specific representation of request and response objects.
Mapper Mapper functions for mapping between domain-specific and protocol-specific models.
Gateway Providing access to external services.
Repository Providing access to external data stores.
Controller Implementing the core domain functionality and logic agnostic of any transport protocol.
Handler Handling protocol-specific requests using mappers and controllers.

Controllers can follow a composable architecture. You can additionally have a separate package or module for modeling requests and responses to external services used by gateways.

Vertically

Another approach is to slice your service vertically. In this approach, you will break your service into a disjoint set of packages or modules formed around your domain functionalities. You will have a package or module per each domain functionality. These packages together partition your request space. For a request to be fulfilled, it should go only through one package or module and all aspects of handling the request will be carried out by that package or module.

Comparison

Like any other layered architecture, horizontal slicing gives a lot of flexibility for changing a layer or completely replacing one. You can easily replace your handler layer to switch to gRPC protocol from HTTP without changing your entities and controllers. Also since your controller only has your domain logic and everything else is moved out, your domain logic is isolated and thus easier to follow. However, like all other layered architectures, this comes at the cost of more overhead, longer development cycle, harder debuggability, and a lot of boilerplate codes.

This vertical slicing has a better and more clear semantic comparing to the horizontal approach. For following a request through your service, you only need to look at one function in one package or module. The development experience is better in terms of velocity, testing, debugging, and monitoring.

In general, although horizontal slicing promises better flexibility and abstraction, in reality, we rarely leverage and benefit from that flexibility. How many times did you have to switch the transport protocol in your last job? Vertical slicing works best when it is used alongside an IDL and a set of solid and robust tools. The models defined in IDL can be directly used as universal models for our domain and we will not need to have entities and mappers anymore. The IDL tools can take care of tasks not related to domain logic such as validation, serializing, deserializing, etc. This way we can eliminate boilerplate codes and keep our vertical packages extremely lean and slick. As a developer, you only need to implement your domain logic in one place, and switching to a different protocol also becomes a very low-cost task.

Control Flow

When it comes to composing and building an application, we have two options. We can let developers import and define everything they need explicitly or we can ask them to only fill in the blanks (inverted). We use the terms explicit and inverted loosely here.

Explicit

In an explicit control flow, you will have full control over the final application and how it is built. You will create all the required files and structures and implement the required definitions and procedures for your application. You will import built-in or third-party libraries for brevity, reusability, modularity, consistency, security, etc. You will decide how your application proceeds from start to end.

Needless to say, you can leverage available tools to increase your velocity and productivity. For example, you can use a scaffolding tool to generate a template application in your programming language of choice.

Inverted

This approach is based on the inversion of control and dependency inversion principles.

In an inverted control flow, you will only fill in the blanks provided by a framework. You will have to provide implementations for some well-defined abstractions (interfaces). Dependencies (logger, database access, etc.) are also provided to you as interfaces (so you can easily mock them). Using a code generation or a runtime framework, your implementations alongside dependency implementations will be injected into a generated or predefined application. In other words, the framework will provide the dependencies and call into your implementations.

Using this approach, non-functional qualities such as security, observability, resiliency, consistency, etc. automatically can be ensured.

Similar Projects

Go Kit

Go Kit is a toolkit for microservices. It takes a similar approach to slicing domain and organizing a service. Go Kit introduces similar concepts such as requests and responses, endpoints, transports, middleware, etc. It also provides standard libraries for logging, metrics, tracing, authentication, and so forth.

Reading More