µObjects: Being Assertive
Being assertive is about being self-responsbile. Being assertive is about an object being lazy.
This also has the object doing all behaviors for the state it holds. It follows from encapsulation that an object will be assertive.
How do µObjects encourage this? µObjects do a single thing, and you need to ask them to do it. If an object never returns anything it holds; it's pretty damn assertive you need to go through it.
µObjects are asked to do something
The simplest aspect of being assertive is to never give away your information. The state of a µObject is inaccessible. No one else gets to touch it. If they want something to happen; they ask the µObject to do it for them. That's an assertive µObject.
µObjects manage their own dependencies
One of the things around µObjects that I've not really seen in other styles is that they manage their own dependency injection.
Most µObjects are initialized through an empty constructor (C#/Java) and they will new up the objects they need and pass it along to a fully interface param constructor.
The Primary Constructor (from Elegant Objects) only has interfaces. The Dependency Constructor is where the concrete instance is instantiated. This gives the object full ownership and control of everything it needs to do to do it's job.
The power of this comes through when refactoring. If what the object needs to do it's job changes; like when refactoring to encapsulate relationships between arguments; then many objects change because this one object changed what it's passed. While in staticly typed languages, this is kinda requirement of compile time... We can break free of that. We can have the object; who is the very best at know what is needed; control all of the instantiation for what it needs.
The µObject manages it's own dependencies.
µObjects do not return state
µObjects follow the style of Object Oriented Programming where they do not return a reference they hold. This prevents any getter/setters. Yes; There's a lot of ways around this. µObjects do not return what they hold. If I hold a string; it doesn't matter if I make a new string to hold the same data - It's a getter. That's returning state.
The idea is to never return your state; if you are - Your design is wrong. Do I expect it to never be wrong? Nope. My production code has a number of instances I don't have a work around to returning state. It happens; it's wrong; it smells. Let it smell. Don't mask the smell, embrace it. Recognize it and let it eat at you. Let returned state be your waking nightmare! Find a way to resolve it!
µObjects prevent tight coupling
By being assertive and being asked to perform something, two objects will not become tightly coupled. You can't break if I change a data type from double to int when all you can do is ask me to calculate something. I handle that change. You remain ignorant of the how the result is calcuated.
If the behavior is done through getters, then a change from int to double will break the calculations you do.
Possibly uknowingly due to boxing.
This is the avoided risk by preventing the tight coupling; subtle language "helping" bugs are not encountered.
µObjects limit change impact
µObjects know how to ask for behavior, not data. This modeling of interaction between objects; as well as through interfaces; seriously limits how sprawling a change can be.
At work; it took a refactor of how resources were retrieved to affect a lot of classes. I think over 100 were impacted. We had a ResourceKey and a ResourceLoader. We didn't refactor this relationship when we first saw it. When we got to it; the pattern had infested a lot of the code base.
Once we refactored it: Tests simplified. Constructors simplified. The code became simpler. Now if we refactor how resources are loaded - It's entirely limited to the new Resource class. This is how objects being assertive can limit impact to the code when changes are required.
We were not treating the Resource with respect. We literally didn't acknowledge it existed. That's how disrespectful we were to it. Once the µObject of Resource existed; it asserted itself and the code changed around it; for the better
Refactor often, refactor early, refractor ruthlessly. It might open up different refactor opportunities for more ways to simplify the code.
µObjects shows new µObjects
The example of the ResourceKey and ResourceLoader are a perfect example of how µObjects show us the new µObjects that need to exist. We need to listen to the code and follow what it shows us.
The µObject push to do only one thing helps limit what's happening in a class. Limiting what's happening in a class helps us see relationships. It's these relationships that need to be turned into new objects.
The µObject assertiveness is what showed us this relationship. We were telling the ResourceLoader, "Take this, and give me associated data". It looks like a behavior; but it took input. It didn't KNOW what it was doing. It was a dumb pipe; data in -> data out.
This isn't respectful to the object at all. It's not an assertive object.
With the refactor to a relationship that encapsulated the ResourceKey and ResourceLoader; the Resource. Then we ask the resource; "Can you retrieve your resource string for us?" We don't tell it, "Give me the resource for this key".
This view of objects can be subtle, takes practice. Once you start seeing it, and cleaning it up; the code that results is much more maintainable.
Summary
µObjects encourage assertiveness. There's no way around having an assertive object when applying the µObject principles.
The focus on behavior for interaction keeps the object assertive.
The focus on behavior and maintaining an assertive object is going to go a long way towards having maintainable code.