Showing posts with label coding standards. Show all posts
Showing posts with label coding standards. Show all posts

Monday, May 18, 2015

When Not To Refactor

Refactoring software is a crucial part of extending the life of software. Refactoring contributes to enhancing the maintainability of the software by incrementally improving the design, readability and modularity of the components. But not much has been said about when not to refactor software.

Don't refactor code unless you need to change the code for a business reason.


One of the common mistakes I often see with regards to refactoring is when people refactor code that doesn't need it under the guise of making it better. The argument usually goes something like "this needs to be more abstract", "I wrote this code a long time ago and it is crappy", "this code is too complex" or something along those lines.

You should only refactor code when you are already in the code to make a change to support the business. That may sound counter intuitive but one of the worst things we can do is change code, however crappy, unreadable or complex that doesn't have a reason to change.

Valid business reasons to change code include (but are not limited to):

  • Adding new functionality
  • Extending existing functionality.
  • Making measurable performance improvements.
  • Adding a layer of abstraction in order to support a new use case.
  • Modularizing a particular object so that it can be reused in another part of the system

Adding new functionality or Extending existing functionality


This is where the boyscout rule comes into play. If you are in already in the code for another reason then you should clean up the code even if you didn't make the mess.

Making measurable performance improvements


This one is probably self explanatory but it's important to note that performance improvements will usually require some level of refactoring. 

Adding a layer of abstraction in order to support a new use case


This is an important one to understand. Often people will over generalize code at the beginning. This leads to overly complex designs and less readable code. If we follow the rule of not creating a layer of abstraction until we have at least two or three use cases for the code then there will come a point when you need to refactor the code in order to provide a layer of abstraction that doesn't already exist.

Until that second or third use case comes about the code should not be generalized. You don't have enough information about future uses of the code to get the abstraction correct. You may get lucky and guess at the future abstraction but you don't want to run your business on guesses and luck.

Modularizing a particular object so that it can be reused in another part of the system


Code reuse is one of the most important tenets of object oriented programming. When we identify code that is not specific to a particular object or package AND is needed in some other part of the system we should refactor this code into it's own module. Its important to ONLY do this when the code is actually needed in another part of the system.

Don't refactor code without tests


In order to refactor code safely you should have unit and integration tests for the existing functionality. I would also argue that you should write tests for the new functionality as well before you refactor. This will help you to understand the proper way to refactor the code as it helps you define how the refactored code should be used from a consumers standpoint.

If the tests don't exist for the the existing functionality you should write them first before you start refactoring. This helps ensure that you don't cause a new bug in the code or regress an old bug when refactoring.


Monday, November 17, 2014

Transitioning to a professional software development role: part 3

In my first post in this series, Transitioning to a professional software development role: part 1, I started to outline some of the gaps I've seen in people's preparation for entering a career in the software development industry. I started off by focusing on what software development is not about.

In my second post in this seriesTransitioning to a professional software development role: part 2, I took a look at what software development IS about. In the final post in this series I'd like to talk about the tools available that make us more efficient.

Being a good software developer means understanding how to apply agile


For a long time developing software was very much like developing a product on an assembly line. Assembly lines are very rigid and not well suited to respond to change. They run on the assumption that what happens upstream in the assembly line can be built upon and won't change. The moment change is introduced most of the product on the assembly line is ruined and must be thrown away.

Software's assembly line is called Waterfall. Overtime we've come to understand the downfall of waterfall and it's major flaw is that it's very rigid to change. Rigidity to change was okay when the primary delivery mechanism for software was the compact disk. But as software has grown to allow near real time delivery of features and functionality Waterfalls rigidity to change has become a hindrance to delivering high quality software in smaller but more frequent updates and features.

That's where Agile come in. Agile software development is about being able to respond to change in a rapid manner. It teaches us to think about software in a less monolithic manner but instead as a group of features that can be delivered in small chunks frequently over time.

