For consistency with FieldDefinition classes and improved DX I think the ContextDefinition class should not have a constructor with many argumetns. Eg. instead of
new ContexDefinition('string', t('A string'), FALSE, FALSE, t('Some description'))
one should use the more explicit and easier to read:
ContexDefinition::create('string')
->setLabel(t('A string'))
->setRequired(FALSE)
->setDescription(t('Some description'));
Then for consistency, I think we should always use ContexDefinition::create(), which in contrast to the constructor allows calling methods on the returned object. We could even opt to make the constrcutor protected to discourage its usage.
Tasks
* Replace all usages of the constructor with ContexDefinition::create()
* Make the constructor private?
Comments
Comment #1
eclipsegc commentedThe setters did not go away. This just allows for constructors to be used. I don't see a reason to remove this as it makes it easier for certain things (annotations) to use the class, and it doesn't inhibit the way you've used it elsewhere. Constructor injection has been preferred at almost all stages of Development during this cycle for good reason. I don't see any reason to change that approach for this class.
At the same time I don't see the need for the static create method on this class at all since:
a.) it conflicts with the more common use case for that method name (i.e. injecting services into a class)
b.) It doesn't actually do anything for us that cannot already be done via the constructor or the existing setters.
That being said, I didn't see a reason to go removing it either since this is a paradigm you seem to have adopted for these *Definition classes. I understand your reasoning around it returning the object, but that's a lot of extra code for setting parameters that I exposed in the constructor already. I really don't see any reason to use this. It's not a better dx.
Eclipse
Comment #2
fagoI do think it's better DX,
what are the parameters for? What does FALSE, FALSE mean? You either have to recall the argument ordering or look up the docs - the other variant tells you that without having to know or to look up anything.
There are no injected dependencies, but values set on a value object. Different case. We already follow the setter approach for field definitions, thus I see no reason to change the approach for ContextDefintion ;)
Comment #3
eclipsegc commentedYes, and the only system that is ever likely to use it is the existing annotation, in which the setters would be markedly more difficult to use than a simple variable pass through like it is now. I did not remove the ability to do the static calls + methods you're used to, please don't remove the constructor arguments that are optional and make my life easier. This should have 0 impact on your normal approach.
Eclipse
Comment #4
fagoIf the annotation only works with those constructor arguments, it misses the possibiltiy to set all the remaining stuff on the context definition.
I don't think it makes sense to have to different approaches flying around in the code base + in documented APIs as it is potentially confusing: which variant should I use when? The more it becomes confusing when people find both variants flying around.
Comment #5
eclipsegc commentedThe Annotation class has to expose this this way for the actual annotation process. Having the class it instantiates have the same constructor seemed obvious to me. This keeps the use case the same whether using an annotation or instantiating the class manually. As it stands, the code couldn't be simpler in terms of instantiating a new ContextDefinition from the annotation. Your proposal would complicate that unnecessarily, and currently the class doesn't require any of those constructors. I don't see a reason to go changing it. It's nice for Annotations, your normal process still works, and this is deep enough in the guts that 99% of devs will never see it. The 1% who care to use this are going to get what's going on and why with very little in the way of explanation.
Eclipse
Comment #6
klausi@fago: I'm not sure we need a static create() method - you can do your improved DX with the constructor already?
Should work just fine?
I also does not help as for Rules development where we have to do ugly stuff anyway to convert context definitions from configuration arrays to objects:
So what we actually need in Rules is a method createFromDumbArray() on the ContextDefinition object.
Comment #7
fagoNope, not for me. Maybe it's php version specific?
In regard to the array problem - yeah, agreed. To me, the following would make sense:
ContextDefinition::create($type)
ContextDefinition::__construct(array $values)
ContextDefinition::toArray()
So the constructor is as powerful as possible, while other static methods can provide decent DX for the 90% usages. Alternatively, we could just add ContextDefinition::createFromValues() or so.
Comment #8
eclipsegc commentedI'm not really excited about the idea of having an array of keys this class expects through the constructor. Having explicit parameters is a lot more clear.
Eclipse
Comment #9
fagoAgreed, but having a looooong chain of explicit parameters sucks and isn't good DX either. That's why you use setters instead when you want to specify it per parameter.
Comment #10
eclipsegc commentedWhich is why all except for the type are optional.
Comment #11
diego.banchero commentedComment #12
diego.banchero commentedhttps://github.com/fago/rules/pull/246
Tester passing, waiting for merging.
Comment #13
klausiThanks, merged that into Rules. But for Drupal core I think this is won't fix otherwise, per Eclipse.
Comment #14
eclipsegc commentedFWIW, I don't think Rules should do this either as it makes your ContextDefinitions mutable... can you imagine someone changing that downstream in the middle of a Rules execution? Bad mojo.
Eclipse