Random thoughts on API design

This excellent book by Steve Krug was a real eye opener when I chanced upon it a few years ago.

image

I’m not a UI/UX designer by trade or by training, and as a backend developer my appreciation for UI/UX has very little outlet in my day-to-day job either. But still I find plenty of symmetries between UI/UX design and API/library design.

Don’t Make Me Think

When it comes to API design, I always cast my mind back to this talk by Joshua Bloch.

Slides

In this talk, Joshua outlined a set of characteristics of a good API:

  1. easy to learn
  2. easy to use, even without documentation
  3. hard to misuse
  4. easy to read and maintain code that uses it
  5. sufficiently powerful to satisfy requirements
  6. easy to evolve
  7. appropriate to audience

Reading between the lines, the first 4 points essentially boil down to a simple rule – that we should appeal to human intuition, and closely resembles the usability study concept of affordance.

An affor­dance is a qual­ity of an object, or an envi­ron­ment, which allows an indi­vid­ual to per­form an action. For exam­ple, a knob affords twist­ing, and per­haps push­ing, whilst a cord affords pulling.

– Wikipedia

or in other words, the easiest and most obvious way to do something should also be the right way to do it.

Just as a great UI guides you towards your goal – be it buying a flight ticket or finding a hotel – a great API design should also guide you towards meeting your data needs.

However, just as in the real world, Software is full of failure examples…

image

and some advices in Software are just as applicable in UX too.

Explicit is better than implicit.

Flat is better than nested.

– Zen of Python

image

Just as UX experts can conduct UX studies by watching users interact with a UI and tracking their eye movements, etc. Perhaps as an industry, we should also conduct usability studies on our API offerings? We can measure how quickly developers are able to successfully perform a set of tasks that require them to interact with the API in various ways. For instance, how many attempts it takes them to correctly retrieve the data they’re after.

Type Directed Development

In a statically typed language, good use of types goes a long way towards expressing and communicating the assumptions and limitations we as API designers have made. Many functional languages such as F# are very well suited in this regard thanks to their power type systems.

For inspirations on what’s possible and how to apply them in practice, see the following talks.

Scott Wlaschin on DDD with the F# type system

image

Edwin Brady – State, Side-effects and Communication in Idris

Lambda Days 2015 – Edwin Brady – State, Side-effects and Communication in Idris from Erlang Solutions on Vimeo.

Edwin Brady – Verifying Stateful and Side-Effecting programs using Dependent Types

Slides

Joshua also talked at length on a number of principles you should follow to help you design a good API. Whilst the talk is based on Java, many of these principles would be familiar to any functional programmer too.

  • API should do one thing and do it well
  • API should be as small as possible but no smaller
  • Implementation should not impact API
  • Minimize accessibility of everything, maximize info hiding
  • Minimize mutability
  • Subclass only where it makes sense
  • Design and document for inheritance or else prohibit it
  • Don’t violate the principle of least astonishment
  • Fail fast – report error ASAP after they occur
  • Use appropriate parameter and return types
    • use most specific possible input parameter type
    • don’t use strings if a better type exists
  • Use consistent parameter ordering across methods
  • Avoid long parameter lists
  • Avoid return values that demand exceptional processing
    • zero-length array, not null

Many others have said before that good OO is very similar to FP, but the problem remains that mainstream OO languages such as C# and Java doesn’t do a good job in guiding you towards writing good OO.

On Complexity

As software developers, we’ve all been taught that maintainability is important but so often I find it difficult to think about maintainability in clear, unambiguous ways since complexity itself is in the eye of the beholder. We have invented many tools and metrics to help us measure complexity, but none gives us a complete and accurate view of it.

Furthermore, software engineering is not only an engineering activity (in fact, Alan Kay argued that our standards and practices fall way short of those expected of an engineering discipline) but also a social activity.

Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations

– M. Conway

Adam Tornhill also demonstrated a number of techniques that use our commit histories to unveil hidden complexities that arise from the way people work together.

