Software development, quantified


I can help your business with my expertise in the following areas:


Once a business process is modeled, it can be both forecast and actively managed.

Software development is commonly regarded as being very difficult to either forecast or actively manage. However, even it can be modeled. One model I created allowed a company to forecast individual projects to within ±20%, and an entire year of work to less than ±5%, even on teams that were convinced that development could not be meaningfully estimated.

Reliable forecasts allow for better control. When that company took on its largest effort ever—involving nearly 100 developers spread across two departments and about a dozen teams—the model and an additional scheduler allowed managers to quickly and accurately see any schedule risks. This enabled conversations and trade-offs before schedule got out of control. In the end, the project was delivered “basically on time and on spec,” the first in the company’s history, and helped them win a $50M contract.

Models can also highlight where a business should focus its improvement efforts, by showing how sensitive a process is to changes in different variables. For example, in software development, development time, cost of labor, expected benefit, and uncertainty of all of those, all affect potential net return of a project, but uncertainty of time typically dominates all other factors by one or two orders of magnitude.

Numerical methods

Among other uses, numerical methods are a common tool when you want to minimize the cost (or maximize the benefit) of a business process.

Gradient methods are good candidates when the shape a function is known analytically, although some functions are easier to minimize than others.

One project I worked on had a function whose minimal valley had a lot of unusual twist in it, causing standard methods to converge slowly. I developed a new approach that allowed the descent to “skip ahead,” allowing it to navigate the valleys better, and cutting total runtime by 50%.

Derivative-free methods are ideal when the function is noisy or otherwise not well-behaved.

Another project I worked on had an error function that was analytical, but very steep near the minimum, and surrounded by a “hill,” causing gradient methods to shoot off or wander out to infinity. Using the Nelder-Mead simplex algorithm guaranteed that the optimizer could not wander from the optimal valley, but the standard implementation still couldn’t converge reliably. I modified the algorithm’s steps to consistently converge and terminate.

Performance optimization

I’ve applied optimization techniques from assembly-level to data-structure and algorithm selection, and everything between. Sometimes, low-level techniques like honoring cache locality can result in all the speed-up necessary. Even dynamic languages like Python and Ruby can benefit low-level techniques, including (surprisingly!) bit-boards, although these languages also bring their own unique performances challenges and tricks. Other times, existing systems such as databases need to be better leveraged, machine performance tuned, or better data-structures and algorithms used.

Typical speed-ups I’ve seen on projects range from 20% to 10×, with a few instances going to 40× or beyond.

Machine performance

Optimizing machine performance can provide immediate, inexpensive, and wide-spread savings. Comparing class-equivalent disks between popular cloud providers can show performance differences of at least 20%, with cost differences being less than 5%. Filesystems can be optimized in many ways to reduce overall I/O requirements. Sometimes, selecting the right I/O scheduler can mean the difference between expensive, provisioned-I/O disks and much more cost-effective standard disks. Tuning memory use and striking the right CPU/RAM balance can also cut the number of machines required.

Data structures & algorithms

Using the right data structures and algorithms can make the difference between intractably slow and nearly instantaneous. I have experience with implementing and applying a wide variety of data structures and algorithms, in both low-level and high-level languages.

As one example, a schedule-planner would have taken an astronomical time to finish, even though it used A* search. Adding a beam-width limit and a good-enough criteria to the planner brought run-times to less than a minute, while maintaining reasonable bounds of optimity on its found solution.