DEV Community

Juan Pablo Ramirez
Juan Pablo Ramirez

Posted on

Distributed Rant Series Part 2

Continuing with my "discussion" and following the guide that I started in my last post I would like to introduce my own personal choice for structuring go projects.

So what's the long term goal:

  • Build Client / Server applications.
  • Has to be web based.
  • Has implement Security standards
  • Has to be cross platform (lets cover non mobile OS for now)
  • Keeping it as simple as possible...

Follow this Github repository to keep track of this project.

So... let's get started.

[ CODE PART STARTS HERE ]

My development environment:

  • Ubuntu 19.04.
  • go1.13.1 linux/amd64

For me getting used to GoLang GOPATH (later versions) was complicated, as an old Python developer, projects were all encapsulated in virtualenv and other horrors. ( Don't get me wrong, I love virtualenv)

But I must admit that getting the order that GoLang required from the start boosted my productivity, solve a few issues, and reduce for sure many headaches.

So my environment will start always here:


/home/{user}/projects/src/

Clone my repo

➜ git clone git@github.com:jpramirez/go-web-starterpack.git

Cloning into 'go-web-starterpack'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
Receiving objects: 100% (4/4), done.cd go-web-starterpack
➜  go-web-starterpack git:(MakefileInit) ls -ltrh
total 4,0K
-rw-r--r-- 1 shellcheff shellcheff 2,4K nov  8 12:30 Makefile
➜  go-web-starterpack git:(MakefileInit) 


I was never a fan of C, C++, Makefile, deps and all that, made my brain hurt just by thinking about it, so many dependencies, so many variables, files, libraries... Why someone will create such a horror!!...

Now.. to be honest the best way to start working with Go for me was a makefile.

Easy, plain, no BS, is somehow pretty standard to any Linux environment.

Lets check that file then


TIME=$(shell date +"%Y%m%d.%H%M%S")
VERSION=0.1.1-alpha-0.8
BINARY_NAME=go-webstarter-go.v1

BINARY_NAME_SERVER=go-webstarter-server.v1


BASE_FOLDER = $(shell pwd)
BUILD_FOLDER  = $(shell pwd)/build

FLAGS_LINUX   = CGO_LDFLAGS="-L./LIB -Wl,-rpath -Wl,\$ORIGIN/LIB" CGO_ENABLED=1 GOOS=linux GOARCH=amd64  
FLAGS_DARWIN  = OSXCROSS_NO_INCLUDE_PATH_WARNINGS=1 MACOSX_DEPLOYMENT_TARGET=10.6 CC=o64-clang CXX=o64-clang++ CGO_ENABLED=0
FLAGS_FREEBSD = GOOS=freebsd GOARCH=amd64 CGO_ENABLED=1
FLAGS_WINDOWS = GOOS=windows GOARCH=amd64 CC=i686-w64-mingw32-gcc CGO_ENABLED=1 

GOFLAGS_WINDOWS = -ldflags -H=windowsgui


init: 
    @mkdir -vp $(BASE_FOLDER)/assets
    @mkdir -vp $(BASE_FOLDER)/build
    @mkdir -vp $(BASE_FOLDER)/cmd
    @mkdir -vp $(BASE_FOLDER)/config
    @mkdir -vp $(BASE_FOLDER)/extras
    @mkdir -vp $(BASE_FOLDER)/pkg/constants
    @mkdir -vp $(BASE_FOLDER)/web
    @mkdir -vp $(BASE_FOLDER)/third-party
    @mkdir -vp $(BASE_FOLDER)/api
    @mkdir -vp $(BASE_FOLDER)/vendor
    @echo "Creating Base Files" 
    @touch $(BASE_FOLDER)/pkg/constants/version.go
    @touch $(BASE_FOLDER)/vendor/packages_windows.txt
    @touch $(BASE_FOLDER)/vendor/packages_linux.txt
    @echo "# README BASE " >> $(BASE_FOLDER)/Readme.md







check-env:
    @mkdir -p $(BUILD_FOLDER)/dist/linux/bin
    @mkdir -p $(BUILD_FOLDER)/dist/windows/bin
    @mkdir -p $(BUILD_FOLDER)/dist/arm/bin
    @mkdir -p $(BUILD_FOLDER)/dist/osx/bin
    cp -R config $(BUILD_FOLDER)/dist/linux/
    cp -R config $(BUILD_FOLDER)/dist/windows/
    cp -R config $(BUILD_FOLDER)/dist/arm/
    cp -R config $(BUILD_FOLDER)/dist/osx/
    cp -R extras $(BUILD_FOLDER)/dist/linux/
    cp -R assets $(BUILD_FOLDER)/dist/linux/


## Linting
lint:
    @echo "[lint] Running linter on codebase"
    @golint ./...


getdeps:
    ./getDeps.sh


versioning:
    ./version.sh ${VERSION} ${TIME}

build/weblayer-linux:
    cd cmd/WebServer && ${FLAGS_LINUX} go build -o ${BUILD_FOLDER}/dist/linux/bin/${BINARY_NAME_SERVER} .


run/dev:
    cd build/dist/linux && bin/${BINARY_NAME_SERVER} --config config/config.json

build/dev: check-env build/weblayer-linux run/dev

clean:
    rm -Rvf build/dist/

startover:
    @rm -fr $(BASE_FOLDER)/assets
    @rm -fr $(BASE_FOLDER)/build
    @rm -fr $(BASE_FOLDER)/cmd
    @rm -fr $(BASE_FOLDER)/config
    @rm -fr $(BASE_FOLDER)/extras
    @rm -fr $(BASE_FOLDER)/pkg
    @rm -fr $(BASE_FOLDER)/web
    @rm -fr $(BASE_FOLDER)/third-party
    @rm -fr $(BASE_FOLDER)/api
    @rm -fr $(BASE_FOLDER)/vendor
    @rm $(BASE_FOLDER)/Readme.md

So a few take away are:

One makefile is all you need to jump start your project, will create the appropriate folders, README and directory structur.

➜  go-web-starterpack git:(MakefileInit) make init
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/assets'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/build'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/cmd'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/config'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/extras'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/pkg'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/pkg/constants'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/web'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/third-party'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/api'
mkdir: created directory '/home/shellcheff/projects/src/github.com/epyphite/go-web-starterpack/vendor'
Creating Base Files
➜  go-web-starterpack git:(MakefileInit)ls -ltrh
total 48K
-rw-r--r-- 1 shellcheff shellcheff 2,4K nov  8 12:30 Makefile
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 build
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 assets
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 extras
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 config
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 cmd
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 web
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 third-party
drwxr-xr-x 3 shellcheff shellcheff 4,0K nov  8 12:45 pkg
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 api
drwxr-xr-x 2 shellcheff shellcheff 4,0K nov  8 12:45 vendor
-rw-r--r-- 1 shellcheff shellcheff   15 nov  8 12:45 Readme.md
➜  go-web-starterpack git:(MakefileInit)

As you notice we created a few folders and a few files, lets try to explain a little bit.

  • build

This folder will be use as output of any compilation and building, we can then divide it into distributions, operating systems and flavor ( we get to that later )

  • assets

In this case assets will hold anything http/web related. Such as css, images, js, vue.js and templates.

  • extras

Anything "extra", such as tls and ssl certificates, tool configurations, or things needed to run. In our particular project this will be TLS certificates.

  • config

Configuration file in json for our app. We will get to this later, but lets just say it easy to have a config/config.json available.

  • cmd

From go standard "Main applications for this project." that means minimal code to run our application.

  • web

Here I will put all the code related to a webserver implementation, and any webapp. Usually I like to divide webserver.go with webapp.go. But we will get to that later.

  • third-party

Reserved for any plugin, auxiliary library, or later in this series protobuf libraries.

  • pkg

THE MAIN LIBS goes here, all the code for our app, implementations, classes, storage drivers etc...

  • api

Will hold any specifications, like swagger or protobuf (later)

  • vendor

Coming from python I rather prefer to have my package.txt file. Don't get me wrong vendoring in Go is mature, I just... don't like it enough. And so far for me has been easier and simpler to get a vendor folder with a few txt files listing my dependencies.

Again, this is my preferred way to order my code and projects, makes it easier for me to handle and specially to spin projects fast.

In my next posts I will show you how to use this structure to easily spin a web server, create a configuration files, build and package it :)

[ CODE PART ENDS HERE ]

[ RANT PART STARTS HERE ]

Today is Friday... So will not be a rant directly associated with this post...

I wish you all happy coding, and PM me for comments or fixes :)

Top comments (0)