Quick takeaways
- Frameworks promise productivity but often lead to issues as projects get larger and more complex.
- The Go community prefers small, focused libraries over frameworks due to Go’s design philosophy influenced by Unix principles.
- Watch out for risks using frameworks like vendor lock-in, deprecation, and costly migrations that can take months.
- Explicit code is more maintainable than magic framework abstractions.
- Choose your approach based on project size and maturity - frameworks might work for prototypes, while modular libraries are better for long-term projects.
Introduction
In this episode of the No Silver Bullet podcast, we discuss frameworks in Go and when they’re useful or problematic. We talk about why the Go community generally avoids frameworks compared to other languages, and how small, modular libraries are often preferred in Go development.
We share our experiences with frameworks across different projects, including tradeoffs between productivity and long-term maintenance.
Notes
- Model-View-Controller (MVC): Pattern first described in the 1970s for Smalltalk, still widely used today.
- Unix Philosophy: design concept created by Ken Thompson (also a Go creator) promoting small programs that do one thing well and work together.
- When to avoid DRY in Go
- Watermill: Our event-driven library for Go designed to not be a framework.
- Repository Pattern: Our blog post that is still relevant and frequently referenced.
- tdl and pq - the CLI tools we mentioned.
- Clean Architecture: The topic of our next podcast episode, a design approach that helps maintain separation of concerns.
- Wild Workouts : Our example Go codebase demonstrating clean architecture.
- The Best Go framework: no framework?
Quotes
The happy path is easy enough, but the happy path is usually not the hard part of software. We often overvalue how much effort the boilerplate requires.
Framework knowledge tends to become out of date. You can spend days or weeks learning something about a framework, but it can be outdated. And if you switch to another programming language or company, a lot of effort that you spent to learn stuff will be just wasted.
It’s more important to learn even-driven architecture because you learn the theory behind it and how it works in general - it transfers better to whatever you will do later. Focus on timeless skills like how to split modules in your application, how to make it decoupled, how to write business logic so it’s easy to read and modify.
The Go language is heavily influenced by Unix philosophy - write programs that do one thing and do it well, write programs that work together. It’s visible in Go’s standard library. This is why Go promotes building independent components that you can connect together.
You need to be careful not to go too far with foundations. It’s better to start with some modular libraries, have some reasonable setup in place, but don’t go too crazy with it. Most of the time you’ll need to refactor the project anyway, whatever you do, because it can change drastically.
One big decision at the beginning may cost you six months of work later. Understanding if something is tightly coupled to your application is simple - just think about how easy it would be to remove it.
Timestamps
Transcript
Robert [00:00]: What if framework you choose today costs your team months extra work next year? Choosing a framework at the beginning of the project can greatly impact the project in the future. We have been in projects where relatively small decisions in the beginning led to many months of work a couple works later. Have you ever considered why the Go community does not favor using frameworks in go? Does it mean that using frameworks is always bad in Go? I’m Robert.
Miłosz [00:31]: And I’m Miłosz And this is No Silver Bullet podcast where we discuss mindful backend engineering. We spent almost 20 years working together in different projects and teams, and during that time we’ve seen that following advice like “always do X” or “never do Y” rarely works and can limit your growth. And in this show, we share multiple perspectives that will help you make smart choices and level up into the principal engineer level.
Robert [01:01]: If you have any follow up questions, leave them on the chat. So we will try to answer them at the end or maybe even during discussion if we will have enough time.
Miłosz [01:14]: So we talk about frameworks today in Go, but also in general, maybe let’s start with what we consider a framework. So we are all on the same level. First of all we focus on backend frameworks. So we don’t talk about the frontend world today. Just the backend side of things. And in this episode we specifically focus on the Model View Controller framework or MVC, which is usually what most people consider a framework during the discussion of “should I use a framework at all?”, or “which framework do I choose?” So maybe, Robert, could you give us a TL;DR what MVC is?
Robert [02:02]: So MVC. So it’s an interesting pattern that it’s already pretty old, but well, I’m kind of fan of some old patterns because I think often they’re still pretty relevant. And the same thing is with MVC. I think for the first time MVC was let’s say invented or written down in 1970s. So yeah, it’s more than 50 years ago. So pretty long time, but it’s still pretty valid.
Miłosz [02:29]: Like SQL.
Robert [02:31]: Yep, yep. And I think it was for the first time in Smalltalk language. That was also pretty interesting one. But we’ll not go today about talk about Smalltalk. But yeah, and MVC. So it’s acronym for Model View Controller. And the interesting thing is that the chance that you are using MVC is pretty high. If you are building an application that has a database and a user interface, and you are allowing to modify this data. So it’s pretty high chance that you are using MVC. And it’s because it’s the industry standard on how you are building applications now. And very often it’s actually MVC pattern. And the idea here in MVC is to split your model, view and controller. So model, this is your domain logic. Your entities that are handling data. View is we can say the user interface often and controller is responsible for orchestrating everything between this. I’m not sure if you agree Miłosz, but probably it may be obvious for some single page applications, but I guess we can also say that even if you are building some react application, it’s some form of MVC also, even if it’s a bit different than how it was built.
Miłosz [03:56]: On a different level, but a similar idea. With the one model that is the source of truth of data, and then some parts of the application that react to it in some way. So that’s similar concept I guess.
Robert [04:13]: And yeah, today we’ll discuss MVC frameworks. So if you think about frameworks like Ruby on Rails, Django, Laravel, Symfony, Spring, all of them are MVC and are MVC frameworks because they have building blocks for building MVC parts. So you have some building blocks for models. Usually you have some building block for controller and you have some building block for view. So the idea is that they should simplify your life when you are building such kind of application.
Miłosz [04:45]: And there are some other libraries that we probably shouldn’t consider MVC frameworks for this discussion. Like router libraries and in Go there is many of them, but you can also think of something like maybe flask in Python or I guess chi or echo in Go. So they give you the tools for working with HTTP messages and you get the views, but there is no model. Or you could do it yourself with some ORM framework maybe, but it’s yeah, it’s not out of the box compared to, for example, Django that gives you all of it.
Robert [05:31]: Django or anything what I mentioned earlier, like Ruby on Rails or Laravel, Symfony, etc. etc.
Miłosz [05:38]: From what you said so far, frameworks seem like a good idea, like the separation between model, view and controller seems like a separation of concerns. What we want most of the time and they do many things for us, they come with batteries included. So usually if something sounds so great, there must be some hidden cost, right?
Robert [06:09]: Yep. And frameworks are no different. So I went over websites of couple of frameworks to figure out actually what they are promising. And I have a list actually about things that are usually mentioned there like authentication and authorization, logging, observability, queues, database access or some sort of ORMs, dependency injection, sending emails, payment provider integration. And the idea is that it’s all integrated. So for example, if you are using any component, it should be integrated with observability with queues. And the idea is that it should work together out of the box. I also checked some promo materials for those frameworks and some sound pretty nice. Like a “complete ecosystem for web artisans” or “build and ship software with tools crafted for productivity”. Sounds good. This one I like pretty much “compress the complexity of modern web applications”, or the last one “optimized for happiness”. It sounds a bit like some religious cult, you can say, but to be fair, well, spoiler alert it’s not false. I mean, in some contexts it’s meeting those requirements moments. Maybe happiness sometimes.
Miłosz [07:34]: It sounds good on paper. I think especially if you just start, if you bootstrap a project, especially before we had AI tools to bootstrap projects with. It could be quite cool to just call a couple of functions and have a website ready.
Robert [07:57]: And it’s kind of “wow” effect. So you just spend five minutes on something and it’s working. You can show it to your mom, “Mom, look what I built, oh”.
Miłosz [08:08]: Especially if you are a beginner, right?
Robert [08:12]: Yeah. So you don’t need to have all this knowledge about how to connect stuff. And you can focus on things that matter at the end and are the most important. So building the useful things. And you are productive when you are doing that. So that’s cool.
Miłosz [08:29]: And what I also like about it is that you can focus on writing the core domain parts of your software because for many web apps, there are probably, I don’t know, 80% of the code that is written is very generic, right? It’s what all web applications use, like database handling or HTTP routing and stuff like that. So it makes a lot of sense to focus on what’s different in your software and not waste time on writing what someone solved already some time ago. But I think there’s also this trap here that I’ve seen many companies and projects have this dream of, you know, we will build all the foundations first. So we have this super custom framework or platform or whatever this means, and then we can just create new applications or microservices or whatever else, like a cookie cutter. So it virtually should take no effort in theory. And it sounds nice, but I think it’s also a trap because it ignores the fact that most of the complexity in software is in the details, in the weird edge cases, which is, by the way, also probably the reason why AI tools are not that great yet. I mean, they are very, very nice for the generic cases, maybe for similar stuff for what frameworks are nice. But when it comes to those weird edge cases you need to handle in the real world, yeah, that’s a bit harder.
Robert [10:18]: It’s actually quite interesting that we can say in some way that AI is competition for frameworks, because, yeah, that’s true.
Miłosz [10:26]: They all fall into this category of this dream of “code with no code” or “software, with no code” to create applications with no code like UML was supposed to be at some point maybe.
Robert [10:42]: But let’s go back for a second to Go, because the title of this live podcast is “When you shouldn’t use frameworks in Go”. So let’s go for a second for Go, because now we covered a bit how it looks like in the different technologies. But it’s worth mentioning that in Go it’s quite different situation. So like in different languages that we mentioned you have some kind of well-established frameworks, Go is different. So there is no leading framework. And generally the community is against using frameworks. And this is interesting situation and I think one of the reasons for this situation is that well, Go is pretty new technology compared to other technologies. And well, building one big framework, it requires much more effort. If you compare it to just building small libraries that do one thing and yeah, it’s just faster. So it may be probably one reason for that.
Miłosz [11:46]: And maybe also the, the libraries that we have now evolved over years. I remember like when we started eight years ago, there weren’t that many libraries for anything but they started appearing over time and they grew and became more polished. But there was nothing that connected them all. Well, there were some attempts for sure, but I think there is no one standard framework right now that everyone uses. Maybe it’s because also of how the standard library looks like and the Go philosophy of small packages that do one thing well. That kind of resonates if you think about the current ecosystem of open source libraries in Go. There are many smaller libraries that focus on doing just one thing.
Robert [12:44]: I think a good reason for that may be also the design of the language, so how the language was designed. So I think, I’m not sure if anybody mentioned it explicitly, but I think it’s visible that it’s heavily influenced by Unix philosophy. So I suspect that for at least one reason that one of the creators of Go language is Ken Thompson, who is also author of Unix Philosophy and Unix Philosophy tells us to write programs that do one thing and do it well. To write programs that work together. And it’s visible in Go standard library. If you look on how, for example, HTTP package is built, how io.Reader or io.Writer are built. So, you know, io.Reader or io.Writer is an excellent example of a small program, let’s say, or interface doing one thing and you don’t really care about how it’s working under the hood. It’s pretty similar. So if I would like to explain Unix philosophy for you, probably the best way will be mentioning how your terminal works. So you have things like cat, you have things like grep and you can connect it together and pipe that. And this is similar. This is actually this idea. And this is moved to Go heavily. And yeah, I think it may be also the reason why Go is kind of promoting the building independent components that you can connect together. And it’s nice because for example, if you have http package, you can have multiple libraries that can understand HTTP request or HTTP response writer and interact with that. So it’s promoting this, creating independent libraries. And for example you can have a library that is just giving you one HTTP middleware, and you can integrate it with the rest of the system.
Miłosz [14:38]: It’s a great API design rule overall, no matter the programming language really. And it’s nice that Go gives you those interfaces out of the box. So most libraries try to stick to them, which makes it easy to connect them together.
Robert [14:53]: And it’s not something that I’ve seen in different languages. So usually in different languages you have library that is doing HTTP, and standard library is not giving you that much. Or sometimes those frameworks or libraries are doing something totally incompatible. So it’s just hard to have multiple libraries that are working together. And in Go giving these interfaces, it makes this much easier.
Miłosz [15:15]: That’s actually a good point. I think Go is the first language I’ve used that gives you this really powerful HTTP server. That’s yeah, it wasn’t ideal from the start, now it’s a bit better. We usually use routing libraries anyway, but it’s quite solid if you want to start with anything. I think most other languages, at least at the time Go was released, weren’t that great. You had to just, you know, include some custom library. So why not use a framework if you have to do it anyway? And there were some attempts at creating Go frameworks, I think. And one risk of using them is that if there is no one big default framework like let’s say Spring in Java, you have this risk of this framework becoming deprecated, and then you are stuck with some project that uses a framework that’s hard to migrate out of. And I think there was go-kit. We’ve seen used some projects.
Robert [16:28]: No, it was go-micro.
Miłosz [16:29]: Oh, true. Yeah. And I think there was also a very popular Gorilla router library that also became deprecated over time. So you can still use this of course, but it doesn’t receive updates. So there is some risk that you might need to migrate out of it in the future. And you know, migrations are fun.
Robert [16:55]: And you know, if you are using frameworks, you have this framework that is integrating all MVC layers. So model, view and controller, it’s much harder to migrate out because if you just have a library that is handling routing for you, it’s kind of simple to get rid of this library. But if it’s integrating everything more, I think model is probably the worst part, because if your model is integrated with views and controllers, it’s very hard to get it out of your application. And yeah, and okay, somebody may say, okay, it’s not happening, that libraries or frameworks are deprecated. You can check history of them, that some of them are quite dead, we can say. And there is also one example of licensing change. So go-micro from what I checked actually changed license and is no longer open-source license. So it’s business source license. So the same license as Terraform is using and it’s not open source. So you can read the code, but you can cannot use it like open source thing.
Miłosz [18:02]: Time to fork.
Robert [18:04]: Yeah. But remember fork the tag before changing license. So the thing what happened with with Terraform. But it’s risky obviously. And in some cases it may just cost you a costly migration. And this is just one example.
Miłosz [18:20]: So someone could say it can happen with any library. Right. So why bother? But I think the difference is the smaller libraries are easier to to replace if it impacts just one area of your code. Using a different library here is quite easy, probably. Depends on how you do it, but hopefully. But if you do it as a core of your project, like a framework, then it becomes much, much harder to do it.
Robert [18:47]: Definitely. And if you go back for a while to discuss the promises of frameworks because, you know, we’ve been there also a couple of years ago when we were starting programming and, and yeah, at this time we’re working, to give you some context. So it was, I think almost 20 years ago. And at this point, the landscape of programming looked totally different. So, for example, if you know Laravel framework from PHP, it didn’t exist yet. jQuery, that already sounds like super old technology, it was almost not adopted yet. And if you are talking about other PHP frameworks. So it was Symfony, but it was also not widely adopted. It was something pretty new. And when I remember that we use Symfony for the first time, it was actually quite great at the beginning because it made a lot of things that we were doing earlier by hand, and it just allowed us to save a lot of time. So I already mentioned authorization, logging, nice observability. It just worked of the box, and it was great. It also generated for us database models. So again, we were able to deliver stuff faster. But again we were also a bit less experienced. So for us it was like magic at that point. And I remember that before that we were just crafting some SQL queries by hand and it was super dirty.
Miłosz [20:22]: But this magic was also a bit unexpected for me when I first started using it. So I remember you tried to onboard me to Symfony. And you know, I was looking through the project and I couldn’t find a SQL migration files and I asked you, where are the SQL files? You told me what? You don’t use it. You just you just use models in PHP. And that felt weird for me at the time because you had to change the mindset. You have to just trust that framework, that it will do its job well. You don’t really. I mean, you can dump the schema, of course, and inspect it, but usually just accept that there’s some annotation you have to do and that’s it. So if you would like to know how it works, the internals, that’s a bit of a mindset change you have to do. And also, on the other hand, if you have someone who is used to working with Spring, let’s say, we had developers who were Java developers and joined us to write in Go, and I remember they were confused about how we don’t have a dependency injection library, and they were just mind blown similarity of, you know, how why do we do it manually? Why not just put a single annotation and it works? So it’s a bit different concepts. You have to adjust.
Robert [22:07]: But I think it’s also one downside that, you know, it’s hiding this complexity from you. And sometimes those people were coming from Spring. They struggle because, okay, they need to write some query by hand. And it’s like writing a SQL query is so hard. I didn’t write any SQL query in my life earlier.
Miłosz [22:29]: That’s maybe why, you know, “no silver bullet” is so difficult because we tend to adopt to one way of doing things when we started.
Robert [22:42]: But I think it’s also showing that it’s, you know, often frameworks are showing you that, okay, you’re doing it in one way and people are not really thinking about doing some exceptions because for many cases, it’s just enough to have generated model that does queries for you and ORM is doing for you, but probably 10, 20% of queries can be written by hand and it can be much more optimal. But people are often going in the direction that, okay, we need to do it with ORM and are going with some crazy stuff and also to ensure that it’s properly shown somewhere with the view layer.
Miłosz [23:18]: Yeah, we like consistency. What can I tell you? I had the same experience as I just just mentioned. It’s nice to work in a way you already know. And if you have to change it’s problematic.
Robert [23:34]: But probably we can recap that as okay, frameworks obviously they have some downsides but well they are giving us a lot. So you may ask us okay why we are no longer PHP developers writing in Symfony. So it may be some reason that, well, it wasn’t the best technology in our life and now we are a Go developers instead. So it’s a question what went wrong. So I already mentioned that, you know, 20, 10 years ago the landscape was totally different. So it was much less open source tooling like for observability, logging, tracing and routing so you didn’t have much choice because you could use Symfony or some magic PHP frameworks, or Spring maybe, or maybe some Python tools. So actually frameworks were giving this a lot for free, but now it’s quite different because you have much more libraries, especially in Go that are open source. And they are using some open standards.
Miłosz [24:38]: Or even standard library like with HTTP in Go, you don’t need a separate library for this and many other similar for stuff like, you know, it wasn’t possible back in PHP. You know the standard library there was quite poor at the time.
Robert [24:55]: Oh yeah, especially compared to the Go one.
Miłosz [24:57]: So basically we learned that there is no free lunch. There is no silver bullet, you have to consider what you need to give up to use a framework. And I think it’s more relevant if you think about the project in the long term. Because if you just start the project, as we said, you know, we just throw in a couple of function calls and you have a working website that’s pretty cool. It feels like magic initially. But over time it becomes less cool because you start getting into those edge cases that the framework doesn’t handle for some reason. And maybe what you mentioned about SQL queries is a good example of this. So often it’s it just makes more sense to use a custom query to get some data you want, some complex query, instead of trying to use the models. I especially like how you know in Go the ORMs often have a separate language in the struct tags. So you have to learn a separate syntax that is not validated by the compiler. And I started to wonder, you know, why is it really that that helpful to use it.
Robert [26:34]: And you need to also do a PhD from how those magical notation works and it’s not great.
Miłosz [26:42]: Yeah, exactly. So at some point it just becomes less flexible. It’s easy to start. But then you need to add some extensions, maybe, you know, even in several components that use the framework and it’s starts to get a bit tricky.
Robert [27:01]: Model is one thing, the flexibility of models. And if you are talking about MVC frameworks because, as we said at the beginning. So in most cases when we are talking about frameworks, it’s MVC frameworks. So if it’s MVC, it needs to support not only model and controller, but also view. And from my experience, very often the biggest problem is in the view because okay, if you are starting to build your simple application, just having a form and a form with some fields there with simple inputs, it’s enough. But probably very soon you will find out that what frameworks are giving you out of the box, it’s not really allowing you to express, let’s say, every UX and requirement that you are receiving earlier. So yeah, it’s also obviously often you can do workarounds or for example, not use the view part from framework. Just return your models from Rest API or from other site, you are losing a lot of advantages that the frameworks is giving you.
Miłosz [28:10]: You need to find this balance. Because if you find yourself spending more time on extending this, those missing edge cases and writing those workarounds, it’s probably a good idea to do something else. Those queries for example. Right. So if you start fighting with those with this weird syntax of an ORM or a library, and maybe just give up and use a standard SQL query and should be good enough.
Robert [28:44]: And I think it’s especially a problem when your project is becoming more successful and team is bigger, because if you are two people, team whatever, and your product is not that successful or widely used, it probably doesn’t matter. Actually, you can take shortcuts and it will be everything fine. But well, if your product is becoming successful, all the problems are starting to pop up there.
Miłosz [29:08]: As usual, the happy path is usually easy enough, but the happy path is usually not the hard part of software. And we often overvalue how much effort the boilerplate requires. Like, it often it just seems boring to to write all this, you know, routing and database database queries and all this stuff that you do in every application. It’s not really different. It doesn’t differentiate you from other applications, but it’s not really a big effort. Right? It’s just boring. And now LLMs will happily do it for you. So it’s even better.
Robert [30:02]: But from one side, writing it by hand is boring. But I would not say that it’s super interesting to do workarounds for that. And I would say that it’s much, much worse than.
Miłosz [30:14]: Oh, but sometimes, sometimes it’s actually fun to do it. I have a story maybe I can share. So you remember in one project we had this entities stored in a database in, and we used one model for them in Go. And yeah, we had this issue that we didn’t want to return the exact values we stored in the database to the front end side. So we had one model and we wanted something different in the views than just the database model. And we could just create a different model and map those fields between them. But that would be the boring part, right? You don’t want to write this mapping.
Robert [31:11]: We are smarter.
Miłosz [31:13]: Yeah. So it’s the usual question we get asked, right? Like, okay, I did clean architecture and I separated my models between database and HTTP, let’s say. But what now? How do I automatically map those structures. Yeah. You don’t. Like in this project. We exactly thought we are too smart to do it by hand. So we wrote a library that could do it for us using reflect and custom struct tags. And please don’t do it.
Robert [31:13]: It was great.
Miłosz [31:52]: And since then, my rule is if you use a statically typed language and use reflection think twice. Is this really what you want to be doing?
Robert [32:05]: Yeah, probably second outcome is that don’t be smart. Usually being smart as programmer, it’s not the best way because you may become too smart. And your solution may be that smart that nobody will understand that. And it will take a lot of time to maintain it.
Miłosz [32:26]: This is actually my favorite part of this story is the why behind it. We just thought we are smarter than writing boring code and that led to more trouble. So you have to be careful around this.
Robert [32:48]: All right. One important thing. So I think in general, the discussion about frameworks that we have today, it’s nicely connected to the previous episode that we had two weeks ago. So if you didn’t have a chance to listen to that, I recommend it because in general it’s often well, choosing framework is big architectural decision. So often if you do it at the beginning, it’s quite hard to remove it later because as we said earlier. So it’s a matter of coupling your models to rest of the application. And it’s not like replacing your HTTP router or something like that. It’s usually very tightly coupled, and it’s just hard to remove that. And yeah, in previous episode we were discussing pretty deeply that it depends a lot in which stage of project you are or if you think this project will be successful in long term, because probably if you are doing some pet project or you have some small team and it’s proof of concept, probably doesn’t matter that much. But if you see that your project is taking traction and team will be bigger, it may be problematic to go out of this decision.
Miłosz [34:20]: So this assumes someone would need to remove a framework, right. Which usually doesn’t happen if it’s a big and proven framework that many people use. But with smaller frameworks it’s a bit more risky. So some time ago we worked with this go-micro framework. You remember, for microservices.
Robert [34:46]: I remember.
Miłosz [34:47]: Across many teams, tens of microservices, and there was some issue with the protobuf version there. There was something custom.
Robert [34:57]: Yes, I think it was some custom implementation of protobuf that supported something extra, but at some point it was no longer maintained.
Miłosz [35:06]: Was it related to gogo/proto or not? Doesn’t matter. But somehow there was a decision to remove it. And that’s a long story short.
Robert [35:18]: Yeah, I think so. It wasn’t like, okay, we need to remove that. I think it was leftover. Somebody decided to use it a couple years earlier. A year and couple years later we were in the project and it was some leftovers from that. And I think it was not maintained and it didn’t support something. And it also have some weird edge cases. At some point we needed to get rid of it because it blocked something, something else.
Miłosz [35:44]: Possibly also back then Go modules weren’t as great as is it now. And I think there were also some issues with this, but basically there was decision to get it removed and it went exactly how you would expect a framework removal to go.
Robert [36:04]: It to be exact. So it wasn’t removing entire framework, it was just leftover from something that was there since a couple of years.
Miłosz [36:13]: I think it took man-months of, I don’t know, half a year, probably in total effort from people from different teams because this spanned across teams, because it was related to communication between services. So obviously it’s what connects the project together. Yeah. I remember when we finally got rid of it, there was a big maybe not event, but I remember celebration where everyone was super happy. I mean, I were too, but then you start to think about how dumb effort this was, you know, spending time on removing some obscure library that caused some issues, but, you know, shouldn’t be there in the first place probably.
Robert [37:07]: I think it’s an excellent example that some decision that happened a couple years earlier that have that big impact later. And yeah, it’s not the only time when we’ve seen that. So obviously it’s hard to do all the decisions fine all the time. But yeah, the thing that I mentioned. So it’s worth thinking like, okay, I’m using this framework library or something like that, just in case if it will be deprecated, how I can remove that. And if the answer is okay, It will be super hard. Maybe it’s worth thinking. Okay, maybe we should choose something different or how we can mitigate that. Or again, maybe again. It’s a bit more in the previous episode about that, but maybe it’s fine because maybe it’s proof of concept.
Miłosz [37:58]: Probably hard to decide what is a good, you know, or maybe maybe a different way. What is what are some red flags that tell you stay away of this framework? Because I guess if someone uses a proven framework like Spring or Ruby on Rails or Symfony or whatever…
Robert [38:20]: Probably it would be not deprecated.
Miłosz [38:22]: Probably. Yeah. Because the community is big enough. That’s one thing. If the company behind it would drop it, I guess you could expect the community to just fork it and maintain it over time.
Robert [38:36]: Or maybe not, because it’s just not adopted enough and because I think it’s the thing in Go. So in Go we have pretty, it’s pretty big segregation of frameworks and there is no one leading framework. And maybe some people will do some updates, for example in the fork. But I would not expect that it will be super big updates. So it’s risky in Go, I would say.
Miłosz [39:04]: Especially if the framework is created by one person or a small team.
Robert [39:09]: Or for example, some other risk that people are often not thinking. So if it’s created by some VC backed company. So, you know VC capital is not free, it’s not charity. So probably they will need to make money at some point. And we’ve seen recently when it was big shift in trying to get money from multiple products and some licenses changed, like with Terraform, for example, and it’s definitely a risk. Again, especially with things like framework that it’s just coupling everything and it’s hard to remove. So I can imagine that in many cases it’s like, okay, let’s better pay for that and forget.
Miłosz [39:58]: Or maybe let’s just pay for the first year and then we’ll migrate. And you know, this migration task sits at the bottom of your backlog, and one month before the next invoice, you realize, oh, we should migrate.
Robert [40:13]: Task: remove framework.
Miłosz [40:15]: Oh, let’s do it next year. And then the next year, the company shuts down because they run out of funding. So yeah, there’s a risk.
Robert [40:29]: If you are thinking about framework, it’s also worth looking on the features list and assess if you need everything from this list. Because frameworks are usually providing many things out of the box, but very often you don’t need to have everything out of that. For example, do you really need, I don’t know, payment provider integration? Do you need ORM or many things from that? And it’s a question if it’s worth paying the cost of coupling everything. Or maybe it’s just better to use something independent.
Miłosz [41:08]: And often frameworks have to be that, have to cover all those edge use cases because otherwise they are not useful because people use a framework and they have all kinds of requirements. I think it’s even for authentication is a good example. I think there is this authboss in Go for authentication kind of framework. I don’t know if maybe it’s more a library, but I think it nicely shows how we can have so many approaches to authentication. If you want to create a library that’s popular, you have to support all of them. Otherwise people will just skip it because it is not supported. But as a user, in contrast, you only probably want 10% of what it offers.
Robert [42:02]: And I think it’s also making the complexity rising exponentially, because when you have multiple things like database models, logging, observability, payments, view controller and you need to have everything integrated. Adding one case, it requires you to add it very often everywhere. So obviously it’s much harder to make it flexible because you are often focused on providing one path that works. But if you need some flexibility around it, just maybe not compatible with the rest of the components.
Miłosz [42:39]: And this one is often very, very useful. If you have a proof of concept app or just a trivial CRUD domain. Then having this happy path scenario and you know, one model for everything that’s actually quite useful because you don’t waste time on this mapping and so on.
Robert [42:57]: That’s true. But from other sides. Well, experience tells me that often applications are not CRUD. I mean, I like to think about that. Okay. If your application is simple CRUD, maybe spreadsheet is enough.
Miłosz [43:13]: Exactly. That’s that’s the usual case, right? Like, why would you build custom software if it’s that trivial? For stuff like this, this no-code solutions should be ideal.
Robert [43:27]: Or spreadsheets. I love spreadsheets.
Miłosz [43:29]: Or some of the more, more complex spreadsheets that are now quite popular.
Robert [43:36]: Oh, come on, you’ve seen what you can do with Google spreadsheets and that entire startups can live on Google Spreadsheets, and it’s fine for a while.
Miłosz [43:46]: Yeah, I think the biggest trap is if you think you have a CRUD domain, but you have not, and you start with this single model for everything, and then you realize it when it’s too late. And we have a lot of articles about this on our blog, so you can take a look. There’s this one to watch out for the DRY, don’t repeat yourself principle, which is about this issue. So we will link this in the summary later. So you can take a look. And it’s also about the mapping issue I mentioned before. And I see that Grzegorz in the chat asked about this mapping. So there is a mapping library in Java mapstruct and it is common to use it. So why can’t we do it in Go. And how did we overcome the mapping problem. So the issue with the magic mapping we created was that it was just hard to maintain because there was a lot of reflect code, which is hard to grasp and test. And, you know, long term it will be just it would be easier to just map the structs manually. And that’s what we did later in later projects. So that’s how we overcame the problem. We didn’t. We just kept separate structs and mapped one to the other when we had to. And I don’t know, maybe it sounds boring or bad. It is quite boring, but there is a big plus of boring code. It’s trivial to understand and test and change.
Robert [45:40]: And it’s also compile time checked for that. So if you break something, you written it properly. Compiler will tell you that it’s something wrong here.
Miłosz [45:51]: And today we have so many, you know, copilot tools that can generate it for you that it’s even better than it was a few years ago. It’s basically free. So that’s you know, that’s our approach right now. We prefer explicit to magic.
Robert [46:10]: And I think what I can recommend is just trying it because again, it may sound boring, but yeah, I would recommend trying that and just feel that it’s not that scary. And actually it works quite nicely. And again, don’t be afraid of boring code or boilerplate because again, we tried different languages also where it’s more promoting some magic, some elegant code, but at the end later it’s super hard to understand. Like Python is probably a great example that okay, it’s in general allowing you to create nice interfaces that look really nice, like some decorators, but at the end you have no idea what’s happening under the hood, and in Go, you just cannot do that. And it’s very explicit. And you can navigate in the code up to system calls to understand what’s happening. And it’s very linear I would say. So there are just navigating and you see what’s happening.
Miłosz [47:12]: But maybe there’s also a good idea now to remind of the no silver bullet principle that now what we just said about this manual mapping and all of this is especially nice if you have if you work with a team in a bigger project and you know, we have you have to have some consistency and maintainability for the long term. And we talk about this in the previous episode. But again, if you have a proof of concept application or something you work on just yourself or want to try to build some MVP, then of course just doing this single model might be a better idea, maybe just simpler and easier in the short run.
Robert [48:02]: Yeah, I think it’s a really good point. And usually where the problem is, it’s when people are going into extremes, like always do it like this and it’s it’s usually the bad idea. And yes, you said so. It’s also not like where you always using separate model for everything. No actually we often using one model for multiple things. But it’s in case when the model is the same everywhere. So for example, or sometimes and sometimes we’re also wrong. I mean, we’re creating some two models for something. And we later see that okay, we’re always mapping it 1 to 1. Maybe let’s just make it one model and whatever. So it’s important to be kind of mindful probably in that. And if you see that you’re doing some stupid mapping and it’s always the same. Because what we just said a couple seconds ago about this mapping manually, etc., it’s good for the models that are different. But if you are always have the same fields in two models, maybe you don’t need to have two models. Maybe it’s fine to have one model. And it’s also a matter of encapsulation, because sometimes you need to have DTO when you are doing an encapsulation like in some of our projects that. So for example in Wild Workouts project that we have. So in this case it’s we are introducing some transport DTOs to have encapsulation in domain layer, but again, it’s not always needed. If you sometimes have some pretty simple models encapsulation, whatever you have, small team, whatever, you have 100 people team, you know, it’s totally different thing. And spoiler alert. So I think it’s also in the topic of clean architecture that also a lot of people are saying like, oh, clean architecture is overengineering or whatever, but okay, how complex is the project that you are mentioning? How many people were there? Was the person that was using clean architecture aware how to do that? Maybe it was overengineered, but maybe it was not the proper implementation.
Miłosz [50:02]: We’ll talk about it in two weeks. About clean architecture. I think what helps is knowing both extremes, because then you can just consciously choose one method. It’s much worse if you don’t know about it. Just stick to one and use it for everything. But what’s also tricky is consistency, especially in a team. If you map structs for the entire project and then someone wants to skip it in one place, it usually rises long discussions about should we do it? Should we not do it? But I think if you work in a team, it helps to have more strict guidelines. So you just get rid of those discussions or you know, someone has to decide.
Robert [50:53]: All right. So time to go back to frameworks. So we already know where more or less we should avoid that. Let’s name it vendor lock in. So we should watch out for frameworks that can become deprecated. Or there are some problems with flexibility. And especially in Go when we don’t have the frameworks that are standard one. So we may be more afraid that something will be deprecated or maybe non-flexible. So what do you think are the alternatives in in this case.
Miłosz [51:30]: What worked very well for me before is just modular libraries, you know, just connecting libraries together. And it can also mean internal libraries in your company or in your project, the so-called common package. That’s also considered bad practice sometime. But I think you need some consistency usually. Or you want some consistency across things like, you know API communication, messaging, maybe database as well across projects, especially in a team or across company, usually makes sense to have some standards around this. So you don’t have just wild west, everyone doing whatever they like. But the difference is, instead of this one framework that you have to fit into the project, you just you use the libraries for where they make sense and sort of like building blocks or puzzles. You just pick what you need and leave the rest. And if something changes or breaks or you want to remove one thing, it’s quite easy to do. And I think what’s also very nice is you hide the complexity from like whoever uses the API. I had this experience of setting up a code base in a company in Go, and I took this approach. And for example, we used Watermill for messaging, and I hid it behind internal library. And there were all the bootstrapping, all the settings and so on, which can be quite complicated if you use some Pub/Subs. And the nice part is, you know, my colleagues didn’t need to know exactly how it worked, although it was documented and quite easy to grasp. But as a user of a library, you usually want very small API, right? So for example, if you use an HTTP router, you don’t want to, you know, work with the internals of the protocol. You just want to say /users GET and that’s my function. And that’s it. You don’t want to configure it further unless you want to do something more specific. So then you can. But I think it’s a nice design philosophy in general to have small APIs.
Robert [54:16]: Yeah, and I think in practice it’s not that hard to usually do that. Again, we’re mostly talking about Go now, but I think often it may sound like rocket science. And I think a lot of people are really promoting frameworks like it’s helping me to create stuff so fast. And yeah, you can also if you go to the frameworks websites, you can also see some big logos using those frameworks. But you know, don’t be fooled by that that much because I’m not sure if you know how often getting some logos on your website work, but you know, if you have some colleague working at some big company, you can ask him to use your library or framework in this company, and later you can put this logo. So, you know, it’s often more like that instead of, you know, I don’t know, some Airbnb using some big framework, so you know, it can be just used in some back office application used by couple people in the company, and it’s fine.
Miłosz [55:20]: Sometimes if you read those stories, it seems like the framework is the success behind the company or something. And when I read this I feel envy because, you know, I would like to be as a successful as they are. So maybe I will use this framework. But most of the time it just gives you this boring boilerplate. That’s quite nice, but also not life changing usually.
Robert [55:51]: And sometimes even opposite from my experience. I mean, I’ve seen some projects where again, it wasn’t that it was couple months to remove the framework. It was rather impossible to do that even. I think I would find some projects that I built. I use a framework and sorry for everybody who is maintaining it now, but I was young and I was optimistic, but I’m pretty sure that if they was able to get rid of that, that’s great, but I’m pretty sure that they didn’t. And it’s probably a mess to.
Miłosz [56:25]: What we didn’t cover yet is in-house frameworks, which can also be a trap because then you have no one maintaining it if you don’t do it.
Robert [56:38]: So I think it’s probably some balance between some internal libraries and that are using something that is pre-built versus frameworks.
Miłosz [56:46]: I really like the internal libraries approach, and especially to hide some open source libraries behind it, behind some API. And one example might be observability. So I think for a logger, you know, it’s I like to expose my own logger type as just a small interface and then use some implementation behind it. And I think you replaced logrus recently with slog in our project. And we used the same approach. And it was quite easy.
Robert [57:25]: Yeah definitely. And probably the same goes for metrics and for tracing. So usually metrics and tracing the interface is not very big. So most of the interface is matter of setup. And but the function to do trace to report metrics. It’s pretty small. So you can and well it looks that those libraries are also changing pretty often. And if you look in the longer time span it it may change again.
Miłosz [57:55]: And the metrics and tracing calls will be scattered all over your your code base. So if you stick to the. You just import the library directly everywhere. You will need to redo it everywhere the same way. And maybe not a big deal. You know you can just do some search and replace or whatever, but it’s much easier if you stick to your own interface and then just replace the implementation behind it. And that’s quite a nice outcome. And you don’t need a framework for this separate package.
Robert [58:31]: And what’s also nice is that you can also hide a lot of flexibility that those libraries are often supporting. So you can expose a simple interface without a lot of complexity flexibility. And it can also standardize how, for example, you are doing metrics.
Miłosz [58:50]: And maybe one counterexample for frameworks or we can have from our own is Watermill. Right. So for people who don’t know Watermill is our event driven library, and we especially had this idea in mind in the beginning to make it not frameworky at all. So the idea is that you should be able to replace it with anything else you want. And of course, it depends on how tight you couple your application with it. Hopefully you don’t. But yeah, that was the idea from the beginning. And I think it it works pretty well right now in our projects we could just, you know, throw it away and use something custom.
Robert [59:42]: And yes, I think it’s nicely answered the question that I mentioned earlier. So how that you can understand if something is coupled to your application by understanding how easy you can remove that. And for example, if Watermill. Well, you can do it pretty easily because you can still keep some application using Watermill and consume messages by any programming language practically. And it will be just compatible because under the hood you have messages on some message broker of your choice and it’s compatible with everything and vice versa. For example, if you have some event driven system that is already there, you can implement Watermill into that because Watermill is not doing anything specific basically.
Miłosz [01:00:27]: Yeah.
Robert [01:00:32]: One more thing that is also interesting about if you think about frameworks and I think it’s visible in the different languages, maybe you heard sometimes the let’s say title like Spring developer, Symfony developer or whatever. And it’s actually kind of makes sense because there are people that are let’s say experts in all this framework works and how to use that.
Miłosz [01:01:01]: I remember like ten years ago, there was a big part of software houses were using Ruby on Rails, for example. I bet they hired experts. So it made sense. Or maybe still makes sense sometime. But…
Robert [01:01:21]: I think it’s one big downside because you know, those framework knowledge how it tends to become out of date. So you know you can spend days weeks or learning something about framework, but it can be outdated. And if you switch to go to other programming language or to other company, a lot of effort that you spend to learn stuff, it will be just wasted. Because this is not, let’s say, universal knowledge that you can put in other projects. So I think it’s also worth mentioning that I would not really recommend to specialize in some frameworks, because you can use your time more wisely.
Miłosz [01:02:08]: And you can learn some patterns that are unique to the framework. And for example, if it supports messaging, you can you could learn how to send a message and receive it, but you don’t learn how it works underneath. So maybe it’s a better idea to learn even driven architecture, because you know the theory behind it and how it works in general, because it’s better transfers to whatever you will do later. And maybe in general, some more timeless skills like how to split modules in your application, how to make it decoupled, how to write business logic so it’s easy to read and modify.
Robert [01:02:55]: Yeah. And there are a lot of discussions now like will AI replace us or whatever. So I would say that if somebody will be replaced. So probably as framework developer, I would be afraid the most because this actually something in what AI is pretty good. So about having the knowledge about all the quirks about frameworks, how to use some strange use cases and how to connect everything. So it’s an example. So I don’t like to write front end, but AI is actually pretty great in that. So if I’m for example, using react and there are some magical things that I have no idea that they existed, I knows that and can use it pretty nicely. And I can imagine that there are people that have all this knowledge how it works. But well, I would be a bit afraid that I may have less, let’s say, job opportunities. And again, it’s also the risk that it will be out of date and from other side. LLMs are not that great in things like design, modularization and you know, splitting bigger problems into smaller. It’s still something that you can do better than it.
Miłosz [01:04:10]: And you need to have the knowledge to verify if hat the AI spit out is valid, which is also important. If you do it blindly, it might not end well. So, you know, there are some skills that are here to stay probably whatever you do, like those timeless architecture patterns and so on, which probably make more sense to learn than just one framework and be done with it.
Robert [01:04:39]: And I think it’s also something what we promote, and we also see that it works for us, because I think one of the good examples is the repository An article about repository that we have on our blog. So I think we have written it five years ago, and I don’t remember how many times it was on Reddit on /r/golang, but I think it was again there for one week ago with more than 100 upvotes. And I don’t know, probably, I don’t know, 20,000 visits again. So, you know, we written an article about some knowledge that is universal and it was valid five years ago, and I’m pretty sure it will be valid in next five years.
Miłosz [01:05:21]: So yeah, even if you use AI heavily to, you know, to update your code, I guarantee if you use repository pattern, it will be much easier to work for the AI than to just have raw queries.
Robert [01:05:34]: You know what to suggest to it. Definitely. And so yeah, this this is the approach that we recommend and we see how it works for us. Because you know we’ve been learning from PHP frameworks 15 years ago. And, you know, it’s not helping us that much now. I mean, it was nice because we learned that, okay, things can be built in this way. Some things are possible. But we also from other side was focusing on the things that are universal. And we can just use for longer.
Robert [01:06:13]: All right. So time to summarize what we said today. So the thing that I already mentioned. So I think it’s not like it’s always bad to use frameworks. And especially if you are a beginner, it’s pretty useful because it can make you more productive. And it can help you to focus on things that matters. And later you can try to reproduce that what you seen in frameworks and create your own simple libraries that are doing that.
Miłosz [01:06:47]: Yeah, but don’t become a framework developer. Just focus on more timeless skills and universal knowledge because the framework specific stuff will probably get outdated soon. And if you learn the universal concepts, it’s easier to join a team that needs something similar, but maybe not exactly. In your in your domain. It’s easier to pick up new skills then.
Robert [01:07:15]: Also watch out because I think there is a lot of promotion, let’s say on social media about frameworks. Maybe some is paid, maybe some not. But it’s often focuses on the bright side that okay, it’s making you productive. It’s simplifying stuff. But I think it often misses the long term implications that you see. You will see when you use this for 2 or 3 years, and team will become bigger, and you may being the trouble. And it’s even harder after a time, because you’re spending more and more time on workarounds. And when you spend weeks or months on doing workarounds, it’s pretty hard to just remove them because of skunk. False sunk cost fallacy.
Miłosz [01:08:00]: But it’s useful to have some experience with frameworks. So at least you know how they look like, how they work. Especially with stuff like code organization or modules or observability. So you can maybe recreate it with modular libraries later. And you know, seeing a project suffer from framework use may also be useful because you see where the issues are. And, you know, you can often see it in in products, even if you don’t work there. I think, you know, products where it seems like initially they iterate so fast and deliver to market, and then you log in one year later and it looks the same just because there were some some nice initial speed but then lost over time. And yeah, if you join a project like this as a developer it’s a nice chance to learn some anti-patterns as well, which will help you.
Robert [01:09:08]: And again, if you join such company and in the first week, say, okay, we need to remove this framework and let’s try to do that. Let’s listen to the previous episode because it’s also not if product is in the stage that okay, it’s all coupled and you cannot maintain that. It also requires some proper approach on refactoring that. And yeah, remember that Go is also pretty specific in terms of frameworks, while in other languages there are some well-established frameworks in Go it’s not. And I’m pretty sure that the situation will not change. So in Go in general, we don’t recommend using frameworks as long as maybe there is some proof of concept or maybe some your pet project. So it may be nice to see okay how some stuff can look like, but for bigger project with more people in general were not recommended in long term.
Miłosz [01:10:08]: I can recommend module libraries approach like internal libraries for your company. That usually works works well. You have some consistency. You can do stuff one way, but then easier to throw some things out if you need. You don’t need to stick to it.
Robert [01:10:29]: All right, so is it time for Q&A? So let’s see what’s happening in the chat. Where is chat? Hello. So Go is a great choice to build a LLM powered applications, but it is visible to use Golang for developing LLM models. Viable. Yes. So I think I can agree with that. Go is pretty nice language for building applications that are using LLMs because. So if I would for example compare it to Python. So for LLMs it’s often nice to do some gathering of the data for example asynchronously. And good luck with Python.
Miłosz [01:11:29]: I actually work on this currently for our platform. And yeah, Go concurrency model works is great for this. Yeah, but for developing models, I don’t think I can say anything. We don’t have experience with this.
Robert [01:11:47]: Obviously, but I think, you know, most probably 99.99% people are not developing models. And it’s fine. Like you are not building your own CPU so you can use something that other people did already. I think you can build almost anything in Go, mate. Yeah.
Miłosz [01:12:13]: You can, but as as the next comment says, as Konstantin says yeah. I think Python is the tool for now for most deep learning. So yeah, we don’t have any experience with deep learning in Go. So we can’t really answer this.
Robert [01:12:32]: But yeah probably Python will be the choice. But from some recent news it seems that you can build TypeScript compiler in Go.
Miłosz [01:12:40]: Oh yeah.
Robert [01:12:41]: So yeah, it seems that Rust is not the only option. Actually, it was pretty fun to see how many people were pissed because they didn’t use Rust for that. I actually wondered if any of them used write something in Rust. Or maybe it’s some cult. But let’s leave it. Yeah. Daniel mentioned that I just signed your platform guys three days ago. I want to grasp skills in Go. Yeah, I hope you like that.
Miłosz [01:13:11]: Welcome on board.
Robert [01:13:12]: And yeah, we should also have some actually AI related stuff in our platform. So we should have AI mentor soon. So if you are starting to learn, Go. I think it will be also pretty helpful to with some more complex exercises that we have there. So stay tuned. Okay. The next message. When I think of frameworks in Go, the first one that comes to mind is GoFr, which is super useful for smart and concise microservices with all powers like observability, gRPC, HTTP and queues. I didn’t hear about this one. I’m not sure if you did.
Miłosz [01:14:01]: No, not really. Maybe we just stopped looking at new frameworks in Go? Yeah. I think like what we mentioned before applies. Basically it’s I’m sure it works well. Just be careful if you have a bigger project that will be there for a few years. Just keep in mind maybe you will want to migrate out of it.
Robert [01:14:27]: And updating five microservices is easy, but 50? It’s just much, much, much harder.
Miłosz [01:14:35]: I’m sure it works for many people, for many projects just, you know, keep in mind those cons of it and consider what would you do if you wanted to move out?
Robert [01:14:49]: So thought experiment. Can I remove that easily.
Miłosz [01:14:52]: If it’s just, you know, gRPC, HTTP and queues then it sounds like just inputs and outputs of your application. Maybe that’s if you keep it separate from the business logic. Maybe that’s fine.
Robert [01:15:04]: Yeah. So in other words it’s not MVC framework. So it’s not coupling everything. So it should be easier.
Miłosz [01:15:14]: Okay. The next one how to how do you set up an API project. You expect to be big. Do you follow clean architecture? Do you use a package for dependency injection? Yeah. If we expect the project to be big, then clean arch or sure is what we will use and we will cover this in the next episode in two weeks.
Robert [01:15:37]: But watch out because I think everybody expects that project will be big. Reality is often different.
Miłosz [01:15:44]: So but this is also something we talked about a bit in the previous episode about when to write high quality code because this is similar similar question. Right. I expect this, this product to be to be big, and you have to be careful not to go too much too far with the foundations. So, you know, be wary of thinking like, I need to set up all this foundations now. So later I will just add features and it will be super quick. Most of the time it’s not like this. You will need to refactor the project anyway, whatever you do, because it can change drastically. So it’s better to start with some modular libraries, maybe have some reasonable setup in place, but don’t go too crazy.
Robert [01:16:47]: Yeah, and remember 90% of startups fails. So if it’s startup, you know it will be good to not fail because of you. Spend too much time on making your product future proof. So.
Miłosz [01:17:03]: Yeah, dependency injection. We used the wire from Google before it was sort of okay, but also had some issues. I think later we switched to just doing manually.
Robert [01:17:17]: Yeah, yeah. So wire was nice because it’s code generation based. So I think it’s the best what we used so far, but also it’s kind of become very complex at the end. So we found out that it’s just better to inject by hand because you see what’s happening there. And at the point when you feel that, okay, it’s super hard to inject everything. It may be not a problem of DI, it may be a problem of your code, let’s say. I mean, maybe your dependency graph is too complicated, and maybe this is the problem because I think it’s a good example. DI is a good example that it can surface other problems. And some people may think that, oh, okay, it’s a problem with the DI framework, but in most cases it’s not a problem with DI framework. It’s a problem with your code and dependency graph that you just have too many dependencies, too many interfaces. So the most often we think that, you know, there were interfaces for things that have one implementation and it was injected and it was multiple layers of injection. And, you know, just having it one level in the AI and simplifying it, it just made things simpler.
Miłosz [01:18:35]: So yeah, I think we need to talk about it in the next episode as well. Combined with clean architecture because it’s related. But it’s also nice concept of because if you start on a project now, you expect to be big. I think dependency injection is something you shouldn’t be thinking about. because that’s this kind of overengineering maybe like just, you know, start with some something simple. Now start with manual dependency injection and see, I don’t know, three months how it works. If you know if it’s painful then consider some framework for dependency injection. Maybe the framework library for dependency injection. But before it happens, maybe you are overthinking it. Maybe just start.
Robert [01:19:26]: Start simple and remember that a lot of boilerplate doesn’t mean that it’s something wrong with that. I mean, it’s just boilerplate. Yeah, but as long as it’s manageable, it’s fine. So this is pretty similar to what we mentioned a bit earlier about structs. So if you’re passing values between structs and doing stupid mapping it’s great. I mean it’s not a problem when you have dumb code and boilerplate. It’s actually good because you can understand. And you know, the alternative will be reflection and we will have no idea how it works. So having basic, you know, you can even have 1000 lines of code file that is doing injection. It’s fine. Yeah, you can totally manage that. And it’s easier to manage than you think. And for example, if you for example, you start to have dependency, like some things are starting to be dependent on something, you just often need to move big blocks of code from bottom to top. And you actually can see what dependence, what state. And if something doesn’t work, compiler will tell you it’s bad.
Miłosz [01:20:31]: And yeah, exactly. That’s what my experience with, you know, recent my recent projects with main.go Being 2000 lines long with just project setup. It seems really dumb, but it works. Basically if you extend some constructor, you go to main.go and you press the shortcut in your IDE that says next error. You go there, fill the missing pieces and you’re good to go.
Robert [01:21:02]: Yeah. And alternative with this dependency injection frameworks is often some magic that you don’t understand. Highly recommended to try to do it by hand.
Miłosz [01:21:13]: So sometimes boring is nice.
Robert [01:21:19]: Okay, the next question or comment? We don’t know yet. Actually, we’re reading that without checking what’s there. It’s risky. We’ve been pushing my team toward Cleanish architecture. We have modular monolith modules, use domain driven design patterns, but we break the rules where abstractions are too much overhead. That I think makes sense. So. And it’s also totally fine that we also are doing it from time to time that we were thinking that it will be more complex, but it’s not. And it’s important to again be mindful and see that, okay, it’s not serving anything. Let’s maybe remove domain layer and put everything to application, remove encapsulation. And I know it’s hard to do sometimes when you spend time on that. It’s hard like removing unit tests I know, but it’s sometimes something that you’re doing and it’s it’s fine And it’s nothing wrong in being trying to do, trying to or actually to overcomplicate stuff. Everybody does that. We are doing that. You can try to do your best and you will be doing that. It’s fine. No worries.
Miłosz [01:22:31]: Yeah, we kind of mentioned this in the previous episode about breaking rules, so it’s fine to do it, but it’s best if you know why you do it and that you actually are breaking rules, because if you do it by accident, then it’s much harder to decide when to change the approach or when to fix it. But if you do it on purpose, then it probably is fine because you probably know what you are doing. It’s much better than being dogmatic about something and just, you know, announcing that, okay, today we do everything domain-driven design way and any other approach is is wrong. And that’s asking for trouble because there’s no one approach that works for everything. So yeah, that’s sounds like a good, good approach. Wilson. Okay.
Robert [01:23:28]: There is another comment about LLMS. I think there is a difference between deep learning and LLMS or and also LLM-powered applications, the latter opening up to more languages. And since it is just just a bunch of API calls, Go is well suited. Yeah, I totally agree.
Miłosz [01:23:50]: Yeah, we currently work with with this like adding LLM features to our platform and using it in Go is really trivial. That’s pretty cool.
Robert [01:24:01]: Yeah. And again I think I like to compare it to like CPUs or something like that. It’s pretty similar situation that you are using something done in some totally different technology. That’s totally fine. You don’t need to fully understand. It’s useful to understand how it works. But again, it’s something under the API and it’s encapsulated from you. And you can also kind of exchange that. What are your favorite frameworks and why. Oh that’s interesting. So yeah probably as we said earlier. So we don’t have really framework that we like in go but in other languages. So I remember PHP times and Symfony was quite nice for that time. And I like how modular it was. What else?
Miłosz [01:24:58]: Yeah, I’m having a hard time coming up with something because I usually felt overwhelmed.
Robert [01:25:07]: I won’t mention anything front end.
Miłosz [01:25:11]: Yeah. I think I would just say my favorite approach is having those smaller libraries used together. Not in a frameworky way. So I wouldn’t say I have a favorite framework.
Robert [01:25:26]: Yeah. But yeah, it totally was useful to use from frameworks because you have some reference that you can, you know, how it could look like. So it’s helpful. Okay. I’m not sure. For the file structure it seems go has philosophy for some directories like cmd, pkg. So I wonder what is the correct way to structure an API project for the most cases? That’s the hard one. I think we probably should do episode just about structure structure in your projects because it’s pretty okay.
Miłosz [01:26:05]: It’s okay. This is a follow up to the API project that will grow big. So I think the answer here is very similar to before. Don’t overthink it in in the beginning because you don’t know how the project will grow. Right.
Robert [01:26:24]: Yeah, yeah. But probably it’s something that we will cover in the next episode in two weeks. But I think some sort of simple, clean architecture can work. So just having, let’s say three packages even like application interfaces and adapters and you know, it doesn’t differ that much from just having everything in one package, but it’s already some start and it doesn’t cost that much to do that. But again, probably something to go deeper in the next episode.
Miłosz [01:26:56]: Yeah. So for sure some separation makes sense if you use the clean architecture, but you don’t have to worry about stuff like should you use it in cmd or pkg because there is no official Go guidelines for doing it.
Robert [01:27:12]: There is one package that looks like official, but it’s not official. And I think the Go developers already mentioned that that it’s a bit misleading. I don’t remember the name of that, but it’s something like I don’t remember the you know what I mean?
Miłosz [01:27:29]: Yeah, I know this standard Go layout or something like that.
Robert [01:27:34]: Yeah, some standard Go something. So but yeah, it’s not official. It’s worth mentioning.
Miłosz [01:27:38]: But my point is it’s not that important. You know, if you, if you use src and then you want to migrate to pkg, it’s just you know, you do git move and you will do it for you and you will keep the history of the files. So that’s not the important part. It’s you can look up our wild workouts example. We have some similar structure to clean architecture. But, you know, you don’t have to worry that much about it because you will need to adjust it anyway in the future. So I would avoid this idea of, you know, let’s let’s prepare this, let’s prepare this perfect structure now and in the future we will just add features later. That usually will end bad because you don’t know how the project will change over time. So instead, start with something simple. And you know, if I would take it to the extreme, you could start with a single file and see how long you can maintain it, and then just start splitting it into files. Of course it’s extreme, so don’t do it.
Robert [01:28:42]: But yeah, it depends. How big is your team? If your team is one person.
Miłosz [01:28:45]: Yeah, maybe it’s fine. Maybe you can start with a single package and then then grow. I think it’s much easier because you don’t make assumptions about how the code will look like in two months, because you don’t know, and it will be a surprise probably anyway.
Robert [01:28:59]: But yeah, if, for example, your team is ten people, Some lightweight, clean architecture definitely can help. So.
Miłosz [01:29:05]: Yeah. Yeah for sure. So. But as we mentioned last time, clean architecture can be really simple, right? Yeah, but maybe more on this in two weeks. Yep.
Robert [01:29:18]: All right. Okay. So it was comment for this one. So how it’s connected to being idiomatic. So yeah, it’s it’s good to be idiomatic.
Miłosz [01:29:30]: But yeah this is a controversial topic. You know what’s idiomatic. What’s not idiomatic. Need to be careful with that. So you don’t spend too much time worrying about being idiomatic in Go, which can mean different things. I think we have the fifth episode about unpopular opinions about Go. We have. So maybe maybe more later. So yeah, this is what we have already covered before about the mapping and what is our opinion about GoFr? We mentioned that we didn’t use it, so nothing to add here, I think. Yeah. Daniel says we are doing a great job. You’re welcome. Thanks for joining us. Grzegorz asks if we know Substack. It seems to me that your newsletter should be so accessible. Maybe you will gain new observers. Yeah, we read Substack. At least I do sometime. With our newsletter. We just prefer to be independent, I guess. So we don’t plan migrating.
Robert [01:30:55]: We already did three migrations of our newsletter.
Miłosz [01:31:00]: But the nice part is it was invisible to our readers. And with Substack, you never know. It seems like a, you know, cool platform right now. But it’s also a startup. So, you know, I think a similar thing happened with Medium ten years ago or so when they became very popular, and then they started putting paywalls. And basically, you have no control over how the how your newsletter looks like.
Robert [01:31:31]: And I’m pretty sure that it doesn’t have the all flexibility of newsletter platforms like. So we are doing a lot of things with our newsletter, like the podcast notifications and automations. So there is a lot of stuff under the hood, and I’m quite sure that it may not support that.
Miłosz [01:31:51]: So yeah, so we don’t plan on creating but thank you for the suggestion. You can share our newsletter with your colleagues to help us get new observers. And then Wilson says go fx is great. Why would you ever want to migrate away from it? Okay. I guess you misread GoFr. We didn’t use go fx, right?
Robert [01:32:26]: Yeah. Yeah, but from what I see, it’s So this one, as far as I remember, it was reflect based. So this was probably the
Miłosz [01:32:36]: This is a reactive framework or this is a dependency injection?
Robert [01:32:39]: Dependency injection.
Miłosz [01:32:40]: Okay.
Robert [01:32:40]: So I think I think it was reflect based. So it was.
Miłosz [01:32:46]: Okay. Yeah.
Robert [01:32:48]: So it was the thing.
Miłosz [01:32:49]: So yeah I mean it’s a library, not a framework probably. Right. So you can if you wanted to migrate out of it. It’s probably easier than just a framework.
Robert [01:32:59]: Yeah, yeah. But yeah, in terms of dependency injection again, we it’s not that hard to do it by hand. And it’s super explicit and it’s much easier to work with. So yeah we recommend this approach even again don’t be afraid of big files because it’s really simple to handle.
Miłosz [01:33:16]: So yeah. What are your thoughts on urfave CLI or is there an example to the DIY go CLI program? We like it, right? This is the one we use for the tdl cli.
Robert [01:33:34]: I think I’m just checking because I don’t remember.
Miłosz [01:33:38]: Once, but I think we do. And I think it’s quite cool.
Robert [01:33:46]: Yeah, yeah. So I think that this is our favorite one. So we have our CLI for our training platform and we are using exactly this one. So other alternatives I think there are not that idiomatic if you are thinking about that, but they have also some weird quirks. And this one has a very nice API and just works super nicely.
Miłosz [01:34:10]: So we don’t have an example I think of building a CLI tool.
Robert [01:34:16]: But you can check our CLI tool for platform.
Miłosz [01:34:19]: Oh yeah, you can, you can do it and.
Robert [01:34:21]: I can put it probably to this chat into the screen.
Miłosz [01:34:26]: And our going one evening training has some CLI exercises but it’s very basic so I’m not sure if that’s useful. But thank you for the suggestion. We may maybe we should write some article on this, although I think the documentation should be good enough to start this. Really? Not that much.
Robert [01:34:52]: I’ve put the link in the screen if you would like to see some CLI example, so you can check this one. It’s a framework worth mentioning. I mean it’s if you ask the question how easy it will be replaced with something else. Quite easy.
Miłosz [01:35:07]: So I’m just maybe we speak about CLI frameworks. There’s also the bubbletea the one which I used for the pq library in Watermill. Maybe we can also link it later. I mean, it’s a bit different because it’s for building TUIs, but if you consider building a CLI app, that might be useful.
Robert [01:35:36]: All right. So I think there are no more questions on the chat. So last couple of seconds to leave something and and and. Yeah, it’ll be it’ll be time to finish for today. So as we mentioned a bit earlier. So we have our newsletter. So this is the best way to be notified about new episodes. So if you are subscribing to us on YouTube or any podcasting application actually a couple people asked us when will be available on podcasting applications. So we’d like to record one more episode and we’ll upload all three episodes there. And if you’re listening on Apple Podcasts on Spotify, it means that we already did that. But we highly recommend to subscribe to our newsletter so you will not miss any new episode because, you know, YouTube algorithm or Spotify algorithm. We don’t. We cannot impact if it will deliver you the notification newsletter. You will always know that there is a new episode, and the next episode will be about pretty hot topic about clean architecture, and I think we’ll have a lot of nice insights. So highly recommended to be with us. And also, it will be great to hear your comments on that, because it would be great to hear some external feedback, let’s say, for that. And yeah, if you have any comments questions, please leave it on under the YouTube video or on Apple Podcasts or Spotify. We’ll read everything. And if you can include anything to a new episode, please leave it. Yeah. Don’t remember. Don’t forget to give us a thumb up in the YouTube or five star review in Apple Podcasts and Spotify, so it can help us to reach more people and give us some motivation to record new episodes. And yeah, something more?
Miłosz [01:37:38]: That’s it. Thank you, everyone, for joining us.
Robert [01:37:40]: Thank you. And see you in two weeks. Bye!
Miłosz [01:37:42]: Bye bye