When it’s worth to write low-quality code

Banner image
YouTube
Watch on YouTube
YouTube
Listen on Spotify
Coming Soon!
YouTube
Listen on Apple Podcasts
Coming Soon!

Quick Takeaways

  • High-quality code is mainly about keeping good iteration speed over time - can you add features without breaking what works?
  • Not all code needs to be high quality - focus your efforts on the code that’s most important, changes often, or creates the most value.
  • The right time to refactor is after you know your product has value, but before technical debt gets too big - make small improvements bit by bit.
  • Architecture decisions need more thought than other code quality factors since they’re hardest to change later - ask “how hard would this be to remove?”
  • Balance between MVP and quality depends on your situation - for experiments, cut corners on purpose; for critical systems or enterprise products, focus on quality from the start.

Introduction

In the first episode of No Silver Bullet live podcast, we talk about the balance between writing high-quality code and taking shortcuts.

Based on nearly 20 years of working together on various projects, we discuss when it makes sense to move fast rather than aim for perfect code, and how to avoid technical debt that can kill your project.

We focus on making mindful engineering decisions instead of blindly following rules like “always do X” or “never do Y”. Different situations need different approaches to code quality.

Notes

  • “No Silver Bullet”: The classic 1986 paper by Fred Brooks that our podcast name references, discussing how there’s no single development that will solve all software engineering challenges.
  • Our Learning Platform: The project we discussed that started as an MVP and was later refactored
  • Architecture Patterns:
    • Clean / Hexagonal Architecture (we’ll cover in more depth in a future episode)
    • Domain-Driven Design (DDD)
  • Pareto Principle: The 80/20 rule we mentioned - often 20% of the code creates 80% of the value
  • Future Episodes:
    • Why you shouldn’t use frameworks in Go
    • Is Clean Architecture Overengineering?
  • Development Practices:
    • Mob Programming - team programming approach for handling complex refactoring
    • Time-boxing - setting specific time limits for refactoring efforts

Quotes

Quality is not about some kind of elegance of code because it’s just an artificial thing. It’s not really helpful for your team if it’s pretty.

Miłosz

Often you have in the code places that you don’t touch often or it’s not earning a lot of money… Ask what are the places that we’re changing the most often? What are the places that are creating most of the value?

Robert

I remember one project when we started applying Domain-Driven Design… Everyone loved it in the team… But what I also remember is that it had no paying users and we had to shut it down.

Miłosz

If you did your dirty POC, don’t miss the time when you should clean it up, because it’s easy to go into a spot where it’s no longer possible to do that.

Robert

After working with [legacy systems] for long enough, you might think, ‘I’ve had enough of this, I won’t allow my next project to rot like this one.’ It sounds like a good idea, but it can also be a trap.

Miłosz

Sometimes it can be even the opposite. Having everything super consistent can actually be worse than having inconsistent things, because keeping this consistency requires effort… Sometimes it requires you to use an approach that is not optimal just because ‘we’re doing it consistently.’

Robert

A useful mental model here is to care about the useful product first, not the technical design, which of course is important, but I think it’s easy to overvalue it.

Miłosz

Try to find some places where you can do refactoring in one week… Often you don’t need to rewrite an entire service. You can just do some refactoring in the code and iterate on that.

Robert

Timestamps

Transcript

Miłosz [00:03]: Hello everyone! Today we talk about writing low-quality code. So most often you want to build high quality software, which makes sense, but sometimes you do not. Sometimes good enough is better than perfect. But when does it make sense? And how to avoid technical debt killing your project? I am Miłosz.

Robert [00:27]: And I’m Robert. And this is No Silver Bullet Life podcast where we discuss mindful backend engineering. We spent together with Miłosz almost 20 years working together in multiple teams and multiple projects. And during that time we learned that following advice like “always do X” or “never do Y” is not the best idea. It can limit your growth or lead your projects to failure. In this show, we’ll share multiple perspectives that will help you to make smart choices that we believe may help you to be promoted to senior or principal engineer earlier.

Miłosz [01:04]: We want to make it interactive. So if you have any questions, drop them in the chat. We will answer them at the end. We plan a Q&A session. Or if you have any comments about what we are currently talking about, we might pick them up early during the conversation.

Robert [01:22]: Exactly, but I think it would make sense to start with the question what the code quality is and why it matters. Because this is not something that we are often thinking of. I mean, many people are trying to implement a high quality code, but without really thinking why they are doing that. And what does it mean that it’s high quality and what it gives to that person? So what do you think Miłosz about that?

Miłosz [01:46]: I guess it has many, many layers, probably a long topic in itself. But at a very basic level, I think you can think of the software quality as, you know, the few bugs it has, and this software does its job well. But I think for today that’s not that interesting topic because everyone understands that probably. For me what’s more interesting is the codebase quality, let’s say. And the best indicator for me of it is the iteration speed. So how fast can you add features to your product or just develop your product and while not breaking what it already does well. And what’s probably important is you do it over time. So it’s not for a short project, but over months or years. As the team grows and as the product changes, you are able to keep working with a good pace. I guess in other words, you are not afraid to change code. You can always come back to it and add something new or modify it. So yeah, I would summarize it as iteration speed combined with developer experience. And I guess they often go together well, which doesn’t mean the business is successful because of them yet. But often if you have a team that likes working with a software, it usually indicates that the project is doing well, at least in terms of how fast it is developed. What do you think?

Robert [03:47]: Yes, I think you are right. And well, what can I add more?

Miłosz [03:52]: It’s a good question why it matters at all. But I guess code quality is something, you know, a topic that exists as long as software itself. And, you know, we have many books and papers from decades ago. People were already thinking about this topic. And for me, I come back to it every time I talk with some friends who recently changed jobs. And they usually tell me something like, you know, it’s okay, but I didn’t realize the codebase can be that bad.

Robert [04:31]: But I think it’s quite funny in disguise because you can have signals like that. It’s hard to work with that. But for other side, you can see in the age of AI, let’s say, many people that are you see that they can iterate with code pretty quickly. Just use AI to build stuff. And well, quality is not best in this case, but in some cases they are taking money, making a lot of money. So it can probably indicate that it’s probably not that simple. And there is probably some hidden complexity there.

Miłosz [04:59]: And I wonder how it will change. I guess no one knows at the moment how AI will change this. When I work with, you know, like code generating tools, I mean, AI generating tools right now for code, it’s often, you know, there are like two extremes. I’m either super impressed by how well it does or it produces some garbage. And if I didn’t know what it’s doing, I would be lost probably in the generated code.

Robert [05:33]: I think we can argue if AI can improve and maybe handle this code better. Let’s see. So obviously large language models have many limitations. Probably many of them can be overcome. But yeah, it’s probably let’s see. It’s probably I would not probably say anything, but it will be like that because I know that it’s easy to say that, yeah, it will be solved. AI will be better, but I think it’s not that simple. And all this old knowledge that you mentioned that from old papers, old books, I think it’s quite funny that sometimes those papers, books have 40, 50 years old even. And, you know, they are still pretty relevant. A lot of people forgot about that, about them. But I think they have a very good point. By the way, fun fact, you can probably check from where our live podcast name is coming from.

Miłosz [06:26]: I guess we can summarize it as we still have quality issues as an industry and probably will be even more important topic now. So yeah, I wonder what are some, you know, traits of a healthy codebase. Do you have something that you can, some ways in which you can describe a healthy codebase?

Robert [07:00]: Yes. I think all of that will be connected to what you said earlier, that it should have a goal of supporting faster iteration. So the first thing that is coming to my mind are tests, obviously. So if you have tests, you are able to, you have tests and they are pretty fast, you are able to iterate on things pretty fast, because one thing is that you are not afraid that you will break anything that somebody or you did earlier, and if they are fast, you’re iterating quickly. So this is important thing. The second thing that is also quite important is modularity. And it’s especially important when your team is bigger than just you or just five people, maybe just ten people. Because in this case, when you have much bigger team, having good modularity helps you to change things independently. So I think it’s pretty important to consider this in the high code quality. And the third thing is that how easy it is to understand your code? Because you can have a lot of tests. You can have multiple people working on this codebase, but if it’s taking ages to understand how something works and nobody really knows how something works, it’s also very hard to work, to implement something, because you don’t know what you should touch. And it’s taking really, really long time to changing logic there.

Miłosz [08:27]: Yeah, that makes sense. And probably all this is automated, so you don’t waste time running in circles during development. So it also kind of sounds like developer experience to me.

