83. Domain-Driven Design | David Felkel


Domain-Driven Design

David Felkel, who joins to talk about Domain-Driven Design, is a Munich based Salesforce developer, software engineer, scrum master. He is also on his freelancer journey.


Sponsors

FormAssembly

This episode is sponsored by FormAssembly.

22 Ways to Use FormAssembly for Remote Work Success – Learn how to streamline remote work processes with FormAssembly’s all-in-one form builder and data collection platform


Main points

  • What is Domain-Driven Design (DDD)?
  • Ubiqitous language and its natural synergy with Salesforce
  • Technical DDD in Salesforce – how is it limited?
  • DDD and Apex – what can be used in Salesforce?
  • How to learn DDD

Links

David’s LinkedIn


Video Teaser

The YouTube Video URL


Contact Me

If you enjoy this podcast, please reach me out to let me know your thoughts or simply say Hello. My (Xi’s) contact info:

Take care, until next time :)!

Transcript

AI-generated, unedited.

[00:00] I'd like to welcome our sponsor Form Assembly. You can find out how Form Assembly helps streamline remote work processes in the free ebook that we've linked in today's show notes. Form Assembly's all-in-one web form platform lets you create forms for just about any use case, from contact forms to donation forms, all while take advantage of useful features such as notifications, e-signatures, and more. Not only that, but you can also connect data to systems you already use. Form Assembly integrates with Salesforce, Padal, PayPal, and many other common solutions. Whatever your data collection needs are, you can be sure that Form Assembly keeps your data secure with encryption at rest and in transit on all plans, plus compliance with GDPR, CCPA, and more regulations. At the end of the day, form assembly helps you save time, money, and effort while getting the maximum benefit out of the data you collect. And I remind you, when you support our sponsors, you support the show. Hey everybody, this is Xi Xiao. This is yet a new episode of

[01:30] Salesforce Way podcast. Today I have a wonderful guest with me. He's pretty new to my podcast, and he's Munich-based. So his name is David Felkel. Hello, hello, David. I should pronounce in the German way. Hi, Xi. Thanks for giving me the opportunity to be on this podcast tonight, and I'd really loved the topic that we will be talking about: domain driven design, and why not dive right into it? Sure. Before that, would you like to quickly introduce yourself? Like what do you do usually? Yeah, my name is David Felkel, and I've been in all kind of roles in software development professionally for almost fifteen years now. And I've been a manager. I've been a software developer. I've been a team lead. I've been an offshore coordinator. I've seen a lot. I've seen a lot of companies, and I think that's where I got a lot of experience. And that's why I value, for example, domain-driven design so much. And now you are doing freelance job, right? At the moment, yeah, I'm working as a freelancer, and I will continue to do that for probably the next years, or maybe until the end of my career. We will see how that turns out. But right now, I'm quite satisfied with my position. And I heard you spend a lot of working time this year, 2020, on Salesforce. Yeah, I spent basically all of my development time 2020 on Salesforce or Salesforce related topics, and it will continue

[03:00] like that probably in the next year as well. So there will be there's no visible end to it at the moment. Welcome to the ecosystem.

[03:11] So our topic today, I want you here to coach me. is called domain driven design. Instantly reminded me another name is called the tester driven development. It's a similar name patterns, so I kind of you know compare there too. It seems to me the domain driven design is more focused on designing a solution, like architect the solution compared to. Development, which is like a coding-related stuff, is it similar to this? Well, in my opinion, it's both. On the one hand, the domain-driven design has an emphasis and is a lot about the so-called strategic design. And what does strategic design mean? It basically means that you look at the business problem you face and try to solve the business problem on a top level. And then you separate and divide and conquer the different business problems from a top level perspective. And after you have done that, after you have done your strategic design, well, you have some tools in your box. They are also sometimes called tactical design patterns, and those are really patterns, much like in the object oriented. Sense of design patterns, or you can have patterns in any language, frankly, and you can use them for implementations as well. So it covers both topics to some degree, but it is technology agnostic. So

