00:00:19.980
Today, I'd like to talk about building a culture of code quality. But, a favorite tip for conference speaking is to avoid being scheduled directly after someone who does improv comedy—that's the worst spot. With that said, I'm really excited to be here at LoneStarRuby, or as it's more popularly known, LoneStarRuby Conf.
00:00:38.470
My name's Bryan, and I work at a company called Code Climate. A couple of years ago, I was asked how many people had heard of us. Since we already did that, how many people here are actually Code Climate customers? Raise your hands. Yes, you guys are my friends, so it’s great to see you all here.
00:00:56.949
So, I lost my train of thought for a moment. I was thinking about a new talk to give and someone suggested I should talk about Code Climate. I thought that was great; it would be really easy to prepare. I’d love to share with everyone the amazing things that Code Climate can do to help improve code quality and catch bugs in Ruby applications. However, about five minutes later, I realized I couldn’t give that talk because then everyone would hate me for just talking about my own product. So, I thought, why not talk about building a culture of code quality instead? That’s what we’re going to discuss today.
00:01:38.130
In fact, very little of what we’ll talk about has to do with Code Climate or Ruby. This is kind of like the softest talk I’ve given, so it will be a bit of an experiment for both of us, but hopefully it will be a fun ride. I want to start with a definition that has to do with presenting problems. This is a term I became familiar with over the last couple of years. It comes from medicine and refers to the initial symptom that motivates you to see a doctor. For example, you might go to a doctor because your arm is sore— that’s the presenting problem. There could be countless reasons for that soreness, but the symptom you want to address is the pain in your arm.
00:02:01.810
Now, with code quality, there are several presenting problems that can arise in your project if you're not maintaining the quality of your codebase. You may be familiar with some of these, maybe not in your current project with your current team, but with a previous project or a different team. You might have encountered issues such as slow progress, where it feels incredibly difficult to add new features. It can seem like you're constantly fighting to implement any changes in the codebase, struggling with every single modification.
00:02:42.050
With every change you attempt, you might feel at risk of introducing bugs unintentionally. During your shipping process to production, your QA team, users, or someone in the business might discover an issue that requires your attention. This is a presenting problem indicating you have a code quality issue. Furthermore, when trying to fix those bugs, you might find that fixing one bug over here causes a new bug to pop up over there. It's akin to playing a game of whack-a-mole against your codebase to prevent bugs from arising; all of these are presenting problems that suggest issues with code quality.
00:03:14.360
This can create a vicious cycle. Let’s explore how that typically works. It usually starts with pressure. Perhaps your business committed to a customer to deliver a fixed set of features by a certain deadline. In some cases, that’s a strategic decision for the business, but at the end of the day, the responsibility usually falls on us to make sure it happens. So, there is pressure to complete these features by the specified date.
00:03:46.820
Under pressure, developers often write code that isn’t up to their usual standards. I refer to that as 'sloppy' coding practices. Some people might use the term 'technical debt,' but I believe there’s a significant difference between technical debt and slop. Sloppy practices can lead to delays, as you're now grappling with unfixed, poor code each milestone becomes harder to meet. It's like running on a treadmill that keeps increasing in resistance. With more pressure, you’ve returned to the beginning of the cycle: pressure causing sloppier code, leading to more delays, and feeling completely overwhelmed.
00:04:34.750
Today, we’re going to look at how to avoid this situation, and if you're already in it, how to get out. There are multiple factors that generally work against code quality. Essentially, everything tends to deteriorate over the life of a project. The natural trend for code quality is to decline, and we see this repeatedly. Businesses change frequently, and many of us work within smaller organizations facing a lot of uncertainties.
00:05:14.470
The things a business considers important today may differ from what is deemed important next month, putting pressure on the engineering team to adapt. Change requires heightened attention to quality, or else trouble ensues. We frequently encounter newer technologies. We may need to replace a SQL database with something like Redis or MongoDB to achieve specific application characteristics. Those changes can also compromise quality and introduce sloppy coding.
00:05:57.530
Also, almost all projects eventually face team changes. People may rotate through projects within the same company, or new hires might come in with different levels of experience than those who originally developed the application. While everyone would love to hire only senior software engineers, that’s not always realistic. Even if they did, how would junior software engineers become senior if they're not given the opportunity to gain experience? We need a way to enhance everyone's skills without compromising overall code quality.
00:06:43.490
There’s an interesting diagram that I came across on David Peterson's blog, looking at why poor quality code gets introduced. Developers typically don't want to introduce bugs; that’s a given. However, changing code can easily result in bugs being introduced. Logically, a developer might aim to minimize changes in existing code, and this inclination can lead to duplication—avoiding altering original code altogether. You might end up using conditional logic extensively around new code to prevent breaking old code, creating complexity in your application.
00:07:32.090
This complexity makes understanding the implications of any change challenging. Ultimately, you find yourself back at square one, where introducing bugs becomes easier again. This pattern can repeat ad infinitum during the maintenance of your applications, making it one reason quality is hard to sustain over time amidst constant change.
00:08:14.460
Now, if you fail to address these concerns, you will likely end up with legacy code. Legacy code is a technical term referring to the code written by someone else—or even you—more than two weeks ago. This is a stark reminder that if you don’t keep an eye on code quality, you will end up with what we commonly refer to as legacy code.
00:08:51.370
Hope is not a plan. Time and time again, I see experienced developers with good intentions venturing into green pastures with their next project. They often recount how their last project was a disaster—difficult, chaotic. They declare that the next project will be better. But, if you press them for specifics on how they plan to improve, you often find it difficult for them to provide concrete answers. It’s usually just a desire for things to be different this time, yet hope itself isn't enough.
00:09:29.600
Therefore, I propose to you that doing the same things repeatedly and expecting different outcomes isn't a viable strategy if you want your next project to feel better regarding code quality. Today, we'll explore how to implement some different approaches. First, we’ll discuss gathering data—a high-level approach to code quality—followed by specific lightweight practices that you can implement with your team to foster continuous improvement.
00:10:03.990
To kick things off, I have a universal solution to solve any problem: step one, assemble information; step two, act on information. You can apply that anywhere. Simple, right? But let's apply this to code quality.
00:10:54.020
When I'm looking at assembling information, I prefer to divide it into qualitative and quantitative data. I always start with qualitative, since this will help you determine the right quantitative information to gather. Within your team, if you feel like you might have code quality issues, a good first step is ensuring you have one-on-ones happening within your organization.
00:11:29.190
These should be recurring opportunities set aside for a developer to talk with their manager. This helps build trust over time and promotes a two-way feedback dialogue about what's going on within the individual’s work and the broader organization. Thus, when feedback is conveyed, it doesn’t come as a shock.
00:12:02.420
You want these conversations to feel natural for both parties. If you’re a manager and have direct reports, I recommend these one-on-ones highly. If you're an engineer without one-on-ones with your manager, be proactive—approach them about setting up a recurring time to discuss how things are progressing.
00:12:39.730
At the team level, retrospectives are essential. Plenty of literature exists on how to run effective retrospectives. Ultimately, it's about gathering everyone—stakeholders and developers—into a room to discuss what was accomplished over a fixed period, how it went, what could have been better, and what went well. Collectively, you come up with action items to improve processes moving forward.
00:13:18.290
You can also rotate the format of retrospectives and the individuals leading them, which is important for keeping all team members accountable for both quality and process improvements. When it comes to quantitative data, as engineers, we appreciate metrics. You can gather various process metrics, such as velocity, cycle time, and defect rates from your releases.
00:14:01.030
These metrics can easily be charted for insights. I believe surveying your team is an underused practice; conducting an anonymous survey could yield useful information. Ask your team whether they feel the code quality improved last week, worsened, or remained the same. Or ask how likely they think the team is to meet an upcoming deadline. You might be able to predicted project derailment faster through these surveys than any Gantt chart could indicate.
00:14:41.380
Lastly, software metrics matter. Code Climate provides these, but you can compile them yourself. Tons of valuable information resides in your development artifacts, such as your source code and test suite. By assembling and analyzing these, you can generate meaningful insights.
00:15:16.250
After you've gathered your data, it’s time to embark on a process of continually improving quality over time. Remember, there are no silver bullets. We've all been searching for quick fixes to software maintenance challenges, but they don’t exist. However, two general strategies work in almost all cases.
00:15:58.600
The first is an old adage: when you find yourself in a hole, stop digging. If you know you have software quality issues, ensure you're not introducing new problems. This consists of being mindful not to add new layers of sloppy code while also ensuring that existing areas don’t deteriorate. If you need to make changes to a class you recognize as problematic, do not simply copy and paste it into a different object. Instead, consider the overall impact on the system.
00:16:40.500
The second approach is known as the Boy Scout rule: always leave your campsite cleaner than you found it. For software, this means whenever you touch your codebase, take some extra time to clean something up—whether it’s refactoring a method or adjusting code to align with your team’s standards. If you adopt this habit consistently while preventing new problems, the quality of your code will naturally improve over time.
00:17:26.390
Now, you might think this is obvious advice, but executing it effectively is often challenging. So how can we ensure our teams actually follow through? One potential issue might be conflicting style preferences among team members. We’ve all worked with that one person who insists on writing code differently from the rest of the team, right? Well, what can we do about this?
00:18:03.540
The answer lies in developing a style guide. You may want to lock yourself into a conference room with your team until you agree on a style guide that defines how the team will format their code. This process may require social interactions and even some compromises. The key is that you can't leave the room until it’s finished.
00:18:45.270
After defining the style guide, it’s important to adhere to it consistently. If some deviations are allowed, state that clearly within the guide, but ensure that any differences do not devolve into circulation of superficial complaints over style preferences. A defined process for out-of-band discussions or reviews of the style guide can be crucial. Ensure everyone knows when these reviews occur so team members won’t feel the need to endlessly debate minor stylistic choices.
00:19:30.550
But let's move to a more substantial issue: perhaps not everyone on the team has sufficient refactoring experience to continuously enhance the codebase. One constructive solution is to hold lunch-and-learn sessions. For example, in New York, Pivotal Labs hosts weekly talks where guest speakers present topics relevant to the development team.
00:20:19.630
You could bring in a speaker to lead staff discussions or utilize online talks from conventions while providing pizza to create a relaxed atmosphere. Furthermore, team members can discuss relevant articles or blog posts that have applicable insights, rotating the leadership of these sessions so everyone contributes.
00:21:06.180
I also coined a term today: 'team factoring.' This technique promotes skill development among team members in refactoring contexts. Block off an hour to review problematic code as a group, guiding discussions through extreme pair programming: one driver in control while others navigate.
00:21:46.210
The benefit here isn’t just the actual changes; it’s the rich discussions that arise and facilitate learning. When a senior engineer shares previous solutions to similar issues and discusses their effectiveness, everyone increases their understanding of refactoring principles.
00:22:23.700
The outcome of the session doesn't always need to be immediate code changes—sometimes, it's sufficient to encourage a culture of collaboration and continuous improvement, focusing on the discussions that shape future practices. If the code gets clean and can go to production, great; ship it! But if it’s not up to the standards, don't feel obligated to force it out.
00:23:03.090
Next, another challenge is discovering issues too late. For example, uncovering a bug a month after it was introduced will likely lead to delays in fixing it and increased costs for the company. Similarly, when addressing quality issues a month after they appeared, my favorite phrase comes into play: 'broken gets fixed, but crap lasts forever'—meaning that a problem may never get fixed.
00:23:49.840
You want to address issues early to prevent them from cementing in your codebase. Early warning systems are vital. Build failures are an example of this; when that happens, send an alert to the team immediately to ensure the build gets addressed. Bugs and quality issues can often be detected with static analysis—if they can, automate alerts to your team. Twitter employs a tool that scans code for vulnerabilities and alerts developers upon identifying issues.
00:24:43.320
Creating an early warning system can save time and money in the long run. Another potential problem you might face involves missing high-level design perspectives. While your team might be proficient at refactoring single classes, adequate attention to overall architecture can sometimes fade during fast-paced agile environments.
00:25:29.440
For this, I recommend utilizing whiteboards. Find a large whiteboard that’s easily accessible to the team and actually use it. I advocate obtaining physical whiteboards in your workspace to assist with team discussions and design planning.
00:26:15.890
Now, let’s talk about code reviews. Code reviews can often feel daunting, especially when conducted in formal settings. To make the process feel more approachable, consider reframing the terminology. Instead of calling it a formal code review, use the term 'pull request review.' It's the same process but sounds far more engaging to the team members.
00:26:54.410
These pull request reviews can be tailored to be non-blocking. As you write code, don’t feel pressured to halt your progress for a review; that can foster frustration. Instead, code asynchronously, inviting reviews later and only pausing when necessary. If the review requires a conversation, you might tap a colleague on the shoulder and ask for clarification or insights.
00:27:40.260
It's imperative to allow developers to assess their code review needs and decide when to engage. The rationale for conducting reviews stems from our inability to effectively edit our work—when so deeply involved in the creation, we can’t step back and offer a critical perspective. For this reason, I suggest that peer reviews accompany paired programming sessions to ensure thorough evaluations.
00:28:26.250
When reviewing, focus on five key elements: formatting, correctness, scalability, and performance, but particularly comprehension. Understanding how well the code communicates its purpose is crucial. Perform all reviews with an eye toward clarity, helping to ensure future developers can easily grasp the code's intentions.
00:29:09.000
As we wrap up, I’ll address a frequent concern: managing team resistance to changes around quality practices. This challenge came up frequently when I asked what attendees wanted me to discuss regarding quality culture. A positive approach is to provide team members every possible opportunity to engage meaningfully with the process—experiment with code reviews, for instance.
00:29:53.510
Set specific time frames, like trying out code reviews for three months to reassess its effectiveness later. Make it clear that the team decides what works for them; this encourages buy-in and transparency. If a team member is resistant despite several attempts, it might be a sign that they are not a good fit for your organization.
00:30:22.360
Moving that individual out could lighten the load for the team, promoting a more positive atmosphere. Happy team members make for better development and could lead to future success for that person elsewhere as well. Lastly, I hope to end on a positive note, as I believe maintaining quality results in happier developers.
00:31:05.240
Satisfied developers equate to more engaged workers, who take greater ownership over their code, ultimately generating higher-quality software. Through this approach, you can transition from a vicious cycle to a virtuous cycle, creating an environment where progress continues upward regardless of baseline quality. That’s all I have for you today; thank you for your time and attention.