Robert [08:44]: Yeah, definitely.

Miłosz [08:45]: It’s rather developer experience-related than product-related.

Robert [08:51]: From other side. I have some impression that often developer experience is really about infrastructure. So you know, DevOps and all this stuff. And obviously it’s important. It’s supporting all those things, but I think it’s not the most important thing. I mean, you can have great CI so it will help you to run your tests. But if your tests are bad, the best CI in the world will not help you. If your modularization is bad and you know having the best Kubernetes cluster in the world will not help you because even it can, I think, make things worse. Because changing one thing will require changes in ten microservices for example. So this is opposite of.

Miłosz [09:30]: Yeah, like like we’ve seen in real life.

Robert [09:33]: Yep, yep.

Miłosz [09:34]: The platform can be great but it doesn’t matter. It doesn’t help if you don’t have those more basic pieces in order. For me, it’s also easier to define what isn’t high-quality code. And I come back to times where we started programming a long time ago, and we didn’t know many patterns back then, but somehow I still knew there is a code I like working with and code I don’t like working with. And later I realized it basically boils down to I like working with the code I wrote recently, because I have all this context in my mind, it’s easier to think about it. And I think it’s also a common trap that when you enter a new codebase, you might assume it’s low quality, because maybe it follows some other patterns that you know and you have no mental model of it yet, you don’t know where to find what. And that’s why, you know, it’s like, it often happens that a new joiner in the team recommends overhauling everything because it’s weird or confusing. So that’s and it’s also about our own code for sure. Like, I’m sure you remember, like thinking what an idiot wrote this. And then of course it’s…

Robert [11:12]: Git blame: Miłosz

Miłosz [11:14]: Yeah, of course it was you or me. But this is pretty much the same thing for me. So you forget the codebase over time and you don’t remember it, but it doesn’t matter it’s low quality. It’s just hard to work with for now because you don’t have this context yet. And similarly, quality is not about some kind of elegance of code because it’s just it’s an artificial thing. It’s not really helpful for your team if it’s, let’s say, pretty.

Robert [11:54]: And I think it’s also hard to measure impact of that. I mean, if you think that your code is elegant, so how you see how it affects any of positive stuff that you mentioned earlier. So yeah, definitely, this is a trap. And it also reminds me that some people like some kind of consistency in the code. So it’s actually kind of quite close to that, that people like to have everything consistent in the code. And I would say that it can be even opposite. So having everything super consistent can actually be worse than having inconsistent things, because keeping this consistency, it requires effort to do that. And sometimes it requires you to use some approach that is not optimal because it’s okay, we’re doing it consistently, it doesn’t make sense, but we’ll do it because somebody said that, okay, we’re doing it consistently. At the end, you just have garbage.

Miłosz [12:49]: Since you mentioned that DevOps and platforms, it’s maybe a good example of this because if you have this dream of having a uniform platform that all teams use in the team in the company, then all of them need to follow some similar standards.

Robert [13:07]: Oh, it’s the worst if somebody from outside of your team is coming to you and no, no, you shouldn’t do it like that. You need to do it in that because and it’s even worse if this is the person that really like consistency. So yeah. Yeah, definitely.

Miłosz [13:19]: So consistency is useful sometimes. Sometimes, not really. As usual, there’s always these extremes are bad. Yeah. And I guess we can summarize this as high quality codebase means quicker delivery of code overall like from very high-level perspective. This is the outcome you want. You want to deliver quickly with stable pace. So for me, I think…

Robert [13:57]: Probably it’s a useful question to probably ask yourself like okay, will it help me to. So if you are thinking about code quality, will it help me to deliver stuff faster? Or maybe not. Maybe it is just elegance and it will not give us much.

Miłosz [14:15]: Maybe it’s easier if you think of it as maintainability. If you want to keep working on this project over time and do it with a steady pace, that sounds like something where you want high quality.

Robert [14:31]: The thing that we mentioned already a couple of times is the fact that we are often talking mostly about how to write high-quality code, but I think it would be interesting question to ask if we always should aim to highest quality code, because it might may make sense. May sound like it makes sense. I mean, you would like to deliver fast, so we’re keeping the code quality high, but literally

Miłosz [15:06]: Yeah. Does it make sense to always aim for high quality?

Robert [15:09]: Yeah, yeah.

Miłosz [15:10]: Well, as you know, there is no silver bullet, so probably not. Sometimes low quality can be a strategy or a tool you choose consciously. But also, as always, it depends on the context and some factors probably. Do you know some?

Robert [15:37]: I think that there are a couple of things that could help us with thinking if we should aim for high quality or not. So the first situation that I can imagine is that if we don’t know if this code will be useful for us, so we’re doing some experiment. We’re doing some product that we don’t know if anybody will use. And we know that our long term maintainability may not exist because we may discover that, okay, actually it’s useless. Nobody will use that. So spending hours on making this code maintainable, it will be just waste of time because often maintainability requires some effort at the beginning. Often also we are implementing things that we’re not really touching after implementing that. So if you think about your projects so very often, it’s like that you have some modules or some parts of the applications that you are modifying often and reading often. But there are also some parts that somebody written couple years ago even, nobody have idea how it works, but nobody is really touching that because there is no need to touch that. And it’s totally fine. I mean, it may sound bad, like we should clean up everything or whatever, but it’s the reality that we’ll never have time to do that. And it’s also worth mentioning that we are also trying always to do applications as robust as we can, as stable as we can, but we forget that often those applications are not really mission critical applications. And if it will be down for day, half day or hour, nobody will care or even if somebody will be a bit upset, it’s fine.

Miłosz [17:21]: It’s not a nice thing to think about if you develop the application.

Robert [17:25]: I’m not saying that all applications should be like that, but some applications definitely doesn’t require that big that big stability, et cetera, et cetera. So it’s also worth mentioning that it’s not always that critical to just have stable applications. Again, I know that it may be not always logical, but I think it’s often visible if something will really be broken because, okay, if you ask your stakeholders if okay, it should be stable. Yeah. Yeah, of course you have to make it stable. Later it’s down for a day. Nobody really cares.

Miłosz [18:04]: But as someone developing this product, you probably don’t want to think about it like that. You don’t want to work on something that doesn’t matter. But sometimes it is the case. There are more critical projects. I have a theory of how the extreme take on high quality starts because we often work with some legacy systems. And, you know, after working with one for long enough, you might think, oh, yeah, I have had enough of this, I won’t allow my next project to rot like this one. So from now on, we will start doing everything high quality and we won’t accept any technical debt or some half measures. And it sounds like a good idea, but it can also be a trap if you swing too far to the other extreme.

Robert [19:17]: Do you remember some projects that you worked in and it maybe didn’t need to have that high quality code?

Miłosz [19:27]: I remember the one when we started applying Domain-Driven Design and similar patterns in Go the first time, and I’m often reminded of it when I talk with former colleagues who worked with us on it, and they usually, over a beer, mention something like, do you remember this project? It was so great. It had all the the best patterns and it was so cool to work with. Everyone loved it in the team and I remember, it is true. But what I also remember is that it had no paying users and we had to shut it down.

Robert [20:15]: At least it was beautiful.

Miłosz [20:19]: Yeah. It might be dangerous to daydream like this because most projects don’t look like that. Are not perfect examples of patterns or whatever you want to see in them. But this project was actually a very important moment for my career because I realized how little all those discussions mattered in the end. Like, we try to do the best job we could, but after, you know, after you see the project dead, then you realize, you know, maybe this one hour meeting on naming conventions or something like that wasn’t that crucial in the end, you know, of course, you never know. That’s the hard part. But I think it’s like a good perspective coming from this previous approach of “I hate technical debt, I will do everything to do things right” to more balanced approach of “Yeah, maybe we don’t always need to spend so much time on, you know, the high quality stuff.”

Robert [21:41]: If I’m thinking about that, it’s also one interesting thing. So survivorship bias. So you mentioned that okay this project failed. But I can imagine if this project wouldn’t fail we can think at the end that yeah okay. So it’s all thanks to our elegant code etc. and I think you should all watch out for that. That okay, if people are saying like as we said at the beginning, always do X because it will make your project successful. And it worked in our big projects that everybody knows. But you know, you don’t know if this was the thing that made this project successful. And it’s probably pretty unlikely. I mean, good technology is useful, but I think it’s not the most important thing at the end to reach the product market fit.

Miłosz [22:30]: Maybe it’s just not related that much. You know, there are companies that are very successful, but with probably terrible code quality. And on the other hand, there are failed companies with with great code.

