 I want to start out today by doing a little exercise. The exercise is lifted from a book called Nonviolent Communication. And it's called Translating Have To To Choose To. The idea is that we all have things in our lives, which we do not because we inherently enjoy them, but just out of some kind of sense of obligation. We feel that we have to do them. And the idea of the exercise is to acknowledge that there's a choice there, and once we realize that it's a choice, figure out what we're gonna do about it, and think about maybe how to re-make that decision. So you take all these things in your life that you don't really enjoy doing, you make a big list of them, and then you have to fill in one by one this sentence with each thing. So you say, I choose to X because I want Y. You figure out what's the reason that you make the choice to do that thing. And what you'll basically find is one of a few things will happen. Maybe the thing that you want is actually really important, and you'll find new meaning in the thing that you were doing. And it'll feel more like an active choice that you wanna make. Maybe you'll say, well, the thing that I want wasn't really that important, so I don't really have to do it. Or you'll say, well, the thing that I want is important, but maybe this isn't quite the right way to get to that point. Or maybe there's just a different kind of broader set of strategies that I need to really get the thing that I want in some kind of better way. So today we're gonna ask the question, why do we choose to write good code? And that's a little bit of a scary question, right? Now what do you mean? We have to write good code, right? It's ingrained into us. We go to talks at conferences, we read books, we watch podcasts, or listen to podcasts, I guess. We watch stuff online, we read blog posts, all about good code, we have to do it. That's just, you know, that's what we do, right? So I'm here to tell you, first of all, today, you don't have to write good code. You choose to write good code, hopefully. And part of today will be figuring out why we choose to write good code. That second line, because I want what? What do we fill that in with? Maybe we fill it in with, well, if I don't write good code by some kind of arbitrary standard, then I'll get fired. A sad reason to, but that might be it. But ideally, we'd find something meaningful and important in terms of why we're choosing to write good code. So why do we care about writing good code? And because this is a talk about software quality, and that's really the ultimate goal here, we have to ask, is good code actually the same as quality software? So we'll get back to that. But first I want to talk about something somewhat, but not entirely different. Dave Thomas, Bob Martin, others as well, but I mentioned them just because they were signatories on the original Agile Manifesto, have said that Agile is broken. It didn't accomplish the revolution that it was supposed to accomplish. Here's a quote from Bob Martin quoting Kempbeck, who was also there. He said that one of the goals of the Agile Manifesto was to heal the divide between development and business. There was a gap that had been created, a chasm between the two sides and a lot of tension, and the goal was to relieve some of that tension and find ways to work synergically and harmoniously. Reality check, I don't think it really worked. They don't think it did either. So at least I have some people who were involved in Agile right from the top saying, not great situation, but what it became was basically some kind of business person, project manager, whatever it is, would take a course, get certified in something, and basically tell developers, okay, now you're all gonna do Agile because that will lead to better software. It's something that developers do to keep business people happy if you could even do, in quotes, Agile. Usually the form that this takes is scrum. I forget the number, 60, 80%, something like that of organizations that claim to be doing Agile are using scrum as their implementation. Fun fact, as far as I can tell, because I've read through the scrum guide and I've read through the Agile manifesto and compared the two, it addresses maybe 50% of what Agile is and it kinda misses out on all the values. So I'm not saying that scrum is bad. I don't wanna give that impression. I think scrum has a lot of really good ideas. It's just not an implementation of Agile, it's a framework in which you can choose to be Agile or not, it makes it easier in some ways, but it's not actually agility. We don't need more processes. Sometimes processes can be helpful, but they're a tool toward something more important. And what I think that we need, and this is why I'm coming down kinda hard on scrum, is we need more trust. Scrum focuses a lot on transparency. As far as I understand, transparency is basically, we have two sides, each side sets to the other. I need to know what you're doing at all times. I need you to be transparent about it so that when I see something going wrong, I can jump in and complain and micromanage you. Trust, on the other hand, is let's have a conversation. Let's understand that there are two sides to the situation here. And let's talk about the needs of each side. Each side will express their needs in a way that makes sense to the other side. And once we're confident that the other side has heard our needs and understands them, we can rely on the other side to think about our needs and account for them in their own decisions. That's what trust is to me, at least. And that's what allows us to build effective organizations. I think we can solve this problem. I don't think it's even too complex. It's difficult, but I don't think it's complex. And it starts with communication. If we learn to communicate between developers and business people in a way that makes sense to both sides, then we can start building the trust that we need to have highly effective organizations. So we have an ambitious goal today. We're gonna create a common language for developers and business people to be able to express their needs in a way that makes sense to both sides. And the way that we're going to achieve it is by going right for the jugular, taking the thing that causes a lot of tension between the two sides, and trying to understand it again, figuring out why we write good code. A lot of times we push for good code in whatever way we define it, and good code takes time and takes investment, and it's hard to explain that to the other side, and that causes a lot of tension. So we're gonna figure out why we write good code. But first, let's figure out why do we write code? And I really mean that. Why do we write code ever? Seems like a strange question, right? We're developers, that's what we do, that's our job. Well, newsflash, controversial statement, okay? But I think it's certainly pretty clear to me your job is not to write code. Your job is to solve problems. I wanna give an anecdote from specifically another field that will help us look at things a little bit more objectively. So there's a man once came to a plastic surgeon, and he said, I need you to do some surgery for me. My ears are very large, and I want you to make my ears smaller. Interesting. So the surgeon decided to probe further, okay, why do you want this surgery? What problem are you trying to solve? And this guy said, well, it's not a problem for me actually at this stage of my life at all. I get along fine, we're all adults, right? But when I was a kid, I got teased a lot, I got bullied a lot over the size of my ears, and I don't wanna pass on that problem to my kids. I'm about to start a family, and I don't want them to get my ears. So how about you fix my ears so that I won't pass it on? So he clearly still had a Lamarckian understanding of evolution. I was curious how many laughs that would get. So, and basically what the doctor did was say, hey, let's talk about modern genetics, let's understand how these things actually work, and why I can't solve your problem, and the solution that you suggested certainly doesn't help. If the doctor had said, okay, that's nice, let's schedule a surgery, we would call that malpractice. But it's funny, because that's very clear to all of us, I think. But what happens when someone approaches a developer and says, hey, I want you to build a mobile app for me? And the developer says, okay, without even understanding the problem that we're trying to solve, without understanding whether this is the right solution, maybe they need a marketing director, maybe they need to just have an email campaign, maybe a lot of things. There's thousands of apps out there in the App Store that reflect this problem. They don't do anything for anybody, they don't matter. I have a hard time calling them high-quality apps, because they don't solve a problem. If you're not solving a problem, there's never a reason to write the code. Now, this doesn't sound very business-y, so I'm gonna give a little translation. Your job is to create value. And that's kind of a loaded term, means a lot of things to different people, so I'm just gonna give a working definition that we're gonna use for the rest of the talk. Value creation, in the context of this talk, means one of three things, or more of those three things. Generating revenue, lowering costs, or reducing risk. Those are the main things that matter in business. In the specific case of a nonprofit, instead of generating revenue, you can substitute doing whatever good the nonprofit is supposed to do. But on the whole, the same pattern still applies. Those are the three things that we mainly care about. And where do users come in? Well, generally, the way that you do these three things is by meeting the needs of your users. So we're gonna use meeting business needs and meeting user needs kind of interchangeably in the talk. Hopefully they go together when they don't is a whole discussion that I'm just not getting into today. So to recap, why write code to create value? That's it. That's the only reason we should ever be writing code. If that's the case, why do we care about writing good code? I think the answer is simple. It usually helps to create value. Does that mean that good code is the same as quality software? According to this definition, I don't think so. So here's the second of two controversial statements. I would define software quality as just the amount of value that it creates. We're writing the code to create value. If it creates that value, it's fit for purpose. It is ergo high quality. If it doesn't meet the needs, then it can be really well-written under the hood, but doesn't really help because it's not actually solving a problem. So rather than asking how can we write better code, what we should really be asking is how do we target our efforts in coding to maximize value creation? And how does good code fit within that whole broad picture? So I'm gonna commit a major programming sin now, which is solving a problem by writing a framework. It's not JavaScript, it's just a human-people framework. It's only three words, so hopefully it's not too bad. I think that there are three factors that if we think about these three, we can pretty much fit anything about software quality as we've defined it into one of these three factors or two or three out of them. I call them usefulness, sustainability, and accuracy. We're gonna talk about what each of these means, but you'll notice that there's an acronym there. I didn't choose these words over the acronym, like that happens sometimes. I just want a cool acronym. It happened to be the acronym that came out, but if thinking about the USA helps you in terms of remembering the three words, all the better. All right, so let's start with usefulness. Each of these is going to have a question and target. The question in terms of usefulness is does it solve a problem effectively? Pretty straightforward, but a lot of details there. The target here is our users. Again, using users and business needs a little bit interchangeably. The question is, is it a problem that affects users, first of all? Sometimes we spend a lot of money to code up a solution that doesn't actually address a need. We have to make sure in whatever way we can that we verify that the problem actually exists and that it affects the users that we're gonna be addressing. Then, even if we've correctly identified a problem, it's important to think about, well, is this actually a solution to the problem? Or are we missing something? And it can't just solve a problem, it has to solve a problem in a way that works for the users. Because if it works, but doesn't work for them, you haven't really done an awful lot. I wanna cite a story from Tara Scherner de la Fuente, who gave a keynote at RubyConf last year, which I think absolutely illustrates this point really nicely. She was working with a user of one of their applications, just kind of seeing what they were experiencing. And it was to upload a spreadsheet with a whole bunch of rows and anything that the application could figure out, great. If not, then you had to kind of fill it in. So one of the columns was a column of dates. And most of us think like, okay, date picker, great. In the case of this application, they decided to allow inserting dates, and putting dates by a dropdown menu without sorting the dates. So there were just hundreds of dates in a completely unsorted list that they had to look through, somehow managed to find the right date and then repeat it again and again and again and again and again until the whole spreadsheet was done. And if there was an error, by the way, you had to go back to the beginning and it wouldn't save what you had done so far. That meets the needs technically, you'll eventually get it done, I guess. But it's not in a way that works for the user. It's really hard to call that a high quality product. Okay, that's usefulness. Sustainability, what's it about? The question is, can we keep building without unnecessary obstacles? And I thought about this a lot, I didn't wanna say without obstacles because there are always gonna be obstacles there. The question is, are we identifying the most important obstacles and trying to account for them, trying to limit the things that are gonna stand in our way as we continue developing? The targets, in this case there's two targets which I think are really one. The first is our software. Is the software resistant to change? That breaks down into two sub-questions. One is an issue of understanding. Is the software written in a way that we just won't understand what it does and it's gonna be hard to make changes? The other piece of it is, well, even if it's very clearly written, we understand what it does, but the certain architecture choices we might have made make it hard to change things later on. So it just takes longer, it's a lot more effort to do. The other target is the development team. We so often forget that the development team is, I don't even wanna say it's as much a part of our software as the code itself. It's more of a part of our software than the code itself. Think about how just carefree you are when the leading code, putting in new stuff. You don't do that with your team, right? The rate of churn is ideally a lot lower and you crash the development team, you basically don't have a product anymore. So it's important to be aware whether the team is unstable in some kind of way that if things are tipped a little bit, is that going to prevent future progress? Is the team gonna collapse? Or just become less effective in some way? That's sustainability, let's talk about accuracy. This is the one that we probably think about the most. The question that we're asking is pretty simple. Does the software work the way that we think it does? The target here, you think I'm gonna say the code, right? The target is ourselves. We have to ask four questions. Have we developed our understanding of the problem? Sometimes we just don't understand the problem correctly. We do everything right in the coding step, but we haven't taken the time or the effort to figure out first, is this actually the problem? Does it solve the problem? Is it, all the usefulness stuff leads into an accuracy problem? Have we developed understanding of the code? Is there something about the code that makes it hard for us to get the next step done? And we're just coding the wrong thing. Sometimes there could be issues of cognitive overload that even if the code is relatively clear but there's so much going on, too many integrated systems, microservices, whatever, that you just don't understand the full impact of your actions. And finally, our understanding of a problem changes over time. Sometimes the problem itself changes over time. If we're not updating the code to reflect that, that ultimately appears as an accuracy problem. These seem like things that are maybe a little bit like mashed together that shouldn't be together, but if you think about it from the perspective of the user, if any of these are failing, your software is broken. That's a bug report, any of those questions. So to me, that means that they're all issues of accuracy. I can't speak for anybody else, but when I think about why I write good code, why I choose, actively choose to write good code, it's because I want software that's useful, sustainable, and accurate, and good code is a significant tool in helping me get there. Here's the traditional model with the business development chasm pictured. In the right corner of the room, we have accuracy and sustainability. Those are seen as the domain of the developers to write good, accurate code. And on the left side, we have usefulness, which is the domain of designers, UX people, product people, et cetera. And never the twain shall meet. We really subdivide those responsibilities, and it's not surprising that each side advocates for the things that it cares about. Well, we said never the twain shall meet, but today, the twain shall meet. What we actually need is to think about quality as all of those factors together. We need to have, we can't leave out any element of that. And we have to be part of that usefulness circle as well. So this has all been pretty abstract, I realize. And I don't wanna leave you with just kind of abstract floating in the air ideas. I wanna take this down to a very practical level. So what we're gonna do, clear out the diagram, we're gonna ask the question, is it quality software? And we're actually gonna fill in the things that we do on a much more granular level to address each of these three points. Usefulness, accuracy, sorry, sustainability, and accuracy. Now this is a Venn diagram. There is gonna be some overlap on occasion. Practices might contribute to more than one of these circles or to something that we might think of as maybe the confluence between those two circles. So I'll just give a little more definition in the middle. We have between accuracy and usefulness, the question of does it work in the way that the users expect. Less thinking about ourselves, starting to think more in the direction of our users. Between accuracy and sustainability, we're asking the question, can we keep building our system without breaking our system? It's future focused accuracy. And up top, between sustainability and usefulness, we have the question of, are there obstacles to future usefulness? Essentially things that aren't threatening usefulness right now, but we're aware that the choices that we make now might have some kind of impact in the future on how useful our product is. All right, so I titled this talk, What Comes After Solid? I thought it was a nice juicy title, but I also think it kind of makes sense to start by talking about solid because it's just this traditional metric of software quality and we think a lot about it, we talk a lot about it. I'm actually not gonna talk a lot about it. I'm actually gonna run through it really, really fast. So if you aren't familiar with all of the details of solid, that's okay. I could spend the whole 40 minutes just talking about that. So you might be bored for about a minute, but we'll be fine after that. There's tons of stuff that you will understand. Fine, so solid stands for five different principles that are related to creating whatever we might define as well-crafted software. The single responsibility principle, the idea that every element in your system should do one thing and do it well. The open-close principle, which is short for open for extension, close for modification, meaning that you should be able to add new features without modifying existing code. How you do that is, again, a long story. So I'm not gonna get into it. Liskov substitution principle. Basically use inheritance properly. Don't inherit from a superclass because you need a method. Inherit because it's actually a specialized instance but it should fully implement the superclass and all of its functionality. Interface segregation. This is not that relevant for Ruby because we don't really have interfaces in the traditional sense, but I think of it as, ultimately it's about limiting the surface area of how objects depend on other objects. You can do that with adequate interfaces. Technically I don't think it matches a principle but it's close enough. And finally dependency inversion. Depends on abstractions, not concretions. You're basically pushing dependencies to the outside of your system and then the core elements, the units are depending on sort of a theoretical idea of what the dependency is doing without relating to too many of the implementation details. So let's run through, we'll do this very quickly. SRP I think is a big winner. If every item in your system does one thing and does it well, it's easy to tell if it's doing the thing that it's supposed to do. It's much easier to change later because you know exactly what to go back to and modify. And this is sort of a personal opinion. There's gonna be a lot of personal opinions here so I apologize but kind of sorry, not sorry. The main thing here is not to learn the details. It's to see the way of thinking and ultimately you're gonna apply it yourselves. But back to right here. So usefulness, I think that single responsibility means that each part of your system has a very clear responsibility and that lets you start thinking about is this the right responsibility? Is it something that actually creates value for people? Is this something that should or should not exist in our system? It opens up a pathway to those conversations. So I think of it as a very, very central practice. Open-closed is really just about the future so I put it all the way over in sustainability. Liskov substitution is about avoiding certain classes of errors. So I think about that as avoiding errors now and avoiding errors later, accuracy, sustainability. Interface segregation and dependency inversion again are really about the future. So those go all the way in the sustainability camp. So that's where solid falls out in the way that we've expressed it. It's all in the sustainability camp. There are a few that get into other places and again SRP to me is a pretty central practice. Let's talk about some other stuff. Sandy Metz has her four principles which get the acronym true. You can read about them in the first chapter of Puder. Four principles that are meant to create systems that are much more robust in terms of their ability to accept change. Makes it much easier to change them in the future. Transparent meaning that the consequences of changing code should be obvious. Reasonable, the cost of change should be proportional to the benefits, if it's a small change then it shouldn't be, or sorry, if it's not that beneficial change versus if it's a very, very beneficial change the cost of change should be proportionally related. Usable basically is the code reusable in other contexts. An exemplary, your coach has had a good example for coders to come because of course we all kinda look at the system, see that oh, it is the way it is, therefore let's just perpetuate those qualities in the future because obviously whoever was here before did it right. Those are all explicitly about the future so I put them right into that sustainability camp as well. So we're pretty heavy on sustainability but let's try to diversify our strategy for quality just a little bit. Let's talk about testing. The first thing that very often in our community we forget is even a choice, is testing at all. You could not test, there's a lot, a lot of places and teams that don't test at all so choosing to test at all is a practice. Code coverage, the attempt to make sure that every piece of your system is exercised in a test. Different types of tests that we could talk about, there's unit tests which test a small piece of your system, integration tests which are testing how pieces of your system interact with each other, a much broader perspective and manual QA which is even further out, you have a person who probably hasn't worked on your system themselves thinking about a user perspective, trying to use it as a user, trying to break it, et cetera. Okay, then we have TDD and BDD. I'm not going to offer my own definition of it, I'm just going to try to give my understanding of how the R-spec book defines them. Either way, you write your tests first but with TDD you start out with very small units, you build your way up out towards the edges of your system. With BDD it's the opposite, you start out with a broader perspective of what you're trying to do for your whole system and then work your way down. So how did those fall out? Well, not surprisingly, they're all in the accuracy camp because they all help you write more accurate code. Coverage helps you out with the future as well, it's explicitly designed that if anything about your code changes in a way that's going to break it, you have a test alerting you to that fact. You have BDD, manual QA and integration tests, I think actually do relate a little bit to usefulness because they're making you think about your system not in terms of is a code, right? But what is the purpose of writing this code? And testing I put in the middle because I think that all of these actually provide a pretty strong signal in a bunch of different directions. So I think of testing as essential practice as well. All right, so that was a little dry, let's talk about some hot new buzzwords. Everyone's talking about functional programming. DHH seems to be, I'm not sure if he's in Twitter or not based on the keynote this morning, but everyone's talking about it, type systems, everyone's talking now about gradual typing, soft typing, type script, type, type, type. Immutability, creating objects that should not change after they're created and scalability. Everyone's talking about now how you have to be Facebook style, you have to be Twitter scale, you have to be, I don't even know. So most of these are actually really in the accuracy camp. You could make an argument to push over some of them into sustainability just a little bit, but ultimately they're about writing code that's accurate, that doesn't have unexpected side effects. So that's most of them. Scalability is a little different, it's about future usefulness. And the reason that I say that is because if you actually need scalability right now, that's not called scalability anymore, that's called our app is down in production. That's a different problem. An important one, but not the same. Scalability is about well, one day we might need to deal with a lot more load, so let's think about that now. Which I don't know how useful that is, but for some apps, I guess it can be. All right, complexity metrics, those are fun. Cyclomatic complexity, how many assignments, branching and conditionals does your code have that make it more difficult to understand? If you use flay, it's looking at that. Low-Canasans, this was introduced to me by the patron saint of Wunder Jim Wyrick in a talk that he gave a few years back. Basically different places of your code that have to change in tandem create canasans and we wanna lower that, we wanna minimize how many things you have to change together to have your system not break. So I put that, basically the more complex something is the harder it is to write correctly the first time and the harder it is to write correctly the next time also. So that's where I see those falling out. Okay, now we get to something that's, for me a lot of fun, something I care about a lot, which is team-oriented practices. Organization conventions, if you have something like, we all use the same, we all use Rails, we all use a certain tech stack, a certain process tool, anything that is consistent across your organization that makes it easy to move across teams if need be, that's one team-oriented practice. A style guide, and ideally, unfortunately that style guide programmatically with Rubikop, JS, whatever's the appropriate tool. Something that keeps your code consistent so it's much easier to navigate and understand. The bus factor, this is the measurement of how many people on your team would have to be hit by a bus in order to destroy your application. Fun fact, most teams have a bus factor of one. Which is bad because occasionally, aside from dying, people also quit, get fired, take vacations, get sick. We want to ideally have room in our organizations for people to do normal people things and have our apps not be destroyed. So, mainly knowledge sharing, also upping the level of really everybody on the team rather than kind of hoarding knowledge or skill. Code review, okay? Stuff gets reviewed before it's checked into source control. Pair programming or mob programming, the sort of like code review on steroids, taking multiple developers, however many it is, and having them work on code at the same time, each providing their own perspectives. Internal documentation, readme's, stuff like that, things that help you both onboard new developers and also remind you of things that you might have forgotten or you might have forgotten to share with other people on your team. Debugging tools, stuff that helps you out a lot when things break, and you need more insight into your system. And the last thing is mentorship. Which I'm choosing to define, and it's a choice, I'll admit it, but I'm choosing to define as taking two people on your team who have different skill sets, pairing them together in a formal context over a long period of time and having them share their skills with each other. So, most of these fall into sustainability because they're practices that help you build up your team. Your team works better together, your team is more stable. I put mentorship on that crossover with accuracy because it turns out that people who are more skilled end up writing better code. So, both the first time as well as keeping your team healthy in the future. Code review, I put in the crossover between accuracy and usefulness because code review, first of all, is just a good check on whether your code is doing what it's supposed to do, but it also creates an opportunity for a conversation about should we be writing this code? Is this the right code to write right now? Is this the right solution to the problem that we're facing? And pairing and mobbing, like I said, are kind of code review on steroids. The cool thing about it is that it does all those things while also building up your team, building those relationships. I once saw something, a Quora answer by Campback, he was asked, actually someone just asked the world, does Campback believe that pair programming is always a good idea? So, Campback I guess found that and answered. He basically said when either the problem space is big, the solution space is big, or you need to build relationships on a team. Really important to remember that pair programming or mob programming also have that effect. All right, couple miscellaneous items. Continuous integration, making sure that your code passes a build before you actually deploy it. Frequent releases, frequent releases, kind of self-explanatory. Refactoring, not as a thing that you do once, but as a thing that you do constantly, always looking to improve the health of your code base. Conventional APIs, basically using things like RailsRest or JSON API, or just the normal ways of doing stuff in the language of choice, things like add a reader and add a writer rather than get adder and get set adder in Ruby or the opposite, I guess, in Java. Just kind of using the things that people expect. So those fall out kind of all over. CI is mainly an accuracy thing. You wanna know that your code works. Refactoring is on that border between accuracy and sustainability because it helps you write code correctly, because usually you're refactoring in the context of writing new code. It helps you make sure that you got it right. It also helps you keep your code base healthy in the long run. Conventional APIs, I put on up top because I think that they are usually well designed and they leave you room to grow in the future. And frequent releases. So, I did not think of frequent releases as a central practice for a long time, so it's kind of a recent revelation for me. But the truth is, when you release things frequently, first of all, you figure out that things are broken really fast. So that, I guess, helps your accuracy. It helps your sustainability, because you're not building castles on top of foundations which you only later find out when you deploy are actually broken. And it helps out with usefulness because until you've actually shipped, any changes that you've made, you could think of as inventory, right? You haven't actually created value until you've shipped. And the faster that you ship, even a small bit of functionality, the faster it's gonna create value. Okay, so we've covered a lot of ground. We have a pretty diverse strategy, but we're kind of missing something. What goes in that red area? What's going in that usefulness section that we can use to balance out this picture of software quality? To me, it's practices that are centered on user-oriented thinking. The main one, which kind of leads to all the others, is a focus on delivering value. Rather than thinking about what's a cool thing that we could do now, or thinking about it from a very technical, like okay, let's build it up from the ground up, just focus on what's the next thing that I can do that will create value for our users. To understand that better, you have to actually talk to your users. You have to research their needs. You have to, if you can collaborate with them, the closer collaboration you can do, the better you'll be able to actually solve their problems because you'll understand what their problems are. Prioritization, it's really easy to get caught up in what's a cool thing to build, but if you're focused on delivering value, you'll prioritize the actual most important things for delivering value. Discoverability, if you create a really cool feature but nobody can find it, then you might as well have not done any of that coding because it's useless. Empathetic UI was not a term until about three seconds ago, as far as I know. I'm sure there's a real term, but what I mean is a UI that thinks about what are the needs of my users, what kind of situations are they gonna be in when they're using our software and then how do we anticipate those needs and give them what they need in the way that they need it. On time, depends on your organization and on your users and their needs, but if you're writing tax software, really try not to be a year late. Performance, we always think of performance as a computer science thing and for the life of me, I can't figure out why. Part of it is because yes, so much of computer science curricula is about performance, but it doesn't matter for some reason of technical accuracy or anything. It matters because users can't wait forever for your app to work. It's just to meet a user need and when you do performance optimization, you have to actually focus on meeting that user need and what are the things that they actually need me to optimize. So that's pretty good in the red area and we're just gonna add a couple more things for technical products. Documentation is the face of your product to your users. If they see a distinction between your documentation and what your software actually does, they don't think that your documentation is wrong. They think your software is broken. Something to think about. Writing client code may or may not be relevant in terms of what you're doing, but sometimes if you write a client library that will help your clients use the code that you're creating, the technical product that you're creating, that will actually give more value to them than just kind of staying on your own and making a more robust product, but they have to figure out how to integrate it. All right, so that's the whole picture in my mind and there's more practices that I care about, but we only have limited time. But this is my brain right here on a slide. There's more to my brain than that, but part of my brain. But ultimately in the question of is it quality software? I can't tell you. You have to decide. So I'm gonna leave you with this. A blank slate. I put it, or I'm about to put it on my site. I tried to deploy before and it didn't appear so I'm gonna try again right after. But bring this back to your teams. Think about these issues. Think about the practices that you do and that you care about as individuals and as teams. And whether there's areas that are missing that are a little patchy in terms of your software quality. All right, so we're gonna wrap up. Couple of parting thoughts. Number one is different projects require different balances of factors. And actually Chembeck has this three X framework you've been talking about recently, which points out that even within one project it'll change over time which of these things matter. Number two, I don't think it's bad to focus on good code first in terms of career development. Why? This is more straightforward. Business understanding takes a really long time to develop. It's really important but it takes a long time. Good code, you can get really, really much better at good code in a scale of months, maybe a small number of years. And once that happens, by the way, it becomes more automatic. Like you'll find yourself less able to write bad code if that's the way that I can put it. Business understanding, you can't automate. It's something that you have to constantly refresh because there are constantly new business realities. So the implication is start off really focused on good code and then move more into business understanding in terms of your focus as you move on. So your career trajectory might look like this. The middle line's sloping down. You start out focusing a lot on good code but then it goes down. Business understanding is kind of coming in in its place. Those lines might cross. Those lines might cross really far if you're going into management or project, a product management or stuff like that. They might say far apart if you're an architect but those lines should change over time. That's okay, that's expected, that's a good thing. The main thing is the line on top is how much value are you creating? So what can I do to build business understanding? It's basically a matter of learning. It's learning about your users, your industry, the organization of your organization looking to solve dysfunctions within your organization, ideas of business, ideas of organizations and processes. So there's all that learning but you also have to become better at empathy skills. And that's my last point is that empathy is gonna become ever more important. What can you do to build empathy skills? Number one is read, learn, find out about new ideas. Next slide, we'll talk about that but the other part is practice. Meaning cultivating curiosity about others. Especially if they're different from you which is really hard. But you have to listen to them. You have to understand their needs and their feelings and see the humanity ultimately in everyone. That will make you a better person and it'll also make you a much more effective developer and person in your business. So I started a club, or I'm starting a club that's launching officially at the end of RailsConf. We're gonna be reading books on empathy. In the software context, in a general context and thinking about how they apply in our professional lives. You can check out the site, devempathybook.club if you're interested. I'd really like there to be more discussion about these things in our community. So check it out. But the bottom line is make your software valuable, high quality, creating value for users and make yourself valuable. I wanna thank a few people. I'm not gonna name them, they're on the slide. But what I've said today is not my ideas per se. They're just my analysis and integration of ideas that I've learned from and through these people. I especially wanna call out Gene Westbrook who was my mentor for my first year at Vitals and he's in the room today. So thank you for being there for me. And the last thing I'm gonna say is I spent a lot of time on airplanes to get here. 18 hours in the air, three flights. So I'm a little like, I have the airline thing still like haunting my dreams. So I'm just gonna say I know you have a lot of options as to where you can spend your time at RailsConf. Thank you very much for spending it here.