5

Specific example question:

I am writing multiple different software packages, in different repos, that each do different things. Many of these packages produce something that we want to visualise/plot. Do I bundle plot functionality in each package or do I write a separate package to do the plotting?

The S in SOLID (Single Responsibility Principle) would imply "write a plotting package". However, new users contributing to this group of packages would need to make changes across two files in two packages, instead of bundling together their new contribution as a change in one location that bundles plot functionality. Can these trade-offs ever be avoided in the general case?

candied_orange
  • 119,268

4 Answers4

10

I think you misunderstood the idea of the SRP. As a rule-of-thumb, the SRP is about separating different orthogonal responsibilities, like

  • the technical requirements for plotting ("how to plot"), apart from

  • the business requirements for plotting ("what to plot")

Requirements for changes for those two (or more) packages will then usually come from different stakeholders. Ideally, there will be a generic, reusable plotting package which just takes a description of what you want to plot, whilst the domain specific plotting code resides in different packages. Then

  • change requests from the business side go into the domain specific packages

  • technical change requests go into the generic package

Of course, in reality, things might not be that simple, since new business requirements might require additional technical features in the generic package. Still, one can usually expect the generic package to converge into something stable, so "users contributing to this group of packages" would finally reach the point where they have only to change one package at a time, depending on whether a requirement is a businesss requirement or a technical one.

This can end up in an organizational splitting, where the generic plot package comes from a separate team or separate vendor (which then obviously uses a separate repository), whilst the domain specific team(s) use their own repositories. Still, we should keep code from one domain area or one bounded context (to use the DDD term) together, not necessarily in a single package, but usually in one repo (which can be seen as a synonym for "under the control/responsiblity of a single team").

Of course, teams may decide to use more than one package for one domain context. For example, they may want to separate their domain-specific plot layer (which uses the generic plot package) inside a single program or component from the core domain objects (or other functionality which has nothing to do with plotting), for better code organization or better testability, but without aiming for orthogonality. This depends to some degree how much domain specific plotting code the program has, and how strong this code is connected to other domain specific parts.

And there you are correct - a single domain requirement can then cause the necessity for changing different packages at once. For example, one adds an attribute to a model - now we have to change a domain model package, an import/export package, a UI package and the plotting package because the new attribute has to be shown as a lable of a plotted graph. It is debatable whether such a layering still counts as an application of the SRP, probably not as much as Bob Martin meant it when he wrote that "the SRP is about people".

Doc Brown
  • 218,378
3

The SRP does not require you to write a different package. It only tells you not to tie the plotting to the other functionality. The rationale is to reduce change propagation and facilitate maintenance.

It is sufficient for SRP to keep plotting in each package, just isolated from other features. By the way, there are other good reasons not to mix plotting with the rest: MVC architecture for example, would require to have plotting (part of a view) separate from the domain object being plotted (part of the model). This allows to have different views plotting the same object in different ways.

You should move plotting to a separate package, only if there would be some reuse possible across the package; Don't Repeat Yourself: no need to rewrite basic pie chart or 3D rendering again and again. However, in your specific case, the need to personalise plotting by package (and even per package and customer) speaks somewhat against it, unless you design it to isolate plotting from plotting customisation (e.g. having the general reusable part in a separate package, and have a customisable part dependent part in each of the other package).

Christophe
  • 81,699
2

To quote from "Clean Architecture A Craftsman Guide to Software Structure and Design" Robert C Martin:

Thus the final version of the SRP is: A module should be responsible to one, and only one, actor. Now, what do we mean by the word “module”? The simplest definition is just a source file. Most of the time that definition works fine. Some languages and development environments, though, don’t use source files to contain their code. In those cases a module is just a cohesive set of functions and data structures

For me reading this book and others it seems clear that Martin believes in the separation of code into dlls/jars etc.

These dynamically linked files, which can be plugged together at runtime, are the software components of our architectures. It has taken 50 years, but we have arrived at a place where component plugin architecture can be the casual default as opposed to the herculean effort it once was.

This is his unit of componentisation and where the rules in clean architecture are applied.

Separating your code out into packages is the way to go. putting the packages into different git repos is a more nuanced choice.

The trade off I use would be to separate packages but not repos. You can then make the change in one commit and build everything together.

Once a package is mature enough to be used across multiple applications, then is the time to consider moving it to its own git repo.

Ewan
  • 83,178
0

The Single Responsibility Principle was given to us by Robert Martin. He said SRP is about changing a class. Specifically, how many actors (be they humans or departments in your org chart) can cause change. Your class should only have one. Such actors have that power because what the class deals with makes it responsible to them.

It's strictly about classes. Just classes. Not functions. Not projects. Period. Because Bob thinks of classes as the scale at which code changes live. How do I know? Because he explicitly said so. If you want to talk about functions go see what he wrote about functions in Curlys law: do one thing.

He has other principles for other structures. But, if you'd like to talk about an applicable principle that does generalize over many structures one of them does exist. It's much older.

Dijkstra taught us the value of having a Separation of Concerns. When done right two very important qualities emerge. 1) You can look at part of the code base and think about one thing without being distracted by other things. 2) You can find things.

It is a form of abstraction and a very powerful one. It's less about actual structure and more about how the human mind works. When deciding where to put your plot code keep these qualities in mind. Any solution that provides for both is acceptable under this principle.

If you can see a way to provide both done either way then I'll ask you, which one is going to make updating your code easier? This is essentially asking you to forecast change. Predictions are hard, especially about the future. But odds are you know the answer to this better than we do.

candied_orange
  • 119,268