---
title: 'Herberto Graça: Making architecture explicit @PHPcon Poland 2019'
source: 'https://youtube.com/watch?v=cqJ__1feSLc'
video_id: 'cqJ__1feSLc'
date: 2026-07-01
duration_sec: 3462
---

# Herberto Graça: Making architecture explicit @PHPcon Poland 2019

> Source: [Herberto Graça: Making architecture explicit @PHPcon Poland 2019](https://youtube.com/watch?v=cqJ__1feSLc)

## Summary

Herberto 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.

### Key Points

- **Speaker Background** [00:21] — 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.
- **Talk Overview** [00:53] — The talk covers ideas from experienced software engineers over the past 30-40 years, focusing on how to create reliable and maintainable software.
- **No Silver Bullets** [01:32] — Graça emphasizes that there are no silver bullets; developers must understand various ideas and patterns and apply the right tools for each problem.
- **History of Software Development** [03:00] — The evolution of software development from unstructured programming to object-oriented programming, highlighting the trend toward modularity and encapsulation.
- **Architecture Evolution: Monolith to Microservices** [04:20] — 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'.
- **What is a Big Ball of Mud?** [08:07] — 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 Behavior vs. Implementation** [09:34] — 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** [12:48] — 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.
- **Uncle Bob's Principles** [13:53] — 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)** [16:54] — Domain-Driven Design (DDD) concepts: ubiquitous language, context map, bounded contexts, shared kernel, and anti-corruption layer.
- **Hexagonal Architecture (Ports and Adapters)** [19:15] — Hexagonal Architecture (Ports and Adapters): application core with ports (interfaces) and adapters that wrap external tools, allowing easy swapping of implementations.
- **Onion Architecture** [24:01] — Onion Architecture: domain model at the core, wrapped by domain services, then application services. Dependencies go inward.
- **Screaming Architecture** [25:28] — Screaming Architecture: organize code by business context (e.g., healthcare, billing) rather than by technical layer (controllers, helpers).
- **CQRS (Command Query Responsibility Segregation)** [26:18] — CQRS (Command Query Responsibility Segregation): separate commands (write) from queries (read). Commands can be queued for async processing.
- **Practical Folder Structure** [40:17] — 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.
- **Enforcing Architecture with Deptrac** [42:03] — Use tools like Deptrac to enforce architectural rules automatically in CI, preventing dependency violations.
- **Final Takeaways** [44:18] — 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.

## Transcript

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