This blog is the first of five blogs about the SOLID principles of object oriented programming (OOP). SOLID stands for:
- Single responsibility principle
- Open/closed principle
- Liskov substitution principle
- Interface segregation principle
- Dependency inversion principle
These principles are first introduced by Robert C. Martin in the beginning of the 21st century. When you follow these principles, you will have a greater chance to deliver software that will be maintainable over a long period of time.
As the title says, this blog is about the single responsibility principle. The goal of this principle is to write classes which have only one reason to change. Let’s take a part of code (Python 3) that writes data from a database to an Excel workbook with the help of Openpyxl (the code is part of a not so well written program but try not too look at that).
ws2 = wb.create_sheet(title="W&V") ws2['A1'].font = self.styb ws2['A1'] = "Winst-en-Verliesrekening over " + str(year) ws2.merge_cells('C3:D3') ws2['C3'] = str(year) ws2.merge_cells('E3:F3') ws2['E3'] = str(year2) ws2['C4'] = ws2['D4'] = ws2['E4'] = ws2['F4'] = "€"
In the code we make a worksheet called W&V. From there we create a font and write and merge cells.
This code can change the values on the worksheet without any problem, the variables make sure of that. But what happens when the final user of the created file want’s his data written to an PDF instead. Then you will find out that this code violates the single responsibility principle, because it does not only change the data in the report, it also defines that we save that data as an .xlsx file.
How can you prevent situations like this from happening
To prevent situations like this from happening you can create an abstract base class called Writer. For this class you create a child class that implements all the methods defined in the Writer parent class (for example: ExcelWriter or PDFWriter). When you start to write the code to write to Excel or PDF you instantiate and instance of this Writer class. This way the data is decoupled from the file type.
class Writer: __metaclass__ = ABCMeta def __init__(self): print("Writer") class ExcelWriter(Writer): def __init__(self): Writer.__init__(self) print("ExcelWriter") class PDFWriter(Writer): def __init__(self): Writer.__init__(self) print("PDFWriter")
When you are starting to build programs this will look like a lot of extra work, but eventually it will make it easier to make changes to your program. Remember to use techniques like this one for (almost) every project, because you will want to be able to change the application fast if the requirements change.