[04:41] you mentioned you start from the strategic planning, and then shift over to technical design patterns. Like we had this design pattern book, right? It was like the correct four design patterns. Those are so called the technical design patterns. But before that, you suggest that we should have this strategic planning. What does that really mean? Of course. Well, in my opinion, a big flaw in many a software is when you have sort of a technical design, and I have witnessed this that countless times, and I really, really hate it when I see something like that. You dive into the codebase, and what you see is not what the business problem is about. Instead, you see abstractions, abstract terms. You see stuff that does not make sense if no one introduces to. And many an application suffers from this overabstraction and the leaky abstractions, and because a lot of people try to have a clever architecture, and then they find weird technical solutions to the business problem they're really trying to solve. And domain-driven design is not like that. Domain-driven design says, okay, if you develop a solution, then this solution has to be really, really close to the business domain. We are not thinking in technical terms at first. Rather, we are thinking in solutions to our business problems. We establish a

[06:11] language, a ubiquitous language that everyone understands, the techies and also the business people. And with this language, we communicate and we model our domain. And the domain is the problem we are trying to solve. And once you know what your domain is about and what the correct perspective to look at your domain is, well, then you can go and implement it. And when you implement it, you should also find those terms and the language that you established with the business in your whole application. In fact, your whole application should read like a book of the solution to your problem domain, and not like technical terms. And that's what DDD is, in my opinion, all about. It makes sense to me because usually when we start a software project in Salesforce, the technical team needs to talk with the business. But you mentioned that, in addition to the collaboration, the close collaboration, you need to have a joint language that both the business and the technical understand. Correct. I'd go even further. I'd say you cannot program a solution to a problem you don't understand. If I don't understand your business, if I don't understand your problem domain, then I cannot build an optimal solution for you. I might come up with something, but it's probably not the best solution.

[07:41] So, we software developers, in essence, we are problem solvers. And we need to look at the problem domain of our customer. We need to look at the problem our customer wants to solve. And then, once we understood the business of our customer. We have to bring our solution that we discussed with the customer in natural language terms into the software. That means we, when other developers open your code, they can see in your code. This business design in the way, right, high level. Instead of going straight into some technical jargons like HTTP call out, instead of those technical details, they should see a high level business strategy behind in the code already. Correct. They should see all the terms and discussions they had with the business people within the code in the same terms. But do you mean that a lot of projects are not done in this way? Yeah, a lot of projects are not done this way. It depends on the technology that you use. You see, because Salesforce, at some points, lends itself quite naturally to domain-driven design. The way you design objects, for example, and Salesforce is basically. Build around a core that enables business people to extend their software, and they always model close to their domain.

[09:12] So, some Salesforce tools are really well suited for this. But if you are, for example, from the Java enterprise world, I cannot tell you how many applications I have seen that have like six layers of architecture, and all of them have nothing to do with the business problem, but are purely some technical instances and over abstractions that just made the software hard to use and made it hard to write UIs for the software. And what else? And I think that domain-driven design. I think I have used it before even knew the term, because I was always a fan of being close to the business and not overly abstracting what I see and what I understand. This is what I program. So, for example. If my customer wanted to model a Scrum board, I would have a Scrum board class or a Scrum board object. I'd have a backlog item project, for example, and I wouldn't start with some technical shenanigans like, "Okay, I build some sort of Scrum element object that is generic and can do everything." And in my opinion, that's wrong. Most many programmers make that mistake that. They propose overly generic solutions to solve future would-be problems that never occur, and domain-driven design, in my opinion, is a way to counter that as well. Apart from giving clear and concise expression within the code