I wrote a post several months ago called Software Craftsmanship: Project Workflow. If you're new to agile it's a good introduction to the anatomy of a project and what I've found useful. While the project workflow I've outlined isn't something you'll see in official Agile books, it is something that I have found extremely useful.

Being a good software developer means understanding how to use Lean


The concept of Lean Manufacturing was invented at Toyota. The primary goal was to reduce waste in the manufacturing cycle. This was done by re-thinking the manufacturing process to identify and remove waste. On example of waste could is parts sitting in a queue waiting to be processed. Toyota was able to show that by re-engineering their manufacturing process they could improve quality, efficiency, and overall satisfaction of customers.

The concepts behind Lean Manufacturing can also be applied to software development. Unfortunately these concepts often are applied incorrectly and have lead to many misconceptions and misunderstandings of Lean Software development. I wrote a post several months ago which outlined common misunderstandings in applying Lean to software development

As a professional software developer it's important to understand Lean and how to apply it to developing software.

Being a good software developer means understanding how to make trade-offs 


The last area I want to briefly cover is understanding how to make trade-offs. As a professional software developer you're going to be asked to make trade-offs all the time. Sometimes it will come in the form of quality (a bad trade-off IMO). Other times it will come in terms of features.

The key to understanding how to make trade-offs is learning to ask a few questions.

  • What am I gaining by making this trade-off?
  • What do I not get that I would gotten if the trade-off was not made?
  • What downstream affects will this decision have on my long term strategy or road map?
  • What additional work will be required later as a result of this trade-off?
The ultimate goal in software development is to provide business value in every part of the process. Understanding how to make trade-offs will help you provide the right business value at each step in the process.

Monday, November 10, 2014

Transitioning to a professional software development role: part 2

In my previous post, Transitioning to a professional software development role: part 1, I started to outline some of the gaps I've seen in people's preparation for entering a career in the software development industry. I started off by focusing on what software development is not about.

In this post I want to take a look at what software development IS about.

Being a good software developer is about understanding data structures


The foundation of a good software developer is understanding data structures and object oriented programming. Data structures like Binary TreesHash Tables, Arrays, and Linked Lists are core to writing software that is functional, scalable, and efficient.

It's not just good enough to understand what the data structures are and how they're used. It's crucial that you also understand WHEN to use them. Understanding when to use particular data structures properly comes with a few benefits. First, it helps others intuitively understand your code. Others will be able to understand your frame of reference better. Second, it helps you avoid "having a hammer and making everything a nail" syndrome. That's when you're learning something new and looking for places to apply your new knowledge, often shoehorning it in to places it doesn't belong.

Being a good software developer is about being able to estimate your work


I can't stress enough how important this is. Your team, your managers, and your customers are going to rely on you for consistency. They're going to make plans around what you do. And because of this learning to estimate your work is crucial in helping you and them meet commitments. Understanding how to estimate your software well also helps you build a regular cadence in what you deliver which is helpful for your customers.

There are a three concepts that I've found that really helped me learn to estimate my work well.  The first is the Cone of Uncertainty. This concept is really helpful because it helps you tease out what you know you don't know as well as what you don't know you don't know. Understanding the cone of uncertainty helps you remove ambiguity in what you're working on which in turn helps you better understand the level of effort it will take.

Once you've teased out the uncertainty in your work you can use Planning Poker as a way to quantify how much work something is. It's important that you try not to tie your poker points to a time scale as it will tend to skew your pointing exercise. Instead, as you get better about learning to quantify how much work something is relative to your other work you'll start to naturally see how much time it takes. For instance let's say you use fibonacci numbers 1, 2, 3, 5, 8, and 13 to quantify you're work. Over time as you get better at pointing your work, you'll also see a trend in how much time certain points take. Only then can you accurately associate a timescale with your pointing.

The last concept that I've found very helpful in learning to estimate how much work I can do in any given period is by tracking my velocity. If you're using planning poker to determine how big the chunks of work are and you're using agile to set a cadence or rhythm for when you deliver your work, then velocity tracking can help you be more predictable in how much work you can deliver in any given agile sprint. Understanding your velocity helps you to set reasonable expectations on what you can deliver and helps those that are planning for the future understand what it would take to decrease the time of a project or make sure that a project is on track and will meet it's deliverable dates.

