Keeping Coupling Low While Adhering to DRY - oop

The mantra "Keep high cohesion and low coupling" (or some variant) is frequently tossed around. However, I find that it frequently conflicts with "Don't repeat yourself."
For example, I think we can all agree that it's a bad thing to re-implement std::string or use C-strings, but doesn't including std::string create another dependency and therefore increase coupling?
For another example, take std::stringstream. It inherits from iostream, which inherits from istream and ostream, which inherit from ios, which inherits from ios_base. Over all these derivations, it inherits a lot of functionality - enough to make re-implementing by hand a very bad idea. It also pulls the <ios> and <istream> headers even though only <sstream> was included, thereby increasing coupling.
How can one keep coupling low without reinventing the wheel for each module?
EDIT: If the two concepts cannot coexist, which one should be favored?

Please go through http://www.artima.com/intv/dry.html on DRY,
particularly "Most people take DRY to mean you shouldn't duplicate code. That's not its intention. The idea behind DRY is far grander than that".
Adding to this, in the example you discussed , std::string and your system are not tightly coupled as you are not relying/using any internal info of std::string. Any (internal) changes to std::string will not effect your system.

Related

In SOLID, what is the distinction between SRP and ISP? (Single Responsibility Principle and Interface Segregation Principle)

How does the SOLID "Interface Segregation Principle" differ from "Single Responsibility Principle"?
The Wikipedia entry for SOLID says that
ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them
However, to me that sounds like just applying the SRP to interfaces as well as classes. After all, if an interface is only responsible for just one conceptual thing, than you wouldn't be able to break it down further.
Am I missing something, or is ISP sort of redundant with SRP? If not, then what does ISP imply that SRP does not?
SRP tells us that you should only have a single responsibility in a module.
ISP tells us that you should not be forced to be confronted with more than you actually need. If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that.
More concretely, and going straight to the point, they are different views on the same idea -- SRP is more focused on the designer-side point-of-view, while ISP is more focused on the client-side point-of-view. So you're basically right.
It all came from
The ISP was first used and formulated by Robert C. Martin when doing
some consulting for Xerox. Xerox had created a new printer system that
could perform a variety of tasks like stapling a set of printed papers
and faxing. The software for this system was created from the ground
up and performed its tasks successfully. As the software grew, making
modification became more and more difficult so that even the smallest
change would take a redeployment cycle to an hour. This was making it
near impossible to continue development. The design problem was that
one main Job class was used by almost all of the tasks. Anytime a
print job or a stapling job had to be done, a call was made to some
method in the Job class. This resulted in a huge or 'fat' class with
multitudes of methods specific to a variety of different clients.
Because of this design, a staple job would know about all the methods
of the print job, even though there was no use for them.
so
The solution suggested by Martin is what is called the Interface
Segregation Principle today. Applied to the Xerox software, a layer of
interfaces between the Job class and all of its clients was added
using the Dependency Inversion Principle. Instead of having one large
Job class, a Staple Job interface or a Print Job interface was created
that would be used by the Staple or Print classes, respectively,
calling methods of the Job class. Therefore, one interface was created
for each job, which were all implemented by the Job class.
# http://en.wikipedia.org/wiki/Interface_segregation_principle#Origin
SRP is concerned with what a module does, and how it is done, disallowing any mix of abstraction levels. Basically, as long as a component can be extensively defined with a single sentence, it will not break SRP.
On the other hand ISP is concerned with how a module should be consumed, whether it makes sense to consume just part of the module, while ignoring some aspect.
As an example of a code that keeps the spirit or SRP, but can break ISP is the Facade pattern. It has a single responsibility, "providing simplified access to a larger subsystem", but if the underlying subsystem needs to expose wildly different thinks, it does break ISP.
That said, usually when a piece of code breaks a SOLID principle, it often breaks the whole lot. Concrete examples that break a specific principle, while preserving the rest are rare in the wild.
Robert Martin tweeted the following on May 16, 2018.
ISP can be seen as similar to SRP for interfaces; but it is more than that. ISP generalizes into: “Don’t depend on more than you need.” SRP generalizes to “Gather together things that change for the same reasons and at the same times.”
Imagine a stack class with both push and pop. Imagine a client that only pushes. If that client depends upon the stack interface, it depends upon pop, which it does not need. SRP would not separate push from pop; ISP would.
SRP and ISP ultimately boils down to the same things. Implementing, either of them, needs a split of classes or interfaces.
However there are differences on other fronts.
Violation of SRP can have a far reaching effects on the entire design structure, giving rise to poor maintainability, reuse and of course low cohesion and coupling.
SRP has an impact on both the behavioral and structural components of an object structure.
Re designing on SRP violation needs a much deeper analysis, require looking at the different components of design in a holistic way.
Violation of ISP is mostly about poor readability ( and to some degree, low cohesion ). But the impact on maintenance and code re-use is far less sinister than SRP.
Moreover, refactoring code to ISP conformation, seems to be just a structural change.
See also my blog for SRP and ISP
From the point of my understanding, both principles are complementary, i.e. they need to be combined.
The ultimate consequence of violating ISP is becoming fragile, "shotgun surgury" or a "butterfly effect". A lot of code can break or require code updates because they depend onto some interface or objects which provide more than they needed. Changes become excessive.
The consequence of violating SRP is mainly decreased readability and maintentance. The lack of clear code structure may require people to search across the code base (a single responsibility is too distributed) or within a single large unit (multiple responsibilities scrammed together) to make a coherent change. In General, it is increased overhead to fully understand the concern (purpose) of some code snippet. Changes are prevented.
In that way, both principles act like a lower and upper bound for sane change management.
Examples for satisfying RSP without ISP – as provided by the other answers – express that there can be code which truly would belong together (like the stack example quote from Robert C. Martin). But it may do too much, is overengineered, etc. Maybe in very small examples, the effect is not visible, but if it grows large, it may be more comfortable to have a depending class still compile correctly after some unrelated part in the (indirect) dependency was changed. Rather than not compile anymore because unrelated things were changed.

