Lullabot

The Accidental Project Manager: Risk Management

Meet Jill. Jill is a web developer. She likes her job. However, Jill can see some additional tasks on her project that need doing. They're things like planning, prioritization, and communication with her boss and with her client about when the project will be done.

So Jill takes some initiative and handles those tasks. She learns a little about spreadsheets along the way, and her boss notices she's pretty good with clients.

This happens a few times more, and suddenly Jill is asked to manage the next project she's assigned to. A little time goes by and she's got a different job title and different expectations to go along with it.

This is a pretty common thing. As a designer, developer, and especially as a freelancer, you spot things that need doing. Before you know it, you're doing a different job, and you've never had an ounce of training. The best you can do is read a few blog posts about scrum and off you go!

Getting up to speed

As an accidental project manager (PM), you’ll have to exercise a different set of muscles to succeed in your new role. There are tricks and tactics that you’ll need that don’t always come naturally.

For example, most of my early PM failures came because I thought and acted like a developer who was out to solve problems for the client. That’s a great perspective, but has to be tempered with regard for the scope of the project. A PM needs to be able to step back, recognize an idea’s worth, and still say “We can’t do that”, for reasons of time or budget.

It can take time to build those new ways of thinking. Even worse, accidental project managers don't benefit much from the training that's available. I’ve found little value in the certifications and large volumes of information that exist for PMs—the Project Management Body of Knowledge (PMBOK) and the related Project Management Professional (PMP) certification are a prime example, but there are other certifications as well.

It’s really a question of scale: As an accidental project manager, a certification like the PMP is a terrible fit for where you're at, because you manage small-to-medium digital projects. Unless you’re building a skyscraper, you don't need 47 different processes and 71 distinct documents to manage things—you just need the right tools, applied in the right way.

In order to help fill that knowledge gap for accidental project managers, I’ve decided to start a series. In the future, I plan to post about scope control, measuring and reporting progress, and other topics that are important to PMs, but for now we’re going to cover just one: Risk Management.

Defining Risk

If you were looking at the PMBOK, you'd see risk defined like this:

an uncertain event or condition that, if it occurs, has a positive or negative effect on one or more project objectives such as scope, schedule, cost, or quality.

I fell asleep just pasting that into this post...I can hear you snoring as well, so we'll need a better definition. How about this:

Risk is a way of talking about uncertainty in your project—things that could affect your project that you're not sure about.

I like that better – it's more human, at the very least.

How to manage risks
  • Identify uncertainties, especially at kickoff or in transitions between project phases
  • Assess those risks for possible impact, likelihood, and relative priority
  • Plan responses to the risks that you feel are likely or high-priority
  • Monitor and address risks as the project progresses

Essentially, you should be brainstorming with the following questions:

  • What am I worried about? (risk identification)
  • Why am I worried about that? (possible impact)
  • How worried am I that this could happen? (likelihood/priority)
  • What can I control about this? (mitigation strategies)
  • What should I do if this thing actually happens? (response planning)
But that doesn't feel good...

You've nailed it. All those questions are great to ask – and better yet, talk about with your team and your client. The tricky part is that all this requires honesty. You have to be honest with yourself about what could happen, and this may lead you to realize some difficult things, possibly about yourself, the team you're working with, or the client you're working for. I'm going to go out on a limb and say that most project problems are not technical.

Brainstorming and being honest with yourself might lead you to truths like "I don't trust my client to deal with me honestly", or "My development team is unreliable.” That's hard stuff, and requires delicate handling.

In the end, the underlying reasons for risks are the reasons your project will fail, so you want to handle them as openly as possible. Letting that stuff go unattended is bad news. Get it out where you can do something about it.

Getting risk management into your routine

Risks can be identified throughout a project, but it’s often best to try and spot them right away during a kickoff. Any time you or your team is uncomfortable with something—a development task, a stakeholder, or whatever it may be—you should write it down. Even if you're not sure what to write down exactly, it's worthwhile to discuss with the team and see if you can spot what’s making you uncomfortable.

As the project progresses, you’ll want to communicate weekly with the client about risks you’re seeing, make plans to address them, and highlight items that are becoming more and more likely from week to week.That might take the form of a brief meeting, or an email summary calling out important points in a shared document that the client has access to.

However you communicate risks to your client, you'll want to track them someplace. You can do it in a simple list of items to discuss together or with your client, or you can use a more formal document called a risk log.

The Risk Log

You can track risks anywhere you want, but if you're feeling formal, it's common to keep them in a log that you can update and refer to throughout the project.

One thing to know is that risks are often stated in ‘condition > cause > consequence’ format. The format is loosely structured like this:

“There is a risk that …{something will happen}… caused by …{some condition}… resulting in …{some outcome}.”

Then for each risk, the log lets you:

  • track scores for likelihood and probable impact (on a 1-5 scale),
  • identify warning signs or dates for when action is needed add action plans for each risk in the log.
  • assign a responsible person

I've created a sample risk log for you to copy and modify as needed. If you don't think your project needs this kind of formality, it's possible to keep a simple running list of items to raise and discuss with the team. Nevertheless, seeing the slightly more formal version can help formulate what kind of tracking and tactics are available for the risks your project is facing.

Really comprehensive risk logs can also contain things like financial cost tracking, but that's rarely been a useful measure in my experience. Even big web projects rarely need that kind of tracking.

Common Risk Areas

Physicist Nils Bohr said: "An expert is a man who has made all the mistakes which can be made, in a narrow field." As an accidental project manager, you may lack the rich history of failures that might help you spot an impending risk. To help you figure out what risks you should be managing, here are a bunch of places to look:

When planning your project, watch out when:
  • Tasks exist that rely on the completion of other work before they can begin
  • Tasks exist that none of the project team has ever done before
  • You are required to use unfamiliar technologies
  • Tasks involve third parties or external vendors
  • Multiple systems have to interact, as in the case of api integration or data migration
  • Key decision makers are not available
  • Decisions involve more than one department/team
  • Resources/staff exist that are outside your direct control
  • You have to plan a task based on assumption rather than fact
