Software Design Principles
Software design is a fundamental process in developing scalable, maintainable, and efficient applications. To achieve this, various principles have been established to help developers create high-quality software. Below, we will explore some of the most important principles along with a practical example in Python.
Fundamental Principles
1.Single Responsibility Principle (SRP)
Each class or module should have a single reason to change. This means a class should focus on one functionality.
2. Open/Closed Principle (OCP)
Software should be open for extension but closed for modification. New functionalities should be added without changing existing code.
3. Liskov Substitution Principle (LSP)
Subclass objects should be replaceable with superclass objects without altering program functionality.
4. Interface Segregation Principle (ISP)
No client should be forced to depend on interfaces it does not use. Large interfaces should be divided into smaller, more specific ones.
5. Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules but on abstractions. This enhances software maintainability and scalability.
Example in Python
Let's imagine a notification system that follows the Dependency Inversion Principle (DIP). Instead of having a service depend directly on a specific implementation (such as email or SMS notifications), we use an abstraction to make the system flexible and easy to extend.
from abc import ABC, abstractmethod
# Interface for different types of notifications
class Notifier(ABC):
@abstractmethod
def send(self, message: str):
pass
# Notifier implementation for email
class EmailNotifier(Notifier):
def send(self, message: str):
print(f"Sending email: {message}")
# Notifier implementation for SMS
class SMSNotifier(Notifier):
def send(self, message: str):
print(f"Sending SMS: {message}")
# Class using abstraction, avoiding direct dependency on a specific implementation
class NotificationService:
def __init__(self, notifier: Notifier):
self.notifier = notifier
def notify_user(self, message: str):
self.notifier.send(message)
# Using the system
email_notifier = EmailNotifier()
service = NotificationService(email_notifier)
service.notify_user("Your order has been shipped.")
sms_notifier = SMSNotifier()
service_sms = NotificationService(sms_notifier)
service_sms.notify_user("Your verification code is 1234.")
Explanation of the Example
We define an interface (Notifier) with an abstract send() method, allowing new notification methods to be added without modifying existing code.
EmailNotifier and SMSNotifier implement the interface and define the send() method.
NotificationService depends on the Notifier abstraction rather than a specific implementation, adhering to the Dependency Inversion Principle (DIP).
Conclusion
Applying software design principles improves code structure and quality, making it more flexible and maintainable. In this example, we demonstrated how DIP helps decouple components and facilitate system extension without modifying existing code.
Link de github del ejemplo
https://github.com/juanjosee15/principios-diseno-software.git
Top comments (2)
Great article! You provided a clear and concise explanation of key software design principles, and the Python example perfectly illustrates the Dependency Inversion Principle (DIP). I appreciate how you highlighted the importance of abstractions in making the system more flexible and maintainable. One observation: while the example focuses on DIP, it also subtly aligns with the Open/Closed Principle (OCP) by allowing new notifiers to be added without modifying existing code. This reinforces how design principles often complement each other in real-world applications. Well done!
I found this article pretty clear about software design principles, especially DIP. The Python example is well-structured and shows how to use abstractions to make the system more flexible and maintainable. I liked that it avoids direct dependencies on specific implementations, making it easier to add new notification types. As an improvement, it would be interesting to see how it works with dependency injection. Overall, it's a great resource for understanding SOLID with a practical example.