Crafting Code Podcast
$ cd episodes/018-searching-for-simple-tools
~/podcast/episodes/018-searching-for-simple-tools $ ls -1a ~/podcast/episodes/018-searching-for-simple-tools $ cat episode-summary.txtWill using simple tools help you keep your codebase simple? In this episode, your hosts try to draw a distinction between simplicity and ease, then examine how they apply to the tools we use to write code. Unfortunately, simplicity and complexity depend on what level of abstraction you're working at. Sometimes we choose to trade simplicity for easiness, or visa-versa. And maybe there are some simple tools that make your coding life both difficult and complex!
~/podcast/episodes/018-searching-for-simple-tools $ cat references.txt- Simple Made Easy. Rich Hickey.
- The Design of Everyday Things. Don Norman.
- P′′ programming language. Corrado Böhm.
$ cat transcript.txt
[00:00:16] Allan Stewart: Welcome to episode 18 of the Crafting Code podcast, where we discuss the importance of doing the right thing at the right time with the right tools. I'm Allan Stewart, a software architect, and lately I've been thinking about 3D printing board game inserts for storing my games.
[00:00:34] Dave Adsit: I'm Dave Adsit, a technologist, and lately I've been thinking about the fragility and neediness of brand new humans.
[00:00:42] Matt Baker: My name's Matt. Lately I've been thinking about building actor systems.
[00:00:47] Allan Stewart: Our episode topic today is searching for simple tools. There's a lot of tooling that is needed in crafting code. But to give context to this discussion, we need to first start by answering the question, what is simple? What does simple mean when we're talking about searching for simple tools?
[00:01:05] Matt Baker: I don't have a definition myself, but I can borrow from one. A guy named Rich Hickey has a talk online called Simple Made Easy, and he separates the two terms, simple versus easy, in order to, I think, highlight what a simple tool is. And the quick summary of his talk is that easy tools are easy because they're familiar to you. For instance, if you speak German, you might think it's easier to speak German than someone who doesn't. Right? Or if German is your native language, you might say, yeah, speaking German is easy. And that's because it's something you're familiar with. It's something you've grown accustomed to, and it's easy to you. Whereas simple, this is Rich's argument anyway, he says that simple is a measurement of how complected things are within the thing you're talking about. So like within the tool, if we're talking about simple tools, and he defines complecting as braiding things together or interweaving things. And so I take that as the amount of things your tool does, like the amount of responsibilities it has. And there's like whole degrees of scope here that it's hard to, it's almost hard to talk about and hard to figure out. Like when you say a simple tool. Tool. What degree are you talking about? And so I think as we have this discussion, we're going to have to set our, our scopes pretty clearly. But anyway, in summary, yeah, Rich Hickey's thing, he says there's a difference between simple and easy. Easy is something you're familiar with that comes naturally to you might not be the case for someone else, but simple on the other hand is the amount of things that a thing does. And we should strive for simple things, not necessarily easy. Yeah.
[00:02:46] Allan Stewart: I recently went back and rewatched that talk and I was surprised. First of all, that it was from. 2012. So it was a little bit older than I remembered. And I was really interested to see how much I had changed since a previous watching of that talk. But I also think it's really interesting to think about that distinction between simple and easy because we get caught up with tooling a lot with our own familiarity. It's actually related to our recent episode about programming languages. Sometimes we think, oh, that programming language is hard. It's difficult. And we conflate that with being complex. That language it's it's so complicated. I just can't get my head around it. But really in a lot of cases, it's really speaking more towards our familiarity. Things that we have done before are familiar and they're easy. Things that you've never done before are hard. I'm working with a person right now who is very new to coding. And so placement of curly braces is difficult. It's something that they're still trying. They're trying to understand. Whereas for a lot of seasoned developers, they don't even think about it. They just let the tooling take care of that for them or they're just have muscle memory around it. So as we talk about simple tools, I think that that's important. The other thing that I think about a lot in terms of how easy or complex a tool is, is also just around how much you keep in your mind. I think the more complicated something is, the harder it is to keep all of the pieces. At the same time, mentally. And that reminds me of the book, The Design of Everyday Things by Donald Norman. He talks in that book about how the average person can only really keep seven things in short-term memory at any given time. And so how complex your tool is, is going to matter. If it's too complicated, you can't actually use it effectively because you can't keep all of those things in mind all at once. Oh. Okay. That's interesting.
[00:04:53] Dave Adsit: You know, I've spent the last three years trying to learn German and I have found it to be quite complex. It has not become easy for me yet. Initially, what you were saying about how many things you keep in mind and how many things your tool forces you to keep in mind, it got me thinking about some of the rules that we put in place, some of the guidance that comes down from, you know, previous developers around abstracting. Yeah.
[00:05:43] Allan Stewart: Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. is Git. Git is difficult to use, especially when you're first starting to use it. And there are things that you can do with it that will mess up your repository in ways that just feel completely unrecoverable. rm-rf, this whole directory, I'm going to clone it again because what even happened, I don't know. But on the other hand, I think most developers only really use a subset of Git, especially if they're using trunk-based development. For what it is accomplishing, it's not actually all that difficult. There's only a handful of commands that you need to know to be able to do trunk-based development successfully. You can work together with a group of people, sharing code, having a store on GitHub or Bitbucket or wherever your favorite place is to store code. That can actually be done pretty easily. It's really focused in on one Kind of work. I don't have to worry about how many different extensions are installed into Git. All I really care about is let me clone the repository, do some work, commit some code, push it. In that case, it makes me think, well, maybe Git's not actually that complicated of a tool. It might be a difficult tool to use, but it really does focus in on the one thing that is source control, as opposed to trying to also have a tool that's not that complicated.
[00:07:15] Dave Adsit: I do think that Git is a response to more complicated tools that had been available before it. Tools like Clearcase or even Team Foundation Server, any of these tools that are trying to be multiple things. I think that that's one of the advantages of simple. You're not bringing in extra complexity, unnecessary complexity. You're not entangling source control and how essential. Source control is with your build system and your ticketing system and all these other types of tools that you end up getting when you've got a ecosystem of source control. That's not to say that every feature of Git is easy. I have certainly had to Google some fairly arcane things that you only do once in a career. Luckily, someone on Stack Exchange can tell you what to do and you try it and it may or may not work, but it's okay because it's all local. You don't have to push to somebody else until you've fixed it.
[00:08:19] Matt Baker: So now that we have this framework separating simple versus easy things, and we want to talk about simple tools, so why does it matter? I think that your code reflects your tools. So the more complex tools you select, the more complex your code will be. I also think you should prefer less complex code. So if you just turn that around and it says, okay, if you want less complex code, you have to use less complex tools. And on the surface, it's like, yeah, okay, that makes sense. Maybe that's not even what we're saying. And I was at a talk, a conference talk at some point, and the speaker said, the complexity of your tools is a comment on the complexity of your code. And I kind of clicked with me. I thought, man, I really agree with that right now. At the time I was working in a big IDE. So yeah, I think that you should strive for more simple tools. And I think that because simple tools will help you produce less complex code, but then the follow-up question I would have is, well, how do you define the complexity of code? So if we're talking about, we want simple tools because we'll produce less complex code, how do we measure the current degree of our code complexity? Do either of you have any ideas for
[00:09:27] Allan Stewart: how we might measure that? Bringing it back to like your hypothesis there, it sounds like you're saying that if you're using a big IDE that has a lot of bells and whistles, that essentially you're more likely to utilize a lot of these tools, a lot of the things that are in your tool, that have complexity and it leads towards code complexity. So like if my IDE has mechanisms for doing database integrations, that I will make my code more complex because I'm kind of chasing after these other bells and whistles. It's like, oh, the IDE will let me do this. And so I'm more likely to actually invoke that. Is that the hypothesis here? It's squishy, right? I think so.
[00:10:13] Matt Baker: So for me, it's... This might be saying the same thing you just said, Allan. I think your tool will shape the way you look at the problem you're working on and in doing so, like drive you towards certain solutions. Like if you take a big IDE and maybe you set up an app and let's say, I don't know, you create some database migrations in the IDE and then maybe the IDE layers on top some sugar that ensures those database migration scripts run only if they need to and kind of manages that. And so you... You just build an API with database migrations that way and you ship that. On one hand, it's great. On the other hand, you just shipped a lot while having to do a little. And I wonder if there are times when that kind of example can go in a not good way. Like surely there are times where having that database migration script management and the IDE is nice, but are there situations that are similar to that where it's no longer nice? Like does your IDE make it easy or even encourage you to do things that don't work? Yeah.
[00:11:27] Dave Adsit: Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. number of lines of code that you have, the number of structures that you have, classes, functions, whatever those structures are in that language. And one of the things, like there's the rules, the four rules of simple design, one of them is, you know, minimize the number of things. After you've expressed the problem or the solution to the problem, you want to minimize the total number of things necessary. And so I'm reminded a lot of the discussions around these concepts that happened around the time when Ruby on Rails was getting very popular. And it was all about, you don't have to do so much to get things going. And that felt really good for a while because you're like, you just create a database model or you create a model and you use the model in your code. And that model is using ActiveRecord and it's tied to the database. But you don't really think about that or worry about that that much because you're just dealing with the code. You're dealing with the simple parts of your domain and keeping your domain simple and pushing all of that complexity out. And that's, you know, you're pushing it behind an abstraction, but you're also relying on a framework to do a lot of the work for you. And so it's like, where is the complexity? And how much of the complexity is essential to solving this problem versus incidental because you're doing things? I used to go to a lot of code retreats and you're coding and you're doing things. We talked about this in our programming languages episode. There's a constraint that they give you during some of the sessions of code retreat where it's like, do not write any function more than two lines of code long. And there's always the caveat. Unless you're in a C-based language or C-derived language, then you can have three. And part of that is because you've always got those extra braces. You know, a Python developer looks at the braces in C-sharp and like, that's unnecessary. And a C-sharp developer looks at the white space, the significant white space in a Python code base and says, I will lose my mind. I have to turn on visual white space to even know what my code is doing. Both of these are attempts at reducing the complexity and making the ideas flow. I think, but from different perspectives.
[00:14:00] Matt Baker: You mean they want you to get going quicker?
[00:14:03] Dave Adsit: I think that most programming languages, most toolkits, most frameworks are built around the idea of you should be able to get started and get going fast.
[00:14:14] Matt Baker: Yeah. It's interesting. Like my first thought is that sounds more like easy. And so I start to try and get back to simple and I say, okay, like if I use this tool, if I use a framework and I get going fast and then I stop and I look at what I built and let's say maybe it's scaffolded some code for me. And then there's a, there's a little bit of a runtime that it needs in order to execute. How do I measure that complexity in a meaningful way? Like how, you know, like, how do you get out? Like, I'm not talking about like, well, like it's definitely three degrees complex and we all feel good about that measurement. Like I don't, not just for the sake of it. I want to say like, when you look at what you've built and you start to think, is this thing complex? And is it so complex that it's going to get in my way? Like, how do you actually start peeling those layers back? Right. And so one of my first questions is, okay, well, if I want to understand how complex this thing is, like, what the hell does that mean? How am I defining complexity? Is it like, let's take lines of code for instance, like just for the sake of conversation, like if you scaffolded something in a, in a framework like Ruby and you're measuring complexity on lines of code, you're immediately complex, right? I don't know how complex you are, but like when you scaffold a new, or I could use a different one, like I'm using AWS CDK a lot lately, and you create these little things called like apps and then stacks and you deploy those into. The AWS when I create a new one, I scaffold it. So I immediately have a few hundred lines of code. It's like, okay, well, is this, is that good? Is that bad? I don't know. Like I haven't even written any code yet and I already have like 300 lines of code. And so I think, okay, well, what are the limits of lines of code? Just as one example. So like the problem I'm trying to tee up is like, how do you actually ascertain complexity of something you've built? And then how do you take that far enough to say, and this is why it matters, right? Like if it's, if it's just to like, like I said, just come up with some arbitrary measurement, But like, how, why does it matter to what you're trying to build? Why does it matter to the company you're trying to build or the team you're trying to build or, you know, feature or whatever?
[00:16:15] Dave Adsit: I think it has to do with the ratio of essential complexity to incidental complexity. And now you just have to figure out how to measure those two things, right? How much of this code is expressing a domain concept and how much of this code is necessary? Because of the language framework or toolkit that I'm using. One extreme example from my past, because I like to go to examples because it helps me to get concrete. We were building a product that used the CSLA, which I don't even remember what that stands for. It's like common something, garbage, tire fire. Anyway, so we had a template for new classes and the template was 10,000 lines long. And you copy the 10,000 line template or you'd like CSLA new template or whatever. And then you get the 10,000 line class file. And then you would add like maybe 20 lines of code total to that file. And that's partially because the tools didn't support things like partial classes. And it's partially because the person who built that framework was trying to make it so that you could at runtime decide whether you were running on a single server or multiple servers. Doing it. It was a hedge against a future that never happened.
[00:17:59] Matt Baker: Oh, that's interesting. Would you say it was quicker to use it than not use it to get to where you wanted to go?
[00:18:06] Dave Adsit: No.
[00:18:06] Matt Baker: It would have been quicker to not use it?
[00:18:08] Dave Adsit: In that case, it would have been quicker to not use it.
[00:18:11] Matt Baker: And just so I understand clearly, you decided to use it because you thought you were going to scale and it would set you up to scale better?
[00:18:17] Dave Adsit: Yeah, it was a decision made by the architect on the team at the time who wanted to basically provide extensibility for an interior environment. And that was back in the day when everybody was like, well, you have to have your presentation layer servers and then your middleware servers and then your backend servers and then your database servers. And by using the CSLA, you could say, I'm going to write one class file and define this idea. Once, and then I'm going to deploy it in different ways at different times. And it is like a relic of the, I don't know, it's definitely not the way I think about problems now. I think that, you know, a good software engineer has an idea how the code is going to be deployed in the production environment. At least partially because they're working with the ops specialist on their team to deploy the code into the production environment on a regular basis.
[00:19:19] Allan Stewart: Going back to what you were asking Matt about, why does this matter? It makes me think that it matters because of the architectural principle of separating things that change for different reasons. Because when we have things that are complex or literally complected, to go back to that definition from simple made easy. If everything is like all braided together and complected, it's hard to separate things out. And so it makes me think about your example. Maybe your IDE has a bunch of database tools. And so you're using the migration tool. And because you're using the migration tool, you're also using their testing framework and deployment framework. That's all like baked into the IDE. And that might be great for a while. You're able to move fast, get started quickly. And in certain contexts, that might be all that you need. There may be a context where you're in a very early pioneer exploration kind of stage. And you just need to be able to throw. Stuff at the wall really quick to see what sticks. But over time, a year or two later, they've put out a new version of the IDE and the old version is not supported anymore. And by the way, you bought some new hardware and it won't even run on the old stuff. So now you're stuck because the complexity of like the migration path is difficult. Or maybe you skipped a version because it was difficult and it only got more difficult as you, as you went on to more and more versions. So the IDE. what do you do to separate your business logic from their framework? They don't have a lot to say about what is going to change and why you might want to do something different in the future. And so if we find simple tools that solve a particular problem, it might be more work upfront or to transition from a single fast, easy tool to a multitude of simple tools. But the simple tools have that advantage that each one of them can be independently swapped out. You don't like your deployment tool? Fine, change it. You don't like your database migrations tool? Change it. But if you're using everything all mushed together, they are complected and you're going to have to do a lot more work to loosen up that weave enough that you can pull out the cord
[00:22:06] Matt Baker: that you want to replace. It's interesting that you arrived at coupling there because it makes me think, okay, so like I'm still on this horn about how do you define complexity? If you have six things that are loosely coupled, that feels less complex based on the definition of like the simple versus easy than it is one thing that does those six things. And I think that's probably because of the way change ripples through it. So one of the things that I'm hearing,
[00:22:31] Dave Adsit: whether you're saying it or not, is that single responsibility applies to the tools we use, not just the classes that we write or the functions that we write. That concept of single responsibility and composability, those are critical to creating the ecosystem for the code. And by building something that's small and focused and simple, we then take upon us the responsibility for ensuring that it can be integrated and used in a bigger system that has more going on. Rather than trying to be the big system, we use that small focus tool with a single responsibility to do each of the pieces. I used to be a big fan of the Visual Studio IDE, and eventually I was like, what is this thing doing? It's got all of these tools in it. And it's doing things that I don't want my IDE to ever do. I'm not convinced I want my IDE to even know about source control, let alone my database, et cetera, et cetera. Certainly the IDE that I use these days has all of those plugins available because it's convenient for some people. I just choose not to use them.
[00:23:41] Allan Stewart: It reminds me of the Unix philosophy of making a whole bunch of little tools that can be chained together and that you can pipeline these things. I like what you said about responsibility, Dave. Where are you deferring responsibility and what do you need to be responsible for? So in the Unix philosophy, each tool just does its one thing, hopefully extremely well, and it's up to the person who is piping all the commands together so that they can grep and word count. And said and whatever else that they're going to do, that's their complexity and it's their responsibility to know whether or not it works or not. And so when we defer responsibility to another party, that can sometimes be useful. That can sometimes make us go fast, whether it's a framework, whether it's a IDE, whether it's some other tool, like I know for React, there's start React app. And one of the things that it gives you is the ability to, you know, you can do a lot of things initially initially initially initially initially initially initially initially initially initially
[00:25:10] Dave Adsit: initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially initially it does to you. So if it helps you do X, Y, and Z, it makes you do X, Y, and Z in the framework's way. And if you want to do it a different way, you have to find a way to decouple and deconstruct
[00:25:25] Matt Baker: that framework. I keep coming back to this question of what do you gain by reducing your complexity? Because I think that's where the conversation is headed, like more complex is bad than less complex. And I think the less complex your code base, the easier it is to add new features or update current ones. And I also think the more composable it is. So going back to what you were just talking about, Allan, the Unix philosophy, being able to compose simple things together. I think the ability to do that is somewhat predicated by those things you're composing being simple. The more complected those things are, the often in practice, the less composable they are. So maybe there's this aspect of building software where we favor compositions of lots of small, discrete things. So I think that's where the big thing, like Dave was saying, and the big IDE, because I feel the same way. I've switched to a more bare bones way of writing code lately, and I don't miss the IDE, and I kind of look back with like disdain a little bit. But I think it matters. And I think that matters to your bottom line, I guess is what I'm trying to say. When your code's complex, it's harder to add new features and maintain or update current ones, and it's harder to extend it. And then I also think it's harder to, it's rather easier to hire an onboard engineers, the less and less your complex your code gets.
[00:26:45] Allan Stewart: There's an interesting balance there too. And I think it also plays into the purpose of a tool. We talk about IDEs, but there's also just text editors. And there's just, there's a question in my mind about like, how simple do you want to go? Because to get more simple, you have to be focused on less things. And so a text editor, generally speaking, is more simple than an IDE. But it also has a more narrow purpose. So like for me personally, I would say I want intermediate level of complexity in some of the tools that I use for writing code. Because yeah, having a really big bloated IDE, it has problems and there's the potential, right? There's the temptation that I might reach in and use a bunch of stuff that I shouldn't. Or maybe I'm just, I'm relying on it like a crutch. But on the other hand, why are there so many different editors? And some of them are serving different purposes and they're not necessarily interchangeable. I could just use Notepad that ships with Windows to write code, right? It is able to write at least some form of ASCII, maybe not UTF-8. Potentially you could use it, but you're going to lose all of these other features, right? It's not going to help you with matching up your braces. It's not going to give you syntax highlighting. It's not going to give you any code completion. Are those things that I can open up something like Nano or Pico on a Linux box or a Mac, and I could write code using that. It's super bare bones. It's about as simple as you could get. You are able to type characters in, and there's like 10 commands in total. You can save the file, you can exit, you can page up and down, you can cut a line. Those are the only things that even exist in the tool. But that might be that it's no longer useful. I don't know that I want to keep in my head all of the exact syntax that a bigger IDE will help me do, let alone some of the other tooling that are nice conveniences, like refactoring tools, where I want to say, hey, I've selected this text. Please extract a variable or extract this out into a separate method. I can do that by hand, but should I?
[00:29:05] Matt Baker: Yeah, it's really hard. So I think we're agreed that The tools you choose, I feel silly saying this, but the tools you choose definitely impact the end result and complex tools can make for more complex code. But there's in situations, Allan, what you were just saying, that call for it. In certain scenarios, you absolutely want those refactoring capabilities. I'm thinking like a big old crafty code base that was maybe a few hundred thousand lines or millions of lines of .NET or Java or something that you're having to sift through. And you'll want a more powerful IDE. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. going to want the IDE of the time most likely to try and wrangle that thing. So how do you know? Like when you when you go to make a decision, how do you know if you're dealing with too much or too little complexity? I, my answer to this lately has been start with the simplest thing that could possibly work and then iterate. And if that means doing something manually at first and do it manually a few times until you get a sense for what it if it's really a big time suck, and it's going to drain your day to day, then maybe you should solve it, you know, and I think when you take the simple approach, it helps you check your own assumptions at the door and say, you know, I'm going to give it a week coding this way. And then I'm going to prioritize a fix for the worst part about the week. So as a concrete example, if you're shipping, let's say you're you're writing some code and shipping it into the cloud, maybe your deployment time into your cloud provider is 10 minutes, and you deploy a lot, and you can make that better. So maybe you should adopt a tool that makes your deployment model better, right? And there, I'm sure that there were other things throughout the week. But you went through this exercise of saying I worked this in the simplest way I possibly could for a week. And the thing that sucked the most was waiting around 10 minutes every time I had to ship something to production. So that's the thing I'm going to fix. That's the spot where I'm going to accept the additional complexity. I think that there's definitely
[00:31:28] Dave Adsit: something there with the idea that different tools, and frameworks, etc, are more appropriate for different contexts. There have been a lot of tools that have come and gone that have been optimized for getting a quick start. I'm reminded that Microsoft Access was intended to be used by, you know, your secretary or your admin or your department secretary or admin to create reporting for the manager. And every tool that every every project that I ever took over that was originally Microsoft Access basically was a disaster. Because there was too much accidental complexity. I'm not even going to say incidental because it may not have just been because of the tool. It may have just been because of the lack of knowledge and experience of the people using the tool. There's definitely a lot of value in taking whatever the complex or time consuming or hard
[00:32:24] Matt Baker: thing is and making it simple. What I would add to that is there's value in giving the hard thing The reason I like the simple like start out doing everything just in the most simple way possible is that you can still be delivering value to what you're doing. You're not sitting there like in a room whiteboarding like solutions for all the risks you could possibly face or something like no, I'm going to move forward in this week, I'm going to do it all manually. And then that gives your solution, it gives the problem you're dealing with rather time to emerge and time to kind of present itself because that stuff is not always obvious upfront. You know, you I think we all know what like to pre optimize the first like week or two into a project and then find out not only did it not help but your pre optimization now actually got in your way and made it more difficult for you to move forward.
[00:33:13] Dave Adsit: I mean, I've seen that with attempts at going to a microservices architecture before it was necessary. We're just going to make this one microservice and like we've doubled our complexity and deployment because now we have two things to deploy every time we deploy, and they have to be done together, because we didn't do a good enough job of untangling them and making them simple rather than complex.
[00:33:38] Allan Stewart: It strikes me how much time plays into this equation. If it was just something that is happening for a short period of time, and then it's done and it's over, then a lot of these decisions don't matter. You could do something simple or you could do something complex and using the complex tool might actually be preferable, because you are able to get more, a bigger set of things done more quickly. Which may be part of the reason for the preponderance. If you're only going to do it for some kind of limited scope, maybe the limited scope is in the amount of time that this thing is going to live for. Maybe the scope is how often you're going to allow it to change. Maybe the scope is for how many features are there. Then those solutions may be perfectly fine. You find the one that does what you need and you're golden and you can just be done. But if it doesn't do what you need over time, if some of these constraints fail, it's no longer true that we're not going to add new features and we want 17 new features now. Or it's no longer true that we're going to throw this away. We're going to keep using it indefinitely. We're going to keep developers on and continue to work on it. All of those constraints mean that there's change over time. And that makes it harder for complex solutions to work. And so it makes me think that there's some kind of middle ground that you just have to strike. It's hard because everything in software is that way. We're constantly saying, well, that depends. And you have to look at the context of a problem. But there's just no way around it because code is such a complex endeavor. It's one of the most complicated things that we've ever tried to do in all of humanity. And so we really have to be careful. And we have to be careful about how we take it on. I like what you're saying about starting off simple, Matt. I wonder if you can go too simple to start off, though. I wonder if there's some amount of like you're trying to stay somewhat simple, but there's some level of accepted complexity that you're willing to take on. Like things like your IDE, right? I'm not willing to write all my code in nano. And so therefore, I accept that I'm going to have Git integration. And there's probably an extension sitting off there just tempting for doing code deploys or database migrations or something out there. But it may be worth it to have that initial level so that you're not starting at ground zero every single time.
[00:36:27] Dave Adsit: I think that there is a context there about who is doing the thing. If Matt is saying, I'm going to write the simplest code that could possibly work, then I'm going to have Git integration. And when I find a case where it doesn't work, I'm going to change it. Great. I have full confidence in that. Even if he has to deal with things like database protocols and HTTP, I'm comfortable with Matt doing that. I know he's been doing this for more than 20 years and he knows his way around a code file or two. If I'm working in a different environment where I've got a bunch of novice developers, I want to provide them with more support because I have less confidence that they can deliver on the promise of simple and just change it as you run into problems. I think that that is something that we have to take into account when we determine which tools do we want to adopt or embrace for this system. There's a lot of tools in an experienced developer's head that are not available to a less experienced developer. And do we need to keep things simple so that the less experienced developer can work on them? Yes. What does that mean for them? It's going to mean something different than what it means to keep it simple for somebody who could write their own text editor and their own programming language and their own compiler or interpreter.
[00:37:59] Matt Baker: Yeah. Easy, right? Not simple. Simple is the degree of complexion. Easy is relative per our model at the beginning.
[00:38:07] Allan Stewart: It's a difficult judgment between simple and easy there because a lot of the things that you need to do to make it easier, which requires less familiarity, which is more broadly inclusive of people of different backgrounds and skill sets, also has this tendency to have complexity baked into them. Yeah. They're handling more things. They've complected more kinds of things because not everybody has all of that knowledge in their head. And so they're trying to help you out. And so if you reach for something that is easy to use, you might be adding complexity to that development environment, which may or may not help you to get simple code out. There's some interesting tradeoffs going on there.
[00:38:53] Dave Adsit: Well, at the end of the day, it's all complex. There is no such thing as writing simple stuff. Because at the end of the day, it all relies on being turned into binary instructions that can be interpreted by the processor. Kevlin Henney pointed this out when he's like, oh, you're hiring for full stack. Which compiler or which processors are you targeting with your compiler that you're home growing in-house type of a thing, right? It's like... Nobody actually is full stack because we all sit on top of compilers and operating systems that someone else wrote.
[00:39:36] Allan Stewart: Or even which beach are you going to get a bucket of sand to make the silicon that you're going to run this software on?
[00:39:47] Matt Baker: So at my current role right now, it's a greenfield project. It's me and two other people. And we're each working on our own little piece right now. And we're still in the POC stage. We're writing stuff and shipping it up to a cloud and then having it execute in like a ephemeral compute model. You know, like a service model, like GCP's functions or Azure's. They might also call functions, right? AWS's Lambda. So to test some of these ideas out that we've been talking out, I decided to start coding in Vim. And I don't use any of the plugins other than one or two. I use command line git for my source control. And then I push, excuse me, I ship code with the cloud vendor's command line tool. So I never leave the terminal. I don't have any IntelliSense. I don't have any like refactoring capabilities. Like I honestly, I miss rename sometimes. I've only been doing this for like maybe about a month, but I miss a few already. But I'm also moving the needle on the company goals like consistently because I'm just focused on like, okay, what's the next thing the company needs? And so when I go to do something. Like as an example, I have to start a, one of these ephemeral compute instances by putting a message onto a log. And then the compute instance is subscribed to it. And so I actually just open up the cloud vendor's CLI tool and push the message JSON just right in the terminal. I just write the JSON right there and I push it. And one of the commands says like, do this thing. And then it goes and invokes the process that I'm working on. I see if it worked. And then I go on. Like I could write some code to change that, right? Like have a little script that says. Start the thing. Start the engine. But that's, I think that's an interesting comment on our simple and easy conversation. So is it easy to know the schema of the message that needs to be put onto the log and started in order to start the ephemeral compute instance for what I'm working on? No. Like you're going to have to go read the code or the schema or have a document somewhere in order to know that. But is it simple? Like per our definition, I think, yes, it's one thing. It's one way to do it. It's this message onto this log. And it might not be easy for you to do that, but it's still simple. And when you figure out how to, when you learn how to do it and like me, have it at the top of your daily notes, you can just go copy paste. And it's very easy. And it's also simple. And so I'm in this spot where I'm able to bring it. I'm able to start this like the, when you ask the question, you know, what's the simplest thing that could possibly work? I'm able to turn that dial way down and say, well, let's see what that actually is. And. And like I said, there's certain things that I've been experiencing over the past month that I don't like, like not being able to rename symbols and the text file is it sucks. But there's also, I've noticed the way I write code is changing because I don't have those things. I'm not willing to proliferate a bunch of code. And because I'm in Vim, if it starts to get over like 50, 60 lines, I start to get kind of icky or not. I start to not feel good about the file. I start thinking there must be something wrong with it. And I. I shouldn't say because I'm. I shouldn't say because I'm not in Vim, but I've started doing that more as I've been coding in Vim. I pay a lot more attention to the size of the. The code file than, than I ever did before. And I, I have some theories for why, but I will say that that's causing me to think about all the things I'm putting into a particular file. And this code base is in Python. So groups of functions. And so I'm noticing that my choice of those tools is in fact changing the way I'm writing code to solve the problem. But at the same time, like there's certain things that suck again, like refactoring. And so. So I suspect at some point there'll be an addition to the workflow, right? Like maybe I'll get a better Vim plugin or a more complex one that's warranted and given the situation. Um, but I like that I'm taking the time to figure out what's warranted and then what we ultimately choose. You know, like, I think it's on, I think you're in this constant carousel of simplest thing that could possibly work. Where does it suck? Okay. Like take on a little bit more complexity if you need to, to make that thing that sucked a little bit better and then go again and go again. I don't know. We'll see where this takes me at some point. I might just say to hell with all this, give me my more robust ID back and whatever. But so far it's, it's been a fun experiment and I am being productive day to day. I would say it's, it's no more or less. And I'm continuing. One thing that's nice is I'm not in the phase of what's all the risk that is coming my way and let me hedge against it and introduce all this complexity upfront. I, we're not doing that. We're saying, well, like we see our goal and we know there's a ton of crap we don't know, but we're going to try and get it done. And then we'll go there and then we'll iterate on our approach. And so that, that to me is like a way, an actual concrete way that you can start to answer the question. How much complexity do I need to take on? Cause I don't know that you can get it like just by looking upfront. I think there's a big portion of reflecting on how your day to day is going. That's going to help you, you know, get to this, maybe get to some semblance of an answer for how much complexity do I need to take on for the given situation? Because you both highlighted, there's so many variables that could be involved when you say, well, you know, what do you mean too complex for this situation based on what? Like, because again, if you're working in an old IDE, excuse me, if you're working in a code base that was written 15 years ago and it's .NET or Java, like any corporation and let's say it's a few million lines of code, it would definitely be more complex to try and make, I think something like Vim work in that environment. And it would to make something like the Java IDE work. Or the .NET IDE they used to write the code in the first place. And so yeah.
[00:45:31] Allan Stewart: I'll be real interested to hear how your system shakes out over time, because it's making me think a lot about different abstractions and where we try to simplify things. We can make things simpler by making a lot of functions a lot of small functions instead of big functions. Right. Or like what do you put inside a function or how many functions should be in a class? Or how many classes should be? And like, there's all of these like different layers. And so you're starting out real small with each deployment into this serverless environment. But eventually you're going to have to complex those serverless pieces together in order to get them all working together. And will the overall complexity of that be worse than having more complexity in each individual instance? I don't know that I can say, because this is like a fundamental problem that we've wrestled with. I think we have learned a lot. We've learned that lots of small things is better than few really big complected things. But we'll have to see what happens with those abstractions. And I think abstraction becomes key in facilitating that work. Because at some point you have to complex things to make interesting code. And so you have to figure out, well, where are we going to complex it? And how are we going to deal with that abstraction? If you can create an abstraction that hides the complexity, then you can treat that thing as if it were a complex thing. Under the hood, right? Like at some point you're looking down at what all the assembly instructions are, right? Like the code that actually flows through the processor. That's going to be always complicated. But we can hide a lot of that complexity behind abstractions that makes the layer that we're working on easier. And so it's really important to make the right abstractions. Because if you have a leaky abstraction, then that's going to be a problem. And that's going to start polluting your space that you're trying to protect with additional complexity. And that's why I don't like magic in tools and frameworks. Because they hide from me what's really going on. If the concept was sufficiently abstract, then it's not magic. It's just doing something for me. I've thought about it in the past in terms of tying your shoes. Is that the interaction between billions of atoms? Or is that the one thing that you do before you go out the door? Or is it just wrapped up within the idea of, I need to go out and get some milk? Depending on the context that you're in and what level of abstraction you're working at, it's all of them.
[00:48:09] Matt Baker: Yeah, it just continues to spiral as we pull on it. And one of the things that's coming up in my mind again and again as we're talking is the importance of moving in the small. And reflecting on the effects of those movements. Again, just like everything else we've talked about, that has degrees of scope. What it means to move in the small at a tiny company means something different than what it means to move in the small at a big company. But I think it's more like, maybe it doesn't. Let me restate that. I think it has to do about minimizing the amount of things you change at one time and then observing the results of that change before moving on to the next. That's one of the ways that I think large or small, you can try and wrestle some sense out of them. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. everything has to complex like in order to become useful but that does not give way to everything should be complex like there's there's an art to what's complexed together which i think is what we're talking about what going to the unix philosophy what simple not easy but what simple tools can i pipe together here can i compose in order to get this job done you know like what's
[00:49:46] Dave Adsit: the simple way to go about it one of the other kevlin hinney talks that i really like he talks about the rule for calculating leap years which is super easy it's every fourth year is a leap year except every hundredth year is not except there's like three levels of exception in in the definition and so that becomes your essential complexity right and that's it's just it is complex it's like at the end of the day if you're accurately calculating a leap year it's not as trivial as it seems like it would be considering that we only encounter them about every four years i'm probably misremembering this because it's been years since i watched the simple made easy talk but it was kind of a sales pitch for the closure language right
[00:50:39] Matt Baker: subtly it was like i think it was a sales pitch for the philosophy okay like and and yes so since he writes closure he would say like and this is the philosophy that i bring to closure so i can
[00:51:12] Dave Adsit: effectively essential for doing anything useful in closure anytime I tried in the far distant past. And so I think this is just another reiteration of what is complex is a function of what is familiar. Are you sure about that? I think so.
[00:51:33] Matt Baker: Interesting.
[00:51:34] Dave Adsit: I think that what feels complex is a function of what we are familiar with and what we have been trained to do.
[00:51:42] Matt Baker: Yes, I agree with that.
[00:51:44] Dave Adsit: Because anytime I try to show somebody some of the C-sharp code that I'm working on, anybody who doesn't know programming, they're like, this is nonsense. For me, it goes back to the idea like we have an assumption that anybody who is going to speak publicly in our society is literate. But we also have an assumption that mathematical literacy is hard. And so a lot of people are mathematically illiterate. And even those who are mathematically literate are illiterate of statistics. Before we started recording, we were talking a bit about the statistical likelihood of certain things happening. And it's really hard for our brains. So it feels really complex. And it's especially hard if we haven't had any training in it. And so that's where I'm kind of landing. And I'd love to be shown what I'm missing. But to me, I'm starting to feel like complexity is related to familiarity.
[00:52:40] Matt Baker: I think that's what Rich Hickey was taking issue with. And saying that simple is a measurement of how much complexion has taken place. And then from that, you get to complexity. Whereas easy is a measurement of how familiar it is to you personally, as opposed to the number of complexions. I don't know what the word is.
[00:53:00] Dave Adsit: I get that. And I agree with it. But also, I think that a lot of those happen outside of the system in front of us. And they happen in our own heads, in our own experience, in our own training.
[00:53:13] Matt Baker: What do you mean? Tell me more.
[00:53:14] Dave Adsit: Well, I mean, all software code looks complex to a novice. And professional software looks complex to an amateur. One example from my history, I think I may have brought it up before, is I took over a code base that was, I was assured that it was weird and hard to work in and had all kinds of unnecessary indirection. And when I opened the code base, I was like, oh, this code was written in such a way that it's not going to work. And it was written in such a way that it could be easily tested, given the framework at hand. And it had a test suite. None of the tests passed. They didn't even compile. They had been removed from the compilation target, and they had been excluded. But they were still in source control, because even removing them from source control was too complex for the people who were working on the code.
[00:54:02] Matt Baker: I just imagine some engineer, like, right-clicking on the project and being like, exclude test, problem solved.
[00:54:10] Dave Adsit: That's exactly what it was. There was a project. There was a project for the software, for the website. It was actually a web application. And there was a project for the tests. And somebody was just like, I can't even with these tests right now. And they excluded the project. It was still in source control. It was still on disk. I checked out the code. I joined the team and checked out the code probably a year after they had stopped doing tests on the code. And I was like, well, this code actually does not feel complex to me. It doesn't affect every single class. System has a single responsibility, except for the ones where the people who had no idea why it was the way it was started writing code. And there, there were a lot of responsibilities, all in a big ball. And that was, to me, that was the complected code. But to the other developers on the team, all these unnecessary abstractions and interfaces and tests, that was the complexity.
[00:55:08] Allan Stewart: It's interesting and makes me wonder if there is some hidden. link between these two concepts that they're not completely orthogonal. And we see this in some other areas with software too, right? Like when we talk about socio-technical systems, we want to say that the technology is one thing and the people is a different thing and they're completely orthogonal and you can vary them independently, but it just isn't true. There's a level of coupling between your people and your code that you can't get away from. And if simple and easy have a similar hidden connection where you can't completely decouple them, you can't just pull on the one lever without also doing something with the other level.
[00:55:56] Matt Baker: I think it highlights for me that you got to get clear on what complexity means for you and your environment. Like if you're actually going to make decisions based on this stuff, like if you're going to say this complexity is worth it or this complexity isn't worth it, whatever. I think that's one of the things that sticks out to me that we, even the three of us, I think have divergent definitions and why wouldn't we? It's just such a broad, ambiguous thing. But for a specific situation, I would say define what it means. Like if you can define complexity as number of responsibilities per file, that's fine. And then work within those bounds or lines of code or whatever, but get clear on that. Know what you mean. Because if you don't, like you stick in this, I don't know, you just, you're in this space where we're all using the same word, but you mean it's hard to talk.
[00:56:50] Dave Adsit: So I'm thinking about programming languages and I had to look it up really quickly because I only know it's derivative language, not the original, but there's a programming language, P double prime, which only has four operators and it's Turing complete because it expresses a finite state machine. And so you can write, presumably any program can be expressed in that language, but I wouldn't call that easy because it's not familiar. I also don't think I would call it simple because you have to create all of the structures yourself. It's not complex. So maybe it's simple.
[00:57:33] Matt Baker: If you agree to the model of simple and easy, simple is number of things, and easy is point of relativity, how easy it is for you to understand. How familiar it is. Yeah. Yeah. Do you still say it's not simple even in that context?
[00:57:47] Dave Adsit: Well, I don't think it's simple because I think that you have to complex those four operators millions of times before you've produced anything of use.
[00:57:56] Allan Stewart: Interesting. Going back to the search for simple tools concept, I'm okay with adopting more complex tools if it makes my code simple because the code space is where I'm going to be living and having to deal with things on a day-to-day basis. Same thing goes with the framework. I might be willing to adopt a more complex framework if it means that I don't have to complex as much code to get the thing up and running and doing what it's supposed to be doing.
[00:58:27] Dave Adsit: I've been thinking about recently, I started at a new startup as well, Matt, and there was a code base and it was arguably more simple than the code base we have now, or maybe not even arguably it was more simple than the code base we have now. It was, I thought, Django, but that's unfamiliar to me. I was unable to do work in it, so I rewrote it in .NET. One of the very first things I did is hook up a CI CD pipeline because I have done many, many, many deploys to the target environment. I knew that I didn't want to do that manually more than maybe once. In fact, I don't think I deployed manually even once. I think that the very first deploy of the environment was through the pipeline. Was that jumping to complexity too quickly? Maybe. Mark H준ekerson
[00:59:23] Matt Baker: How would you... If you actually tried to answer that question, if you tried to quantify the amount of complexity you took on and then the impact it had, how would you... You know what I mean? Is it just a squishy feely or is it Mark H준ekerson Mark H준ekerson
[00:59:37] Dave Adsit: Mark H준ekerson Mark H준ekerson Mark H준ekerson Mark H준ekerson Mark H준ekerson Mark H준ekerson Mark H준ekerson
[00:59:42] Matt Baker: That's what I'm asking.
[00:59:44] Dave Adsit: So for me, it took me probably two hours to set up a CICD pipeline to a new environment. I don't do immutable infrastructure. I don't have infrastructure as code because that to me, deploying over and over onto the same system feels simpler than spinning up new systems and tearing down old ones. But I know that other people feel the exact opposite about that. That changing, mutating state on an existing system is more complex.
[01:00:17] Matt Baker: Yeah, it's hard to figure out what degree, like going to what Allan was saying, what abstraction you should consider this from when you say like, well, this thing has more things or less things than that other thing. And something that you're saying, Dave, that's sticking out, the way you're talking makes it sound like there's this continuum or whatever you would call it, a spectrum, I guess. And then on one end, the simple and the other one's easy. And like, we're dancing in the middle a lot of the time. Because I, and Allan has like hinted at the subtle connection too, right? As the more you make something easy, maybe the more complexity you take on, like you were saying, if you make it easier to ship code to production, one command, bloop, you know, then like doing all the requisite. Get push. Yeah.
[01:01:04] Dave Adsit: I learned to get so that I could do get push so that I could deploy to production.
[01:01:09] Matt Baker: Yeah. Like, that's easier than not having a deployment pipeline when it comes to deploying to production, right? And it might, it's not simpler. I don't think, like, I think it's dead simple to FTP into a server, SSH into server and bloop, like drop a file. But granted, it's like, it has less complecting. It's not what you want it to. So you, so you take on that complexity and you know that. So I get, I see now like the point, I think that both of you have been highlighting, like there's this dance back and forth and maybe as you make things easier, you, you, you sacrifice complexity and I still don't understand though, like how to, how to not do this in a gut feely kind of way, you know, like, and this is why I was harping on like how you define complexity at the beginning of the podcast. And I think Allan blew it out of the water when he said that, well, there, it depends on the degree, the level of abstraction you're standing from. And like, once you add that to the stew, my whole like mental model falls apart of like, how do I, how do I actually measure complexity in a meaningful way? You know? Well,
[01:02:13] Dave Adsit: and I think that I'm, I'm relying on some complexity out there in the ether that I, if it broke and I had to fix it, it would be a problem because right now I get pushed to get up. There's a hook and get that triggers an event on a server in Azure that then pulls my code and builds it and tests it. And all of those things inside of a giant, general purpose, CI engine that creates an artifact that then gets deployed to a server also running in the cloud. And if I had to build all those things myself, you know what I would do is I would have a little one you server in Iraq, and I probably just connect up to it and drop my code directly on it. In fact, I've done that in the past. I have worked in environments where we would basically to debug a production problem. You would just remote desktop, into that computer and change the code on the computer directly and see what happens because it was an interpreted language and you could just do that. That was substantially worse in a lot of ways, but also simpler than relying on get in get hub and get hooks and open connections and TCP sockets and whatnot between Azure and get hub and, you know, all of the different things that I have to rely on, but it's a behind it abstraction. That I don't care about because I created a YAML file and then it worked even though I don't love YAML because I don't love, I don't love what a significant white space.
[01:03:49] Allan Stewart: In fact,
[01:03:50] Dave Adsit: I anti love significant white space.
[01:03:53] Matt Baker: I've been coming around to it. I'm been coding in Python for a while now.
[01:03:58] Dave Adsit: I will believe people when they turn off visual white space.
[01:04:03] Matt Baker: What's that? What do you mean visual white space?
[01:04:05] Dave Adsit: Do you see, can you see the difference between a space and a tab in your ID, in your editor visually? No. Oh, and then you are coming around to it.
[01:04:19] Allan Stewart: I think the only thing that we can say for sure, as we're wrapping up this topic is that we're in agreement that we should avoid things that are both difficult and complex and strive for things that are simple and easy, but where in that quadrant diagram you land is, uh, a much more murky question. One thing that is less murky is that the music for our podcast was generously provided by Todd Fisher, whom we think. And as always, we recommend that you join a community of professionals by attending a software crafters group or meet up near you. The Utah SC group at utahsc.org has a virtual meeting the first Wednesday of each month. Maybe we will argue about simplicity and ease with the
Copyright © 2026 - Crafting Code Podcast