Writing cleaner code with Domain Driven Design by Paul van der Slot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] thank you all right welcome everybody and um it's great that everyone here came to my talk about domain driven design and clean code two topics I'm very passionate about so um I will get started because there's a lot to cover what I will be talking about here is first what is domain driven design after that I will touch upon three things ubiquitous language Supple design and the bounded context and how those themes can help you to make your codes cleaner and to improve your code after that I'll talk about what's next but starting my domain driven design Journey it all started at beer Central here in Antwerp during devlox about four or five years ago I was there sending what some friends discussing what we liked that day of conference and I really like to talk about refactoring to a system of systems by Oliver dropbaum it was a talk about the transition from monolith to microservices and yeah some of my friends went there as well and they said yeah I like the talk too and what I noticed is that he uses a lot of DDD Concepts and I didn't know what he was talking about DDD what's that well it stands for the main driven design still no clue for me but it was something that I was interested in I like that talk so much so why I thought I should invest in it and look what it meant well at the end it wasn't the only talk about domain driven design and microservices since microservices came around Domain Drive design became increasingly popular as well and that's mainly because of this book it's a book of Sam Newman building microservices which is very popular and in that book he says uh something about domain driven design and especially the bounded context and he says that the bounded context is one of the key concepts for partitioning your larger system into smaller parts so thanks Sam Newman for making DDD a more popular again and since that moment DDD became more mainstream well DDD itself the main Drive design refers to quite an old book it's from 2003 by Eric Evans almost 20 years old already but if you look at it most of the Core Concepts are still very relevant from that book so what I did is uh I bought the book and I started but um yeah it's quite a big book around 700 pages and it really wasn't an easy read very slow progress for me and I stopped halfway but later that year I had to go to a job interview and I had to make an assignment there and based on my assignment um yeah which I was very proud of I thought my code was very clean and well written a technical coach asked me questions like do you know something about tell don't ask and what is an anemic domain model and how do you split up a bigger system into smaller parts well I had some questions but not all the right ones and although I like my code the technical coach said to me you might want to dive into domain driven design and I was like damn again somebody who says the main Drive designed to me and so it gave me some extra determination to pick up the book again and this time I finished it it really has lots of wisdoms in it but because it was so new for me the information didn't stick so my advice for people new to domain driven design is to take another path and I think Alberto brandolini the guy from event storming um had the same ID he wrote a blog post domain driven design in 2020 and in that blog post he wrote what the the core of the main driven design is and people new to the main driven design had like a starting point to see okay this is what the main driven design is about and you can see it as an approach to software development with some aspects and one of them is focus on learning so it's very important um Alberto says even the most important the bottleneck is not writing the code but understanding what the problem is you're trying to solve and solving that so learning what we are trying to solve and you need the business for that you need to do that together another important part is language language is very important and especially a shared language between business and developer so that you can collaborate and talk on the same level together so that you understand each other another thing is that multiple models are key for not evolving into a big ball of mud this is about the bounded context and I will touch upon this later but the idea is that you can't solve anything with one big model but for specific problems you need specific models another one is that good coding practices are expected and this is very much linked to the focus on learning because if you learn new things and you want to make that feasible in your code then you have to have for instance good test coverage to be able to change that code your code should be structured in a way that is easy to change so that the things you learn can change and that you can make that reality in your code and the last part is know what your core domain is not all problems are equal some problems are more important and should be invested more time in than some other details all right so if I have to do it all over again The Learning Journey of the of DDD I would start with maybe this blog post and if I want to read a book I would start with implementing the main driven design or the Penance principles and practices book before I go into the blue book where also a lot of wisdom is but not if you read it the first time it's probably uh too much for me it at least was too much and if you're not a person who likes to read books there's also a free book on lean Pub it's all only 25 pages and mostly pictures and visuals it's called the anatomy of domain-driven design which yeah gives a quite a few on what domain-driven design is all right so now we have a global ID about what domain driven design is I will take you with me on my journey how domain driven design made my code cleaner but before we do that let me introduce myself who am I my name is Paul Van Der schlot I'm from Rotterdam in the Netherlands I'm a freelance software engineer and I'm a big fan of practices like DDD and collaborative modeling all right let's talk about the ubiquitous language first what often happens is when developers and domain experts are talking together here on the right the domain expert and on the left the developer is that the domain expert says something hey I want to do something with this cargo and what happens in the mind of the developer is a translation oh with cargo he should probably mean shipment in our code base all around our code base is the word shipment so I think that's the same thing and you see that if that language isn't aligned you always have to have some extra cognitive load in your head to do the translation and it's also a starting point for big misunderstandings and above that um yeah you're not able to fully collaborate with the domain experts if your mental model is different so in the ideal situation it would be that you're talking about the same thing and the solution that DDD provides is the ubiquitous language a language that is the same everywhere so that language resides in your code base in your communication with domain experts or within your scrum team in your user stories or your test scenarios and this language is unique and specific for a domain ubiquitous means everywhere so everywhere it is the same thing and the key part here is specific for a domain because a word can't mean one thing always but inside a domain it can so an example here is a product if you have e-commerce in the catalog domain a product is mainly about something that you can buy maybe a picture of a description of what is displayed but if you talk about the shipping domain a probability is probably something with a weight and a size and has to be delivered somewhere so there are way different attributes than in the catalog so the product means only one thing in the catalog domain and always the same but if you are talking about a different domain it means something different so this is where you want to get that the domain expert talks about something has a model in their mind and the same model is represented in the code base and that's also what domain driven design mentions tackling complexity in the heart of software that's also the subtitle of the Blue Book and what this means is that the most important part the complexity is in the heart of software in the domain and that is where you want to tackle it and you want to focus all your attention on the domain and not on all the technical details but that's that's not always how it is in the code base often our code is cluttered so we don't only have the domain model there but also references to a database where we get some data Maybe rest calls or monitoring these are all things that are inside our code base and clutter our understanding of the domain model and what we ideally want to achieve is that domain logic will be matching with the business problem only and not the adapted technical details the brown parts are moved away to the outside of the domain logic so that we are thinking about the most simplest thing and have as little as possible accidental complexity in our domain model well a way to achieve that is by using a hexagonal architecture so here you have the business Logic the important stuff in the center and all the details around it so on the left you have the driving adapters things that need your business logic as an API or a command line interface they call your business logic with all your uh important stuff and then the business logic uses other details like a database or a message queue or maybe it has to fetch some other data via rest um and those are the driven adapters and if you want your business logic to not be dependent on a database or a rest call the trick that is used in hexagonal architecture is the ports and adapters it's the dependency inversion principle so the business logic has an output Port an interface that is defined and that interface is implemented by one of the adapters on the right side and in that way the database for instance is dependent on the business logic and not the other way around and what you achieve by that is that your business logic will only evolve because of improved understanding or change of business needs but your business logic won't change when some technical detail changes that should not impact your business logic I'll show you an example to make this more explicit so here where we don't use an hexagonal architecture you have a guard surface where some cards are activated first we get some card details via rest then we get some cards from a database called DB entities and then we activate the cards and when we activate the cards we probably have to do some validation of the data we have gotten from external parties we might have to do some transformation to have one view on the whole maybe some null checks of the external data and then at least the business logic and we can save the data and you can see this is not like the picture I showed before this is not only the business logic we want to talk about this is full of details so how would this look like if we get this out of our code well then on the right side we would activate cards and the trick here is that we introduce a domain object card our definition of what a card is and we find all those guards via the card repository activate them do some business logic and save them this is very straightforward this is like something the business could understand but how did we get here well the trick here is to introduce a board an interface a definition in terms of the main objects on how we can get these cards and how we can save these cards and all the details are put in the adapter that implement this port so for instance we can introduce a card repository so implementation of this port and in there is the validation the null checks the transformation all the nasty stuff so that we can get the domain object that is most important inside the card surface via the Repository so here on purpose you put everything that is not related to the business logic towards the outside towards the adapter so I talked about the hexagonal architecture as a way to get your details towards the outside we've talked about ubiquitous language to reach a shared understanding but now what we have a shared understanding how do we get that into the code well a famous phrase from the domain different design is make the implicit explicit so we're going to do that and one thing that's not that explicit is strings everywhere it's also called stringly typed instead of strongly typed and this is also related to primitive obsession so if you want to move Beyond this you can use things like value objects to make it more explicit well what is a value object the definition of a value object is an immutable type that is distinguishable only by the state of its properties so for example height or an account number and the trick is that we use these value objects to create new types um to make our code more explicit well this might still sound a bit fake so we're getting to an example and if you want more examples I would highly recommend the talk of Denmark Johnson the power of value this is a talk where Denberg Johnson refactors a code base with the use of value objects to make everything more clear and explicit but the same thing applies to this example if we have a check-in method where we have as an input a room number which is an integer we might want to validate if that room number is positive we want to determine the floor based on that integer and do some checking logic and in determine the floor we have to validate again if it is positive because that method can also be called from somewhere else so we do the validation again and what where we can get to if we use value objects is that we introduce new Concepts apparently there's a concept like room number so we can make the object room number and if you ask the room number to get the floor and do the check-in logic everything is really straightforward now so what did I do what happened first the validation of the value objects can be put inside the value object so a room number is implicitly valid all the time it's always a positive number we can also limit operations to useful ones so if it was an integer you could add two room numbers and maybe get a new room number well that's really strange so um now you can't do that anymore now it's put in a container and another one is that you can place your relevant logic inside the domain object so the method get floor now has a home it can reside into the room number and doesn't have to be a separate method anymore and on the last part what I see is that value objects become a center of gravity for business logic so business logic can reside close to the data it belongs to inside the value object and if it is about complex business logic it's even better because value objects are immutable and therefore easy to test so all your different complex path can be easily tested if they are abstracted away inside a concept inside the value object all right now on ways to avoiding duplication so if you see some email validation in this example duplicate it around the code base um so here you see some complex pattern matching to see if the email is valid there are multiple ways to solve this and one of the ways all also the things I did early in my career was introduce a utility class like an email utility that matches a pattern and some downside to that are that you have to call that utility class always when you need to validate and the other one is that is also not forcing you you need to know that utility exists and a bigger problem is that if you don't know where that utility resides and you can't find it you might think oh let's introduce a utility clause for that and then you have two methods that are there and in the worst case they also do different validations um and later on in the code you also don't know if your email is validated already because you still get a string as a parameter so I would advise on introducing value objects and in that case you would create a new concept email which embeds the string of the email address and now you have the security that's everywhere where you have this email object you have a validated email address because it's implicitly valid also if you use this as a parameter it is uh type save and you know for sure that's only a validated email address can be used and it has explicit domain domain meaning so with the introduction of those names you get uh yeah a larger ubiquitous language in your code base so my advice would be if you want to go from stringly typed and primitive accessions towards more domain Primitives with the use of value objects just start talking with you with your team and your domain experts and your product owners and introduce ubiquitous language just start somewhere with some common ground and make your code more expressive and how you can do that is when you learn new Concepts just start and introduce them into your code and if you keep doing that and doing that at some point your current understanding of the problem and the solution you build for that problem will be reflected in the code all those types will be in your code base and it's even better at if you have at some point also um yeah the enlightenment that you see oh we have to change this code it really doesn't work like that anymore and then you verify with the business okay we changed our model we changed our code is this also how you look at the model and maybe you should change your perception of our shared model as well so that we have common ground again and of course this is an iterative process so uh you're never done with this uh this stuff all right so now we've talked about the value objects the domain objects that can be used as building blocks to create a domain model and now I'm gonna talk for a moment about what should be inside that building block and what should be outside and one of the things that I use as a guidance is the tell don't ask principle and this is an important concept that helps you with staying close to the ubiquitous language but has another benefit that it helps you with having decreased coupling so what is Talent ask the idea behind it is that you tell an object what to do instead of asking for the internal data to do it yourself and this action invites you to add Behavior into the object that the data belongs to okay let's get to an example because this this might be still a bit fake all right so if you have a snippet of code here when you where you want to know if a card can be activated well if you do a lot of asking like card give me your account so I can check for you if the account is blocked card give me your owner so I can check for you if he exists and if he is trustworthy and if that's all the case I decide if this card can be activated or not but when you look close to this you see that all the asking is from data inside the cart why would we ask the guards all that those stuff that we aren't interested in we are interested in if the cards can be activated so instead instead of getting the data out of the object let the data make the decision itself so you can say card can you be activated and all the details are inside the card that's the principle of tell don't ask and what you get then is that you put the knowledge close to the data a related concept is a phrase that Alan Holub once mentioned Getters and Setters are evil and I will elaborate on this because it's not black and white but in this example you can see a lot of setting on the left so we set a short type and a dose on the nurse and a nurse on the patient sorry and you already can see yeah this is not what it looks like in reality this is not ubiquitous language we don't set a nurse on a patient while on the right you get a vaccine and you administer a flu vaccine to work through to a patient that's more like reality so you see that setting is almost always not like the ubiquitous language there are better words in the ubiquitous language that can Define what you are doing there another problem here is that that you're not explicit about the combinations because the combination of these Setters have a meaning but what if I only set the short type and the nurse and I forget to set the dose yeah that's the start of a lot of big problems um so that's one of the reasons why uh SATA should be avoided the one on Getters is similar to the the example I already gave for the tell don't ask a lot of getting information while you actually don't need that information so my advice on Getters and Setters is uh yeah threat cautiously for Setters I haven't seen a good example yet so I would avoid them and uh name things like business actions for Getters I always ask myself the question do I really need this data outside this object or am I actually interested in something else should I be telling someone some object to do something instead of asking all that information so I would advise don't Auto generate your Getters and Setters when you create a new object but think twice before you introduce them all right this was the part on language so now we'll move on to Supple design what is Supple design well the meaning of supple is the opposite of stiff so it's flexible it's fluid you can say and the idea behind that is that it is easy to change and your code should be as Supple as well that's related to the focus on learning of course because if you learn new Concepts you want your code to be flexible to move with your new learnings so if you unders suddenly think that something else should be better as a solution you want to be able to change that your view on the problem changes so your code base might have to change as well and some important parts of supple design everything comes down to being Loosely coupled and highly cohesive at the end and to help you to get there because Loosely coupled and highly cohesive are kind of fake terms dependent there are some heuristics and patterns Into the Blue Book that can help you to get to support design so I will talk about two of those patterns but first I will talk for a moment on coupling and cohesion so what is coupling and cohesion I like to think about it as coupling is tying things together on purpose so that's an activity while cohesion are things that belong together by itself they stick together so on coupling first tying things together well coupling has to do with change so if you couple things together that means that you can see it as a function of a b and change so if something around a changes B has to change as well for the total correctness of the system in that case A and B are coupled so there's a relation between a and b and you can see that on different levels so you can see it on amount if you see those blue circles as a class or a micro surfaces then you can see okay there are a lot of dependencies so on the left obviously there's tight coupling while on the right where it's more structured and less lines it's more loose coupling but you can also see coupling as a degree of coupling so the number of lines between the blue circles you can also see it as the chattiness between two components so here on the left you have a billing service that asks the item for the gross price and ask the items for the test tax rate and at the end Returns the computed net price so there is a lot of coupling well on the right where you have more loose coupling you just tell the ask him tell the sorry you tell the item compute the net price for me and you also see that the tell don't ask principle we earlier talked about is helping you with uh getting a lower degree of coupling now on to cohesion cohesion sticking together so the idea behind cohesion is that if one thing changes everything has to change well that might sound a bit strange you might think okay everything has to train it has to change isn't that bad but if you think about it what's the alternative if you have a cohesive clause and everything has to change that means that all the related stuff are closely together so if you make a change all the things that are touched are very close and the change is easy well if you and that's great in this quote if you attempt to divide a cohesive class that would only result in increased coupling and decreased readability so you if you have to change something in that case then you have to follow multiple classes around the code base to get one change done so actually if you follow cohesion change is easier because it's all located in one place and if you think about it like that you immediately see that cohesion has a lot to do with terms like single responsibility principle and separation of concerns so on the left the high cohesion has really one responsibility while on the right you see three groups of linked items you could argue that maybe inside that class there are three responsibilities and this class should be split up in three parts all right so now summary on the coupling and the cohesion what's the effect on software if you follow the low coupling and high cohesion part your testability will increase because you have single person single purpose and less dependencies also your maintainability will increase and the impact of your changes will decrease because your changes are located at one place and not scattered all around your code base and your reusability increases because you define units with a single purpose and that's also related to the value objects I talked before you define units with meaning okay so this was the the side step to the coupling and cohesion now black back to the Blue Book so there are some heuristics and patterns in there I'm gonna talk about two intention revealing interfaces and side effect free functions and here you can already see that there are some Concepts that are not new probably it's also an old book so intention revealing interfaces the idea behind that is that if a method's name isn't clear you have to look inside the method to understand what it does and you can go all the way down the rabbit hole because if there something isn't clear you have to go inside that method and inside that method to understand what is really happening here so the idea is that you have intention revealing interfaces and what will help you is if you group things together that belong together so think about cohesion then things are probably easier to name and take your time to name things very well so an example here could be a chef that's preparing a string well this might be too fake for you to uh yeah to understand what is happening here so you might want to look into that method well if the chef is making a dish and this is a concept that is known inside your code base you probably know what is happening here and you might not have the urge to look inside the method what is happening and an advice that I can give here as well is let your let you guide by the ubiquitous language so maybe the business experts already have a name for this oh this concept that I'm thinking about a chef he's doing something with a dish what is he doing and then you again have a shared language together I was making a dish that's what we call it okay all right the other one side effect free functions well this is similar to Pure functions if you're from functional programming so the idea here is if that you have some methods um here the calculate price details and what happens here is you create some price details you add them to the total order price and you return those priorities price details well it's this side effect free now you're probably very easily see that this is not side effect free every time that you calculate the price details the collection of total order price is extended so you can't freely calculate the price twice that has side effects also there's a site course the tax rate if the tax rate that is present there is changed in some manner then you also get another output so if you put this in a diagram um you ideally only want the the green part inputs arguments in return value out straightforward nothing else happens but what we saw here was some side causes and side effects and this is really the cause of a lot of bugs and problems so yeah I think you should write pure functions wherever possible and yeah try to remove side effects from uh from your code base because they can lead to uh yeah very unexpected Behavior but you can't remove all the side effects right some side effects have to happen so side effects can't be prevented at all there are always things that you have to do like updating a database at some moment maybe sending a message or calling a web service so what to do then if you think about it those are things that often happen at the edge of your system so if you think about hexagonal again most of these side effects happen on the on the outside and in your business logic you can have a lot of pure functions and purely functional clear code where you don't have side effects and there's a very interesting uh thing from functional programming called functional core imperative shell that can help you with getting your function your business logic more functional and moist more side effect free so the idea behind this is this the whole circle is the center is your um your business logic actually so without the details and in your business Logic the majority can be functional core can be purely functional code and on the outside you will have an imperative shell with some side effects but because this is so a small amount of code what happens here is that this code is very straightforward and very easy to test and all the complexity can be put inside the functional core which is really easy testable because it's purely functional so if you're interested in this look it up on Google it's really a cool concept if you uh want to get your code more functional and of course just like the hexagonal architecture this is the direction of dependencies so the shell is dependent on the core and the core not on the shell all right this was the support design so now I'll talk about the bandwidth context and to talk about the balance context I will use a story to elaborate a bit so there once wasn't software where there once was some software for an I.T consultancy company and inside that software they use one big model for the whole business so one canonical data model but yeah One does not simply use one giant model so what happened to this uh this group a bug appeared and not just some bug the no pointer exception happened um yeah and if you track back what happened here is that the cost of this Buck was that different groups had different views on that canonical model so there was one employee class in that model and it consists of a lot of different things it has some projects and rates but it also was an i-ben and an address on that employee and completed trainings and what happened was that the rate of an employee was no during the calculation of end of Year's bonuses so an employee had a rate of null when working as a consultant if you look more closely there are different groups that have a view on that employee sales was mostly interested about the projects and the rates and the seniority of the employee Finance was more interested in the address and the i-band to be able to pay the salary Etc and because it was all the employee Finance thought hey I'm calculating uh end of Year's bonuses let's use the rate of the employee to calculate the end of Year's bonuses but what turns out is that not every employee had a rate so if you think about a CEO or the accountant who doesn't work as a consultant he didn't have a rate and you see that it becomes quite complex if you have one big model because your hat has to think about all the aspects of the whole business and all the cases where it can be nil or can't we know so what they noticed was that they had different problems that they were solving but they used one model and they actually needed multiple well the solution that domain driven design provides is the Bandit context and the bounded context is actually a boundary within a domain where a particular domain model applies it is language driven so the language inside a bounded context is unique and you can use it as a natural way to split up your bigger model into smaller parts and in that way your model will be strictly consistent within that boundary and you don't have to be distracted with anything on the outside so if you think for instance on people management people management only need for employee probably an employee ID completed trainings and ambitions and they don't need any information about i-bans or rates or projects and in that case for people management the solution they make becomes way cleaner and way simpler than if they had to think about the whole employee and in this example HR doesn't even have an employee they have a candidates that might become an employee all right so this was the theory what does that mean for my code well the company noticed that there was some bounded context principle so they tried to split it up in a finance a people management and a sales context but when splitting up they noticed there was some shared code for instance the employee so they created a shared package that all these parts used um but what now happens is that every part is dependent on the shared package shared package and now these are Java packages but they can also be microservices for instance with a shared library or shared service and this is very natural for developers to think oh this might be duplication otherwise so let's use a shared package so that we don't have to have duplication but the consequence of that and we don't realize that always always is that you create quite some coupling between the sales context people management and the finance context because you have a shared part and in this case employee and employee repository so you probably also have a shared database together and if you think about this you come to the realization that try and don't repeat yourself and coupling a cross-bounded contexts are in battle with each other you can't have you can't have both it's like like you have to take a decision which one is more important it's a trade-off and what I noticed is that dry is very important inside your bounded context so inside a certain solution that you build for a problem you want no duplication and you want to be very straight in um in having one single sort of Truth but if you go across bounded context the reduced coupling is probably more important and I will elaborate why so if you have more reduced coupling um you're autonomous in your ballot context and you're able to evolve alone so if you think for instance with the completed trainings with the uh that I noticed and the ambitions if you want to do something with that employee and with the data structure you don't have to talk with all the other parts of the company that use the same employee you're just free to make your own decisions based on your own problem and another part is that you have decreased cognitive load so you only have to think about your own bounded context and you are not distracted by everything that's on the outside so all the other parts are not distracting you in your solution and this is especially true if your bounded context is equal to a team so if a team works on a bounded context team topologies is a very great book about team structures how do you structure your team to be decoupled and to increase your flow and also the bounded context is mentioned in there so if you're more Curious on that part how do I structure my teams to be more independent and to uh yeah reduce the coupling in my software as well it's uh take a look at that book it's it's really amazing all right so back to the software so no shared module we decided so what does happen then well some duplication at the end but you see that with ubiquitous language you can now also use some better terms so on the left we had a shared employee but on the right in the sales context you come to the realization that it isn't called an employee in sales it is a consultant in sales it is a consultant that works for other companies so um you also see that you can be more explicit in your context now now you have that duplication and you're able to evolve free of the other parts and now it's also easier to answer questions because first it was this was a very fake question and this was the cause of the bug is the CEO and employee but you now see that this question only can be answered within a context So within the finance context is the CEO and employee well of course we have to pay him otherwise he's going to do something else in the people management context maybe yeah maybe we have some Ambitions and trainings that we register for the CEO or maybe that's something we only do for Consultants and in the sales context definitely not our CEO isn't working for other companies as a consultant he is only working for us so you see that it becomes way clearer if you have the separation of context to answer these questions all right so this was what I wanted to say about bounded context now about finding those um there's a already a lot of talks in here that that mentioned this so it won't be a surprise but event storming can really help you with finding Bandit context if you describe in a big picture event storming session together with the most important people in the room what kind of events happen then you naturally will see events that are related to each other so you will see clusters of events that are related and based on that you can see bounded context emerge so if you want to know more about that there's also a book by Alberto brandolini about that and there's a lot of information online as well all right wrapping up what's next how can I write code like this well Uncle Bob has a has a great quote on this one I don't write clean code from the start I don't think anyone could and this gets the focus on the iterative process that you have you will learn more things about the problem you're working with the longer you stay on the project and the longer you stay in the domain you will have more knowledge and you will be able to do it better each time so you should not be shy of refactoring and be sure that you have great coding standards so you're able to refactor that you have a Supple design and uh just go for it and then there's also a personal advice on that part because the moment that the code works is the moments that you start investing in your career so making it work is one part but then make it clean make it better try to make it the best possible thing you could at that moment that's where you really get better as a software engineer so I would challenge you all to uh start doing that and don't think okay the test is Green Let's ship it and if you want to do more deliberate practice there's a great book on coding dojos by Emily beige which is a thing about having people together to do coding dojos to take some problem and yeah write a solution for that discuss it with each other and this is one of the ways that really can help you to get better at things like refactoring or test driven design or domain driven design so uh that would be my advice as well and now we've come to the end so uh thank you all had me done for questions if you have them feel free to connect on LinkedIn if you want to and you can't hunt me down you can also send me personal messages that's uh that's all fine and well thanks a lot for your attention and this spot [Applause] [Music]
Info
Channel: Devoxx
Views: 17,410
Rating: undefined out of 5
Keywords:
Id: 3t0tZTOGk08
Channel Id: undefined
Length: 50min 15sec (3015 seconds)
Published: Thu Oct 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.