Hello there!
Todays post we will be looking at two topics, clean code, and code-smells!
Looking at the articles, “What Is Clean Code? A Guide to Principles and Best Practices” (clean code) and “When and Why Are Smells Introduced?” (code smells), I will be looking at practices that I want to start as well as stop in order to write better, more maintainable code. Let me share with you some of the things I learned from these articles.
What I’m Starting: Writing Small, Single-Responsibility Classes
While reading the article clean code, the Single Responsibility principle, SRP, stood out to me. It states that “every class should have a single, focused purpose.” (Codacy, 2023) this idea reduces complexity, makes testing easier, and improves maintainability. On the other hand, code smells article identifies that Blob Classes or classes handling too many responsibilities usually are created at the start of the project and remain problematic (Verwijs, 2021). It explains, “Classes that are poorly designed tend to be smelly right from the beginning and continue to be so for a long time” (Verwijs, 2021).
With SRP, we can actually be proactive at avoiding Blob Classes and laying down a good foundation for clean and scalable software. We can look at this with a code example. Suppose we are developing an e-commerce application and need to handle customer orders, storing them in a database. In that case, one Blob Class approach can combine these responsibilities into one class, which over time will create a big mess.
Code Smell Example: Blob Class
class OrderManager:
def mark_as_paid(self, order_id):
print(f"Order {order_id} marked as paid.")
def save_to_database(self, order_data):
print("Order saved to the database.")
def generate_invoice(self, order_id):
print(f"Invoice generated for order {order_id}.")
This may be fine for the moment, but as time goes on and we decide to add more features-such as sending notifications or handling refunds-it will inflate the class. This is a violation of SRP and brings about complexity.
Clean Code Example: SRP in Action
Here’s a refactored design using SRP:
class OrderService:
def mark_as_paid(self, order_id):
print(f"Order {order_id} marked as paid.")
class DatabaseService:
def save_order(self, order_data):
print("Order saved to the database.")
class InvoiceService:
def generate_invoice(self, order_id):
print(f"Invoice generated for order {order_id}.")
Each class has a single, well-defined responsibility: managing orders, handling database interactions, or generating invoices. This modular design makes the code easier to maintain and test as the application grows.
What I’m Avoiding: Rushed Changes Before Deadlines
The Code Smells article highlights that most smells, such as Spaghetti Code, are introduced just before a release (Verwijs, 2021). The study found that “89%-98% of code smells were introduced in the month before a major release” (Verwijs, 2021). This aligns with the Clean Code article, which warns against sacrificing clarity for speed: “Quick fixes prioritize short-term wins over long-term stability” (Codacy, 2023).
Using another code example scenario we can look at this issue. Imagine having to implement order processing logic quickly when a release date is getting closer. In the absence of due planning, rushed changes can lead to Spaghetti Code.
Code Smell Example: Spaghetti Code
def process_order(order_id, order_data):
if order_id:
if is_valid(order_data):
if not is_paid(order_id):
mark_as_paid(order_id)
if save_to_database(order_id, order_data):
if generate_invoice(order_id):
print("Order processed successfully.")
else:
print("Invoice generation failed!")
else:
print("Database save failed!")
This is too nested and unclear a structure to read, debug, or extend.
Clean Code Example: Modular Approach
We can avoid Spaghetti Code by breaking the logic into smaller functions:
def process_order(order_id, order_data):
if not is_valid(order_data):
print("Invalid order data.")
return
if is_paid(order_id):
print("Order already paid.")
return
mark_as_paid(order_id)
save_order(order_id, order_data)
generate_order_invoice(order_id)
def save_order(order_id, order_data):
print(f"Saving order {order_id} to database...")
def generate_order_invoice(order_id):
print(f"Generating invoice for order {order_id}...")
This is a modular approach, following the principles of clean code, improve readability, and ease debugging.
In conclusion the few key takeaways are, write small single-responsibility classes early in a project. As well as avoid rushed last-minute changes that often lead to the creation of code smells (Verwijs, 2021). Clean code is not just about how it looks; it’s about creating maintainable, scalable, and error-resistant systems (Codacy, 2023).
References
Codacy. (2023, December 19). What Is Clean Code? A Guide to Principles and Best Practices. Blog.codacy.com. https://blog.codacy.com/what-is-clean-code
Verwijs, C. (2021, December 20). In-Depth: What Scientific Research Has To Say About Technical Debt And Code Smells. Medium; The Liberators. https://medium.com/the-liberators/on-technical-debt-and-code-smells-ae8de66f0f8b