Category: Software Engineering

I recently started exploring Go for some of my side projects and was really struck by its beauty.

I realized how beautifully it made a balance between ease of use (generally associated with dynamically typed, interpreted languages), and performance and safety (type safety, memory safety etc) (generally associated with statically typed, compiled languages).

Apart from these, two more features make it really the perfect language for modern systems development. Both these features are explained in more detail in the Strengths section below.

One of them is first class support for concurrency in the language (through goroutines and channels, explained below). Concurrency, by its design, enables you to efficiently use your CPU horsepower. Even if your processor just has 1 core, concurrency’s design enables you to use that one core efficiently. That is why you can typically have hundreds of thousands of concurrent goroutines (lightweight threads) running on a single machine. Channels and goroutines are central to distributed systems since they abstract the producer-consumer messaging paradigm.

The other feature I really like about Go is interfaces. Interfaces enable loosely coupled or decoupled components for your systems. Meaning that a part of your code can just rely on an interface type and doesn’t really care about who implements the interface or how the interface is actually implemented. Your controller can then supply a dependency which satisfies the interface (implements all the functions in the interface) to that code. This also enables a really clean architecture for unit testing (through dependency injection). Now, your controller can just inject a mock implementation of the interface required by the code to be able to test if it’s doing its job correctly or not.

Notice: This solution only works if NGINX and PHP-FPM both reside on the same server.

A ‘git pull’ on a live server for deployments isn’t ideal since all files don’t change on the disk at the same millisecond. A request that starts on one version of the code might access other files which could be updated during the request. To get truly atomic deployments, PHP deployment applications like Capistrano have a symlink pointing to the current build and simply update the symlink to the new build once the new build folder is ready. Since Linux doesn’t itself have any disk cache, changing the symlink to point to the new build is atomic. At the same millisecond, all files in the symlinked folder now point to their newer versions.

This build process has some issues.

The setup:

1) NGINX(the web server) and PHP-FPM(PHP FastCGI process manager) both reside on the same server.

2) NGINX serves from the document root(/var/www/app.com) which is a symlink to the current build.

2) Visitor requests https://app.com/hello.php. Nginx proxies PHP-FPM and asks it to execute /var/www/app.com/hello.php. PHP-FPM returns output of the above script to NGINX and NGINX serves it back to the visitor.

3) PHP Opcache is a cache with maintains a mapping of (script path -> machine code translations). This cache prevents interpreting PHP code again and again and makes a lot of difference in performance.

4) PHP’s Realpath Cache is a cache containing path mappings for relative file includes within PHP scripts. It also makes a lot of difference in performance if a lot of ‘require/require_once’ and ‘include/include_once’ statements are used in the scripts.

The problem

The last step in the build process is changing the symlink. On changing the symlink, FPM was still executing PHP scripts from the old build folder.

So you just wrote a bash script and you’re scared of running it on your system due to a lurking rm -rf statement in the script. Here is some stuff you can use to prevent disasters due to unhandled errors in your scripts:

1) Use set -u (Just put set -u at the top of the script):

In this mode, the script will exit if we try to use an uninitialised variable. Useful for preventing rm -rf $uninitialized_variable/ type disasters

This translates to rm -rf / if this mode is not on and will destroy your whole system.