Sense and Structure: Towards a Textual Analysis of Software Zach Tellman 5 minutes... 5 minutes... One more minute! One more minute. >> Welcome back to the last session of the day. My -- my name is Chas Emerick, I one of the organizers for PWLConf. Our next speaker has been a friend for a long time, met at one of the first Strange Loops, maybe the second one, where he was giving a talk. And came to know him in the Clojure ecosystem and open source projects, hanging out, visiting with each other's families. And he's a great guy. But beyond that, and more relevant here, but he from the first time I met him, has been very interested in very carefully thinking about what it means to write software and what that software means to both the author and the people that consume it. Not just the computers that consume it. And what that means for how we build software, how we build software together. And it's been great talking with him over the years about these kinds of issues. And he brings a lot of insight because of a lot of his background and interest in non-computer topics in the humanities, philosophy, linguistics, et cetera. With when we were having a talk in June-ish or so, he has been talking about research he's been doing on a book he's writing. Not trying to blow up your spot, but it's happening. He was talking about how there's this interesting problem about how we write software and the linguistic consequences of that. And how there wasn't a lot of good research that was extant out in the world or that he could find that was pertinent. And I said, you know, PWLConf was being organized and I said, this sounds like the great foundation farce Papers We Love talk. Not being able to find a paper that is relevant to the topic that you're interested? And here we are. I suggested that to Zeeshan and company. Everyone talked and now Zach is here to talk about textual analysis of software and what that means for everybody. Give it up. [ Applause ] ZACH: Okay. Can everyone hear me? Great. All right. All right. So, I'm writing a book about software design. And I think that this is a term that is thrown around pretty loosely in the industry. Right? We say it a lot and we define it very seldomly, right? I think that we have this sort of general notion of what it is, right? It's like a thing that we do when you write design docs at the very least. And a thing we do more as we get more senior. Right? It's the hallmark of being an expert programmer is being able to come up with good designs. But what is or is not software design? Is everything we do in the course of a day software design? If not, where do we draw that line? This is not, I think, an easy question to answer. But a good place to start is trying to define what design is. And the best definition I'm familiar with comes from Christopher Alexander. Every design problem begins with an effort to achieve fitness between two entity Is: The form is in the and its problem. For our purposes, trying to judge how well-designed our software is. Our code and the context around that code. But what are the contexts, right? And obvious answers are users, right? This is arguably the sort of ultimate measure of whether or not our software is any good is whether or not it empowers the users, whether they find is easy to understand. But I think a lot of development kind of happens over the horizon from the users, right? We're many layers of indirection from them. It's hard to use the user's perspective as a sort of way to shape our design decisions. We tend to focus on something a little bit closer to home. Which is to say, the other nearby software, right? These are both good and useful contexts to consider. But they are by no means the only ones that we do, right? When we're writing software in -- [Audio stopped] -- creating, right? And they are just as important in terms of how we're judged by what we deliver. A lot of times these idiosyncratic considerations are at least as important as if the users find the software easy to understand. And this is a problem, right? Because the first two of these contexts generalize pretty well, right? Pretty much every software project is gonna have users, it's gonna have other adjacent software. But this last kind of grab bag doesn't, right? Even trying to enumerate all these possible considerations would probably be like the work of a lifetime, right? And so, I think the result of that is a lot of design -- software design literature sort of focuses on the parts that do generalize. And then have a big old asterisk dangling off the ends that says there are other things too, you could figure it out. And that's a problem. We do not have an actual descriptive model for software design as it's done in the world as opposed to an idealized thing that we wish would be done. As we try to think about how to bundle all these things up, something worth noting is that all of these views of the context are what in linguistics is called synchronic, focused on a moment in time. Taking the codebase and the snapshots and comparing them to each other. And this is perfectly reasonable. But software is not a static artifact. It's constantly being reshaped. We can take a diachronic perspective, how is our software changing over time? In fact, what we can do is say that's our context. I want to judge the codebase against what we expect that codebase may become. Right? And the neat trick here is this does actually wrap up all the other things, right? Because our expectations for the future are shaped by all of these other forces, right if both the needs of the user and the needs of the organization. And so, this is actually a path towards a descriptive model if we can figure out how to talk about the possible futures of our code. And it's worth noting, right? If we talk about change and the future, that the sort of predominant philosophy of change in our industry, which is these sort agile methodologies, do not like to talk about the future. The agile manifesto was written in response to the failures of the earlier, big design up-front methodologies. And they saw talking about the future as sort of a slippery slope, right? If you begin to acknowledge the future, before too long, we'll be writing big design documents again. So, they focused on this sort of ever-present now. We don't talk about the future. We just prepare for change, whatever that may be. And the way that we prepare is by following these best practices that they espouse. We keep our code clean, write our tests first. And the assertion was, that if we do that and respond to change, then a design will just sort of appear, right? Bottom-up. As if by magic. And, you know, I have nothing against the sort of lower case agile sort of methodologies, right? These have become the norm in the industry for a good reason. But I think these stronger capitally agile sort of perspectives are kind of weird. I think maybe obviously wrong. Certainly they don't reflect how we actually do design and write software, right? When we go and we create our software, we can always reshape it, but it has a form, right? And certain forms are going to be easier to create from wherever we are than others, right? And as we go and we make choices, we sort of close certain doors and leave others open, right? And this is absolutely something that we talk about, we think about when we write software. We are in conversation with these futures. Whether sort of the signatories of the agile manifesto like it or not, right? So, I want to do a textual analysis of software, right? And this is because based on sort of prior reading that I had done, I had felt this sort of resonance with this idea of thinking about possible futures in certain things that I have read in like analytic philosophy and -- and other literary analysis. And, you know, if nothing else, software is a text, right? That is a representation that we work with day in and day out. It's not a particularly normal text. It's what we call a living text, right? It's never complete, it's eventually abandoned. It's a collaborative text, we are working with multiple people towards a shared end. It's what is referred to as a hypertext. There's no well-defined order in which it's read. These are fairly unusual, and together, extremely unusual. But it's not unprecedented. There are other texts and books out there that talk about these sorts of texts. And so, my expectation when I started my project, this book, I thought that I would find someone somewhere had analyzed software as a text, right? There are a lot of people out there who do it. Software is a pretty important thing in society. Surely someone had done my work for me. And I found that there was a field called Software Studies. Largely populated by people in the literature departments in the air universities. I thought, great, I'll start here. And I spent about a month reading pretty much all of the software studies literature. And I found was... odd? So, these are three quotes that are in a book called The Interface Effect written back in 2012. It's pretty representative. It's a highly-cited book. And these quotes are sort of built up to over the course of two pages. And Alexander Gallo way, the author, gains with code is the only language that is executable. And, you know, I don't know. Like arguably the recipes in a cookbook are also executable. But maybe he means like unambiguously executable. We'll give him a pass. He then says code is machinic first and linguistic second. Not only is it executable, but that's the most important part. The linguistic quality is not as important. And finally, he reaches the apex, code essentially has no other reason for being than instructing some machine in how to act. Which is, you know, wrong. Right? I mean, you know, code is, among other things, a repository of institutional knowledge, right? It's a steppingstone to the other software that we're going build using it, right? It's a way of learning about sort of software practices in general. Right? It's many things. I mean, if Galloway were talking about like compiled, you know, artifacts, right? I would be on board with this. Right? Those are kind of linguistic, sure. There's a language that the GPU is trying to go and decode. But like he's not talking about that. He's talking about the thing that we write for a living which is like high-level languages. And he is saying all that matters is it has a button on it that says "Go." And so, I am not able to talk you about a single paper or a single book. Much to my chagrin. I have over the past year been reading a lot of stuff that is not about software. Searching for things that resonate with my sense of what software is. And I have sort of taken them where I found them and I've tried to sort of stitch them all together. And as a result, this talk is going to be pretty far-ranging. It's also going to be a little discontinuous. Because the original outline would have taken three times as long. I can't provide all the necessary connective tissue. But I hope it will all sort of make sense and ring true. So, where I want to start is with interfaces. Because interfaces are the longest-lasting part of our code. And I think that this is easily demonstrated by closely-related thought experience. The first is the grandfather's axe. Right? My grandfather had an axe, he replaced the handle, he replaced the blade, is it the same axe? And I don't know. But one thing that is preserved is the interface between those things. Even if the handle and the blade are completely different, even if it's completely unrecognizable as the previous axe, there is some part that is preserved, right? And then the ship of Theseus. Theseus is on a journey, on the ship, repairs it one plank at a time. Eventually all the planks are replaced, is it the same ship? I don't know. But I do know what is there are the relationships between the boards, right? The interfaces between them. And, you know, what this means is that the smaller and more incremental our changes, the more the interfaces are preserved. That is very much the trend in our industry. Our interfaces are becoming longer lived. To think about interfaces, the most useful kind of perspective is to look at the most common kind of interface, which is names, right? A name might point at a value, the implementation for a function or class. We can change the implementations, but the name remains the same. And I think in our day job its, we come up with a lot of names. Probably more than any other profession in human history, right? And for some bizarre reason, we do not look at names very often. Do not look at the literature and try to formally study them. We ought to. But if we go and write code for some number of years, chances are we have a well-developed intuition about names. I would like to poke at that intuition and kind of use that to draw sort of broader inferences about interfaces as a whole. Let's say we have two values here, right? Two variables close together to our code. They have different names, but they are assigned the same value. Is this an opportunity to get rid of some redundancy, right? Can we collapse these two variables down to one? Who thinks we can do that? Literally nobody, great. [ Laughter ] So, of course we can't, right? These might be the same value for different reasons. And at some point in the future, they might diverge, get different values. If we go and collapse them, we have lost a potentially meaningful distinction, right? This is effective lit point that a logician Gottlob Frege, used the morning star and the evening star in ancient Greece, on sense and reference. He was responding to an idea of names which is just that a name is a we of pointing at a referent, right if pointing at some value. And Mill who had the earlier go-to expert on naming wouldn't have said collapse the two variables down, get rid of the variables all together. sprinkle 42s everywhere the in code. You hear this and you cringe because you have this intuition. What is in a name? Why do we have them? What Frege called this quality, this thing that differentiated these two variables is he called is the sense of a name. Also sometimes referred to as the meaning of name. And a good informal way to think about it, it is the path that we take to the referent. Frege in a different writing talked about the mountain peak that you could approach from the north and the south. As you approach the mountain peak, it takes on want flavor that you pass through, the climate, the culture, the cuisine. Two people who arrive at the same point will have completely different sort of meetings in their mind. Different connotations. They will be thinking of different journeys. Even though they, you know, both exist at the same sort of point at the very end of their journey, right? And more formally, it's a predicate. It's a way of describing a set of the things that it could possibly be pointing at. And so, this is a useful way to think of an interface, right? An interface has a sense. And that sense describes what sort of implementations can sit behind it, right? And as these interfaces last into the future of our code, they constrain that space, right? They give us some handle on what is likely or possible in the future. But we have to go and complicate this a little bit more. So, about 60 years later, Wittgenstein wrote in a book called Philosophical Investigations about the biblical figure, Moses. If you test actual historical figures to see if they were Moses, we are not going through all the things. He was named Moses, born in ancient Egypt, led the Israelites out of Egypt. Came down and Mount Sinai. These are the big ones in the old testament. He said we could probably throw it overboard and reasonably refer to this historical figure as Moses. Either of these, that probably makes someone Moses, right? There might be multiple historical Moses spending how specific we want to get about it. Not just anything qualifies. Someone who named Moses and lived in ancient Egypt and did nothing else of note is not a Moses, right? Not our Moses. And so, what Wittgenstein is point out, it's not just necessary qualities. Not just going down the line and saying, was he named Moses? In ancient Egypt? And fished out of the river, nope, not a Moses. That's empirically not how we think about meeting. What it is is closer to the second function. Which is I should note is not something that Wittgenstein talked about. This is my translation. We have these two pieces. We have this inner function which gives a score on how similar to Moses is this person? And then going and testing against some threshold, right? And each of these two pieces, I think, are important in different ways, right? The first part, right? The fact that we have this kind of sense of the intensity of similarity to Moses, means that we not only can identify who is and isn't Moses, we also have a total ordering, right? Anything that we know the meaning of, we can see this is more than, than this other thing, right? And if we want to go and talk about the internals of this function, it's difficult, right, so the concept of similarity is very foundational to language and it's hard to use a language to analyze itself. It's kind of like trying to bite your own teeth. And so, you know, Wittgenstein talks about this more in Philosophical Investigation if you're interested. But it's kind of beyond the scope of this talk. The second part is also interesting, right? One thing about it is, is that it is actually easier for us to discuss, right? If I'm talking to somebody about Moses and we're talking past each other. It's hard to discuss our internal sense of what means to be Moses. No, I mean, all the way down the line biblical Moses. I can talk about the meaning even it's harder to talk about the meaning itself. The relevant thing for us as software people, when we're thinking about our interfaces, the specificity, the threshold they have to clear is almost always increasing over time. This is for a few different reasons, right? One of them is what is referred to as Hyrum's Law. If you have an interface and people are using it, they will begin to rely on the implementation whether or notes it pardon of the contract offered by that interface, right? The general consequence of this, we don't to want break user's code, the implementation detail becomes part of the code. This is not the major driver. What I think the major driver is, what our understanding of what a thing is, includes what we expect it to become, right? So, if we are going and trying to represent a real world thing. Our initial prototype will only capture a handful of facets. Our users begin life as just an email address. But we have other things that we know that we soon have add. We have to add a physical address and payment information and all this other sort of stuff, right? And that may not be not code, but it is in the our understanding of that interface and what the implementations behind are likely to become, right? And for non-representational things, I think there's a similar sort of property where we go and we compare it to more mature versions of that interface, right? If we're writing a key value store, a key to value. There are other more mature, we can look to Cassandra, to Redis, for examples of what other people found useful and those become part of our sort of possible future. And so, when we're looking at a code review process and why someone might say... I don't think this quite works. There are kind of two reasons. One is that the implementation as it is simply doesn't clear the threshold, right? There are some fundamental misunderstandings of what this has to be today. Ideally, we catch this with tests. Properties that have been promoted to being essential and we hopefully have tests that capture that. But then there's another kind which is a little bit more amorphous. Yes, okay, this works for now. But I think it won't for very long, right? I can go and I can sort of twist this threshold to the right. I can raise it up. And sort of think about at some point in the future, am I going to have to go and fix this? Hey, you took away this certain degree of freedom we need. Or lay, you have an ON squared solution here, as we scale that's too slow. There are many ways to talk about this. And none of them are, you know, this sort of immediate glaring issue. It's not a functional problem. It's something that has to do with, you know, how can we go and make our lives easier down the road, right? And there's a reason we have the most experienced members of the team doing code review. They have the clearest understanding of what the future sort of holds. What it is that we need to plan for. Relatedly, I think this can go and help us reason a little bit about two ends of a spectrum when it comes to trying to make a change in our code. On the one hand, we have this highly-disruptive change. We go and make a change. But then it breaks something next to it and we try to fix that, and it cascades out and out and out. And all of a sudden we have this PR from hell, right? And this is because we've gone and we've changed the sort of the shape of that meaning, right? We have broken assumptions that exist in the code and the attempts to fix that breaks assumptions in the code. But on the other hand, we have the good PR. We have something where someone has to do something, and it's like the code was anticipating it. Pushing it down the road that stretches out in front of us. And so, you know, this is for me at least what I associate with good design, right? It's really pleasing where I go and try to add something and I find, oh. It's like someone anticipated this. It's like I anticipated this without realizing it. Right? And so, you know, this is, I think, what we want. Right? We want to maximize the amount of time we spend at this end of the spectrum. So, the forward march of time, the continuous development is not just the Hyrum's Law calcification, we accumulate cruft. It's not just that. We want to as much as possible go and simply have our software become more like itself, right? And to do that, we need to have everyone have a like largely consistent view of like what are the paths ahead of us, right? For us -- for everyone to kind of, you know, paint within the lines, there needs to be a shared understanding of what those lines are. And so, the rest of the talk will be basically focusing on like, well, how do we do that? Right? And I think that a really important sort of framework to think about this is what is typically referred to as a principle of least surprise. Which if you apply it to say user interface design, says when a user performs an action, what happens ought to be the least-surprising thing. And the surprise is shaped by a user's expectations. And those expectations are in part due to our software. We should be consistent. If it does one thing on one screen, do another thing on another screen. But there are things that come from the larger ecosystem of software, right? And there is a concept in statistical mechanics called surprisal, the measure in the data. It points out that surprise is not intrinsic to the data. Surprise comes from a mismatch between some predictive model, our expectations and so the data. You can have a arbitrarily long dataset, as long as it's expected, there's no entropy, not being conveyed. We want to minimize surprise, right? And I think this framework gives an answer to -- or at least a potential answer to this question I posed before. Which is what is and isn't software design? Right? Given that we want to go and minimize the surprise of someone going and trying to read our code. There are sort of two things we can do. We can set expectations or we can write code that conforms to the existing expectations, right? And in the sort of earlier big Stein up front, what we would do is spend a bunch of time setting very particular expectations and we would finally go and act upon those expectations. But that's not really what we do anymore. And so, it's possible to go the other way, right? We can have a bunch of pre-existing code and we can create a model for why it makes sense. Why the choices that were made in the past are retroactively unsurprising. Right? And I think this is something that we often do. I think, again, this is something that, you know, more senior members are often trying to go and make sense of what is already there. To explain it such that the next person that has to go through it finds it unsurprising. And so, there's a feedback loop, right? We're constantly switching between these two things. But again, this talk is about software design and so, I want to focus specifically on that. How do we set expectations? And the way that we're gonna do that is using a field of kind of literary analysis called structuralism that sort of reached its peak in the mid-20th century. It builds upon ideas from Ferdinand de Saussure's course in general linguistics, on semi-- the label structuralist was thrown around loosely. A lot of people use it for didn't things. But for our purposes, it is a tool for talking about possibility and expectation. Most of you are familiar with the hero's journey, right? This kind of very archetypical, it has a my though poetic resonance in the human mind. This is a structural text. One of the best known. There are also slightly smaller bore attempts. One is I like is Tzvetan Todorov, the typology of detective fiction. In the structure, the one put forward was language. The structure was language. He said language is basically a graph where the words are vertices and the edges are connecting each word to highly similar and highly dissimilar words. The point he makes, when a word comes into existence, it doesn't emerge full-fledged with a dictionary definition packed on to it. It begins life with a bare label and the meaning accrues from the words that are next to it. Right? The words that are similar add to the meeting, the words that are dissimilar chip away. And we have the thing which is the sense of the word which we try to approximate with a dictionary definition. And, I want to talk about a particular structure, which is the structure of a murder mystery. There are two different structures here which are interrelated. The first is the trace. Which is the sequence of events that are in the story, right? We would begin with some number of events that might have motivated a murder. Then we have the murder, then we have a series of interviews with all the suspects. And finally, the detective reveals who died, right? And I want to emphasize this is not some sort of regular expression that validates whether something is or is not a murder mystery, right? We can go and we can sort of work outside of this formula, right? We can deviate from it, we can elaborate upon it. But what this structure does, is it provides a baseline such that the only thing being communicate ready these deviations and these elaborations, right? And then the trace as these events occur, they're updating the state which is shown above as the characters or roles and their properties and their relationships, right? And since the state is derived from the trace, right? It's tempting to say that -- the trace is the only thing that really matters, right? This is the primary source of information. And certainly the perspective taken by the structuralists. And also the perspective taken by Kafka, right? We should focus on the events that construct the state rather than the state itself. But I think it's worth asking. Let's say that you are sitting down to watch a TV show and you're like, deep into it, right? Third, fourth season. And a friend sits down next to you and says, catch me up. What do you tell them, right? Do you start from the first episode of the first season and then begin to recount every word that was said? Everything that happened? Well, no, right? What you'll do is you'll generally describe what this state of the world is now, plus maybe a handful of events that are just recently happened, right? And the reason that we're able to do that is because stories are made up of narrative arcs, right? And narrative arcs have some equilibrium, some destruction, and a new equilibrium. Once The ARC is complete, we don't care about the events that occurred within it, we can focus on the new equilibrium. What we're describing to our friend is the state as of the most recent equilibrium, plus the narrative arcs that still in flight, right? And so, let's think about debugging for a second. We are perpetually the friend sitting down and asking to be caught up. Right? We don't set a break point at the entry point to the main function. We set a break point where we care about what's going on. And generally speaking, there have been several billion events that have preceded that break point. How are we able to make sense of this at all? The answer is we have created our own narrative arcs. An important one is functions. We can replace a pure function with its return value, right? We can do this for less pure functions. In general, if we go and call a service, or read something from disk, right? As long as there's not an error, we can focus on what was returned rather than all the things that went into doing it. But in more complicated cases, where we want to think about failure, there's also database transactions or protocols, right? PCP allows us to for the about all of the -- [audio stopped] [Captioner standing by for audio] And these two introductions. The state and the trace. Which of the two things is sort of most represented in the text of our program, right? According to Dijkstra in Go To Statement Considered Harmful, we should do the utmost to make the correspondence and the spread out in text pace as trivial as possible. Don't use go to statements. What he and others argued for, structured programming. Yeah, we do actually have a forward progression through the code unless we have certain special control flow operators like if statements or loops or other things like that. And, you know, that's good. We should do that, right? But if we go and sort of apply this logic to other things in modern programming languages, like what else would this criteria consider harmful, right? If one function calls another function, right? We're going narrowly through our text linearly. And then all of a sudden, we jump to another part of our code base. Is that bad? If we have multiple dispatch and call a method, we don't know where the trace is going to end up. It depends on what the object is we're invoking. Right? Is that bad? And let's not again get into how we can go and try to serialize multi-logical threads or processes into a single coherent trace, right? these are all things which like we do in modern programming languages in our sort of day to day thing. These are things which sort of go and make the trace very indirectly represented in our program's text. And so, I think it's uncontroversial to say that generally speaking, in our, you know, code we are trying to represent the state, right? Certain patterns within the state, how we represent data within memory, right? That is sort of what the text of our code most directly represents. And so, let's look at the state of our murder mystery, right? At the outset, right? We have this structure and each of the vertices are here, and they have an associated sense. The sort of person who might be a victim. The sort of person who might be a suspect. And you'd think that the sense of who is a Detective might be kind of narrow, but it isn't. Often the joke it is a little bit incongruous, you have a elderly woman or a Catholic priest and they just happen to come across dead bodies really often, right? But like also, the victims and the suspects, these are pretty broad. Who is a victim? Well, someone who someone else wants to kill, right? And so, we don't get a lot of shape from this if we are ourselves trying to write a murder mystery. But the moment we try to fill in any one part of the structure, the other connected parts of the structure begin to narrow as well. These edges are mutually constraining. The way to think about this is a much simpler structure, a sentence, right? Say we have a few gaps in the sentence we want to fill in. There's clearly relationship between the words. Whatever is on the left needs to be able to jump over the brown thing on the right. And so, the first choice we make here is the most open-ended and everything else is gonna be sort of incrementally narrower. And depending on what we choose, you know, we might shrink our options down to a singleton set, right? So, where we make our first decision when creating a design matters a lot. Right? And in a sentence maybe it doesn't matter, right? We can kind of hold the whole thing in our head, play it backwards and forwards. But dealing with a larger text, a murder mystery, say, our code. But it matters more. We can't fit it in our head. Where should we start with a murder mystery, right? As I said, the relationship between the detective and the other people is a little bit loose because almost anyone could be a detective. Right? And if Miss Marple spends a lot of time in England, we can send her on vacation to find it somewhere else. There are constraints, and the interest sits at the Nexus of the three. It's clear this is where we begin. This is the one decision that gives maximal shape. This is the center of our structure. So, with that in mind, I want to talk about a different structure. One that you're probably more familiar with, which is the venerable model view controller. When this is explained, it's often explained as a broadly trace-like partitioning, right? The request comes into the controller, the response goes out of the view, somewhere in between we do some stuff with the model. But I don't think that's why this is useful. Why I think this is useful is that the model is a superlative center, right? What we put in the model gives a lot of shape to what we find elsewhere in the codebase. And this is why Rails is able to do this autoscaffolding. Once we say hey, there's an entity. It has these fields. Great. Check for what I put for you not controllers and in the view. These are not mandatory. You can go and edit the scaffolding. But these minimize the surprise there, right? They give the structure to this where not only when we're writing do we have the work laid out in front of us, when we're reading, we know that we can look in the model and get a pretty clear understanding of what the rest of the codebase looks like. And so, the model is a very useful center. But it also contains its own structure, right if typically sort of shown as like an entity relationship diagram. And here we have a very simple one, student, teacher, janitor, class, classroom. What's the center here? What's the center of our database schema? I would argue that it's typically the user, right? And, you know, notice here that we've gone from sort of under-directed edges to directed edges. Right because in a relational database, there are no directions to the relationships. But once we put it in memory, references point somewhere and objects contain other objects and typically it's our user that contains all the other things. This provides a sort of path through them. Right? If the student is a user, then we pass through the student to reach the class and the classroom. We take on the perspective of the student when thinking of the class and the classroom. And so, when we think about what is a classroom, we say, oh, well, a classroom is where a student attends a class, right? What do we need to know about it? We need to know its location so we can get there. But if we think, you know, what if the teacher is a user? Well, now, a classroom is where class is taught. We don't only need to know where the location is, we also need to know its capacity and the AV setup, right? How many students can I teach? How can I teach them? And it's worth noting that when you write our MVP-like prototype of this, it's like they we won't come up with a database schema for the setup. I don't know what the taxonomy of that would look like. But it's in our head, our teacher view of the classroom. Right? That becomes part of the meaning of that interface, even if it's not directly represented in our code. So, structures exist to minimize surprise. Right? And the way that they do that is that they have strong constraints and obvious centers so that we can all start in largely the same place. Right? And have a largely sort of consonant understanding of what we can expect elsewhere. And these vertices may contain and constrain other sub-structures, right? The fact that our -- all the things in our model are part of that model. Like that gives them a certain sort of flavor, right? A certain sort of shared meaning. And so, with all that said, I want to move to what I think is a necessary consequence of everything that I said so far. So, top-down development was basically the bad, old big design up front, right? We begin with the master design document. But, of course, that leaves a little bit unspecified. We write sub for the component. In the '70s and '80s, they were ascendant, they would have full on flow charts. When you reach the end where the code was written, that was treated as the least-interesting part. basically compiling it down to code. We don't that anymore, for obvious reasons. But when we put aside the top-down, the obvious sort of resort was bottom-up. We start writing code and the sort of design sort of blossoms up around it. But like bottom-up as it is currently described asserts essentially that it doesn't matter where we begin, right? Sure, we can go and start with the model. But we can also start with the view or start with some util code or something like that. The assertion is the result will be the same. arrive in the same place. I don't think this is true. This is not descriptive of how people write code. People don't start anywhere, they start with the center, they start with the model. I assert that any time we are talking about bottom-up development and we're actually getting stuff done, it's because we are working within these structures and we're not fully 2009ing them at every level. We are descending through this sort of central spine. Right? And then we finally land where we write some code. And then through this sort of surprise and minimization, right? Going back and forth between reshaping the design, reshaping the code, we are going and sort of filling out the rest. And I think that this is, you know, again, a perfectly-reasonable description of what people do to be successful in our industry. And I think it's a perfectly reasonable strategy to do that. But we don't talk about it that way, right? Oftentimes people will go and say, no, no, no. I'm not doing any sort of explicit design. And I will argue in those cases, it's largely because they're unaware of it, right? If you write your entire career writing crud MVC web apps, that's the water you swim in. It might be invisible to you, but it doesn't mean it doesn't exist. So, I have talked about structures and I think these are valuable because structures are a fungible expertise, right? This is the sort of knowledge that we can carry between jobs, right? And clearly, such knowledge exists, right? When we're hiring someone who has like 5 + years of experience, we don't sweat whether or not they know the particular language or the particular framework that we're using, right? We assume that they will pick it up, you know, quickly enough, right? And part of the reason that they are able to do that, part of the reason that they are able to go and get up to speed so quickly is because they know where to look first, right? The one thing they can read that will give them the maximal information. And, you know, I think that structures don't need to be taught, right? I'm pretty sure that none of you here today have ever had someone show you a diagram of a murder mystery. But you kind of know how they work, right? We're good at this. We're good at coming up with these sorts of patterns in our head and thinking about how all the pieces relate to each other. But it doesn't have to be that way, right? We could talk about these things. We could actually go and try to, you know, talk about what these structures are and we could, you know, give names to them. And we could create a shared vocabulary, a shared literacy for talking about them. And I think that's, you know, something that's worth doing. And something that I want to explore in my book. So, that's it. I'm just almost completely out of time. So, please do catch me when the talk is over. But, you know, also, I'll just say,, you know, to everybody in the audience, to anybody watching this video, like, I have been spending like a awfully long time in the wilderness here trying to draw connections between things that have not been connected before. And, you know, this talk was a little bit harrowing for me because I genuinely don't know what other people will thing. Right? I've kind of convinced myself, but I don't know if other people are convinced. So, if you are not indifferent to what I've said here, if you like it, if you hate it, I genuinely would value your feedback. So, you know, here today, at the rest of the conference. Over email. Whatever else. You know, please do drop me a line. Thank you. [ Applause ] >> All right. I think Zach is saying "Buy his book." [ Laughter ] That was great. Thank you, Zach, that was really awesome. Very, very great talk.