[10:42] to the business problem at hand, and also when you have established this language in code and with the business people. You're in a much better position to talk to the business people because you're communicating on the same level, and that's so important. Indeed, I see in a lot of cases that when developers talk with the business, it's kind of difficult because the developers use in the technical terms. Like, if we call out to external system, we say it's a HTTP call out. But business doesn't care that at all, right? They just say, "Okay, we are sending something to the external. That's it. I don't care. It's HTTP or whatever." Yeah, but the truth is, there's business meaning behind this transaction. So, what is this transaction actually doing? And that should be the name that you find in the software. For example, if you push orders from Salesforce to an SAP system, yeah. Well, then that's probably some sort of invoicing, or and well, then you you would have a method which is called like create invoice for order. And suddenly it would become clear what is the meaning behind it, and then okay, within the implementation details of this method, it would do the the HTTP callout. But that's the technical stuff the programmer is concerned with, and it's not the top level hierarchy anywhere. If I just read the method signatures, if I

[12:12] just read the interfaces, I know about the business meaning. You mentioned that for good developers like you, naturally you started already with the domain driven design, even without knowing that. And I also noticed that some good architects and good developers around me, they really know what the business wants, what the business requires, demands, and then they can easily switch between the business turn and the technology turn if needed. So I think a lot of listeners maybe you're you're kind of like underestimate the skill, but it's really really important. It makes your customer actually love you, makes their life easy. I'd say it's more important to understand the business than to be technically one hundred percent proficient. It's really better to understand the problem you are trying to solve than to be the master at technology. Like you needn't be a rockstar programmer. If you get that right, if you have your problem domain and you understand it very well, you will probably outperform the rockstar programmer and deliver better software. Okay, for the strategic planning part, I think I get the idea. And then we need to slowly shift into coding part, right? We have to translate this strategic planning into our code. Is there any technical? Patterns that you follow.

[13:43] How do you do that? Yeah, well, I think the technical patterns I follow are pretty well established, albeit not so much in the Salesforce world. Basically, I mostly do standard layer architectures. You know, I have my persistence layer, or I encapsulate my persistence somewhere. I have my business logic layer, and then I have my UI somewhere. And there's not really much to that. So within my bounded context, or within my domain or subdomain that I currently implement, basically just use. Standard software development or software engineering practices. So those are so called like separation of concerns. So you have the domain, you have different layers, right? Right. Yeah. Okay. Because I know in Salesforce, let's say the official documents rarely, really talking about these software good practices. But there are libraries like FF Lib in the past we talked about. They have this kind of separation of domain. Yeah, that's true. And Dev Flip did a good job at introducing that to Salesforce. They also have Trailheads available, and they followed the DDD route a bit. Also, in my opinion, not quite one hundred percent, because DDD in Salesforce has some hard problems that you need to overcome, and. But don't get me wrong. As I stated earlier, there's also some sort of natural synergy between Salesforce and DDD. The way you model your objects, for example, and then you

[15:13] encapsulate your validation rules basically within the object. And that's a pretty good thing, in my opinion. And when you design an object, you also have to give the object a name and the plural name, and that means you have to think about your terms, and they come directly from the business. So you're probably not as prone to overly abstracting as in other technologies, but in Apex. It's really hard because all you ever got to perform logic in a standard UI is basically a trigger, and triggers in Salesforce in Apexs make things here and there quite a bit difficult. Yeah, that's a whole another episode topic about the trick. I know it is challenging and it has all those a little bit weird rules. But yes, I totally understand. You mentioned you have your own way of doing the technical. I would say translation from the design into the code. Do you have your own library, or what things do you usually follow? Well, I have my own library. And it's basically the same as FF Lib, although it's a bit more lightweight. So FF Lib has got a ton of features that I really don't need. I don't need like field access checking. And I don't like the selector design pattern, and I also don't like the syntax of the trigger

[16:43] handlers as much. I can see why it is like that, but to me, it's just a lot of bloat code or boilerplate code that I don't want to write, and that's why I do some things differently. For example, when I write a selector, or as the DDD term would be a repository, well, I don't extend any class. I just write my class and provide accesser to the data that I want to retrieve, and give it a good name, and that's it. And then I have got what I wanted, and I didn't need to extend any interface, implement any interface, or extend any class. And you can do good stuff with that. That I don't know if FLP can really provide that. For example, in Salesforce, when you're always coding against limits, it's a good thing. For example, to have lazy accessors to data, so you fetch data only once and only when needed, and that solves a lot of query limit problems. And you can implement that very well if you roll your own repositories for your persistence layer. Or in other places, for example, you might run into API limits when you use a lot of platform events. So you could, for example, roll your own event bus. Which events are an important topic in DDD, but maybe we can come to that later. And so there are some parts I'd rather like to write myself. Obviously, not what I do. I think not

