 to be here. This is my 10th Gerucho. I've been at all of them. So I'm especially honored to be speaking at this Gerucho X edition. Also really honored to be keynoting. That was a bit of a surprise. And until I found out that that actually meant that I was the first one up in the morning. So there were trade-offs with that. But I made it. So we're going to talk a little bit about code quality lessons learned. As Luke mentioned, I started a company called Code Climate about five years ago. How many of you have heard of Code Climate? All right. Anyone who doesn't have their hands up, come see me afterwards. But the reason I mention this is because Code Climate helps teams by providing automated code review using static analysis to help teams and projects achieve higher quality and better outcomes. So we have a little bit of experience working with this code quality and the questions that it poses. There are over 80,000 repositories that get analyzed by Code Climate with our static analysis every day from over 75,000 developers who have taken advantage of our tools across 1,500 organizations. So that is where a lot of this experience that we're going to be talking about today is drawn from. So we thought it would be interesting to look at six questions related to code quality that might have sort of non-obvious answers or interesting answers that we're going to sort of walk through today. The first question is, what is code quality? This comes up almost right away when we start talking with an organization about what they're trying to achieve. The code part is very obvious. We all know what code is. But what does quality mean? Maybe that is not as easy to answer. So one way to try to answer the question of what is code quality might be looking at the opposite of code quality. So everybody is familiar probably with legacy code. This is often described as the opposite of code quality. So the definition of legacy code, it's a noun. It means code written by somebody else or code written by me more than two weeks ago. That is legacy code. So anything that's not legacy would be quality. Of course, like we said, we realize that code quality has many meanings. When we talk with developers about the quality of their code, they use adjectives like simple. They want to be able to get the work done in as efficient way as possible. Well tested either with unit tests or integration tests or both. Bug free. Does the code do exactly what it was intended to do without defects? Is it clear? Can somebody read it and understand it and can the team maintain it over time? Some teams will talk about refactored code. Was it not just written once, committed, and sort of did the developer move on? Did they actually go back and try to iterate the design of the code to match best practices and the team's conventions? Documented. Some teams will want code to be documented either inside the code or with supplemental documentation. Extensible. Can the code be evolved to meet new requirements that show up in the future? In some cases, just fast performance. If you're building a trading system, it would be hard to talk about your code being high quality if it takes 300 milliseconds to process a trade when you need to be able to do them in under a millisecond. The takeaway here is to make sure that your team is on the same page about your goals. If you want to improve code quality and different individuals on your team have a different understanding about what code quality is or how to achieve it, then you are at risk of spending a lot of time, energy, and potentially frustration moving in different directions, either opposite directions or even just not exactly the same direction. And one quote that I feel like really sums this up is thinking about the design of code. Somebody once said, any code less decomposed than mine is a mess. And any code more decomposed than mine is over engineered. And you probably all felt this before, right? That code that is, you know, less decomposed is a mess. But everyone's also, at the same time, criticized code that they felt was over engineered and thrown around the word yagney. So start with that conversation with your team is the takeaway. The second question that I wanted to look at is what is the best way to measure the complexity of the code? Suppose we've identified that maintainability and complexity are the goals. How could we actually measure that with our code base and with the changes that we're making to determine that we're moving in the right direction? Now, the oldest and most famous measurement of code complexity is WTFs per minute, as you can see. On the left side, there is a code review going on. And the code being reviewed is of high quality because the reviewers are only swearing a little bit. And then on the right side, you can see that that code review is going much less well. So the code is obviously of lower quality based on the profanity. Now, in truth, there are many metrics that can be used to evaluate the complexity of a given unit of code. Some of you may be familiar with cyclomatic complexity, which sometimes is also known as McCabe's complexity or McCabe's number. And it refers to the number of individual paths through a given block of code. Some of you may have also heard of the ABC metric, which is slightly less well known, but it's a measure of code complexity or size based on the assignments, branches, and conditionals within a method or a class. And we'll have to take a look at that in just a moment. And thirdly, the sort of classic oldest measure of code complexity. Everyone knows lines of code. It's very easy to understand the lines of code. We'll talk about that in a second as well. So this is the definition of the ABC metric that you're seeing here. And you can see that to compute the ABC metric for a given unit of code, you take the assignments in that code, squared, plus the branches squared, plus the conditional squared, sum that all up, and take the square root, and it'll produce a single number. Now, what can seem nice about this is it doesn't just take into account code paths and conditional logic like the cyclomatic complexity. It also incorporates elements like assignments, which do tend to add to the cognitive load of processing a given block of code. So it can be perceived as more precise for estimating the code complexity. However, if you tell a developer that the method that they just wrote has an ABC score or an ABC metric of 47.3, that might be difficult for that developer to interpret. It's unclear if 47.3 is a low score or a high score. It's also unclear, importantly, what the developer would do to reduce that score. Now, they might infer that by moving some code out of the method in question that one of those variables would be reduced, and therefore the overall score would be reduced, which is true, but it's somewhat indirect. So with code climate, we have support for cyclomatic complexity and ABC metrics in many cases, and what we've found through talking to a number of teams is that the most important thing when choosing a metric to track is to choose a metric that resonates with your team. So if your team is used to talking about things like cyclomatic complexity or McCabe complexity, then that can be a perfectly appropriate choice as a metric to track within your team. However, if those are not concepts that your team is familiar with, then it may be preferable to choose something simple. So at this point, when a team comes to us and says that they want to start tracking a metric related to complexity or code size or maintainability, our recommendation often is just to use lines of code, which sounds almost naive and silly, right? The reason that people laugh at lines of code as a metric is that in the past, there were managers who would evaluate the productivity of their developers in terms of the number of lines of code written per day or per week or per month, and that's how you sorted the good developers from the bad developers. The good developers wrote lots and lots of code. Everybody knows that. But if you look at the lines of code metric on a class or a method, it actually turns out that it correlates incredibly well above a certain size with how easy it is to understand that unit of code. If you have a class or a file like userRB, I'm sure none of you have this, but if you knew somebody who had a userRB file that was 1,300 lines long that nobody ever wanted to change anything in, but somehow every week somebody's adding just one more thing to it, just for the feature that needs to shift this week in that userRB file, you would be able to see that that code is probably difficult to maintain. So the nice thing is if you use lines of code as a metric, it's very clear what you need to do to improve on it. The code needs to go somewhere else. There's only one solution. So that can make it easier to understand what to do when the metric is showing you something that you don't expect or that doesn't seem preferable. Also, you have the advantage of being able to choose the lines of code metric and just get back to work, because we have seen teams burn immeasurable amounts of time with internal debates about the relative value and precision of metrics like cyclomatic complexity and ABC metrics and all of this stuff, and there are very quickly diminishing returns. The third question that we wanted to look at is why are older projects harder to maintain? Everybody loves working on green field projects. Just the name, it sounds delightful. You picture a blue sky and a sun shining down on this empty field. The problem with green field projects is that very quickly, or green fields, is they very quickly tend to attract cows, and you are all the cows. Because cows enter a green field, and it tends to be that over time they turn it into a brown field. So why does that happen? One of the reasons is that sloppy code is self-reinforcing. If you introduce sloppy code into a code base, you don't just have to live with that sloppy code for a potentially long amount of time, often years. It's also the case that that sloppy code may perpetuate other instances of sloppy code in the code base. Let's look at what that cycle might be like. Oftentimes it starts with pressure. So there might be some need, some business critical priority like a key customer deal, or perhaps an event. Maybe you need some large amount of functionality finished by the time Geruco rolls around, and I'm sure none of the code climate developers can relate to this at all. There might be pressure to get the code done. The pressure leads to the sloppy code. The developers cut corners and in some cases will knowingly act differently with respect to the way that they craft that code and do not apply the same level of rigor, but the intentions are good here. They're trying to meet the business need. Unfortunately, sloppy code can make it harder to work in the code base. It can mean that you're no longer able to deliver as quickly as you were before, which leads to the project in a word being late. And of course, when you tell somebody on the business side that the project is going to be late, that loops right back around to pressure. And you can see how this cycle perpetuates. So that's one reason why code quality on projects that are older might not be as good as newer ones. Another is that code quality is a moving target. So to look at this diagram, you can see that the code is represented by the horizontal line on the bottom. At the time that the code was written, it aligned perfectly with the domain as it was understood by the business. In this case, the code is not changing. The code just continues to exist over the horizontal axes. But what you can see is that the domain of the business actually diverges from the code because the business is not standing still. It's learning new things. It's entering new markets. It's subject to new requirements. And the delta between the domain and the code at any given time can be described as technical debt. And the more technical debt you have over time, the more that that can slow your project down. There are a few ways to deal with this. Everyone probably has familiarity or experience with efforts like a rewrite or a big redesign to try to align or replace components with components that are more connected to the domain as it's now understood. And that is one approach. We often recommend taking a more iterative design approach where on a more regular basis, the team is aligning the code with the domain. And you can see in the difference between these two diagrams that the area between the two lines, which is the technical debt, in the iterative design approach is much lower. You're not waiting until the big refactoring to converge those two things. So this is an example of a principle that sometimes gets referred to as the Boy Scout rule, which is to always leave your code better than you found it. In this case, it would be always leaving your code closer to the understanding of the domain than it was when you found it. Okay. The fourth question that we wanted to look at is what is the optimal size for a pull request? Many of you have probably seen pull requests as simple, of course, as a single line or single word change all the way up to those very large pull requests that incorporate thousands and thousands of lines. And as we know, because lines of code correspond with more work being done, those are the really good ones. The joke is that if you present a developer with ten lines of code to review, they'll probably have 13 comments about little things that you can do differently. But if you present a developer with a 4,000 line pull request, the comment will be, looks good to me. So why is that? A company called Smart Bear Software did an interesting study of about 2,500 code reviews at Cisco, and some of the information that they collected was the size of the change that was being reviewed, and also the density of the defects that were identified. In this case, this was human reviewers who perceived that there was a problem with the code and would note it. And so they looked at the way that the defect density of the code related to the size of the change. What they found was that fewer issues are found in larger pull requests if you look at it in terms of issues per line of code. The problem is that it doesn't take a whole lot of intuition to realize that when we're making large changes, it's not likely that those changes have a lower defect rate than small changes. It's pretty obvious that you would expect that the defect rate of a larger change would be at least as high as a smaller change, if not higher, because there's many more things that can go wrong in a larger change. So this wasn't because larger pull requests have higher quality. What they found was that 400 lines of code was an interesting sweet spot where the human reviewers were still able to identify defects at the same ideal rate. And then above 400 lines of code, the rate of the human reviewers ability to find defects would decline substantially. So what you could consider on your team is any time you see a pull request that's over 400 lines of code, you might post a comment and just ask, is there a way that this could be broken down into a series of smaller changes? And perhaps that's a feature that Code Climate will support at some point. There's an interesting quote that I think is kind of related to this from Brandon Keepers who works at GitHub, which is that we are more receptive to feedback from pedantic robots than pedantic people. And robots are more reliable. So everything we talked about in terms of defect identification relates to human reviews. So if you are using a static analysis tool or a linter, of course, it doesn't get fatigued by the size of your change. It's going to do the same thing on every file. So it can be a way to supplement and hedge against the human's ability to identify defects in larger changes, to supplement that with automated tools that aren't going to be subject to that fatigue. Okay. The fifth question that we wanted to look at is when is sloppy code not a problem? When might it be okay or perhaps even desirable to have code which is lower quality than you might otherwise intend to write? And there are three different cases that we've seen where that may be the case. The first is proving a hypothesis. When you're getting started with a new project or a new business, it might not be clear whether there is actual business value that can be created from the code that you're writing at that point in time. You might have an existential threat to the survival of your business to answer the question of how are we going to deliver value? What is the product that we're going to provide? And in those cases, it can be preferable and in some cases necessary to write code that doesn't necessarily represent your idealized version of quality. My friend Patrick McKenzie has an interesting quote about this that he tweeted. There are two types of bootstrap startups in the world, those with integration tests and those with revenues, which is not entirely accurate, but it's a little tongue in cheek and you can kind of see his point. I can certainly say that the initial versions and iterations of the code climate code bases were not necessarily of the highest quality and the developers at Code Climate can probably attest to that. Another example would be if you can build the first one to throw it away. There are certain situations where you might have a problem you need to solve as a developer and you may realize going in that it's very hard to know the exact approach that you're going to end up needing to take to solve the problem. It's not just a form for collecting content or something like that that you've done 100 times in the past. You don't actually know how you're going to solve it. In those situations, it can be useful to build a version of that code to enhance your understanding with a plan to throw it away at the end. Sometimes this gets referred to as a spike. The key with a spike is to actually throw it away. Spikes have a tendency to be created with the understanding that will be thrown away and then end up in production. So you have to be careful there. The third example would be what's known as an omega mess. Omega mess was a term coined by Sandy Metz which is defined as code that has only inbound dependencies and does not change. And these things, of course, are very related. If the code has a lot of outbound dependencies, then it would necessarily need to change if any of the code that it depends on changes. But sometimes you have a unit of code which only has outside callers into that unit. And it may not need to change at all. In those cases, you might have a higher tolerance for lower quality code than you would in the rest of the areas of the system. So an example would be perhaps you have a module which interacts with a legacy external system, like calls into a main frame or something like that. You may know that that code, the server that it makes calls to, is not changing, has not changed in many, many years. And so the fact that if you open that module, the code is difficult to understand, may not be a big deal as long as everybody on the project is able to take advantage of that module because it has a clean interface that it exposes. So the omega mess may be the third type of situation where sloppy code or lower quality code may be more acceptable or desirable. Okay? The sixth and last question that we wanted to look at is one of my favorites. And that's what is the biggest enemy to clean code or high quality code? Why aren't all projects high quality? Is it apathy? Is it that developers don't actually care about the quality of the code in their projects? I would pose that it's clearly not apathy. Everybody in this room, I feel like, likely has a desire to produce high quality results as a developer that's something that we feel internally regardless of whether we're asked to do that specifically by somebody who's asking us to implement a project. We also know that if the code is low quality, we're the ones who are going to be stuck maintaining it and dealing with it afterwards. So it's not apathy. Is it ability? Is it that developers want higher quality code, but they just don't know what to do in order to achieve that result? Well, I would argue that it's not ability because what we've seen is even in cases where projects are staffed by very experienced engineers, they tend to fall victim to these same cycles and pressures where the code quality over time does decrease. So it's not the experience of the team. Is it changing requirements? Is it those dastardly business people who are always pulling the rug out from under us? You know, they tell us to do one thing and then they tell us to do something else a week later. That might be a little bit of it, but I think there's a more interesting reason for why code quality can be so hard to maintain. So why don't we walk through an example of a developer making a change and how they might think about that change and what it tells us? So starting at the beginning, developers don't want to introduce bugs, but they know that it's easy to introduce a bug when changing code. By the way, this is a diagram by a gentleman, David Peterson, that he did on his blog a while back, and I think that this is just a really great example, so that's why I wanted to walk through it. So the developer doesn't want to introduce bugs, it's easy to introduce a bug by changing code, so the developer will take care to minimize changes to existing code. Now, the way they do that is where things start to go awry. They know that working on a copy of the code means that you don't have to change the original, so the developer may introduce duplication. Also, the developer understands that putting a conditional around new code will reduce the chances of breaking the existing code, so they can introduce a conditional to make sure that they're only going to modify the behavior in their particular case. Together, what you see is that conditional logic increases the complexity of the code and duplication increases the complexity of the code, resulting in code that is difficult to understand, and so the developer doesn't understand the ramifications of a change they're about to make, which brings us right back to the beginning, that it's easy to introduce bugs. Now, what's interesting about this is that at every step of the flow chart, the developer made a reasonable decision to try to reduce the likelihood that they're going to introduce bugs, and in a way, have higher quality code, but if you follow this logically through, you are introducing more and more duplication, more and more conditional logic, and creating more and more complex code that is actually working against your initial desire. So, the reason that the biggest enemy to code quality in our experience is actually fear. It's this visceral fear, it's the fear of not being able to make the change that you want without introducing another problem, and that leads to poor decision-making. So, if you want to improve the quality on your project, the biggest thing that I can recommend is reduce the fear of making changes, and there are many ways to reduce fear, and we're not going to have time to go in depth into them today, but some of them, they will all probably be familiar. You can reduce fear with automated testing, unit tests, integration tests, you can reduce fear with operational metrics, if you know that your code is functioning well in production and performance and not returning exceptions to end users, that can give you confidence. Code review, which we've already talked a lot about. Static analysis, of course, near and dear to our hearts is a way to reduce fear of certain types of changes, and many teams leverage pair programming, having two sets of eyes on every change to advance the code and be confident that they're not going to break anything. So if I can leave you with one idea, it's that hope is not a plan. If you have issues with quality on your project that you want to resolve, if you keep doing the same things, they're unlikely to change. So you need to take a step back and sit down with your team and figure out what code quality means to you and your team, define it, agree on it, and then start taking actions to reduce the fear associated with making changes, and that's how you're going to be able to achieve the results that you set out to do. So thank you very much. I really appreciate it.