According to Wikipedia, “Muntzing” is the practice of reducing parts in an electronic appliance to the minimum required for it to function. At it’s core, Muntzing is about simplifying by challenging core assumptions. Muntz rejected the assumption that his television sets had to work everywhere. By designing them to work only in areas with a strong signal he could leave out expensive components needed to pick up weak signals. With fewer components, his sets needed less power and didn’t overheat as easily. They were then much cheaper. All this because he challenged one basic assumption.
Thanks in part to Go, single-executable programs are becoming more popular. Replacing Ruby or Python scripts with compiled, binary executables makes deployment much easier. Programs can be compiled, copied to the destination server, and run without the need for installing a full runtime platform. Compiling dependencies into the binary also avoids having to install a package manager like Pip or Bundler. Compiled programs are, in sum total, much smaller than scripts, since a full runtime platform and standard library are not necssary. They are also faster since optimizations can also be applied in ways impossible with scripts.
One of the most interesting languages I’ve toyed with is K. K is a vector programming language like APL and J and makes several major departures from mainstream languages. It favors terse expressions with short variable names, forcing the programmer to examine the whole expressions rather than the individual pieces. Compared to API and J, K has very few operators. Higher-order operators provide additional functions. K elides common functions like filter and reduce in favor of highly orthogonal and composable operators. For example, filtering a list to even-valued entries is done as follows:
Graphviz is a handy tool for visualizing graphs and networks. It uses a graph specification language called Dot. Dot is both readable by humans and generable by machines. The Graphviz toolset includes several executables for rendering Dot code into PDFs or images. Each program renders the Dot code using different layouts. Graphs are extensively customizable. Graphviz is a good platform for quickly mapping out an entity relationship diagram or the structure of a system. It’s much quicker to write out the relationships in code and generate a visualization than to drag shapes and draw the diagram manually.
Unix introduced the concept of chaining program outputs to the inputs of other programs via pipes.
For example, the commands
cut are very simple and focused, but using pipes they can be composed together to do non-simple searches.
cat file.txt | grep 2015-04-23 | cut -f5
This example finds the fifth tab-delimed field of lines in
file.txt matching the given date.
Unix-like systems have a large toolbox of small programs that can be connected together.
Often I’ve used pipes to write a program that would have been non-trivial in a scripting language.
One of Haskell’s key features is lazy evaluation. Expressions are not evaluated until they are needed. This is also a valuable technique for writing programs. For example, rather than writing all the lowest-level database code first, start with user-facing code and work down through the layers of the application, writing only the code that has to be written to support the top-level changes.
There are also other ways to consider laziness in programming. Larry Wall considers it one of the three virtues of great programmers. Laziness is also a weapon against the temptation to prematurely optimize.
The Flipboard Engineering blog has a nice outline of using the HTML canvas element to create animations and interactions that can’t be done with a plain, DOM-based webpage. Even with HTML5 and CSS3, some transitions and effects still aren’t possible, but you can have pixel-by-pixel control over the canvas element. Compared to the HTML and CSS API for rendering a webpage, the canvas drawing API is incredibly small. Unlike SVGs, which are driven by a DOM structure, canvas renderings don’t retain any information about what’s been drawn to them, which makes rendering to a canvas extremely fast.
Make is a long-standing build utility. It allows build commands to be specified in terms of the files they depend on. If a dependent file has changed, the commands are run; if none of the files have changed, the output is considered up-to-date. It’s a much faster build pipeline than many modern tools, such as Rake and Grunt. Make has become my preferred way to document what shell commands build, test, and run my code, especially in compiled languages. Make steps can also be parameterized. The basics of Make are reasonably straight-forward, though mastery may take time.
cURL is a convenient command line tool for making HTTP requests. While it’s easy to make a GET request from the browser, other request types are more difficult. cURL only requires a flag:
curl http://localhost:3000/items -X POST
cURL can also send custom headers. One of its most valuable features is the ability to interact with other programs over pipes. The body of a request can come from standard input, and the HTTP response can be piped into another command. Browser web inspectors often have an option to copy a network request to the clipboard as a cURL command.
The Io programming language is small in size (in order to be embeddable) and simple in syntax. Like Smalltalk, objects in Io pass messages to each other. Unlike Ruby’s syntax for message-passing, Io’s is not disguised as C-like method invokation. For example,
signal send("Hello World")
Judging by the Lindy effect, Vim will be around for another quarter century. Vim’s keyboard-based navigation, reliance on editor commands, and various different modes makes learning the editor difficult but pays dividends to those who stick with it. I’ve used Vim in a terminal without mouse integration for several years, and find I’ve learned how to move through the text and make changes faster than I would with a mouse. Fingers on a keyboard builds muscle memory in a way that pinpointing pixels with a mouse never can, and editing text anywhere else feel incredibly limited.
Facebook’s React introduced the pattern of using a virtual DOM to construct and update a webpage. The solution is elegant, but the implementation is tightly integrated into React’s core. Instead, use virtual-dom, a minimal library that does DOM diffing without need for the much larger React. Using virtual-dom is as simple as creating a virtual DOM tree, attaching it to an actual DOM node, then when changes are needed, generating a new virtual DOM tree, diffing against the old one, and applying only the changes that are needed to the actual DOM.
The Pareto principle is popularly known as the 80⁄20 rule—that is, 80% of the effects come from 20% of the causes. It’s useful to remember that not all tools or tasks are equal in value and effort. Often an easy task can be disproportionately valuable while a small improvement takes a surprising amount of effort. The relationship between effort and value is non-linear. An old joke states that the first 90% of a project takes 90% of the time and the last 10% of a project takes the other 90% of the time.
Git includes the
bisect command, which performs a binary search between two commits to find when a problem was introduced.
git bisect start bad-commit good-commit
Git then updates the working directory to a revision between the given commits.
Tell git whether the current revision is good or bad with
git bisect good or
git bisect bad.
Git will then update to another commit and repeat the process.
Git can run the search automatically using a script that returns particular exit codes for good and bad revisions.
git bisect start bad-commit good-commit git bisect run test-script arguments
Tmux has allowed me to structure my terminal sessions and move between them more quickly than using plain terminal tabs or separate windows. Instead of having a series of top-level tabs, I can create separate, named Tmux sessions for separate workspaces. Each session has namable windows, for me usually one for command line operations, one or two for Vim, and one for long-running daemons. Each window can have panes or splits for side-by-side viewing of processes. Using keyboard commands also speeds switching windows and sessions.
The Lua programming language is designed to serve as an embedded scripting language for larger, compiled applications. Where LISP languages use lists as the universal data structure, Lua uses tables. All other data structures can be built from tables and meta-tables. Unlike the Python or Java virtual machines, which use stack-based instructions, Lua uses register-based instructions. Lua supports first-class functions, lexical closures, tail call optimization, and coroutines. The base language is designed to be easy to adapt to specific purposes. The reference interpreter is only 180 kilobytes.
An interesting feature of Haskell is that all functions take only one argument. Multi-argument functions are an illusion. Whenever a two-argument function is needed, Haskell instead defines a function that takes a single argument and returns another function. The returned function takes the second argument and returns a result. All multi-argument functions are extensions of this pattern. When doing the final computation, all the arguments that have been passed in are in scope thanks to function closures. Haskell thinly hides this behavior in its syntax. Closures enable Haskell to have multi-argument functions while technically only supporting single-argument functions.
One of my favorite features of Haskell and other ML-inspired languages, such as Elm, is their support for algebraic data types (ADTs). ADTs are, in part, small data structures, but they can be combined, unpacked, and dispatched on in ways most statically typed languages don’t offer. For me, it took hands on usage of ADTs to really appreciate them. They provide a very natural way to express what various values are, without resorting to heavy-handed or over-sized classes.
Tony Hoare’s concept of communicating sequential processes (CSP) is heavily used by the Go programming language and has been adopted by Clojure under the name
CSP is a remarkably simple pattern for handling multiple things at once.
As the name implies, it’s formulated on separate, co-running processes that communicate and coordinate with each other over synchronous channels.
CSP allows a language to break out of being either synchronous or asynchronous and be both.
CSP is the feature I miss most in languages without it.
Among other things, the Go programing language was designed to compile and run very fast. A lot of new server software is taking advantage of its performance. Critics argue it’s missing some important features, such as generics or memory management. I, however, feel Go’s designers have chosen the 36% of functions that meet 96% of the needs, and not tried to meet the last 4% of needs by complicating the basic conceptual architecture.
Developers often laud some tool or other for giving them a lot of leverage. The focus of Small, Fast, & Simple is not just tools that give a lot of leverage, but tools that provide extreme leverage. Screwdrivers offer leverage, quite a bit, but it isn’t extreme leverage. Many of the features offered by modern programming languages and frameworks are not long levers, but marginal offerings that make the tool a little easier to use. SFS is about Archimedes-style move-the-world length levers; techniques, structures, and paradigms that—all on their own—offer the wide range of capabilities needed.
GNU Stow is listed as a package manager, but I’ve been using it as a simple way to stay on top of my dotfiles, both system-wide dotfiles in my home directory, as well as project-level dotfiles scattered throughout the filesystem. Rather than commit project dotfiles to the project repo, I prefer to keep them in a central location where they can all be version controlled together. The command
stow -t ~/code/project project-dotfiles
symlinks files and directories in
project-dotfiles into the
The Stow executable is 28 kilobytes, and doesn’t depend on any Ruby or Python installation.
Hugo has become my de facto static site generator.
It’s written in Go, so it’s a single executable and recompiles very quickly.
In development, Hugo automatically refreshes browser windows.
Setting up a new project is easy (
hugo new site such-and-such).
Make sure to include a theme or a layout template, or you’ll get
Hugo uses Markdown and Go’s HTML templating language, and abstracts HTML out of your content using shortcodes.
Hugo compiles your static site to a single
public directory, which can be pushed to GitHub Pages without all the source files using
git subtree push --prefix=public origin gh-pages
I’ve come to prefer first-class and higher-order functions with closures in place of classes and objects. Nothing will stop you from writing large functions, but you’ll face more resistence than you will writing large classes. The interface for a function is well-defined and battle-tested: values are passed in, values are available from the enclosing scope, and a value is returned. By contrast, every class in an object-oriented system tends toward being a snowflake whose interface has to be studied each and every time. Many common OOP design patterns can be replaced by functions.