Basic Design Principles in Software Developmemt - thehighestbidder/2143--Object-Oriented-Programming GitHub Wiki

Basic Design Principles in Software Development

Definition:

Basic design principles in software development are fundamental guidelines that help in creating well-structured, maintainable, robust, and understandable software systems. These principles provide a foundation for making design decisions at various levels, from the architecture of the entire system down to the design of individual classes and functions. Adhering to these principles generally leads to higher-quality software that is easier to evolve and less prone to errors.

Explanation:

These principles are not strict rules but rather guiding philosophies that encourage good practices. They often overlap and reinforce each other. Understanding and applying these principles can significantly improve the software development process and the final product. Some of the core basic design principles include (but are not limited to):

  • Modularity: Designing software as a collection of independent and interchangeable modules, each responsible for a specific part of the functionality. This promotes reusability and reduces complexity.
  • Separation of Concerns (SoC): Dividing the software into distinct sections, each addressing a separate concern or responsibility. This makes the system easier to understand, modify, and test.
  • Information Hiding (Encapsulation): Restricting access to the internal details of a module or object, exposing only a well-defined interface. This protects the integrity of the internal state and reduces dependencies.
  • Single Responsibility Principle (SRP): A class should have only one reason to change, meaning it should have only one responsibility. This makes classes more focused and easier to maintain.
  • Open/Closed Principle (OCP): Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means you should be able to add new functionality without altering existing code.
  • "Keep It Simple, Stupid" (KISS): Favoring simplicity in design and implementation. Simple systems are generally easier to understand, build, and maintain.
  • "Don't Repeat Yourself" (DRY): Avoiding duplication of code by abstracting common functionality into reusable components. This reduces redundancy and makes maintenance easier.
  • Principle of Least Astonishment (POLA): Designing the system so that its behavior is as expected by its users (both developers and end-users). This improves usability and reduces confusion.

Analogy:

Think of building with LEGO bricks.

  • Modularity: Each different type of LEGO brick (2x4, 1x2, slope, etc.) is a module with a specific purpose. You can combine them in various ways.
  • Separation of Concerns: You might have one set of bricks for the structure (walls, floors) and another set for decoration (windows, doors).
  • Information Hiding: The internal structure of a complex LEGO piece (like a Technic gear) might be hidden, but you know how to connect it to other pieces.
  • SRP: A brick designed only for being a wheel axle has one responsibility.
  • OCP: You can add new types of LEGO bricks to your collection (extension) without having to change the design or functionality of the existing bricks (modification).
  • KISS: Building a simple tower with basic bricks is easier than a complex structure with many specialized pieces.
  • DRY: Instead of building the same wall structure multiple times, you create it once and then replicate it.
  • POLA: If you connect two standard LEGO bricks, you expect them to stay connected.

Code Examples (Illustrative and Conceptual):

It's often challenging to provide concise code examples that fully demonstrate high-level design principles. However, we can illustrate the intent behind some of them.

1. Separation of Concerns (Python):

class UserDataProcessor:
    def __init__(self, database_connector):
        self.db_connector = database_connector

    def fetch_user(self, user_id):
        return self.db_connector.get_user(user_id)

    def validate_user(self, user_data):
        # Logic to validate user data
        pass

    def format_user_report(self, user_data):
        # Logic to format user data into a report
        pass

# Instead of one monolithic class doing everything, we separate concerns:
class UserDatabase:
    def get_user(self, user_id):
        # Database interaction logic
        return {"id": user_id, "name": "Example User"}

class UserValidator:
    def is_valid(self, user_data):
        # Validation rules
        return True

class UserReportFormatter:
    def format(self, user_data):
        return f"User ID: {user_data['id']}, Name: {user_data['name']}"

# Now, each class has a single responsibility
db = UserDatabase()
validator = UserValidator()
formatter = UserReportFormatter()
processor = UserDataProcessor(db)

user = processor.fetch_user(123)
if validator.is_valid(user):
    report = formatter.format(user)
    print(report)

2. Single Responsibility Principle (Python - illustrating a violation):

class UserSettingsManager:
    def __init__(self, user_id):
        self.user_id = user_id

    def load_settings(self):
        # Load user settings from database
        print(f"Loading settings for user {self.user_id}")

    def save_settings(self, settings):
        # Save user settings to database
        print(f"Saving settings for user {self.user_id}: {settings}")

    def send_notification(self, message):
        # Send a notification to the user
        print(f"Sending notification to user {self.user_id}: {message}")

# This class has more than one reason to change (settings management and notifications)
# It violates SRP. These responsibilities should be separated into different classes.

3. Open/Closed Principle (Conceptual):

Imagine you have a system that calculates the area of different shapes. If you need to add a new shape (e.g., a triangle), adhering to OCP would mean you can add a Triangle class with its own calculate_area() method without modifying the existing code that uses the Shape interface. This might involve using inheritance or interfaces.

Diagram (Conceptual):

+---------------------------+
| Basic Design Principles   |
+---------------------------+
| - Modularity              |
| - Separation of Concerns  |
| - Information Hiding      |
| - Single Responsibility   |
| - Open/Closed             |
| - KISS                    |
| - DRY                     |
| - POLA                    |
+---------------------------+
      ^
      | (Guide and influence)
      |
+---------------------------------+       +-------------------------+
| Software Architecture & Design  |------>| Code Implementation     |
+---------------------------------+       +-------------------------+

Links to External Resources: