An Agile Front End Workflow

Eric Smith

@ericgsmith

Project Timeline

Ticket Workflow

The old way

The Process Problem

  • Development is a bottleneck
  • Theming at the end creates pressure

The Historical Problems

  • Drupal - A million ways to die
  • CSS is a one man game
  • Hell is other people's CSS
  • Adding things to the end of stylesheet
  • Time taken to deliver a page that looks the same
  • Onboarding time for new developers

The Target

  • A development team not an individual
  • An efficient workflow
  • Deliver amazing results and value each sprint

Where to start?

Sprint 0

  • Theme setup
  • Drupal's CSS / markup
  • CSS Methodology / Architecture
  • Documentation
  • Automation
  • Assets
  • Testing
  • Definition of done
  • Team structure

CSS Foundations

  • SASS
  • SMACSS / BEM

Coding standards

Drupal has CSS coding standards

The rest of the web has coding standards

There are tools to help you enforce coding standards

Will my team mates understand this?

Documenting CSS

SassDoc

Hologram syntax


/*doc
---
title: Alert
name: alert
category: basics
---
I am a comment
```html_example
I am the example code
``` */

PatternLab

Benefits

  • Visibility within the dev team
  • Visibility for the client
  • You can test the style guide
  • You can theme without Drupal

Doubts

  • Duplication of markup
  • A solution for any project size?
  • Yet another tool to learn

Sprint 1 onwards...

What we did wrong

3 User stories

  • Theme: no dependency
  • Functionality: no dependency
  • Integrate: dependent on both

What we did right

1 User story - up to 3 sub tasks

  • Theme
  • Functionality
  • Integrate

The new way

Theme tickets

  • Look to the style guide for existing styles
  • Estimate new components / prototype

Prototyping inside Drupal

  • Not tied to functionality
  • Designer can sign off mid sprint
  • HTML / CSS is integrated once signed off (and functionality is developed)

/**
* Implements hook_menu().
*/
  function sage_statics_menu() {
  $items = array();
  $items['statics/%'] = array(
    'page callback' => 'sage_statics_page',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
  );
  return $items;
}
                        

/**
* Page callback: Statics pages
*/
function sage_statics_page($page) {
  switch ($page) {
    case SageStatics::PAGE_BOOK_PRODUCT:
    return theme(SageStatics::THEME_BOOK_PRODUCT);

    // etc...
    }
}
                        

Development tickets

(Mostly) Unchanged

Integration tickets

  • Available when theme and dev work is complete
  • Can be shared amongst the team

Option 1: Fuglies


.component,
%component {
  content: 'component';

  &--variant {
    content: 'variant';
  }

  &__element {
    content: 'element';
  }
}

// Fugly selectors.
.my-fugly-selector {
  @extend %component__element;
}
                        

Source: https://gist.github.com/JohnAlbin/b4329a2a4fb4a5caf1f2

Option 2: Preprocessing

AbstractThemeProcessor


abstract class AbstractThemeProcessor {
  /**
  * @var array
  */
  private $vars;
  /**
  * @param array $vars
  */
  private function __construct(&$vars) {
    $this->vars = &$vars;
    if ($this->isApplicable()) {
      $this->execute();
    }
  }
  /**
  * @param array $vars
  * @return static
  */
  public static function process(&$vars) {
    return new static($vars);
  }
  /**
  * @return mixed
  */
  abstract public function execute();
  /**
  * @return bool
  */
  abstract public function isApplicable();
}
                        

Article Processor


class ArticleNodeProcessor extends AbstractNodeProcessor {
  // Example variable.
  const VAR_EXAMPLE = 'example';
  const VAR_EXAMPLE_FROM_NODE = 'example_node';
  /**
  * {@inheritDoc}
  */
  public function isApplicable() {
    return $this->isNodeType(ArticleController::getClassEntityBundle());
  }
  /**
  * {@inheritDoc}
  */
  public function execute() {
    $this->articleController = example_article_factory()->initWithEntity($this->getVar('node'));
    $this->addExtraDisplayItems();
  }
  /**
  * Add extra display items.
  */
  public function addExtraDisplayItems() {
    $this->setVar(self::VAR_EXAMPLE, 'Variable value');
    $this->setVar(self::VAR_EXAMPLE_FROM_NODE, $this->articleController->getExampleValue());
  }
}
                        

/**
* Implements template_preprocess_node().
*/
function example_preprocess_node(&$vars) {
  ArticleNodeProcessor::process($vars);
  ArticleNodeTeaserProcessor::process($vars);ß
  BlogNodeProcessor::process($vars);
  CarouselItemNodeProcessor::process($vars);
}
                        

Both?

Another Problem

"That hover colour isn't right"
"That slide transition is too slow"

Feedback loop

Early Feedback

@todo: TEST!

Questions?

  • Mail: eric.smith@cameronandwilding.com
  • Twitter: ericgsmith

@see: Sass

@see: Design components

@see: Coding standards

@see: Style guides