Understanding compression oriented programming and 'writing usage code first' methodology

So after watching some handmade hero and reading some of Casey's blog posts, I'm really excited to try and start thinking and working with the compression oriented mindset. However, I'm trying to understand how his two ideas of compression oriented programming and 'writing usage code first' come together.

In his compression oriented blog posts Casey says to first write the simplest code you can that works and then go back and 'compress' duplicate code into functions/structs where appropriate. This way the code can sort of guide you to creating appropriate functions/structs for the situation at hand. Then if you find you need to expand your api later on you should always at least consider just writing new functions on top of the functions you've already written, instead of going back and changing your original functions. This way your api won't have any granularity discontinuities meaning that there will always be lower level functions to supplement higher level functions in case someone needs to access some lower level functionality.

However he also advocates to ALWAYS write the usage code first and work towards those original ideas of how the api should be structured. Don't these two ideas sort of conflict with one another? If I'm trying to think of functions/structs to write for my api from the start, then I'm sort of pre-planning my api design instead of letting the code guide me to what's appropriate. So when I'm I suppose to have the compression oriented mindset and when should I be trying to write the usage code first?

Edited by Jason on Reason: Initial post
Designing a good API is hard.

It's a balancing act between easy to use versus easy to implement.

Most people tend to go from the implementation side. This tends to create APIs that are hard to use.

Creating some usage code directly creates at least one set of functions required for 1 straightforwards path to using the code.

Test Driven Design (write testing code first) tries to do the same thing (focus on usage over implementation) however easy to test does not equate to easy to use.
boagz57
However he also advocates to ALWAYS write the usage code first and work towards those original ideas of how the api should be structured. Don't these two ideas sort of conflict with one another? If I'm trying to think of functions/structs to write for my api from the start, then I'm sort of pre-planning my api design instead of letting the code guide me to what's appropriate. So when I'm I suppose to have the compression oriented mindset and when should I be trying to write the usage code first?


The amount of up front work you can do in designing an API depends largely on how trivial (to you) that API is going to be. If fairly trivial then you may be able to do the whole thing up front on paper. If not so trivial, then usage code is a perfectly good starting point and obviously some iteration will be required.

I haven't read the compressions oriented post but I presume that the basic idea is something like, wait until you actually know that more than one part of your code base will need to use a given function/module before creating a more generalized function or public interface.

Wether you start with usage code or data structures and public functions doesn't make a whole lot of difference because you're going to have to iterate either way. The usage code will likely change in response to you structs and public interface changing while your public interface and structs will likely change in response to your usage code changing.

Okay. So it seems like both will kinda be used interchangeably depending on the situation. Maybe if your completely new to a domain, it would make sense to just start writing very simple code and see where it takes you. If your working with some more familiar domains, then you might already have an idea what a decent api would look like so you can start there.
Balancing between easy to use and easy to implement is good. You also want it to be intuitive to read and easy to understand so you can easily maintain, and expand on the functionality. I think the times I've shot myself in the foot by trying to make something clever far outweighs the times I've actually benefited from it.

My approach to interface design is as follows.
What's the minimal amount of information I need to provide, and how would I like to provide it.
We know at least some of the data we need to provide and the lifetime of that data, so it's easy to at least get started.
Another thing to think of is optimizability, how easy it would be to optimize a piece of code without having to rewrite the use code. But have to weigh the pros and cons.
Bozemoto
Balancing between easy to use and easy to implement is good. You also want it to be intuitive to read and easy to understand so you can easily maintain, and expand on the functionality. I think the times I've shot myself in the foot by trying to make something clever far outweighs the times I've actually benefited from it.


Writing clear intuitive APIs that are easy to understand and maintain is more just a trait of a good/mature programming style than it is some kind of tradeoff consideration. Of course there's always the tradeoff of doing something relatively "correct" vs. implementation speed but that goes for just about everything.

A far more common tradeoff you'll be forced to consider is power vs. elegance of design. For example, do you want to expose the raw data structures themselves, giving users low level access and control, or do you want to wrap them in abstract data types? This sliding scale is really what a lot of API considerations boil down to.

Edited by NelsonMandella on
A far more common tradeoff you'll be forced to consider is power vs. elegance of design. For example, do you want to expose the raw data structures themselves, giving users low level access and control, or do you want to wrap them in abstract data types? This sliding scale is really what a lot of API considerations boil down to.

Well it seems with Casey's compression oriented approach, you wouldn't have to choose one or the other (low level control vs higher level function), you could have both. Since your designing from a more bottom up approach you would start with creating the lower level api stuff and then if you find your api would benefit from some higher level abstractions you add those in while still giving users access to the lower level functions/data if they need them. So the skill would be determining when you actually need to add higher level functionality and when you should just modify current lower level functions. I believe this is what Casey was talking about in his blog with continuous granularity.

Edited by Jason on
boagz57
A far more common tradeoff you'll be forced to consider is power vs. elegance of design. For example, do you want to expose the raw data structures themselves, giving users low level access and control, or do you want to wrap them in abstract data types? This sliding scale is really what a lot of API considerations boil down to.

Well it seems with Casey's compression oriented approach, you wouldn't have to choose one or the other (low level control vs higher level function), you could have both. Since your designing from a more bottom up approach you would start with creating the lower level api stuff and then if you find your api would benefit from some higher level abstractions you add those in while still giving users access to the lower level functions/data if they need them. So the skill would be determining when you actually need to add higher level functionality and when you should just modify current lower level functions. I believe this is what Casey was talking about in his blog with continuous granularity.


Not really, we seem to be talking about slightly different things. I'm talking more about a spectrum of modularity. There is always going to be some tradeoff between exposing every single function and data structure (to give the user maximum granular control/power) vs. using using opaque data types and creating a bare bones minimal public interface to expose as little as possible needed to get the job done.

Now which side you favor depends on all sorts of factors. For example, are you designing it for yourself primarily? Is it designed for use in small programs? Big programs? Generally speaking, if I were designing it for myself writing a medium-large scale program I'd naturally lean towards the side of modularity, because doing so helps to keep overall program complexity under control and program complexity is always a major concern for medium-large sized programs. But there may be specific cases in which other parts of my program would really require highly granular control in which case I'd tend towards the control/power side of the spectrum, but no more so than was necessary. There's no one size fits all kind of answer, and like most things it just depends on a number of different factors and considerations.

Edited by NelsonMandella on