Expert Talk: Five Lines of Code
Revamp your code with refactoring! In an insightful interview with Julian Wood, Christian Clausen, author of Five Lines of Code, shares practical tips for improving your code without relying on “code smells”. Simplifying your code is the key to running your business smoothly. Clausen highlights what matters most in terms of simplifying your code and how it can aid in choosing the right architectural paradigm. Streamline your code today and focus on what really matters!
Why only five lines of code?
Julian Wood: Hello, and welcome to another episode of "GOTO Unscripted." We're here in GOTO Copenhagen, and I'm joined by the wonderful Christian Clausen, who's from Denmark.
Christian Clausen: Thank you. Yes, my name is Christian Clausen. I'm from Denmark. I've written a book called "Five Lines of Code."
Julian Wood: Well, that's what I wanted to pick up on it, I was speaking to some people who'd come from another country. And they were from a huge big bank and I said, "Was GOTO Copenhagen useful this morning?" And they said, "We'd been to two sessions and one of them was particularly amazing. And it was "Five Lines of Code." I said, "I'd noticed the title, and I wanted to dive into what does "Five Lines of Code" means." So yeah, you've written a book, "Five Lines of Code," is that all the code we ever gonna write?
Christian Clausen: It's the length of a method. Of course, it's to be a little bit controversial and to be a little bit catchy in the title.
Julian Wood: Of course.
Christian Clausen: But it's also because I found that... For a long time, I've been a very strong advocate that we need more quality, and we need more refactoring, and we need people to do it. And I've been wondering... I find it super amazing to have a clean codebase. And it's super fun to work with. Why are people not doing it then? Why do we have all these legacy code bases? Why does no one fix it?
So, for many years, I was recommending books like "Clean Code" and Martin Fowler's "Refactoring" book and stuff. But what I found was every time people came back and they said, "Yes, they're, they're good books," and I'm like, "Okay, do you do it then, in your work?" And they're like, "Nah, it doesn't fit or it's a bit difficult. I can't get started with it. I don't quite have a good handhold on the things." And I'm like, "Well, but there's a code smells, right? They say exactly where you need to fix stuff."
Recommended talk: A Path to Better Programming • Robert "Uncle Bob" Martin & Allen Holub • GOTO 2021
And people were still like, "Yeah, but it's like it says, 'Don't have long methods.' That's the classical one," right? But if you have just two seniors on the team, having them agree on what is too long is impossible already but then you have sometimes up to five or nine people on a team that didn't have to agree. And so, what I figured was, what if I sit down and I digest all of the code smells into some nice, concrete, actionable rules that people can then easily follow and spot without having to think about extra stuff and adding extra complexity? So, the first rule I came up with was five lines of code. As I said, when our method is too long, it's past five lines.
Readability vs maintainability
Julian Wood: Okay. So it's not about necessarily, vastly reducing the amount of code and trying to encapsulate your business logic only into five lines. In a way, it's splitting up a bigger code base using more methods, using better classes, I would presume as well. And is that for more understandable code, so other people can iterate on it and other people can understand it? Or what is the sort of end goal of thinking in the five lines of code?
Christian Clausen: That's a very interesting point, especially because I sort of split architecture into a few different categories. One of the degrees or one of the various where I split it was to make it more readable or to make it more maintainable. Because there's a lot of confusion between these two. And if people don't distinguish between the two, they'll... They have different sorts of impact in different scopes. So, for instance, something where you're improving the naming of variables or method names, that makes the code more readable, for sure but it has no impact on the architecture and on the maintainability of that code because it's still connected to other things.
That's because the maintainability depends largely on two things, the coupling, two other things, and invariants in the code that you need... Both are things you need to keep track of while you're working with it. And so I focus almost entirely on the maintainability aspect and actually having the architecture be improved. And I think I have a small section about naming things. But I really, really tried hard not to talk about it because naming is notoriously unsolvable and it's really difficult. And I can't do better than North already has done with his paper. They call things... I don't even remember what it's called. But it's a really good article he has on it.
Julian Wood: So how would you explain to people who are thinking more methods, that are actually adding more complexity to my code? You want less coupling, which means interdependent systems. There's then a communication channel between those separate systems, and now then talking about microservices, I think gotta handle additional complexity. So, on one hand, you've got the simplicity of the understandable maintainability of your code but your code is talking to other bits of code across something else.
Christian Clausen: Yes. And I especially love a quote by John Carmack who said that you can trade perceived complexity for actual complexity, right? Adding another layer of indirection will make the code more difficult to understand but it will make it seem simpler. And so, I also like to talk about two different types of abstraction. There is a true abstraction where I'll never need to get underneath and look at what's under the abstraction. This is a true abstraction and it has truly removed some complexity that I never need to think about.
And then there's a shallow abstraction where you need to somehow go around it or you need to know what's underneath to truly use it and stuff. That's where all of the layered architectures I've seen in the real world have been shallow abstractions. People always found a way to sort of go underneath or they just exposed some of the secret data or the platform underneath.
So, it's very different whether you have these things where you can actually abstract away stuff and make it actually simpler. And the way that I sort of enforced that those are the types of abstractions done through my book is by having the invariants be the thing that we're abstracting into. So all of the code will go to where the invariants are, localizing them, and making sure that you don't need to at least keep track of them in other classes and in other places.
As you say, I split up large code bases into all of these hundreds of smaller methods. In fact, it doesn't make it shorter at all. It makes it a lot longer, in the beginning, especially. But then I used all of the methods to guide where all the classes should go because then if methods concern the same thing, like if they have a common suffix or prefix, probably they should be in a class that has that suffix or prefix, right, as its name.
Then over time, you get a lot of classes also. And then you look at the classes and see, well, some of these have the same thing in the title. That's the other thing. So probably there should be a package, right? We have this amazing hierarchy that we're barely using in a lot of cases where code can just talk to all different parts of the code. But if we start pushing it out and distributing it, it looked much more like a tree structure. And you only have to consider the leaf that you're in for the code because that's where the invariants are. That's where the data is.
From monoliths to microservices
Julian Wood: Because I know a lot of people struggle from the sort of monoliths to microservice migration. I think part of it is because the monolith does get so unwieldy, that you don't understand. So I can supersede this idea of a tree structure that even if you do have a monolith, that is much easier to reason about, and you can understand which part of the tree and which part of the leaves you are within a monolith. But then I suppose, if your monolith does get too big, and you are coming up against some sort of ceiling in terms of scalability, that if everything is named correctly, not that the naming is important, but everything is classed and methoded correctly, then that does make it simpler to split out?
Recommended talk: When To Use Microservices (And When Not To!) • Sam Newman & Martin Fowler • GOTO 2020
Christian Clausen: Probably it will. It will also... There is another interesting factor that I find a lot of people struggle with when they talk about this journey from monolith to microservices. And it's that latency becomes a thing. And it wasn't a thing before, right? When you're on a CPU, you can have these manager classes, which is a smell in itself, where that pull all the data to where they are, and they do all the calculations, and then they deliver the results to somewhere else. That doesn't work in a microservice architecture, because you now are not on the same chip anymore. And there might be latency between each of these calls. And so collecting all the data is vastly inefficient.
In my book, I talk about this pull-based architecture, where you're pulling all the information to one place. And instead, I describe how you shift your code to be more push-based, where instead of if I know that I need to perform my code calculation at this point, I'll pack up all the information that I have this relevant for this thing and send it to the next service that can then keep putting on more...decorating more data until that final link in the chain will know how to actually perform the calculation. And there'll be no need to return it anywhere. You just return it directly to the next place it needs to go. So it's a much more push-based, much more forward-type of architecture that then passes information along the chain.
Julian Wood: And does it tie into how we used to and still do you think about event-driven architectures?
Christian Clausen: Yes, very much because... And I'm also a huge advocate for doing event-driven architectures because I can't see how direct microservices can be viable in a real setting due to exactly the latency and the coupling that you have between the components. The fact is, classes and code services tend to grow over time. At some point, we need to cut them up into two components. If you have a direct microservice where the caller knows where the callee is, then you can't split it up without having two teams work together, or three, or more. And that's impossible. Teams... Whenever we introduce handoffs, we know quality suffers every single time.
Julian Wood: So how do you then explain these concepts with people who get very tied up to do with the state, and storing state, and managing state in the database? And I know with events, you can do events state transfer. How do people move information through their application and handle state in this disaggregated world?
Christian Clausen: I won't claim that I'm an expert on how to handle state. I'm also, of course, a huge fan of stateless things. And I want to think about my services as pure functions in some abstract sense, so they can't contain in the state. But then I have these databases, and especially since it's become very popular to talk about least privilege and stuff like that, I find that we know how to handle databases. And so far, I haven't been offended by anyone who wants to just share the link to a database and then deal with the access control there, and then the events are more notifications that you need to do some work, go to the database, and see.
So you still have a very nice and finely-grained control over who has access to what, at what point. Transferring huge amounts of data is really annoying if you have a message queue because you're captive something like 10 megabytes usually, which is understandable. But sometimes we have a lot more data that we want to communicate between them. So putting it in a commonplace first, and then just sending the event as notifications that other people need to then go and fetch it, I find this is all right. It does introduce coupling between the services on the data. So long as we keep it simpler than it was before, it's not like I'm sharing references to different databases from different teams. But I can share data in that way, sort of read-only type of data.
Julian Wood: I suppose they are some architectures where you can have a local cache or a local copy of the data while you're doing some processing. And I know you do have some eventual consistency possible issues. But these are different ways that you can have a localized state.
Christian Clausen: I do say that when you have shared databases like this, you can have as many read keys as you want. You can only have one write key. There is one owner of all pieces of data in all systems. And also, there's one team owning old code. There can't be shared code, you can't have shared data. That's not a thing, because that's a coupling, and it's going to kill your entire productivity and stuff. But so long as the data is read-only, I haven't found a lot of issues with actually distributing that between many teams.
Julian Wood: Okay. How does sort of application integration patterns fit into this? Because we're talking about abstractions, and we're talking about a sort of common language that people are going to talk about these things communicating? What are your thoughts on that?
Christian Clausen: So, for me, I've thought about architecture for so long in so many different contexts, that it's all sort of become the same thing. It seems like when people talk about functional programming, object-oriented programming, or the old style of refactoring, or the new and all of these different things, we're all advocating the same thing really. When we talk about how people used to code and purely object-oriented languages, like small talk and stuff, it's the same principles that I'm trying to revive now.
I've been meeting some very old programmers who were like, ''Well, I used to do Smalltalk and stuff and we didn't have all these problems.'' I'm like, ''No, I know because that's what my book is about the same style.''
Julian Wood: Everything old is new again. Yes.
Christian Clausen: Yes, exactly. It's the same thing. And exactly, when I'm talking about, we need more methods, so we can have more classes, so we can have more packages, that will be a monolith kind of way to say it, but we could say the exact same thing about services, right? Because we add more features or more hooks to the events. That will be like the methods and then the classes, the service, and then over time, you need to split those up as well in exactly the same way. So, for me, it's all sort of the same thing that we're going through just in a different scope.
Julian Wood: I like the wording that you're using as well because you are talking within a sort of single programming construct of things like events, coupling, and using services. Because I work with AWS on the serverless kind of side, that's our sort of whole lightbulb moment we tried to spark in other people that you have code and bits of functions, and you have message buses that you need or message buses, queues, event routers, anything, to send messages across applications. And I very much like the language that you're using from an individual programming language perspective because, for me, that's applicable in the cloud as well that you want to reduce your code and you want it to scale up, scale down as much as you can, and use managed services if you can. So you're not reinventing the wheel, building additional infrastructure, all these hooks and additional integration things which you really don't need to. And it's ultimately not important for your business. You want to run your business code.
Christian Clausen: Yes, exactly. The user needs just to have the code run and everything else is a distraction, right? Everything that doesn't add value, I also try to eliminate from every process. So a typical example that I've met in my work as a consultant would be something like scrum meetings. And a lot of people do them. And I'm like, ''Okay, are they valuable? Do you learn something? Are they useful for you?'' So many developers hate them. I take that as an immediate feedback that they're probably not valuable, right? Because developers like their job. They like doing the right thing.
I remove that stuff, infrastructure would be the same thing, right? It's like, do I need to know how to set up a network? Do I need to know how to build images in Docker to just run, like, my Node.js application? Maybe not, right? Maybe I just need to push this to somewhere and then it'll be run. I don't have to deal with all those details and extra cognitive load.
Julian Wood: Yeah, it's a term that we use the undifferentiated heavy lifting. And I was relistening to a podcast recently, kind of thinking of something, does it make your beer taste better? If you're a beer brewing company, whatever you're going to be building in your application, does it make your product better, or is that a distraction?
Christian Clausen: Yes.
Why TypeScript gets neurons firing
Julian Wood: You were mentioning before we were talking about the sort of language of choice that you liked, and you were mentioning TypeScript. Talk us through why TypeScript gets your neurons firing.
Christian Clausen: TypeScript had many things going for it. First of all, of course, I'm a type guy. I'm very big in type language skills. And TypeScript has one of the most fascinating types of systems that humans have ever conceived, which is already amazing to me. I've worked with the very most difficult type systems, like sort of dependent types. And so Microsoft has this Lean thing they're coming up with. In France, there is the language caulk [SP] in them. And then there's also Act In [SP] and a lot of other things.
I really like these languages, because I can teach the type system anything. I can have another program on top to check that my program is still valid at compile time. So I don't need to run it. That's also a bit of a joke from when I was doing research that performance is when people want to run their code. I just wanna type check them, everything else doesn't matter, right, then I know they're correct. So TypeScript has an amazing type system. It also has a very low startup time, which is especially interesting, if you're moving towards a sort of serverless world where the virtual machine is just up and then you don't need to wait for it. So that's also something I find very useful.
Recommended talk: Serverless: 6 Years Later • Erwin van der Koogh • YOW! 2022
Christian Clausen: Yes, but also for people who are familiar with Java or C Sharp or other object-oriented languages, because it is very inspired by them. It looks the same. The syntax is fairly similar. I haven't... So my book is written in TypeScript. And I haven't presented it to a Java programmer who wasn't like, ''Oh, yeah, this is exactly the same.'' I mean, there are some quirks here and there, and I explained them, but in general, it's a really nice language to work with, except for the runtime, of course.
How to improve your architecture
Julian Wood: I was going to ask the question, what would you advise people to do the first thing to improve their architecture? But I think the first thing they should do is, first of all, buy your book, because that'll be useful and give them a whole bunch information more than we can just cover in this chat. But if some developer wakes up, and they've hopefully read your book, what's the one thing you think they should start immediately with to improve their work life, their code base, and their approach to developing?
Christian Clausen: Depending on how much time this person who comes to ask me about the thing, from giving professional advice, I would usually say, just start using the tools that you have, right? A lot of people have a lot of really cool tools, like Git, that their editor, like their compiler, stuff like that. There are things you already have at your disposal, just get to know them better. Because I've seen developers who can code at 20 times the speed of the other developers on the same team, because they know all the shortcuts, they know all these tricks, and all these methods. By just learning the tools that we have, we can already improve a lot in our productivity and in our daily work.
The method I would recommend them for doing that would be something like ensemble programming, which I also recommend that any opportunity to people. Work more closely together, one flow, one team, that's it. And then you will start distributing this knowledge and learning new things. You can't move a team if you're completely focusing on delivering new features, because you're filling your head with the feature work, right? You can learn a new habit. And if it's not a habit, you'll forget it when you're doing something that's cognitively difficult. So, ensemble programming and then just get really good at your tools.
Julian Wood: Christian, thanks so much for joining us. There's a lot more I need to learn about this and read about this, and certainly opened my eyes to a whole kind of thing. Where can people find you on the internet? Where's a good place to...a landing page or Twitter, or wherever you're online?
Christian Clausen: I'm on Twitter. And I also have a blog that I've been very bad at posting on recently. But I do have some articles there that I really like. And yeah, on LinkedIn, on...
Julian Wood: So what's your Twitter username?
Christian Clausen: I'm always The Dr. Lambda on every media that I'm on, GitHub, YouTube, everything. That's always me. So, it should be fairly easy to find. You can find one of them. Thank you very much.
Julian Wood: Well, thanks for coming. Thanks so much for joining us here again today on ''GOTO Unscripted'' in Copenhagen, where we're learning from some of the experts on all the new ways and the old ways being reinvented to rebuild your software and ultimately do a better job and hopefully enjoy it a bit more. Thanks for joining us.