If you have dependency between software components developed by different people, then you essentially have dependency on people. Just as the communication between software components is a source of complexity, so too is the communication between people responsible for these software components.

Complexities can creep into your API in any number of ways, e.g.

  • complexities with the underlying domain leaking through
  • impedance mismatch between the API’s designed use case and users’ actual needs

Having worked with no less than 25 of AWS’s APIs, we have encountered a number of such complexities. And since we are not in control of the APIs themselves, so we do the best we could to manage and mitigate these complexities with the use of DSLs.

Take a look at the following slides on some of these complexities and the approaches we took.

Links

Warning, Conferences ahead!

Hello, it’s been a while since I last wrote, work has kept me busy for a while – we’re making some interesting changes and experimenting with Docker again, so fun fun fun!

Anyhow, I thought I drop you a note to tell you about some of the cool conference that are happening around Europe in the next few months.

 

F# eXchange, London

This one is very close to home and to my heart, the first F#-only conference in London on the 17th April. The line up is amazing, full of people who have done amazing work to push F# forward and contributing towards the F# OSS ecosystem:

and we still haven’t even mentioned Tomas Petricek, Evelina Gabasova, Andrea Magnorsky, Robert Pickering, Ross McKinlay and Riccardo Terrell!

Of all the conferences I’ve listed here, this is definitely the one I’m looking forward to the most.

image

 

Lambda Days, Krakow

Happening this Thursday and Friday, 26th – 27th Feb, is Lambda Days which  brings together a whole host of experts in the FP space. The conference has an entire track dedicated to research talks, which is amazing to see and an approach that I wish more conferences would adopt.

Lambda Days covers a diverse range of languages – F#, Scala, Clojure, Erlang, OCaml, Elm, Haskell and Idris. Bryan Hunter is on the programme committee, so you know it’s gonna be good!

image

 

QCon, London

Another big tech conference in London, spanning across 3 days from 4th – 6th March. This year’s QCon again covers all the host topics in the industry, ranging from IOT, reactive programming, microservices to DevOps and Docker.

Some awesome speakers are on show – Dan North, Martin Thompson, Kevlin Henney, Randy Soup, Pieter Hintjens, Howard Chu and Adam Tornhill (whose Code as a Crime Scene talk is well worth watching) just to name a small handful.

image

 

LambdaCon, Bologna

Over in Italy on the 28th March we have LambdaCon, which is the first FP-only conference in Italy I believe.

With 4 tracks + 2 workshops, covering quite a number of FP languages – F#, Scala, Clojure, TypeScript, Elm, Elixir, Erlang, Haskell and Rust – this one day event is one of the best value for money around. Tickets are almost sold out, so hurry up and get the last couple of late bird tickets.

Besides all the conference stuff you get to do, let me also say that Bologna’s reputation as the food capital of Italy is definitely well earned!

image

 

Craft, Budapest

A two day conference on the 23rd – 24th April that brings together speakers from some of the biggest tech companies on the planet – PayPal, Netflix, Twitter, Google, LinkedIn, ThoughtWorks, Atlassian, JetBrains and Red Hat.

Not to mention some of the most respected people in the industry – Michael Feathers, Michael Nygard, Mitchell Hasimoto, Jessica Kerr, Dan North and Erik Meijer!

image

 

Joy of Coding, Rotterdam

A one day conference on the 29th May in Rotterdam, the full programme is not out yet, but the list of confirmed speakers looks promising already.

image

 

With so many awesome conference coming up, I’m excited to be able to learn from some of the best people in the industry (and burn a hole in my holiday allowance along the way..).

 

Hope to catch you at some of these events!

Project Euler – Problem 68 Solution

Problem

Consider the following “magic” 3-gon ring, filled with the numbers 1 to 6, and each line adding to nine.

Working clockwise, and starting from the group of three with the numerically lowest external node (4,3,2 in this example), each solution can be described uniquely. For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12. There are eight solutions in total.

image

By concatenating each group it is possible to form 9-digit strings; the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16- and 17-digit strings. What is the maximum 16-digit string for a “magic” 5-gon ring?