[18:13] everyone. We like it, but it's my style, and I've been effective with it so far. And I always go by the rule: if something is stupid and it works, it ain't stupid. I totally get it. You know, everybody has its own requirement and its own tolerance. Let's say somebody wanted to go to the extreme to really use existing frameworks, which is good. That somebody want to build everything by himself, and a lot of people are standing in between. Yeah, I think I have a good example for why I didn't use the AirFlip for other parts. AirFlip, for example, has a great, really great dependency injection library, but I didn't use it. Why didn't I use it? Because the dependency injection I need can basically be implemented in twenty lines of code in one class, and that's all the dependency injection I need. And Everything else is just code overload for me, so I leave it out. When I reach the point that I really need those features, I'm going to take Force DI from F A Flip, and that will be great. And it is a good library; I really like it. I have read the sources. But currently, I don't need it, and then I'd rather stick to my twenty lines of code. Yeah, indeed. Based on the context, then decide what you really want. What else are related to DDD, especially for Salesforce developers? We're writing Apex, right? So, is there any tips or experiences sharing you want to talk? Yeah, because I'm doing DDD

[19:44] currently, or I'm trying to evolve it in Salesforce. Because right now we have a big monolithic application, and I want to break it down into packages and breaking the application down. And packaging up, especially if it already exists, is a daunting task. And if you package your application and want to provide small packages that can interact with another, you have to think hard about where to draw domain boundaries, which domains to establish, and which subdomains to establish. Because each subdomain will receive its own package. When you say package, do you mean the second generation packaging? Yeah, I'm currently using second generation unlocked packages, and so far I like them quite a lot. But the packaging isn't even the hard part. It might be tedious, and some metadata might not be so nice at packaging. But for Apex and flows and the like, it works kind of well. If you and the problem is really isolating the domains, and if you don't follow a divide and conquer approach and strategic design from the beginning of your software on, then you will have a lot of trouble untangling your big ball of mud later on. So you mean in the design because you already have a kind of modules in your design, you know the clear boundary between those modules. Then you translate them each of the modules into your own package. That makes your life easy in the later phase.

[21:14] See, the problem is in your regular application. No one ever thinks about dependencies, and then when developers have no physical boundaries between modules, they will place code where it does not belong. This will work, but it will just it will just create spaghetti code, and then you have a lot of pieces of code which are interdependent and which are not clearly separated, although they serve different purposes. And then you end up with a design that's hard to untangle, and that's why I recommend for everyone who is starting out to think hard about strategic a strategic. Design and about the domains that you are working on, the problems you're working on, and how to encapsulate them into different subdomains and different problems, and solve each problem separately from another. That way, you also when when you have separated it like that, and you introduce from the beginning like physical packaging, like in unlocked packages. Then you have a physical boundary the developers are not able to cross as easily, and that will also lead to better encapsulation, better modularity, and better code in general. It's good that we somehow connecting it back to. The packaging system Salesforce like newly introduced it because DDD is cool. It's good to learn, but always I need to find a way to convince our listeners to study that. And then now I think that's a really

[22:44] good good point. Yeah, good point. Is for example where DDD also shines is what if you have this application and everybody thinks of it as a monolith, but it really isn't. And then you have multiple teams in Salesforce working on different organizations, and that's hard because in the end everything is going to be in one production instance. Say you've got like. A service cloud, and then you get a sales cloud, and the developers they are from different companies. They have to work on their subdomain separately, and afterwards integrated into one organization. And they also have dependencies between the modules. That is going to be hard. You have to like coordinate changes to core objects like the account. And if you do a trigger here, you might cause a limit exception for the other team. And such things should be isolated. And when you develop these kind of things in packages and have well defined interfaces between the packs, so like a foundation package which provides the business capabilities in the form of interfaces. That can be implemented or that can be called by the subdomains. Then you have effectively separated them physically, provided a clear, concise contract: what they can do and what they cannot do, in the form of the interfaces in your foundation package. And then they can just work with mock implementations from the other team completely

