Setter anxiety
Sometimes sudden (or slow) realisations can wreak havoc in ones mind. I've always (since long?) been a a proponent of constructor injection for dependencies. On the other hand I was not unused or diametrically opposed to constructing objects with their values usings getters and setters. But now, these setters scare me. I'm suffering from setter anxiety.
Observe the following code
class Product { private $id; private $title; public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } public function setTitle($title) { $this->title = $title; } public function getTitle() { return $this->title; } }
I used to be pretty much okay with this, right now it terrifies me (artistic exaggeration included). Ask yourself the following questions:
- What guarantees that a Product is always in correct state? Sure you guaranteed it for the locations you now use it, but what if you missed one? What happens when your colleague uses Product next?
- What tells you what Products correct state actually is?
- Why would it be okay to not know the answer to the above two questions?
I hereby solemnly vow to always write product as follows:
class Product { private $id; private $title; public function __construct($id, $title) { $this->id = $id; $this->title = $title; } public function getId() { return $this->id; } public function getTitle() { return $this->title; } }
This is a simple example, this post was triggered by an object that had about eight properties of which some where required, some were not and one was calculated externally and injected in the service that stores these objects and all this state was guaranteed by chance. If that does not sound as bad modelling to you you're lost :P
Had I started modelling without setters it would never have ended up like that, there would simply have been no way for me to create the chaos.
Yes, I quoted myself :p
Lets all start suffering from setter anxiety!
P.S. This blog is a try-out. Shorter braindumps, possibly less well thought trough. I do this because a lot of posts stay stuck in conceptualisation fase :)
Comments
-
And maybe you don't even need all those setters. You might have behaviour that describes the processes better and need the data and there is no need to make it public.
But maybe I'm wrong. It is just a thought. -
Would you add only required fields to the constructor, or optional ones as well?
What makes this state more correct than the ones that still have null-attributes? Define good state.
You can still add null values to the constructor. I presume these lead to exceptions?
I don't mind being lost. I like to think that every modelling scheme has its own context and that no technique is always right. And I disapprove of suffering, but that's just me :)
-
First of all, I would assume needing optional values is a modelling problem. Maybe there is no Product with an optional Price (as an example) but a Product and a SellableProduct. SellableProduct is a poor name, but you'll get the idea I presume.
-
I suffer this thought. I think should setters can help with refactoring and working.
If you put more checks into your setters you can then save yourself inside the object having more repeated if statements.
So $product->sizes can in $product->setSizes($size) check for it being an array or maybe an object and certain keys and return false if not, so you only need to test for true and false outside.Maybe the angst is just a natural and good conditioning to make us fear adding too many properties to an object. There by getting us to evaluate after 5 or 10 if refactoring is needed?
Still not a solved question though, just one to be consistent on.