6

What is more important? SOLID or KISS?

To be consistent with SOLID I would have to inject Decorator and Footer classes and create interfaces for them.

public class HelloService {
   String name;
   HelloService(String name){
      this.name = name;
   }
   public String getHello() {
      Decorator decorator = new Decorator();

      String full = decorator.bar
              + this.name 
              + Footer.add(this.name);

      return full;
   }
}

public class Decorator {
    public String bar() {
        return "Some";
    }
}

public class Footer {
    public static String add(String name) {
        if (name.length() > 10) {
            return "A";
        } else {
            return "B";
        }
    }
}

Would not that be an exaggeration?

My example is simple, but if it was complex, what should I do? If I use other classes in the classroom only in one place, should I also inject them?

How can I improve my classes so that they are compliant with the rules and readable for everyone?

  • 3
    "To be consistent with SOLID I would have to inject Decorator and Footer classes and create interfaces for them." No. – Euphoric Mar 5 '18 at 21:20
  • 2
    What would you gain by abstracting Foother and Decorator? Other than nice feeling that you follow "SOLID". – Euphoric Mar 5 '18 at 21:24
  • 3
    What's most important is to do the thing that most effectively meets your specific requirements. – Robert Harvey Mar 5 '18 at 21:45
  • 2
    @cimlihor: if you are new to programming then put SOLID and other stuff like it on hold and focus on learning how to turn english language descriptions of problems into solutions a computer can perform. Until you have those skills developed SOLID and other stuff is just going to confuse and waste your time. You have to walk before you can run. – whatsisname Mar 5 '18 at 23:18
  • 8
    Beware of getting lost in the design patterns-land or in the principles-land. There's no need to force them into your code if you cannot justify their usage in some other way than "It's best practice to use them.". – Mael Mar 6 '18 at 7:00
17

TLDR;

Neither is "more important." Developers do not serve principles; principles serve developers. Apply them in the manner and extent to which they achieve your goals and help you deliver.


A few calibration points:

  • The D in SOLID is not Dependency Injection; it's Dependency Inversion. Dependency Injection just happens to be a prominent solution for inverting dependencies. The important aspect of that D is making it easy to change things that might actually change.

  • KISS reminds developers to keep things as simple and "stupid" as they are. It does not suggest making things more simple than they really are. It does not mandate that you sacrifice on maintainability, extensibility, or features. Nor does it require you to tank your business's ROI to satisfy a developer's sense of "simplicity" or "elegance."

  • Software principles are pragmatic. Neither simple code, nor code with inverted dependencies, nor even test-driven code is inherently "better." Good code serves a purpose. Coding principles are only applicable to the extent they serve the code's purpose.

  • You need to understand your code's purpose and the principles. If you don't understand the purpose of your code (including company "goals" like maintainability), principles will do little to help. And, if you don't understand the principles, you can't really apply them anyway.

In other words, apply the POAP, which I will now shamelessly quote from my own single-article "blog" ...

Principles, patterns, and practices are not final purposes. The good and proper application of each is therefore inspired and constrained by a superior, more final purpose.

You need to understand why you're doing what you're doing!

(The POAP is not exempt from the POAP.)

Unfortunately, this stuff is hard to teach — if it's teachable at all. If you don't have a domain expert mentor, fuddle through it as best you can. And, the next time you have to touch this code, ask yourself what worked and what didn't?

| improve this answer | |
  • Thanks for the answer. +1 This question was just to learn, because it's just an example of code. I know that the most important is the operation of the program, but I would also like to adhere to good rules. How would you write my code? – cimlihor Mar 6 '18 at 19:33
  • 1
    @cimlihor Your success in applying a principle depends on the end goal. If the end goal is to learn Dependency Injection, KISS just suggests that you "apply Dependency Injection in the simplest way possible." Otherwise, you just need to fabricate some goals and practice aligning the principles to the goals. I.e., for each principle, ask yourself what the purpose of the principle is and how it helps you achieve your goal -- despite the fact that it's a fabricated goal. – svidgen Mar 6 '18 at 19:48
  • 1
    ... That said, I would highly suggest building something meaningful to you. Fabricated goals don't often teach well. But, if you have a vision for something genuinely valuable, with a real domain and everything (not just foo's and bar's), you can experiment to an extent with how various principles and patterns help and hinder your efforts. (Even better if you can collaborate on something. A lot of these principles only show their value in long-lived projects and/or in collaborative settings.) – svidgen Mar 6 '18 at 19:52
8

The most important thing is that your program works and makes the users happy by delivering the expected results. But what made them happy yesterday, might no longer be sufficient to keep them happy tomorrow.

This is why the two principles are not competing but are intertwined:

  • KISS may help to focus on the initial results without distraction, by working out a simple solution. As an extra bonus, by avoiding complexity KISS reduces the potential for bugs.

  • However, in the real life users tend to change their mind and add new or forgotten requirements during the development, not speaking afterwards in the many years the system will be used. So very often, your code has to evolve before it is even finished. It appears that SOLID helps to achieve a robust design that can evolve much more easier.

  • Sometimes SOLID and KISS could even to refer to the same solution

