Represent All Concepts
Let's continue our exploration of how the MicroObjects technical practices support the principle of representing all concepts that exist in the code as objects in the code.
In the last post we covered
- No Getters / No Setters
- if Only as a Guard Clause
- Isolate Their Code
Interestingly these are the only points I cover in the hour long presentation of these practices. :)
The Practices (continued)
As I wrote in the email to my colleague, This is a special case of representing all concepts. A
null MEANS something. There's a reason we have a null; that situation is a concept that exists in our code - Represent that concept. If we ask for a file and get
null - Is it not found? Do we not have permissions? Is it exclusively opened by something else? If these have different behaviors; then they are different representations. We typically throw exceptions for this - Even then, exceptions are behavior representations. Those should also be represented, but that's not this point.
null has associated behavior. Represent that concept by creating an object for those behaviors.
No new Inline
(I'm still trying to find a better phrasing for this)
It's harder to do composition when a code is creating all of the objects it wants to interact with. It's harder to create representations for all of the concepts when code creates the objects that may need to be different.
It's harder to create new representions when we can't easily replace implementation details. Not instantiating the objects in the code flow they are used enables us to more readily change objects that logic uses, allow us to create more representations that exist in our code, with much less work.
This one is a little weaker for the representation of all concepts; but it's going to be very hard to go very fast in the creation of related concepts without this practice.
Composition, not Inheritance
I've found that the behaviors represented by the base class can usually be refactored into representations (yes, plural) of the specific concepts. A base class obfuscates conceptual representations in the code. The interactions between the derived and the base class are concepts that are missing in our code.
Using inheritence makes it harder to recognize and extract (see Extract Cohesion) the concepts that exist. This is the key point of the idea to "Represent all concpets".
The concepts exist in the code. They are there. I'm asking for them to be explicitly represented.
Inheritance hides these concepts. Composition exposes them. Composition, not inheritance is how we can better represent the concepts that exist in the code.
I'm not going to try to shoe-horn this one in. It might not apply to the idea of Representing All Concepts. I don't have a solid argument for it... yet.
I suspect that anything causing mutability could be represented by a new concept... I don't know. My implementation of these practices have been immutable, so that's the space I'm familiar with their construction.
The foundational example of representing concepts in code. An
int value is something. It's intended to be used in a specific way. No Primitives is the primitive form of "represent all concepts". That's what this is.
Using this as a specific approach to "represent all concepts" enables us to start to see value quickly from encapsulating behavior in a concept. It makes it easier for us to ensure we're doing the right thing. Minimize the need for defensive coding. The defense is handled by the type system of a compiler. A bias from working in statically typed languages.
Once we have the basic data blocks represented, the value of representing concepts starts to emerge. It's where it started for me.
This is really "Create the representation of the concept". When we're extacting cohesion; we're extracting a relationship of concepts. These concepts interact in a given way, which is itself a new concept. Extract cohesion is creation of a concept that exists in the code. We recognize the concept, encapsulate the concept, and give it a name.
No Public Statics
One of the more challenged ideas. One I don't press much. There's other bigger impacts to focus on. This is crucial though. The public static value we're using all over - it's a concept. It's something. This "thing" should be represented by a class.
If it's a static string - What is that string? A display message? A resource key? A state indicator? What is it? What's the concept that it represents? It represents SOMETHING. Identify what it IS, give it form, give it a name. When you use a static value in multiple places, are those places related? They're using the same thing; what's the connection? Is there a concept around the use that's waiting to be discovered?
using public static values prevent concepts from being in our system. They force us into imperitive programming. These are concepts in our code, we need to represent them.
With the sub-title of "Or type inspection". Just don't. This isn't a practice that helps drive towards conceptual representation; but it's a practice that's absolutely destructive to the sytem.
These aren't all of the practices. The link to the microObjects practices has some more.
- No Logic In Constructor
- No Switch or Else
- Interface Everything
- No Enums
- Manual Dependency Injection
These aren't ALL of the things I do. I'm working on extracting all the tiny things and getting them documented. The ones I'll talk about here are the big ones. Things I think have the largest impact are what I've really been focusing on. All the little details will be documented in time. But let's look at the big impact on representing all concepts.