Being a good software developer is about re-use in order to avoid re-inventing the wheel


As newer engineers we want to solve problems that we find interesting and a challenge. Often as we get into the depths of a particular problem space it will be evident that you're trying to solve an already solved problem. At this point you're at a cross roads where you can continue down the path of solving the problem yourself and re-invent the wheel. Often this is the result of both curiosity and mistrust. You're curious about how to solve a particular problem or curious about whether you could solve the problem better than those that have come before you. This also happens when we don't trust that a particular library actually solves the problem you're trying to solve. Or because another solution solves a slightly different, but compatible problem, we don't trust that our problem is in the same problem space.

This is very detrimental to a project for a few reasons. First, the problem has already been solved so you're going to waste time solving an already solved problem. Second, it's likely the case that the problem is more nuanced than you're aware of. It's also likely the case that the people who have already solved the problem have dedicated themselves to solving that problem. I.e. it's the entirety of their problem domain. This means that they're going to be the subject matter experts in this area. Because this is only one part of your overall problem you won't be able to dedicate the required amount of time solving the problem as well.

I would encourage you to first look to see if someone has already solved your problem either in part or in whole. There's plenty of high quality open source projects on GitHub and SourceForge. These projects have people who are eager for you to use and incorporate their projects into your project.

Being a good software developer is about knowing the limits of your understanding


There are several aspects to understanding the limits of your understanding. One aspect is to know that knowledge about any particular domain has both a breadth and a depth to it. It is impossible to gain both a breadth and depth of understanding in all areas of software development amongst all subject domains. Because if this it's important to be aware of what you have a breadth of understanding in but are lacking depth and what you have a depth of understanding in but don't have a breadth of understanding. Over time you'll develop both a depth and a breadth of understanding in a few particular subject areas. But it's important to know that this takes time, theory, and practice. Without all three of those you won't gain the breadth and the depth.

Knowing the limits of your understanding also involves being able to say you were wrong. There are going to be plenty of times when you thought you had a depth of understanding or breadth of understanding of something only to find out you didn't fully understand or misunderstood the subject. Being able to say you were wrong is the first step to correcting your understanding and being able to build on your new knowledge.





Monday, April 21, 2014

Coding Standards Revisited: Tips For More Readable Code

In my previous post, Coding Standards Revisited: My Language Agnostic Coding Standards, I talked about some non-traditional language agnostic coding standards that I believe apply to all code on all (modern) frameworks, languages, and platforms. In today's post I want to talk specifically about some standards that can increase (or decrease if ignored) the readability of your code. As I've argued before maintainability is crucial in the craft of software development.

So let's talk about a few readability coding standards that I like to use. When adhered to they greatly increase the readability, and therefore maintainability, of your code.

Meaningful Variable Names

Use meaningful names. x is not meaningful. client is not meaningful. provider is not meaningful. Chose names that are specific to the domain you are in. Chose names that clearly define the value of the variable. For example rowIndex is more meaningful than x.

Shorthand Variable Names

DO NOT use shorthand for variable names. Shorthand assumes that you have a shared context from which the shorthand was generated. It becomes difficult for members of other teams or new team members to read your code if you use shorthand.

Private Variables

DO NOT use _ to denote private variables. The English language doesn't use _'s to start words. So starting variable names with _ causes the brain to do more work in recognizing the pattern. I would strongly suggest casing your private variables the same as function variables and differentiating them using keywords like this or self if your language supports them.

Constants

If there is one place I am willing to break from the language standard for my own standard it's with constants. I usually use all caps for constants whether they're private or public. I've found that even developers that haven't been traditionally exposed to this style can figure it out intuitively pretty quickly.

With that said, if your language does provide a standard for how Constants are defined you should try to first adhere to that already defined standard.

Variable Scope