Could override be deprecated?

There is a Design Principle that says Favor composition over inheritance and its advertised benefit is that it simplifies design. Let's agree on that as background for this question.
So, could override be deprecated? Could we, in theory, get rid of it for good?
Let's be a bit over zealous on the above mentioned Design Principle and take it to the extreme: composition all the way. One reason should be enough for now, override abuse.
One question arises: are we, programmers, going to loose something? Is any power lost trying to prevent some possible abuse?
So, what applications are there for override and can they be achieved otherwise? Should they?
Not only is this a completely radical and impractical proposal, it's not a particularly compelling one. Just because a feature gets abused doesn't mean that it should be removed entirely. People have been abusing all sorts of things for a very long time, but that hardly implies that they don't serve a useful purpose when used correctly.
Design patterns are one thing; designing an intentionally limited language to conform with your ideal notion of a good design pattern is quite another. To my mind, it's an exercise in futility. Programmers will still find something to abuse.
And I take issue with the central assumption that any use of override is inappropriate or abusive. There are lots of cases where you want to take advantage of inheritance implying an is-a relationship. Sure, this model doesn't fit the real world 100% of the time, but there are plenty of times that it does.
The Animal and Shape class examples that you read about in textbooks might be a bit contrived, but I frequently use inheritance in real-world applications.
That's not to imply that I disagree with the sentiment that one should generally or when in doubt, favor composition over inheritance. But that's not saying that inheritance is bad and should never be used.
If you remove inheritance altogether you remove a significant feature of OOP design.
Using inheritance allows you to use a "is a" design, which has a strong meaning in OOP design, and of course saves code redundancy.
If you'd use only encapsulation you'd have to either expose the members (which isn't always what you want (raises design complexity because of the amount of stuff the programmer needs to know about).
Or, make wrapper methods that will call the member's methods (which is redundant).
Besides that, lets assume you know the difference between overriding and hiding, you can see that most OOP languages will choose to use strictly overriding when given the choice.
This is because overriding is usually more intuitive than hiding.
So, if you remove overriding, and still allow inheritance, you are left with hiding. That usually leads to many runtime errors and un-expected results with type conflicts.
Farther more you won't be able to have things like an array or list of base class pointers that point a lot of different derived classes. Because if you don't have overrides it won't be able to call the specified derived class method, it will only call the same base class method for all of them.
I've added a response on behalf of astander extracting from his link (hope you don't mind)
For example, one advantage with inheritance is that it is easier to
use than composition. However, that ease of use comes at the cost that
it is harder to reuse because the subclass is tied to the parent
class.
One advantage of composition is that it is more flexible because
behavior can be swapped at runtime. One disadvantage of composition is
that the behavior of the system may be harder to understand just by
looking at the source. These are all factors one should think about
when applying composition over inheritance.
I'm always using polymorphism. I always seem to have a bunch of objects with some common concept behind them and a lot of code that is interested in that concept--that is, they care about Animals, not Lions and Tigers and Bears or even Carnivores. Interfaces often work better for this than superclasses, so I suppose I could get by without subclassing. (Are interfaces okay when subclassing is not?) However, I have often found that a lot of classes using an interface have identical code for the interface methods. Changing the interface to a superclass can let me get rid of a lot of duplicate code. The other situation I find myself in is where a large, complex class does what I need except for one teeny, tiny little thing. With subclassing, I can create a new class that does exactly what I need in just a few lines.
There may be a language component to this debate. When I'm writing in Java I subclass at a furious rate. When I'm writing in C# I think long and hard before overriding anything or even using interfaces. I'm not sure why and it may have more to do with the type of work I do in those languages than the languages themselves. But working in C#, I am quite sympathetic to this idea, while when working in Java...well, I'd have to toss almost all my Java code if I couldn't override.

