Skip to content

Instantly share code, notes, and snippets.

@wojteklu
Last active December 21, 2024 05:21
Show Gist options
  • Save wojteklu/73c6914cc446146b8b533c0988cf8d29 to your computer and use it in GitHub Desktop.
Save wojteklu/73c6914cc446146b8b533c0988cf8d29 to your computer and use it in GitHub Desktop.
Summary of 'Clean code' by Robert C. Martin

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.


General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can be called from the client without the flag.

Comments rules

  1. Always try to explain yourself in code.
  2. Don't be redundant.
  3. Don't add obvious noise.
  4. Don't use closing brace comments.
  5. Don't comment out code. Just remove.
  6. Use as explanation of intent.
  7. Use as clarification of code.
  8. Use as warning of consequences.

Source code structure

  1. Separate concepts vertically.
  2. Related code should appear vertically dense.
  3. Declare variables close to their usage.
  4. Dependent functions should be close.
  5. Similar functions should be close.
  6. Place functions in the downward direction.
  7. Keep lines short.
  8. Don't use horizontal alignment.
  9. Use white space to associate related things and disassociate weakly related.
  10. Don't break indentation.

Objects and data structures

  1. Hide internal structure.
  2. Prefer data structures.
  3. Avoid hybrids structures (half object and half data).
  4. Should be small.
  5. Do one thing.
  6. Small number of instance variables.
  7. Base class should know nothing about their derivatives.
  8. Better to have many functions than to pass some code into a function to select a behavior.
  9. Prefer non-static methods to static methods.

Tests

  1. One assert per test.
  2. Readable.
  3. Fast.
  4. Independent.
  5. Repeatable.

Code smells

  1. Rigidity. The software is difficult to change. A small change causes a cascade of subsequent changes.
  2. Fragility. The software breaks in many places due to a single change.
  3. Immobility. You cannot reuse parts of the code in other projects because of involved risks and high effort.
  4. Needless Complexity.
  5. Needless Repetition.
  6. Opacity. The code is hard to understand.
@brianmcconnel
Copy link

Turns out paying too much attention to the "cleanliness" of your code can have significant drawbacks. Such that it may become indefensible.

https://www.youtube.com/watch?v=tD5NrevFtbU

It seemed like he was looking to prove his point rather than being honest about it. I very rarely need to depart from these principals to make performant code.

@OmarLaham
Copy link

Appreciate your efforts. Very useful.
Thanks

@cgsandford
Copy link

Some testing principles I can't resist noting here - pretty sure I got them from this book:

  • Test interface not implementation
  • All untested code is broken, you just don't know it yet!

Thank you for the summary!

@tharper1977
Copy link

Great page. Tou covered it well.

@madeso
Copy link

madeso commented Apr 29, 2023

Petition to remove "Have no side effects" from "function rules". Side effects in the clean code book referrers to a function doing two or more things but only saying it does one thing. Since functions should only do one thing in the first place this rule is just repeating another rule with a worse wording.

Clean code (the book) actually prefers functions to have side effects (regular meaning now) if you can reduce the number of arguments it takes. This is never stated but it's evident by the clean code sample at the end of that chapter.

@SHAM-BHU123
Copy link

Nice

@luisdatec
Copy link

Thanks. I used it as a reference to improve my codes from now!

However, I will read that book.

@NidusUmbra
Copy link

Hello Excuse me, do you know me? I am sorry.

On Fri, Mar 3, 2023 at 4:22 AM NidusUmbra @.> wrote: @.* commented on this gist. ------------------------------ Turns out paying too much attention to the "cleanliness" of your code can have significant drawbacks. Such that it may become indefensible. https://www.youtube.com/watch?v=tD5NrevFtbU — Reply to this email directly, view it on GitHub https://gist.github.com/73c6914cc446146b8b533c0988cf8d29#gistcomment-4490308 or unsubscribe https://github.com/notifications/unsubscribe-auth/A5BVSDB5VI2O7DGOAIUABFTW2GZ55BFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFQKSXMYLMOVS2I5DSOVS2I3TBNVS3W5DIOJSWCZC7OBQXE5DJMNUXAYLOORPWCY3UNF3GS5DZVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVA2DANZRHAYDQM5HORZGSZ3HMVZKMY3SMVQXIZI . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

