Practical Code Refactoring, Part 1 – What is Good Code?

Share this article

Refactoring is about re-thinking your code, everything in it, for the sake of making your code better. In this series on code refactoring, I’ll show you the Why, When, What, Where, and How of refactoring since refactoring is more of an art more than a science. In this part I’ll explain what makes code good, the basis which I build upon later through the rest of the series.

What is Good Code?

The main goal of refactoring is clean code, better code, or whatever you might call it. But what actually constitutes good code? Good code is smelled and tasted. If you’ve written a lot of code, you understand what I mean; you can easily identify whether code is good or bad with experience. But what if you are new to coding but still want to do things right? We can summarize the aspects of good code with these three guidelines:
  • Readable
  • Extensible
  • Efficient

Readability

When your code follows some standard well-known syntax, style, and documentation practices, or in other words when you and your development colleagues can easily interpret the code with minimal ambiguity, your code is said to be readable and consequently maintainable in terms of style and appearance. To achieve this, you should follow a coding standard. You may use some public standard or create your own if you like, but whichever you choose, your colleagues should find your syntax, style, code documentation, and comments straight forward, clear, and require no further explanation as much as possible. I prefer using a public standard since it can shorten the learning curve for new people joining my development team later. Readability and extensibility overlap when you use basic constructs of your programming languages for what they were intended as much as possible, and for solving well-known problems you use well-known patterns (design patterns). But what if you have a new problem? Or what if you’ve just crafted a better solution for an old problem? Terrific! Other programmers won’t be able to understand your new billion dollar solution if you don’t document it properly! Keep your mind working at its best and flying as high as you like, but remember to take the time to describe inside your code how and why you made it.

Extensibility

Both readability and extensibility contribute to the maintainability of your code and overlap at certain times. But to sharpen the difference, readable code is maintainable in terms of its style and extensible code is maintainable in terms of its logic. The same argument applies to design patterns since they contribute to both readability and extensibility. Your code is extensible when it follows some re-usable, logical, well-known patterns, be it defined standard design patterns or normal logical flow. For example, some developers favor using the Singleton design pattern for working with database connections. As another example, most of us would use a standard foreach to iterate over an array, which is a standard flow. One might use a for loop or even a while loop under similar circumstances, but this is fairly uncommon in PHP so it should be documented why such constructs were necessary foreach to avoid confusion. The major aspects of extensibility are decoupling and encapsulation. Decoupling means that your code (mainly functions/methods and classes) shouldn’t depend or overlap each other; code should be as “pure” as possible, with any overlapping functionality and other non-related entities removed. If you are writing procedural code, your functions should only contain the logic that their names imply; don’t make functions do too much! Use a “toolbox” approach when writing code – small basic routines work together to build big complicated systems. Encapsulation is an integral part of decoupling. Whenever you decouple components, you have already done some encapsulation. To encapsulate components, continue separating its internals from the global scope and make all interactions with it occur at its interface level. This is a modular approach which makes it easier to later remove or update any part of your system as opposed to a monolithic design which makes your code spaghetti.

Efficiency

You should keep efficiency in mind from the very first line of code in any project since bottlenecks are known to come from some very unwise usage of language constructs, for example nesting several loops and using recursion unwisely, and from some unwise usage of logical patterns, for example not making use of caching and sending/receiving data to/from streams without proper buffering. Efficiency is important, but don’t compromise the first two rules for the sake of it. In fact, compromising readability and extensibility can actually result in less efficiency! For the majority of cases, efficiency is directly proportional to applying the first two rules. When there is an exceptional situation, do your best to make sure you have other ways of keeping your code good.

Summary

In this article I introduced you to what makes code good. I limited the discussion to three major aspects: readability, extensibility, and efficiency, and described what each means. Now that you know what constitutes good code, we can move on to the next parts in the series. In part 2 I’ll show you some things to be on the look out for when refactoring for better readability. Image via Fotolia

Frequently Asked Questions (FAQs) about Practical Refactoring and Maintainable Code

What is the importance of writing maintainable code?

Writing maintainable code is crucial for long-term project success. It ensures that the code is easy to read, understand, and modify, which is particularly important when working in a team or when the codebase needs to be updated or expanded in the future. Maintainable code reduces the time and effort required for debugging and adding new features, leading to more efficient and cost-effective software development.

How can I make my code more logical and maintainable?

There are several strategies to make your code more logical and maintainable. Firstly, use clear and descriptive names for variables, functions, and classes. Secondly, keep your code DRY (Don’t Repeat Yourself) by reusing code through functions or classes. Thirdly, write comments to explain complex parts of your code. Lastly, follow established coding standards and conventions for your programming language.

What is refactoring and why is it important?

Refactoring is the process of restructuring existing code without changing its external behavior. It’s important because it improves the design of the software, makes it easier to understand, and helps find and fix bugs. Refactoring also helps you prepare for future changes, making the code more flexible and adaptable.

How can I refactor my code effectively?

Effective refactoring requires a careful and systematic approach. Start by identifying areas of your code that are difficult to understand or change. Then, make small, incremental changes, testing your code after each change to ensure it still works as expected. Use refactoring tools provided by your IDE to automate some of the process.

What are some common code smells that indicate my code needs refactoring?

Code smells are indicators that your code might need refactoring. Some common code smells include long methods, large classes, duplicate code, and too many parameters. If you notice these in your code, it’s a good sign that you should consider refactoring.

How can I ensure my refactored code is still correct?

To ensure your refactored code is still correct, you should have a good set of tests that you can run before and after refactoring. The tests should pass both before and after refactoring. If they don’t, it means that the refactoring has changed the behavior of the code, and you need to investigate further.

What is the role of testing in refactoring?

Testing plays a crucial role in refactoring. It provides a safety net that allows you to make changes to your code with confidence. By running your tests after each refactoring step, you can ensure that your changes haven’t broken any existing functionality.

Can refactoring improve the performance of my code?

Yes, refactoring can improve the performance of your code. By simplifying complex code structures, eliminating unnecessary operations, and optimizing algorithms, you can make your code run faster and use less memory.

What are the risks of refactoring and how can I mitigate them?

The main risk of refactoring is introducing bugs into your code. You can mitigate this risk by refactoring in small steps, testing your code after each step, and using version control to track your changes and revert back if necessary.

How can I learn more about refactoring and writing maintainable code?

There are many resources available to learn more about refactoring and writing maintainable code. You can read books on the subject, take online courses, or follow tutorials and guides. Participating in code reviews and pair programming sessions can also be a great way to learn from more experienced developers.

Abdullah AbouzekryAbdullah Abouzekry
View Author

Abdullah Abouzekry is an experienced web-developer with over 7 years developing PHP/MySQL applications ranging from simple web sites to extensive web-based business applications. Although his main experience is with PHP/MySQL and related web technologies, he has developed and localized many desktop applications in C#, Python/Qt, Java, and C++. When not writing code, Abdullah likes to read, listen to oriental music, and have fun with his little family.

AdvancedRefactoring
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week