[0:00] okay uh yeah good morning everyone [0:04] so let's get started um [0:07] okay so my talk is uh [0:10] called making architecture explicit it [0:13] talks about the [0:14] many things but first [0:18] first of this so first a bit about me [0:21] i'm [0:22] portuguese i graduated in it and then i [0:25] became a [0:26] high school teacher i was a high school [0:28] teacher for a few years [0:30] and then i get uh got fed up with it and [0:33] uh decided to be a software developer [0:36] um currently i'm a lead developer at [0:38] worksport in [0:39] the netherlands and i'm yeah [0:42] like a good food with wine coding [0:46] just like uh pretty much everyone else [0:48] here and i love my [0:49] plucky my motorbike [0:53] so what this talk is about it's about [0:56] ideas from [0:57] people that are way smarter than me [1:00] they've been in the business for [1:01] many many years 30 40 maybe more [1:05] they have the ideas from 20 30 maybe [1:09] 40 years ago ideas that are still valid [1:11] today ideas that [1:13] we still don't know them very well today [1:16] we don't use them enough and in the end [1:19] it's uh [1:19] also about how you put all those ideas [1:21] together in order to create a good [1:24] quality software that is [1:25] reliable and it is maintainable for many [1:28] years [1:32] however no matter how much [1:37] i'm confident about what i'm saying here [1:39] today there are no silver bullets [1:41] there's no holy grail [1:43] there's no one would fit all in the end [1:45] we need to [1:46] understand all ideas [1:51] increase our our toolkit of ideas [1:55] and patterns and knowledge and then [1:57] analyze the project that we had at hand [1:59] and analyze the pro the problem that we [2:01] need to solve and then use the tools [2:03] that are [2:05] fitting the solution [2:12] history is uh very interesting for me [2:15] i think it's very important [2:18] we all have our own personal history [2:22] we do mistakes along the way and then we [2:24] try to learn from them [2:26] and hopefully not repeat them very often [2:31] as a country as well we have mistakes [2:36] the way that's why we learn history at [2:38] school right [2:39] that we so that we try not to make the [2:41] same mistakes [2:42] um portugal had a dictatorship for [2:45] example [2:47] so we learned that at school so that we [2:48] try not to [2:50] get convinced into getting a [2:51] dictatorship again [2:53] so we learn from history and we as a [2:56] community [2:57] should also learn from history so let's [3:00] uh [3:00] take a look at at last few years in [3:03] software development [3:05] so we started off with non-structured [3:08] programming [3:09] back then it was maybe the 50s so just a [3:12] series of [3:13] assembly commands scattered or splashed [3:17] on the screen moved on from there to [3:20] structured programming because we were [3:21] repeating a lot of code [3:22] so we came up with the conditionals and [3:25] with [3:26] loops to help us not repeat so much code [3:30] then we moved on to procedural and [3:31] functional programming where you can [3:33] actually group [3:34] sections of code then call them whenever [3:37] we need them [3:39] and finally we came to object-oriented [3:40] programming which groups [3:43] data with the related functionality that [3:47] that should change and manipulate that [3:49] data [3:50] and this was uh op was in the [3:53] showed up in the beginning of the 80s [3:55] maybe a bit before but then in the [3:57] beginning of the 80s was when actually [3:59] started to pick up and after that the [4:02] the [4:02] language paradigms they didn't really [4:04] evolve much [4:06] so we but the problems kept kept [4:08] evolving and kept growing [4:09] software kept growing and we needed [4:12] something more so we [4:13] turned our heads into uh design patterns [4:18] on the other hand at the more coarse [4:20] granular [4:21] view we started with the monolith of [4:23] course [4:25] everything one single program [4:28] then in the beginning of the 80s we had [4:30] our first attempt at [4:32] distributed computing that was corba and [4:34] corvo was interesting because it [4:36] obstructed the network away [4:39] that was handy we had an object and [4:43] that object would have execute but not [4:45] execute locally in our machine it would [4:47] execute in another machine [4:48] that was really cool except that when we [4:52] were running our code we didn't really [4:54] know where it was going to execute [4:57] and there was network lag and we never [4:59] knew where it where [5:00] where and when it would happen so that [5:02] was a problem [5:04] then we solved that by threading our [5:06] heads into [5:07] service oriented architecture explicitly [5:10] knowing [5:11] when we are reaching for something [5:13] outside of the local machine [5:18] but then back then we had software that [5:21] was [5:22] deployed deploying different servers [5:23] they were communicating or they needed [5:25] to communicate [5:26] but they had the time they weren't built [5:28] to communicate [5:29] so what we needed to do was put [5:32] something in between [5:33] that would translate the messages or the [5:36] payloads right and that sounds like a [5:39] very nice idea and it was [5:42] so we had servers that actually could [5:44] communicate through that [5:46] one middle thing and that was how the [5:48] enterprise service buzz [5:49] came to be but with time [5:53] well we didn't even own the actual [5:57] uh software uh that needed to [6:00] communicate we only [6:01] won the part in the middle so we started [6:04] to put more and more logic there [6:06] more business logic in there and then [6:10] well it became so complicated [6:13] that no one there touching it because if [6:16] you touch it and you break it we break [6:18] everything and that was a problem with [6:20] the enterprise service bus [6:22] so after that came finally microservices [6:25] and microservice has actually a [6:26] principle which says [6:29] smart endpoints them pipes exactly [6:32] because [6:33] of the problem of the enterprise service [6:35] bus so no smart things in the middle [6:38] all the smarts are in the ends in the [6:41] micro services [6:42] and nowadays we're already talking about [6:44] nano services lambda serverless and so [6:46] on [6:48] in the end if we think about it it all [6:50] evolved in the cen in the direction of [6:52] modularity and encapsulation [6:56] building things in small parts that can [6:58] fit together [7:00] and that can work together and that we [7:01] can swap them [7:03] and construct different things if we [7:04] want to an encapsulation which is [7:07] putting related codes together [7:11] and hiding away the implementation [7:14] details [7:19] so let's talk about the monolith [7:23] some time ago a few years ago when the [7:25] microservices came [7:26] into the hype everyone was saying [7:30] microservices are the way to go monolith [7:34] is a big ball of mud all the time let's [7:36] not do it anymore [7:39] but it's not true nowadays we know that [7:41] microservices [7:42] don't solve all the problems [7:45] microservices solve a set of problems [7:47] and bring along another set of problems [7:52] so the monolith in the end it can be a [7:55] beautiful thing [7:57] and the micro services don't really [7:59] solve [8:00] all the problems that we had and if we [8:02] cannot solve it with the monolith who [8:04] says that we can solve it with [8:05] microservices [8:07] so when do we have a big bowl of mud [8:08] then for example [8:11] when class and method names they don't [8:13] convey meaning [8:14] we actually have to dig into the code go [8:17] see what a method [8:19] does inside in order to understand [8:23] how the code works and there's no [8:26] obvious place to put the code [8:28] i remember once i was in a i started at [8:30] the company and [8:32] i did my first task and then i asked a [8:33] colleague i asked him [8:35] hey where where should i put this i mean [8:37] it's working now i know it's working i [8:38] have a test for it but [8:40] where should we actually live and either [8:43] yeah i just put it anywhere [8:44] it doesn't matter [8:47] so it shouldn't be like that there [8:49] should be a meaning to where you put [8:51] your code [8:53] so also when you have a dependency mess [8:55] code depending on code depending on code [8:56] depending on code [8:57] never ends and you can't really isolate [9:00] it [9:03] and then also when there's no boundaries [9:06] which means you cannot really have a [9:09] sane testing strategy which means [9:12] is quite difficult to refactor and what [9:16] do i mean with this well [9:18] refactoring means that you change code [9:21] but you don't actually change the [9:23] behavior [9:24] it also means that you have a test to [9:26] prove that the code still works the same [9:28] way [9:30] that's refactoring [9:34] when we test one class we have private [9:37] methods [9:38] and we don't test those private methods [9:40] right [9:41] why because it's an implementation [9:43] detail [9:45] because we can at any moment change that [9:47] code [9:48] and the class should behave the same so [9:51] we don't test it we only test the public [9:53] interface of that class [9:55] with modules it's the same thing [9:59] we shouldn't test every little piece of [10:02] code [10:03] explicitly we should test behavior [10:06] but that doesn't mean we have to [10:09] explicitly write a piece of code [10:11] a test to every piece of code [10:14] so when you have a module you have one [10:17] class that is an entry point [10:18] and you have nine other classes [10:22] what should we test should we test all [10:25] 10 classes [10:26] or should we test only the public [10:28] interface of the [10:29] of the module the public interface of [10:32] the module [10:34] because everything else is an [10:35] implementation detail you might want to [10:37] change the behavior with [10:38] the the code the implementation of that [10:41] module [10:42] but keep the behavior the same if you [10:44] had tests [10:45] for every single piece of code in that [10:47] module then you're going to have to [10:48] rewrite [10:49] every single test and you're going to [10:51] just waste time [10:54] think also for example you know tdd [10:56] right [10:57] you know the three steps are 3d so you [11:00] go through all of that [11:01] in the end you have a test and you have [11:03] a class [11:04] and that class [11:08] in the end it's not the perfect right [11:11] it's the first version of the [11:12] functionality [11:13] so you have a big class and then you [11:15] decide okay i'm going to refactor this [11:16] make it [11:17] easier to understand so you refactor it [11:20] you have the test so you keep [11:21] checking that everything works you end [11:24] up with [11:24] five classes one class is the entry [11:26] point so you have five classes [11:29] you have one test should we change the [11:31] tests [11:33] no the behavior is the same you have the [11:36] same test [11:37] so you have five classes one test [11:40] you only test the the public api of the [11:43] of the module [11:47] so in the end this means that we don't [11:48] have clear and enforced design rules [11:51] that's what it means to have a [11:54] big ball of mud [11:57] so what is a big ball of mud well this [11:59] is a big ball of mud [12:00] uh imagine you have this and you work [12:02] with this and you need to take this to [12:04] work every day [12:05] and then at work you need to find [12:09] some nuts and bolts and you need to find [12:11] some specific nuts and bolts and what [12:12] are you going to do with this [12:14] you're going to spend a bit of time [12:16] searching for the [12:17] nut or bolt that you need right this is [12:20] a mess [12:22] the same thing with the code so what we [12:25] do [12:26] when we have this if you have this at [12:28] home and you want to go to work and just [12:30] take a piece of the of your big bowl of [12:33] mud [12:34] just that specific type of bolts what do [12:37] you do [12:38] if you want to reach that point then you [12:40] just start to organize it right [12:41] you put some balls in one box some bolts [12:44] in another box [12:45] and so on [12:48] so you group them things that are [12:51] similar [12:52] you put them together this is [12:54] encapsulation [12:56] so you put similar things in one little [12:58] box and you group the little boxes in a [13:00] bigger box and you put it in another box [13:02] and then you go to work and you can [13:04] choose what you want to [13:05] take to work and it's easy to find what [13:07] you want [13:08] it's easy to use it so you don't waste [13:11] time with it [13:12] if you want to throw it away it's also [13:14] fine you just know exactly what you want [13:16] to throw away [13:18] these are granularity levels and we can [13:20] do the same thing with code [13:23] in code you also have granularity levels [13:26] you have plain code [13:27] we have methods we have classes [13:31] interfaces that are basically files then [13:34] we have namespaces which are folders [13:36] in the end we have libraries as well [13:39] and i'm going to focus on the namespaces [13:43] because i think that's where we still [13:46] [Music] [13:47] fail quite a lot [13:53] so a bit more of history [13:56] in the end of the 90s uncle bob [14:00] robert c martin he started publishing a [14:02] series of [14:03] principles he then came up with the [14:05] principles himself [14:07] he learned them from books from [14:09] experience [14:10] from colleagues and then he published it [14:12] in online magazine [14:16] of those principles are for me quite [14:18] important for this for this talk [14:19] so first the single responsibility [14:21] principle um [14:23] which he defines as a class should have [14:25] only one reason to change [14:27] but i think of it as a bit a bit [14:28] different i think of it as a code unit [14:30] should have one single responsibility [14:34] because well a class okay [14:37] should have one single responsibility [14:38] but the better method as well [14:41] in the module as well if you think about [14:43] an orm no rm has one single [14:45] responsibility [14:46] translate from objects into a database [14:51] one single one single responsibility [14:56] then we have the common closure [14:57] principle and the common reuse principle [14:59] that basically means that classes that [15:02] work together that change together [15:03] should be [15:04] next to each other so if we think about [15:08] symphony [15:09] in symfony the default folder structure [15:12] you have the source folder and then [15:13] inside there you have a folder for [15:16] your controllers and you put your [15:18] controllers there and then at some point [15:19] you have 500 controllers [15:21] and you create some folders for those [15:23] controllers so you organize them a [15:24] little bit [15:25] but then next to it you have a folder [15:27] for resources [15:28] and you have a folder inside that folder [15:30] for the views [15:31] which are templates and controllers work [15:34] with the templates [15:35] and when you change the controllers [15:36] you're probably going to change the [15:37] templates [15:38] and vice versa and they work together so [15:41] why are we [15:42] grouping putting them far away from each [15:44] other [15:46] what happens in the in the end is that [15:48] you have 500 controllers organized in a [15:50] folder structure [15:51] you have maybe 700 views organized in a [15:54] similar [15:56] folder structure that you try to keep up [15:58] in sync but you never do because there's [16:01] 20 30 developers working in your company [16:03] and it's always a mess [16:05] so you're going to make mistakes and [16:07] then it's never in sync it's always a [16:09] mess to find what you need [16:10] it's always a big uh list of files to [16:13] search for [16:14] and so on so what we should do he says [16:17] that we should put it together [16:18] have a controller you have two two [16:20] templates using the [16:22] being used by that controller just put [16:23] them next to it [16:25] it doesn't really matter if there are [16:27] different file types or not [16:29] you're just a piece of code that works [16:34] together [16:36] in the 90s we had later architecture [16:40] in this case three-tier architecture [16:43] dependencies are vertical we have the [16:45] user interface depending on the [16:46] presentation depending on business logic [16:48] depending on [16:49] the database [16:54] then 2003 and eric evans publishes his [16:56] book [16:57] about domain driven design and of course [17:00] driven design is a whole subject [17:04] so i cannot explain everything here but [17:06] i can explain what is more important [17:08] in ddd and what's more important for [17:10] this talk [17:11] so how does this start how does domain [17:14] different design start it starts with [17:15] domain expert interaction [17:17] people talking have the relevant and [17:20] important people [17:21] talking to each other developers with [17:23] domain experts [17:25] pos users and so on nowadays [17:28] it's very common to do it with event [17:29] storming [17:31] so together we create a ubiquitous [17:33] language which is a set of terminology [17:35] that we can all uh use in order to not [17:38] have ambiguity when we were talking to [17:40] each other about the product [17:42] so we have that common knowledge and we [17:44] can build a context map [17:46] in that context map we can draw [17:50] on a whiteboard more or less what [17:53] our application look like so we have [17:56] for example genetic subdomains in that [17:58] case a crm [18:00] which is an error you can just get it [18:01] off the shelf so you don't need to build [18:03] it [18:04] you can have a support domain [18:08] that you might need to build it uh but [18:11] it's not really your core business [18:12] it's not what you sell and then you have [18:15] your car domain and your car domain is [18:17] uh [18:18] is composed by several um [18:21] bounded contacts the bounded contest is [18:24] an isolated piece of code [18:26] that deals with something for example in [18:28] this case categories products orders [18:30] so on there's a specific type of code [18:34] though [18:35] although these bonded courses are [18:37] isolated there's a specific type of code [18:39] that sometimes [18:40] we need to share and that's called the [18:41] shared kernel [18:45] and finally there's the anti-corruption [18:48] layer [18:49] which is something basically a [18:52] translation layer [18:54] where you get some data from one [18:56] balanced context [18:57] you translate it into what your body [18:59] contact needs [19:01] and you avoid leaking data structures [19:05] from one button context into another [19:06] bubble context [19:11] then is to five 2005 and there's always [19:15] aleister carbon he publishes a [19:18] post in his blog about hexagonal [19:21] architecture [19:22] he later renamed it to parts and [19:24] adapters to convey more meaning to what [19:26] he wanted to um [19:27] to explain so what he says is okay [19:31] we have an application core [19:34] the application core does whatever it [19:36] does it doesn't matter what [19:38] he wants to talk about is how the [19:40] application communicates without [19:42] with what is outside of the application [19:45] so the application has use cases in this [19:47] case for example create a user [19:50] and that's a port that's an entry point [19:52] for the application [19:54] on the other side it has an sms port [19:57] which is some kind of a door [19:59] that allows the application to do [20:01] something in this case [20:02] send out sms's [20:06] on the left side we have the delivery [20:08] mechanism [20:10] which can be http through an api through [20:13] a website [20:14] or you can can also be a console command [20:17] and on the right side we have an [20:20] external library a tool [20:23] so what he says is okay to make this [20:25] work we create an adapter [20:29] on the left side we have the primary or [20:31] driver adapters driver because they [20:33] drive the application [20:34] they tell the application what to do and [20:36] what they adopt is they adapt the [20:37] delivery mechanism [20:38] into our use case so if you have [20:42] http you're probably going to have a [20:44] controller which will [20:46] receive uh request an http request [20:50] get data out of it and send it to the to [20:52] the use case [20:54] if we need to trigger the same use case [20:55] through command line [20:57] it's exactly the same thing we create an [20:59] adapter for the command line [21:00] we extract the data that we need from [21:02] that command [21:04] from the command line and we send [21:06] exactly we trigger exactly the same use [21:08] case [21:09] so there's no duplication of code [21:14] on the other side we have the driven [21:16] adapters [21:17] and the driven adapters are slightly [21:19] different because the ports are [21:20] different [21:22] on this side a port you can imagine it [21:24] in the most simple [21:25] form as an interface so there's an [21:28] interface [21:29] and what we do is that we create a class [21:32] that implements that interface and wraps [21:35] around the two wraps around the [21:38] third-party library [21:41] with sms for example is is quite easy to [21:44] imagine [21:45] that um some we are using some sms [21:48] provider [21:48] and then some competition some [21:51] competitor of them [21:52] um lowers the prices so you want to [21:54] change save some money [21:56] the only thing we need to do is create a [21:58] new adapter for that other [22:00] provider um implement the interface [22:03] wrap around their library and we are [22:06] good to go [22:07] uh actually in my company the cto which [22:10] only does some [22:11] coding every two times in a year imagine [22:15] to [22:15] manage to replace our sms provider in [22:18] one morning if i'm not mistaken it's [22:21] quite easy to do that [22:23] of course not all ports are as simple as [22:25] an interface [22:27] especially when it comes to persistence [22:29] but you get the idea [22:34] so so a small example of what is [22:39] what it looks like a an adapter a [22:42] driver adapter so you have here a login [22:45] controller [22:46] you get the constructor it receives a [22:48] service you need to get in this case not [22:50] the authentication service [22:52] we get it from dependency injection then [22:55] we have an action [22:56] to log in we get the [22:59] the http request injected in that [23:03] action we get data out of the http [23:07] request [23:08] and we pass it on to the use case [23:11] it's pretty simple in this case [23:15] on the other side we have something very [23:18] similar [23:19] so you have an adapter it implements [23:23] an interface which is the port [23:26] it gets injected with dependency [23:28] injection the client which is [23:29] the third party library then we have a [23:32] method that we can use [23:35] so we only pass some data into that [23:36] method and that data is transformed [23:39] into whatever the client needs the third [23:42] party library [23:43] so in this case we're creating an object [23:45] message and we pass it [23:47] on to the to the client to the third [23:49] party library [23:57] okay so then it's 2008 [24:01] and jeffrey palermo he came up with this [24:05] idea of onion architecture and he [24:08] in in opposing to the exact [24:11] architecture we talked which talked [24:13] about what's outside of the application [24:14] he talks about what's inside of the [24:16] application [24:17] and here it identifies three layers [24:20] so the first one the domain model which [24:22] is the representation of the domain [24:24] with entities value objects that the [24:26] entities use and so on [24:30] so then there is the main business logic [24:33] and outside that [24:34] wrapping around that we have domain [24:36] services [24:37] domain services are [24:40] is code that is still domain code but [24:43] the code that [24:44] the logic doesn't quite fit in an entity [24:46] so it's [24:47] mainly code that coordinates entities [24:51] and outside that finally we have the [24:53] application services so the application [24:55] layer [24:56] and the application layer for example [24:58] repositories [25:00] repositories they get data from from [25:03] persistence so [25:04] they instantiate some entities tell the [25:06] entity to do something [25:08] persist the entity it's a use case [25:12] important here to note that the [25:13] dependencies go inwards so the outside [25:15] layers [25:15] know about the inside layers the inside [25:18] layers are completely isolated from the [25:20] outside layers [25:24] there is 2011 and uncle bob comes again [25:27] and he says [25:28] we need to uh think about architecture [25:31] and organize our code in a different way [25:34] the program the software so [25:37] the project should scream out what it [25:40] does what it is about [25:42] so we usually organize our controllers [25:43] in one folder our helpers in another [25:45] folder and so on [25:47] and we should do it differently we [25:48] should group them by [25:50] um by context [25:54] so you make these components components [25:56] about healthcare and you put everything [25:58] about healthcare there [26:00] billing you have a component about [26:01] billing you put all all things ready to [26:03] building there [26:04] and so forth so on this is again [26:07] encapsulation [26:09] modularity [26:15] okay this is uh almost over this part [26:18] so then it it's 2006 greg yen comes [26:22] along [26:22] starts talking a lot about cqrs [26:25] so how does this work well we have the [26:28] presentation layer controllers [26:30] they use a command object [26:33] which is just a dto just an object that [26:35] has some data inside [26:37] they trigger dispatch that command that [26:39] object with just data no logic [26:41] just data it sends it to the command bus [26:44] in the command bars it works well [26:46] like a buzz there's several stops along [26:48] the way [26:49] so that piece of data it goes first to [26:51] the first stop it validates it later [26:54] if the data is validated correctly if [26:56] it's valid then it moves on to the next [26:58] step [27:00] next step it's for example opening a [27:02] database transaction [27:04] and then the that data that command that [27:06] means something [27:08] it will be handled it will be handled by [27:10] a command handler which is basically an [27:12] application service [27:13] is a use case that use case of course [27:16] gets that data it knows what to do with [27:18] that data [27:20] gets some data out of the database tells [27:22] it to do something or creates some [27:24] entity persists it so on [27:26] fine everything works out goes back to [27:29] the command bus [27:30] close the transaction and the data is [27:32] saved in the database [27:34] now this is not very different from what [27:36] we [27:37] are used to doing without cqrs the main [27:40] difference here is that [27:41] we have one command that means something [27:44] to the domain [27:45] for example create user or upgrade user [27:50] or bill whatever [27:54] but what's interesting here is that [27:56] instead of handling the command [27:58] we can queue it [28:01] so instead instead of immediately [28:03] handling the command and leave the user [28:04] waiting for it [28:06] we can send it to a to a queue and then [28:08] we're done there we can immediately [28:10] return to the user [28:11] then we have workers that are pulling [28:14] data from that queue [28:16] and they are finally executing it and [28:18] sending it to the command handler [28:21] this allows us to parallelize processing [28:24] and to [28:24] handle a lot more load of course [28:28] then there's also the query so we're [28:31] trying to separate [28:32] the um right model from the read model [28:36] and then there's always the also the [28:37] query buzz to be honest i never used [28:39] this [28:40] um i never really needed it i just [28:43] create some [28:44] query object and just do a query to the [28:46] database [28:47] get the data that i need and show it to [28:48] the user [28:52] okay so finally [28:56] let's give a recap on this so you have [28:59] the application card on one side we have [29:00] the user interface and the other side [29:02] you have the infrastructure [29:04] so you have your users that are using uh [29:07] our application [29:08] they do something on the website or with [29:10] an api or whatever [29:12] or a console command on the other side [29:15] we have the tools that we use [29:17] third-party libraries [29:21] and the first thing that our request [29:23] from the users [29:24] reaches is our controllers or the [29:26] console command [29:29] now these are gonna get the data that [29:32] the user sends [29:33] and pass it on to the application [29:37] on the other side we have the secondary [29:39] or driven adapters [29:40] and they adjust third party tool [29:44] to what the application actually needs [29:50] so again remember the dependencies go [29:53] inwards [29:54] and then inside we have the ports as the [29:56] first thing [29:58] then the application layer which is [29:59] basically our use cases [30:04] we have the command and query buzz on [30:06] the left side because it's what drives [30:08] the application [30:09] when we issue a command we're telling [30:12] the application what to do [30:15] and on the other side we have an event [30:17] buzz [30:19] events are important they're similar to [30:22] commands but while the command [30:24] tells the application to do something an [30:26] event tells [30:27] says that the application did something [30:31] so it's triggered after something [30:33] happens after a use case happens which [30:36] is useful [30:36] because you can make your application [30:39] more organic [30:41] do something when something else [30:43] happened [30:45] then in the middle we have finally the [30:47] domain layer with the domain services [30:48] and the domain model [30:51] and finally we slice our application [30:56] remember the screening the screaming [30:57] architecture from uncle bob [31:00] we made this component and here [31:03] it's very important then to have events [31:06] because these components these sections [31:08] of our code base they should be isolated [31:11] they should be bounded contexts but then [31:14] they need to work together right [31:16] so how can they work together if they [31:18] don't know about each other [31:21] through events so command tells the [31:23] component to do something [31:25] for example create a user and there's [31:27] that component that's going to create [31:28] the user [31:29] and then it triggers an event hey a user [31:32] has been created [31:34] then whoever is listening to it will [31:38] react to it and do whatever needs to be [31:39] done so there's one thing [31:42] that is shared among the two components [31:44] still [31:46] which is the event [31:49] but then it comes into play the shared [31:52] kernel [31:53] that we saw from ddd we clearly identify [31:56] the code that is shared among components [32:03] but there's more so we have the [32:06] application ui card and adapters [32:08] so mainly our application [32:11] and then we have three more layers below [32:13] it from which it depends so the first [32:15] one the shared kernel [32:17] that we talked about in the bottom of [32:19] course you have the programming [32:20] languages php or java or whatever [32:24] and then in between the shared kernel [32:26] and the programming languages we have [32:27] still one layer [32:29] which i like to call the userland [32:32] language extensions [32:33] which are our own it is is our own [32:37] extension to the language so think about [32:39] it for example with [32:41] daytime objects in php [32:45] they're native to php we can use it [32:47] everywhere right [32:48] but they they're pretty much agnostic [32:50] they're domain agnostic [32:52] they're ascetic [32:55] so we can use it through our our our [32:57] code and that's fine [33:00] unless of course we want to control for [33:02] example for testing purposes [33:04] we want to control exactly what value is [33:06] coming out of there [33:07] what value the data has the date has [33:10] because if you are going to compare [33:11] compare objects on your tests and there [33:14] is one second difference [33:15] or one microsecond difference then it's [33:18] going to fail [33:19] and it shouldn't right so you want to [33:20] control that but then yeah [33:22] you have daytime objects being [33:24] instantiated all over the place [33:26] they're native you're using it correctly [33:28] but it's not quite working out for you [33:30] so what do you do you make a wrapper [33:32] around it [33:33] create your own daytime object which can [33:36] be just a wrapper around [33:38] the native time object and then you use [33:41] that one [33:42] and at run time you can just swap the [33:44] implementation [33:46] in during the tests [33:50] same thing with the uuids uuids are [33:52] pretty much [33:54] not agnostic they're ascetic [33:57] in that case they are not part of a php [34:02] the reason being that uuid is kind of uh [34:06] have a new version every once in a while [34:09] and it's not really a good idea to put [34:11] into the core of php because then [34:13] the php actual car developers will have [34:16] to [34:16] update it all over all the time so it's [34:18] easier to have it as an external library [34:20] but still it's quite agnostic and we [34:23] could use it [34:24] in our code base as just yeah it's a [34:26] uuid [34:27] but so what but we don't want to be [34:30] depending on a third-party library so we [34:32] can make our own wrapper [34:33] around it then we can control it then [34:36] you can use it as if it was part of the [34:38] language [34:40] so we have this dependencies as well [34:47] okay so we have these ideas we have the [34:49] these principles we have [34:51] uh some idea of how to put it all [34:53] together um [34:54] but it's still very abstract right just [34:57] ideas [34:58] just some sketch on the paper [35:01] well um there's this idea as well about [35:04] architectural evidence coding style [35:08] it means basically two things one that [35:11] we can drop hints uh in our code about [35:15] the the architectural responsibilities [35:18] of each piece of code this means for [35:22] example [35:23] uh or mainly even [35:25] [Music] [35:26] class names so if you have a repository [35:30] that deals with users then we call it [35:32] user repository that's pretty simple [35:34] you know what the repository is okay [35:37] that class is repository i know [35:38] how it should be used where it should be [35:40] used and if it's going to be used [35:42] if i see it being used in the wrong way [35:45] then i know this is a mistake i need to [35:47] fix it [35:48] now i don't say that we should do that [35:50] everywhere [35:51] if we have uh entities i don't say that [35:54] we should push fix [35:56] an entity name user entity that doesn't [35:59] really sound very good i think it's [36:00] redundant but as everything [36:03] we should think about what makes sense [36:06] to use [36:09] then there's also simon brown saying [36:11] that we should reflect the architecture [36:13] in the code [36:15] which is basically the same idea as [36:18] streaming architecture and [36:19] slicing the code into pieces [36:23] so we had one more idea [36:26] but how do we actually put this to [36:28] practice well what's the boundary [36:30] in the end you have a model if you have [36:32] microservices the boundary [36:34] is the microservice itself right you [36:36] have http in between [36:39] in a monolith a boundary is just a [36:41] folder that's what it is [36:44] it communicates something to you so if [36:47] you have [36:48] user interface the application car and [36:50] infrastructure you can just create [36:51] folders for it [36:55] then yeah what's inside the folder for [36:58] the user interface well [37:00] you have uh apis right [37:03] you can have a great graphql api in the [37:05] rest api [37:07] so you can have a folder for all your [37:09] apis in a folder for each type of api [37:11] you have console commands so you create [37:13] a folder for all your console commands [37:16] and you can have several websites [37:18] running on your application [37:20] you have a website for admin and a [37:22] website for the actual consumers think [37:24] for example of wordpress [37:26] has uh a view that is only for the users [37:29] going to the [37:29] to the to the website but there's a [37:32] completely different website [37:35] for administering the the blog right [37:38] so it's two different websites two [37:40] different views of the same application [37:46] then on the infrastructure side pretty [37:49] much the same thing [37:50] we have a folder for the infrastructure [37:51] then one folder for each comma for each [37:54] tool that we use and inside each one of [37:57] those [37:59] tool folders we have a folder for each [38:01] vendor adapter [38:02] so think for example you have an [38:04] application and your [38:06] application sends out sms's it's here in [38:08] poland we are going to [38:10] we are going to expand to the [38:11] netherlands and you [38:13] figure out our business figures out yeah [38:15] we have a provider here in poland but [38:18] in the netherlands it's cheaper to send [38:20] us a message with another provider [38:22] so what do you do you create two [38:23] adapters and then it's just a matter of [38:25] configuring [38:26] configuration if it's in the netherlands [38:28] you use one adapter if it's poland you [38:30] use another adapter [38:31] then you have two adapters living next [38:33] to each other and you are using them in [38:35] your application real in in production [38:42] then the core this is a bit more [38:44] complicated [38:46] so first level you have the components [38:48] so one folder for all your components [38:51] you have for example the block component [38:53] inside the block component [38:55] we're going to have one application one [38:57] layer for [38:58] which is the application layer with all [39:01] the code that related to that [39:02] to that layer then another folder next [39:06] to it [39:07] for the domain layer with whatever code [39:10] is needed there [39:13] then you have a folder for your ports [39:17] that identify each one of your tools [39:21] now the ports folder is not inside the [39:23] components folder because [39:24] it's not a component it's something it's [39:27] code that is going to be used by all [39:29] your components [39:30] so it's outside of the components next [39:33] to the component folder [39:34] but it's still inside of the core [39:36] because it's the ports are what [39:39] tells you how you are going to use [39:43] a specific tool [39:48] then finally next to the components in [39:50] the ports you have the shared kernel [39:52] which is also not part of a specific [39:54] component is shared among [39:56] all components so it's still in the car [39:58] but then next to the components folder [40:17] so again recap so we have our source [40:20] folder [40:21] we have three main folders one for the [40:23] user interface the car [40:24] and then the infrastructure inside the [40:26] car we have components [40:28] and we have ports each company has its [40:30] own application domain layer [40:34] then we still have the shared kernel [40:37] which is part of the core [40:39] then finally we have uh the language [40:42] language extension which is something [40:45] that [40:46] you own you control it entirely and [40:48] that's very important [40:50] because you don't want some uh uh open [40:53] source project to change [40:55] their code and then suddenly your [40:56] application breaks [40:58] so you own this and this can is [41:00] something that can be owned [41:02] only for that project but maybe it can [41:04] be even be reused [41:06] in other projects of your company the [41:08] important thing [41:09] is that you own it and you can change it [41:11] and you can improve it as uh [41:12] as you see fit in this case we put it in [41:15] a lib folder [41:16] next to the source folder because it's [41:17] completely unrelated to [41:19] the car code of your application [41:22] and you can even extract it and put it [41:24] in your own in a separate project and [41:26] just [41:27] include it with composer [41:33] so we have all these ideas we know how [41:35] to [41:38] put these ideas to practice but we're [41:41] going to make mistakes [41:43] and how do we prevent mistakes from [41:45] happening how do we make sure that we're [41:48] not gonna [41:49] have problems online because of mistakes [41:52] well [41:53] the same way we do with the rest of the [41:54] code we test it [41:56] so we have unit tests integration tests [41:59] and so on [42:00] for structure you can do the same thing [42:03] there's this uh [42:04] tool command line tool called depth [42:06] track it was built by [42:08] by the guys at symphony um essential [42:10] labs [42:11] and well the way it works you just [42:13] create a [42:14] configuration file in yaml we specify [42:17] the layers that you have [42:18] and you specify a rule set saying okay [42:21] layer [42:22] a can depend on layer b layer b can be [42:24] dependent on layer c and so on [42:27] and then you run it you run it like you [42:30] run any other test [42:31] like your unit tests it's command line [42:34] tool [42:35] if it uh if there's a rule being broken [42:39] it spits out an error it fails you put [42:41] it in the ci [42:43] run it like a unit test fails the build [42:46] we need to fix it that's it [42:49] if the command line [42:53] output is not enough for you you need to [42:54] understand it a bit better [42:56] it can also generate some nice images [42:59] for you [43:00] so you see for example controllers are [43:02] allowed to depend on services and [43:04] queries and repositories [43:05] but if repository is going to depend on [43:08] control then you can see that something [43:10] is wrong [43:10] right [43:13] if you have a bigger application that [43:16] you can have in the end something like [43:18] this [43:20] so you see for example here the domain [43:22] depends on nothing [43:24] except for the code itself [43:27] so the the extension which is part of [43:30] the language as you see it [43:31] it depends also on the shared kernel [43:35] domain which is [43:36] the part of the domain that is shared [43:39] within [43:40] several components [43:44] we can see for example code depending on [43:46] psr [43:49] interfaces you can see the [43:51] infrastructure [43:52] depending on a lot of stuff but nothing [43:54] is depending on the infrastructure [43:56] the infrastructure being third-party [43:58] libraries [43:59] why because there's ports and adapters [44:03] isolating that that infrastructure code [44:06] so our code actually depends on the [44:08] ports and then there's adapters [44:11] making the connection [44:18] so finally the last slide if you fell [44:21] asleep [44:22] in the meantime this is the moment you [44:24] need to wake up [44:27] so first takeaway a code unit must have [44:30] only one logic place to live [44:32] well by this i don't mean that we [44:34] magically know where [44:36] the code is or where it should be [44:39] what i mean is when we open the source [44:41] folder if we're looking for a controller [44:43] that [44:44] creates users okay we open the source [44:46] folder [44:47] it's user interface stuff okay go into [44:49] the full reviews interface [44:50] okay now you it's about users so we have [44:55] several folders there use cases whatever [44:57] modules [44:58] oh it's about there's a folder here for [45:00] users going to that one [45:02] and so forth so on so we can navigate [45:04] not that we magically know where it [45:06] lives but we can navigate through it [45:08] in a logical way [45:11] make the architecture explicit and by [45:14] this i don't mean that you should do [45:15] exactly what i say here it's not about [45:19] following this [45:19] this this this like a dogma [45:23] no it's it's that you okay you learn [45:25] these [45:26] patterns you learn these ideas and you [45:28] use what you need [45:30] but the important thing the the most [45:32] important message that we [45:34] that i want to pass here is make sure [45:36] everyone [45:37] understands and everyone is in the same [45:39] page make sure [45:41] people look at the code and they can [45:43] understand what's going on there [45:46] either by name of code or by folders [45:51] but people can understand that [45:52] communicate with your colleagues [45:54] and make decision decisions together [45:55] with your colleagues about how [45:57] you should structure application what [45:59] makes sense for your team [46:02] should be it must be explicit for [46:04] everyone [46:07] in the end no matter whatever what is [46:10] the [46:11] the the way you organize your code base [46:17] you must favor modularity encapsulation [46:20] this is not [46:23] a software development principle this is [46:25] an engineering principle [46:27] you find it everywhere you find it in [46:29] software but you follow find it in [46:30] mechanics you find it in electronics [46:32] you find it in buildings you find it in [46:35] building cars puzzles whatever [46:37] it's always about modularity and [46:39] encapsulation [46:40] this is engineering [46:45] build moderates but plan micro services [46:52] this is not to be taken literally [46:55] what i mean is for me it helps me to [46:58] think about microservice how would i do [47:00] this [47:00] if i would do it in microservices where [47:03] would be the boundaries [47:05] how would i make this these these [47:07] isolated pieces of code communicate [47:10] and then adapt that to a monolith if you [47:13] have a monolith of course if you have [47:14] microservices well [47:16] but it helps to think about it in in [47:19] that way [47:20] if i had an explicit http layer there [47:23] how would i do this and in the enforce [47:27] architecture because you're going to [47:28] make mistakes [47:29] we're not perfect you have junior [47:31] developers have senior developers [47:33] some people know some things better some [47:35] people know other things better [47:37] and even if we know things very well we [47:40] are just humans we're going to make [47:41] mistakes [47:41] so we need to enforce it that's it [47:45] there's uh here's some links for the [47:47] slides [47:48] or similar slides to this one cold [47:50] sample [47:51] in php um my blog posts [47:55] uh explaining all this and more and [47:58] please [47:58] give me some rating on joined in so that [48:01] i can improve myself [48:03] thank you very much [48:13] any questions [48:24] oh it doesn't work as usual [48:29] you can just yeah speak loud i don't [48:31] know my question is as you [48:34] started you are focusing on namespaces [48:43] in one main space of course did you try [48:46] to reverse the namespace [48:48] that complement itself should [48:53] speak the course [48:56] that you don't have one core for all [49:00] components [49:07] um yeah so the question is if [49:10] i tried reversing the core with the [49:13] components and having [49:14] um the core inside [49:18] have one core for each component if i [49:19] understand correct this question [49:21] um yeah i gave this a lot of thought [49:27] i don't think that's the best approach [49:28] personally maybe it works [49:31] it depends also on the context and on [49:32] the team but for me [49:34] i don't think that's the best approach [49:36] because [49:37] here we're talking about the core of the [49:39] application [49:41] and the the way the application is [49:42] structured is there's [49:44] okay i mean the code is actually [49:47] the application the way you [49:51] reach the application is the [49:54] driver adapters right but then the [49:57] application [49:58] itself is the core and then what you [50:00] want to do is slice that application [50:02] uh in pieces that uh deal with [50:05] one specific set of logic [50:09] so i don't quite see it as a [50:13] component having a core or i see it [50:17] as a component having as a component [50:20] having a application layer [50:22] and a domain layer and maybe [50:26] the domain layer you can imagine it as a [50:28] core but [50:29] um yeah i you need to give it [50:33] different names and [50:39] each yeah probably is [50:49] independent therefore if we [50:54] group every component in one place [50:58] therefore we don't show the independent [51:02] of the components [51:03] like that if we reverse the name spaces [51:06] therefore [51:07] our [51:28] yeah yeah yeah i don't see it that way [51:34] but uh but yeah i'm not a lot of [51:37] knowledge [51:38] so maybe your approach works as well or [51:40] maybe it works better [51:42] for me what my experience this works [51:44] really well [51:45] um we're having one folder for each [51:49] component so we're clearly [51:50] separating them anyway of course [51:54] at some point if you want to transform [51:57] this component [51:58] into a microservice then yes then you [52:01] if you stretch it the same way you're [52:03] going to also have a car [52:05] folder for it inside that micro service [52:07] and then that core will be [52:09] maybe separated even in in other slices [52:12] it depends also on the the size of that [52:14] that micro service is going to have [52:16] but yeah thanks for a question i hope i [52:19] answered the [52:20] satisfactorily [52:24] any other questions [52:27] excuse me thanks [52:31] you said that the validation should be [52:33] on the command bus [52:35] but what if i want to use the validation [52:38] validation component from the symphony [52:40] and the command bus is inside my core [52:44] so it shouldn't be dependent on the [52:46] infrastructure detail right [52:48] no the command bus is part of the [52:50] infrastructure [52:51] so it's not in the core um the command [52:55] class itself will leave in the [52:56] application layer um [53:00] but you can use the the symphony [53:03] uh validator in the command buzz anyway [53:06] yeah if i um dispatch the command [53:10] on my command bus so the command hunter [53:13] is responsible to handle that comment [53:15] so where is the place for the validation [53:18] using the [53:20] third party library [53:23] let me let me just get there okay [53:27] so we have so we have as part of the [53:30] infrastructure [53:31] we have a message buzz right and the [53:34] message buzz is not a command buzz [53:36] it's not an event buzz it's a message [53:37] box now what we do [53:39] is that we use this with two different [53:42] adapters [53:43] one adapter is going to be implementing [53:45] the command bus and another adapter [53:47] implementing the event bus but in the [53:49] end they're both [53:50] message buses and they're both part of [53:52] infrastructure [53:53] so in your controller you're going to [53:55] get injected [53:56] the command bus dispatcher which is [53:58] basically the command bus [54:00] um you instantiate the command object [54:03] and you set it to the command bus the [54:05] command bus leaves here [54:07] figures out it figures out which handler [54:10] is going to handle that command [54:12] and it's going to deliver it the command [54:13] handler lives here [54:16] so it's completely in in reality [54:18] conceptually it's working on this side [54:21] because it's [54:21] it's driving the application but it's [54:24] actually [54:25] the the the buzz itself is actually part [54:28] of infrastructure [54:29] so what it says is wrap up the third [54:31] party library like the command bus [54:33] and inject there the validation and do [54:36] the validation [54:37] on that yes but not quite inject the [54:39] validation [54:40] because the command buzz needs to be [54:42] while it's basically set up with [54:43] configuration [54:44] so in the end we have a service in the [54:47] yaml file that configures it you have a [54:49] service that is the [54:50] command dispatcher and then you have a [54:52] list of of [54:57] what you call it buzz steps or whatever [54:59] you call it [55:00] and one of these steps is actually the [55:03] validator [55:04] and the command buzz what it what it [55:06] does is well basically [55:08] you can imagine it it's not exactly but [55:10] you can imagine as a forage loop [55:12] okay we have this command now for each [55:14] one of the [55:15] steps uh give this command into that [55:18] step so [55:20] the first step is going to be the [55:21] validator and then it validates or not [55:24] and the buzz itself is part of [55:27] instructor [55:28] and it's going to get injected the the [55:30] symphony validator which is also part of [55:32] instructor [55:33] so your application core doesn't know [55:35] anything about the validator of symphony [55:38] did this make sense it makes [55:44] any other question [55:51] i just wanted to ask you if you write [55:53] your code [55:54] on top of any framework like symphony [55:57] and if yes [55:58] how do you treat the framework code as a [56:01] what kind of [56:02] layer yeah we we use symphony [56:07] symphony yeah i treat it as part of [56:11] infrastructure [56:12] because your your application itself [56:15] doesn't care what [56:16] framework it's using so [56:19] in um in a ideal world [56:23] you would be able to swap the the [56:25] framework [56:26] you should be able to swap the framework [56:27] and your application will still be able [56:29] to work [56:29] of course in practice that's not going [56:31] to happen or at least [56:33] not easily on a pet project of mine [56:37] i did go through with all that [56:40] separation and i didn't man i wanted to [56:43] manage to to replace [56:44] symphony with with with another [56:46] framework just to try it out to see how [56:48] it uh [56:48] if it was was at all possible but i [56:51] didn't i don't have the time for it [56:53] but but yeah we treat it as [56:54] infrastructure okay thank you [56:59] uh can i add to your answer for him so [57:03] what you can do and what we did in our [57:05] company that helps a lot to switch [57:07] frameworks [57:08] rely on the psrs so for example [57:11] uh do not rely in the symphony requests [57:13] and response classes [57:15] rely on the psr interfaces because then [57:18] each framework is going to implement [57:19] that interface so you can just switch [57:22] cool more questions i think we have [57:26] zero minutes yeah zero minutes so [57:29] we're done i guess if you uh want to [57:31] make more questions and i'm outside [57:32] just reach out and that's it cool thank [57:36] [Applause] [57:38] you [57:41] you