No. These reply notifications don't work like one would intuitively think. I did not reply to you nor did I quote you. You get a notif when anyone answers the main thread. Cheers.

@ChrisLuckComes
Copy link

Thanks very much! I'll read that book carefully sometime

@kehiy
Copy link

kehiy commented Jun 21, 2023

very very useful !

@tbrehuescu
Copy link

https://kingadesign.com/clean-code-poster-free-download?fbclid=IwAR2p9y7Rf5gyH586sXYxp2dgoA3kWvRlLO5jfgeHlj77k1Y94qM1grjdW84

Hi, the link is not working. I got: Something went wrong!
Page not found.
. Thanks!

@tbrehuescu
Copy link

@JahanzaibIlyas
Copy link

So helpful

@marcegarba
Copy link

Thank you!!!

@Unbreak4ble
Copy link

I would like to contribute to this amazing Clean Code hints by one that I noticed it's possible to be done and nobody talks about...

Conditional Simplification

You can always turn a complex conditional into a simpler one through the Propositional Logic rules
Screen Shot 2021-11-16 at 21 27 24

  • References
  1. De Morgan
  2. Tautology
  3. Propositional Logic

Inspired by Robert C Marin's book: Clean Code

Or you could just paste an "obfuscated" ((a && b) || (b &&c) || (!a && !c)) version of your condition into https://www.wolframalpha.com/ and let it do the work. (Minimal forms)

That's work. But if "setting" is null when hideOnGrid is false, it's generate exception.

@jomisacu
Copy link

I would like to contribute to this amazing Clean Code hints by one that I noticed it's possible to be done and nobody talks about...

Conditional Simplification

You can always turn a complex conditional into a simpler one through the Propositional Logic rules
Screen Shot 2021-11-16 at 21 27 24

  • References
  1. De Morgan
  2. Tautology
  3. Propositional Logic

Inspired by Robert C Marin's book: Clean Code

Or you could just paste an "obfuscated" ((a && b) || (b &&c) || (!a && !c)) version of your condition into https://www.wolframalpha.com/ and let it do the work. (Minimal forms)

That's work. But if "setting" is null when hideOnGrid is false, it's generate exception.

You could define additional vars to add semantic. Ex.

const mustHideOnGridByColumn = column.hideOnGrid;
const mustHideOnGridBySetting = setting && setting.hide_on_grid;

return !(mustHideOnGridByColumn || mustHideOnGridBySetting);
 // or: return !mustHideOnGridByColumn && !mustHideOnGridBySetting

This way is very clean and improves readability

@jhoeljp
Copy link

jhoeljp commented Aug 8, 2023

Very helpful!

However heres a video challenging the efficacy of 5 design rules of clean code: https://youtu.be/tD5NrevFtbU

@JohannesJacop
Copy link

I am not a programmer myself. So, I haven't read the book myself (although I knew about it for sure 😉) and I read the summary here now for the first time—and I just realized, the recommendations actually apply to quite a lot of other things as well!

So, for all non-engineers, it's worth the read! 💡 Thanks for sharing. 👍

@pedroluiznogueira
Copy link

I would like to contribute to this amazing Clean Code hints by one that I noticed it's possible to be done and nobody talks about...

Conditional Simplification

You can always turn a complex conditional into a simpler one through the Propositional Logic rules
Screen Shot 2021-11-16 at 21 27 24

  • References
  1. De Morgan
  2. Tautology
  3. Propositional Logic

Inspired by Robert C Marin's book: Clean Code

Or you could just paste an "obfuscated" ((a && b) || (b &&c) || (!a && !c)) version of your condition into https://www.wolframalpha.com/ and let it do the work. (Minimal forms)

That's work. But if "setting" is null when hideOnGrid is false, it's generate exception.

You could define additional vars to add semantic. Ex.

const mustHideOnGridByColumn = column.hideOnGrid;
const mustHideOnGridBySetting = setting && setting.hide_on_grid;

return !(mustHideOnGridByColumn || mustHideOnGridBySetting);
 // or: return !mustHideOnGridByColumn && !mustHideOnGridBySetting

