In my last posts I’ve been writing about many of the concepts and principles that I’ve learned and a bit about how I reason about them. But I see these as just pieces of big a puzzle. …
seen from Portugal

seen from Portugal

seen from Portugal

seen from Georgia

seen from Poland

seen from Portugal
seen from Portugal

seen from Portugal
seen from Portugal
seen from Poland
seen from China

seen from Italy

seen from Thailand
seen from United States

seen from Thailand

seen from United States
seen from Thailand
seen from China

seen from Italy

seen from Thailand
In my last posts I’ve been writing about many of the concepts and principles that I’ve learned and a bit about how I reason about them. But I see these as just pieces of big a puzzle. …
Implementing Domain-Driven Design with Go (Golang)
I recently joined the Domain-Driven Design group on LinkedIn Domain Driven Design and the group owner David asked me:
"How do you like golang? Any features of go that make it work well with DDD or micrososervices?"
So here we go, I'll use that stimulus to start blogging again.
A bit about my background and history with Go
Before I started programming with Golang in my last company I did PHP for almost 2 decades (true story). Last PHP version I worked with was PHP 7.0, which had all relevant features to do SOLID OOP, with the exception of strict typing (that was added later). My team was switched to a new greenfield project working with Go, in a Microservice environment. We did DDD with EventSourcing from the start. Some more tech stack namedropping: Kafka, PostgreSQL, Docker, Kubernetes - backend services talking RPC with "go-micro" as their framework.
Now we had a similar journey getting into Go as many other devs who were also coming from OOP, we started trying to turn Go into OOP, which is generally not a good idea. Actually, if you favour "composition over inheritance" there is not SO much of a difference, at least to PHP (PHP has no generics, no method overloading, no other OOP Voodoo). Most of the differences lie in what's idiomatic in Go, which can savely be ignored given developers make educated decisions, for example by declaring higher level concepts more important than language concepts.
Some details about Go and it's challenges
There is one important difference to OOP languages, which is how interfaces work in Go. You don't declare an object in Go to be implementing an interface, instead it's "duck typed". So anyhing that fulfills all method signatures of some interface just magically implements it. In Go it's common to not define interfaces on the implementation but on the client side, or put other way, every client using the implementation of some service can bring it's own interface and use interface segregation (e.g. if only a portion of the service's methods are needed). I totally like that, but it conflicts a bit with hexagonal architecture aka. ports and adapters. Luckily this is a case of "idiomatic Go", so here's our good reason to ignore that. As an example, in DDD you would define the interface for a Repository or a DomainService in the Domain package, in Go you would define it where it's used, e.g. in the Application package.
Some other common ways of doing things in Go are probably not even described as "idiomatic", e.g. creating objects like structs on the fly without using factory methods, which is only possible if the internals of such a struct are public (Go calls it exposed). As DDD practitioners we want our ValueObjects immutable, so we'll keep our stuff private and have proper factory methods.
I plan to write about how I would implement things (VOs, Entities, etc.) in Go nowadays - after 2.5 years of learning and changing my mind back and forth at least 5 times about every detail.
My friend James has blogged about BYPASSING GOLANG'S LACK OF CONSTRUCTORS which he could also have named "How can I avoid all those nil pointer checks in Go?", it's very interesting!
Spoiler alert -> With quite some effort you ... still can't fully avoid those nil pointer checks (but there are some ideas how to reduce them)
What makes Go a good fit for DDD / Microservices
Speed
There are faster languages around, but Go runs fast and it compiles very fast, mostly because of the simplicity of the language. And it's getting faster, afaik mostly because of improvements in the garbage collector. For people like me - coming from an interpreted language like PHP or Python - it's fast as lightning, which raises the bar for (premature) performance optimisations quite high. I profiled our stuff a while ago and there was no worthwile target for optimisations in our event-sourced application (unmarshalling was the biggest "thing" but only accounted for around 10% of runtime). To give a rough idea about speed - we could easily serve any command that did not have to make synchronous calls to other external services under 10 ms. With full reconstitution of the Aggregate, no snapshotting or other caching involved.
Simplicity
As Microservices tend to be small they also tend to be relatively simple (this is for sure a simplification), so a language with simplicity as a core concept is a natural fit. I'll put another fact into this catogory, which is the lack of sophisticated frameworks, ORMs, etc. For sure frameworks and ORMs exist, but they tend to be more lightweight and none of them is a de-facto standard which you have to use because everybody does it and then suddenly you're spending more time fighting the accidential complexity of such things instead of solving your domain challenges.
Concurrency
I totally love Go's way of concurrency with goroutines and channels to synchronise them if necessary. As an example, we have implemented a very efficient and hight throughput event publisher, which publishes Domain Events after they were commited to the Event Store. Often all you need is to fire and forget a goroutine to do things that must not block your main application flow, e.g. sending notifications (emails) given it's not critical if the sending fails.
Summary
I like Go alot, especially for not too big services. It takes a while to find your own way through Go, SOLID, DDD, hexagonal architecture but I think it's worth it, because it forces you to think about concepts, instead of blindly applying them. I still love PHP for various reasons (community, eco system, ...) but would not switch back without a very good reason (e.g. a new job requires it).
EBI Architecture
This post is part of The Software Architecture Chronicles, a series of posts about Software Architecture. In them, I write about what I’ve learned on Software Architecture, how I think of it, and how I use that knowledge. The contents of this post might make more sense if you read the previous posts in this series.
The Entity-Boundary-Interactor (EBI) Architecture has been made known by Robert C.…
View On WordPress
Software Architecture - Hexagonal Architecture Pattern
Software Architecture – Hexagonal Architecture Pattern
In this article we will see “Hexagonal Architectural Pattern” also known as “Ports and Adapters” pattern. As developers so far we have created applications with tiered architecture styles like MVC (Model View Controller). With this architectural styles, up to certain extent we were able to decouple the domain logic with other functionalities. At times the domain logic use to…
View On WordPress
Domain Layer as a specification
Thesedays, I'm writing application using Hexagonal Architecture with python and feel that "domain layer seems to be behaving as a specification". Let me explain about that here.
Example: TagService
For explanation, let's use a simple example, "TagService".
I'll define ITagService interface on domain layer, implement it on infrastructure layer and use it on application layer. The application is writen by python, so interfaces are defined with zope.interface package (zope.interface is useful for Hexagonal Architecture in Python).
Domain Layer
from zope.interface import Interface class ITagService(Interface): # specification u""" Tag management domain service """ def add_tag(post, tag): u""" add tag to a post """ def remove_tag(post, tag): u""" remove tag from a post """
Infrastructure Layer
from zope.interface import implementer from .domain.model import ITagService @implementer(ITagService) # implement TagService as described in ITagService class TagService(object): u""" TagService using xxx """ def add_tag(self, post, tag): u""" add tag to a post """ # do some actual staff def remove_tag(self, post, tag): u""" remove tag from a post """ # do some actual staff
Application Layer
from .infrastructure import TagService def add_tag(post, tag): srv = TagService() srv.add_tag(post, tag) # use TagService as described in ITagService
The point is that ITagService defined in Domain Layer behaves as a bridge between application layer and infrastructure layer. In other words, ITagService behaves as a specification for both application and infrastructure layer.
browser implementation analogy
Let's think about these relationships using an analogy of browser implementation. (Or if you want, you can use C++ compiler implementation analogy or else instead.)
EcmaScript Specification behaves like a domain layer
Google Chrome implements EcmaScript Specification, like an infrastructure layer
Application Developer uses EcmaScript Specification, like an application layer
By defining EcmaScript specification, Chrome developer can implement features without knowing actual usage of application developers, and application developer can use JavaScript features without knowing Chrome's detailed implementation.
After I have adopted Hexagonal Architecture rather than Layered Architecture, responsibilities of each layer have been getting clearer.
"Tell, don't ask" and Controllers
Check out these easy to make refactorings and keep your domain logic out of the framework!
The code example is in Rails but the idea is framework agnostic.
Standard Rails controller:
class UserController < ApplicationController def create @user = User.new(new_user_params) if @user.save redirect_to @user, :notice => "Welcome!" else render :new end end end
Becomes
class UserCreator attr_reader :listener def initialize(listener) @listener = listener end def create_for(user_attributes) user = User.new(user_attributes) if user.save listener.user_creation_succeeded(user) else listener.user_creation_failed(user) end end end class UserController < ApplicationController def create user_creator = UserCreator.new(self) user_creator.create_for(new_user_params) end def user_creation_succeeded(user) @user = user redirect_to @user, :notice => "Welcome!" end def user_creation_failed(user) render :new end end
Or how about compose functionality together using the decorator pattern?
class UserEmailer attr_reader :next_listener def initialize(next_listener) @next_listener = next_listener end def user_creation_succeeded(user) next_listener.user_creation_succeeded(user) send_welcome_email(user) end def user_creation_failed(user) next_listener.user_creation_failed(user) # emailer doesn't care end def send_welcome_email(user) # etc end end class UserController < ApplicationController def create user_creator = UserCreator.new(UserEmailer.new(self)) user_creator.create_for(new_user_params) end def user_creation_succeeded(user) @user = user redirect_to @user, :notice => "Welcome!" end def user_creation_failed(user) render :new end end