Robert [22:46]: And I think it’s also the opposite. So there are even more successful companies with with great code quality, but I think we will go touch on that a bit later.

Miłosz [22:55]: Maybe a useful mental model here is to care about the useful product first, not the technical design, which of course is important, but I think it’s easy to overvalue it.

Robert [23:16]: And also we don’t want to sound like okay, never write good quality code. We’ll go into that. No worries. Where to, when to it makes sense to go with high quality from the beginning and we’re not too sure or take shortcuts, so wait for a while for that. But I think we may also sound now like, okay, always write bad code. It’s not also like that.

Robert [23:43]: What I think is also pretty important is the fact that it’s more maybe related to what your boss expects from you. So for example, if your boss is saying that okay, it needs to be great code scalability code. So your and you are creating for example, proof of concept. So your job is to ask boss, hey, are you sure that it’s the right time for that? And if he will say that, yeah, yeah, we need to handle thousands of transactions per second and make this code great. And you are not able to convince the boss for going the shortcuts. Well, probably it’s better for you to say what he ordered. I mean, at the end, he’s kind of your customer, and you are building what your boss is ordering from you, so not to be in the situation, like, okay, in one year, for example, your traffic is super big and your boss is asking, well, but you promised us that it will be scalable and it’s not. And you are saying, oh, you know, we needed to do something and it’s also not the best situation. So also watch out. Watch out for that.

Miłosz [24:57]: For sure there is some responsibility on you to explain. Maybe this is not the best idea. Especially if it will take a long time to implement, which usually it will. It’s if you aim for like huge scale or something before you really need it. But at some point, yeah, you’re not the owner.

Robert [25:21]: And remember, if you ask it for the first time, you’ll always hear the question. No, no, it needs to be scalable and high quality. You need to go deeper and say, okay, we can do that. But for example, instead of doing this feature for this time, it will take this time. And, you know, be pretty specific. And you know, your boss is thinking in terms of money and time is money. So, you know, if you use this argument, it can help. But again, it’s not always possible.

Miłosz [25:54]: Maybe we could go the other way now and choose some opposite project where actually high quality would be nice to have.

Robert [26:03]: I remember one project like that and this is a good example that it’s hard to find a good time to do this refactoring or improvement, because sometimes you are starting this project as a proof of concept. You’re doing it in a dirty way, but at some point you are at the point where fixing that will take really, really a lot of time. And I remember one project like that. And yeah, in this case, we should start the, let’s say, refactoring much earlier because it will be easier. And now at the end, again, we were in situation that total rewrite would be the only way to fix that. And unfortunately reality is that it’s often hard to do total rewrite. And even if you are able to do that, it’s often happening that it’s failing, unfortunately.

Miłosz [27:16]: You mentioned about the project that started as an MVP, right?

Robert [27:21]: Yeah, yeah.

Miłosz [27:26]: So it started as some sloppy code, maybe just to validate some idea and then grew over time into something that’s hard to refactor.

Robert [27:37]: Yes, yes, exactly. And again, it validated the MVP in some way and well, but I think the point when we should start to do refactoring was already gone.

Miłosz [27:50]: I think that’s the hardest question. Like when is the moment when doesn’t matter to it doesn’t make sense to keep going the current way. I mean, where is the moment in in the project’s lifetime when you work on the MVP and then you decide, okay, we need to do something about it. We need to change the approach. And when does it make sense to keep going the sloppy way.

Robert [28:28]: It’s an interesting question. I think it’s probably hard to answer. So it’s probably somewhere related to the question. If you start to see that it’s useful and anybody will use that and it will make some money and…

Miłosz [28:45]: Maybe if you ask yourself this question often, then it’s a good sign that probably something could use some refactoring here.

Robert [28:55]: But I think you know what the trap here is that if you are working in a project and it’s bad, it’s easy to get used to that. I mean, so you get used to how bad quality of this project is and you’re starting to think like, yeah, okay, maybe it needs to be like that. What’s useful is probably when some new people are joining your team and every person is saying how bad this codebase is. Obviously, you need to also take in mind that often people are just complaining that code is bad, and when it’s not.

Miłosz [29:28]: Maybe they don’t know it yet.

Robert [29:30]: Yeah. But again…

Miłosz [29:32]: On the other hand, new joiners often have this fresh perspective that’s also useful.

Robert [29:37]: Definitely. But I think I can have. So unfortunately, it’s hard to give one good answer when to do that. But I think I can give you some hints on how to approach that, because I think that this is also important part though. How to approach such refactor. The first thing that I would consider is timeboxing this, because it’s easy to go with never ending refactoring project or total rewrite that very often are just failing because it’s too big, it’s hard to I mean, stakeholders usually doesn’t like projects. Like, you are going to your cave for one year and trying to fix something. After one year, you’re going like, oh, unfortunately, we need to have another two years, so it shouldn’t be like that. So it’s important to be able to cut it to some smaller pieces.

Miłosz [30:37]: And maybe start with some first iteration of changes in a small scope, you know, smaller module or something like that. So you see if it makes sense or not.

Robert [30:50]: And probably it’s good to start with places that are often modified. So you can see the benefit of this. As we said about code quality, it’s all about making your development faster. So if you are refactoring things that nobody touched for five years who cares?

Miłosz [31:07]: I think that’s super controversial. I mean, when you think about refactoring a big project, I think the first intuition is to pick the least used thing, you know, where nothing happens because it’s low risk, so you won’t break anything. We can do whatever. But yeah, first of all, probably it’s simpler because it’s not used much. And second, there is little benefit in refactoring it in the first place. Maybe it doesn’t need to be refactored ever, because who cares if it’s not used that much? So that’s tricky part.

Robert [31:48]: The second thing that’s also pretty important is trying to find place that is not that big and you can change it quickly. So we are not talking about year because it’s super hard to, you know, do one year refactoring of the thing and later deploy that. It’s super risky or you will probably lose a lot of trust. Try to find some places where you can do. I know one day is maybe very optimistic, but let’s say one week. Start with the question what you can refactor in one week, you can deploy after one week and try to do it in small parts. So often you don’t need to rewrite an entire service. You can just do some refactoring in the code and just iterate on that. The good thing is that if you will do it on smaller iterations, you can see if you will break something where it’s broken. Because if you are refactoring something for one year, it’s super hard to later figure out what’s wrong here, because usually you are refactoring some logic that is hard to understand and it’s a mess to try to fix it later.

Miłosz [32:59]: And most probably also key here is to make it working end to end, right? So you don’t work on some unused piece of code for a long time and then plug it in. But do the changes in a kind of vertical slice so it touches on the entire codebase, and you can actually deploy it and see if it works or not.

Robert [33:22]: I know that it may sound like a stretch goal, especially for harder projects that okay, how you can do refactoring and deploy it after one day. Okay. So maybe if not one day, maybe one week, but okay, if you are not able to do it in one week parts, it’s maybe worth asking questions what you can do to deliver it in a week iterations. Maybe we need to add CI for this service / project. Maybe you need to add some tests. No, I think it’s useful to just start asking questions. Okay. Why I cannot cut this refactoring in smaller pieces. And if you spend some time to try to figure it out, you’ll find out that, okay, it’s actually possible. And you will see benefits really, very, very soon on that.

Miłosz [34:08]: There’s one more trap I see here that when you work with code base that you consider legacy, whatever this means in this context, but basically some older project older, which means maybe it’s one year old even, and it’s easy to assume it just has to be this way because everyone keeps complaining about this project. That there is no time to refactor. And just at some point you just give up. And then comes the big rewrite, which is probably not going to help, or it’s going to take massive amount of work and time to finish. So I guess maybe if you see the the project will be there for a while, it’s not going away. It’s probably a good time to start this refactoring earlier than later.

Robert [35:09]: And try to do this refactoring in small iterations. So again, not one year refactoring, aim for one day iterations of changes that you are doing there. If not, start with week. But I wouldn’t go with one month because one month is already very, very long time. So if you are not able to do one week iterations on refactoring, let’s ask questions why and what you can do to be able to do that.

Robert [35:38]: Does it mean that it’s not possible to balance code quality? And we need to always start with ugly POC and later refactor it with time, with pain, sweat, and uncomfortable questions from our stakeholders.

Miłosz [36:03]: It probably boils down to this question of when. When to do it. That’s what I have in mind. So to take for example, the our academy platform, which also started as an MVP, because we just had an idea to create something new and we had no idea if anyone would use it.

