Jump to content

The Day in a Life of a Dude Writing a VPG in Go.


Recommended Posts

Having written VPGs in PHP since the dawn of time and using various languages like java (misc stuff), ruby (misc stuff and websites), python (because I *thought* it was cool), C++ (everything under the sun for no reason), C# (3D and 2D games), and various other languages. I decided it was time to embark on writing more than just small tools or automations in Go. Prior to this I've written parts of a cryptocurrency, various tools to help myself as a linux administrator, a web hosting control panel (for a LAMP stack), and a couple of other odd things. So yeah, this should have been just easymode.

Outputting page header content, page body content, footer content, and considering the API for the phone app.

From the beginning of this project I decided I'll be releasing a phone app along side the website for accessibility. The problem I ran into was directly due to how the `net/http` package was made. The idea is one function, one action, one result. It is better gears toward microservices and APIs than to a full fledged website. So I had to write a router that did the following:

- Register page functions to mapped URLs
- Regster page header and footer functions to be ran before and after page functions based on a template map
- Pass a special context variable so that the header/page/footer functions can all pass an transaction structure from function to function

I used a template tool I made a while back so I could parse HTML like the xtpl library I loved in PHP: https://github.com/protosam/vision

MySQL Models... Good Luck!

The first thing I began to build was the user registration and login. Something I greatly loved using in PHP was ORMs that followed an ActiveRecord pattern. I built one myself a while back called catalyst that I used a lot: https://github.com/Igknighted/acid/blob/master/drop/components/catalyst.class.php

This is easier said than done in Go. One of the most popular solutions made for Go is called GORM and it is quite a hideous entanglement of method calls. I spent 3 weeks making design considerations on how to tackle this. Eventually I landed on just giving in and learning the `reflect` package. With `reflect`and `database/sql` I ended up writing a structure called MODEL. Now all I have to do is embed MODEL in any new structures I make and there's some reflect magic that will allow it to generate CREATE TABLE, INSERT, UPDATE, SELECT, and DELETE queries. This was not easy at all and due to constraints, I had to add a field in MODEL called `context` with type `*interface{}`. Before I can use one of my model structures, I have to something like this:

user := model.User{}
user.Init(&user) // This is a method in MODEL that will make a reference to the super.


Extra Data Between Functions

Still on the quest to make user registration and login, I managed to make the registration. Now it was time to login! In the HEADER template function that gets ran before the PAGE content function, I wanted to figure out user login there. I had to expand the http transation structure by adding a variable and 2 methods to it. The variable was `storage map[string]interface{}` and the methods were `SetCtx(key string, i interface{})` which would store data in storage and `GetCtx(key string) interface{}` which would return an interface from storage. There was a huge compromise here, but it turns out I managed to do something interesting on accident. My user variable gets created by an Init_User() function so I don't have to manually type user.Init(&user) every single time. Normally to interact with your pointers in go, you have to do something like `*ptr_var = val`. It turns out that with a pointer to a structure doesn't need this type of coddling: https://tour.golang.org/moretypes/4

Go figure! Originally I was manually passing by reference to SetCtx and expecting a pointer back from GetCtx. Considering the special way that structures worked, I just swapped the original *interface{}'s for just interface{}. 

Still Questing... but...

These are all things that are already considered by design in PHP for example. You don't have to think hard about these things at all because type conversion is magic. Once you step foot into a statically typed language like C/C++/C#/Java and Go, you open yourself up to dealing with complex things that are very hard to account for. Even though I've managed to work something out for these first 3 major hurdles, I'm not confident I've accounted for edge cases that could arise. Heck, the MySQL ORM I created makes some pretty bold assumptions on data types all around!

I wanted to share my experience here, for those that are considering stepping away from PHP, hack, Ruby, or Python. While statically typed languages are great, they are not what you would generally want to write you game site in. They are super powerful, but you're going to have to put more time into dealing with the basic things that are already well handled in PHP and the like. You should greatly consider what your reason for something like this might be. In my case, I want to use Go specifically for some of the features I'll be delving out in the future and I want every feature to be as easy to deploy as possible. So I want a single binary that I'll be dumping onto servers I arbitrarily spin up. I don't want to be configuring my environment at the end of the day, which Go will allow me to ignore the environment at the cost of doing extra work.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...