[24:14] alone on their own org, and integration will be a lot easier when it comes together to production. I see. You know, coincidentally, I recently started to look at one of our customers' code, and I realized one requirement is really to bring the the business planning into the code. It's already implemented. It's a lot of call out here and there in chained call out. So you have to call the system A, external system A, and once you get a success, then you call the system B. So all those are implemented in this technical terms. You really easily got lost. Okay, I'm doing this, but why? What is the business requirement behind? So, for these kind of projects, since it's already implemented, is there some good way for us to bring the business domain in afterwards? Well, it depends. Sometimes, if it's working, you better leave it untouched. You know, sometimes you have a chance. And for example, in my current project, we have a chance to extract some modules from the monolith, and we are going to do that because they don't have as tight as dependencies to the core module as other parts of the system have. And when you see such things. You can refactor them and put them into their own packages, and then the situation will gradually become better. But you face some challenges

[25:44] when you do that in Salesforce. So let's assume you have this monolith and you want to break it up into different packages. Now the first problem that you have is your objects. And when you put, suppose you need your objects, your domain objects as a base dependency layer for the other modules to depend upon, and then you want to package them. Into a foundation package. Now all your developers in your team have to get used to a new process. Mean because when they add a new field to a core domain object, or add a new validation rule or the like, they have to update a package. And most Salesforce developers are not used to that. And introducing that to larger teams is the challenge, not the technology in itself, in my opinion. And if you can't do that, well, then you have to live with. Like, then the best thing you can do is like at least extracting the Apex code and providing like services that update the objects for you. And those services aren't then really implemented in your package, but instead you create a core package and put interfaces into that, and. Then you fetch the interface implementation via dependency injection into your module, and your module uses the implementation. Then it has been injected to update or to perform the CRUD operations that have to be carried out. That way, you do not depend on the objects

[27:15] in your Apex. You do not have two dependencies, but it has got its own drawbacks because there are several ways to implement it. It seems you are doing a lot of cutting edge features in Salesforce already. You're touching the the package instances. You are doing you know breaking the modules, the monolithics. So we in the past we talked about these in separate episodes, and we do see the challenges for the developers. And you know it's not a a quick solution can fix all these. So it takes time. We need to learn the new stuff. We need to collaborate with Salesforce. Give them feedback to improve the packaging system as well. But yeah, we will be there. Sooner or later, yeah. If you the problem is always the customer most often does not pay for refactorings. And so many a company has to do that on their own account, and sometimes it's really not worth it. If you have the big ball of mud without hope to ever untangle it, then just leave it be. And quite a while ago, I talked with a new customer in my company. It's like they are starting a. A big project. We're considering whether we're using the package system or we're using the old way. But you know the decision is hard. So we see the pros

[28:45] and cons. But in the end, before the project kicks off, you have to make a decision—a big decision. Well, in my opinion, you should always use some form of packaging, especially if you're starting out on a new project, and be it only for the physical boundaries and to harness the power of Scratch Orgs and Salesforce DX. Because it's really powerful, especially in multi-project environments with multiple teams working on different stuff. And I wouldn't do anything else. Of course, it's not without its troubles. But all the troubles with with metadata that are not easy to package. You you have as well just in some other way when you do an org based development policy, for if something does not deploy on your package, it probably won't deploy on another org via Copado or with whatever technology flawlessly as well. So. I don't know for a good reason to not do packages. If you dive into Apex, if you do flows, if you use the the full feature set of Salesforce, and if you write a lot of code and have a lot of developers, and not only business people and consultants. Who create a few objects and program a few flows? Then you should always use packaging, in my opinion. Good point. Good point. If we switch back a bit