I make all member variables private. Even variables that may be subject to change from outside influence. Exposing private variables as public or even protected means that the state of your class can change without the class having an opportunity to respond to the state change.  This is often the cause of bugs in the system (hard to find bugs at that).

Define get or set methods for your class if your really have to expose the value of a member variable. Having a set method allows the class to control the change and therefore giving it an opportunity to keep it's internal state consistent.

Some languages provide syntactic sugar for the get/set methods and should be preferred to more explicit get/set methods.

Curly Braces

Use curly braces according to the standards of the language you're writing in. Don't just arbitraily put curly braces on their own line or on the line of the block their defining. Different languages have different standards for curly brace style. In fact, some languages support curly braces but use the convention of not including them except in specific scenarios.

It's better to deal with uncomfortably in looking at curly braces than it is for you to be non-standard. In my experience I've found that it really only takes a week or two to get used to the curly brace style of the language you're using.

Whitespace

There's nothing more annoying then checking in code for a one line change only to notice that the diff shows 500 lines changed. What happened? You, or the person who last touched this file, is using a different standard for whitespace. Nowadays, most IDE's auto-format the code for you. So even if you don't change a line of code the whitespace may change to bring the file into conformance with whatever your IDE preferences have been set at.

Define your use of whitespace such that a standard developer for that language would expect them. If there is no guidance for your language on whitespace choose the use the default for the most common editor or IDE for that language.

Monday, April 14, 2014

Coding Standards Revisited: My Language Agnostic Coding Standards

In my previous post, Coding Standards Revisited: Writing Code That Lasts, I talked about how to approach a code review from a slightly different perspective. Today I'd like to talk about approaching coding standards from a slightly different perspective.

As I mentioned in my previous post I find a lot of value in framework, language, or platform specific coding standards. But I do not believe they tell the whole story. Here's a short list of non-traditional coding standards that I believe apply to all code on all (modern) frameworks, languages, and platforms.

Naming


Use meaningful variable, method, parameter, and class names. DO NOT use shorthand. A person that does not know how to read code should be able to tell you what the variable, method, parameter, or class is doing just from the name.

Separate out your concerns

A method or class should have one reason to change and ONLY one reason to change. If a particular method in that class has more than 10 - 20 lines it's probably doing too much. There are very few exceptions to this. Methods and classes should be distinct features that overlap in functionality as little as possible.

Cohesiveness

Write highly cohesive classes. The methods in a class need to have a lot in common. The methods in a class should act on the same data. The methods in a class should all be related to the data. I.e. an image manipulation class that has code to physically save the image to disk is not cohesive… it's coupled. There should be a class that deals with saving things to disk and a class that deals with image manipulation.

Dependency Management

Dependencies should be added by reference as much as possible and injected into the classes that depend on them. This allows the dependencies to be created at the correct level of abstraction. 

High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

Don't Start By Abstracting

Only abstract as you need too. The first (and I would argue second) implementation of something should come in the form of concrete classes. Only when you run into a scenario where you need to interchange these classes should you then abstract it.

Code Duplication

Follow the Don't Repeat Yourself (DRY) principle. Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Commented Out Code

Don't comment code out and leave it. Delete it as you can always go back to it using source control.

Only Write Enough Code To Satisfy What You Need Now

Don't write a single line of code for something in the future (i.e. I'm gonna need a class that….). Only write code that is actually used right now for what you're doing.  Usually for me, this means starting with a test class. In the case of a UI I usually start by writing static UI Code and then working backwards making the code dynamic as I go and ensuring that each piece of dynamic code as a set of tests associated with it.

Monday, April 7, 2014

Coding Standards Revisited: Writing Code That Lasts

Over the last several weeks I've been writing a series of posts on Software Craftsmanship. While I don't think I'm completely finished with the topic (nor do I ever hope to be) I thought I would take the opportunity to switch gears and talk about coding standards.