Are Traits good or bad?

This is an open-ended question, but I would like to solicit some opinions from the SO community on Traits; do you think Traits in Squeak/Pharo are a good thing, or should you stay away from them and use composition and delegation instead? I ask because while I know how to use them (thanks to the Pharo book), I am not really sure how acceptable it is to use them or where it is OK to use them and where it isn't.
I do not like traits because they introduce strong dependencies into code. These dependencies can be obvious (a class that imports a trait, a trait that expects methods), but also very subtle (a trait that shadows super methods/instance variables). Furthermore there is no adequate tool support for traits.
In my experience delegation gives a much better and more reusable design in a dynamically typed object-oriented language like Smalltalk.
Things have their pros and cons. Lukas rightly mentions many of the cons:
Introduce strong dependencies into code.
no adequate tool support.
While the second may go away some day, the first will not.
The purpose of traits is to prevent code duplication that occurs, when two classes that don't share a superclass other than Object, share an instance method. Now, sometimes delegation can fix that, but oftentimes it cannot. So, the pro of traits is:
Reduced code duplication.
My verdict here is that the disadvantages overweigh. I think that, today and forever, code duplication is bound to occur. And when delegation won't do, I can even imagine that code duplication isn't all that harmful, as it often precedes the divergent evolution of the copied code snippets.
I think, the best thing to do, as of today, is to keep automated track of code duplication, and always monitor when one end changes while the other doesn't. I'm currently writing a tool that'll keep track of such links, even across repositories. I'll report on it in my blog when it's ready.

Objectively Good OO Design Principles

