From .NET to Go: The Meaning of the Bloat is Revealed to the Bloat Itself

I checked my LinkedIn profile recently because I wanted to make posts about the articles I write on this blog, when I saw that my last post was 10 months ago at this time (27 Jul 2026), and it’s about a project I made in ASP.NET.

This might be surprising if you had a chance to check the articles and projects I have on this blog because the only code snippets are either in Go or C, and all my projects are made in Go.

So I decided to larp about my transition in this article.

Catalyst

One day, a long time ago, while I was finishing up a project using ASP.NET with DDD Architecture, I saw, I forgot if it was a video or an article, but it was about socket programming in C. And, I’m not going to lie, I got a little bit intimidated because I realized all I know about the stack I’m currently using is implementation steps of a framework, and I don’t really know what actually happens.

I didn’t know HTTP, I didn’t know what a pointer is, I didn’t know that a bitwise AND is faster than modulo when the divisor is a power of two. All I did was create the same bullshit CRUD application over and over again with a different theme, focusing more and more on Domain-Driven Design Architecture to the point where a CRUD app for creating food recipes was 10k lines of code.

As an example, let’s say we have one recipe “model” (I hate this term now), and all the API is doing is CRUD operations. So, I believe somebody who just wanted a food recipe app would define the endpoints, make a couple of DB calls there, and be done. What I was doing was creating a repository using the Unit of Work pattern, splitting my reads and my writes using CQS, taking a step further and decentralizing my services and repositories using CQRS with commands and queries, dependency injection for everything, a separate Domain model with Value Objects, API contracts, DTO models, the Result pattern (which I still like, ngl), and unit testing all the small bullshit functions.

After I saw that article/video about an HTTP server made in C from scratch using Berkeley sockets, and I actually managed to create one myself, I realized how much work I was putting into bloating my projects. Yeah, you can argue about DDD being bloat or not. Yeah, it has its benefits in terms of big teams working on projects. Yeah, whatever. It’s just not for me, and it made all projects I worked on the same. It made programming feel like cooking, following a recipe without knowing why I do the things that I do, because I never encountered the issues these patterns were created to fix, and I learned that most of them do not even exist.

Finding out about Go

While the pipe dream of switching everything to C, making everything from scratch, and understanding all details to the bit was pretty empowering, I soon realized that creating thousands of lines of code for parsing HTTP was also not the solution. I completely flipped to the other side of the spectrum where the level of nativity was still the same. This realization came halfway through creating an HTTP parsing library in C, which was way out of my skill set, not necessarily in terms of understanding it, but in terms of time and scope. It’s just not feasible to create everything from scratch even though you will learn a lot more doing so. But then, if you spend 3–4 months on a parser, are you really learning at the rate you could be if you just made small, example-ish projects just to prove the point and see it happen with your own eyes?

I kept hearing about Go and people comparing it to C, and about how it was made by Robert Griesemer, Rob Pike, and Ken Thompson, and its balance between actually getting things done and still keeping it at a lower level than most languages, so I decided to check it out.

Fast forward

Due to the simplicity and the “one way to do a thing” Go provides, the no-inheritance data model, and the function receivers, I stopped caring about “Architecture” and realized that so-called architecture, as I was perceiving it, was just a middle manager for my software. I was finally actually creating solutions to problems to achieve what the use case needed.

If it fixes an issue and it’s performant enough for the use case, why should I split it in 100 classes, why have classes in the first place? It’s right in the middle of creating everything from scratch in C and higher level languages, in terms of using structs for your data and having control over what gets passed around as a reference or value. The concurrency model I find far more hands-on than what async/await languages provide, but more thread-safe than pthreads.h, and having the runtime managing OS threads leaves me far back enough where I don’t have to worry about managing OS threads directly in the most efficient way they could be.

I know this will sound corny, but I think I would’ve given up on programming if I kept using C# and .NET libraries. Because the actual issue, leaving everything aside, it’s not the bloat, it’s not the 10k lines of code for one CRUD operation, it’s not f****g EF Core. It’s the soullessness. I know a lot of people will be insulted by this, but I’m talking about my own experience: using C# felt like being a web janitor. I could not keep myself interested enough to finish a simple CRUD API with token authentication because everything was done for me. I was not learning anything but the hierarchy of the library and the available models and functions it provides.

Conclusion

If you like .NET and C# and it satisfies your goals, keep on using them. I know most people just want a high-paying job, work on a big team, drink flavored water, have meetings, and so on. I get it.

But if you really want to understand what’s going on and have an easier time expressing yourself in code, make a TCP server from scratch, even in C#. Make a sockets chat, make a relay server for it, make a parser. Don’t attempt to create your own production-ready libraries for it unless you really actually want to compete with the existing ones, but make it good enough to understand the issue and the solution. Because if you only learn solutions to problems you don’t encounter yourself, you are just following a recipe.