When interacting with people, watch out for:
  • People who are worried about loss of their job
  • People who will require retraining
  • People that may be moved to a different department/team
  • People that are being forced to commit resources to the project unwillingly
  • People who fear loss of control over a function or resources
  • People forced to do their job in a different way than they're used to
  • People that are handling new or additional job functions (perhaps that's you?)
  • People who will have to use a new technology

Many of the people-oriented risks in the list above fall under the heading of ‘Change is hard’. This is especially true with folks on a client or external team where a new project introduces changes to the way they do business. If you're providing services to a client, you may bear some of the brunt of those change-related stressors.

Change-related risks aren’t limited to people outside your team —sometimes the developers, designers or other folks working directly with you have the same concerns. Wherever you find it, risk management is often about taking good care of people in the middle of change.

Organizational risk

It’s probably also worth mentioning that risks can also arise from organizational change outside your immediate control. Corporate restructuring and changes in leadership can impact your project, and politics between different business units are frequently a source of challenges.

There may not be a ton you can do about these kinds of risks, but identifying them and understanding how they affect your project can make a big difference in how you communicate about things.

So, accidental project manager, go forth and manage your risk! Take some time and think through what you’re uncomfortable or worried about. Be circumspect, ask yourself a lot of ‘why’ questions, and then communicate about it. You’ll be glad you did.

Rebuilding POP in D8 - Development Environments

This is the second in a series of articles about building a website for a small non-profit using Drupal 8. These articles assume that the reader is already familiar with Drupal 7 development, and focuses on what is new / different in putting together a Drupal 8 site.

In the last article, I talked about Drupal 8's new block layout tools and how they are going to help us build the POP website without relying on external modules like Context. Having done some basic architectural research, it is now time to dive into real development. The first part of that, of course, is setting up our environments. There are quite a few new considerations in getting even this simple a setup in place for Drupal 8, so lets start digging into them.

My Setup

I wanted a pretty basic setup. I have a local development environment setup on laptop, then I wanted to host the code on github, and be able to push updates to a dev server so that my partner Nicole could see them, make comments, and eventually begin entering new content into the site. This is going to be done using a pretty basic dev/stage/live setup, along with using a QA tool we've built here at Lullabot called Tugboat. We'll be going into the details of workflow and deployment in the next article, but there is actually a bunch of new functionality in Drupal 8 surrounding environment and development settings. So what all do we need to know to get this going? Lets find out!

Local Settings

In past versions of Drupal, devs would often modify settings.php to include a localized version to store environment-specific information like database settings or API keys. This file does not get put into version control, but is instead created by hand in each environment to ensure that settings from one do not transfer to another inadvertently. In Drupal 8 this functionality is baked into core.

At the bottom of your settings.php are three commented out lines:

# if (file_exists(__DIR__ . '/settings.local.php')) { # include __DIR__ . '/settings.local.php'; # }

If you uncomment these lines and place a file named settings.local.php into the same directory as your settings.php, Drupal will automatically see it and include it, along with whatever settings you put in. Drupal core even ships with an example.settings.local.php which you can copy and use as your own. This example file includes several settings pre-configured which can be helpful to know about.

Caching

There are several settings related to caching in the example.settings.local.php which are useful to know about. $settings['cache']['bins']['render'] controls what cache backend is used for the render cache, and $settings['cache']['bins']['dynamic_page_cache'] controls what cache backend is used for the page cache. There are commented out lines for both of these which set the cache to cache.backend.null, which is a special cache backend that is equivalent to turning caching off for the specified setting.

The cache.backend.null cache backend is defined in the development.services.yml file, which is by default included in the example.settings.local.php with this line:

$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';

If you want to disable caching as described above, then you must leave this line uncommented. If you comment it out, you will get a big ugly error the next time you try and run a cache rebuild.

Drush error message when the null caching backend has not been enabled.

The development.services.yml file is actually itself a localized configuration file for a variety of other Drupal 8 settings. We'll circle back to this a bit later in the article.

Other Settings

example.settings.local.php also includes a variety of other settings that can help during development. One such setting is rebuild_access. Drupal 8 includes a file called rebuild.php, which you can access from a web browser in order to rebuild Drupal's caches in situations where the Drupal admin is otherwise inaccessible. Normally you need a special token to access rebuild.php, however by setting $settings['rebuild_access'] = TRUE, you can access rebuild without a token for specific environments (like your laptop.)

Another thing you can do is turn on or off CSS and Javascript preprocessing, or show/hide testing modules and themes. It is worth taking the time to go through this file and see what all is available to you in addition to the usual things you would put in a local settings file like your database information.

Trusted Hosts

One setting you'll want to set that isn't pre-defined in example.settings.local.php is trusted_host_patterns. In earlier versions of Drupal, it was relatively easy for attackers to spoof your HTTP host in order to do things like rewrite the link in password reset emails, or poison the cache so that images and links pointed to a different domain. Drupal offers the trusted_host_patterns setting to allow users to specify exactly what hosts Drupal should respond to requests for. For the site www.example.com, you would set this up as follows.

$settings['trusted_host_patterns'] = array( '^www\.example\.com$', );

If you want your site to respond to all subdomains of example.com, you would add an entry like so:

$settings['trusted_host_patterns'] = array( '^www\.example\.com$', '^.+\.example\.com$', );

Trusted hosts can be added as needed to this array dependent on your needs. This is also something you'll want to set up on a per-environment basis in a local.settings.php, since each environment will have its own trusted hosts.

Local Service Settings

When Drupal 8 started merging in components from Symfony, we introduced the concept of "services". A service is simply an object that performs a single piece of functionality which is global to your application. For instance, Symfony uses a Mailer service which is used globally to send email. Some other examples of services are Twig (for template management) and Session Handling.

Symfony uses a file called services.yml for managing configuration for services, and just like with our settings.local.php, we can use a file called development.services.yml to manage our localized service configuration. As we saw above, this file is automatically included when we use Drupal 8's default local settings file. If you add this file to your .gitignore, then we can use it for environment-specific configuration just like we do with settings.local.php.

The full scale of configuration that can be managed through services.yml is well outside the scope of this article. The main item of interest from a development standpoint is Twig debugging. When you set debug: true in the twig.config portion of your services configuration file, your HTML output will have a great deal of debugging information added to it. You can see an example of this below:

Drupal page output including Twig debugging information.

Every template hook is outlined in the HTML output, so that you can easily determine where that portion of markup is coming from. This is extremely useful, especially for people who are new to Drupal theming. This does come with a cost in terms of performance, so it should not be turned on in production, but for development it is a vital tool.

Configuration Management

One of the major features of Drupal 8 is its new configuration management system. This allows configuration to be exported from one site and imported on another site with the ease of deploying any other code changes. Drupal provides all installations with a sync directory which is where configuration is exported to and imported from. Be default this directory is located in Drupal's files directory, however this is not the best place for it considering the sensitive data that can be stored in your configuration. Ideally you will want to store it outside of your webroot. For my installation I have setup a directory structure like this:

Sample Drupal 8 directory structure.

The Drupal installation lives inside docroot, util contains build scripts and other tools that are useful for deployments (more on this in the next article) and config/sync is where my configuration files are going to live. To make this work, you must change settings.php as follows:

$config_directories = array( CONFIG_SYNC_DIRECTORY => '../config/sync', );

Note that this will be the same for all sites, so you will want to set it in your main settings.php, not a local.settings.php.

Having done all this, we are now setup for work and ready to setup our development workflow for pushing changes upstream and reviewing changes as they are worked on. That will be the subject of our next article so stay tuned!

Why We Built Tugboat.QA

Videos require iframe browser support.

Three years ago, Lullabot started a project to bring visibility to the web development process. Asking our clients to wait to see work in progress is not only an embarrassing ask, it’s an alienating one for stakeholders. Waiting two weeks until the end of a sprint cycle for a demo was not only nerve-wracking, it also slowed potential progress, and meant that feedback was often delayed until too late. The truth was that building these demo sites was a lot of work: work that was taking time away from creating the actual website. How would you feel if your general contractor said you could only see the house they were building for you twice a month? Unacceptable. Time and time again, through client interviews and market research we found this pain was widespread and in need of resolution. The lack of visibility and thus engagement was leading to out-of-sync stakeholders and expensive rework. We knew we could work smarter and with lower costs.

For stakeholders and non-technical team members, the barrier to collaboration in web development is nearly insurmountable. Stakeholders need to know how to setup a local working copy of the project and they need to know how to continuously keep that local instance working—which is its own sisyphean task.

With Tugboat, we’re able to eliminate the technical barriers and share work as it happens with everyone, anywhere. Tugboat does this by automatically building a complete working website whenever a new pull request is generated. The entire team can see every change, every feature, every bug fix fully integrated into the larger site the moment it’s ready for review. No more waiting to see the work. No more waiting for feedback.

Tugboat is hosting agnostic. You don’t host your website with us in order to use it. But we do take platform architecture seriously, so every account is its own silo of dedicated resources and each project begins with a custom setup to ensure you’re ready to set sail. Tugboat can even run inside your own hosting environment (on premise) if you need to keep your data behind your firewall. We can also run custom Docker containers if you’re already using Docker as part of your production workflow.

We hope you get a chance to check out Tugboat. Stop by the Lullabot booth at Drupalcon and say hello. Meanwhile, if you’re a developer we’ve built a sandbox version of the platform for you to explore. Fork the public repository of our website, create a pull request and voilà! You can watch Tugboat chug chug chug its way into action. Be sure to check out some of the cool features while you’re there: built-in command-line access, visual regression tests, and real-time logging. But don’t take our word for it. Head on over to the demo to take Tugboat for a cruise!

Dynamically Inlining Critical CSS with Server-side JavaScript

Data gathered by Akamai on e-commerce sites shows that 40% of users will abandon a site if it fails to load within 3 seconds. Google will even penalise your site in search rankings if it's slow to load. Couple that with large numbers of users accessing sites from mobile data connections, and the time it takes for your site to initially render should be a very important consideration.

There's a number of ways to analyse how your page is being rendered, from directly in the browser using Chrome Developer Tools' Timeline feature to remotely with WebPagetest's visual comparison tool.

Optimising your page to load quickly is chiefly about understanding how the browser will download, parse and, interpret resources such as CSS and JavaScript. This is called the critical rendering path. A fantastic tool for analysing the front-end performance of your site is Google's PageSpeed Insights.

The very definition of irony

An issue this tool frequently highlights is failure to optimise CSS delivery. This warning will be triggered when CSS has been included externally in the head of the document.

<!doctype html> <html> <head> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>Hello, world!</h1> </body> </html> Before the browser can render content it must process all the style and layout information for the current page. As a result, the browser will block rendering until external stylesheets are downloaded and processed, which may require multiple roundtrips and delay the time to first render. Google PageSpeed Insights

As well as the time required to download and parse the stylesheet, for browsers which don't yet support HTTP/2 there is an even futher overhead from the round-trip time to open a new connection to the web server. To solve this problem, PageSpeed recommends adding inline CSS to the HTML document. This doesn't mean we want to embed the entire stylesheet into the document, as then we would still have to wait for the entire document to download and be interpreted by the browser, instead we only inline the CSS required to display the initial viewport when loading the page.

A great tool for this is Critical. Take a look at the source of the before and after examples and what PageSpeed Insights has to say about them.

Using Critical requires analysing the page with PhantomJS, a headless browser, which will then extract the styles required to show the above-the-fold content. This can be awkward to implement into a site which has a large number of different entry points (e.g. the homepage, an article, a product page). It would require pre-analysing each page type, storing the generated styles and then delivering the correct one depending on where the user has come into the site. This becomes even harder when you consider that each page type could have a different set of styles required depending on what content has been added to it. Will all articles have full width images? Will all products have a gallery? This kind of page examination with Critical can't be done at run-time either as spinning up a PhantomJS instance for each page request would cause atrocious performance issues.

With markup generated on the server-side, we're given an opportunity to analyse what's been produced and make some performance optimisations. I've created a simple example for Node.js and Express, which you can find on GitHub. We're currently using this technique on lullabot.com, where we use React to render the initial markup for the page on the server. After the page is delivered and client-side JavaScript downloaded, React Router takes over, and navigation around the site is done with the History API and XHR calls. This negates the need for a full page load each time, but also doesn't require the site to keep generating critical CSS for each new navigation action.

Below is a very simple example of rendering a React component to a string that can be delivered from Node.js — see https://github.com/mhart/react-server-example for more detailed examples.

var pageMarkup = ReactDOMServer.renderToString(MyReactApp);

The package we use to generate our critical CSS is PurifyCSS. It takes HTML and a stylesheet, then returns only the CSS which would be applied and used for that markup. Although the CSS generated won't be as optimised as using Critical, it gives us a dynamically generated fallback option for all types and permutations of pages on the site.

Taking the rendered markup from the code above, the example below runs it through purifyCSS and then injects it into our page template, loading the remaining CSS with the loadCSS technique.

var template = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8'); var markup = { externalCss: 'style.css', criticalCss: '' }; purify(pageMarkup, [markup.externalCss], { minify: true, output: false, info: false, rejected: false }, function (purifiedOutput) { markup.criticalCSS = purifiedOutput; var html = mustache.to_html(template, markup); }); <!doctype html> <html> <head> <style> {{&criticalCSS}} </style> <script> function loadCSS(e,n,o,t){"use strict";var d=window.document.createElement("link"),i=n||window.document.getElementsByTagName("script")[0],r=window.document.styleSheets;return d.rel="stylesheet",d.href=e,d.media="only x",t&&(d.onload=t),i.parentNode.insertBefore(d,i),d.onloadcssdefined=function(e){for(var n,o=0;o<r.length;o++)r[o].href&&r[o].href===d.href&&(n=!0);n?e():setTimeout(function(){d.onloadcssdefined(e)})},d.onloadcssdefined(function(){d.media=o||"all"}),d} loadCSS('/{{&css}}'); </script> <noscript><link href="/{{&css}}" rel="stylesheet"></noscript> </head> <body> <h1>Hello, world!</h1> </body> </html>

Make sure to keep on eye on how much CSS is being inlined, as running this over a framework such as Bootstrap could cause a lot to be produced. Finally, whilst we haven't seen any performance issues with this technique in production (we also typically use Varnish in front of Node.js), at this point it would be advisable to run some benchmarks for your pages to ensure it's not causing any meltdowns!

DrupalCon New Orleans Session Extravaganza!

Matt and Mike talk with a plethora of Lullabots about their sessions at DrupalCon New Orleans, what their favorite all-time DrupalCon experience was, and what sessions they’re looking forward to seeing this year.

Web Accessibility: The Inclusive Way to Boost Your Bottom Line

We have a lot of words that we use to describe people with disabilities. We have words like ‘differently abled’, or ‘blind’, or ‘motor impaired’, but there are some really important labels that we often forget, like ‘customers’, and ‘viewers’, and ‘students’. While members of the disability community might do some things a little differently, they are also a group of consumers twice as large as the entire nation of Australia in the United States alone. When we’re talking about so many people, we’re discussing massive buying power. People with disabilities watch shows, buy products, subscribe to services, and take classes. They’re fans, foodies, and potential brand evangelists just waiting to happen! When we make our web presence accessible to people with disabilities, we’re not just doing the right thing; we’re unlocking a huge group of customers that we otherwise would have missed out on. 

Web accessibility is about including people by making sure that people with disabilities can use the sites we build. Can someone using a screenreader navigate to your contact form? Can a purchase be made on your site without using a mouse? Can that enrollment application be filled out by someone who can’t see the screen? Concepts like these need to be taken into consideration to ensure that we’re including everybody. Yes, it is about recognizing humanity in all of its diversity and doing our very best to give everyone the experience they came for. However, making websites accessible isn’t a charitable act. It’s not a nod to an edge-case scenario to satisfy a requirement somewhere, nor is it about spending money to put in features that are only going to benefit a few people to give us the warm fuzzies inside. At the end of the day, it’s good business.  After all, we’re talking about impacting 56.7 million potential users, and that’s if we’re only counting users in the United States (Source: US Census Bureau, 2012). If your website wouldn’t work for anyone in the state of New York, there is no chance that you would even consider launching it. So how is it that we disregard web accessibility as an ‘extra feature’ to be culled when there are nearly twice as many Americans with severe disabilities than New York residents?

Cyclical Non-inclusiveness

Usually we disregard accessibility because we don’t realize the large impact of that decision. As human beings, we collectively suffer from something called the “False-Consensus Effect”. Essentially, we naturally gravitate toward people who we have a lot in common with, validate our experiences amongst ourselves, and end up with an incomplete world view. For instance, many Deaf people associate mainly with other Deaf people within their own community. It might be more challenging for a hearing person to form a friendship with someone Deaf without knowing ASL, so a lot of hearing people don’t have many (or any) Deaf friends. However, the fact that your average hearing person doesn’t know many Deaf people doesn’t mean that there isn’t a huge thriving Deaf community. Non-inclusiveness is cyclical. Poor accessibility leads to people with disabilities not being able to fully take part in the mainstream community. From there, it’s out of sight, out of mind. Poor visibility and representation lead to mainstream society forgetting to make accommodations for them — or worse, actively deciding that it’s not worth the cost or trouble to do so based on an obstructed view of the impact of that decision. The carousel of non-inclusiveness spins around and around, but we have the power to break the cycle.

The thing about exclusion is that it rarely feels personal to the side doing the excluding. Businesses don’t skip web accessibility because they hate people with disabilities and want to keep them out of their websites. A lot of the time, accessibility gets skipped because stakeholders have never heard of it before and have no idea they should be doing it. Sometimes businesses skip accessibility on their websites because they don’t know what it would entail to implement it, or are worried about the budget or the timeline. Web accessibility doesn’t happen for lots of reasons, but for the business, it’s not personal.

Consumers, on the other hand, absolutely choose where to spend their money and which brands to follow based on personal reasons, and accessibility is very personal when you’re the one who needs accommodation. One of the strongest motivators for repeat business and brand evangelism is how your company makes its target market feel. If your company excludes a user from your online experience, that person now has a negative association with your brand, and that’s pretty hard to undo. After all, everyone likes to feel like they matter. If someone arrives at your site to find that no one considered their needs or made any accommodations for them, it sends a pretty strong message that you either forgot them or disregarded them. Either way, it doesn’t make a great impression. As my grandmother used to say, “You can’t take it back once you spit.”

Breaking the Cycle and Creating Loyal Customers

On the bright side, if you make a site with great accessibility, customers with disabilities will remember that, too. Delighted users love to return to deliver repeat business again and again. Additionally, the disability community is pretty tight-knit, and they often shout it out loud through their circles when a brand does things right for them so that other people know where to go to find a good experience. As a result, a small amount of accessibility work can buy you a huge network of loyal customers.

For instance, consider the case of Legal & General (L&G) on W3.org. After a full accessibility audit, they decided to take the plunge and make their site fully accessible. Within a day of launching their newly accessible site, they saw a 25% increase in traffic. Over time, that increase grew to a full 50%. Visitors who converted into leads receiving quotes doubled within three months, and L&G’s maintenance costs fell by 66%. Within 12 months, they saw a 100% ROI. Talk about a lot of bang for your buck! 

CNET has some a11y bragging rights, too. After adding transcripts to their website they saw a 30% increase in their traffic from Google. How come? It’s because accessibility is awesome for SEO! Between the easy-to-crawl site outlines, the relevant keywords found on the alt-text for all of the images, and the adherence to best practices, accessible sites are prime picking for Google’s algorithms and tend to rank more highly in searches.

Of course, there are also cautionary tales; just ask Target about their pockets being $9.7 million lighter (before paying their own attorney’s fees) after a settlement with the NFB over their non-compliant online shopping experience. After a very expensive lesson learned, Target’s website is now beautifully accessible for everyone. 

The fantastic news is that accessibility usually isn’t especially time-consuming or challenging to do in the grand scheme of a normal web development project — especially if you plan for it from the beginning and implement it as you go along. By defining accessibility as a priority for your web presence right at the beginning and checking for it along the planning, design, and development stages, you’ll be on the right track to reach your entire market base at launch. Oh, and don’t forget your editors! Once you launch your awesome accessible site, make sure that you keep it that way by ensuring that your editorial team knows how to post new content that is access-friendly with alternative text for images and other accessibility basics in place. In the end, access-savvy sites are business-savvy sites, and like most business-savvy endeavors it requires some investment to give you a return. Including everybody? That’s priceless.

Whether you’re thinking about building accessibility into a new web presence, already have a site that needs a little bit of a11y love, or are keeping a wise eye toward the ADA and WCAG 2.0 / Section 508 compliance, Lullabot can help! If you’re more of the do-it-yourself type, there are some great resources to be found through the Web Accessibility Initiative, on the University of Washington’s Accessible Technology page, and from the American Federation of the Blind. Want to get an idea of how your site is currently doing? Try running it through the free WAVE tool.

A Framework for Project Kickoffs

Project kickoffs can be the shortest individual component of a project, but they can also be the most important. Done poorly, a kickoff can feel like a reading of a contract by inhuman actors doing inhuman work. Done well, a kickoff can bring a team together and push them towards success. Kickoffs are one of the project skills we don’t get many opportunities to iterate and learn. Developers at Lullabot commonly end up attached to a client or project for many months (or years!) at a time, so it’s entirely possible to go that period of time without having a formal kickoff. Here are some thoughts I’ve had after doing several kickoffs this year.

About the Client

In a distributed team, a kickoff usually happens with a phone call. While pre-sales communication will have already happened, the kickoff call is usually the first time when everyone working on a team will be together at once. As a team member from the vendor, this is your chance to ask questions of the business stakeholders who might not be available day to day. I like to find out:

  • Why are we all here? Are the business, technology, or creative concerns the primary driver?
  • What is the business looking for their team to learn and accomplish?
  • What are the external constraints on the project? Are there timelines and due dates, or other projects dependent on our work? What are the upcoming decisions and turning points in the business that could have a big affect on the project?
About Me

We all have ideas about how we want to work and be utilized on a project. Making sure they align with the client is very important to work out during a kickoff. Sometimes, a client has specific priorities of work to get done. Other times, they might not have realized you have skills in a specific subject area that they really need. It’s really important to understand your role on a project, especially if you have multiple skill sets. Perhaps you’re a great Drupal site builder, but what the client really needs is to use your skills to organize and clean up their content model. Figuring all of that out is a great kickoff topic.

About Us

Once we understand each other, then we can start to figure out how we work together. It’s kind of like moving in with someone. You might know each other very well, but how are you going to handle talking with your landlord? How are each person’s work schedules going to integrate?

For a distributed team, communication tools are at the core of this discussion. We all have email, chat rooms, instant messaging, video, and more. What tools are best used when? Are there specific tools the client prefers, or tools that they can’t use because of their company’s network setup? Finding the middle ground between “all mediums, all the time” and “it’s all in person until you ask” is key.

Recurring meetings are another good topic to cover. Some companies will take new team members, add them to every recurring meeting, and use up a 10 hour-per-week consulting engagement with nothing but agile ceremony. Perhaps that’s what you’re needed for—or perhaps they’ve just operated out of habit. Finding a good balance will go a long way towards building a sustainable relationship.

Sharing each person’s timezones and availability also helps to keep expectations reasonable. Some companies have recurring meetings (like Lullabot’s Monday / Friday Team Calls) which will always be booked. Sometimes individuals have days their hours are different due to personal or family commitments. Identify the stakeholders who have the “worst” availability and give them extra flexibility in scheduling. Knowing all of this ahead of time will help prevent lots of back-and-forth over meeting times.

Finally, find out who you should go to if work is blocked. That might be a stakeholder or project manager on the client’s side, but it could also be one of your coworkers. Having someone identified to the team as the “unblocker of work” helps keep the project running smoothly and personal tensions low.

About Tech

For development projects, the first question I ask is “will we need any sort of VPN access?”. VPN access is almost always a pain to get set up—many companies aren’t able to smoothly setup contractors who are entirely remote. It’s not unheard of for VPN access to take days or weeks to set up. If critical resources are behind a VPN, it’s a good idea to start setting that up before an official kickoff.

Barring the VPN-monster, figuring out where code repositories are, where tickets are managed, and how development and QA servers work are all good kickoff topics. Get your accounts created and make sure they all work. If a client is missing anything (like a good QA environment or ticket system), this is when you can make some recommendations.

About Onsites

Some projects will have a kickoff colocated somewhere, either at a client’s office or at a location central to everyone. In distributed teams, an in-person meeting can be incredibly useful in understanding each person. The subtle, dry humour of your video expert becomes apparent in-person, but could have been misunderstood online. Most of the above can be handled in the first hour of an onsite visit, leaving much more time to fill given the travel time!

We like to focus onsites on the topics that are significant unknowns, require a significant number of people across many teams, and are likely to require whiteboards, diagrams, and group brainstorming. Project discoveries are a classic fit; it’s common to meet with many different people from different departments, and doing first meetings in person can be a significant time saver. The goal of an onsite shouldn’t be to “kick off” the project—it should be to build the shared understanding a team needs so they can be effective.

But what about sales engineering?

I’m sure some readers are now thinking “Wait a minute! Aren’t these all things you should know before a contract is signed?”. It’s true! Going into a kickoff without any of this information would be a serious risk.

It’s important to remember that the team on a kickoff isn’t going to be identical to the team who did the sales engineering work. Both the client and the vendor will have new people just getting started. As well, it’s useful to hear the project parameters one more time. Discrepancies in the discussions can alert the team to any misunderstandings, or more likely changes in the business environment running up to the signing of the contract. Especially on projects where a team is already working, hearing about progress or changes made in the week between signing an SOW and kickoff can be invaluable.

What did you learn the last time you helped to kick off a project? Let us know in the comments!

Does Working From Home Benefit the Environment?

I work from home. As I commute up the stairs to my home office, I confess to a certain smugness. Steaming coffee in hand, I think of those poor souls and their wasteful commutes, trudging out in the snow to scrape windshields, or those who commute from suburb to city. One of Lullabot’s clients, let’s call him John, commutes 2.5 hours one way by train and subway from Succasunna, NJ, to 30 Rockefeller Center. Every. Single. Work day. That’s close to 1,200 hours of commute time each year. To meet with John, as I do frequently, I merely walk up the stairs and spin up a Google Hangout.

But this smugness extends beyond the time savings. I’ve always assumed that not using a car to get to work—not even owning a second car—put me squarely atop the moral high ground when it came to the environment. I’ve long harbored the belief that the communication tools and techniques we’ve pioneered in distributed companies like Lullabot will eventually enable all knowledge workers to work from home. And, together, we’ll save winter. I live near Aspen, Colo., after all.

According to the most recent US Census, about 4% of the US workforce telecommutes and that number is rapidly growing. That keeps a lot of carbon out of the atmosphere. A 2007 IBM study showed that having a distributed workforce saved the company five million gallons of fuel, preventing more than 450,000 tons of CO2 from entering the atmosphere. Companies like Aetna, Dell, and Xerox use their telecommuting programs to market their environmental credentials.

But what does this all mean? Does telecommuting actually make an impact or does the need to heat and cool a house that would otherwise be empty during the day offset the savings? What about having to fly to meetings and company retreats? Does living in a lifestyle destination like the Roaring Fork Valley with our relatively low population density help or hurt?

To explore these questions, I called on one of Lullabot’s clients, Lisa Altieri, president of GoCO2Free, a Palo Alto-based company that is working with the cities of Menlo Park, Palo Alto, and Fremont to reduce their carbon footprint. She’s been working with Lullabot Juan Olalla to build a new carbon calculator that will help each household quantify their footprint. Altieri helped me do the math.

The Commute

According to the most recent US Census data, the average worker commutes for 50 minutes a day over an average of 32 miles. Burning a pound of gasoline produces about 19.4 pounds of CO2. What?! Taking a very dense form of energy, a hydrocarbon like octane (C8H18), and burning it for energy adds a lot of weighty oxygen. (Remember combustion is just really, really fast oxidation.) The result of burning one of these octane molecules—remembering the law of conservation of mass—is eight molecules of carbon dioxide (CO2) and nine molecules of water (H2O). Turns out this carbon dioxide is heavy, voluminous stuff. But 19.4 pounds isn’t the extent of CO2 burned. We also have to factor in the energy used to extract the crude oil, transport it, refine it, and then transport it again. Taking this “embodied energy” into account, Altieri gave me the constant of 28.3 pounds of CO2 emitted per gallon of gasoline used.

So, back to our math. A typical American probably works 235 days per year. If we multiply that by our average commute of 32 miles we get 7,520 miles. My Chrysler Town & Country gets a pretty average 25 mpg, meaning I’m saving about 300.8 gallons of gasoline by not commuting, or (multiplying by our constant), I’m preventing about 8,513 pounds of CO2 from entering the atmosphere. To calculate your own carbon footprint exactly (taking into account your model of car, energy usage, etc.) try the following calculator.

Burning 128 gallons of gasoline produces enough CO2 to fill the Washington Monument, and I’m saving more than twice that! I’m feeling pretty smug about saving all that smog. But hold on…

Heating the House

To work from home, I have to stay warm in the winter by heating my 1,484-square-foot home with our inveterate 1974 Slant | Fin stainless steel boiler. Despite what Harry and Lloyd say, Aspen is not warm. As you can imagine, this is less efficient than heating an office with many people occupying a small space. In fact, the average North American office employee occupies 150 square feet, so about 1/10th of the space.

Altieri instructed me to subtract the total “therms” from my July natural gas bill from the total on my January bill to get the extra therms I use just for heating. What the heck is a therm? Apparently it’s enough for English majors like me to just grab these handy numbers from our bill and then multiply by the constant 17.4 pounds of CO2 per therm. So I multiply the 90 therms I use to heat the house in winter, times five cold months, times 17.4 pounds of CO2 per therm. That yields 7,830 pounds of CO2. I can subtract the 1/10th I might have used if I was in an office to derive 7,047 pounds of CO2.

But, I’d have to heat my house anyway in the winter, right? But let’s say I’m parsimonious and turn down the heat during the day. The average worker is away from home about 50 hours a week, taking into account commuting, lunch and working hours. That’s about 30 percent of the time. So claiming 30 percent of that 7,047 as my carbon footprint, I use an extra 2,114 pounds of CO2.

So I’m still feeling good about myself for telecommuting with a net savings of—8,513 (no commute) minus 2,114 (extra heat)—6,399 pounds of CO2.

Air Travel

What about air miles, Altieri asked me? Ruh roh! Turns out flying is the cardinal carbon sin of modern life. For every mile of air travel, figure about .58 pounds of CO2 emissions, says Altieri. I get together with other Lullabots at four retreats per year. Assuming the pattern of two retreats on the West Coast, one on the East Coast, and one in the Midwest, I’m probably traveling around 10,000 air miles per year that can be directly attributed to working for a distributed company. Plus, shorter flights, like my favorite Aspen-to-Denver trip, result in greater emissions per mile because a larger portion of the trip is spent in the energy-intensive takeoff and landing. Suddenly, I’ve got another 5,800 pounds of carbon footprint to worry about.

Living the Dream

Finally, there’s life in the Roaring Fork Valley, with its relatively low population density. Dense urban areas tend to have much lower per capita emissions than less dense ones. Turns out our zip code in Carbondale, 81623, comes in way above the already astronomical US average carbon footprint. Carbondale residents average an annual carbon footprint of 57.8 metric tons of CO2, whereas the American household average (astronomical by world standards) is 48 metric tons of CO2, about 20% higher.

I used the carbon calculator on Terrapass to calculate my total carbon footprint in a given year and came up with 36,585 pounds of CO2. I have to assume this is about 20% higher than if I lived in an area with average population density where knowledge worker jobs are usually found, which means another 7,317 pounds of carbon.

In my example, living the “distributed” workforce lifestyle means a net increase of 6,718 pounds of CO2 are being pumped into the atmosphere. That's not a blanket condemnation of working from home as each person's situation will vary, but I'm guessing additional air travel will offset many of the benefits of not having a commute. Smug smile wiped off my face, I turn to Altieri for absolution.

Sounds like it’s time to purchase some offsets, she says, referring me to Terrapass. I could either plant 426 urban trees, which sounds time consuming, or purchase offsets at $5.95 per 1,000 pounds of CO2 or about $42 worth. Terrapass uses the money to do things like buy anaerobic digesters for animal waste, to capture landfill gas, and to derive clean energy from wind power.

Altieri also suggested that I could cut my impact by looking up my local utility provider to see if they have a local renewable energy pool. While this may increase your power bill a bit, it’s likely the single simplest way to reduce your carbon footprint short of buying a plugin electric car. Perhaps a Tesla Model 3 will absolve my sins?

A Recipe for Creating CouchDB Views

When we built the Lullabot.com front-end using React, we needed a way to get data from Drupal. Setting up a REST API directly from Drupal was one way of doing this. We found, however, that the existing modules for implementing our own API were rather complex and not so performant. In addition, since the navigation at Lullabot.com was anonymous, we did not need the Drupal bootstrap for user sessions when querying the API. Instead, we decided to use CouchDB, a NoSQL database which stores its data as a flat collection of JSON documents. The best thing about CouchDB compared to other NoSQL offerings available out there is that it provides a REST API out of the box. This makes CouchDB the bee’s knees for this project. In this article, we will share a few recipes for querying and aggregating data with CouchDB.

We will be using curl to access the API in the examples for this article, but you can use your preferred REST client.

Creating a Design Document

Since CouchDB is a NoSQL database, we can't write queries to join and aggregate data in the same way we would when using a relational database such as MySQL. There are no tables and no relationships. There is, instead, a JavaScript view engine to help us create and run queries using the map-reduce paradigm. The map portion of the paradigm takes a list of values and applies the same computation to each value to produce a new refined list. The reduce operation then collapses or combines those values into a single or given number of values. For example, the total sum of all the values. The views which act as the map part of the paradigm, are defined using JavaScript functions that take a single CouchDB document as an argument. These functions determine which documents are made available through the views. 

View functions live in the database’s design documents. Design documents store application code that is run inside the database. The following example declares a view:

{ "views": { "all": { "map": "function(doc) { emit(doc.title, doc) }", } } }

We can save this into a javascript file, upload it to CouchDB, and save it as design document to create the view. For example, using curl:

curl -X PUT @docs_view.js 'http://localhost:5984/lullabot/_design/[your_design_doc]'

In this case we are making a PUT request because a new design document is being created at http://localhost:5984/lullabot/_design/docs. If the request was successful we get this response:

{"ok":true,"id":"_design/docs","rev":"1-485d01ba401d41a9e922780eca73a384"}

You can check on the design document by retrieving it:

curl -X GET 'http://localhost:5984/lullabot_1/_design/[your_design_doc]' { "_id":"_design/docs_1", "_rev":"1-485d01ba401d41a9e922780eca73a384", "views":{"all":{"map":"function(doc) { emit(doc.title, doc) }"}} } The Basic View

To start with, as an example, we will use the following document structure for storing a speaker's conference events:

{ events: [{ title: "DrupalCon Barcelona 2015", subtitle: "Monday 21st-25th September 2015 — Barcelona", role: "speaking", link: "http://lanyrd.com/2015/drupalcon-barcelona/", location: "Barcelona, Spain", start_date: 1442808000, end_date: 1443153600 }, { title: "ZendCon 2015", subtitle: "Monday 19th-22nd October 2015 — Las Vegas", role: "attending", link: "http://lanyrd.com/2015/zendcon/", location: "Las Vegas, United States", start_date: 1445227200, end_date: 1445486400 }], speaker: { name: "Joe Shindelar", headshot: { uri: "bio_image/dsc_0272.jpg", mime: "image/jpeg", }, link: "who-we-are/joe-shindelar" }, type: "speaker" }

To get a list of all the speakers, the map function looks like this:

function(doc) { if (doc.type && doc.type == 'speaker') { emit(doc.speaker.name, doc); } }

When we query the database using a view for the first time, each record in the database is run through the map function. This only happens once when the view is first run so that the database can be indexed and stored in a B-tree (Further reading on performance can be found here). The emit() function outputs a key and the value, which we specify as the first and second parameter respectively. In this case the key is the speaker's name and the value is the entire document. Here we also check if the document being returned is of the type speaker so that only speaker documents are returned.

Each view comes with a neat way to access it via the REST API. The views can be retrieved at a url that looks like this: /[your_database]/_design/[your_design_doc]/_view/[your_view]. The view we just created is accessed at http://localhost:5984/lullabot/_design/docs/_view/speakers.

To query the above view we can send a GET request using curl:

curl http://localhost:5984/lullabot/_design/docs/_view/speakers

This returns a list of speakers with their names as the key:

{ "total_rows": 22, "offset": 0, "rows": [{ "id": "84e77231cae12a572cc6724241004f43", "key": "Angus Mak", "value": { "_id": "84e77231cae12a572cc6724241004f43", "_rev": "6-5f9bee7b6b2c428657fdc8b2a7d5dcea", "events": [...], "username": "makangus", "speaker": {... }, "type": "speaker" } }, { "id": "84e77231cae12a572cc6724241001f47", "key": "Jared Ponchot", "value": { "_id": "84e77231cae12a572cc6724241001f47", "_rev": "6-87ee7de4b615a75dc786a85367c5e445", "events": [...], "username": "jponch", "speaker": {... }, "type": "speaker", } }] } Querying a Document Set

Now that we've nailed down a simple view, we can look at an example of how to query it. Suppose we want to display a list of events a speaker is attending. We would need to query for their particular speaker record. As the map function above returns the speaker's name as the key, we can easily pass the in the query parameter when we are making our request:

curl http://localhost:5984/lullabot/_design/docs/_view/speakers?startkey=['Angus Mak']&&endkey=['Angus Mak']

Here we have used the startkey and endkey parameters. Under the hood, the view is stored in a tree structure, when we specify a startkey, it tells CouchDB the position to start looking. If we have an endkey defined, the lookup will stop when it hits the endkey. In this case the start and end keys are the same, so we return just this record as there is only one match.

Building more complex queries

So a straightforward display of each record is simple enough, let’s complicate matters with a real scenario. For the Upcoming Talks page, we want to display a list of all talks that staff at Lullabot are presenting in chronological order.

The lullabot.com upcoming talks page

The problem is that each event does not have it’s own record but is stored as an array as part of the speaker record.

Here is the map function:

function(doc) { if (typeof doc.type !== 'undefined' && doc.type === 'speakers') { doc.events.forEach(function(event) { emit([event.role, event.session_date, event.title], { event: event, speaker: doc.speaker.name }); }); } }

To solve this problem, we iterate over all the events listed in each speaker record and output a result for each event. The resulting objects contain both the event and speaker objects. The key is a composite one made up of the role, event title, and session date. The fields in the key have been carefully chosen for the following reasons:

  • We want to be able to order the sessions chronologically, so the session_date was included.
  • We would also like to filter by whether or not a speaker is just attending or speaking at an event.

Here is a resulting row from the view with each event displayed as it’s own result row. A key/value pair is produced for each event:

{ "id": "84e77231cae12a572cc6724241004f43", "key": ["attending", 1442808000, "DrupalCon Barcelona 2015"], "value": { "id": "84e77231cae12a572cc6724241004f43", "event": { "title": "DrupalCon Barcelona 2015", "subtitle": "Monday 21st-25th September 2015 — Barcelona", "role": "attending", "link": "http://lanyrd.com/2015/drupalcon-barcelona/", "location": "Barcelona, Spain", "start_date": 1442808000, "end_date": 1443153600 }, "speaker": "Angus Mak" } }

To display just the speaking events, the query looks like this:

curl http://localhost:5984/lullabot/_design/docs/_view/upcoming_talks?startkey=["speaking"]&endkey=["speaking",{},{}]

Since we are only using one part of the key to filter with, we need to also specify the values of the other two parts of the key in the end key. As we are only interested in filtering by role, we can use wildcards {} for the other parts.

As a further example of querying using a compound key, if we want to filter all the speaking events between a date range, the query is as follows:

curl http://localhost:5984/lullabot/_design/docs/_view/upcoming_talks?startkey=["speaking",1442808000]&endkey=["speaking",1444968000,{}]

Here we are filtering between 21st Sept 2015 - 16th Oct 2015. When we are querying using a compound key, the order of each key part is important. We can only filter in the order of each part of the key. For example in this case, we can filter by [role], [role, session date] and [role, session date, event title], but we cannot filter by [role, event title].

Sorting

On the Upcoming Talks page, we would like to display the most recent speaking session first. We can use the descending parameter.

curl http://localhost:5984/lullabot/_design/docs/_view/upcoming_talks?startkey=["speaking",1444968000,{}]&endkey=["speaking",1442808000]&descending=true

Notice that the start and end keys have been flipped compared to the previous query example. This is because when we sort in a descending order we reverse the position in which we begin searching. The example below displaying a list of keys illustrates this.

["speaking",1431359982,"DrupalCon Los Angeles 2015"] ["speaking",1442808000,"DrupalCon Barcelona 2015"] // End position here ["speaking",1443844800,"Open Source North"] ["speaking",1444241700,"HOW Interactive Design Conference: Chicago"] ["speaking",1444449600,"New England Drupalcamp (NEDCAMP)"] ["speaking",1444968000,"DrupalCamp Atlanta 2015"] // Start position here ["speaking",1445227200,"ZendCon 2015"]

When you have a compound key, the fields are sorted in the same order as they are in the key. So in this case, the results are sorted by role, date, and then title.

Using the Reduce Function

Suppose we want to display some statistics on how many sessions Lullabot staff are speaking at in total. We can use the reduce function to help aggregate the data. The reduce function is executed on the documents returned by the map function. Similar to the map function, the reduce function operates once on each document.

With a few modifications, the map function looks like this:

function(doc) { if (typeof doc.type !== 'undefined' && doc.type === 'speakers') { doc.events.forEach(function(event) { emit([event.role, event.title], 1); }); } }


The resulting rows are of the following structure:

{"id": "84e77231cae12a572cc6724241004f43", "key": ["attending","DrupalCon Barcelona 2015"], "value": 1}

In order to count up all the speaking sessions, we can add a reduce function to our view in the design document:

{ "views": { "upcoming_talks": { "map": "function(doc){ //map function operations..}", "reduce": "function(key, values){ //reduce function operations..}" } } }

Here is the reduce function:

function(key, values) { return sum(values); }

The reduce function is called after the map function. The key parameter is an array containing all the keys returned by the map function and the id of the corresponding document. The values parameter contains an array of the values returned by the map function. When the function is run at index time, the values (in this case 1) are all added together using the the sum function to give us the number of sessions Lullabot are speaking at for each event.

The results are grouped using the whole key. In this case, we are adding the values where both parts of the key (role and title) are the same. For example:

["speaking", "DrupalCon Barcelona"] ["speaking", "DrupalCon Barcelona"] ["speaking", "DrupalCamp Atlanta 2015"]

The above contents of the key array will return the values 2 sessions at DrupalCon Barcelona and 1 session at DrupalCamp Atlanta 2015.

To return the number of total sessions overall, we can add the group_level parameter to the query.

curl http://localhost:5984/lullabot/_design/docs/_view/upcoming_talks?startkey=["speaking"]&endkey=["speaking",{}]&group_level=1

This will group the results by only the first part of the key and the reduce function will return the total number of sessions overall.

Conclusion

In this article, we discussed some basic techniques to get the data from couchDB. From our experience with using couchDB in the lullabot.com project, we found that it was a great alternative to building a Drupal REST API for powering the data layer of a decoupled site. The advantages are:

  • If the Drupal database becomes unavailable, it does not affect the front end site.
  • CouchDB provides a REST API out of the box.
  • Increased security as only the content editors have access to the Drupal back end.

When considering if couchDB is a suitable solution for a decoupled site, the advantages need to be balanced with the overhead of managing how the data is exported from Drupal to couchDB, and maintaining a couchDB instance in addition to the back-end Drupal database.

Lullabot's 8th Annual DrupalCon Party

Lullabot’s annual party has become a DrupalCon tradition – fun friendly people hanging out and having a good time. If you’re new to DrupalCon, it’s a great place to meet people. And if you’re an old-timer, it’s a great place to see old friends and make new ones.

Lullabot’s DrupalCon Party 2016
Wednesday, May 11th at the Ace Hotel
600 Carondelet St.
New Orleans, LA 70130
7PM ‘til whenever
(a 15 minute walk from Drupalcon)

We have 31 Lullabots attending Drupalon this year. Nine of them are presenting sessions, so don’t miss those. Also, both Lullabot and Tugboat will be representing at booth 206 in the exhibit hall. We’ll have our famous floppy disk party invites at the booth, so stop by early on Tuesday if you want to fill out your collection. And finally, since it's our 10 year anniversary, if you happen to stop by the booth wearing an old Lullabot tee, you'll also receive a new special edition Lullabot shirt. Hooray for new threads!

The venue for the party is a short 15 minute walk from the Convention Center. So stop by on Wednesday evening, enjoy a drink with us, and say “hello!”.

Lullabot DrupalCon Sessions 2016

This year we have a stellar lineup of sessions by the Lullabot and Drupalize.Me teams which were accepted for DrupalCon North America being held in New Orleans. Take a look at who is presenting and read a short synopsis of what they’ll be talking about.

Coding and Development Altering, Extending, and Enhancing Drupal 8 - Joe Shindelar A large part of Drupal's appeal lies in its flexibility. The fact that a developer can alter, extend, and enhance almost any aspect of Drupal without having to hack core. Historically this versatility has been made possible through the existence of hooks. Specially named PHP functions that are executed at critical points during the fulfillment of a request. And they've served the framework well for years. But times are changing, and Drupal 8 offers a variety of new patterns that all module developers will be required to learn, and understand. Configuration Management for Developers in Drupal 8 - Matthew Tift Is the configuration system your favorite feature of Drupal 8? Are you interested in doing continuous integration? Do you want to easily export all of your Drupal configuration to code? Interested in building a best practice continuous integration and deployment solution? This session, hosted by co-maintainers of the configuration system, will focus on how Drupal 8's configuration management system works, how to integrate it with a continuous integration system, and what developers can do to extend its power through contributed modules and custom code. Come with your questions and learn more about this magical part of Drupal 8. Core Conversations Drupal (admin) as an application: More JavaScript in core? - Marc Drummond In recent months, much debate has revolved around the compelling user experiences increasingly accompanying the runaway growth of JavaScript frameworks. Some argue that Drupal already has many moving parts and should evolve toward more seamless user experiences with existing tools and better processes. Some argue that Drupal should address this trend with additional capabilities for JavaScript in the form of a JavaScript framework. Some argue we should look at using modern PHP and JavaScript technologies that don’t require a JavaScript framework. Others have positions that fall both inside and outside this spectrum! Learning to Let Go (Contrib Burnout) and Module Giveaway - Dave Reid How can someone deeply involved in the Drupal contributed module ecosystem start to step away? How do we handle burnout not just in Drupal core development, but in contrib? I'd like to engage a conversation based the challenges I have encountered and currently face personally/emotionally on my journey from being one of the top contributors to Drupal 7, prolific writer of modules, to someone starting a family and needing to rebalance their personal, work, and Drupal life. With so much focus on getting people involved in Drupal.org, are there technical solutions we can explore to help make active contributors happier? Drupal.org Documentation Is Getting An Overhaul - Joe Shindelar Having high-quality documentation available for Drupal.org is key to gaining wider adoption, growing the community, and the overall success of the Drupal project. I want to share the work related to documentation going on in the community, as well as some of our plans for continued improvement in the future. Front End Debugging, Profiling, & Rocking Out with Browser-Based Developer Tools! - Mike Herchel Browser based developer tools have become an indispensable tool for modern front-end web development. New features and changes are being added at a rapid pace, and keeping up with all of the changes is difficult, but well worth it! In this session, Mike will walk attendees through modern debugging techniques, tips and tricks, front-end profiling, and more! Sizing up responsive images: Make a plan before you Drupal - Marc Drummond Drupal 8 has built-in responsive images support based off of Drupal 7’s contributed Picture and Breakpoint modules. Understanding how to use those modules without first making a plan could easily lead to a cat-tastrophe! Horizons AMPing up Drupal - Karen Stevenson, Matthew Tift, and Marc Drummond In many cases, the mobile web is a slow and frustrating experience. The Accelerated Mobile Pages (AMP) Project which involves Google is an open source initiative that embodies the vision that publishers can create mobile optimized content once and have it load instantly everywhere. When AMP was first introduced last October 2015, many commentators immediately compared it to Facebook's Instant Articles and Apple's News app. One of the biggest differentiators between AMP and other solutions is the fact that AMP is open source. Beyond the Blink: Add Drupal to Your IoT Playground - Amber Himes Matz What does making a light blink have to do with Drupal? Come to this session to find out how you can add Drupal to your Internet of Things data playground. (THERE WILL BE BLINKING LIGHTS.) Site Building Recoupling: Bridging Design and Structured Content - Jeff Eaton For years we’ve talked about separating content and presentation. Structure, reuse, and standardization are the name of the game in a future-friendly, multi-channel world — aesthetics are someone else’s concern … right? UX Web Accessibility 101: Principles, Concepts, and Financial Viability - Helena Zubkow If your website wouldn't work for anyone living in the state of New York, would that be a launch-blocker? Of course! So why are we ignoring the even larger population of people with disabilities?

Photo by: Jeff Turner and used via Creative Commons License

Selling Drupal Modules and Distributions

Matt and Mike talk to Taco Potze, Robert Douglas, Matthew Tift, Greg Dunlap, and Jeff Eaton about selling Drupal modules, and all of the benefits, downsides, and questions that arise from selling GPL and dual-licensed software in the Drupal community.

Why Paid Drupal Modules Fail: Drupal as Art

Recently the Drupal Association announced accepted sessions for DrupalCon New Orleans. While it looks like we can expect another great DrupalCon (this will be my 7th straight North American DrupalCon), one particular session on the program about the sale of Drupal modules caught my attention. Although I have tried to stay focused on preparing my own sessions, I have had conversations with other people in the Drupal community about “paid modules” that have led me to the conclusion that confusion about this topic persists. So here I would like to offer a perspective on why these kinds of plans consistently fail. Specifically, I hope to expand the scope of this frequently discussed issue and suggest why so many paid module initiatives fail: the Drupal community protects its free software with the same vigor that other communities protect artistic freedom.

The GPL Protects Software Freedoms

Before offering my analysis, I should start by acknowledging the obvious reason why paid Drupal modules fail: the General Public License (GPL). The Drupal Association clearly states that “Drupal modules and themes are a derivative work of Drupal. If you distribute them, you must do so under the terms of the GPL version 2 or later.” Consequently, anyone who wishes to sell a Drupal module must provide the source code.

Drupal community members are standing by with their credit cards ready to purchase those modules – and then post the code to Drupal.org so that everyone else can use it. These principled individuals believe that copyleft provides a powerful tool for ensuring software freedom and will exercise their right guaranteed by the GPL that allows the recipient (buyer) “to copy, distribute or modify” the module or theme purchased. The seller “may not impose any further restrictions on the recipients’ exercise of the rights.” The GPL greatly curtails most plans to sell Drupal modules, and these would-be capitalists might have more success selling popsicles during a blizzard.

Yet the GPL does not close the debate on this subject. I have heard many reasons provided to justify revisiting this conversation, and most frequently they come down to money. Let me share some direct quotes used to justify the pursuit of a “Drupal Marketplace,” “paid Drupal apps,” or “paid modules”:

I have read and listened to a great deal of arguments defending these commercial endeavors, and I remain unconvinced that the potential upsides outweigh the considerable drawbacks.

A History of Failure

The words of the American literary critic Fredric Jameson influence my thinking on this topic: “always historicize!” A look at attempts to sell Drupal modules reveals a distinct lack of success, and yet people continue to claim they have found a solution. Consider SubHub, who announced in 2011 to great fanfare the “World’s First Drupal-Powered App Store.” They hoped to offer some of their “apps” at no cost, while other “apps” would require a small recurring charge. This plan failed and SubHub abandoned their initiative in 2013, lamenting the fact that the Drupal community “simply didn’t share the same motivation to make Drupal a highly commercial, competitive alternative to WordPress.” My apologies to anyone who built a Drupal site with integral SubHub functionality.

Also in 2011 – a big year for “apps” in the Drupal community – Phase2 announced the Open App Standard initiative. The title contains the word “open” so surely this plan would find traction with Drupal people, right? While Phase2 found some success with OpenPublic, which uses apps, I don’t see evidence that “apps” ever found traction in the Drupal community, and certainly not adoption with alacrity.

Keep in mind that many people make money selling Drupal services and that the community generally supports such efforts. I work at a company filled with people who make money building Drupal websites. Rather, I think this evidence shows that paid module schemes tend to fail, that others have found Drupal to be “actually a horrible solution to build apps,” and that when people ask the question, “Is a Drupal App Store a good idea?” the community generally responds with a decisive “no” (unless it features ponies). We absolutely want people to succeed in the community, just not by selling modules.

Certainly exceptions exist. For instance, some companies have found success selling Drupal themes. A case could be made that Acquia, a company founded by Drupal’s creator, peddles its own variety of “paid apps.” The Acquia Connector module “enhances the Drupal experience by providing the support and network services to operate a trouble-free Drupal website.” However, the module does little without an Acquia Subscription, which requires regular payments.

Acquia, and other similar services, get around the restrictions of the GPL by taking advantage of something known as the “application service provider (ASP) loophole.” When the Free Software Foundation published GPL version 2 (all Drupal code must be GPL version 2 or later) in 1991 we did not use web services like we do today. Because providing a subscription service (such as Mollom or New Relic) does not involve distributing software, Acquia need not provide any additional code than that which connects the site to the service.

The Drupal community could adopt a stronger copyleft license that closes the ASP loophole, such as the Affero General Public License (AGPL). Just do not expect this to happen anytime soon. Dries Buytaert, the founder and project lead of Drupal, built a business that takes advantage of this loophole and he made his opinion clear a decade ago in a blog post titled, “Long Live the Web Services Loophole.”

Consequently, the focus of the discussion around paid modules often revolves more around the merits and problems of what Richard Stallman calls “Service as a Software Substitute (SaaSS)” than on actually selling Drupal modules that address common challenges. While some companies have found success with the SaaSS model, why do so many others fail? To answer this question, we must look beyond code and licenses to the Drupal community.

Products and Practices

I wrote at length about the Drupal community in previous articles such as “The Cultural Construction of Drupal” and “Better, then Bigger: Cultivating the Drupal Community,” and I do not intend to re-hash those same ideas here. Rather, I would like to examine why “paid module” schemes have flopped.

As I see it, one fundamental explanation for failure has to do with when business people misunderstand Drupal as a product rather than an organic accumulation of practices, or more broadly, when they ignore the differences between machines and humans. I deliberately add the qualifier “business” to describe these people because all efforts to create paid products are intended to generate revenue. Efforts to sell Drupal modules, in the Marxist sense, epitomize efforts to create capital, to accumulate money – a goal that comes off as at odds with a community that values participation.

All modules that come with a fee are intended to generate revenue, but we must not forget that “free” modules (that are also “Free”) have the potential to do the same. Many people, including me, enjoy getting paid to write Drupal code. For the paid module argument to work, its defendant must demonstrate that existing models are somehow lacking. Defending a new commercial approach necessitates, in my view, demonstrating the unsatisfactory nature of a free software project with more than 33,000+ shared modules that has existed for more than 15 years and has a vibrant marketplace of vendors offering Drupal services. Such an argument not only requires a high level of mental gymnastics, it, at least tacitly, represents an affront to years of successful collaboration.

Because some of those recommending that Drupal re-evaluate its commercial ecosystem are contributing members of the community, I open myself up to the critique of constructing inaccurate divisions, pitting Drupal and its community against business people who desire to convert Drupal into a revenue-generating product. But we know too well that many of us in the Drupal community could represent either side. We aim to balance our need to support our families with our desire to defend Drupal and fight for its freedom. Luckily, we can often choose both.

Drupal as Art

Moving away from discussions of licenses and capitalist motives, I would now like to venture beyond the typical boundaries of the “paid module” discussion to explore why people feel so connected to Drupal. I get the sense that many people in the Drupal community do not actually understand the intricacies of the GPL and how it differs from other free software licenses such as the AGPL. I believe that the community is protecting something more ephemeral. Consequently, this part of my argument ventures into much more abstract topics and requires thinking about Drupal differently, less as a “technology” and more as an artistic practice.

I am not the first person to notice Drupal’s artistic side. For example, a DrupalCon session had the title “Zen and the Art of Drupal.” Someone else even created a new word, “Drupl’Art,” to describe “Drupal code that is both beautiful and artistic.” The conception of “Drupal as art” is not new, but I am going to be using it here in order to offer new insights into how the Drupal community works.

More than just a thought experiment, the idea of Drupal as art becomes useful when we position it within another long-running debate, namely the effect of technology on art. For instance, when proponents position technological advances as something that improves the lives of many, critics will sometimes note that those advances also threaten the purity of art – for example, photographs (the “new technology”) were seen as a threat to portraiture (“pure art”). Ironically, Drupal, as I construct it here plays the role of art, even as we cannot deny that most people would label Drupal “technology” well before they would ever call it “art.” And yet when members of the Drupal community react negatively to the suggestion of paid modules, it is not simply because of the GPL, it is because the community is defending its perceived “purity.”

Drupal and art have both been understood as pure expressions, deeply tied to their predecessors, consisting of ever changing practices, and driven by community. Yet it would be idle to suggest that concerns about the threat of technology to art are exactly the same as concerns about the effect of paid modules on Drupal’s ecosystem. Nonetheless, I believe that we can better understand the Drupal community’s typical allergic reaction to “paid modules” by interrogating previous debates about technology and art.

This line of reasoning follows a long history of thinkers who have conflated art and technology that goes at least as far back as Ancient Greece. The Greeks did not enjoy art for aesthetic reasons. The word “technology” refers to a “treatise on a practical art or craft” and its Greek root is techne. For the Greeks, techne also referred to art. Aristotle described techne as both practical knowledge and practical art. And what Drupal enthusiast would not admit that most websites convey practical knowledge?

In his 1954 essay, “The Question Concerning Technology,” the German philosopher Martin Heidegger variously described both art and technology as a “mode of revealing,” a way of “bringing forth.” A painting reveals another person’s point-of-view and a website “reveals” information. As uncomfortable as it may seem to some among us to describe Drupal as art, it helps explain why people feel so connected to Drupal and vigorously defend its purity. The community wants to work together and reveal its solutions rather than hide them behind a web service. Developers treasure not just revealing websites, but revealing (sharing) the code in the modules that enables their functionality.

Another well-regarded German philosopher, Walter Benjamin, provided valuable insights that are useful for our purposes in his 1936 essay, “The Work of Art in the Age of Its Technological Reproducibility.” Therein Benjamin explores when inventions such as photography and film (both being kinds of “mechanical reproduction”) “separated art from its basis in cult, the semblance of its autonomy disappeared forever.” Not only did these products threaten the group, they also threatened the group’s output (its art). He believed that “the unique value of the ‘authentic’ work of art always has its basis in ritual.” Likewise in the Drupal community we value ritual: we discuss issues, post patches, review the work of others, attend camps and cons, celebrate the accomplishments of new members, and create code with unique value – code that lives with other Drupal code on Drupal.org. Hiding code threatens our rituals.

Paid modules or services revoke our access, our autonomy, and our beloved practices. Drupal is something people do, and we cannot learn by doing when we cannot see the code. Products are purchased, while practices are lived. Drupal, like other forms of techne, is communication, and we cannot communicate in the same manners with black boxes as we can in the issue queue.

In addition to affecting what we do, the existence of paid modules could negatively affect perceptions of the Drupal community. Benjamin writes of a “decay of the aura,” which sounds much like what the Drupal community works against. While some may argue, as one Slate writer did, simply that “Drupal hates change,” many in the Drupal community still believe that Drupal exudes a sort of magical aura. We hold the community close to our hearts and defend its name. We do not half-heartedly promote our community, we instead speak of our “unique, diverse Drupal community,” say that “Drupal has made a big difference in my life,” and that “I’m truly proud to be part of this community.” We protect our people, practices, and reputation by following the Drupal Code of Conduct, in the hope that “we preserve the things that got us here.”

Our current system for creating modules on Drupal.org values the work of humans. Benjamin observes, “What matters is the way the orientation and aims of that technology differ from those of ours. Whereas the former made the maximum possible use of human beings, the latter reduces their use to the minimum.” Drupal is not so much the thing that is built but the way it is built by people. In fact, one of Lullabot’s most frequently quoted core values is “be human.”

The Drupal software will never be complete, and we hope the sharing continues indefinitely. In the same spirit, Benjamin believes, “It has always been one of the primary tasks of art to create a demand whose hour of full satisfaction has not yet come.” The Drupal community wants to continue building, to keep moving forward, never content that we have finally arrived at an “end” where our interactions have been replaced by web services.

Fredric Jameson once warned that “machines are indeed machines of reproduction rather than of production.” The Drupal community has produced a great deal of code that powers much of the web. Few among us would want to shift from production to reproduction, from working together to solve problems to purchasing solutions to problems. Repeatedly and continuously solving the sames problems – building the same websites – breeds boredom. We like to create new and shiny things, producing not reproducing. Our rituals, our process, and our freedom to tinker allows us to continuously move forward.

The Contrasting Case of WordPress

Even if these theories accurately describe the Drupal community, they do not fully account for the success of paid WordPress plugins. Do paid plugins make WordPress unpure, inhabited by a community of dispassionate contributors? Absolutely not. Does the availability of paid plugins somehow cheapen the WordPress community or imply that WordPress lacks meaningful rituals? Certainly no. WordPress powers a huge chunk of the web with GPL-licensed code. It would be fruitless to deny the overwhelming success of a project with a vibrant community. Rather, I hope to convey how the WordPress community’s embrace of paid plugins informs my argument that the Drupal community understands its practices as a kind of artistic expression.

Simply suggesting that WordPress and Drupal are different helps about as much as arguing that Drupal and WordPress are words that contain an incommensurable number of letters. We could go a step further, as Dries Buytaert often does and argue not only are they different, but that WordPress and Drupal target different markets, with “WordPress dominating the small business segment” and Drupal geared toward the “larger organizations with more complex requirements” (an idea I dispute). If that were true, one would think the community that caters to “large organizations” would have the customers with the funds to purchase modules rather than get them at no cost. Then again, the reverse argument seems equally defensible, and that small businesses would rather pay for plugins than for those reportedly expensive Drupal developers. None of these avenues feel satisfactory.

One might expect that WordPress and Drupal espouse contrasting ideas about paid add-ons and the GPL. Quite the contrary, the Wordpress.org licensing page provides clear guidance about how plugins should be licensed: “derivatives of WordPress,” including plugins and themes, “inherit the GPL license.” While they admit to “some legal grey area regarding what is considered a derivative work,” they “feel strongly that plugins and themes are derivative work and thus inherit the GPL license.” The community leaders back up their assertions with thoughtful discussion as well as expert analysis from the Software Freedom Law Center. The WordPress licensing page even provides a link to Drupal’s “excellent page on licensing as it applies to themes and modules (their word for plugins).” Thus, WordPress and Drupal provide almost exactly the same guidelines.

Remarkably, certain members of the WordPress community completely ignore the advice on the licensing page. They claim “the GPL FAQ has no legal validity.” Some sellers proudly declare, “got my own licensing terms” and others offer code with terms and conditions that make no mention of the GPL. Some explain the norm thusly: “Premium WordPress plugin and theme developers usually sell you a license key, which allows you access to support and automatic upgrades.” One store believes it takes advantage of GPL loopholes and sells plugins under a default split license ostensibly to “protect authors.” In other words, the WordPress.org plugin directory that lists over 40,000 plugins is not a comprehensive directory of WordPress plugins. If this sounds a bit like the Wild West, then you may be a Drupal developer.

If Drupal modules are about process, then WordPress plugins – at least a portion of them – are products. Members of the WordPress community write at length about the benefits of "premium products." Some stores offer plugins that are “guaranteed to work, always updated, top quality plugins. Beautifully coded, packed with features, and easy to use.” They offer “free trials.” Another store proudly trumpets its “professionally developed and supported options not found on WordPress.org.” Ventures of this nature are justified with such syllogisms as “‘free’ doesn’t make me rich.” Plugins like these are products, plain and simple, and clearly the WordPress community (“happy customers,” as one site put it) willingly pays.

In comparison, Drupal developers get modules from Drupal.org. More than just a “best practice,” this is the norm in the Drupal community. It keeps things simple, and has a practical benefit: acquiring a new module requires typing drush dl module-name.

Incidentally, another kind of software facilitates an analogous workflow: GNU/Linux. For example, to install software on my operating system, Debian, I type apt install package_name. I would never consider downloading software to my computer from some random website, let alone software that I could not inspect. For me, at least, these two processes (drush dl and apt get) feel nearly identical, and I could make a good argument that the Drupal community is more like the Debian community (i.e., that many of the commitments outlined the Debian Social Contract are lived in the Drupal community) than the WordPress community.

Once again, the words of Benjamin feel relevant: “It might be stated as a general formula that the technology of reproduction detaches the reproduced object from the sphere of tradition. By replicating the work many times over, it substitutes a mass existence for a unique existence.” App stores for paid plugins fragment traditions established on WordPress.org. The Drupal community, on the other hand, has decided not to purchase paid Drupal modules, not to depart from its tradition of keeping Drupal as close to 100% free as possible. Whenever this issue arises, the Drupal community votes with its voices and its wallets to favor practices over products, to reveal the modules it creates rather than conceal them behind paywalls, to work with – rather than sell to – each other. The fact that WordPress customers have chosen a different path reveals contrasting, not misplaced, priorities.

While it is difficult to generalize a community with more than a million users (or at least user accounts), Holly Ross, Executive Director of the Drupal Association, believes “the one thing we all have in common is that we care about the fate of Drupal.” It might be fate that someday paid modules will find success in the Drupal community, and that would not necessarily be wrong. It would mean, however that the essence of Drupal has changed. That may even signal the end of Drupal. But history suggests that day will not soon come. Until then, the Drupal community will continue to defend its practices. It will band together to resist paid module schemes, treat its software with a reverence that others reserve for works of art, share code, and encourage others to do the same.

Works Cited

Benjamin, Walter. The Work of Art in the Age of Its Technological Reproducibility, and Other Writings on Media. Edited by Michael W. Jennings, Brigid Doherty, and Thomas Y. Levin. Cambridge, Mass: Belknap Press, 2008.

Heidegger, Martin. The Question Concerning Technology and Other Essays. New York: Harper Perennial, 1977.

Jameson, Fredric. The Political Unconscious: Narrative as a Socially Symbolic Act. Cornell University Press, 1982.

Jameson, Fredric. Postmodernism, or, The Cultural Logic of Late Capitalism. Duke University Press, 1992.

Welcome to Drupal

Drupal 8 is here! And with all the new bells and whistles that the community built into the administrative experience, it’s simpler than ever to get your site up and running. If you’ve worked with Drupal before, you’re probably familiar with terms like “node” and “theme,” and you may have even installed Views to generate blocks of content to drop into regions in your page template. However, if you are new to Drupal, these words may seem more appropriate in a video game than in your website. You’ve come to the right place! Allow me to show you around and introduce you to Drupal.

If you’d like to follow along at home you’ll need to have a working Drupal 8 site up and running, though it's not required to continue though this article. The easiest way to get a Drupal site up and running is to sign up for a service like Pantheon or download Acquia’s Dev Desktop. If you’re more of a do-it-yourself-er, you’ll first need to setup a local environment. There is documentation on Drupal.org for just about any system you might be running. Then you’ll need to install Drupal 8. You can follow the steps in Drupal’s install.txt file, or try this tutorial written by Hui Jing.

The Basics

Before we start pushing buttons and twisting knobs, let’s go over some basic terminology. I listed the terms we'll talk about in a glossary at the bottom of the page for an additional reference.

When you download Drupal, you are downloading a set of files called Drupal core. These files make up everything Drupal needs to function. Inside there are modules, which extend Drupal’s functionality, and themes, which provide the front-end structure, layout and design. Drupal core comes with some modules that are required, others that you can enable if you like, and there are a plethora of modules created by the community on Drupal.org that you can install separately to add functionality to your site. Just like modules, Drupal ships with some themes you can use right out of the box, or you can download and install one from the community. Some themes are designed to be used right away with just a little configuration. Others are known as base themes, which provide some basic structure and are intended to be used as a starting point to create your custom theme. For example, you can choose Bartik or Seven and have a good looking and functional site right away. In fact, Seven is the theme that is used for administrative pages. Classy and Stable are two base themes in Drupal core that you can use to start building out your own theme. Check out Marc Drummond's article "A Tale of Two Base Themes in Drupal Core" to learn more about these awesome tools.

Now that we know the basics, let’s take a look at what Drupal does.

Creating Content

Every website has different requirements, but most commonly the goal is to create content that you can deliver to your visitors. In Drupal we do this by using the administrative tools to create a content type, for example Event. We then add fields to it such as Date and Location. Now we can create pieces of content, commonly referred to as nodes, of the type Event. When we add a new event, Drupal will automatically create a URL to view it and will display it in a nice format. In the simplest form that's all we need! We can create events and give people URLs where they can view them.

If you are playing along at home, this is a good place to try things out for yourself. See if you can complete the following steps:

  1. Create a new content type. Call it whatever you like.
  2. Add two fields to the content type.
  3. Create a new piece of content of this type.
  4. Visit the URL that Drupal provides to view it.

Defining content types and adding the necessary fields to them is the basis for getting content into Drupal, but what if we want to change the way it is presented on the screen? Luckily, Drupal also makes it very easy for us to change the order in which the fields appear, their formatting, their labels and even whether they should be displayed at all.

Customizing the Display

When you are adding fields to a content type you'll notice a tab labeled Manage Display. On this tab you can drag your fields up and down to reorder them, hide or show the labels and many more options depending on the fields you created. Just above the field table you’ll notice a secondary set of tabs with the option of Default selected. These are view modes. The most common way of viewing content is by visiting its url, but there are times we want to display a piece of content in a different format, for example, as a teaser in a list of recent posts. View modes let us change the way a node is displayed. If we don’t choose a specific view mode, the Default view mode is selected. A couple of common view modes are provided out of the box and can be found under Custom Display Settings at the bottom of the Manage Display page. We can also define different view modes for different purposes by going to Structure > Display Modes > View Modes through the toolbar. For the content we’ve created so far, Drupal will use the Default view mode when we visit that node’s URL. We'll talk more about ways to use view modes later. Next, let's talk about how to create custom pages that are not just pieces of content, such as an events list, blog roll, or your homepage.

So far Drupal has been providing URLs for the content we created. Somewhere in our website, however, we’ll likely want pages that show not just a single piece of content but collections of many pieces content. Maybe we want to list all of our upcoming events on the homepage. There are many modules that can help us create and manage custom pages, but installing new modules is slightly out of scope for this article. Luckily, Drupal comes with a module will take us pretty far called Views.

Custom Lists of Content

The Views module lets us define filters and sorting mechanisms to create lists of content. It calls these lists views. The Views module also allows us to display that content in a variety of formats. For example, if we want a list of the 5 most recent blog posts or the next upcoming event, we can create a view to get that content and format it for us. Let’s continue with events as an example.

When we create a new view from the admin interface, we give it basic information about what we want, such as the type of content we are looking for and how to sort it. Next we create different displays of that view. We could create a Block display to show the next upcoming event, and a Page display to show all upcoming events. Views will even link them together for us.

If you are playing along at home, this is a good place to try things out for yourself. See if you can complete the following steps:

  1. Add a new view and limit it to the content type you created earlier.
  2. Enable the Page and Block options, then Save and Edit.
  3. Visit the URL for the page you created to view it.

There are many ways to configure a view, but for now you have the basics. One last piece that we haven’t talked about yet are blocks. Blocks are small chunks of content that don’t deserve their own page, but more likely live in a separate region like a sidebar or footer. Let’s add a block to one of our pages.

Working with Blocks

Opening the blocks UI from the admin toolbar, you’ll see a list of regions with a button to Place Blocks. These regions are defined in the current theme. If you enable a new theme or create one yourself, the regions will likely change. Use the Place Blocks button to choose a block from the available list and put it into a region. If you created a view in the last section, you should see your view block in the list! Each block can be configured to only show on certain pages, to certain users, etc. After adding your block to a region, use the button at the bottom to save your changes, and you should now see your new block in whichever region you added it.

Now you have all the tools necessary to start building your website in Drupal 8. You can create content types, add fields to them, change the way they are displayed, create lists of content with Views and place blocks into your layout. There’s a lot more that Drupal can do, and the best way to learn is by trying. Now that you have a grasp on the basics, explore some of the other fields and settings in the content types, views and blocks. On behalf of the Drupal community, welcome!

Glossary

These are some of the terms I referenced. There is a more complete glossary at https://www.drupal.org/glossary.

Base Theme
A Base theme is a well-written set of CSS and template files that a theme developer can make use of in a new custom theme. Theme developers can make sub themes to override the default base theme. Some of the popular base themes include Zen, Omega and AdaptiveTheme.
Block
The boxes visible in the regions of a Drupal website. Most blocks (e.g. recent forum topics) are generated on-the-fly by various Drupal modules, but they can be created in the “administer blocks” area of a Drupal site.
Drupal Core
The files and modules included with the Drupal project download.
Module
Software (usually PHP and CSS) that extends Drupal features and functionality. Drupal distinguishes between “core” and “contributed” modules.
Content Type
Every node belongs to a single “node type” or “content type”, which defines various default settings for nodes of that type, such as whether the node is published automatically and whether comments are permitted. Common "Content Types" that just about any website would have include: blog post and page. Content types can have different fields and modules can define their own content types. The core Drupal Book and Poll modules are two examples of modules that define content types.
Field
Elements of data that can be attached to a node or other Drupal entities. Fields commonly contain text, image, or terms.
Node
A piece of content in Drupal, typically corresponding to a single page on the site, that has a title, an optional body, and perhaps additional fields. Every node also belongs to a particular content type, and can additionally be classified using the taxonomy system. Examples of nodes are polls, stories, book pages and images.
Region
Defined areas of a page where content can be placed. Basic regions include: Header, Footer, Content, Left sidebar, Right Sidebar. Different themes can define different regions so the options are often different per-site. Content is assigned to regions via blocks. They can be ordered by weight within regions to define the order in which they display.
Theme
A file or collection of files (PHP, INFO, CSS, JPG, GIF, PNG), which together determine the look and feel of a site. A theme contains elements such as the header, icons, block layout, etc. Drupal modules define themeable functions which can be overridden by the theme file. There are additional themes available in the themes section of downloads.
View Mode
A view mode is way to customize how an entity is rendered. Examples are 'Full Page', 'Teaser' or 'JSON'. In Drupal 8 this is located under Structure > Display Modes.
Views
A module which allows site developers a graphical interface for creating lists of various Drupal entities; most notably users and nodes. Views permits selection of specific fields to display, filtration against various attributes, choice of basic layout options (i.e. list, full entities, teasers, etc.), and other more advanced features. Many Drupal sites use Views extensively. In Drupal 8, the Views module is part of Drupal Core.
View
In reference to the Views module above, a view is what is created when the site builder adds or creates a new view from the interface. Each view uses a table in the database as a "base table" to build a list of objects. The view by itself is an abstract wrapper of instruction that are inherited by each view display created within the view.
View Display
In reference to the Views module above, view displays are created inside of a view to display the objects fetched by the view in different manners. For example, a view called "Blog Posts" might have view displays for "Top 5", "Most Recent", or "Posts by Author".

Injecting services in your D8 plugins

Drupal 8's plugin system is one of the most flexible and widely used subsystems in Drupal. If you are a developer, chances that you will write plugins in Drupal 8 are high.

A couple of months ago I made a case in favor of unit tests in a series of articles. Today I have good news for you, your plugins are good candidates for testing! Before you get carried away by overexcitement, it's likely that your plugins depend on other parts of the system, and that complicates things a little bit. In these cases, it is a good idea to inject the services that include the dependencies you need. Dependency injection is an alternative to the static \Drupal::service. If you don't inject your services you will have a hard time writing unit tests for your plugin's code.

There are, at least, two widely spread patterns in Drupal 8 in order to inject services into your objects. The first uses a service to inject services. The second uses a factory method that receives Drupal's container. Both of these involve the dependency injection container, although you can still inject services using other manual techniques.

Injection via services

When you declare a new service you can also specify the new service’s dependencies by using the arguments property in the YAML file. You can even extend other services by using the parent property, having the effect of inheriting all the dependencies from that one. There is thorough documentation about writing services on drupal.org. The following example defines a service that receives the entity manager:

services: plugin.manager.network.processor: class: Drupal\my_modyle\Plugin\MyPluginManager arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@entity.manager']

You cannot use this pattern directly to inject services to a plugin, since your plugin cannot be a service. This is because services are one-instance classes, a global object of sorts. Plugins are –by their definition– multiple configurable objects of a given class. However, the plugin manager is a great candidate to be a service. If you declare your plugin manager as a service, and inject other services to it, then you are only one step away from injecting those services into the actual plugin instances. To do so you only need to do something similar to:

class MyPluginManager extends DefaultPluginManager { protected $entityManager; … public function createInstance($plugin_id, array $configuration = array()) { $instance = parent::createInstance($plugin_id, $configuration); $instance->setEntityManager($this->entityManager); return $instance; } }

As you can see (aside from the lack of docblocks for brevity), every time that your plugin manager creates an instance of a plugin it will set the entity manager for that particular instance. in this scenario you only need to write setEntityManager in your plugin. This strategy is a mix of service injection and setter injection.

Factory injection

The other big injection pattern in Drupal 8 involves adding all your dependencies as arguments in the constructor for your class (also known as the constructor injection pattern). This pattern is very straightforward, you just pass in all the dependencies upon object creation. The problem arises for objects that Drupal instantiates for you, meaning that you don't get to do new MyClass($service1, $service2, ...). How do you pass the services to the constructor then? There is a convention in the Drupal community to use a factory method called create. To implement it you need to write create static method that will receive the dependency injection container as the first parameter. The create method should use the container to extract the services from it, and then call the constructor. This looks like:

class MyOtherClass { … public function __construct($service1, $service2, ...) { // Store the services in class properties. } public static function create(ContainerInterface $container) { // new static() means "Call the constructor of the current class". // Check PHP’s late static binding. return new static( $container.get('service1'), $container.get('service2'), … ); } }

There is the remaining question of "who calls the create method with the container as the first parameter?". If Drupal is instantiating that object for you, then the system should know about the _create method pattern_ for that particular object.

The default plugin manager (\Drupal\Core\Plugin\DefaultPluginManager) will use the container factory (\Drupal\Core\Plugin\Factory\ContainerFactory) to create your plugin objects. It is very likely that your new plugin manager extends from the default plugin manager –via code scaffolding or manual creation–. That means that by default if you add a create method to your plugin, it will be ignored. In order to have your new plugin manager use the create pattern, the only thing your plugins need is to implement the ContainerFactoryPluginInterface. In that case your plugin will look like:

class MyPluginBase extends PluginBase implements PluginInspectionInterface, ContainerFactoryPluginInterface { protected $entityManager; … public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->entityManager = $entity_manager; } public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity.manager') ); } }

The plugin manager will detect that the object that it's about to create implements that interface and will call the create method instead of the basic constructor.

The plugin system is so extensible that you may run into corners where those techniques are not enough. Just know that there are other ways to achieve this. Some of those, for instance, involve using a different factory in the plugin manager, but that is out of the scope of this article.

Sometimes the create factory method pattern can be considered a bit more robust, since it does not involve injecting the services to an object that doesn't need them –the plugin manager– only to pass them down to the plugin. Regardless of the approach that you use, you are now in a good position to start writing unit tests for your plugin class.

Drupalcon: A Look Ahead to ‘Nawlins

Matt and Mike talk with Drupalcon organizers Rachel Friesen, Amanda Gonser, and Tina Krauss, alongside NOLA natives Eric and Sabrina Schmidt. We talk session and site submission criteria, and where the next Drupalcon will be! We also talk a lot about 'Nawlins including what and where to eat, where to listen to music, museums, what's within walking distance, and lots more!

Pages