Solution

(see full solution here)

 

Before we go into details on the solution, let’s first structure the question in a way that’s easy for us to compute.

To construct the magic circle, be it for a 3-gon or a 5-gon ring, we can slice up the numbers into pairs – e.g. A => [1; 2], B => [3; 4], C => [5; 6], D => [7; 8], E => [9; 10] – and the problem becomes finding ways in which the numbers can be permuted such that:

  1. a0 is the smallest amongst a0, b0, c0, d0, and e0
  2. the sums of a0 + a1 + b1, b0 + b1 + c1, … are the same

For example:

image

 

First, we’ll find the different ways the numbers 1 to 10 can be permuted, and for each permutation slice the numbers into pairs:

image

(this makes use of a permute function defined in the Common.fs source file in the solution).

 

Then we need a function to sum a pair of number with the last element in the adjacent pair – e.g. a0 + a1 + b1:

image

 

For each permutation, we need to check:

  1. if a0 is the smallest amongst the head elements
  2. if the sums of the groups of 3 – i.e. a0 + a1 + b1, b0 + b1 + c1, etc. – are the same

image

This predicate function allows us to find arrangements that meet our criteria. All that’s left is to turn the result groups of 15 numbers into 16/17-digit strings and find the maximum (see full solution below).

 

Here’s the full solution:

image

 

This solution took 26s to execute on my machine.

Project Euler – Problem 64 Solution

Problem

All square roots are periodic when written as continued fractions and can be written in the form:

image

For example, let us consider ?23:

image

If we continue we would get the following expansion:

image

The process can be summarised as follows:

image

It can be seen that the sequence is repeating. For conciseness, we use the notation ?23 = [4;(1,3,1,8)], to indicate that the block (1,3,1,8) repeats indefinitely.

The first ten continued fraction representations of (irrational) square roots are:

?2=[1;(2)], period=1

?3=[1;(1,2)], period=2

?5=[2;(4)], period=1

?6=[2;(2,4)], period=2

?7=[2;(1,1,1,4)], period=4

?8=[2;(1,4)], period=2

?10=[3;(6)], period=1

?11=[3;(3,6)], period=2

?12= [3;(2,6)], period=2

?13=[3;(1,1,1,1,6)], period=5

Exactly four continued fractions, for N <= 13, have an odd period.

How many continued fractions for N <= 10000 have an odd period?

Solution

(see full solution here).

 

Based on the algorithm on continued fractions from Wikipedia, we can implement the expansion algorithm as:

image

From the Wikipedia page:

The algorithm can also terminate on ai when ai = 2 a0, which is easier to implement.

which corresponds to the termination condition we have in the Repeat active pattern (which also checks if the accumulator is empty):

image

Also, this algorithm doesn’t work on numbers that are perfect squares, i.e. 4, 9, 16, … hence we need to exclude them when searching for our answer.

Here’s the solution in full:

image

 

This solution took 92ms to execute on my machine.

Project Euler – Problem 80 Solution

Problem

It is well known that if the square root of a natural number is not an integer, then it is irrational. The decimal expansion of such square roots is infinite without any repeating pattern at all.

The square root of two is 1.41421356237309504880…, and the digital sum of the first one hundred decimal digits is 475.

For the first one hundred natural numbers, find the total of the digital sums of the first one hundred decimal digits for all the irrational square roots.

Solution

(see full solution here).

The premise of the problem itself is fairly straight forward, the challenge here is down to the way floating points are implemented on computers which lacks the precision necessary to solve this problem. So the bulk of the research went into finding a way to generate an arbitrary number of digits of a square root.

As usual, Wikipedia has plenty to offer and the easiest solution implementation wise is this solution by Frazer Jarvis.

image

which translates to:

image

The rest is really straight forward, with the only tricky thing being the conversion from char to int since this returns the internal integer value instead – e.g. int ‘0’ => 48 and int ‘1’ => 49 – hence the need for some hackery in the sum function.

Here is the full solution:

image

 

The solution took 95ms to complete on my machine.