A brief information of writing clean code instead.
Spaghetti code, also known as spaghetti programming, is a term used to describe a programming style or a piece of code that is overly complex, tangled, and difficult to understand or maintain. It typically refers to code that lacks structure, has convoluted control flow, and is often characterized by a dense web of interconnected logic and branching.
-
Unstructured Flow: Spaghetti code lacks a clear and organized structure. It may have excessive branching, loops, and conditional statements that are difficult to follow.
-
Goto Statements: Historically, spaghetti code was often associated with the excessive use of "goto" statements, which allow code execution to jump to arbitrary points in the program. This leads to chaotic control flow.
-
Poor Modularity: Spaghetti code tends to be monolithic, with little or no separation of concerns into functions or modules. This makes it challenging to reuse code and challenging to test.
-
Lack of Documentation: Spaghetti code often lacks meaningful comments and documentation, making it even more challenging to understand.
-
High Complexity: Due to its tangled nature, spaghetti code tends to have high complexity, making it prone to bugs and errors.
-
Maintenance Nightmare: Spaghetti code is challenging to maintain over time. As the codebase grows, making changes or adding new features becomes increasingly risky and error-prone.
-
Debugging Difficulty: Finding and fixing bugs in spaghetti code can be a time-consuming and frustrating process, as changes in one part of the code can unintentionally affect other parts.
-
Refactoring Challenges: Refactoring spaghetti code to make it more structured and maintainable can be a daunting task, often requiring a significant rewrite.
-
Modern Practices: Modern programming languages and best practices discourage the use of "goto" statements and emphasize structured programming, modularity, and clean code principles to avoid spaghetti code.
// Wrong Example
int a = 5; // What is "a" ?
// Correct Example
int numberOfBooks = 10; // So easy to understand what does it represents.
// Bad example
int a = Sum(5, 10); // Sum of 2 integer
// Correct example
int numberOne = 5;
int numberTwo = 10;
int result = Sum(numberOne, numberTwo); // Counting 2 number for specific purpose.
/// <summary>
/// The function for adding new student.
/// </summary>
/// <param name="newStudent">Student, will be added to list of students.</param>
public void AddStudent(Student newStudent)
{
if (newStudent != null)
{
Students.Add(newStudent);
}
else
{
throw new ArgumentNullException(nameof(newStudent));
}
}
if (newStudent != null)
{
Students.Add(newStudent); // Bad Example
}
else
{
throw new ArgumentNullException(nameof(newStudent)); // Correct One
}
List<Student> Students = null;
Students.Add(new Student("Kamil", 15, 9)); // Example will be finished with exception
// Correct example
try
{
Student newStudent = new Student("Kamil", 15, 9);
Students.Add(newStudent);
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
// Bad example
int result1 = CalculateSquare(5);
int result2 = CalculateSquare(10);
// Good example
int result1 = CalculateSquare(5);
int result2 = CalculateSquare(10);
int CalculateSquare(int x) {
return x * x;
}
- Try not to write complex functions.
- Keep functions focused on one thing.
// Code , full of errors and mistakes.
public void CountAndSave(int a, int b, FileStream s)
{
int z = a + b;
byte t = Byte.Parse(z.ToString());
s.Write(t);
Console.WriteLine("Saved!");
}
// Functions which are focused for one job.
public int Count(int numberOne, int numberTwo)
{
// Some Codes here...
}
public void SaveNumber(FileStream stream, int number)
{
// Some Codes again..
}
# Commit your changes with meaningful messages
git commit -m "Add CalculateSquare function"
git commit -m "Fix issue #123: Invalid input handling"
// Bad example (violating SRP)
public class Student {
public void CalculateGPA() { /* ... */ }
public void SaveToDatabase() { /* ... */ }
}
// Good example (adhering to SRP)
public class Student {
public double CalculateGPA() { /* ... */ }
}
public class StudentRepository {
public void SaveToDatabase(Student student) { /* ... */ }
}
Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
// Bad example (violating OCP)
public class Rectangle {
public double Width { get; set; }
public double Height { get; set; }
}
// Extending for a new shape
public class Circle : Rectangle {
public double Radius { get; set; }
}
// Good example (adhering to OCP)
public interface IShape {
double Area();
}
public class Rectangle : IShape {
public double Width { get; set; }
public double Height { get; set; }
public double Area() {
return Width * Height;
}
}
public class Circle : IShape {
public double Radius { get; set; }
public double Area() {
return Math.PI * Math.Pow(Radius, 2);
}
}
Subtypes must be substitutable for their base types without altering the correctness of the program.
// Bad example (violating LSP)
public class Bird {
public virtual void Fly() { /* ... */ }
}
public class Ostrich : Bird {
public override void Fly() {
throw new NotSupportedException("Ostriches can't fly.");
}
}
// Good example (adhering to LSP)
public interface IFlyable {
void Fly();
}
public class Sparrow : IFlyable {
public void Fly() { /* ... */ }
}
public class Ostrich : IFlyable {
public void Fly() {
throw new NotSupportedException("Ostriches can't fly.");
}
}
// Bad example (violating ISP)
public interface IWorker {
void Work();
void Eat();
}
public class Manager : IWorker {
public void Work() { /* ... */ }
public void Eat() { /* ... */ }
}
// Good example (adhering to ISP)
public interface IWorker {
void Work();
}
public interface IEater {
void Eat();
}
public class Manager : IWorker, IEater {
public void Work() { /* ... */ }
public void Eat() { /* ... */ }
}
// Bad example (violating DIP)
public class LightBulb {
public void TurnOn() { /* ... */ }
public void TurnOff() { /* ... */ }
}
public class Switch {
private LightBulb bulb = new LightBulb();
public void Toggle() {
// Direct dependency on LightBulb
if (bulb.IsOn()) {
bulb.TurnOff();
} else {
bulb.TurnOn();
}
}
}
// Good example (adhering to DIP)
public interface ISwitchable {
void TurnOn();
void TurnOff();
}
public class LightBulb : ISwitchable {
public void TurnOn() { /* ... */ }
public void TurnOff() { /* ... */ }
}
public class Switch {
private ISwitchable device;
public Switch(ISwitchable device) {
this.device = device;
}
public void Toggle() {
if (device.IsOn()) {
device.TurnOff();
} else {
device.TurnOn();
}
}
}
This is not that all about writing clean code. You can get more information and tips from anywhere else.
I have got asists of both OpenAi and Forums for writing this article⚡.