In this episode, I explore the notion of fit and how it is missing from the Stratified Design paper.
Eric Normand: What’s missing from stratified design? Hello, my name is Eric Normand and this is my podcast. Welcome.
Today we’re going to be revisiting a paper that I read and commented on in January of 2020. It was episode 162. The paper was called Lisp, a Language for Stratified Design, a really great paper and I want to revisit it and ask some pointed questions about design as it defines it.
First, before we get to that, I want to talk about my book “Grokking Simplicity.” It is now out. It is on Amazon. You can also get it on the Manning website. I’m sure you can get it on Barnes and Noble, anywhere that you buy your books.
Grokking Simplicity is a book that is trying to teach the fundamentals of functional programming for someone who has not been introduced to functional programming in a sufficiently good way yet. Maybe they’ve been introduced, but they never really got the idea.
I think a lot of functional programming books will focus too much on what I call lambda calculus gymnastics. They’re just like, “Oh, look at all the cool stuff we can do with currying and partials and stuff like that.”
They don’t get to the heart of the matter, which is understanding the difference between pure functions and impure functions, how to work with immutable data and then how to build higher-order abstractions that are actually useful and save you code. That’s what the book is about. Please buy it. Please read it and recommend it to your friends if you like it.
I would also appreciate five-star reviews on Amazon if you like the book. That really helps, especially other people who want to know if the book is for them. It helps to have some reviews up there. Helps me, helps them and thank you.
On to our topic. I really like this idea of stratified design, and it’s an excellent paper. You should go listen to episode 162 or read the paper. There’s a ton of stuff in it. I’ve reread it since I’ve done that episode and found even more cool stuff in it.
I spend two-and-a-half chapters on stratified design in Grokking Simplicity because I feel like it’s one of the principal ways that functional programmers do build their code. It’s a perspective of making stuff out of layers and how each layer builds on the layer underneath it. It’s really cool.
I have an issue I want to bring up with the notion of design as presented in that paper. There’s something missing. They talk about how design helps you with flexibility. The different layers, you can decide for yourself where a change needs to be made.
The example they gave is building M.C. Escher style pictures, so you have some repeated pattern that can tile and shrink as it gets more to the right. They have this recursive way of building these images out of a single tile and how do you tile it and mirror it and stuff like that.
It’s a really cool system. They credit a lot of the design power, the flexibility of it is from the stratified design. By making different layers, you’re essentially building up a nicer and nicer language for expressing the picture that you want to draw.
Then, if you need to change something, you could say, “Well, I need to change how mirroring works.” Or you could say, “Well, I need to change how I choose to mirror,” which is that at a higher layer, if you’re building layers up.
You could talk about how mirroring works in general for every picture, or how I am calling the function that mirrors what arguments I pass it at a higher layer. You’re able to choose whatever layer that you need to make the change at. That’s very flexible. It adds to the flexibility.
On top of that, they’ve got a thing that they’re talking about called the Clojure property, which basically means that the functions at some layer…There’s some layer above which all the functions take a picture and return a new picture.
What that lets you do is recursively nest them. That gives you, basically, another dimension of expressivity. That you’re not just linearly sequencing some set of calls. You can actually nest the call so that the result of one expression is passed to another expression which is passed to another expression. That lets you be flexible as well.
Without changing any of the layers, you can re-work the expression of your picture and make a new picture. That gives you a lot of flexibility as well. The pieces compose well and they recompose well.
All of that is really cool. I think that is something that we should all strive to be able to do in our code. I’ve talked a lot about that.
The thing that’s missing, I think, is that it’s really separating out the…OK, let me back up. You know how people will say, “Design is not just about how it looks. It’s also how it works”? This, to me, looks much more like, they’re talking about how it looks, how expressive is the code, how easy is it to change. It’s not about how it works.
What would it look like to talk about how it works? I think what they’re missing is that the functions that they chose — regardless of whether they’re built-in layers or not — to build are really good for expressing that kind of M.C. Escher image. They’re not good for different kinds of images. They’re good for expressing M.C. Escher style images.
That was their problem. They wanted to express these M.C. Escher style images. The fact that it works well is…They’ve figured out what functions they need and carve the problem up in a certain way so that they can express these M.C. Escher problems, that is completely ignored in the paper.
There’s nothing in there that said, “Well, we could have just talked about plotting pixels and then had no leverage for building this kind of image,” but instead, we chose to start with an image and then you can put two images next to each other. You can put them one on top of the other and you can mirror it and flip it and scale it, that kind of thing.
By doing that, you can build these tessellations of the tile and make patterns with it. If you were dealing with drawing pixels and other very primitive graphics constructs, it wouldn’t be a good language for expressing the M.C. Escher images.
What I’m trying to get at is they’re completely ignoring what I think might even be a more fundamental design concept. This concept of fit, the abstractions, the concepts that you’re encoding in your software need to correspond to a useful functionality for solving the problem that you’re trying to solve.
That is part of design. They could’ve solved it with pixels, with a Turing complete language and a way to draw pixels, you can draw any picture. That’s well understood, but then it might be really hard. It’s a hard problem to start with those tools, but by starting with these other tools they made the problem easier.
It’s not about flexibility. It’s not about being able to change it or express an infinitude of different images in a recursive way. It’s about choosing the concept. It’s about modeling.
I’ve never seen someone talk about that when they talk about design. They act like it comes out of nowhere. That it’s just some a priori thing that now we can apply design to in scare quotes.
It’s not design is all about structuring your code and choosing good names. That’s what they talk about when they talk about design, but this is much more about finding a good concept.
That is what I’m really trying to explore here in this podcast is “How do you do that? How do you look at M.C. Escher picture or a set of them and think, ‘There’s something interesting about repetition and scaling and putting two versions of the same tile next to each other and mirroring.'” You start to break down what is in fact going on in that image.
You could call it a style, but it’s maybe the building blocks of how those images can be put together. You might look at something else like a different kind of painter. Like a Monet, [laughs] something like that, and try to think “What are the building blocks of a Monet picture?”
Maybe you can’t find it, maybe every Monet is unique or there’s just something about how his eye worked or whatever that let him do those strokes that he chose, but notice that’s a hard problem. They didn’t attempt to solve that problem.
What I’m trying to get at is we need to find a method or a set of methods for breaking down the domain that we would like to model.
Now, we have a model, might just be in our heads, or it’s on whiteboard or it’s pieces of paper. We take that model and we encode it into software and, of course, that’s where functions come in and stratified design and stuff like that. How do you find that model?
That is the thing that I’m trying to explore, I’m trying to figure out here. Like I’ve said before, I don’t see anyone else doing this. I’ve talked about this before and try to pinpoint what I’m talking about that I see that other people aren’t talking about. Talking about style versus content. If you go to a writing workshop, you could divide advice between style and content.
Your word choices…That this is style. This is unclear word choice, maybe you should go faster or go slower, length your sentences, simpler sentences. Things like that are style. Word choice. Style.
There’s also “Oh, you’re writing a novel, you need a good plot. You need good characters. You need an interesting setting.” There’s all these other aspects that are not really about what words you choose and how you put your sentences together.
It’s much more mental and about the meaning of the thing. There’s these two aspects. What I see in software is we’re talking much more about style. We’re talking much about how long your method should be, how you name your functions, what directory structure to make it clear, where to start, and things like that.
That’s all style. That’s the non-functional requirement stuff. “We want to make it easy to change.” “We want to make sure that it’s readable so that someone who can figure out what’s going on.” Maybe it makes it easier to debug or to get started at your company. That’s all style stuff.
The fact that there are better and worst representations of the domain is totally not talked about. They act like that’s fixed. This is the meat. This is the substance, the content.
We have a function that will take an image and flip it on the x-axis or on the y-axis. This function is an important piece of making M.C. Escher drawings.
Someone discovered that. Someone discovered that this is useful regardless of how’s it implemented or how’s it structured as a stratified design. That is a useful construct.
I said no one is working on it. The person who comes the closest is Connell Elliott and I’ve been following his work a lot. I do think that he has demonstrated the ability to do this and has tried to talk about it.
The real problem is then when he’s talking about his method, it goes into stuff like category theory pretty quickly. People, when they listen to it, they get hung up on that, like, “Category theory is where all the useful stuff happens.”
That’s similar to the problem of stratified design, which is that now you’re talking about the structure of the code and you’re not talking about what the code is doing and what it’s representing, which is the meat of it again. You’ve forgotten about the content.
Connell Elliott is doing it, but the way it’s presented, it would be like a writing teacher saying…I sit down, I come up with very interesting plot with good characters. He talks about the plot and the characters for five minutes.
Then for 45 minutes, he’ll talk about how he breaks it down into chapters, how he, make sure that every chapter ends with a cliff-hanger, so you want to read the next chapter. All that is now, like “Oh, wait, you’re talking about style now? What about that? [laughs] How do I make the great characters with the interesting plot?”
I’m exploring that here and I’ve been trying to poke at it in different ways, looking, reading about design work in general. Stay tuned because that’s the kind of stuff that I’ll be talking about here in addition to all my other contents — all the stuff about the Turing Award winners and interesting papers.
Thank you for listening. My name is Eric Normand and as always, rock on.