The main challenge in the art of software development is to balance the two. Keep it as simple as it can be, but not simper, and at the same time, make it SOLID without adding to much weight. In other words, don't apply principles blindly.


P.S: your program is neither KISS nor SOLID: it would be much simpler to have bar() and add() as members of HelloService. So this solution is already over-engineered.

P.S.2: But if you think that Decorator and Footer deserve encapsulation, it would be much more future proof to decouple the classes with proper DI, so that you can have several different Decorators and Footers (for example to optimize the layout depending on the target device).

P.S.3: Of course adding DI seems disproportionate for your small piece of code. In the real world however, with classes of real world complexity, very often the additional DI effort is proportionally much slower

| improve this answer | |
  • Thanks for answer, +1. P.S - bar() and add() are used also in others services, so it should be separate classes. P.S.2 - so I should create interfaces for these classes? P.S.3 - This is just a simple example. – cimlihor Mar 6 '18 at 19:27
  • 1
    @cimlihor I understand; sorry if my PSs are so provocative ;-). But I think you got the point: in a simple example it's easy to make the one or the other approach disproportionate. But what in real life ? If you use these classes in several location, it could make sense to create an interface to abstract the problem. Intuitively I'd be tempted to use DI as well, as these classes start to look as a strategy. But I don't know your problem and drivers for change. – Christophe Mar 6 '18 at 19:59
3

SOLID is no end in itself, it is a means to an end. Applied to your example, this means to make the code as SOLID as you need it, no less, no more. This matches also the KISS principle.

  • for example, if for unit testing purposes you need to decouple HelloService from Decorator, use DI. If you think functional or integration tests are enough, you probably don't need it.

  • if you want to reuse HelloService, but with different decorators and footers, injecting those as a parameter is probably the most "simple and stupid" solution to keep the code DRY. If there is only one decorator and one footer, you will probably not even need separate classes for the decorator and footer

  • if you need to avoid to introduce a direct dependency between components, because is part of a general purpose lib, and the logic of Decorator and Footer have to be supplied by a user of that lib (OCP), then DI will be required

Especially the D from SOLID is probably the most simple solution for these kind of problems you want to solve, so it is perfectly in line with KISS.

If DI is not required (yet), then do not start using it "just in case". Instead, apply YAGNI: refactor to DI as soon as you get a real requirement for it.

| improve this answer | |
  • Thanks for answer, +1 for you. Let's assume that I do not share applications so that it's easier to test. Decorator and Footer are used in other classes, so they must be separated. Currently, I do not want to use another Decorator and Footer in HelloService, but maybe someday... So I do not want to do DI because of that? Sometimes you have to think ahead... This class is not in the project as a library, but a normal design class. – cimlihor Mar 6 '18 at 19:13
2

Applying principles and "best practices" without fully understanding their purpose can be quite destructive. The D in solid is a notorious one.

Dependency inversion reads to many as "use interfaces". Which isn't that far off but triggers many to slap an interface over every class they create. This is usually not helpful.

What it really means is, try to decouple dependencies between A and B by introducing a third entity C. Then have both A and B know C, but not each other.

This can be beneficial but like others already pointed out, you need to have a purpose for it. If you do not know why you are doing it, please don't.

Interfaces are most valuable when they define some behavioral aspect of a class. That is their primary value. Using them just because it allows you to test your code is already abusive use of an interface. It typically leads to interfaces that have a one-to-one relationship with the classes they represent, which violates the I in SOLID, the interface segregation principle.

Cat : IScratcher, IJumper, IPettable   // helpful

Cat : ICat    // utterly useless

So if you do make that ICat interface for testing, be aware it is a trade-off. You are basically saying "I don't care shit about SOLID, I just want test my class".

What you really should do is have separate test methods for IScratcher, IJumper and IPettable.

| improve this answer | |
  • Thanks, +1. I do not want to use SOLID to be easier to test. I learn good practices and I don't know when to use DI and when to create interfaces. – cimlihor Mar 6 '18 at 19:16
0

SOLID.

The trouble with KISS is the definition of 'simple' depends on who you ask. Where as your example code has a few concrete problems which are solved with the 'simple' patterns of interfaces and not typing the word 'static' ever.

Your code will be longer, but not any more complicated with the interfaces.

Indeed you could write shorter but arguably more complicated code, perhaps a regexp? which someone used to regexs would say "But its so simple! why do you need all those classes??"

| improve this answer | |
  • 4
    The problem with SOLID is the definition of SOLID depends on who you ask. Except maybe for the Liskov Substitution Principle, whose definition is quite specific. – Robert Harvey Mar 5 '18 at 22:07
  • 3
    the good thing about the LSP is that is got who you have to ask in the name – Ewan Mar 5 '18 at 22:14
  • I have yet to see a reasonable example of LSP relevant to the real world. Squares and Rectangles need not apply. – user949300 Mar 6 '18 at 1:40
  • And in my case, what should the code look like to make it look like KISS? +1 – cimlihor Mar 6 '18 at 19:19
  • @user949300 See this SO answer for a real world and reasonable example. – user1451111 Sep 8 '18 at 13:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.