Bottom up vs Top Down Programming

I think the real trick to all of that is always think about the data as being forever. One thing that we often do when we're programming is we want things to be a little bit more concrete.


Eric Normand: Hello. My name is Eric Normand, and these are my thoughts on functional programming.

I was in a Slack discussion yesterday with someone who was asking for advice in a ClojureScript app for how to make it a process for ensuring that your code will last longer, that it will be more reusable and you'll have to change it less often.

I think the real trick to all of that is always think about the data as being forever. One thing that we often do when we're programming is we want things to be a little bit more concrete.

We worry about getting too abstract, which happens. It's true. We get abstract, but I think also we get too concrete. We say, well, the story says that on this one view, on this one page, I should be able to change my name as a user.

What happens is we create an API that's like, "I don't want to be like...what is a name change, really? I just want to make a thing that's for this feature." You make an API endpoint or an event, or however your system does that, a command that is called something like Profile Page, Change Name, or Update Profile.

The problem with that is that you're putting as primary the thing that is the most ephemeral. The primary thing is the data. The primary thing is capturing that intent of the user, because once you store that, in theory with records, with data, it's supposed to be a fact about an event. You're going to store that forever.

What's going to change is probably the UI. The app is going to change. To tie it to the UI first, to say this is the update profile API endpoint, you have put the cart before the horse basically.

Now, when I mentioned this, the person I was talking to said, "Well, so what you're saying is you need to do top-down programming."

I know what he means is that I'm thinking more about the higher level concerns of the app more than I'm thinking about the individual features, but I actually think that what I was doing is the bottom-up approach, which is to go down to the most smallest units of actions that the user can take. That's like down at the bottom. That's the bottom that I'm talking about.

The unit of action is, or the unit of data, let's start there, because that's where you should start, is the person's name.

Software is all theory-building. You're building a theory of the world of this domain that you are programming for. That domain is going to include a model of people, maybe, if it has people involved.

There's going to say that people have names and that those names can maybe...maybe it's not they change, but you can correct a name, because maybe you got it wrong the first time you entered it. You're building this theory of what's in the world, of how the world works.

Down at the bottom, you say, "Well, that's it." A person has a name and a person can correct their record of their name. Maybe you model that they can change their name, like legal name change, something like that. That might be another operation.

That is the bottom-up. I think what one thing that's happened in the industry is we've done this agile process, "agile," like it's a prescriptive process. We had this notion of you write down a user story and then you spike a solution.

When you spike, you're hitting all levels from the UI, all the way down to let's say the data base, through everything that needs to happen, and you're getting that one feature done, in theory, the simplest way possible. That's like the extreme programming way.

Clojure is actually a little bit opposed to this. This is not bottom-up. This idea of attacking something and spiking is cognizant of it being a sideways. It's not bottom-up. You're hitting everything from the top down. The difference is that, in the agile...I'm not saying agile in the good way. I'm saying agile in the way it's practiced in a lot of places.

If you start taking about design at all, then you're doing top-down. I think that the Clojure world is cognizant of the fact that design happens at all levels, that it's all about making decisions.

You have to make decisions, so, you'd rather make good decisions rather than bad decisions. The problem is we often will work in this middle ground. We're not even doing top or bottom.

Top-down would be the idea of trying to design the whole thing first and then working on the individual pieces that fit into that thing. Bottom-up is working on the individual pieces and then putting them together into a solution. That's the one I think is the best, because those pieces...If you're wrong on any of those pieces, it's a very cheap mistake to be wrong there, because it's a small piece.

You might be wrong but, "We'll just throw that away. It was only five lines of code." Whereas if you design the whole thing and you find out you're wrong, the whole thing is not going to work or it's going to require a lot of fixing and duct tape to get it working. It's costly. You have to scrap the whole thing, start over, rework a lot of stuff.

What we do though is we start in the middle, which is neither top-down nor bottom-up. We exist in this land where nothing is really designed. We try to couple things together that we don't really know if they go together yet, but they feel like they do for this one feature.

We haven't designed it from the top-down, so we don't really have a big picture of where things are going, but we haven't gone to the bottom-up. We don't have these little pieces, so we make these things at the middle level. That is, I guess it's better than top-down, because their mistakes are less expensive, but it's not as useful as bottom-up. We often talk about it as being bottom-up. We don't actually hit bottom.

What does hitting bottom look like? That is where the pieces you have are truly atomic. They are truly something that you could consider timeless. Now, you might be wrong about it being timeless, but it's at least potentially timeless.

A person has a name. That's been true for a long time. The idea that someone's name got entered wrong, you have to correct it, that correction operation, that's also been true for a long time. It's probably going to be true in the future. It's hard to imagine a world where we enter in data correctly the first time.

People can change their names, and that's even external to our system. It's a legal thing. We should allow that too.

There's all these things that are pretty guaranteed to be timeless. That UI, those things don't last very long. You want to isolate your UI from your timeless data. That's one of the things that functional programming gets us to think about. Sorry. There we go. It's what functional programming gets us to think about. It's this data.

You know you have good data if you can interpret it in multiple ways in the future. Someone's first name or their name can be used in multiple ways. One way is to use it as a greeting. You say, "Hey, Joe," "Hey, Mary." You could also use their name to look up their phone number in a phone book or some other directory.

That sounds so trivial. We do those kinds of things all the time, but this is the kind of thing that you're looking for in data that is not so clear. Someone's name is actually not a great example because it's well-known that people have names.

When you're making a theory of your domain, you have to find stuff like that. What is the data and what are the operations on that data? That is what will make your code last, is organizing it around that. That's the stuff that's going to stick around, the data. It's not going away. You don't want it to go away.

Please, if you like this discussion, subscribe and I will see you later. Bye.