No Silver Bullets in Software
49sChallenges the audience's search for a perfect solution, resonating with experienced developers who know there's no one-size-fits-all.
▶ Play ClipHerberto Graça's talk at PHPcon Poland 2019 focuses on making software architecture explicit through modularity, encapsulation, and clear boundaries. He draws on decades of software engineering wisdom, including principles like Single Responsibility, Domain-Driven Design, and Hexagonal Architecture, to show how to organize code for maintainability and reliability.
Graça introduces himself as a lead developer at Worksport in the Netherlands, with a background as a high school teacher before becoming a software developer.
The talk covers ideas from experienced software engineers over the past 30-40 years, focusing on how to create reliable and maintainable software.
Graça emphasizes that there are no silver bullets; developers must understand various ideas and patterns and apply the right tools for each problem.
The evolution of software development from unstructured programming to object-oriented programming, highlighting the trend toward modularity and encapsulation.
The shift from monoliths to distributed computing (CORBA), then to service-oriented architecture, enterprise service buses, and finally microservices, with the principle of 'smart endpoints, dumb pipes'.
A 'big ball of mud' is characterized by unclear class/method names, no obvious place to put code, dependency mess, and no clear boundaries, making testing and refactoring difficult.
Testing should focus on behavior, not implementation details. When refactoring, you should only need to test the public interface of a module, not every internal class.
Granularity levels in code: plain code, methods, classes, interfaces, namespaces, and libraries. Graça focuses on namespaces as a key area where teams often fail.
Robert C. Martin's principles: Single Responsibility Principle (a code unit should have one reason to change), Common Closure Principle, and Common Reuse Principle (classes that change together should be together).
Domain-Driven Design (DDD) concepts: ubiquitous language, context map, bounded contexts, shared kernel, and anti-corruption layer.
Hexagonal Architecture (Ports and Adapters): application core with ports (interfaces) and adapters that wrap external tools, allowing easy swapping of implementations.
Onion Architecture: domain model at the core, wrapped by domain services, then application services. Dependencies go inward.
Screaming Architecture: organize code by business context (e.g., healthcare, billing) rather than by technical layer (controllers, helpers).
CQRS (Command Query Responsibility Segregation): separate commands (write) from queries (read). Commands can be queued for async processing.
Practical folder structure: source folder with three main folders: User Interface, Core, and Infrastructure. Core contains Components (each with Application and Domain layers), Ports, and Shared Kernel.
Use tools like Deptrac to enforce architectural rules automatically in CI, preventing dependency violations.
Final takeaways: a code unit must have only one logical place to live, make architecture explicit, favor modularity and encapsulation, build modules but plan microservices, and enforce architecture.
"The title accurately reflects the talk's core message about making software architecture explicit through patterns and practices."
What is the Single Responsibility Principle (SRP) as defined by Robert C. Martin?
A code unit should have only one reason to change.
14:20
What does the Common Closure Principle state?
Classes that change together should be grouped together.
14:57
What is the Anti-Corruption Layer in Domain-Driven Design?
A translation layer that prevents data structures from leaking between bounded contexts.
18:48
In Hexagonal Architecture, what is the difference between a port and an adapter?
A port is an interface that defines how the application core communicates with the outside world; an adapter is an implementation of that interface that wraps a specific technology.
19:15
What is the Dependency Rule in Hexagonal Architecture?
The application core should not depend on external frameworks or libraries; instead, it defines ports (interfaces) that are implemented by adapters in the infrastructure layer.
21:00
What is the difference between a command and an event in CQRS?
A command tells the application to do something; an event announces that something has already happened.
30:19
What is a shared kernel in Domain-Driven Design?
A shared kernel is code that is shared among multiple bounded contexts, such as common value objects or interfaces.
18:40
What is Deptrac and how does it help enforce architecture?
Deptrac is a static analysis tool that can verify architectural rules (e.g., layer dependencies) by running as a command-line tool, often integrated into CI.
42:03
What is a 'big ball of mud' in software architecture?
A big ball of mud is a codebase with no clear structure: class/method names don't convey meaning, dependencies are tangled, and there are no clear boundaries, making it hard to test and refactor.
11:57
What does 'Screaming Architecture' mean?
The architecture should be reflected in the folder structure and class names, so that the codebase 'screams' its purpose (e.g., grouping by business domain rather than by technical layer).
25:28
Single Responsibility Principle
A foundational principle for modular design, applicable not just to classes but to methods and modules.
14:20Hexagonal Architecture (Ports and Adapters)
Provides a clear pattern for isolating core business logic from external concerns like databases and web frameworks.
19:15Screaming Architecture
Encourages organizing code by business domain rather than technical layer, making the project's purpose immediately clear.
25:28Enforcing Architecture with Deptrac
Introduces a practical tool for automatically verifying architectural rules in CI, preventing drift over time.
42:03Modularity and Encapsulation as Engineering Principles
Frames these concepts as universal engineering principles, not just software-specific practices.
46:40[00:00] okay uh yeah good morning everyone
[00:04] so let's get started um
[00:07] okay so my talk is uh
[00:10] called making architecture explicit it
[00:13] talks about the
[00:14] many things but first
[00:18] first of this so first a bit about me
[00:21] i'm
[00:22] portuguese i graduated in it and then i
[00:25] became a
[00:26] high school teacher i was a high school
[00:28] teacher for a few years
[00:30] and then i get uh got fed up with it and
[00:33] uh decided to be a software developer
[00:36] um currently i'm a lead developer at
[00:38] worksport in
[00:39] the netherlands and i'm yeah
[00:42] like a good food with wine coding
[00:46] just like uh pretty much everyone else
[00:48] here and i love my
[00:49] plucky my motorbike
[00:53] so what this talk is about it's about
[00:56] ideas from
[00:57] people that are way smarter than me
[01:00] they've been in the business for
[01:01] many many years 30 40 maybe more
[01:05] they have the ideas from 20 30 maybe
[01:09] 40 years ago ideas that are still valid
[01:11] today ideas that
[01:13] we still don't know them very well today
[01:16] we don't use them enough and in the end
[01:19] it's uh
[01:19] also about how you put all those ideas
[01:21] together in order to create a good
[01:24] quality software that is
[01:25] reliable and it is maintainable for many
[01:28] years
[01:32] however no matter how much
[01:37] i'm confident about what i'm saying here
[01:39] today there are no silver bullets
[01:41] there's no holy grail
[01:43] there's no one would fit all in the end
[01:45] we need to
[01:46] understand all ideas
[01:51] increase our our toolkit of ideas
[01:55] and patterns and knowledge and then
[01:57] analyze the project that we had at hand
[01:59] and analyze the pro the problem that we
[02:01] need to solve and then use the tools
[02:03] that are
[02:05] fitting the solution
[02:12] history is uh very interesting for me
[02:15] i think it's very important
[02:18] we all have our own personal history
[02:22] we do mistakes along the way and then we
[02:24] try to learn from them
[02:26] and hopefully not repeat them very often
[02:31] as a country as well we have mistakes
[02:36] the way that's why we learn history at
[02:38] school right
[02:39] that we so that we try not to make the
[02:41] same mistakes
[02:42] um portugal had a dictatorship for
[02:45] example
[02:47] so we learned that at school so that we
[02:48] try not to
[02:50] get convinced into getting a
[02:51] dictatorship again
[02:53] so we learn from history and we as a
[02:56] community
[02:57] should also learn from history so let's
[03:00] uh
[03:00] take a look at at last few years in
[03:03] software development
[03:05] so we started off with non-structured
[03:08] programming
[03:09] back then it was maybe the 50s so just a
[03:12] series of
[03:13] assembly commands scattered or splashed
[03:17] on the screen moved on from there to
[03:20] structured programming because we were
[03:21] repeating a lot of code
[03:22] so we came up with the conditionals and
[03:25] with
[03:26] loops to help us not repeat so much code
[03:30] then we moved on to procedural and
[03:31] functional programming where you can
[03:33] actually group
[03:34] sections of code then call them whenever
[03:37] we need them
[03:39] and finally we came to object-oriented
[03:40] programming which groups
[03:43] data with the related functionality that
[03:47] that should change and manipulate that
[03:49] data
[03:50] and this was uh op was in the
[03:53] showed up in the beginning of the 80s
[03:55] maybe a bit before but then in the
[03:57] beginning of the 80s was when actually
[03:59] started to pick up and after that the
[04:02] the
[04:02] language paradigms they didn't really
[04:04] evolve much
[04:06] so we but the problems kept kept
[04:08] evolving and kept growing
[04:09] software kept growing and we needed
[04:12] something more so we
[04:13] turned our heads into uh design patterns
[04:18] on the other hand at the more coarse
[04:20] granular
[04:21] view we started with the monolith of
[04:23] course
[04:25] everything one single program
[04:28] then in the beginning of the 80s we had
[04:30] our first attempt at
[04:32] distributed computing that was corba and
[04:34] corvo was interesting because it
[04:36] obstructed the network away
[04:39] that was handy we had an object and
[04:43] that object would have execute but not
[04:45] execute locally in our machine it would
[04:47] execute in another machine
[04:48] that was really cool except that when we
[04:52] were running our code we didn't really
[04:54] know where it was going to execute
[04:57] and there was network lag and we never
[04:59] knew where it where
[05:00] where and when it would happen so that
[05:02] was a problem
[05:04] then we solved that by threading our
[05:06] heads into
[05:07] service oriented architecture explicitly
[05:10] knowing
[05:11] when we are reaching for something
[05:13] outside of the local machine
[05:18] but then back then we had software that
[05:21] was
[05:22] deployed deploying different servers
[05:23] they were communicating or they needed
[05:25] to communicate
[05:26] but they had the time they weren't built
[05:28] to communicate
[05:29] so what we needed to do was put
[05:32] something in between
[05:33] that would translate the messages or the
[05:36] payloads right and that sounds like a
[05:39] very nice idea and it was
[05:42] so we had servers that actually could
[05:44] communicate through that
[05:46] one middle thing and that was how the
[05:48] enterprise service buzz
[05:49] came to be but with time
[05:53] well we didn't even own the actual
[05:57] uh software uh that needed to
[06:00] communicate we only
[06:01] won the part in the middle so we started
[06:04] to put more and more logic there
[06:06] more business logic in there and then
[06:10] well it became so complicated
[06:13] that no one there touching it because if
[06:16] you touch it and you break it we break
[06:18] everything and that was a problem with
[06:20] the enterprise service bus
[06:22] so after that came finally microservices
[06:25] and microservice has actually a
[06:26] principle which says
[06:29] smart endpoints them pipes exactly
[06:32] because
[06:33] of the problem of the enterprise service
[06:35] bus so no smart things in the middle
[06:38] all the smarts are in the ends in the
[06:41] micro services
[06:42] and nowadays we're already talking about
[06:44] nano services lambda serverless and so
[06:46] on
[06:48] in the end if we think about it it all
[06:50] evolved in the cen in the direction of
[06:52] modularity and encapsulation
[06:56] building things in small parts that can
[06:58] fit together
[07:00] and that can work together and that we
[07:01] can swap them
[07:03] and construct different things if we
[07:04] want to an encapsulation which is
[07:07] putting related codes together
[07:11] and hiding away the implementation
[07:14] details
[07:19] so let's talk about the monolith
[07:23] some time ago a few years ago when the
[07:25] microservices came
[07:26] into the hype everyone was saying
[07:30] microservices are the way to go monolith
[07:34] is a big ball of mud all the time let's
[07:36] not do it anymore
[07:39] but it's not true nowadays we know that
[07:41] microservices
[07:42] don't solve all the problems
[07:45] microservices solve a set of problems
[07:47] and bring along another set of problems
[07:52] so the monolith in the end it can be a
[07:55] beautiful thing
[07:57] and the micro services don't really
[07:59] solve
[08:00] all the problems that we had and if we
[08:02] cannot solve it with the monolith who
[08:04] says that we can solve it with
[08:05] microservices
[08:07] so when do we have a big bowl of mud
[08:08] then for example
[08:11] when class and method names they don't
[08:13] convey meaning
[08:14] we actually have to dig into the code go
[08:17] see what a method
[08:19] does inside in order to understand
[08:23] how the code works and there's no
[08:26] obvious place to put the code
[08:28] i remember once i was in a i started at
[08:30] the company and
[08:32] i did my first task and then i asked a
[08:33] colleague i asked him
[08:35] hey where where should i put this i mean
[08:37] it's working now i know it's working i
[08:38] have a test for it but
[08:40] where should we actually live and either
[08:43] yeah i just put it anywhere
[08:44] it doesn't matter
[08:47] so it shouldn't be like that there
[08:49] should be a meaning to where you put
[08:51] your code
[08:53] so also when you have a dependency mess
[08:55] code depending on code depending on code
[08:56] depending on code
[08:57] never ends and you can't really isolate
[09:00] it
[09:03] and then also when there's no boundaries
[09:06] which means you cannot really have a
[09:09] sane testing strategy which means
[09:12] is quite difficult to refactor and what
[09:16] do i mean with this well
[09:18] refactoring means that you change code
[09:21] but you don't actually change the
[09:23] behavior
[09:24] it also means that you have a test to
[09:26] prove that the code still works the same
[09:28] way
[09:30] that's refactoring
[09:34] when we test one class we have private
[09:37] methods
[09:38] and we don't test those private methods
[09:40] right
[09:41] why because it's an implementation
[09:43] detail
[09:45] because we can at any moment change that
[09:47] code
[09:48] and the class should behave the same so
[09:51] we don't test it we only test the public
[09:53] interface of that class
[09:55] with modules it's the same thing
[09: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
⚡ Saved you 0h 57m reading this? Transcribe any YouTube video for free — no signup needed.