exploring a problem solving design space

This post started out as

because I was trying to write about designing a DSL that deals with variables with multiple values. Continue reading

How does Ruby do X?

The answer can usually be found with ruby -rdebug or ruby -rtracer. There is also the trick with RUBYOPT. If you are executing something with bundler then you can run RUBYOPT="-rdebug" bundle exec ${command} and you will be dropped in the debugger as usual.

good design through abstraction lowering

Many times when I run into buggy software and peek under the hood I notice that the design is convoluted and confused. Ther are modules with cross-cutting concerns, there is no obvious flow for the inputs and outputs, and there is no set of core abstractions that everything else builds on.

Now compare this to something that is well designed. There is usually a core set of abstractions and associated operations for building up larger computations to accomplish a goal and the rest of the software is built upon those core components. Parser combinators and optimizing compilers are good examples of such software. The flow of the computation is obvious because there are explicit and clear steps that transform high level abstractions and operations into successively lower level ones until everything is expressed by the core set of abstractions. So to understand the whole you just need to understand the core components and how they are combined. There is no reason more general applications can not be built this way. In fact most enterprise architectures with their layered approach are trying to do exactly this but fall short for one reason or another.

production grade branching policies

Most software shops these days use github or some other variation of git as a service and integrate with any number of CI as service pipelines to do testing and general sanity checking. This is fine except most places do it at the wrong level of granularity by using pull requests. Pull requests can work fine but they don’t provide enough structure. For example, you can have two outstanding pull requests that have no conflicts and pass all CI checks in isolation but one breaks as soon as the other is merged. A theoretical concern but can happen if the entire branching/merging workflow is based around pull requests. Over the years I’ve seen a few branching models in various source control systems. Most either overconstrain the workflow and add too many annoyances or they don’t constrain enough so there is no structure to exploit and build tools around. I think this happens because the technical people don’t think about what they want out of their source control policies or they let non-technical people design it and it turns into a bureaucracy because most people think of bureaucracies as structured systems. Continue reading

production grade logging

Logging to sockets is better than logging to files. It allows for more flexibility in terms of log rotation and data integrity. I started looking around for examples of this but everything these days when it comes to logging is built for the enterprise. The actual skeleton of what all those enterprise systems are doing is quite simple. In fact it is so simple that you can do it in less than 30 lines of code in most high level languages. Here’s the skeleton for a logging server in Ruby: Continue reading