Robert [36:28]: As a context. So if somebody doesn’t know. So I think three years ago, we had written down from scratch a platform for learning by building projects. So something that nobody is, I think, doing. And we didn’t know if anybody will like that. So it was kind of risky project, especially that at that time we were working in a daily jobs. So we were doing it over nights, over weekends, and we just didn’t have time to do it better. Now, okay, we know that people like that. Buy at that point we didn’t know. But the good thing is that I think after those almost 20 years working with different projects, we found this good time when we started to clean it up. And it wasn’t that painful.

Miłosz [37:20]: It was exactly this dilemma because it was a rough MVP. And, you know, I remember the first version was basically mostly TODO statements in the code.

Robert [37:35]: There’s still a lot of TODOs there.

Miłosz [37:37]: If we had a proper design session on architecture and design, everything, I mean we had some. But to do it properly, I’m not sure if we would not just give up and just, you know, didn’t have the energy to do it. And I think you just scraped the initial POC in a weekend or something.

Robert [37:56]: I also remember that it’s also quite funny how it’s changed with the time. So at the beginning, I think our idea was that you push the code in GitHub and it will run some kind of CI to validate your exercises. And during that time we totally changed how it works. And if we’ll go with this GitHub part and do it high quality, we’ll lose a lot of time and will not be the correct state because we’ll just spend time on things that didn’t matter.

Miłosz [38:26]: I remember we had completely different idea about how the CLI would work, but then you just spent some evenings trying different UX approaches and we would never know it just before. But anyway, my point is that like last month or two, we were exactly at this spot where we have more time to refactor it. But you know, it’s a tough decision because refactoring is also not not giving you any product improvement. So it doesn’t feel like you improve the project that much at least from the business perspective. But I think it was a the perfect time to actually sit down and fix some of the issues so we don’t continue with adding more hacks to it, because if we did, then one year later it probably would be too late to come out of it. So we fixed the CI improved it a bit. We migrated to Postgres from Firestore and refactor the codebase a bit. And again, it was mostly developer experience, but I think it was a good investment at the time.

Robert [39:53]: And it also didn’t take ages at the end. I mean, you were doing ugly development for three years and yeah, it took some time, of course, but it wasn’t like a one year project to fix that. And we’re able to do rather small iterations.

Miłosz [40:12]: And it was also tricky to pick what to fix, because I think it is also dangerous to take a naive approach of “let’s look at all TODOs in the code and fix them,” because there are still a lot in the code base, but most of them are probably not relevant if we didn’t have to touch them for the last three years. So it’s better to look for something that actually solves some problems, even if it’s developer experience, which is quite important for an MVP.

Robert [40:55]: Especially in bigger teams. Because, you know, if you don’t know us, we are two people team. So not that big team. But so we can still cut some shortcuts that wouldn’t work in a bigger teams. But still there are some things that like CI, that we’re not cutting corners because our time is pretty limited. We are just two and we are not doing only development. We’re also doing a lot of things around. So, you know, having CI that runs ten minutes versus five, it’s a really big difference for us.

Miłosz [41:29]: So if your MVP gets good traction and you know you want to continue developing it, I think it’s better to do it earlier than later. At least some some initial improvements. But this is all about MVP’s and I’m wondering if you think this is the best approach for every project.

Robert [41:57]: You may guess that there is no silver bullet. Ha ha ha ha. Yeah, but so this approach worked pretty nicely for our project. That doesn’t require super big scale. We don’t have any external customers, if it will be down, okay, some people will be upset about it but it will not be that millions of dollars of our customers are lost, but sometimes we were working on such projects. So let’s imagine that you are working in a project that will be later sold to some enterprise customers, and you know that you need to take into consideration bigger scale from the day one. And you know, if you cut some shortcuts and you will be lucky to have some customer with bigger scale, with bigger requirements on the reliability. And, you know, it will be not stable. Your boss may start to ask your questions like, okay, you promised us that it will be scalable. It will be handling 5000 requests per second, and it’s barely handling 100 requests per second. And you know, it will be kind of your fault if you promised something else. And your boss may be a bit upset because it can lead to losing this customer. So it’s not like you can always cut shortcuts. You need to be pretty aware of what kind of project you are working on. And it’s no silver bullet. What can I say?

Miłosz [43:41]: It’s probably a big decision up front. If you want to start with a rough POC or design something more like proper high quality architecture from the ground up.

Robert [43:57]: Do you think that there are some places where you should not cut corners ever? So in other words, if there are any places in your projects that you never, ever should. Okay, never say never, ever. But in most cases, you shouldn’t cut corners. Do you have something like this in mind?

Miłosz [44:19]: I think if you want to break rules, it’s best if know them beforehand. So you know the patterns and the better you know them, the better you know when it makes sense to break them. And that’s how you know when cutting corners works best. And because I think our platform is a good example of where cutting corners on purpose is much different than doing them by accident, which might be sometimes something similar. But at least you you know how to fix them. And you can leave some some context for yourself in the future so you understand why this works in a simpler way right now. Why this is a hack, but it’s not an afterthought, but something you do on purpose.

Robert [45:22]: In other words it would be good to understand if you break some rules why those rules exists.

Miłosz [45:33]: And especially now coming back to the AI discussion, which can spit out huge loads of code for you, which is very useful sometimes, especially if you work on front end and you don’t want to do it. But still, if you don’t understand what’s going on behind the scenes it probably won’t take you far. At least that was my experience so far.

Robert [46:03]: There’s also another example that I think cutting corners doesn’t make sense, and this is architecture. So for architecture there’s one bad thing that is usually hard to change. So we often seen that we’re working in some projects that were already successful and in terms of traffic customers. But there were some decisions that somebody made at the beginning of the project, and it was already impossible to change them. So we were able to refactor some services, what were inside of them, but still they were working environment where some other decision like using some library, using some framework.

Miłosz [46:52]: Frameworks are the worst for it.

Robert [46:54]: Yeah. And you know, if somebody were just be a bit more, more mindful at the beginning of this project and think about this architectural outcomes of this decision, it would be much, much easier to develop something. And sometimes we were participating in some rescue projects that were trying to fix those architecture problems, or maybe removing some frameworks that were used there, but it took like man-months to remove something. So let’s imagine couple teams needed to work for a couple of weeks to remove one library. And it was like just crazy amount of time lost just because somebody used some library at the beginning of the project.

Miłosz [47:37]: And it was tightly coupled to all the microservices in the company.

Robert [47:44]: What helps in this scenario is modularization. So if you are able to modularize things so you can develop them independently. And this is for example a case in our learning platform. So we have some modules that are super ugly. And I have no idea why it works but it works. But we’re not touching that because it works and it works properly. And if it will be the place when we’ll be changing often, obviously we’ll refactor that, but it works. So, you know, it’s maybe it would be good to make it nicer. But let’s be real, we’ll never have time for that.

Miłosz [48:21]: That’s a tricky part, right? Because the architecture should be probably high quality. You want to make it the proper way, but it’s also easy to overengineer it. Right? Especially if you start with an MVP that doesn’t need all this consideration before you can just be stuck with some system that you thought will handle all possible use cases in the future, but turns out it’s not really needed. You will be fine with a simpler approach. So that’s something to be careful about. And on the other hand, no design is usually bad design, so you probably want some initial idea at least about how the system will work.

Robert [49:19]: I think one of the best advices here is to build stuff. I mean, because it’s really hard to give one advice like how to not over design things and how to see the things that will get into fire later. And what I think worked, at least for us best was just building, building, building and building. And after time you will break a couple of things. We’ll see. You will see how in some cases it worked badly after time or aged badly, for example, I think it’s, for example, useful to work in one project for a longer time to see how it will really what will get into fire from your initial assumptions and it’s help. And yeah, this is what we always advise people to build, to build and do it mindfully. Because if you also do it not mindfully and just build stuff without thinking about that much, it will not help you much because you will be just in the same position for longer time and will not develop yourself.

Miłosz [50:26]: Yeah, it makes sense. Sometimes it also depends on the team size, right? And how experienced people are in the team. So, for example, if it’s just the two of us working on the MVP and you know, I see you commit 50 TODOs in one commit, I’m mostly okay with it because I know you will tidy it up later. But in contrast, if you have a team that’s just formed a couple of months ago and people come from different backgrounds, don’t have that much experience with the current architecture and stuff like that, it makes more sense to have more, you know rules in place.

