Parallel Development in Drupal With This One Trick
Little tweaks to make Drupal development easier
July 23, 2016
Being in different projects and roles is fun. I get to try every technology I can get my hands on. The goal is not just to get a finger on every pie, it's also to accumulate knowledge of what works, what doesn't and when, and apply improvements in other projects or projects to come. But if there is one thing that still eludes me, it's how to efficiently do Drupal development in a multi-developer team. More is merrier, but not without some challenges.
Inefficiencies in workflow
The first problem to tackle is the fact that Drupal's admin is too involved with the UI. I don't blame Drupal, it's a CMS after all and a damn good one too. But it often gets in the way with custom development. Admin configurations dictate markup but a slight misconfiguration can break the UI.
As a side-effect, developers tend to work on features back-to-front, configuring the feature in the admin in the right way then polishing the UI to a shine. This is inefficient because 1) there's too much context switching, and 2) the UI is still tightly coupled to volatile configuration.
Another side-effect is the sequential development that it causes. Styles depend on the markup generated, but markup depends on the field's configuration, and you can only configure a field when it's present (duh!). This forces the workflow in a sequence of field creation -> field configuration -> markup -> styles. What this means is that the task cannot be broken down, done in parallel and by multiple developers.
Another problem is the nature of iterative development. Without a broader knowledge of the entire application, developers will tend to write functionality specific to a task. When a similar piece arrives in the queue, one cannot easily reuse code without tearing apart the existing functionality. This is inefficient because 1) of the tightly-coupled nature of the code and 2) it's inducing unnecessary regression.
Step 1: Strip Drupal of its rendering authority
Let's say you want to add a field in your data that represents color. The Color Field Module is the perfect module for the job. However, the field it supplies only renders the color as a CSS class or as text in the form of the color's hex code. Sounds useless right? That's only because you're limiting yourself on what the module did out of the box.
The data is there and it's provided to the template in its raw form. All you have to do is step away from the out-of-the-box rendering options and consider other methods of representing that data in the UI. For instance, you can get the the hex code from the data, override a template, and use that hex code in something like an inline style, or as an argument of a template function for further processing.
You're essentially stripping Drupal's authority on rendering, turning it to a mere data model and storage. If you think about it this way, you can model data in Drupal without worrying how it will look like in the UI. In the same way, you can write the markup and styles without worrying how it is configured in the admin. As long as they agree on what data should appear, these tasks can be done in parallel. Furthermore, the UI need not be designed by a Drupal developer.
Step 2: Taking back control of rendering
Drupal generates markup in a prescribed and predictable manner. For instance, you want a piece of data that puts a quote, the source, and a picture. Without rendering modifications, the markup that Drupal generates out-of-the-box to represent the 3 pieces of information looks something like the following.
<div class="content">
<div class="field-name-field-quote-text">
<div class="field-label">
<label>...</label>
</div>
<div class="field-items">
<div class="field-item">
<span>...</span>
</div>
</div>
</div>
<div class="field-name-field-quote-source">
<div class="field-label">
<label>...</label>
</div>
<div class="field-items">
<div class="field-item">
<span>...</span>
</div>
</div>
</div>
<div class="field-name-field-quote-image">
<div class="field-label">
<label>...</label>
</div>
<div class="field-items">
<div class="field-item">
<img src="...">
</div>
</div>
</div>
</div>
This is great if you are only giving the markup a "retouch", sprinkling styles using the provided classes. But for heavily customized layouts, you cannot work with this markup; it will just get in the way. In most cases, you will want to work with a specific structure particularly in cases that require floating and positioned elements. Also, the classes and attributes are derived from configuration. Using them would be tantamount to submitting yourself to Drupal's control.
To break free of Drupal's authority, you will have to construct your own markup that satisfies the job. You will have to override specific templates and position fields in their respective places. Given the requirement, you probably only needed the following.
<div class="quote">
<div class="quote__body>
<blockquote class="quote__text">...</div>
</div>
<div class="quote__footer">
<img class="quote__image" src="...">
<cite class="quote__source">...</cite>
</div>
</div>
Step 3: Giving structure to CSS
Unlike programming languages, where architecture is introduced early on to give structure to code, structure is a hindsight in the world of CSS. We all write CSS blindly, conjuring up selectors until something works and then cry when an unrelated CSS hit your markup dead-on due to naming collision and was more specific. I bet at one point you have written CSS that looks as ungodly as the following.
// Pseudo-content in a large screen only on a hovered cite in a quote section under a slice
.content{
.field-name-field-quote-source{
span{
&:hover{
@media (max-width: 768px{
&:after{
content: 'WTF!';
}
}
}
}
}
}
One of the big names in CSS is the BEM naming scheme. I won't explain too much about BEM, read the documentation instead. In a gist, BEM makes you write structured, predictable CSS eliminating the fear that modifying CSS might break something somewhere. It may look fugly (like all other frameworks), but maintenance becomes a breeze once observed correctly.
// Base styles for a quote component's source
.quote__source{
// styles when on mobile
&:hover{/* styles when hovered on small screens */}
@media (min-width: 768px){
// styles when on a larger screen
&:hover{/* styles when hovered on larger screens */}
}
}
// A modifier style which overrides the previous
.quote__source--huge{
transform: scale(2);
@media (min-width: 768px){
transform: scale(3);
}
}
<div class="quote">
<!-- regular-sized source -->
<cite class="quote__source">...</cite>
<!-- super-sized source -->
<cite class="quote__source quote__source--huge">...</cite>
</div>
Conclusion
So in summary:
- Decouple data from rendering.
- Don't rely on volatile configuration.
- Render sane markup.
- Give structure to CSS.
- Stick to convention.
- Keep everything predictable.
That pretty much sums it up. Hopefully this helps you in your adventures. The last thing we need in this world is FUBAR code, and another refactoring session.