Has software design taken a wrong turn?
This is an episode of The Eric Normand Podcast.
Subscribe: RSSApple PodcastsGoogle PlayOvercast
I analyze two similar definition of software design, one from OOP and one from FP. We see that each is talking about making the code more flexible. But design shouldn't focus on the code alone. In this episode, I explore what it should focus on instead.
Transcript
Has software design taken a wrong turn? Hello, my name is Eric Normand, and this is the Eric Normand Podcast. So, today I'd like to talk about the wrong turn that I think software design has taken. It's headed in the wrong direction, and I want to talk about the direction. I think it should go in, that it should be going. So, let's get started. Software design is a term that is hard to define. It's one of the reasons I don't like it that much. You don't even know if you're talking about the same thing when you're talking to someone. And there's lots of arguments about what is good design, what is bad design, and you can't tell who's right. There's no way to just evaluate it on the definition to see like, "Oh, you're wrong because you didn't do this thing in design." It's all subjective. And I often think that one of the reasons why people use the term "design" is to keep it subjective. Because they intuit that there's a lot of subjectivity to it. And so, they use a term like "design" which in a lot of ways includes a sense of like aesthetics or something. That you can say, "Oh, well, we just have different taste." Okay, so I want to talk about two different views, very similar views of software design. One from the objects oriented community and one from the functional programming community. The first one is from a book called Practical Object Oriented Design, an agile primer using Ruby by Sandy Metz. Good book on object oriented design. You know, it's very well regarded and I respect the author quite a lot. I watch all of her talks and really like the ideas that she's got. She's really pushing for software design and I'm for that. Okay, so she has in chapter one, section 1.1.3, the section is called a practical definition of design. Every application is a collection of code. The code's arrangement is the design. Okay, so that's the definition. I think that that's what she's getting at. And she talks about the purpose of object oriented design is about making your code easier to maintain and change as requirements change. The features come in as old features need to change. You can't foresee what's going to happen, what changes are going to be needed, but you can make your code able to adapt to those better than some other code might adapt to it. The software design is about all these choices, about where to draw module boundaries and where to put code, like what methods things should be in, how to name stuff. All these code issues that will affect how maintainable your software is. Another definition, maybe it's not a definition, I don't know if you could really call that a definition, what I just read. It's certainly an explanation and it sets a goal, maintainability, changeability. That's the goal of object oriented design. So the next source is a paper from 1987 called LISP, a language for stratified design by Harold Davidson and Gerald J. Sussman. Okay, in this they talk about design as a way of arranging code, so very similar. So let's read it. If a system is to be robust, it must have more generality than is needed for the particular application. The means for combining the parts must allow for after the fact changes in the design plan as bugs are discovered and as requirements change. It must be easy to substitute parts for one another and to vary the arrangement by which parts are combined. This is necessary so that small changes in the problem to be solved can be affected by making small changes in the design. Okay, so it's very similar. We're going to arrange this to parts in such a way that we can later make small changes when we get small requirement changes. Okay, we don't want a small requirement change to result in a big change in the overall structure. Okay, and so the next sentence that they say is to this and expert engineers stratify complex design. So in this paper, which I read on a previous episode, very good paper, I gave commentary. I'll just kind of summarize it really quick. You put your code into layers where each layer is implemented in terms of the layer below it. And that way you can create this kind of stack of abstractions and each stack gives you a new level of expressivity. And then later on when you have a requirements change, you can kind of choose what layer needs to change. Right, and so if you change the layer, then everything above it is going to change. So you have to look at your problem statement and how it's changed. And now you can kind of figure out what level of abstraction that change is in. Okay, it's very cool, very cool. I think that this is kind of common is to think of software design as a quality that indirectly, or sorry, not indirectly, but in the future leads to maintainability. Because you can't have, you know, you can only measure maintainability after the fact. How much, how expensive was it to make a change? Right, after you make it, right, you can't really know ahead of time. Okay, but where's the wrong term? I believe that the major wrong term is that these two definitions, very similar definitions, they don't talk about the domain. They're about the code, they're about the arrangement of the code in itself being flexible and maintainable. As opposed to the code being a good representation of reality. Or that small part of reality that we call the domain. Okay, so let's unpack that a bit. When we write software, it's for some purpose in the world, and we need to model some phenomena in the world. We might be accounting, might be, might be bridge building or, you know, something, and we have to have some representation of the concepts of accounting or the concepts of bridge building. We have to have those in our software in order for it to function. Okay, and so I posit that the, that a good software design is one that allows for you to express that domain more accurately, more faithfully, and with fewer, fewer corner cases. Okay, and by corner case, I mean a mismatch. So something like there's two types of corner cases. One is where you have something in your domain that you can't quite express in your code. And so you have all these workarounds. The other type of corner case is there's something in your code that you can express that doesn't correspond to anything in your domain. And so now you have other workarounds for avoiding, writing that, right? So the purpose of design is to find a way, and that's designed as a verb. Okay, I was using design as a noun up until now, that was a mistake. But good software design is about finding a way to express the concepts in your domain accurately and precisely. Okay, and if you do that to the level of granularity that you need, then your software will be easy to change. Your domain is often not changing, right? Often it is, but at some level, there is something that's not changing. So if you're doing accounting, accounting is not changing that much. Okay, the basic idea of having accounts and their transactions with credits and debits and the whole double bookkeeping system, that doesn't change. Some law about getting a tax credit for some new thing, that changes all the time, but how do you represent that? And I believe a good way to do it is with stratified design, you know, as described in the paper, but you can represent that domain as a layer of transactions and accounts and things with debits and credits. And then on top of that, you have other rules for what allows, how do you get tax credits, what do you get tax credits for, and who's allowed to get which credit, etc. All of that can be done in terms of the transactions. Okay, and so the accuracy and the granularity of what you can express in your code is the software design. Okay, this is something that you can measure here and now, right, it's not something like maintainability that you have to, you know, wait until you have to maintain it to know how much it cost. Right, it's something you can measure here and now, can we express this thing that our domain demands us to express, or we can express this in code, does it correspond to something in the domain. Okay, so this is the direction I think it should head, which is to move toward a discussion of how to represent things. It's more of like a semantics, more of a semiotics. How do you represent things from a domain in software? And, you know, now we're talking about modeling domain modeling, data modeling, object oriented modeling, all of that. I think that that is where it should be headed. It has to reunite with the domain. Okay, the book over there domain driven design, that community, I believe is headed in this direction. They are pushing for this more than any other community I've found. The mainstream, this other software design, you know, movement is moving more toward focusing on just the code, right, the design patterns movement. When you look at the descriptions of the problems that different design patterns solve, they're all about code. They're all about how do we, you know, this, this naive solution to the problem generates too many classes. How do we not have so many classes? Well, you're not talking about whether it is a good fit for the domain. You're just talking about the number of classes. It's just a code problem. You know, you're trying to solve a problem in your code. You're not trying to represent something in the domain any better. And so I feel like this is the turn that's been taken, I don't know when, but we need to turn back. And so if I ever do write another book on this, it might be about this, right, like how do we model the world and turn it into sort of a process for building good designs, what I want to call it, building software that allows for the maintainability. That's a, that is a consequence of good modeling as the stratified design paper talks about. But it is not the main focus. You can't get it by focusing on maintainability. That's enough. That's a discussion for another time, but it's a, it's a lagging indicator. It's like, we need, if you, if you. I want to get into it in another time. I don't want to get into it right now. I want to wrap this up. Okay. So I've talked about the wrong turn. It's focus on the code instead of focus on the representation of the domain in code. And I think that there's not enough written on how to represent the domain. The domain driven people have done a lot of good work there. I think there's a lot yet to be done. And I hope to be part of that. This is the kind of thing I want to talk about in the foreseeable future on this podcast. I think the functional programming community has a lot to say here. The stratified design paper, it comes very close to this, but I think misses that and talks more about structure of, of the code and its implementation less about the domain. I think that it missed, it misses a part of why stratified design is powerful in this way, because you could have a stratified design. That's not powerful. They didn't show an example of like, this doesn't actually fit the domain. It's like, you can express a million things, but they don't actually mean anything. Okay, so if you're interested in hearing more discussion about this, please subscribe, you can go to lispcast.com/podcast. I always appreciate reviews and other things on iTunes, likes or, you know, five star ratings, ratings and reviews. That helps other people find the podcast. You can also rate on Google Play, etc. Alright, thank you so much and rock on.