This way is very clean and improves readability

This is by far one of the best things I’ve started doing for a while.

Usually boolean conditions are a representation of a behavior, meaningful names will always help your code read like a story.

That way just by reading the variable name you get the problem statement.

For example:

if (isReadyToReceiveMessage) {…}

Of course one should be careful to not create misleading variables that don’t mean what the condition represent. (tests help with that semantics).

@Victorcorcos
Copy link

Victorcorcos commented Sep 12, 2023

@Victorcorcos if setting is null or undefined the old code is working but not the new code, or am I missing something ?

The new code will work, because this is applied:

  1. Avoid NPE on q by using || {}
  • Before
setting = fieldSettings[column.foreignAttribute] || fieldSettings[column.description]
  • After
setting = fieldSettings[column.foreignAttribute] || fieldSettings[column.description] || {}

So, in case setting is null/undefined, it will be {}, which won't cause NPE.

→ We can't see that on the picture, but that || {} was the change on that specific line

@SpringfieldC
Copy link

Interesting

@M1SHANIA
Copy link

Can I download this book somewhere for free? TY<3

@philipvella
Copy link

thanks for this @wojteklu 👍

@Dariushdragon
Copy link

it helps a lot for me thank you.

@hassan-mohagheghian
Copy link

sounds great, thank you!

@arkadiusjonczek
Copy link

❤️

@jjsutil
Copy link

jjsutil commented May 4, 2024

Thanks for this notes!

@fosterushka
Copy link

Would be helpful if someone will add code example refactored as above one.

@realgio95
Copy link

Adding Some Code examples in C# with ChatGPT

Code Examples with GPT4o

Certainly! Here are C# code examples illustrating the principles and rules described:

General rules

  1. Follow standard conventions
// Correct
public class OrderService
{
    private readonly IOrderRepository _orderRepository;

    public OrderService(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public void PlaceOrder(Order order)
    {
        _orderRepository.Add(order);
    }
}

// Incorrect
public class orderservice
{
    private IOrderRepository orderrepository;

    public orderservice(IOrderRepository orderrepository)
    {
        this.orderrepository = orderrepository;
    }

    public void placeorder(Order order)
    {
        orderrepository.add(order);
    }
}
  1. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible
// Simple and clear
public double CalculateArea(double radius)
{
    return Math.PI * radius * radius;
}

// Overly complex
public double CalculateArea(double radius)
{
    double area = 0;
    for (int i = 0; i < 360; i++)
    {
        area += (Math.PI / 180) * radius * radius;
    }
    return area;
}
  1. Boy scout rule. Leave the campground cleaner than you found it
// Clean up resources
public void ProcessData()
{
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        // Perform data operations
    } // Connection is automatically closed here
}
  1. Always find root cause. Always look for the root cause of a problem
// Logging the exception and identifying the root cause
public void ProcessOrder(Order order)
{
    try
    {
        // Process the order
    }
    catch (Exception ex)
    {
        Log.Error("Error processing order: " + ex.Message);
        throw;
    }
}

Design rules

  1. Keep configurable data at high levels
// Configurable data at high level
public class Config
{
    public string DatabaseConnectionString { get; set; }
}

public class DataService
{
    private readonly string _connectionString;

    public DataService(Config config)
    {
        _connectionString = config.DatabaseConnectionString;
    }

    // ...
}
  1. Prefer polymorphism to if/else or switch/case
// Using polymorphism
public abstract class Notification
{
    public abstract void Send();
}

public class EmailNotification : Notification
{
    public override void Send()
    {
        // Send email
    }
}

public class SmsNotification : Notification
{
    public override void Send()
    {
        // Send SMS
    }
}

// Instead of
public void SendNotification(string type)
{
    if (type == "Email")
    {
        // Send email
    }
    else if (type == "SMS")
    {
        // Send SMS
    }
}
  1. Separate multi-threading code
// Using Task for multi-threading
public async Task ProcessDataAsync()
{
    await Task.Run(() => 
    {
        // Perform CPU-bound operations
    });
}
  1. Prevent over-configurability