Robert [51:21]: To summarize a bit. So I think there’s one tip that can help you to maybe decide if something is important architecture decision. And this is the question that you can ask yourself. And this question is how? So if you are adding something to the code to think how hard it would be to remove that. So I mentioned the history of removing one library for a long time for the project. And if somebody would ask himself a question, okay, how hard it would be to remove this library. The answer will be “super hard” because it’s just coupled to everything. And you can ask this question about almost everything. So if you are using some framework or you’re, I don’t know, using some external vendor, some database, whatever, you can always ask your question how hard it would be to remove that. And if you don’t have that much experience already with building architecture, building products, it will help you to, you know, start thinking about things. And sometimes, unfortunately, the answer will be it will be hard to remove that. And okay, the follow up question will be do I really need to use that?

Robert [52:38]: Often, okay, if you think for that for a while, maybe not. Maybe some frameworks or external vendors, maybe you don’t need to use that. But sometimes, unfortunately, you need to use things that you need to couple with. Like if you are using Postgres for example, removing this later will be harder. I will not say that it’s impossible because it’s possible, and it’s probably unlikely that we’ll do that, but it’s a decision that you are taking that okay, I’m using Postgres and I will need to stay with that. So if you see anything with you like need to stay for longer, really be sure that this is the thing that will not hurt you. Like Postgres for example, I would not say that using Postgres is let’s say risky, but for example, using some vendor that, you know, just had founding one year ago and they released their proof of concept that and your CTO would like to use that. And you see that it will be just hard to remove from your code. Maybe it’s not the best idea to use it. Maybe, I don’t know, maybe Miłosz you have some good examples of such things.

Miłosz [53:53]: You definitely need to commit. And it’s a good thing to commit to something because it simplifies many things. Just need to be careful when you pick what to commit to. So if it’s a stable technology that’s been around for a long time, like Postgres or basically any SQL database probably, that’s probably very low risk. But as you said, if it’s something experimental sometimes it also makes sense because it’s maybe you know, something, it’s a perfect match to your product. But the issue is if you pick too many of them and then the risk is super high that something will go wrong. And now we have to migrate. And yeah, migrations are fun.

Robert [54:45]: But again, remember some things may be experimental and not stable, but it may be easy to replace. So probably one good example are large language models like Claude or ChatGPT. So the API of it is very small. You are sending a list of strings, and you’re receiving a list of strings in a very simplified way. But more or less it’s that and replacing one with another. It’s not a big deal at the end. So you know.

Miłosz [55:17]: That’s kind of how our migration from Firestore to Postgres went recently, which but our code wasn’t exactly ready for it from, from the start even though we promote it on our blog to to use clean architecture and use interfaces for it. We didn’t care that much initially for the POC, but it was very easy to reintroduce. So that’s the part about conscious corner cutting.

Robert [55:51]: But it’s also probably worth mentioning that in our platform, we are not really storing that much data in Postgres or we didn’t store that much data in Firestore.

Miłosz [55:59]: It was quite simple.

Robert [56:00]: Yeah, but there are applications where you have a lot of data and it will be, i would not say impossible because it’s always kind of possible, but it will take a lot of time. Yeah. So there’s also one thing that I think you generally should not cut corners on. And this is your pipeline. CI/CD pipeline. And we already touched on that a bit earlier. So why CI is important. So again CI when it’s unstable, slow it’s just wasting a ton of your time. Again, it’s just me and Miłosz in our company and we are building our stuff. And you know, we don’t have that much time to do that. And if our CI is unstable or slow, we have even less time. So making it fast and stable just allowed us to go faster. And again, at the beginning it often happens that it’s unstable, but in general, from my experience is that if you try to not keep CI stable soon, it’s really, really hard to improve it later because it’s ongoing work to keep it stable and fast. And doing it later will just require a lot of time.

Miłosz [57:24]: And you keep using it every day, Every person in your team uses it. So all the tiny issues add up and you just keep wasting more and more time over time. It sounds like we talk about developer experience a lot today, but I think it’s also quite important because the morale of your team is a big factor in pushing the project forward. Like if everyone’s frustrated with a slow CI or, you know, flaky tests or a project that’s hard to set up locally, it’s a hard environment to iterate quickly on anything.

Robert [58:15]: And remember, if you need to convince your boss to have time to work on CI, remember your boss is thinking in terms of money. Get the average salary in your team say, okay, our CI pipeline is taking 20 minutes. I can take a tea, eat my breakfast during that time. It costs this amount of money. Our team has this amount of people improving performance of CI by 50, 70, 80% will save us this money.

Miłosz [58:47]: It’s one of the best, the easiest metrics you can measure. It’s very easy to track how many time you spend on waiting on CI, and how much it improves over time.

Robert [58:59]: And if it’s, you know together with flaky tests, it’s even worse. I mean, I’ve seen CI in my life. That pipeline took 20 minutes, but, okay, I know it’s not that bad. I heard stories about pipelines that are taking days, but let’s don’t go there. But, you know, if it’s flaky and you’re waiting 20 minutes three times, and you also there is some delay when you are retrying. It’s just a very big waste of time. Yeah, and it’s also a lot of frustration. That’s it. And to make it worse, it’s also a lot of context switching because okay, you can drink one tea, eat one breakfast, but after the second retry what you will do.

Miłosz [59:44]: That’s also why we spent some time to refactor our CI in the last iteration because we had these issues. It’s much better.

Robert [59:54]: And remember, it’s also sometimes fine if you see that some tests are unstable, disable that. I mean, if they are flaky and you don’t see value in them, disable them. Remove them. It’s also fine.

Miłosz [01:00:11]: Maybe not fine, but better than retrying over and over.

Robert [01:00:16]: Definitely. And I think it’s also important to mention one thing because, okay, I know that it’s already a bit complicated, that there are different kind of projects when you can cut corners, should not cut corners, you shouldn’t cut corners. But unfortunately, I need to add another level of complexity here. And this level of complexity is company culture. So, you know, I know that in some companies you can have time to refactor things after creating POC, but unfortunately it’s not the case in all companies and in some companies out there. If you will develop something, you will never, ever have time to refactor it. So it just makes sense to do things right from the first day, spend more time to do it properly because you know that, okay, if I will not do it right now, I will never have time to do it properly and I will just have mess to work with forever. So it’s also important to keep this dimension in.

Miłosz [01:01:18]: And it also depends on who decides about this choice, because you probably don’t want to ask your manager or product person or whoever, “should this project be high quality software?”, because no one will tell you, “No, it shouldn’t be.” So on one hand, it’s an engineering decision, but on the other it also needs to be a dialogue sometimes with the management. If there’s some tight deadline you need to reach or something like this, but it’s easier to talk about, you know, not the technical quality. Like an example of bad idea is, okay, we will skip tests for this to make it faster. Instead, I would focus on cutting the scope of the feature of the product. And sometimes the Pareto principle applies here. So maybe you can find some, you know, like maybe you can cut 20% of the scope that will take 80% of the time to fix, to work on or to deliver. And if you have this dialogue with the product person or product team, then it’s much easier to cut the scope in a way that won’t affect your codebase quality. So you can keep your developer experience. You can keep having tests and a nice environment to work in, but you can cut some of the scope, at least in the current iteration or the first iteration. And the Pareto principle is maybe a nice idea here to ask about the project in general. Like maybe some parts of it can follow more strict high quality ideas and maybe some parts can be simpler.

Robert [01:03:32]: I’m not sure if you actually explained how Pareto rule works.

Miłosz [01:03:37]: I didn’t. So if you don’t know it, the idea is that often things split in this 20/80 percentages. So let’s say 20% of the code takes 80% of time to write because it’s more complex. And the remaining 80% takes 20% because it’s much easier.

Robert [01:04:03]: Or 20% of the code earns 80% of money. This is also very often the case.

Miłosz [01:04:08]: It turns out this applies to many things in life. So I wonder about the same. Apply that on the project level where we can focus the 80% of focus, let’s say.

Robert [01:04:22]: We already touched on people that like consistency in the code, and we already touched a bit earlier that it’s usually not best idea to do. And it’s also with code quality. So some people would like to approach code like okay, it should be consistent quality and standards over entire code base. But unfortunately in practice it’s a waste of time because like I mentioned multiple times, often you have in the code places that you are not touching often or it’s not earning a lot of money. Or maybe it doesn’t need to be stable because nobody will really care about. So I think some important ideas how to find this 20% that is the most important in our code base is asking a question, “What are the places that we’re changing the most often? What are the places that are creating most of the value of the company? Or what are the places that where the stability of our application matters the most?” And in those places you can use some sophisticated methods like Domain-Driven Design or do some better layering, because this code usually that makes money is often changed. It’s usually the most complicated code in our company, and it’s just worth to keep it high quality because it will pay back pretty nicely because we are touching it often. It’s complex, so we’ll be able to work with that faster. And again, it’s important to mention that not all code in your application needs to be bad. Not all code in your application should be good. It’s well, for some magical reason, usually some sort of part or all. So sometimes it’s enough to have 20% of application that is high quality. Sometimes it’s closer to 80. It doesn’t need to be always 80. I mean, it can be 60, let’s say, or 90. But you know, the idea.