[30:16] to the DDD, since we're talking about the packaging already. Is that we started with strategic planning, so that we create a ubiquitous language, which both the business and the technology has no trouble to communicate one with another. Then we somehow need to translate the design into technical code. Which we use different design patterns and the separation of concerns somehow separate the code, which naturally leads to the packaging system. If you are using that, right, it gives you all this benefit of modularity is. And even scratch work. I guess you are using that. So, how do we learn DDD if people want to study the concept? Well, I think it comes with experience and just common sense. So, which things belong together? In my opinion, it can be done a lot like the single responsibility principle. A module or a domain should have like a core responsibility. Like if you are in sales. Then sales is your is your responsibility, and service cloud is not your business, and you shouldn't have any touching points with. What's it called with cases, for example, and the like? That's not your business if you are in sales and in the sales domain, and you shouldn't have any code that touches these things. And if you do, well,

[31:46] then you've messed up because now you have a dependency from sales onto your support system and. Likewise, if you are in service, you shouldn't have a dependency on sales as well. Obviously, both depend on some sort of core data, like account data and master data in general. But they shouldn't really have any hard dependencies to each other. Of course, sometimes domains need to communicate with each other, or subdomains need to communicate in some contexts, and there are ways to model that in Salesforce without violating architectural boundaries. Like, for example, the sales contact trying to update cases. Yeah, which doesn't make sense, but I've seen that often enough. What I really have seen oftentimes, for example, if you have like your foundation domain, like with all the master data, account data, and contact data, and really many domains depend on that data. Service likes to know what the name of a customer, and of course the salespeople want to know what a customer's called as well. And if you have this foundation package, and then both subdomains might be interested, for example, in changes. What happens when I change the the address of an account? And then sales might have processes to act on this, like notify the employees that they've got a new telephone number or the like, that they can. Still maintain their sales performance and service. For example, if you have to supply

[33:16] service by telephone, they might be interested in a new telephone number as well. And the question is how to communicate that to the domains, and that's really a problem in Salesforce too. Because if you go the naive route, you would do it with triggers. You would go into your account trigger and would say, if the telephone number changes, then update the case object, and then update some sort of sales object. And that's wrong because now your core domain and the trigger for account has a dependency on the case, and it has a dependency on what's it called a dependency on the opportunity, for example. And that mustn't ever be the case. Why would an account have a dependency on an opportunity? Why would an account have a dependency on a case? It's the other way round. And that's and if you implement it naively in Salesforce, then you violate one of the biggest architectural constraints that ever were in the whole architect software architecture world. Meaning, just call down, don't call up. Yeah, but would the account triggers effectively calling up? But there are solutions. So this is exactly the reason. In the past of this podcast, we talk about the principles, software principles. How do we? Like the solid principles, the dependency principles, dependency injections. So these are so called design smells and code smells. When you see that,

[34:47] you know those principles. Then you know how to fix them. So that's kind of you know something we try to advocate in our podcast, and it's good to have you here to teach us about the DDD as well. Thank you. So before we close the session, do you do you have something else you want to add? I'd like to tell everyone in the Salesforce world, especially if you're doing Apex, please read about the software architecture and about proper software design. And even if it is from other technologies, just broaden your views because I think we can bring a lot of benefit to Salesforce. If we take principles, paradigms, ideas, and inventions from other technology and incorporate them in the Salesforce world, perfect. At the moment, a lot of us are only at. Get the things right. Get the things work phase. We are not yet not to get things right phase. You know, so that's also the reason we need to learn from outside of Salesforce, indeed. Thanks a lot, David. It was great having you on the show. You're welcome. I'd love to talk another hour about that, but I guess the time is limited. She, thank you for the opportunity to be on your podcast, and I wish you all the best and have a nice evening. You are welcome. Thanks, David. Hi, I'm constantly looking for good guests. If you have any guest recommendation, please reach me out. I'll make sure

[36:17] they're joining to the show to share their knowledge. Otherwise, thanks for listening to the show. I'll see you next Thursday.

Leave a Reply