Wim Leers
@wimleers
wimleers.com
Principal Software Engineer, OCTO,
Things I learned so I know slightly better what I do not know
I'm responsible for the π & π.
My analysis in a nutshell
can be used for anything!
β¬
All code must have an API to be generic & overridable
but not enough time to carefully design every API
β¬
Overengineered
β¦ yet underengineered!
β¬
BC = nightmare. Let's get better.
BC = promise of updating without problems
Q: Why does Drupal have so many APIs?
A: Optimized for targeted overrides
β granular APIs
β many, many APIs
Drupal allows you to replace a particular leaf.
Others require replacing a branch or even tree.
Drupal has 3 types of APIs
d.o/core/d8-bc-policy: @api
vs @internal
But in Drupal coreβ¦
@api
@internal
99% "undocumented"
β 99% considered API
The API assumption
Part 1: Accidental API
Example of an accidental API
Every class must have an interface
Issue #2266809: Make QuickEditEntityFieldAccessCheck::access() use the $account that's passed in
* @param string $field_name
* The field name.
+ * @param \Drupal\Core\Session\AccountInterface $account
+ * The user for which to check access.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
- public fn accessEditEntityField($entity, $field_name);
+ public fn accessEditEntityField($entity, $field_name, AccountInterface $account);
}
(Introduced by yours truly in #1824500: In-place editing for Fields
on Dec 21, 2012.
Suffering the consequences >4 years later.)
Poorly designed APIs make BC very difficult
Prefer duplication over the wrong abstraction
API when:
Little work + high complexity (granular APIs)
vs
More work + low complexity (duplication)
Part 2: orthogonality
β using Entity API === using >10 APIs!
NodeInterface $node
1. NodeInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface, RevisionLogInterface, EntityPublishedInterface
2. ContentEntityInterface extends \Traversable, FieldableEntityInterface, RevisionableInterface, TranslatableInterface
3. FieldableEntityInterface extends EntityInterface
4. EntityInterface extends AccessibleInterface, CacheableDependencyInterface, RefinableCacheableDependencyInterface
FieldableEntityInterface::get()
aka $node->get($field_name)
1. FieldItemListInterface extends ListInterface, AccessibleInterface
2. ListInterface extends TraversableTypedDataInterface, \ArrayAccess, \Countable
3. TraversableTypedDataInterface extends TypedDataInterface, \Traversable
4. TypedDataInterface
AKA a rabbit hole
REST
module: Taxonomy term REST responses don't list parent term, because:Taxonomy
module does not define parent
the proper way in Entity
API, but cannot be fixed because:Views
module breaks for multi-value base Fields on EntitiesAKA a deep rabbit hole
Massive composition & long inheritance chains require massive knowledge
Part 3: assumptions
X
X
X
Y
Breaks when advagg
is installed π
$request = $this->requestStack->getCurrentRequest();
$link_headers = $request->attributes->get('http2_server_push_link_headers', []);
foreach ($elements as &$element) {
+ if (!static::isLinkRelStylesheet($element)) {
+ continue;
+ }
+
// Locally served CSS files that are sent to all browsers can be pushed.
- if ($element['#tag'] === 'link' && $element['#browsers']['!IE'] === TRUE && $element['#browsers']['IE'] === TRUE && $element['#attributes']['href'][0] === '/' && $element['#attributes']['href'][1] !== '/') {
+ if (isset($element['#attributes']['href']) && static::hasRootRelativeUrl($element, 'href') && static::isUnconditional($element)) {
$link_header_value = '<' . $element['#attributes']['href'] . '>; rel=preload; as=style';
$link_headers[] = $link_header_value;
Make assumptions explicit
even better:
Test assumptions
REST + Serialization
REST in Drupal 8.0.0
REST module: what + API?
Wim in 2016
No more incomprehensible errors, nor BC breaks!
π΅ "serialization gaps" π΅
Response === API β extreme care
When API surface is great, test coverage must be greater
and
Clearly define what isΒ an API (and hence BC guaranteed)
BigPipe + Dynamic Page Cache
Dynamic Page Cache: what + API?
X-Drupal-Dynamic-Cache
response headerBigPipe: what + API?
Surrogate-Control
response headerTry hard to not provide an API
(Then BC is kept as long as functionality works!)
Contrib: organic feature growth
Hierarchical Select 7.x-3.0
CDN 7.x-2.9
CDN 8.x-3.0
Functionality first, API later
or@internal
first,@api
later
Prefer duplication over the wrong abstraction
Test 1) critical path, 2) edge cases, 3) assumptions
(especially for APIs)
π