Typically when people think about coding standards they may think of Google's Java Style Guide, GNU's C++ Coding ConventionsMSDN's C# Coding Conventions, Apple's Objective-C Conventions, Android's Style Guidelines for Contributors, or so on. There's practical guidance out there for most languages and frameworks. These conventions provide you with several advantages. They will help you write code that other developers in that language or on that platform will recognize and therefore be able to maintain easier. They help you code for compiler optimization or run-time optimization. And they help you navigate some of the trickier elements of the language. What these guides don't generally do is give you a good framework of how to write code that will last.

My Software Craftsmanship series was a good start down this path but now let's dive a little deeper and see if we can't identify some additional practicals tools that you can use to help you design and write code that will last. Ultimately that should be out goal; to write code that lasts. Code that lasts may not be elegant and it may have flaws but ultimately it has proven useful. So useful that it has stuck around. Sometimes you find code that lasts just because others are afraid to touch it for fear that it will break. I would argue that, while that code may have bad style or convention, it has lasted because it did it's most important task well; it did the one thing it was written for and has proven useful for that task.

Traditionally when we evaluate code fitness we look at how well the developer adhere'd to a certain style guideline or how well they adhere to a language or platforms best practices. We often look for places where patterns have emerged in the code and try to optimize our implementation around this pattern. We look for poor memory utilization or inefficiencies in dealing with large data sets. These are are great things that MUST be part of a code review. But these things alone don't tell the full story of whether or not the code will last.

So here are a few tips from me on what I like to also look for during a code review that I think identifies a pattern of code that will last.

What would a standard ______ expect?

Fill in that blank above with whatever framework, language, or platform the code was written for. So often it's the case that we let other framework, language, or platform coding standards creep into unrelated code. A standard developer for that framework, language, or platform should be able to open the code and see style that their familiar with. They should recognize patterns that are specific to that framework, language, or platform. The code should flow in a way that's optimized for the way that framework, language, or platform expects to run the code.

A few ways I often see this brake down are:
  • Adding a dependency on a third party tool that auto-manages code style (like ReSharper)
  • Adding a dependency on a particular IDE (like Eclipse) when the framework, language, or platform is IDE agnostic (like C++ or Java)
  • Not using an IDE built for the framework, language, or platform. I.e. Xcode for iOS or Visual Studio for Microsoft .NET (though I would argue NOT for Mono)
  • Curly braces, tabs, and spaces. Let any Java, C#, or Ruby developer read the others code and you'll hear be able to hear the complaints from down the hall.
  • Programmatically defining UI elements in code when the framework or platform provides built in mechanisms to define such elements.
Often these dependencies are added with good intentions. They're added because the organization wants to increase productivity. Or they're added because the organization believes that conformance to a style is important for the cohesiveness of the code, which it is. Conformance to a style other than what a standard developer of that framework, language, or platform would expect is not cohesive. Cohesiveness should be determined both by how self cohesive it is as well as how cohesive it is within the ecosystem it is built for.

What external dependencies has this code been coupled to? Are they necessary?

Developers become very fond of particular pieces of code or particular third party libraries. We're taught in school and at work that we need to focus on re-use. Often this is misinterpreted to only mean reference other code. But occasionally, or often, it's the case that in order to reuse existing code without adding unnecessary dependencies we need to refactor the code we're referencing into a library or module. This allows us to manage the dependencies of our new code correctly. Often we reference the correct code but add dependencies on other packages or classes that are unnecessary because we fail to refactor the dependencies as their consumption changes.

When this code changes what affect will that have on other non-related code?

This is a smell that you've either got something messed up with your class encapsulation or code organization. You should expect direct consumers of your code to change as your interfaces change. But you should not expect transporters of your code to have to change. One way to test this is to simple change a public method signature and compile. See what will no longer compile. Are all the places you have to change reasonable?

How discoverable are the features of this code? Do I have to read the code to understand what it does?

This one is one of the more subjective items on the list. But I still think they're questions that absolutely must be asked. Your first pass during a code review should be to look at how the code is used. If during this pass you find yourself asking things like "why do you need to pass that?" or "why is this call necessary?" then you're probably looking at code that could use better method naming or is written with the wrong level of encapsulation.