Quick takeaways
- Complexity comes from two extremes - projects fail both when they’re overcomplicated with unnecessary patterns and when they’re oversimplified for a complex domain
- Essential vs accidental complexity - essential complexity comes from the domain itself and can’t be removed, accidental complexity is created by poor implementation choices
- “Keep it simple” is lazy advice - achieving simplicity takes effort; closing your eyes to complexity just pushes it elsewhere
- Match patterns to the problem - using the same approach everywhere is a red flag; mix simple solutions for simple parts and sophisticated patterns for complex domains
- Ship fast and iterate - if you can’t deploy daily and fear making changes, something is wrong regardless of whether it’s over or under-engineered
Introduction
We discuss where complexity in software projects comes from and how to deal with it. There are two common extremes: projects that are overcomplicated because someone applied patterns they saw at a conference without understanding them deeply, and projects that started simple but became a tangled mess as they grew.
Both can be equally difficult to work with. The key insight is understanding the difference between essential complexity (inherent to your domain) and accidental complexity (created by your implementation choices). We share diagnostic signals to identify unhealthy projects and practical advice on matching your tools to the actual problem you’re solving.
Notes
- No Silver Bullet paper by Fred Brooks - discusses essential vs accidental complexity
- Domain-Driven Design (DDD) - a pattern for tackling complex domains
- Clean Architecture - another approach for managing complexity
- YAGNI (You Aren’t Gonna Need It) - principle against premature generalization
- Defensive programming - validating inputs early to prevent errors propagating
- Canary releases and rollbacks - deployment strategies that can add overhead
- Three Dots Labs blog - articles on Go patterns and architecture
- Go with the Domain ebook - free ebook about DDD in Go with 60,000+ downloads
- Wild Workouts example DDD project - complex Go project demonstrating real-world patterns
- Microservices architecture - discussed as sometimes adding unnecessary complexity
- CRUD applications - simple approach that works for some domains but not others
- The Domain Engineer training - upcoming training mentioned for early next year
Quotes
On one hand, you have someone who says we need to support 10 million users a day—this is one extreme— but on the other hand, you also have people who say, ‘just keep it simple and it will be fine’ and it sounds good. But to me, it’s one of the lazy advice. It’s easy to say to tell someone, ‘keep it simple but it’s not that easy in the end.
The complexity doesn’t go anywhere, no matter how you implement it.
If your team is unhappy working with the project. If the team brings up plan for migration or rewrite every other day, that’s a solid sign something went very wrong. You’re probably on one extreme already and it’ll be hard to get out of it.
If just keeping projects simple would be that easy, all projects would be great. But unfortunately, it’s the opposite.
So you cannot close your eyes and say that this complexity doesn’t exist. It will pop up somewhere else and it will be much more expensive to handle at the end.
Don’t be dogmatic about using any tools because it’s never ending up properly.
Timestamps
- 00:00:00 - Introduction
- 00:01:21 - Two sources of complexity
- 00:05:14 - Complex vs complicated
- 00:09:20 - Essential vs accidental complexity
- 00:14:00 - The trap of generic solutions
- 00:19:15 - Complexity doesn't disappear
- 00:23:05 - Patterns and defensive programming
- 00:26:58 - Red flags in projects
- 00:32:05 - Avoiding premature optimization
- 00:35:12 - Don't be dogmatic
- 00:37:40 - Practice and resources
Transcript
Miłosz [00:00:00]: On one hand, you have someone who says we need to support 10 million users a day—this is one extreme— but on the other hand, you also have people who say, ‘just keep it simple and it will be fine’ and it sounds good. But to me, it’s one of the lazy advice. It’s easy to say to tell someone, ‘keep it simple but it’s not that easy in the end.
Robert [00:00:18]: If just keeping projects simple would be that easy, all projects would be great. But unfortunately, it’s the opposite.
Miłosz [00:00:25]: It takes a lot of effort to have simplicity in the project.
Robert [00:00:28]: Your eyes and say that this complexity doesn’t exist, it will pop up somewhere else and it will be much more expensive to handle at the end. It’s a very important concept to understand the problem. Accidental complexity and essential complexity. Accidental complexity is created by poor implementation. If you approach the implementation of your application in an overly complicated way, so we’ll put just some patterns that are unnecessary, you will have accidental complexity. On the other hand, if your project will be, for example, this complex financial product and you will try to build as a CRUD, you’ll end up with a lot of accidental complexity there.
Miłosz [00:01:05]: Yeah, but you can reduce it if you use some patterns that play well with the domain. So you can reflect it in the code in a more natural way. Then it’s easier to work with. So the accidental complexity goes down.
Robert [00:01:21]: I’ m Robert.
Robert [00:01:21]: And I’m Miłosz.
Robert [00:01:22]: And today we’ll talk about complexity in projects and from where this complexity is coming. And from my experience, there are probably two types or two sources from where it can come. So the first one. Probably. Many of you can relate to that. It’s the situation when you are joining some project and there is some team leader or some very senior engineer. And this engineer is dictating, let’s say, some good practices and some patterns in this project.
Robert [00:01:55]: You can clearly see that those patterns are not adding a lot to this project. Actually, it’s adding a lot of unnecessary complexity. Often, this person is getting those techniques from some conference, maybe, or from some video, or maybe this person read some article. Later, this person is forcing everybody to use those patterns.
Miłosz [00:02:15]: So it’s this ivory tower architect who dictates from the top how to do things and the solutions are already invented.
Robert [00:02:26]: Yeah, so it’s often the problem. It doesn’t need to be architect because it’s sometimes maybe, again, some more senior person. But from my perspective, very often the problem in this situation is that this person doesn’t really understand those patterns very deeply.
Robert [00:02:45]: As I said earlier. This person has seen those patterns in one video or maybe one talk and knows how it looks like. So you are going to conference, there is some idea, it looks great on the paper. In practice, Well, there are a lot of complexities and it doesn’t work as simple as it was thought on the conference.
Miłosz [00:03:04]: And being an engineer on this team, maybe peer of this person, you will probably feel like this project is overengineered, right? There is too much patterns and it seems overcomplicated. It’s very difficult to get something done.
Miłosz [00:03:22]: Because there’s so much work involved.
Robert [00:03:24]: Definitely. And I think for many people, it will be the main source of complexity in projects, but maybe you have some other idea what can be another issue that can happen in projects.
Miłosz [00:03:35]: So on the other hand, I can remember other types of projects where everything seems very simple, but at some point it’s very difficult to continue development.
Miłosz [00:03:50]: Project lifetime, it’s sufficient to have some very basic patterns in place. Maybe no patterns at all.
Robert [00:03:58]: If you have small enough application, maybe you can just do only one file and sometimes it’s starting as some proof of concept or maybe side projects and because of some lack reason this is becoming pretty successful project at the end. And it’s becoming also the problem because it started to be it started as a proof of concept. And at the end, it it became a successful product.
Miłosz [00:04:22]: These are fun. You can just add new endpoints, add new database tables.
Miłosz [00:04:30]: Works fine, but then that team grows and at some point it starts to be very difficult to extend this project because you know everything is coupled together when you change something you don’t know what else is going to change and usually at this time you you might be long for some patterns actually to be used in place and I started researching some architecture, how to approach this thing. It has two extremes, right? One is overcomplicated, the other is no patterns at all and both can be equally annoying to work with, difficult to develop.
Miłosz [00:05:14]: Thank you.
Robert [00:05:14]: In this episode, we’ll cover a bit more. How to understand if your project is in the bucket of overcomplicated by using too many patterns or maybe oversimplified. So the problem that you are solving or the product that you are working with is already pretty complex and building is a crud with just frameworks. It may not work anymore. And I think it’s a very important skill that many people is missing. So I think many people are stopping on the side that, yeah, this project is very overcomplicated because we use too many patterns but it’s not only the case yeah so it’s a similar issue but Okay.
Miłosz [00:06:01]: two extremes, right? But the root cause is kind of the same. It’s using wrong tools to the wrong problem. Or you don’t know what the problem is yet and you use only what you know.
Robert [00:06:14]: Bye. It’s not only about the complexity of the project but sometimes it’s also the scalability. So we’ll also cover a bit about this today, because also you probably heard many stories like: ‘This application will have millions of users.’ At the end, we have 10 users. And it’s hard to add anything more because you prepare your application for big traffic.
Miłosz [00:06:35]: And because of that, it’s very, very complex. On one hand, you have someone who says, ‘we need to support 10 million users a day,’ which is one extreme. other hand, you also have people who say, ‘keep it simple and it will be fine and it sounds good but to me it’s one of the lazy advice.
Miłosz [00:06:55]: It’s easy to say, to tell someone, ‘keep it simple.’ But it’s not that easy in the end.
Robert [00:07:03]: If just keeping projects simple would be that easy, all projects would be great. But unfortunately, it’s the opposite. It takes a lot of effort to achieve simplicity in the project. If you’re joining a new project and you notice that this project is complex. So in this case, do you wonder if it’s complex because of some patterns that make it overly complicated? Or maybe this project has some kind of baseline complexity that made this project complex.
Miłosz [00:07:33]: I think it’s very different. Tell the difference when you just joined the project— actually. You might know that it is difficult to work with, but you might not yet know what it solves, what’s the business domain.
Miłosz [00:07:47]: So it might be not that easy to tell if it’s over-engineered or it’s just inherent domain complexity that’s not going anywhere.
Robert [00:07:58]: And I think what may be pretty useful here is distinction between complex and complicated, because I think those words are nicely encapsulating the different characteristics of this. So when we have a project that is complex, so it’s a project that has, for example, some complex domain like accounting, complex e-commerce, or is pretty old product supporting many use cases. So in this case, it’s complex, but it doesn’t need to be complicated. So, if somebody will not approach it properly, it may be complicated, but I think what’s also pretty interesting is that some projects are not complex, but they are just complicated. And in this case, it’s the scenario when, for example, this team leader went from a conference and just read some blog article, started to copy some patterns, and just unnecessarily complicated that. For the sake of it, instead of solving something.
Miłosz [00:08:53]: Exactly. Yeah, but it might be hard to tell the difference if you are not very deep into the project. I remember working with some MVPs that looked complicated on the surface. And then you start rebuilding them or trying to understand what’s going on. And you see that, okay, this is not actually technical complexity. This is how the business works. So that’s why someone did this this way.
Robert [00:09:20]: So some examples of projects that are complex, but maybe not complicated, are for some financial-related applications. So for example, some accounting systems that are supporting multiple countries and even hundreds of countries, different tax rules that can be different for multiple countries and some domain. May have some special requirements, like for example, taxi or something like that. And this kind of projects are very big. Baseline complexity. And by the way, we’re currently working actually on a training that we’ll be releasing at the beginning of the next year when we’ll be showing how to build such very similar domain actually. So you can see the description. Yeah, so check the domain engineer in Google. So you will find it. But what I think it’s pretty interesting in this kind of projects is that if you, at the first site, look on all these accounting rules and support of multiple countries, you might have a feeling that it’s super complicated, but actually depends how you approach implementation of that.
Robert [00:10:37]: So no matter what you do, in the implementation part, it will be complex because it’s just a complicated domain.
Miłosz [00:10:46]: The complexity doesn’t go anywhere, no matter how you implement it.
Robert [00:10:49]: And often this is named as essential complexity. This is the complexity that is kind of created by the domain. And the opposite of that is. Accidental complexity. So accidental complexity is complexity that is created by engineers, basically. So when you are, for example, preparing your application for global scalability, millions of users. So this is where you are creating the accidental complexity.
Miłosz [00:11:16]: Yeah. I think it comes from the No Silver Bullet paper from Fred Brooks, which shares the name of our podcast. It’s actually a good read.
Robert [00:11:24]: What a cool incident.
Miłosz [00:11:26]: Check it out. It goes into detail on essential versus accidental. But maybe we can just quickly go over it. Hmm, hmm.
Miłosz [00:11:37]: Hmm.
Robert [00:11:37]: Also, because I think it’s very important to understand that concept to understand the entire problem of accidental complexity and essential complexity. So basically, the accidental complexity is created by poor implementation. Because if you approach the implementation of your application in an overly complicated way, so you’ll put just some patterns that are unnecessary, you will have accidental complexity. But on the other hand, if your project will be, for example, this complex financial product and you will try to build as a CRUD, you’ll also end up with a lot of accidental complexity there.
Miłosz [00:12:16]: Yeah, but you can reduce it if you use some patterns that play well with the domain. So you can reflect it in the code in a more natural way. Then it’s easier to work with. So the accidental complexity goes down.
Robert [00:12:31]: Unfortunately, if you do the opposite— so if you have a complex problem to solve and you try to approach it in an oversimplified way— it will add. So we will have the base complexity, so the essential complexity, and you will have also accidental complexity. So this product probably will be a great mess that nobody would like to touch.
Miłosz [00:12:51]: And suddenly, we developers often bring this on ourselves, focusing on the technical details, trying to build a framework that will capture cases in the future, stuff like that, which all can add up to extensive complexity before you need all the features.
Robert [00:13:11]: It’s starting with a solution that is generic from day one, and it’s basically creating a solution that is generic. Always much more complicated than creating a solution for one use case. I have some examples when we’ve been adding some functionality and some teammates were proposing like, ‘Oh, let’s maybe create a library to do that.’ You will not need to do it in the future. But after trying to design that, we found that actually making it in a generic way is a couple times more complicated than just doing it in one way for one scenario. And sometimes it’s even easier to just copy some logic and have a bit different implementations if it doesn’t change that often in two places and independently.
Miłosz [00:14:00]: Because again, having this generic solution be just very expensive, yeah, so you need to be very conscious of where to use the generic solution, where to when to abstract away the details, and for for what system you need, what will approach.
Robert [00:14:18]: Let’s go back again to the problem of complex projects, because I think it’s also interesting that if you are working with these more complex projects, sometimes some people from other teams or some new joiners may look at it and think, ‘Oh, guys, you’re overcomplicated that so much. You’re using so many patterns and it’s hard to go over this code and understand how it’s working. It may look like this at the beginning when you are working with some more complicated domains. But people may sometimes miss the context here. And sometimes you may be in a rescue project, basically, that earlier failed. Because it was created as a CRUD, you are trying to save this project and implement it in a way that you can tackle this.
Robert [00:15:10]: Essential complexity. And some people looking at that later may be missing this context here.
Miłosz [00:15:22]: Overengineering. Yes. Yeah, but on the other hand, it’s also the opposite issue, right? If you oversimplify things from the beginning, it may be too late to change the architecture.
Robert [00:15:38]: And I think it’s also sometimes interesting when, for example, the team was changed and most people left this team.
Robert [00:15:47]: If it was a complex project, not overcomplicated, but the person that was trying to change it later. May have in mind that, oh, okay, it’s so overcomplicated, let’s try to rewrite it. So this person or this thing is spending like their half year or year to rewrite that to just realize at the end that basically, all the complicated or the complex, not complicated stuff is again there. Because when you start to support more and more use cases and edge cases, you’ll see that actually all those checks and all those complex parts were necessary there so yeah and they don’t go away when you change the approach.
Miłosz [00:16:31]: Even if you change the technical approach, the underlying domain complexity doesn’t disappear. All right. And. If you’re like a developer focused on simple code, if you like simple code, you might be annoyed that there’s new requirements coming in.
Miłosz [00:16:49]: I know you need to change the factor to capture it, but it’s just the reality. You need to support the business this way. And however you model it, the complexity is there. And if you try to avoid patterns at all costs and just do it simple, you may end up down the road with some weird solutions, like for example, instead of having a good transaction boundary where you need it, you start running cron . checks for consistency. In your system and report some errors, and for some teams this is like the business as usual approach. Let’s just fix it afterwards, but that’s so much— you know— with operating efforts. You are bombarded with alerts all the time.
Miłosz [00:17:52]: You need to react and fix the system.
Miłosz [00:17:57]: After the fact, instead of just designing in the first place in a way that it’s resilient and I think it doesn’t need to be.
Robert [00:18:04]: We don’t need to reuse any advanced patterns to avoid that. So sometimes it’s basically just some defensive programming. So let’s take an example when we’re building this accounting system, for example, and you are not validating if, for example, the amounts are positive or non-zero. And you can accept any value and issue thousands of invoices that have a total value of zero. And. Okay, you can later clean it up. You maybe have some chrome that will void them or do whatever with that. But basically, it will be much cheaper to do this defensive programming approach earlier and ensure that it will not propagate further. It’s not only basically about uh operating overhead from side of your team, but it may be also some financial team seeing later that, oh, no, we have thousands of invoices that we need to do something about that. And those developers again.
Miłosz [00:19:09]: Right. So you only push around the complexity this way instead of solving it.
Robert [00:19:15]: So you cannot close your eyes and say that this complexity doesn’t exist. It will pop up somewhere else and it will be much more expensive to handle at the end.
Miłosz [00:19:24]: Some analogy that comes to my mind is like if you decided you won’t have files bigger than 100 lines in your project. And you will have simple files, right? Small files. Sure, it’s great, but then you end up with thousands of them. And you push the complexity to the number of files instead of the length of the file.
Miłosz [00:19:47]: Back in the day, there was some big question: how big should be a microservice, and some people suggested metrics like this. This comes to my mind.
Miłosz [00:20:00]: Let’s build our huge application into really tiny services. So you solve this complexity of big code base, but now you deal with thousands of code bases.
Robert [00:20:15]: So basically, divide and conquer doesn’t always work with software. It can work, but you need to know basically how to split them. I think it may be also an interesting topic for some other episode because, Well, not a surprise. There are some patterns and ways how to detect that. And spoiler alert, it’s not as small service as you can because, at the end, you can just end up with big mess and some sagas that you need to orchestrate some really small part of the flow. But I think it’s enough for today.
Miłosz [00:20:51]: The problem here is you think the size of the code base is the issue, right? It’s similar to what we discussed before. The complexity is in the domain, so you can’t just change this. If you have a complex business and it needs a big application to work, this complexity will be there, however you model it. So you just need to make effort to model it in a way that’s best to reflect how it works and for teams to work with it.
Robert [00:21:20]: And I think it may be misleading sometimes, because you may feel that splitting this big problem into smaller microservices can actually make this problem simpler, easier to tackle. On the other side, sometimes you may wonder. How?
Robert [00:21:38]: Some application can have, I don’t know, 5000 of developers for running and developing such simple application. I know that it’s sometimes hard to judge an application from outside because you may not know all the complexity inside. But come on, thousands of developers— it’s a ton of people. Splitting it into hundreds of microservices can create an illusion that you just cut this problem into smaller and it’s easier. But there are cases when, basically, this application could be one service with 50 times less developers developing it.
Miłosz [00:22:17]: Maybe you won’t need a whole platform team then to manage all this complexity and communication between them.
Robert [00:22:25]: And if you add the extreme scalability requirements that are, I think, also often out of nowhere, because really, you can probably handle Twitter-like scale on a single VM. Just a reminder that you can have VMs that have one terabyte of RAM, 96 cores. On GCP, it’s even 150 cores per one machine. So come on, you can really handle Twitter scale on this one VM.
Miłosz [00:22:54]: RAM is expensive now, so I don’t want to do that.
Miłosz [00:22:58]: So coming back to the essential versus accidental complexity, what is the solution here?
Robert [00:23:05]: So I think for the case with cron. Again, some simple solutions like defensive programming and very very very very very very defensive programming. So you have any input that this not as expected, don’t accept that. Don’t allow to propagate it further. And the other thing, when you are splitting problems into smaller, also watch out to not split it too granularly. Other thing that is coming into my mind is trying to tackle this essential complexity instead of always splitting that. Because there are some patterns that are helping to tackle that. In, for example, this one service, it can be clean architecture, it can be domain-driven design. Thank you. Very important disclaimer. I’m not saying about some dogmatic clean architecture or domain-driven design because it’s very easy to go into caricature of those techniques instead of some pragmatic approach. So don’t be this person that you see in one video or one presentation or one article.
Robert [00:24:08]: Dig a bit deeper, try to understand what problems those techniques are solving, what problems they are not solving, when to not use them, and apply them in places where you have the essential complexity to not add more accidental complexity.
Robert [00:24:27]: Sounds like a plan.
Miłosz [00:24:28]: Yeah, that’s something I would recommend to consider where in the project you use what approach. If there’s one approach you use in your entire project everywhere, that’s probably an amber flag. Probably something is weird because The most projects don’t have only you know, only complex or only simple domains. There will be a mix of some very generic parts that, you know, we can use something simpler for it. And the core domain where you need your most sophisticated patterns.
Robert [00:25:06]: Definitely. And also when you are using some patterns that you read about, you’re trying to apply that. Also, if you feel that it doesn’t fit, don’t try to push it by force because probably it may not be fitting there or maybe you don’t understand something about this pattern.
Miłosz [00:25:21]: Sometimes you can look back after implementation and I remember we did it many times. Uh-huh. Uh, which created some domain layer and try to model something in it. And then we look at it and, hey, it’s like mostly boilerplate. Maybe we can just simplify it because there is nothing it gives us, no benefit.
Robert [00:25:44]: It’s basically a crud. So we just can have one struct getting it from API, put to the database and it’s fine.
Miłosz [00:25:51]: We have a mix of these parts of complex domains, complex patterns and some very simple ones. I think it’s a healthy sign of a codebase in general.
Robert [00:26:01]: So watch out for being dogmatic. So it’s.
Robert [00:26:05]: It’s coding, it’s not religion.
Robert [00:26:09]: Many people will probably disagree, but it’s reality.
Robert [00:26:13]: And I think it would be useful to maybe give you some advice from our experience.
Robert [00:26:20]: What are some, let’s name it, diagnostic signals to understand if your project may be over complicated or oversimplified? Because I think we can probably find a couple of signals that may suggest that there is something wrong with this project. Well, I think it’s pretty interesting is the fact that those signals may be the same for projects that are oversimplified and overcomplicated. So you may remember that at the beginning we said that it’s the same problem, but from another side, basically.
Robert [00:26:58]: It’s about half of the codebase in general. So what would be, from maybe your perspective, some red flags that the project is unhealthy? So it may be overcomplicated or oversimplified.
Miłosz [00:27:11]: Probably the king of all would be if you can ship the project fast and do it over time, iterate often, and maintain it— that’s a good sign. If you can’t do it, something is wrong. So it’s like a big number one rule.
Robert [00:27:33]: Some anti-examples here, maybe some old enterprises that are deploying. Every half year, for example.
Miłosz [00:27:40]: Yeah, like the other extreme. Yes. For example, you need to hand over your deployment to someone who does it during the night because it’s, I don’t know, risky.
Robert [00:27:56]: And you can also do it daily because it’s the scenario when you have an essential with accidental complexity. So it’s a very old project that has already a lot of edge cases to handle. But it’s also overcomplicated because maybe in some places it’s not planned strategically properly.
Miłosz [00:28:15]: Yeah.
Miłosz [00:28:17]: So if you can deploy daily, that’s probably one red flag. If you fear merging changes or just changing some areas of the project, because you don’t know what can happen. That’s another red flag, I would say. Whatever the reason, you should be comfortable deploying and managing stuff.
Robert [00:28:40]: So in other words, if your project is crude and you are able to merge it daily or a couple of times a day, and you are not afraid to introduce new changes, it’s totally fine. It’s probably enough. But for example, when you have some complex domain and you are not able to do that. Well, you may have some excuse that, oh, it’s so complicated. We are working with money. We cannot merge every day. But yeah, there it is. The reality is that if you tackle this accidental complexity, if you handle this essential complexity properly, you can even deploy multiple times a day application. Pretty complex and is doing some risky operations.
Miłosz [00:29:21]: Yeah, if you are working with money, I hope you just don’t just you know cross your fingers and deploy. But you are confident this will work. If you, if you’re not, then probably something is wrong. Maybe the project is oversimplified.
Robert [00:29:37]: Other red flag that I have in my mind is when you have some new joiner in your team and it’s taking weeks to onboard this person. So it’s kind of connected. Previous points because, if you aren’t able to deploy daily, you have fear of touching anything in your project. The same will also apply to new joiners and even more, because you’re a new joiner. You see that this project is complex, and/ or people warn you or don’t touch this part.
Miłosz [00:30:09]: You don’t want to see this.
Miłosz [00:30:14]: I’ve seen projects like this.
Robert [00:30:16]: Exactly, exactly. And in a healthy project, I would say that it should be quite safe to fail, basically. And it’s connected to defensive programming. Basically, and also having some good infrastructure in place that is maybe doing some Canary releases and rollbacks, but it can be also the opposite. For example, if you don’t have application with complex domain, and making mistake is not that big problem, but you have very complicated infrastructure for rollbacks, for Canary releases. It can add a lot of overhead for your deploying pipeline and, in this case, it even cannot deploy the simple application daily because the process of deployment is too heavy compared to what’s required for this application.
Miłosz [00:31:05]: Also, if your team is unhappy working with the project. If the team brings up plan for migration or rewrite every other day, that’s a solid sign something went very wrong. You’re probably on one extreme already and it’ll be hard to get out of it.
Robert [00:31:28]: I think many people may say, like, ‘projects like that don’t exist.’ I think it’s a nice excuse, but it’s not the case. Such projects exist that you can really deploy daily, even if it’s not very simple projects.
Robert [00:31:46]: So, to maybe recap.
Robert [00:31:48]: Those indicators a bit. So I think there are some questions that you may ask yourself. So the first one is asking yourself, Can you remove some stuff without fear that you’ll break everything, basically?
Robert [00:32:05]: And when you’re thinking about those red flags, remember, it’s not just because some patterns that some people use sometimes, it may be because premature optimizations, like preparing for scale that will never happen.
Miłosz [00:32:21]: Yeah, that’s a lot of accidental complexity there.
Miłosz [00:32:25]: Or focusing on performance before you need it. So instead of choosing something more explicit and easier to grasp, you choose something very optimized, but not really needed at the time.
Robert [00:32:41]: And sometimes it may be also preparation for the future—like, maybe at some point we’ll need X. Let’s do it now, so it will be easier. Unfortunately, usually it’s a trap. Usually it will never happen, or if this functionality will be needed, if we will need to add this functionality, we’ll find out that actually what we prepared earlier no longer works in this way. And we spent a lot of time on writing that and maintaining it. So, jagni.
Miłosz [00:33:10]: Yes, it’s easier to get things that are easy to remove or replace instead of looking for all the possible edge cases.
Robert [00:33:19]: Always have in mind that most of the techniques, tools, or whatever you are using, you’re using it to make your development lifecycle as efficient as you can. So, if you see that but something is making your development lifecycle worse, slower, and it’s slowing you down, you should maybe rethink if it’s needed or you’re applying it in the right way, or maybe it’s not needed at all. And at the end, you should aim to making some small incremental changes. And I know that it sounds easier than it is, it’s easier to say than do. But it’s a matter of experience and learning, learning and learning, and trying to be as close to this go to deploy multiple times a day. And also, watch out to not go into the trap that we already invested couple of months into this feature to make it super scalable. It doesn’t matter that we need to spend now weeks on maintaining that.
Robert [00:34:21]: Watch out for this trap. Don’t be afraid to remove some stuff that is slowing you down.
Robert [00:34:29]: Yes. So it’s important to be aware of that. So if you already invested a lot of time into something, it’s harder to work some framework. Some generic library trying to do everything. Some stocks. But it’s showing it similarly. Like you invested in something. Company and you see that it went down, and you are waiting years to recover. And probably just saying that and buying some better stock can help more. By the way, not investing advice.
Robert [00:35:03]: I was about to say that, yeah.
Robert [00:35:07]: And at the end, I think it’s important to emphasize one thing.
Robert [00:35:12]: Don’t be dogmatic about using any tools because it’s never ending up properly.
Robert [00:35:22]: Have an analogy of some worker that is, I don’t know, big fan of pneumatic hammer, and this person is just using pneumatic hammer everywhere. And it may work if this person is demolishing buildings, but if you need to nail nails, well, probably using nomadic armor for that. At best, you’ll hurt yourself.
Robert [00:35:44]: But in this case, it would be just more practical to use the normal hammer. But from the opposite side, maybe there is some fun in using a normal hammer. Saying that a normal hammer is great and it’s simple— it doesn’t need any other energy source. You can just use it everywhere. But it’s true. However, if you need to demolish a wall, it will take ages.
Miłosz [00:36:07]: For example, something that we mentioned in a previous episode about having a toolbox. You can choose your tools basically for the job.
Robert [00:36:16]: And even if it sounds, maybe, very obvious. From other side, we’ve met a lot of people that were like these people with simple hammer or pneumatic hammer used for everything, and even if it sounds that obvious, they were doing it in this way.
Miłosz [00:36:38]: So it helps if you ask yourself, why are you doing this? Why use this tool in the first place? If you want to solve something specific, for example, if you have a complex domain and that you want to model better, that’s probably a good reason to use something. Or if you kick off a project that you know is supposed to be a big one, you probably want to have some idea of the architecture of the design beforehand. But on the other hand, if you just kick off an MVP, you don’t need all this stuff. You can just start simple and grow.
Miłosz [00:37:23]: and yeah watch out for extremes, what we mentioned before. So if you are far on the over complicated or over simplified spectrum, the project probably will be difficult to work with.
Robert [00:37:40]: And the thing that we can probably recommend most, and we are saying it over and over, but play with technics sometimes in work, sometimes after work, also. So if you would like to be good at what you are doing, it’s it’s also good to practice this outside of work, because you’re also sometimes limited by the projects or maybe sometimes you’re limited by some dogmatic people that, for example, like oversimplified code and you cannot do much about that, but you can always experiment a bit in in the home. So one thing that we can probably recommend is checking our blog tree . tech and where we have a lot of articles that are totally free. We also created one pretty big Go project that you can play with and try to apply. Look how we applied some patterns there. And you can also try to play with this project and add some of your features there. And you can gain this muscle memory on how to use those patterns and later, when you will encounter some problem, you’ll have some tools in your toolbox and you’ll be able to experiment with that.
Miłosz [00:38:51]: So we tried to create more complex examples, so you can see the ‘why’ behind the patterns, not just some toy projects where they don’t make sense.
Robert [00:39:01]: Yeah, because if you have sometimes those dogmatic people about using some patterns, you can notice that very often they have very shallow knowledge because they’ve been reading some article. That again, are very shallow. So it’s like five minutes read. And they are thinking that they know everything about some technique after doing that, or doing it differently. So our articles are not simplifying things, but there are—pretty long, but they are long enough to prepare you for applying some patterns in the wild. There are some good articles out there. It’s not like only our articles are good, but very often there are some articles that are very, very shallow. And when you look on them, you can just see that applying what’s suggested there will introduce more troubles and this accidental complexity without solving any problem actually. So we would have your base complexity with accidental complexity, and at the end it will be how to work with.
Miłosz [00:40:01]: So we also have the Go with the Domain ebook about working with domain-driven design in Go. And it shows refactoring of a bigger codebase.
Miłosz [00:40:14]: This is not a toy project, but more like a real-world scenario.
Robert [00:40:19]: And it’s, I think, already pretty popular. So last time when I was checking it, it had over 60,000 downloads. And we also received a lot of emails from people that it helped them a lot in the project. So for some people, it’s quite useful.
Robert [00:40:34]: Check it out. It’s also free by the way, so just google go with the domain and I’m sure you will find that Cool. So I think that will be all for today. So thank you Miłosz. Thank you Robert. See you next time. That’s it.


