February 27, 2024
When you have 25+ years of experience in software development, you start to see patterns. The repeat more then you think. The same problems, the same solutions, different languages, different frameworks, different tools, different libraries, different patterns.
You come to a point where you start to question the value of the frameworks you use. You start to question the value of the tools you use. You start to question the value of the languages you use. You start to question everything. You don't give a shit more about clean code, but you do it anyway, because it has been drilled into you. You try different tools/frameworks/libraries, even languages, and yet same results. You just try to find right tool for the job. You just want the job done as quickly as possible.
Don't get me wrong, it like Superhero Ability, but you just don't get excited anymore. You just want to build it. Move one to next thing. Possibly, complete different thing.
When I started base, I was experimentin with Flutter Flame. Trying to clone some games I was playing in my phone. I did some game mechanics, some playable game, and got bored. Then I was lets do a GraphQL project in Go. I might need for my future games, for saving leader board, or some other game related data. I was never meant to be shared publicly, just internal tool to use inside basecode. I did baseQL. Made some mutations, queris and types and went to sleep. Next day, I was like, lets make a cli generator for baseQL, so I can generate modules instead of repeating thing.
Then shit went deeper. I felt like hardcore developer, one that I never thought I was. In there I felt experience. It was so easy to make that.
Then I was requested to build Albafone app. I took great risk and started in base. It was just some simple crud app, but I was like, lets make it in base. I started to add features, then a big mess was created. Huh, it's refactoring time, I thought. I wanted to be clean, so I can reuse for other projects. I wanted to have main.go, app and core folder in root. I do business logic in app folder, and core folder for core logic, so I can reuse core for other projects.
I was looking if there is any popular directory structure for Go, but I didnt like namings. internal, handlers ... so unknown to me. I was like, lets go rails way, but hmvc instead.
So app/{module}/controller.go, app/{module}/service.go, app/{module}/model.go. Whoop whoop, Circular Dependencies error. Never heard of it before. Then
app/models/{module}.go. All models in app/models folder. This way I can call them anywhere via
models.{module}.
I'm gonna miss OOP, I thought, I loved app = new App(), and do app.methods(), then I discovered package keyword. So package app and package core. package is like namespace in other languages. I could call
package.method(), and it would work.
Reorganize directories to support packages.
On main.go I was initializing app packages, and core packages, but I wanted to have cli generator for modules, so I created
app/init.go and core/init.go files. Everytime I run base g post, it would add module to
app/init.go. Then main.go got to large, so I created core/start.go. Basically,
core/start.go will run app/init.go and core/init.go files. Boom, it worked. Now I have clean way to initialize modules, and clean way to start application, and clean way to generate modules. Mission success.
I was looking on Albafone requirements, we had file upload, and image upload, and user authentication, send emails, middlewares, etc. I started to make them as core packages. Stared with database. Found gORM. Perfect. Tried to replicate ActiveRecord pattern, but I didn't work. I cannot chain in Go. So no
User.all(), User.find(), User.create(), User.update(),
User.delete(). That was kinda disappointing. Still couldn't get out of OOP mindset. Then dug into gorm.io docs, and found gorm.io/docs/query.html and gorm.io/docs/associations.html. Then I was like, lets make it work. It wasn't that hard, to do queries, and relationships.
I wanted to be third-party agnostic, so I created database package to work with all SQL databases. I also created storage package to work with all file storage. I didnt know if I will save files locally, or on cloud, or on S3, or on R2, or on any other storage. So I created storage package to work with all file storage.
Same for email package. I wanted to be third-party agnostic, so I created email package to work with all email providers. I didnt know if I will use smtp, or sendgrid, or mailgun, or postmark, or any other email provider. So I created email package to work with all email providers.
Same for logger package. I wanted to be third-party agnostic, so I created logger package to work with all logger providers. I didnt know if I will use console, or file, or syslog, or any other logger provider. So I created logger package to work with all logger providers.
Albafone required user authentication, and I loved how Laravel has it built-in. I want it to be built-in in Core, So I can reuse it for other projects. Then I wanted to have OAuth too, so built-in that shit too. It started to take shape. Albafone went live. I created an backend with language I did not know, for industry I did not know. That was the risk.
Most feature that sold me on Go was its deployment. I didn't want to deal with server setup, LAMP, or install passenger, or nginx, or apache, or any other server.
go build -o main main.go and run it on server. Damn, that was the best feeling. ~30 Mb binary with 49 endpoints, and I can run it on any server. Sold.
I extracted base from Albafone, refactored it, and made it open source. I called base because it was the base of my projects. I wanted to make my life easier, and easy prototype backend and api for next projects. I worked on 2024 on tools, mostly. They are shared with the works at dev.base.al. I really home some one can use it, and make it better. I am where I am, because of open source. That's why I write code I write, structure app the way I structure it. So making base open source, is just a way to give back to the community that shaped me.