Why these things in stay in books and blogs and never make their way into Java web apps:
1. Use immutable values:
Models used in client server communication need to follow Java Bean spec which is like the exact antagonistic concept to immutability. Service methods that implement business logic are stateless. As objects are not shared across threads, nobody feels the need for immutability. The most popular frameworks Spring and Hibernate dictate this architecture.
2. Do no work in the constructor
Are constructors still used? All services are wired using dependency injection. Models are either DTOs or Hibernate POJOs - both dumb and anyways don't do any work.
3. Program to small interfaces:
Interfaces are dictated by functionality they provide and not size. They can have hundreds of methods. This is how it looks: DocumentService - put every document related method in here, FinancialInstrumentService - put every instrument related method in here
4. Represent computation, not the world
Almost everybody begins OOP with this misconception - objects in real world directly map to OOP objects. Its maybe a good place to start but how many grow up from the initial simplistic rule - map nouns in requirements to classes. So, you end up with objects that don't really mean anything and don't do much. Naive use of UML diagrams also leads to this. Discovering abstractions is tricky. One needs to really live with requirements inside out before they present themselves. Who has so much time? Believe me in a quarterly release- developers get around only 3 weeks – rest is divided into BA, QA, UAT, freeze, deployment time.
PS: Please don’t get me wrong OP makes good points. It's sweet but the reality is different. May be Google does this (and they do in Guava which is just an example one after another of good stuff in Effective Java). But there's a big corporate java world out there that does things differently. They have well defined easy run of the mill patterns where these things don't fit (yet). This was just a peek into it.
1: Just because some ubiquitous libraries have dictated a practice doesn't make it a good idea or a good model. In fact, Hibernate's tracking of mutable objects in the current session is one of the most painful things about it. There's nothing inherent about client server communication that forces beans on you?
2: That's good, but work in the constructor is by no means gone.
3: That sounds like god objects. "FinancialInstrumentService" is way too much functionality (or poorly named). Getting a current quote, getting historical quotes, doing quant-stuff and placing a trade are all completely separate concerns. Opening a document, saving it, printing it - all separate concerns that are better kept in separate interface. Now, there's little harm in having an implementation implement several interfaces if the implementations has much in common. Extra bonus: Easier to write tests for.
4: Mostly agree, but:
> Believe me in a quarterly release- developers get around only 3 weeks – rest is divided into BA, QA, UAT, freeze, deployment time.
I won't believe you, because I've worked on a team that pushed out releases every two weeks, and got 8-9 days development in for each.
That's what I meant - should have said interface_s_, I see now :)
Actually, opening a document is probably not even a good abstraction. DocProvider is better: You can have FileSystemDocProvider and BlankDocProvider - the latter can't meaningfully be said to "open" a document, but it's interacted with in the same way.
(1) The "Java Bean spec" is not closely followed for precisely this reason. Technically it requires setters for all attributes but in practice many libraries (certainly Spring) permit initialization via the constructor and treat getters as sufficient.
(2) Because of (1) constructors are indeed still used. In fact they're very actively preferred because IF you use the constructor then all immutable attributes can be declared final making the compiler warn you of unintentionally altered state.
(3) I violently disagree. Vast interfaces are a code smell and would fail code review in every team I've ever worked in. If you can't do this then odds are in a deficiency not in the principle but in your understanding of the domain.
(4) Sounds like a problem with your process not the principle.
> Are constructors still used? All services are wired using dependency injection. Models are either DTOs or Hibernate POJOs - both dumb and anyways don't do any work.
Guice encourages constructor injection.
> 3. Program to small interfaces:
> Interfaces are dictated by functionality they provide and not size. They can have hundreds of methods. This is how it looks: DocumentService - put every document related method in here, FinancialInstrumentService - put every instrument related method in here
Surely, by the point you reach hundreds of methods, you can refactor your service into several different, smaller services.
"Interfaces are dictated by functionality they provide and not size. They can have hundreds of methods. This is how it looks: DocumentService - put every document related method in here, FinancialInstrumentService - put every instrument related method in here"
Then what is the point of having interfaces at all?
There is no way multiple implementations will be created for such interfaces, so just make it a single class and be done with it. Otherwise, you are missing the whole point of an interface.
I guess the exceptions are proxy objects and other such patterns, but Java makes it difficult to implement such patterns without explicitly implementing each method to forward the exact same call to the delegate.
"Models used in client server communication need to follow Java Bean spec which is like the exact antagonistic concept to immutability."
I agree, and believe the wide adoption of Java Beans marked the end of any real application of object oriented principles in common enterprise Java development.
Public access to all state through setters, and no encapsulation of state in your data model. This is utterly antithetical to object oriented programming principles.
1. Use immutable values:
Models used in client server communication need to follow Java Bean spec which is like the exact antagonistic concept to immutability. Service methods that implement business logic are stateless. As objects are not shared across threads, nobody feels the need for immutability. The most popular frameworks Spring and Hibernate dictate this architecture.
2. Do no work in the constructor
Are constructors still used? All services are wired using dependency injection. Models are either DTOs or Hibernate POJOs - both dumb and anyways don't do any work.
3. Program to small interfaces:
Interfaces are dictated by functionality they provide and not size. They can have hundreds of methods. This is how it looks: DocumentService - put every document related method in here, FinancialInstrumentService - put every instrument related method in here
4. Represent computation, not the world
Almost everybody begins OOP with this misconception - objects in real world directly map to OOP objects. Its maybe a good place to start but how many grow up from the initial simplistic rule - map nouns in requirements to classes. So, you end up with objects that don't really mean anything and don't do much. Naive use of UML diagrams also leads to this. Discovering abstractions is tricky. One needs to really live with requirements inside out before they present themselves. Who has so much time? Believe me in a quarterly release- developers get around only 3 weeks – rest is divided into BA, QA, UAT, freeze, deployment time.
PS: Please don’t get me wrong OP makes good points. It's sweet but the reality is different. May be Google does this (and they do in Guava which is just an example one after another of good stuff in Effective Java). But there's a big corporate java world out there that does things differently. They have well defined easy run of the mill patterns where these things don't fit (yet). This was just a peek into it.