- Published on
Development best practices learned from the Drupal Dev Days Seville 2017
- Authors
- Name
- Christophe Jossart
- @colorfield
Freshly back from Seville, with so many in my suitcase! Thanks to the organizers and the community for this great event!
This is the first article from a serie of five, the next ones will be :
- Unit Tests and Continuous Integration
- Components and Styleguide
- Composer and Configuration Management
- Headless and Mobile
Many session were oriented towards coding attitude.
It looks like we now have the time to let the technical specs of Drupal 8 a bit behind and focus on sharing developer experience.
This article is a summary of the following sessions:
- A Cautionary Tale for Defensive Programmers by Xano
- Don't just upgrade your module to Drupal 8, modernize it by hussainweb
- Commerce 2.x: Lessons learned by bojanz
- Development efficiency by harings_rob
I will begin from the more general (attitude) and end by the more specific (coding with D8).
Do not make assumptions
- Educate your client to phrase requirements.
- Do not make assumptions: know what you have to do or don’t do it.
- Plan the implementation, a good preparation is half the work done.
- Keep it simple: any new feature must be tested and can introduce bugs.
You and your team
- Explain your issues… even to a rubber duck : ) phrasing issues will help to solve them partially.
- Do not depend on your colleagues too much, one day they will leave, and it is much more valuable to solve your issues without relying too much on the others.
- Avoid interruption: recovering a 5 minutes interruption = 1h to get back to full code productivity. Also disable as many notifications as you can (mail, Slack, Trello, ...).
Your environment
- Work on a clean desk, avoid a cluttered desktop, just get the windows you need to code.
- Let printed cheatsheets close to you, they will not take space on your desktop.
- Have a good IDE: it knows much than you and you have to know it.
- Use your debugger, it saves a lot of time at short term. It avoids print - refresh - delete flow (and also avoids to let debug message in your code). Debugger provides full context in your IDE, and you keep looking at the code.
- Use tools that can automate but do not depend on them (phpcs, CI).
- Enforce coding standards on build (CI).
- Have a good workflow: run tests instead of manual testing. One more time... stay focused on the code.
- Listen to support requests, if many similar feedback are coming to you, turn it into a bug report or into documentation.
Coding attitude
- Code a mess without having any other idea than the solution in mind, then iterate and improve, then look at the standards. Do not try to be perfect at the first time.
- Start over, get new ideas.
- When you are satisfied, clean up.
- Keep standards high, pressure is not an excuse for bad code. Explain to the commercial staff the meaning of technical debt.
- Keep quality under pressure, test every possible scenario.
- One is a special case of many: cover the exceptions early and foresee many.
Developers spend more time reading code than writing
- Make your code readable, avoid nested conditions or any other difficult structure to grasp.
- Refactor continuously: apply what you’ve learned and make the code easy to read and to test.
- Document the why and not the what.
- Create higher level docs. Try to put the description on top, at the entry point. Do it on the interface and do not force to gather several classes documentations to get the idea.
- Dependency injection quantity acts as a code smell: too many or too few (one method per class) means needed refactoring.
Fail early, loudly and often
- Throw exception when you do not have to handle what needs to be covered by the client class (« do not babysit broken code »).
- When you catch, catch only what you can handle.
- Harden entry points: put a priority on handling errors in public API’s, this will avoid hassle to other developers.
Use constraints
- Validator component (Symfony).
- Static schemas (json, xml, …).
- Whitelist / blacklist (enum, dynamic lists).
- Type checking function in function signature (give a try to PHP7).
Object Oriented programming
Drupal 7 had cyclomatic complexity, so it was really hard to test because of too many control points (example: the deprecated drupal_http_request).
This kind of complexity introduces Spaghetti, Lasagna and Ravioli code.
While coding with OO, keep this in mind:
- Map the problem domain, use it to define players and pass messages to players.
- Don’t be that afraid of static classes: helper code that does not have dependencies (no need of injection), are sometimes a candidate for static.
SOLID
Common guidelines:- Single responsibility.
- Open for extension closed for modification (don’t hack it).
- Liskov substitution: objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
- Interface segregation: many client-specific interfaces are better than one general-purpose interface.
- Dependency inversion: one should depend upon abstractions, [not] concretions.
- ... and still: beware of the S in SOLID : do not fall in the case of a method per class.
Use value objects
- As return values: useful instead of plain arrays, because they can be validated and documented.
- As field values : on field type/value, to avoid many duplication (example in Commerce: value object for the field value for PriceItem that extends FieldItemBase: $values are instance of Price).
Test driven development
This will be much more described in a following post, but here is a preview...
Now that we have the benefits of OO for testing, let’s use test !
- Most of the time, the same people wrote the test and the code, so it can be wrong. But... it is not an excuse to avoid them, because test will still be useful to avoid regression. This is really the reason #1 to write test and keep confidence between the development team and the product owner.
- That said, a good test provides no logic: it only checks expected output for an input.
- Well tested code is easier to refactor and to maintain. So it will evolve much more quickly.
Drupal 8 specific advices
- FormElement is more generalizable than FieldWidget (that only applies to Entities). Examples in Commerce: Address, CustomerProfile, Payment Gateway extends FormElement.
- Drupal primary target is developers, that will collaborate with the product owner:
- Use bundle plugins instead of a configuration entity.
- Too many settings equals no settings: use less UI’s, and do not use them for the less used case.
- Use more Twig instead (token in UI's cannot iterate and hold conditions). Example: instead of config for emails, provide a template, a site builder should still handle this.
- Use more YAML instead. Example: designing a workflow is a developer concern: staying in the code makes sense.