Premise
I believe that there is a way to objectively define "Good" and "Bad" Object-Oriented design techniques and that, as a community we can determine what these are. This is an academic exercise. If done with seriousness and resolve, I believe it can be of great benefit to the community as a whole. The community will benefit by having a place we can all point to to say, "This technique is 'Good' or 'Bad' and we should or should not use it unless there are special circumstances."
Plan
For this effort, we should focus on Object-Oriented principles (as opposed to Functional, Set-based, or other type of languages).
I'm not planning on accepting one answer, instead I'd like the answers to contribute to the final collection or be a rational debate of the issues.
I realize that this may controversial, but I believe we can iron something out. There are exceptions to most every rule and I believe this is where the disagreement will fall. We should make declarations and then note relevant exceptions and objections from dissenters.
Basis
I'd like to take a stab at defining "Good" and "Bad":
"Good" - This technique will work the first time and be a lasting solution. It will be easy to change later and will pay the time investment of its implementation quickly. It can be consistently applied and easily recognized by maintenance programmers in the future. Overall, it contributes to the good function and lowers cost of maintenance over the life of the product.
"Bad" - This technique may work in the short term, but soon becomes a liability. It is immediately difficult to change or becomes more difficult over time. The initial investment may be small or large, but it quickly becomes a growing cost, eventually becoming a sunk cost and must be removed or worked around constantly. It is subjectively applied and inconsistent and may be a surprise or not easily recognizable by maintenance programmers in the future. Overall, it contributes to the ultimate increasing cost of maintaining and/or operating the product and inhibits or prevents changes to the product. By inhibiting or preventing change, it becomes not just a direct cost, but an opportunity cost and a significant liability.
Starter
As an example of what I think a good contribution would look like, I'd like to propose a "Good" principle:
Separation of Concerns
[Short description]
Example
[Code or some other type of example]
Goals
[Explanation of what problems this principle prevents]
Applicability
[Why, where, and when would I use this principle?]
Exceptions
[When wouldn't I use this principle, or where might it actually be harmful?]
Objections
[Note any dissenting opinions or objections from the community here]
There are some well understood principles that might form a good starting point:
Open/Closed Principle
Liskov Substitution Principle
Law of Demeter
It is also a good idea to study existing design patterns to find principles behind them, the most important one is to (generally) prefer composition over inheritance.
Separation of Concerns
Prefer Aggregation to Mixin-style Inheritance
While functionality can be gained by inheriting from a utility class, in many cases it can all be gained using a member of said class.
Example (Boost.Noncopyable):
Boost.Noncopyable is a C++ class that lacks a copy constructor or assignment operator. It can be used as a base class to prevent the subclass from being copied or assigned (this is the common behavior). It can also be used as a direct member
Convert this:
class Foo : private boost::noncopyable { ... };
To this:
class Foo {
...
private:
boost::noncopyable noncopyable_;
};
Example (Lockable object):
Java introduced the synchronized keyword as an idiom to allow any object to be used in a threadsafe manner. This can be mirrored in other languages to provide mutexes to arbitrary objects. A common example is data structures:
class ThreadsafeVector<T> : public Vector<T>, public Mutex { ... };
Instead, the two classes could be aggregated together.
struct ThreadsafeVector<T> {
Vector<T> vector;
Mutex mutex;
}
Goals
Inheritance is frequently abused as a code-reuse mechanism. If inheritance is used for anything besides an Is-A relationship, overall code clarity is reduced.
With deeper chains, mixin base classes greatly increase the likelihood of a "Diamond of Death" scenario, wherein a subclass ends up inheriting multiple copies of a mixin class.
Applicability
Any language that supports multiple inheritance.
Exceptions
Any case where the mixin class provides or requires overloading members. In this case, inheritance usually implies an Is-Implemented-In-Terms-Of relationship, and an aggregate will not be sufficient.
Objections
The result of this transformation may lead to public members (e.g. MyThreadSafeDataStructure may have a publicly-accessible Mutex as a component).
I think the short answer is that "good" OO designs are robust under change, with the least code breakage for any requirements change. If you consider all the usual rules, they all tend to that same conclusion.
The difficulty is that you can't evaluate the "goodness" of the design without context; it is, I believe, a theorem that for any modularization, there exists a change in requirements that will maximize breakage, causing every class to be touched in each method.
If you want to be rigorous about it, you can develop a collection of "change cases" and order them in probability order, so that you minimize the breakage for the highest probability changes.
On most cases, though, some well-developed intuition helps a lot: device-specific or platform specific things tend to change, business rules and business process tend to change, while the implementations of, say, arithmetic, change very rarely. (Not, as you might imagine, never. Consider, for example, a business system that may or may not be able to make use of platform-supported BCD arithmetic.)

How do you define a Single Responsibility?

I know about "class having a single reason to change". Now, what is that exactly? Are there some smells/signs that could tell that class does not have a single responsibility? Or could the real answer hide in YAGNI and only refactor to a single responsibility the first time your class changes?
The Single Responsibility Principle
There are many obvious cases, e.g. CoffeeAndSoupFactory. Coffee and soup in the same appliance can lead to quite distasteful results. In this example, the appliance might be broken into a HotWaterGenerator and some kind of Stirrer. Then a new CoffeeFactory and SoupFactory can be built from those components and any accidental mixing can be avoided.
Among the more subtle cases, the tension between data access objects (DAOs) and data transfer objects (DTOs) is very common. DAOs talk to the database, DTOs are serializable for transfer between processes and machines. Usually DAOs need a reference to your database framework, therefore they are unusable on your rich clients which neither have the database drivers installed nor have the necessary privileges to access the DB.
Code Smells
The methods in a class start to be grouped by areas of functionality ("these are the Coffee methods and these are the Soup methods").
Implementing many interfaces.
Write a brief, but accurate description of what the class does.
If the description contains the word "and" then it needs to be split.
Well, this principle is to be used with some salt... to avoid class explosion.
A single responsibility does not translate to single method classes. It means a single reason for existence... a service that the object provides for its clients.
A nice way to stay on the road... Use the object as person metaphor... If the object were a person, who would I ask to do this? Assign that responsibility to the corresponding class. However you wouldn't ask the same person to do your manage files, compute salaries, issue paychecks, and verify financial records... Why would you want a single object to do all these? (it's okay if a class takes on multiple responsibilities as long as they are all related and coherent.)
If you employ a CRC card, it's a nice subtle guideline. If you're having trouble getting all the responsibilities of that object on a CRC card, it's probably doing too much... a max of 7 would do as a good marker.
Another code smell from the refactoring book would be HUGE classes. Shotgun surgery would be another... making a change to one area in a class causes bugs in unrelated areas of the same class...
Finding that you are making changes to the same class for unrelated bug-fixes again and again is another indication that the class is doing too much.
A simple and practical method to check single responsibility (not only classes but also method of classes) is the name choice. When you design a class, if you easily find a name for the class that specify exactly what it defines, you're in the right way.
A difficulty to choose a name is near always a symptom of bad design.
the methods in your class should be cohesive...they should work together and make use of the same data structures internally. If you find you have too many methods that don't seem entirely well related, or seem to operate on different things, then quite likely you don't have a good single responsibility.
Often it's hard to initially find responsibilities, and sometimes you need to use the class in several different contexts and then refactor the class into two classes as you start to see the distinctions. Sometimes you find that it's because you are mixing an abstract and concrete concept together. They tend to be harder to see, and, again, use in different contexts will help clarify.
The obvious sign is when your class ends up looking like a Big Ball of Mud, which is really the opposite of SRP (single responsibility principle).
Basically, all the object's services should be focused on carrying out a single responsibility, meaning every time your class changes and adds a service which does not respect that, you know you're "deviating" from the "right" path ;)
The cause is usually due to some quick fixes hastily added to the class to repair some defects. So the reason why you are changing the class is usually the best criteria to detect if you are about to break the SRP.
Martin's Agile Principles, Patterns, and Practices in C# helped me a lot to grasp SRP. He defines SRP as:
A class should have only one reason to change.
So what is driving change?
Martin's answer is:
[...] each responsibility is an axis of change. (p. 116)
and further:
In the context of the SRP, we define a responsibility to be a reason for change. If you can think of more than one motive for changing a class, that class has more than one responsibility (p. 117)
In fact SRP is encapsulating change. If change happens, it should just have a local impact.
Where is YAGNI?
YAGNI can be nicely combined with SRP: When you apply YAGNI, you wait until some change is actually happening. If this happens you should be able to clearly see the responsibilities which are inferred from the reason(s) for change.
This also means that responsibilities can evolve with each new requirement and change. Thinking further SRP and YAGNI will provide you the means to think in flexible designs and architectures.
Perhaps a little more technical than other smells:
If you find you need several "friend" classes or functions, that's usually a good smell of bad SRP - because the required functionality is not actually exposed publically by your class.
If you end up with an excessively "deep" hierarchy (a long list of derived classes until you get to leaf classes) or "broad" hierarchy (many, many classes derived shallowly from a single parent class). It's usually a sign that the parent class does either too much or too little. Doing nothing is the limit of that, and yes, I have seen that in practice, with an "empty" parent class definition just to group together a bunch of unrelated classes in a single hierarchy.
I also find that refactoring to single responsibility is hard. By the time you finally get around to it, the different responsibilities of the class will have become entwined in the client code making it hard to factor one thing out without breaking the other thing. I'd rather err on the side of "too little" than "too much" myself.
Here are some things that help me figure out if my class is violating SRP:
Fill out the XML doc comments on a class. If you use words like if, and, but, except, when, etc., your classes probably is doing too much.
If your class is a domain service, it should have a verb in the name. Many times you have classes like "OrderService", which should probably be broken up into "GetOrderService", "SaveOrderService", "SubmitOrderService", etc.
If you end up with MethodA that uses MemberA and MethodB that uses MemberB and it is not part of some concurrency or versioning scheme, you might be violating SRP.
If you notice that you have a class that just delegates calls to a lot of other classes, you might be stuck in proxy class hell. This is especially true if you end up instantiating the proxy class everywhere when you could just use the specific classes directly. I have seen a lot of this. Think ProgramNameBL and ProgramNameDAL classes as a substitute for using a Repository pattern.
I've also been trying to get my head around the SOLID principles of OOD, specifically the single responsibility principle, aka SRP (as a side note the podcast with Jeff Atwood, Joel Spolsky and "Uncle Bob" is worth a listen). The big question for me is: What problems is SOLID trying to address?
OOP is all about modeling. The main purpose of modeling is to present a problem in a way that allows us to understand it and solve it. Modeling forces us to focus on the important details. At the same time we can use encapsulation to hide the "unimportant" details so that we only have to deal with them when absolutely necessary.
I guess you should ask yourself: What problem is your class trying to solve? Has the important information you need to solve this problem risen to the surface? Are the unimportant details tucked away so that you only have to think about them when absolutely necessary?
Thinking about these things results in programs that are easier to understand, maintain and extend. I think this is at the heart of OOD and the SOLID principles, including SRP.
Another rule of thumb I'd like to throw in is the following:
If you feel the need to either write some sort of cartesian product of cases in your test cases, or if you want to mock certain private methods of the class, Single Responsibility is violated.
I recently had this in the following way:
I had a cetain abstract syntax tree of a coroutine which will be generated into C later. For now, think of the nodes as Sequence, Iteration and Action. Sequence chains two coroutines, Iteration repeats a coroutine until a userdefined condition is true and Action performs a certain userdefined action. Furthermore, it is possible to annotate Actions and Iterations with codeblocks, which define the actions and conditions to evaluate as the coroutine walks ahead.
It was necessary to apply a certain transformation to all of these code blocks (for those interested: I needed to replace the conceptual user variables with actual implementation variables in order to prevent variable clashes. Those who know lisp macros can think of gensym in action :) ). Thus, the simplest thing that would work was a visitor which knows the operation internally and just calls them on the annotated code block of the Action and Iteration on visit and traverses all the syntax tree nodes. However, in this case, I'd have had to duplicate the assertion "transformation is applied" in my testcode for the visitAction-Method and the visitIteration-Method. In other words, I had to check the product test cases of the responsibilities Traversion (== {traverse iteration, traverse action, traverse sequence}) x Transformation (well, codeblock transformed, which blew up into iteration transformed and action transformed). Thus, I was tempted to use powermock to remove the transformation-Method and replace it with some 'return "I was transformed!";'-Stub.
However, according to the rule of thumb, I split the class into a class TreeModifier which contains a NodeModifier-instance, which provides methods modifyIteration, modifySequence, modifyCodeblock and so on. Thus, I could easily test the responsibility of traversing, calling the NodeModifier and reconstructing the tree and test the actual modification of the code blocks separately, thus removing the need for the product tests, because the responsibilities were separated now (into traversing and reconstructing and the concrete modification).
It also is interesting to notice that later on, I could heavily reuse the TreeModifier in various other transformations. :)
If you're finding troubles extending the functionality of the class without being afraid that you might end up breaking something else, or you cannot use class without modifying tons of its options which modify its behavior smells like your class doing too much.
Once I was working with the legacy class which had method "ZipAndClean", which was obviously zipping and cleaning specified folder...