Miłosz [01:06:34]: And maybe the opposite of high quality is not low quality sometimes, but just “good enough” quality, which might be a tricky balance. But basically the idea is that you start with the happy path. And at least for the first iteration of a feature, you don’t need to implement everything. You don’t need to cover all edge cases that can happen, because there’s very often a very long list of them. But you can focus on this 80% of important, often used features and implement them good enough. And of course, there’s always this other factor here that if you don’t cover the edge cases, then you have to support them manually very often. And it often makes sense because I remember we had projects where we skipped some manual support for the most weird edge cases, because even our stakeholders didn’t know how to handle them. It was so complicated. So why spend weeks of developer’s time automating it if it happens very, very rarely?

Robert [01:07:50]: In other words, if you’re automating something, think if, for example, you are not spending a week on automating thing that it’s taking, you know, five hours a year.

Miłosz [01:08:01]: Eexactly. I had a project like this before. And when I calculated it was a dumb process that we had to do every month, but when I calculated it, it took two hours over the year for one person. So it feels dumb that you have to do it manually, but then how can you do it? How can you automate it so it makes it worth to save two hours a year?

Robert [01:08:33]: I think I have a good example even from today. So the downside of developing our training platform after hours is that we didn’t have time for developing very basic features, like we didn’t have feature for changing your email address. I know it sounds silly, but again we did most of this time over weekends and after work and we were just cutting all functionalities that were not possible. And okay, you can think what can be hard with changing email address. And yeah, I had the same idea this morning. So I thought, okay, it’s super simple, let’s even try to use Claude Code for generating this. Four hours later. I found that there is a bit more complexity for that. So we don’t have actually that many requests to change email address over the year. But I already spent those four hours and it’s there with some shortcuts done anyway. But it’s often like that you have some dumb thing that you are doing rarely, but you think that, okay, automating that, it will just take one hour and one week later, you see that, okay, it was a bit harder. So I just saved my minus four days and eight hours.

Miłosz [01:10:01]: But on the other hand sometimes the small issues compound. And you may have, you know, you might spend a bit of time on one issue a year. But if there are 20 issues like that, you may find yourself doing support for full time. So again, balance. You need to pick what needs to be fixed now and postpone what doesn’t need to be fixed right now.

Robert [01:10:38]: I think it depends a lot on the company culture. So the thing that I mentioned a bit earlier. So in startups you can probably live for a while with spreadsheets, CSVs, and, you know, your company is based on spreadsheets and CSVs and it’s fine for the beginning. After you are scaling, it’s probably good to maybe keep track of that, of how much time you are spending on such stupid things and balance that.

Miłosz [01:11:18]: I guess it’s good to set some expectations also on yourself so you don’t feel bad about having some low quality code somewhere in the codebase. And I remember feeling bad, especially when hiring new people. You know, you have some parts of the project where you don’t want them to look, but it’s completely normal, right? Most projects have parts like that, especially if you have some legacy software that has been there for a long time. So I think you also need to accept that some parts of it will be there. And be careful about this mindset, as you know, things need to be nice and tidy everywhere, which I think is common among developers. I also feel it sometimes that, you know, I would like things to be nice and tidy and all the corner cases covered and all the TODOs fixed, but very often it’s not really useful to to do it.

Robert [01:12:35]: And one more thing. If you are joining some new project and you see some old code that you think is bad, try to maybe not blame previous coders because you don’t know actually in what conditions they needed to work.

Miłosz [01:12:50]: Sometimes it’s hard.

Robert [01:12:51]: Yeah, yeah. How long they needed to spend on some code. So for example, I have an example that I worked in one project and later I was talking to one person that was complaining a bit why it’s that bad. And later I added a bit of context that we written this code in probably two days and didn’t touch it mostly later because we didn’t have time, but it worked good enough. So it’s like it was not our bad will to write something badly. It was just we’re doing some hackathon or whatever and we just implemented it quickly. It worked good enough and that’s it. And yeah, I think it’s also making your life a bit easier, if you will just try to assume that your previous colleagues that are no longer with you did your best. Especially that I also seen it multiple times that after some person is leaving, some people are tending to blame this person that oh, okay, this is bad because of this person. And you know, truth is usually a bit more sophisticated. And often those people that are blaming this person that left, they’re also not without any blame. So, you know, watch out for that.

Miłosz [01:14:09]: Now that you mention hackathons, it’s also an interesting topic to think about. Like how do you run a hackathon and then not end up with a pile of garbage, which we did a few times. It’s interesting. But that’s an extreme example. Most of the time you probably don’t create a new product in three days.

Robert [01:14:36]: But again, I think in general the idea is good because sometimes it’s allowing you to really cut corners, because you need to cut corners because you have some deadline to do that. And the outcome I think sometimes can be really interesting because you can go much, much further than you think that normally you wouldn’t be able to do that because sometimes it can even take months because of some stupid conventions. And maybe at the end you will find out that, okay, maybe actually we don’t need to do that because it’s no value in that. So yeah, I can really encourage you to run some hackathons if you are able to do that and, you know, try to not do hackathons that don’t care about functionality, to not use any bad words. And yeah, I think it can be an interesting exercise, but it’s also, again, important to clean it up in places that we mentioned a bit earlier.

Miłosz [01:15:37]: But sometimes, the high quality, low quality difference is not that big. I mean, high quality sometimes doesn’t require so much effort, even for a hackathon, right, for example, like using the repository pattern or even clean architecture maybe.

Robert [01:15:59]: In some lightweight form.

Miłosz [01:16:02]: Yeah. It’s not like a huge investment upfront. And once you do it, it’s easier to manage the project. So even for hackathons, you could use some of the more advanced patterns, let’s say. And it won’t slow you down.

Robert [01:16:25]: And the thing that we mentioned a couple of times. So try to be mindful about code quality and remember that it’s something that you need to learn with building over time. So after you build a lot of projects you see better where you can cut corners, where you shouldn’t cut corners. So during this episode, we did give you some hints. But again, I think practice, practice and practice, it’s very important. And it’s also fine to be wrong here. So even if with Miłosz we have pretty lot of experience, sometimes we’re also wrong in deciding if we should go with higher or lower quality. And it’s fine. I mean, as long as it’s not some decision that is not reversible, it’s fine. So I think there are a couple of questions that it’s worth asking. So if you are thinking about code quality. So the first thing is that something that we mentioned at the beginning. So if this code is more an experiment, or we know that, okay, we already have customers there or it will be potentially sold to some enterprise customers that will need to just make it working properly from the day one. So it’s good to start with that.

Miłosz [01:17:46]: It will also help you decide if you want to use an MVP or not for this project. And a similar question is if this project is mission critical, if something terrible will happen, if it goes down for a couple of hours, let’s say. As I said before, we don’t like to think our code is not important, but maybe at least parts of it are not.

Robert [01:18:18]: It’s also good to think, okay, what will happen with that after we develop that. Maybe this is feature complete part and will not touch it in the next year. I know that, okay, the chance that we will touch any code in five years is probably not that low, but maybe in one year what’s the chance that we will be touching that. If we will not be touching this code in one year, we assume we never know, but we can have some assumption. Maybe we can cut some corners there because if we will not be touching that what it will give us if we make it high quality.

Miłosz [01:18:53]: And if you touch it, then it’s good to have some context of the approach that we used. So for example when refactoring our Academy platform it was useful to have this context in the comments or the todos that scattered it. And they don’t look nice, but it was super helpful for me to know okay, that’s why we took this approach. But it also doesn’t mean that you have to get rid of all the TODOs. Sometimes it just, you know, it just exists there, and it’s fine. We don’t need to to worry about it. Because if you don’t change it over time, what’s the issue?

Robert [01:19:41]: Like prehistorical paintings in caves?

Miłosz [01:19:46]: Yeah, kind of.

Robert [01:19:48]: I love those comments in the code like, “it shouldn’t be like that. We should fix it ASAP.” Git blame: five years, ago and everything is fine.