// Simple configuration
public class AppSettings
{
    public string DatabaseConnectionString { get; set; }
}
  1. Use dependency injection
// Using dependency injection
public class OrderService
{
    private readonly IOrderRepository _orderRepository;

    public OrderService(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    // ...
}
  1. Follow Law of Demeter. A class should know only its direct dependencies
// Following Law of Demeter
public class OrderProcessor
{
    private readonly OrderService _orderService;

    public OrderProcessor(OrderService orderService)
    {
        _orderService = orderService;
    }

    public void Process(Order order)
    {
        _orderService.PlaceOrder(order);
    }
}

Understandability tips

  1. Be consistent
// Consistent naming
public class UserService
{
    public User GetUserById(int id)
    {
        // ...
    }

    public User GetUserByEmail(string email)
    {
        // ...
    }
}
  1. Use explanatory variables
// Using explanatory variables
var fileName = "data.txt";
var fileContent = File.ReadAllText(fileName);
  1. Encapsulate boundary conditions
// Encapsulating boundary conditions
public class DateRange
{
    public DateTime Start { get; }
    public DateTime End { get; }

    public DateRange(DateTime start, DateTime end)
    {
        if (start > end)
            throw new ArgumentException("Start date must be earlier than end date");

        Start = start;
        End = end;
    }
}
  1. Prefer dedicated value objects to primitive type
// Using value objects
public class Email
{
    public string Address { get; }

    public Email(string address)
    {
        if (string.IsNullOrEmpty(address))
            throw new ArgumentException("Email address cannot be empty");

        Address = address;
    }
}
  1. Avoid logical dependency
// Avoiding logical dependency
public class User
{
    public string Name { get; set; }
    public bool IsActive { get; set; }

    public void Activate()
    {
        IsActive = true;
    }
}
  1. Avoid negative conditionals
// Avoiding negative conditionals
if (IsUserActive)
{
    // Do something
}

// Instead of
if (!IsUserInactive)
{
    // Do something
}

Names rules

  1. Choose descriptive and unambiguous names
// Descriptive names
public class InvoiceService
{
    public void CreateInvoice(Order order)
    {
        // ...
    }
}
  1. Make meaningful distinction
// Meaningful distinction
public class Order
{
    public DateTime OrderDate { get; set; }
}

public class Shipment
{
    public DateTime ShipmentDate { get; set; }
}
  1. Use pronounceable names
// Pronounceable names
public class CustomerService
{
    public void AddCustomer(Customer customer)
    {
        // ...
    }
}
  1. Use searchable names
// Searchable names
public const int MaxUsers = 100;
  1. Replace magic numbers with named constants
// Using named constants
public const int DefaultTimeout = 30;

public void Connect()
{
    // Using named constant
    var timeout = DefaultTimeout;
}
  1. Avoid encodings
// Avoiding encodings
public class UserService
{
    public void CreateUser(string name)
    {
        // ...
    }
}

Functions rules

  1. Small
// Small function
public void SaveUser(User user)
{
    ValidateUser(user);
    _userRepository.Save(user);
}
  1. Do one thing
// Single responsibility
public void ValidateUser(User user)
{
    if (string.IsNullOrEmpty(user.Name))
        throw new ArgumentException("User name cannot be empty");
}
  1. Use descriptive names
// Descriptive names
public void SendEmailConfirmation(User user)
{
    // ...
}
  1. Prefer fewer arguments
// Fewer arguments
public void CreateOrder(int userId, int productId)
{
    // ...
}
  1. Have no side effects
// No side effects
public int CalculateSum(int a, int b)
{
    return a + b;
}
  1. Don't use flag arguments
// Separate methods
public void EnableFeature()
{
    // ...
}

public void DisableFeature()
{
    // ...
}

Comments rules

