Learning Go, creating an IDE and confusing language points

0

(Note, this is the start of my Medium friendly posts, so away go the bulleted and numbered lists which it doesn’t support at all and up with headings and subheadings. Hat tip to Blog2social for a nice plugin that cross posts).

Creating a Go environment: Github

Well another month, so another language, have to learn Go in order to work on some code, so here are some tips about how I do, first some limitations about it. The default is basically to do a brew install golang on a Mac and you are ready, but to really make it robust, here are some suggestions.
Go likes to live in a place ~/go or you can set it with GOPATH if you want something different, this makes it easy to test code natively. But if you want to send the running code to someone else, then you should make sure that whatever is in that directory is a GitHub repo. Go’s emphasis on imports that use URLs (which is pretty cool that import github.com/richtong/go/lib actually works properly, this is pretty portable.

Creating a runtime environment: Docker

But what about actually delivering code and preventing all those dependency disasters (oh what version of Go do you have on your other machine problems). I like to run almost everything in a docker container when it is going to be used by other.    It’s a big hat tip to having a public URL even for your companies code, so you can load it anywhere in the world.
Why Docker? This seems to be one consistent way to remove all the local machine dependencies, this takes longer to setup, but it means that anything I do can be docker pull and then run nearly anywhere, on a Mac with Docker for Mac, on Windows, on Linux or in the cloud with Docker Cloud.
It is really convenient to use the new layered Docker system, so most of my go programs are literally a 5MB container instead of having the entire development system in it. The trick is to run a development container and then a run-time container. If you look at the Dockerfile below, it loads the 500MB golang development environment, then copies everything in the current directory to it and then builds the application. To create the runnable container, you just copy executables into a minimal Alpine image and you are done. This is one of the great things about Go, it has everything loaded into one binary, you don’t need to worry about LIBPATH:

FROM golang:alpine as build-env
LABEL maintainer=”Rich Tong”
ARG USER=golang
# take all current files and move them into the container
ADD . /src
RUN cd /src && go build -o goapp
# Now take the build and put it in the container
FROM alpine
LABEL maintainer=”Rich Tong”
WORKDIR /app
COPY –from=build-env /src/goapp/ /app/
ENTRYPOINT ./go-app

Writing Go Applications: Vim IDE

Everyone has their own development environment. Some use Sublime, others like Emacs or JetBeans, but for me, the easiest has been vim. One important detail is how to handle the lint and compilation, in this case vim-go seems to be the standard tool. So installation is pretty easy. I’ve been using Pathogen, but the cool kids are now using vim-plug, so this is a good time to edit, so you need to add this to your ~/.vimrc file assuming you are on a Mac or Linux:

if empty(glob(‘~/.vim/autoload/plug.vim’))
silent !curl -fLo ~/.vim/autoload/plug.vim –create-dirs \             http://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
autocmd VimEnter * PlugInstall –sync | source $MYVIMRC
endif

Then inside your .vimrc file, you can now add the vim-plug modules:

” https://github.com/junegunn/vim-plug
” – Avoid using standard Vim directory names like ‘plugin’
call plug#begin(‘~/.vim/plugged’)
” https://github.com/fatih/vim-go/blob/master/README.md#install
Plug ‘fatih/vim-go’, { ‘do’: ‘:GoUpdateBinaries’ }
” Initialize plugin system
call plug#end()

Then when you are done, you need to execute :PlugInstall in vim if you didn’t add the ~/.vimrc otherwise the .vimrc does it for you. Now you can run these extra commands in Vi. I”m finding these work well, except there is some strange problem with :GoLint

Compile your package with :GoBuild
Install it with :GoInstall
Test it with :GoTest.
Run a single test with :GoTestFunc.
Quickly execute your current file(s) with :GoRun.
Debug programs with integrated delve support with :GoDebugStart.
Completion support via gocode.
gofmt or goimports on save keeps the cursor position and undo history.
Go to symbol/declaration with :GoDef.
Look up documentation with :GoDoc or :GoDocBrowser.
Easily import packages via :GoImport, remove them via :GoDrop.
Precise type-safe renaming of identifiers with :GoRename.
See which code is covered by tests with :GoCoverage.
Add or remove tags on struct fields with :GoAddTags and :GoRemoveTags.
Call gometalinter with :GoMetaLinter to invoke all possible linters (golint, vet, errcheck, deadcode, etc.) and put the result in the quickfix or location list.
Lint your code with :GoLint, run your code through :GoVet to catch static errors, or make sure errors are checked with :GoErrCheck.

Learning Go (the web server way vs printf)

I’m sure every language looks a bit weird compared with any other language, but as I’ve learned about one new language every six months (?!!!) over the last three years, some observations:
All programming books seems to start with some variant of printf("Hello World\n) which seems a bit weird when the real standard application is a web server. I’m pretty sure that in this day and age, the standard bit is more about figuring out how to start with two things. First,
How to make a web server that you gets from http://localhost:8000 and let’s you POST to it, so it can display “hello world”. If you look at the code fo that web server (Python/Flask, Node/Express, Go/net) and they all look pretty similar. For instance, here is a short Go Web server thanks to Golang, Hackernoon and thenewstack.io. It doesn’t get simpler than this where you call http to create an anonymous function handler and then start it with ListenAndServer, there is even logging built in:

package main
import ( "net/http", "fmt", "log" )
func main() {
    http.HandleFunc("/hello",
        func(w http.ResponseWriter, r *http.Request) {
             fmt.Fprint(w, "Hello World")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

To see what I means, let’s take the same example written in express.js for node using the latest ES6 (aka ES2015) variant of Javascript:

const express = require('express')
const app = express()
app.get('/hello', (req, res) => res.send('Hello World!'))
app.listen(8080, () => console.log('server on 8080'))

And finally Python with Flask (not the latest framework, but representative):

from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
    return "Hello World!"

Making Printf

The second how do you create something like printf which accepts any number of arguments and any number of types. To me, this shows you how the whole type system works rather than the way too simple example of a person with a first and last name. With Go this is done with interfaces

Related Posts

© All Right Reserved