Miłosz [01:19:59]: It mostly shows that it wasn’t that important maybe. And I remember having some time in the sprint when we are out of work and it’s time to look through the backlog. And I remember looking at the technical debt issues that we added over the years before, months before, and we always complained there was no time to do them. And finally there is time. And I looked at them and I realized I don’t want to work on it because it doesn’t seem important. So then you can just delete them and don’t worry.

Robert [01:20:43]: And if you did your dirty POC, don’t miss the time when you should clean it up, because it’s easy to go into spot when it’s no longer possible to do that. And I think it’s very nicely visible in some products that it’s visible that they were able to develop it quickly at the beginning. But you can see maybe three years later that they were not able to add any single feature to this product because it’s so hard to touch. Everybody is so afraid to touch and change anything there, and it’s just slow death for the product. And it’s already too late because it has too many functionalities that it’s hard to replace and it’s maybe just not justifiable job. You may not justify to rewrite it from scratch.

Miłosz [01:21:42]: It’s probably worth to keep in mind also that code quality is not the end goal. It will help your projects succeed over time, especially in the long run. But be careful not to make it the metric, to not care too much about the quality itself, which is hard to define in the first place.

Robert [01:22:06]: I know that there are many people that are thinking like, I don’t care if this project will be successful. I just care about money. So if you are this person, right, it’s fine. But if you are trying to find a well-paid job, it’s much easier if you have some success stories. So you just didn’t work in the projects that were mediocre or failures because, well, the market is pretty hard now, and I was interviewing many people in my life, and it’s super easy to see if people really worked in their projects that were successful, and they had some positive impact on how those projects were delivered and how they succeeded. And, you know, if you are just working in the projects that “I don’t care if it’s successful”, really, it will be much harder for you. So if it’s you, really, I highly recommend to try to care, even from a selfish perspective.

Miłosz [01:23:06]: Probably also watch out for some extreme tips like “never do X”, “always do Y”, because most of the time it’s not so simple. There are more subtle corner cases and context you need to understand.

Robert [01:23:28]: I think there are multiple dimensions of parameters let’s say that are affecting that. So if you are listening to us from the beginning, so you see that just code quality can have that many dimensions and you see that out there there are a lot of people that are saying that, oh, you don’t need to care about code quality, or code quality is super important for how fast you’re delivering. So you can see that it’s not that easy. And I think it’s just showing that a lot of people that didn’t probably work in many projects or didn’t work mindfully in these projects may not give you the best advice.

Miłosz [01:24:07]: It’s hard to boil it down to some very simple rules. I think it’s quite lazy if someone tells you something like “just just keep it simple”. Yes, of course, I want to keep it simple, but you can’t just take a 12-person team and tell them, just keep it simple guys, it will be fine. So there’s many, many different ways you can approach any project.

Robert [01:24:38]: Check good sources, some good live podcasts, for example.

Miłosz [01:24:46]: Okay, I think we are nearing the end.

Robert [01:24:48]: Yes, I think we should be able to go into our Q&A now. So sorry for not looking for the chat, but our multitasking abilities are limited. So let’s see what questions we have on the chat. So we’re mentioning a bit of our learning platform. So it’s a proof that we have a lot of fans of how it works. And yeah, how the strategy of cutting corners at the beginning and fixing it later, it works. So yeah, we have “Go Event-Driven was really good. Highly recommended for everyone to check out.” That’s true.

Miłosz [01:25:32]: Thank you.

Robert [01:25:35]: All right. So time for the first question. Do you want to take it?

Miłosz [01:25:39]: Okay. So Rohit asks, “do you think that careful design decisions maybe at low level would avoid refactoring later on? Sometimes I have made decisions that to priority addition of changes over code quality. Is that normal?” Maybe that’s the question whether you want to start with a POC and do something dirty and then figure it out. Or do you want to create some proper architecture from the ground up.

Robert [01:26:21]: I think it’s probably important to set some expectations here. So I think it’s good to spend some effort on design because if you always have some design so there is no that you have no design. If you will not make design you will have bad design. But it’s not that you will not have the design, but if you try to do your best, even spend ages on the proper design you probably will also not do it totally right. And it’s fine because you have some assumptions at the beginning how it will work, but it will change over time when you’re implementing stuff, and at some point you will end up with need to refactor something and it’s totally fine. So like we mentioned example of our platform for trainings. So our initial idea was totally different. And at the end we ended up with something different and design wasn’t perfect, but we were able to adjust it with the time.

Miłosz [01:27:27]: I think the part I would be careful about here is the avoid refactoring later on. So this is not something you want to aim for. You don’t want to make something perfect now, so you avoid refactoring later because it will anyway happen. So rather better to adjust as you go with some small improvements rather than try to come up with a perfect solution that will cover all future use cases. That usually ends badly.

Robert [01:28:01]: Remember about the question that I suggested at some point. So I think design is the most important for things that are hard to change and to know if something is hard to change. Ask a question. Is it hard to remove? If it’s hard to remove, probably it’s good to think about the good design or thinking if you need to redo it in this way. I hope we answered your question. If not, please leave a follow up on the chat. Yeah. Second question is a bit simpler. So, “hey guys, will you be releasing on Apple Podcasts later?”. Yes, we’ll release on Apple Podcasts, but we would like to have three episodes done, so it will take more or less one month will be releasing it to another three platforms, so it will stay just on the YouTube for since we will release two more episodes and later it will be on Apple Podcasts, Spotify or whatever application for listening podcasts that you are using. It will be there. If you are in our newsletter. We’ll also send a summary tomorrow. Tomorrow? Yeah, I guess tomorrow. We’ll send summary, transcript, and all this interesting stuff. Another question. “Is hexagonal architecture worth in the real world?” What do you think, Miłosz?

Miłosz [01:29:25]: I want to say yes, but.

Robert [01:29:28]: There is no silver bullet!

Miłosz [01:29:31]: But I can tell you that, we used it a lot in many different projects and teams. Hexagonal, clean architecture or whatever you want to call it. And one thing I noticed is like this. This is the pattern that many former colleagues tell us about that they introduced in their new team. And the new team members also love it. So I think it shows that’s something developers like working with. And we do too. But of course, if it’s a simple POC or some scrappy MVP, you can probably skip it. But then also it is not a big effort upfront. At least, maybe that’s just my perspective because I’m used to it so much.

Robert [01:30:28]: I think it requires more effort if you are doing it for the first time. So I will definitely not do it for the first time. Especially that I think clean architecture is sometimes kind of the trap. So people are trying are overcomplicating that.

Miłosz [01:30:44]: And we will be talking about it in four weeks, so I think we will cover it more in depth, but I think it’s one of the most useful patterns we use overall. And also not that complicated. And it’s not even about the exact approach, but just having some layers, splitting the important code from the less important code.

Robert [01:31:10]: TL;DR yes, it’s worth.

Miłosz [01:31:15]: Definitely in the real world it is useful.

Robert [01:31:19]: It’s just important to not over-complicate that, unfortunately a lot of people are doing and okay, also what other people are doing is applying clean architecture without understanding that. So it’s leading to a complicated code.

Miłosz [01:31:35]: That’s the issue with many patterns. It’s very hard to understand what someone means by clean architecture. do you remember the rant on Reddit about how clean architecture is the worst thing to happen in Go? And you know, I then read the thread. And basically the author said that you shouldn’t use more than three layers.

Robert [01:32:05]: Instant question. So how many layers you are using there? TEN?

Miłosz [01:32:11]: That’s the general issue with naming. I think it’s similar with Domain-Driven Design.

Robert [01:32:16]: Maybe they are combining clean architecture with hexagonal and onion and using all layers from that.

Miłosz [01:32:24]: It’s very hard to understand what someone means by one of the acronyms used in tech.

Robert [01:32:32]: Long story short, we’ll touch a bit more on that in the next episode. Please remember to subscribe on our landing page of the podcast so you can. You’ll not miss that. All right. Next question. “That’s actually how I’m developing first version, I write the POC, then I do the refactoring in cycles and until I’m happy with the story the coding is telling.” Yep, it’s a good approach.

Miłosz [01:33:04]: That’s iterating

Robert [01:33:09]: Yep. Okay, the next one. “Is it better to refactor or code review every certain interval? Because in startup environment almost no one wants to add review as their task.” I think that this is interesting question.

