A couple of weeks ago I had the genius idea to rewrite SnailLife in Go. I’ve already looked into doing this once before a couple of years ago, but wasn’t really feeling it and stuck with PHP (mostly for nostaligia reasons). Now though, SnailLife is this bloated PHP app. Most of the core functionality is in. After weeks of battling infrastructure issues, when everything was back up and running again, I took a step back and saw how big the app (or rather the 3 apps now) had become. At the same time I’d been reading in passing about Go and became curious, so I figured - why not look into learning Go by rewriting SnailLife? Not because I think Go itself will necessarily make anything better, but because a rewrite might.

The features are mostly already designed, reimplementing them in another language would hopefully let me focus more on improving the overall project structure while learning the new language of choice. Of course, the “learning the new language of choice” part also increases the likelihood of my turning my messy PHP app into a messy Go app as I go, but…it’ll be fun, OK?

Anyway, I’m not yet sure if I’ll stick with the Go port or if I’m just amusing myself for a while before going back to the already largely implemented PHP version. So far I haven’t coded anything snail-specific and have instead been focusing on setting up database-related packages. I’ve made the code public on GitLab for now, though not sure if that’ll change when I go into writing the more snail-specific functionality: https://gitlab.com/drakonka/gosnaillife

When I started the PHP version of SnailLife, I started by building the website and the main functionality that lets users interact with their snails. As time went on this focus switched almost exclusively to the back-end, and to working on functionality that required no user interaction. I realized that this is what the core of the idea was - simulating the actual snails - the brain, organ function, etc - things that the user could eventually influence indirectly, but things that would tick away on their own even if no user was involved. So for the Go version I am not starting with a web front end but with a simple CLI, and focusing on implementing the core of the snail itself first. Eventually I can build whatever front-end I want, or even multiple front-ends if I feel like it. Heck, I could even expose some sort of API for others to make their own apps on top of the simulation (if anyone wanted to, in theory).

Go notes to self

  • Open and close DB connections as little as possible - the driver handles connection pooling for you, you should only really need to do it once.
  • Best way of reusing constructors between tests might be to create some test utilities outside of _test files which are imported only by the tests. Example usage in my case is creating a test db and table to run my mysql and repo tests against, which are in different packages.
  • Every directory is a package. There is no way to structure code in subdirectories without each subdirectory being a separate package.
  • Make use of table driven tests. They allow you to run multiple test cases per test.
  • interface{} is an empty interface and can hold values of any type…avoid passing this around too much, better to learn to structure the code so you don’t have to.
  • Go code looks to be very easy to move around and restructure if needed, so it should be fine to experiment with different project structures as I go.

Current tentative directory structure:

├── cmd
│   └── snaillifecli
│       └── main.go
├── config
│   ├── dev
│   │   └── database.json
│   └── env.conf
├── lib
│   ├── domain
│   │   ├── item
│   │   └── snail
│   │       ├── snail.go
│   │       └── snailrepo.go
│   ├── infrastructure
│   │   ├── databases
│   │   │   ├── database.go
│   │   │   ├── mysql
│   │   │   │   ├── delete.go
│   │   │   │   ├── insert.go
│   │   │   │   ├── mysql.go
│   │   │   │   ├── retrieve.go
│   │   │   │   ├── tests
│   │   │   │   │   └── mysql_test.go
│   │   │   │   └── update.go
│   │   │   ├── repo
│   │   │   │   ├── repo.go
│   │   │   │   ├── repoutil.go
│   │   │   │   └── tests
│   │   │   │       ├── repo_test.go
│   │   │   │       ├── testmodel_test.go
│   │   │   │       └── testrepo_test.go
│   │   │   └── tests
│   │   │       └── testutil.go
│   │   ├── env
│   │   │   └── env.go
│   │   ├── init.go
│   │   ├── init_test.go
│   │   └── util
│   │       ├── collection.go
│   │       └── err.go
│   ├── interfaces
│   └── usecases