Clean Architecture with Spring by Tom Hombergs @ Spring I/O 2019

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] yeah thanks can you hear me okay thanks for the introduction mark did a good job in pronouncing my name I didn't think he could do it but he did yes I'm going to talk about clean architecture today little some words about me I'm a software engineer at adesso in Germany were software consultancy so I've been in the consulting business for the last 12 years doing java mainly doing a little bit of open-source and I just took this this screenshot this morning to have it to have it up to date I just looked here there's something wrong here in April I think github had an error or something like that actually if I think about it that's the time my current project started into the hot phase of roll out and well didn't have time for open source then okay so that's enough about me I'm going to talk about clean architecture architecture in general are going to motivate what clean architecture is about and hexagonal architecture as an instance of clean architecture but first I'm going to talk about the layered architecture style we're all so fond of who has done layered architecture in a project hands up yeah that's pretty much everyone I guess that much obviously I'm showing this slide only to set up layered architecture to compare to another architecture style that it's much better so have your Rotten Tomatoes handy and throw them at me when I'm going to bash on layered architecture but first of all before we talk about the pros and cons of different architecture styles let's talk about what architecture actually is so why do we actually bother with architecture at all why aren't we just coding away and put it into production and they do it work all it works on my machine so it should work there what is architecture about what are the goals of architecture anyone what why are we doing why are we thinking about architecture just throw it at me what was that readability okay usability well actually any ility you can find right so yeah you're completely right some people think that architecture is about making making it work making the software work obviously we're building as we're thinking about when we're doing architecture it shouldn't be in the way of making the software we're building work so our architecture should enable the software to actually implement the requirements that were given to us but there is software out there that has a an awful architecture but it's still working best what 101 good example is our own ERP system at adesso we bought it we didn't build it ourselves so nothing we didn't do anything wrong except to buy it but it's it's it has an awful architecture when you use it as an software engineer to track your time and track invoices and stuff like that you just feel that it's a bad architecture underneath you have the same forms in every on every page and you have a very bad UX experience so but but we it's working we're we're profitable we are creating invoices through that system the invoices are getting paid even and it works but it only works because we have to use it so there is software out there that has a bad architecture and it's it's working nonetheless so this is not the main goal of architecture you were right with with all the abilities this is that the quality attributes the quality requirements to our architecture that's that's what architecture is about it's about facilitating the whole development experience facilitating development facilitating deployment to production or even to test environments it's about facilitating maintenance because maintenance is more expensive than actually building the software initially and with these le T's we're trying to achieve with architecture we're trying to keep the software soft so these three phrases down here are quotes from Robert Martin's book clean architecture so we want to keep the software soft because software the the meaning of software is that it's flexible that we can we can we can push it we can poke at it and it changes compared to hardware for which you actually have to break things and reassemble them we want to keep frameworks at arm's length so we don't want to build upon the features of a framework we don't want to bind to the framework too much because if the framework changes we have to change our business co2 and we want to avoid that and we want to keep options open we want to have we want to make decisions at the lightest possible moment and keep our options open until then so the goal the the ultimate goal of software architecture is to minimize the lifetime cost of the software a lifetime cost means the development cost of course but it also means the maintenance cost afterwards because that's I don't know the numbers but maintenance is factor of I don't know how much more expensive than actually building it so now we know that the goal of software architecture is to minimize cost to keep options open and everything I introduced the layer architecture and the start so what's wrong with layers first of all it before I start bashing the layered architecture and get thrown at with Rotten Tomatoes a little disclaimer layer layers are a solid architecture pattern we there's a reason why we all do it and if you do it right then it's a perfect perfect decision to do a layered architecture I'm doing this myself in my current project but before but when in my experience a layered architecture without more restrictions than just the layer layer one can call layer two layer two can call layer three this this is the only restriction in a layered architecture if you don't put any more restrictions on it it's very prone to design flaws that creep in over time so keep keep this disclaimer in mind if while I'm bashing on layered architecture so a good layered architecture is a good architecture but one thing I have observed in and a lot of projects in in my experience that we're doing actually database driven design a lot in our layered architecture what does that mean it means that we have a service layer the in regice or a business domain layer which which is in red in the empty slides and we have a persistence layer which is and in the domain layer we have our services stateless services that do something that implemented business logic that implement the main logic and in our persistence layer we usually have an entity class which is for example a JPA entity a repository which is the spring data JP a repository perhaps and this makes this this couples the domain logic in our services very much to the database why is that it's because the entity has all the the JPA annotations and stuff like that and in our service if we're using the JPA entity directly we have to take care of things like lazy loading and everything that that can go wrong with using JPA III like JP a very much I use it I like to use it very much but in my experience there are we're actually solving problems in our domain layer that should be solved in the persistence layer so these couples are the main logic to the database or at least to the to the database to the persistence layer before the database and usually we're starting in a setup like this when we're developing a certain use case we're starting at the bottom layer we're starting creating and we're starting by creating an entity creating a repository creating the database table the database structure and only then we're going to the domain layer and build our application logic when it should be the other way around we should build the business logic first and then care about the data that the database and persistence there because the business logic is the more important code the next thing about layered architecture is that we're usually having this service layer this domain layer and if we have certain classes that are used through our multiple layers we just push them to the bottom most layer because everyone can access them so we have a utility classes and perhaps other classes that are needed everywhere that that should be accessed everywhere we just push them down to the lower most layer so every other layer above it can can use it this makes boundary the boundaries we have they're easily blurred if you don't if you don't have the discipline or if you don't have something in place that that catches it so there is no no real boundary if you don't if you don't if you don't especially build it into your architecture next thing is layered architecture allows shortcuts like layer bridging we were accessing the persistence layer from our web layer for example which is not bad per se but if we do this then the tests are going to be a little harder at least if we were doing unit tests so for the tests and in our controller here we would have to mock the business layer away and we would especially have to mock away repository so we're having a lot of mocks if someone new comes to the team and sees the the test code you might get confused tests are getting harder we're have we have to mock more we have to mock different different layers different technologies is it's going to be a little harder than if we just have to mock away only one there next important thing I have observed in a lot of projects is that the functionality we're building the use cases we're building in our application are actually hidden somewhere we have a service which is a business service or domain service or whatever and it's doing a lot of different use cases so for example we have a service that is concerned about orders so to create an order to update in order to I don't know place an order whatever and this service does everything for orders and everything that that that's around the entity or around the order entity and you don't really if you're looking for a certain use case in the codebase you know that it's somewhere in this this order service but you don't have you have to search through the service to actually find it so this is makes makes use cases usually makes use cases hard to find if we have these broad services that are spanned across multiple use cases and it also makes makes hard makes it hard to work in parallel on the same feature so if two developers are developing are working on this on the same or similar feature they have to they both have to work in this service and might have merged conflicts and other problems so what's the cure instead of layers we just do circles so we just wrap the layers around each other and everything that's better I'm not done yet there's something coming in okay so this is what Uncle Bob Robert Martin called clean architecture I'm going into a little more detail later but first let's look at solid solid principles everyone knows them right you can if you're if you're getting woken up in the middle of the night you can say what s oli D is right who can do that oh come on I know you can okay I'm not going are going to ask you now I'm just going to open this up so a single responsibility principle open-closed principle Liskov substitution principle interface segregation principle dependency inversion principle we're only going to look at two here which which I think are the most important ones and which motivate the architecture style that I'm going to introduce so let's look first at the dependency inversion principle what does that mean obviously it means that we can invert dependencies in some way it means that this is our on the left side is our database driven design now we have the service we have the entity and repository and the service has a dependency on the on the persistence layer so we're bound we're coupled to the to the database through the entity if we apply the dependency inversion principle we turn this dependency around so that no longer the the domain layer no longer has a dependency to the persistence layer but the other way around this is on the right side we see we have yeah okay I also replaced service with use case here but that doesn't matter it means on the right side we're using dependency inversion which means we have moved the entity up into the domain layer so that our domain entity that this is actually now a domain entity no longer a JPA or hibernate or whatever entity and in the domain layer we added an interface which I called repository here but which doesn't necessarily have to be named like that and the persistence layer simply implements this repository interface with whatever technology is sensible in the project JPA spring data JDBC whatever so what this means is we can choose the dependent the direction of any codependency as long as we have control over the code if we have a dependency to some third-party framework third-party library obviously we cannot change the dependency because we can't change the coach so what does that mean on an architecture level and this is where the clean architecture ID comes into play clean architecture as a as a buzzword is not that young it's been around I don't know for a long ten years or so I'm not really sure but Robert Martin has recently published the book clean architecture about this which explains this architecture style but it's very generic but I'm going to this is the only slide about it actually so I'm going to not go into the details here but go over the main main facts so what have we here we have in the middle our domain layer and there are layers around that and the the main rule is that dependencies only may point in words so for example the blue circle we have the UI code the code for the UI or the code for accessing the database it may acts as the green layer and the green layer may access the red layer something like that we have applied the dependency inversion principle to actually allow this change of dependency yes and this is actually it we have the domain logic actually in the core and everything on the outside is just a detail so if you believe Uncle Bob the database and the web are actually only detailed to our application the important stuff is the red stuff in the middle I see that a little more pragmatic I think it's pretty important that we have a web layer and then we have a database layer because otherwise the data just gets lost but what it means is that we can actually change the database later on and exchange it by I don't know storing storing files on a hard drive or something like that so this is dependency inversion depend we inverted the dependencies our domain layer is no longer dependent on a persistence layer because we turned the dependency around by introducing an interface and implementing this from the outside the next solid principle I want to talk about is single responsibility the single responsibility principle who knows what it what it means yeah just I can see you anyway just tell me what what does it mean single responsibility here you're cheating yes I was expecting something like a class or module should do only one thing but what you said is completely right a class or module should actually only have one reason to change so this is a common misinterpretation of the single responsibility principle that it only should do one thing while actually it should only have one reason to change it's a slight difference and it's not not so big a difference but but a meaningful difference because if a certain module or class there's one thing but it has multiple reasons to change because there are different requirements that that that have that that produce a change in in this modular class then it's going to change all the time while if a certain modular class only has one reason to change it's only going to be changed for this one reason and this makes the code base just more stable so and instead of module I put the word module here instead of module you can read class package component whatever element architecture or code element you want so what does single responsibilities mean on a on a macro level on an architectural level if we look at the layered architecture our business layer or our domain layer has one reason to change that it shouldn't have and that's the persistence layer below if we change something in the persistence layer in the blue layer and the bottommost layer there is a certain possibility that we have to change things in the business layer too because the dependency shows points downwards so changes in persistence may affect business code which we don't really want in this clean architecture circle circular style when we applied the dependency inversion principle this is no longer the case because the dependencies point towards our business layer and if something on the outer layers changes the business layer doesn't have to change so this makes the business code more stable this means single reason to change single responsibility on a high level on a macro on an architecture level and this means we're we're free to do everything we we see fit everything that we think is good in our domain layer we can do everything without even having to think about persistence effect persistence problems lazy loading stuff like that and I go so far and say that only a domain centric architecture where which has the domain layer in the middle of it independence is pointing toward the domain layer allows domain driven design because only then we can design and we can design freely without having to think about certain technology issues only goes so far but the gist is that this is this is true what does it mean on a micro level on a class level single responsibility in our layer architecture we we often have the case that we have these broad services I talked about earlier and we have multiple actors using this service so for example if this is an order service providing use cases around orders placing orders whatever and we have three different three different user roles that actually use this service use use cases in the service we have three actors that use the service so if one of these actors at one of these user roles requires a change to the to the application we have to change this service and we have to test everything else that in it again even if the other two actors are not actually don't think that anything has changed so what can we do here we can split our service up into use cases actual classes that are named XY z-- that use case and each service or use case whatever you call it is responsible for one actor for one user role and if you take this to the extreme every of these classes actually only responsible for one use case so and this brings me to the next architecture style which is hexagons so we're talking a lot of we're talking about a lot of shapes today I think a hexagon is more sexy than a circle because it has these edges but that's just personal meaning what does it mean if we drill into an hexagonal architecture this is my interpretation of an a hexagonal architecture it looks like this we have a hexagon obviously six sides six corners and within the hexagon we have our domain layer or domain code use cases entities on the edge of our hexagon of our application core we have ports on the left side we have input ports and on the right side we have output ports input meaning we provide an interface we provide an API to outward let's call them adapters to outward code that wants to call our application logic and on the right side the output ports provides functionality for for example persistence we call our our application core called something else so why is this a hexagon I don't really know and I don't think mr. Cockburn who branded the the word hexagonal architecture I'm think I read somewhere that he mean men's just it's because boxes with four corners are boring and he wanted to show that an architecture can actually have more than four sides I don't really know what he meant but if you think that six sides are too much for you you can just choose any polygon you want for example if the customer is says that oh six six sides are too much for me you can just go with a triangular architecture but then you should be prepared that the customer only wants to pay half for it because it only has half the number of sides so be careful with that so actually the hexagon doesn't really mean anything but it looks cool so we will stick with a hexagon back to use cases I mentioned before that use cases should be that that services should be cut into multiple use cases so that each use case only has a single actor so use cases we should treat use cases as first-class citizens in our architecture and in a hexagonal architecture this is just much more concrete that in a clean in the clean architecture I am introduced earlier if you google the words clean architecture and hexagonal architecture you find very much about the baha'i level concepts but at least if you if you're looking for clean architecture if you're looking for hexagonal architecture you even get some code examples because the clean architecture there's it's just a concept and hexagonal architecture is just is an instance of clean architecture which actually puts the concepts to which is easier to to turn into actual code so what does a use case do a use case class implements an input port the input port is just a Java interface then the use case class modifies the domain model the domain entities in some in some way and on the way it might call certain output ports for example to load data from the database or to send data to the database or to load data from some other external system whatever let's have a look at the impact of of this this this style of this architecture file with with having specific use case classes so this is a package structure of a little application without actual use cases can anyone tell what this application does pardon it records time yes very smart any anybody any other guess well it obviously does some some something with time so you're completely right you can't tell any more than it records time so no offense to you I couldn't have seen it anyway either it does something we have we have a service it does something with with time records but what's the time record I don't know what what do we do with these time records I don't know if we split it up in use cases instead we get this anyone tell now what this application does pardon yes managers time records we can even probably go one level deeper we see that we have multiple use cases we can submit time records we can approve time records we can reject time records so it's actually probably multiple users multiple roles we have a proving use case which is done by probably another role so it's probably a time time tracking application where you track your time and later on you you create invoices from that and track time you can do this in a layered architecture too so this is certainly a good way to go but in this in this hexagonal architecture this is even more powerful because of the dependency inversion and we don't have to change use cases because persistence code changes okay let's look at some code I promise to show some code you can find the code examples at this link or in the slides can you see it okay so what does code look like so this is just just a disclaimer this is my interpretation there are certain we we can certainly do it in different style this is just one one template one could use to create such a hexagonal architecture with or without spring I'm going to point out the the spring parts on the way so this is our we're going to implement a use case that is called register book use case so the application is about is a book reviewing application so if you write a book you can upload the book in Mactan or whatever other format and you can provide it to other people who can then review the book and and edit and suggest edits and stuff like that so the first use case in this applications is to register a book so I'm an all of a book and I want to register my book there it actually is a simple create use case we just create a book but I don't call it create book because that's too generic I call it register book so we should try to call our use cases with the most with the best verb possible and create it's just too generic so we have this register book use case which is an interface this is our input port in the hexagonal architecture it has a single method currently which is register book which takes a register book command which contains every all the data that is needed to execute this use case the register book command I put it here in into this interface as well it just has has two fields and a constructor that takes these fields as input here's the first question about validation I chose to validate the the input on this level so the register book command actually implements and/or extends a self validating class which simply does some creates a Java Bean validation validator and called the validations so its results these it evaluates these bean validation annotations so we can only create an command object that is valid in the sense that the business logic expects so the business logic itself can then work with these attributes and doesn't have to do the validation itself there's also an exception here which I don't know if it's a good idea non-unique book title exception perhaps a better way would be to not use this to not create an exception in this case but instead before calling the register book method to actually check if there is already a book but that's just a little flavor so we have this register book use case no spring so far even though there is here and spring icon so what does actually implement this this interface I called it register book service so it's a service which which serves only this this actual one use case and it implements this method and so we're starting when we're starting to implement this register book method we just type away and implement our business logic and we find that we need an author entity so we just create an output port which I called find author by a deport which only has this one method find author by ID and we're happily coding some more well then we find okay we need to persist this book somehow so we create another output port which which takes the book and persists in the database still very little spring here but we're using Springs at service annotation to declare this service as an as an as a spring bean one thing you could do here is if you want to make the architecture even more evident in in the code you can create your own annotation and annotate this meta annotate this annotation with the add component annotation annotation and then you actually know when you look at this that this is a use case spring serves as a dependency injection mechanism here to fill these fields I'm using Lombok here which create automatically creates a constructor for all required for all final attributes and spring automatically injects implementations of these ports so if we have created a test before and we run the test now and without having implemented the these ports that the spring container won't won't fire up and it will tell us there is a port missing which is which is pretty cool because there's spring checks our architecture for us okay so this is the business logic very little spring here the only thing spring does is actually dependency injection that's the way it should be so spring is very non-invasive we can spring spring is in the behind the scenes and just does the work behind the scenes and we don't have to actually use any spring code except for perhaps one or two annotations so this is our business code I didn't actually explain the package structure so we have an application package structure which with a port package input ports output ports so these are just the interfaces and we have a service package within the application package which has our register book service so now we someone have to implement these ports and these ports are implemented by our persistence adapter so hexagonal architecture we have the core in the middle and on the outer layers we have adapters that call our core or that are called by us and here I took again I created a custom annotation which you don't have to you can also use this one but it just makes it more evident and this implements some output ports it's in a it's in its own package and every class in this package actually is packaged private we don't need to publish it out to the outside of this package because spring allows to inject beans into the spring context without them actually being public which is pretty cool because we don't we can't accidentally accidentally call persistence code from our business layer then so on this is pretty simple code it takes it takes a book and saves it this is a spring data JDBC repository pretty simple stuff yeah one thing about this book class the book class is in our domain package so this is actually in the in the middle of our of our hexagonal architecture I don't forget to track your time sure I will we I chose here to add this ID annotation this is an annotation of spring data spring data JDBC or actually I think it's not even JDBC it's just spring data in general so I chose to just to use the same object in my persistence there as I use in my business layer this but but the persistence layer needs this ID annotation so now I chose to just put it here this is a kind of a shortcut because again in my business code I actually don't want to have any persistence any dependency to persistence code but I think if you're starting to build a use case many use cases start as as a single as a simple Crotty use case we create some entity or something like that we can start with this so we can add some JPA or spring data annotations to the entity in the actual in the in the business layer and then we can just pass this entity along to the persistence layer then persisted in whatever database however once we get to a point where the use case evolves to something more complex and we we start we're thinking about oh we're doing some persistence relevant code here in in the business layer we can then choose to remove this annotation from our domain object and then just do an introduce a mapping here so here we would map the book to some JPA entity or or we just move it to the database / via plain JDBC so that's that's what I want to bring across we don't actually have to start with this very strict boundaries between the layers we can move we can start without these mapping steps because that's one of the main criticisms about hexagonal architecture or clean architecture in general that we have to in each layer we have our own model and we have to map between these models but it we don't necessarily have to do it this way we should start to do it this way if we think we're doing code in the if we're putting code in the business layer that has to do with persistence and stuff like that so there's also a web adapter in the adapter package which is simply a rest control which is I'm not going to details there because it's pretty straightforward okay so we've seen this we've seen this so to sum up what what spring does for us in our architecture Spring doesn't really care about the architecture we're implementing which is a good thing spring is always in the background has been in the background since day one I guess so if we think about architecture spring doesn't care we can build any architecture with with spring so we really have a lot of options of doing things spring also helps to test isolated parts of our architecture we've seen in the talk before about the the component scanning and stuff like that but we can also do specific java configuration files that only spin up part of application so that we can test this part of our application in in isolation Oliver drop what Walmart has given a talk yesterday about modulus this is one option we can we can also do here and to sum up spring is easily held at arm's length so we don't really have to buy into using spring because spring is in the background ok I'm going to skip the mapping strategies because I've just told I've just told you about it that we can use different mapping strategies we can do no mapping so the the ports the output ports and the persistent setup they use the same entity as the domain layer or we can do something like this in the front in the in the interface to the web adapter using a command pattern which is a more elaborate mapping strategy how can we enforce architecture just really quick we can build multiple jar files separate build artifacts so that the dependencies are resolved automatically by maven or Gradle or whatever we can use something like Ark unit which is a framework that allows to enforce certain package structures or even more than package structures actually I'm only using it here to enforce package structures package dependencies actually or we can use the modulus approach by Olly which he introduced yesterday I just edit this slide after the talk we can use Java modules which will probably work too but I'm used to having a little more time to learn new Java stuff so I haven't looked at it yet yeah that's about enforcing the octave which which is important enforcing the architecture is kind of important because if you're not doing microservices yes I set microservices for the first time in this talk which which is great if you're not doing microservices if you're building the application in a giant in a monolithic code base then it's very important to enforce architectural rules because otherwise certain design flaws will slip in okay to conclude what are the benefits of a domain centric architecture like clean architecture or hexagonal architecture we have separate classes for separate reasons of change so we don't have this disk up into the database we can find our use cases better because we separate them in in certain in different classes we can work in parallel better because we have cut things up into more small pieces it's easier to test because the dependencies are clear and the boundaries are no longer blurred so easily there are certain drawbacks certainly just as I said there is if you do it if you make hard boundaries boundaries at building boundaries is expensive just ask Donald Trump I think he's he has a problem with the boundary currently so we have each boundary requires if you want to do heart boundaries you have to do a mapping and so it might feel that you have to map a lot we have some perceived redundancy because if we cut the use cases if we make the use cases separate from each other we have to duplicate some things so if we change one use case the other one won't have to change and we need real business logic it's very hard if you just do a simple crud application you don't need this architecture style so this only really helps if you have real business logic that you can put into the middle of your into the center of your architecture then you have the real value and that's it thanks for your patience I've summarized some of this and a little more in a little a book which you can download under this link thank you for your patience it has been a lot of fun for me [Applause] [Music]
Info
Channel: Spring I/O
Views: 50,053
Rating: undefined out of 5
Keywords: springio19, clean architecture, hexagonal architecture
Id: cPH5AiqLQTo
Channel Id: undefined
Length: 49min 45sec (2985 seconds)
Published: Thu Jun 20 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.