Misko Hevery wrote:Mixing Service Objects with Value Objects: There should be two kinds of objects in your application.
(1) Value-objects, these tend to have lots of getters / setters and are very easy to construct are never mocked, and probably don’t need an interface. (Example: LinkedList, Map, User, EmailAddress, Email, CreditCard, etc…).
(2) Service-objects which do the interesting work, their constructors ask for lots of other objects for colaboration, are good candidates for mocking, tend to have an interface and tend to have multiple implementations (Example: MailServer, CreditCardProcessor, UserAthenticator, AddressValidator).
A value-object should never take a service object in its constructor (since than it is not easy to construct). Value-objects are the leafs of your application graph and tend to be created freely with the “new” operator directly in line with your business logic (exception to point 1 since they are leafs).
Service-objects are harder to construct and as a result are never constructed with a new operator in-line, (instead use factory / DI-framework) for the object graph construction. Service-objects don’t take value-objects in their constructors since DI-frameworks tend to be unaware about the how to create a value-object.
From a testing point of view we like value-objects since we can just create them on the fly and assert on their state. Service-objects are harder to test since their state is not clear and they are all about collaboration and as a result we are forced to use mocking, something which we want to minimize. Mixing the two creates a hybrid which has no advantages of value-objects and all the baggage of service-object.
Jesse Silverman wrote:You really don't need to be creating factories for your Injectables, you leverage what your framework gives you and go with that.
For "Value Types" or "Newables", you should *not* be trying to inject those
Lastly, there seems to be a third category of "Entity Types" that are still "Newables".
Stephan van Hulst wrote: At the end of the day, dependency injection is really just passing an argument to a method or constructor that needs that thing to do its work.
I couldn't. Just can't think of many common cases where I need to do so.
Stephan van Hulst wrote:
When you take this perspective, what is wrong with passing a "newable" or "value type" to a method or constructor that needs it? Can you quote an argument against doing so?
Amended. When the target is shaping the source, it's not IoC, it's Service Locator (or worse, service construction).
Stephan van Hulst wrote:
The inverse is true however: "Injectables" or "services"
shouldmust not be created by the method or constructor that needs them. They must always be injected. Instances of service types are either provided to the dependency injection framework by configuring fixed instances, or by configuring factories or providers.
Stephan van Hulst wrote:
Entities usually have an "id" field (or a set of fields that together make up the identity of the object), or they are identified by associating them with an external identifier (such as their memory address, or by putting them at a specific index in an array, or by associating them with a specific key in a map). Entities may or may not be mutable, and they generally should NOT have their equals() method overridden. An example of an entity is an Employee. Two different employees may have the exact same state (name, age, salary, etc.), but they are not equal to each other. If an employee has an internal field that identifies them (such as an employee number), then if you have two different instances with the same employee number, you should still not treat them as equal, because having two different instances with the same identity is usually an indication that your application is bugged. It usually means you retrieved an object from a database twice during the same request, or you cloned an object when you really shouldn't have. Think of it as a case of identity fraud.
People often make the mistake of overriding the equals() method for entity types. Sometimes this is even allowed or encouraged by the persistence framework. Do not fall for this trap. It almost always leads to bugs where you think two objects are equal, set the properties of the wrong one, and then overwrite a database record with inconsistent data. Even if you decide to override Employee.equals() so that two employees are only considered equal when ALL of their state (including an internal identifier field) are equal, what does that bring you?
And finally, not all database tables have any defined key fields at all. SQL not only doesn't require it, keys and indexes are not part of core SQL at all. Granted, a table without keys can be a royal pain to work with, but it is allowable.
Jesse Silverman wrote:Anyway, away from SQL a bit, for people doing Modern Java, does it makes sense to focus more on Hibernate? JPA itself?