Robert [01:33:29]: So what’s my experience in a similar situation is that if you have problem with people doing your code review, it’s probably something wrong with team responsibilities. If in the team. I mean, if people are kind of working on things individually, not like a team, it’s a problem because it’s not the team’s responsibility to deliver something, but it’s individual responsibility to deliver something. And from my experience, this is the root cause because, well, if you are responsible for your feature, why you should review other people’s work, you kind of don’t care. And if you are doing more team work, so you’re planning the work as a team. You’re implementing entire feature as a team. You know, it’s interest of all of you to deliver it faster. But I’m not sure.

Miłosz [01:34:25]: But, you know, I think the question is more about the interval. So the way I understand this, should you do like two sprints of product work and then one sprint of refactoring or review? And I don’t have good experiences with this approach of this, you know, like dedicating entire sprint to code quality. I don’t remember it ending well, at least in the projects I was in. So I don’t know. What do you think, Robert? I think it’s better to iterate. So just do small improvements as you go.

Robert [01:35:14]: Yes. There’s also one thing in this question that I think it’s also pretty relevant.

Miłosz [01:35:18]: Oh, unless you do what we did. So we actually had to dedicate this one iteration pretty much to changing, to refactoring the code base so you can start working quicker. So sometimes this “go faster” initiative also can work. I would just be careful with stuff like okay, maybe it’s about if you know what you want to do beforehand. So if you know we have this issue with the CI, let’s focus one week on improving the CI. Then it sounds pretty good to me. But if you want to do something like okay, we worked six weeks on the product. Now let’s take two weeks to fix the TODOs. That sounds like more tricky part because you don’t know what you what you want to solve. So I would try to, you know, first understand what you want to fix.

Robert [01:36:21]: And there is one more thing that, so please let us know if we’ve answered this question properly. We’re after ten hours work day and it’s almost 8 p.m. here in Poland. There’s also one more thing that may be worth mentioning here. So for some hardcore refactorings. So what we also recommend for that is mob programming. So you are gathering with the team. One person is coding and you’re kind of helping this person. I will not cover how mob programming works, but I think that not a lot of people know about that. Worth checking, especially for harder refactorings because it’s easier to kind of synchronize with the work that you are doing with the entire team. I know that for some people it’s like, oh, we’re wasting entire team’s time for this. And it would be easier if one person will work on that. But for other side, somebody needs to review that. And the good thing about mob programming is that you have real time review. So everybody is looking on that and you are kind of doing a review together with them.

Miłosz [01:37:27]: The bad part is that it promotes looking for consistency. So you have to be very careful about cutting offtopic discussions or nit picking of how something works.

Robert [01:37:43]: But I think it’s good for things that let’s say you will be working on for a week and it wouldn’t be possible to do code review of that, because sometimes it happens that you have that big refactoring that there’s no way to do code review of that. If you are doing mob programming, there is kind of no need of doing code review. All right. So I hope we answered. If not, please let us know. All right. So the next one Miłosz maybe you would like to pick up this question?

Miłosz [01:38:14]: “It is always good practice to keep your code at a minimal level without looking for perfection, but at least enough clean to be comfortable to give it to someone else without being nervous about it.” Yep, sounds like a good baseline level. Like, don’t don’t stress too much about perfection. But you know, take effort. Yeah I think that’s actually a good question to ask yourself. Am I comfortable giving it to someone else and having them work on it? Would I be ashamed of myself. I used to, you know, half-joke about this, about our platform, that if we hired someone to work on it, our reputation would be over because they would see all the TODOs in the code. Yeah. So that’s pretty good. Good idea.

Robert [01:39:15]: All right. And so time for so far, the last question. If anybody has more questions, you have still some time. So “how do you measure that you’re overthinking and overengineering.” So I’m not sure what you think about that, but I would say that what I personally like is I think that most of us doesn’t like, but it’s sometimes also useful. So having some timebox or deadline. So if you’re timeboxing your work for some time, or giving yourself some deadline, or maybe some days doing it externally. So it’s kind of forcing you to not overthink things because, okay, you have some time to do that and you need to focus on thinking on things that really matter. And I think I noticed it for the first time when I had some external deadlines that I noticed that, okay, I needed to refocus on things that did matter and other things I didn’t have time to run it. Again, I know that we don’t like deadlines, but this is the small, useful part of them. Definitely. I’m not sure what’s your take on this?

Miłosz [01:40:29]: I think it’s hard to measure yourself because we don’t like to think that we are wrong about something. But what I like is cutting scope. And I think it’s something we did this week, actually. And when we we have a new project going on and we had an initial idea how to do it and with like a brainstorming session and then we thought, okay, let’s now remove everything that is not absolutely required to make it work. And let’s just finish this v0.1, deploy it and see if someone uses it. And very often you later realize, oh, actually, this is good enough. Maybe we didn’t need all this complexity. We initially planned for. Or as Robert mentioned before, with our platform, we had much more complex setup in mind, first with CI connected to it and all of it, and then we stripped it from all this and focused on the critical path. And that usually helps because you can see that maybe you don’t need all this.

Robert [01:41:55]: Also having some kind of MVP, maybe connected with some deadline that you’re putting yourself on that doesn’t need to be that strict. But again it helps. And I think what also helps is to have some end-to-end part working. So for example now we are working to adding some AI on our platform. But also I think we also have some nice idea how to have it working end to end with some limited functionality. And we’re not overthinking that that much because okay, we’re focusing on the simplest part and we can start to overthink it later after we’ll see that it was working. Because the problem with overthinking is that you can overthink things, that you later find out that it’s not useful, and you need to overthink another thing.

Miłosz [01:42:45]: Sometimes it also helps to have someone else who can tell you, you know, maybe you just want to use this AI API or this database. Maybe you should do it in your side project, not in this one. You know, like someone who can tell you if you if you go too far, it should be easier for someone else. But then you need high levels of trust to accept this.

Robert [01:43:20]: Okay. So I think it would be it for today so we can finish up. So if somebody doesn’t know us yet. So I highly recommend to check our blog. I don’t know if you can see QR code. It’s not that big. Let me try. We’re using this platform for the first time, so let’s do it like this. Okay. It’s not so big.

Miłosz [01:43:54]: True MVP.

Robert [01:43:55]: This is QR code with our blog, so highly recommend to check this out so there is more content there that is mostly about Go. So if you know Go it may be interesting for you. If you don’t know Go, it may be also interesting for you. If you liked this live podcast episode, fun fact is that this is the first episode that we recorded ever, so I hope that you liked this. So if you liked this, I highly recommend you to subscribe to us on YouTube so it can reach more people. And, you know, you can be also sure that you are not missing any new episode because we are already planning a couple more. Oh, I see that actually a lot of people just joined us because it was 70 people and now it’s 94. Hello for everybody who just joined, we’re finishing, but you can scroll to the beginning to check that. So yeah, if you would like to also to support us, please let all your friends know about that so it will help us to release new episodes. What else? So we already have a couple more episodes planned. So the next one will be why you shouldn’t use frameworks in Go. So if you are writing Go, it may be very relevant for you. If you’re not writing in Go, it may be also relevant because I think it may be pretty universal advice. The next episode will be Is Clean Architecture Overengineering. So we covered a bit about that earlier, but we’ll go a bit deeper in this episode.

Miłosz [01:45:50]: That’s a broad topic.

Robert [01:45:52]: Yeah. After that, we’ll cover how we believe you can learn faster. So we also covered a bit of that today, but we’ll cover definitely much more. Also if you’d like to not miss an episode we totally recommend to subscribe to our newsletter on our blog, because YouTube may not send you notification or Twitter may not send you a notification. In our newsletter, you will be sure that you are receiving the notifications so you will not miss the episode. And yeah, if you have any comments questions and you are listening it a bit later, leave us a comment on the YouTube. We’ll read that. And if you have anything that we should include in the future, please write down and we’ll try to include it in the next episode. Please also give us a thumbs up if this is already uploaded to Spotify, Apple Podcasts, or whatever, please also leave us a five star review so it can reach more people. Something to add Miłosz?

Miłosz [01:46:57]: Thank you, Robert, for meeting me today.

Robert [01:46:59]: Yeah. Thank you.

Miłosz [01:47:00]: See you in two weeks.

Robert [01:47:01]: Yeah. See you in two weeks. Thank you.

Miłosz [01:47:03]: Thank you everyone. Bye bye.

Robert [01:47:05]: Bye bye.

Let's stay in touch

Never miss a new episode: get notified directly, without relying on unpredictable social media algorithms.

You'll know when we're live, get updates on new episodes, and receive exclusive content.

Last update:
  • March 5, 2025