  1. Always try to explain yourself in code
// Self-explanatory code
public void CalculateTotalPrice()
{
    var totalPrice = items.Sum(item => item.Price * item.Quantity);
}
  1. Don't be redundant
// Redundant comment
// Adds two numbers
public int Add(int a, int b)
{
    return a + b;
}
  1. Don't add obvious noise
// Obvious noise
public int Multiply(int a, int b)
{
    return a * b; // Multiply a and b
}
  1. Don't use closing brace comments
// No closing brace comments
public void ProcessOrder()
{
    // ...
}
  1. Don't comment out code. Just remove
// Remove commented code
// public void OldMethod()
// {
//     // ...
// }
  1. Use as explanation of intent
// Explanation of intent
public void SaveData()
{
    // Save data to ensure it is not lost
    _dataRepository.Save();
}
  1. Use as clarification of code
// Clarification of code
public void CalculateDiscount()
{
    // Apply 10% discount to all items
    foreach (var item in items)
    {
        item.Price *= 0.9;
    }
}
  1. Use as warning of consequences
```csharp
// Warning of consequences
public void DeleteUser(int userId)
{
    // Warning: This action is irreversible
    _userRepository.Delete(userId);
}

Source code structure

  1. Separate concepts vertically
// Vertical separation
public class UserService
{
    // Constructor
    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    // Public methods
    public void CreateUser(User user)
    {
        // ...
    }

    // Private methods
    private void ValidateUser(User user)
    {
        // ...
    }
}
  1. Related code should appear vertically dense
// Related code close together
public class OrderService
{
    public void CreateOrder(Order order)
    {
        ValidateOrder(order);
        SaveOrder(order);
    }

    private void ValidateOrder(Order order)
    {
        // ...
    }

    private void SaveOrder(Order order)
    {
        // ...
    }
}
  1. Declare variables close to their usage
public void ProcessOrder(Order order)
{
    var orderTotal = CalculateTotal(order); // Variable declared close to usage
    // ...
}
  1. Dependent functions should be close
public class OrderService
{
    public void CreateOrder(Order order)
    {
        var total = CalculateTotal(order);
        SaveOrder(order, total);
    }

    private decimal CalculateTotal(Order order)
    {
        // ...
    }

    private void SaveOrder(Order order, decimal total)
    {
        // ...
    }
}
  1. Similar functions should be close
public class UserService
{
    public User GetUserById(int id)
    {
        // ...
    }

    public User GetUserByEmail(string email)
    {
        // ...
    }
}
  1. Place functions in the downward direction
public class OrderService
{
    public void ProcessOrder(Order order)
    {
        ValidateOrder(order);
        SaveOrder(order);
    }

    private void ValidateOrder(Order order)
    {
        // ...
    }

    private void SaveOrder(Order order)
    {
        // ...
    }
}
  1. Keep lines short
// Short lines
public void DisplayUserInfo(User user)
{
    Console.WriteLine($"Name: {user.Name}, Email: {user.Email}");
}
  1. Don't use horizontal alignment
// No horizontal alignment
public int MaxUsers    { get; set; }
public string Database { get; set; }
  1. Use white space to associate related things and disassociate weakly related
// Using white space
public class UserService
{
    public void CreateUser(User user)
    {
        ValidateUser(user);
        _userRepository.Save(user);
    }

    private void ValidateUser(User user)
    {
        if (string.IsNullOrEmpty(user.Name))
            throw new ArgumentException("Name is required");
    }
}
  1. Don't break indentation
// Correct indentation
public void ProcessData()
{
    if (data.IsValid)
    {
        SaveData(data);
    }
}

Objects and data structures

  1. Hide internal structure
// Encapsulation
public class Order
{
    private List<OrderItem> _items;

    public void AddItem(OrderItem item)
    {
        _items.Add(item);
    }

    public decimal GetTotal()
    {
        return _items.Sum(i => i.Price * i.Quantity);
    }
}
  1. Prefer data structures
// Data structure
public class Point
{
    public int X { get; set; }
    public int Y { get; set; }
}
  1. Avoid hybrids structures (half object and half data)
// Avoid hybrids
public class User
{
    private string passwordHash;

    public string Name { get; set; }

    public void SetPassword(string password)
    {
        passwordHash = Hash(password);
    }

    private string Hash(string input)
    {
        // Hashing logic
    }
}
  1. Should be small
// Small class
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}
  1. Do one thing
// Single responsibility
public class EmailValidator
{
    public bool IsValid(string email)
    {
        // Validation logic
    }
}
  1. Small number of instance variables
// Few instance variables
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
  1. Base class should know nothing about their derivatives
// Proper inheritance
public abstract class Animal
{
    public abstract void MakeSound();
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Bark");
    }
}
  1. Better to have many functions than to pass some code into a function to select a behavior
// Many functions
public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Subtract(int a, int b)
    {
        return a - b;
    }
}
  1. Prefer non-static methods to static methods
// Non-static method
public class Logger
{
    public void Log(string message)
    {
        // Log message
    }
}

Tests

  1. One assert per test
[Test]
public void TestAddition()
{
    var calculator = new Calculator();
    var result = calculator.Add(2, 3);
    Assert.AreEqual(5, result);
}
  1. Readable
// Readable test
[Test]
public void ShouldReturnTrueForValidEmail()
{
    var emailValidator = new EmailValidator();
    var isValid = emailValidator.IsValid("test@example.com");
    Assert.IsTrue(isValid);
}
  1. Fast
// Fast test
[Test]
public void ShouldProcessOrderQuickly()
{
    var orderProcessor = new OrderProcessor();
    var stopwatch = Stopwatch.StartNew();
    orderProcessor.Process(order);
    stopwatch.Stop();
    Assert.Less(stopwatch.ElapsedMilliseconds, 1000);
}
  1. Independent
// Independent test
[Test]
public void ShouldSaveUser()
{
    var userRepository = new UserRepository();
    var userService = new UserService(userRepository);
    var user = new User { Name = "John Doe" };
    
    userService.SaveUser(user);

    var savedUser = userRepository.GetUserByName("John Doe");
    Assert.AreEqual(user.Name, savedUser.Name);
}
  1. Repeatable
// Repeatable test
[Test]
public void ShouldCalculateTotalPrice()
{
    var cart = new ShoppingCart();
    cart.AddItem(new Product { Price = 10, Quantity = 2 });
    cart.AddItem(new Product { Price = 5, Quantity = 3 });

    var totalPrice = cart.CalculateTotalPrice();

    Assert.AreEqual(35, totalPrice);
}

Code smells

  1. Rigidity
// Rigid code example
public class OrderProcessor
{
    public void ProcessOnlineOrder(OnlineOrder order)
    {
        // ...
    }

    public void ProcessInStoreOrder(InStoreOrder order)
    {
        // ...
    }
}
  1. Fragility
// Fragile code example
public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class UserService
{
    private readonly List<User> _users;

    public void UpdateUserEmail(string name, string newEmail)
    {
        var user = _users.FirstOrDefault(u => u.Name == name);
        if (user != null)
        {
            user.Email = newEmail;
        }
    }
}
  1. Immobility
// Immobile code example
public class ReportGenerator
{
    private readonly Database _database;

    public ReportGenerator(Database database)
    {
        _database = database;
    }

    public void GenerateReport()
    {
        var data = _database.GetData();
        // Generate report using data
    }
}
  1. Needless Complexity
// Needless complexity
public class ComplexCalculator
{
    public int Calculate(int a, int b, string operation)
    {
        if (operation == "add")
        {
            return a + b;
        }
        else if (operation == "subtract")
        {
            return a - b;
        }
        else if (operation == "multiply")
        {
            return a * b;
        }
        else if (operation == "divide")
        {
            return a / b;
        }
        else
        {
            throw new InvalidOperationException("Unknown operation");
        }
    }
}
  1. Needless Repetition
// Needless repetition
public class UserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public void CreateUser(User user)
    {
        if (string.IsNullOrEmpty(user.Name))
            throw new ArgumentException("Name ```csharp
            throw new ArgumentException("Name is required");

        if (string.IsNullOrEmpty(user.Email))
            throw new ArgumentException("Email is required");

        _userRepository.Save(user);
    }
}
  1. Opacity
// Opaque code example
public class InvoiceService
{
    public void ProcessInvoice(Invoice invoice)
    {
        if (invoice != null)
        {
            if (invoice.Amount > 0)
            {
                if (invoice.Status == "Pending")
                {
                    // Process the invoice
                }
            }
        }
    }
}

By applying these principles and rules in your C# code, you can enhance readability, maintainability, and overall code quality.

@zleypner
Copy link

Thank you! Very useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment