Like so many of you, both here in the United States and elsewhere, I am deeply troubled by the incidents of hateful harassment and the threats to democracy that have spiked since November 8. My thoughts have been routinely consumed with the task of analyzing my work and motivations, trying to detect any positive impact that my contributions have on the world. Because of my involvement in the Drupal community, my thoughts are as much about Drupal as they are about me. I am a proud member of our community and I cannot help but reflect on how the organization of our community brings people together, discourages hate, and promotes democracy.
What it would mean to "make the world better" is up for debate. We cannot be experts in all subjects, and a group of Drupal developers might not fully understand, for example, the policies that allow tax havens, the economic implications of a $15 minimum wage, how to combat predatory lending, or the solutions to climate change. Perhaps we have strong opinions on these topics, but many of us would begrudgingly admit that we know more about dependency injection, re-rolling patches, or even the hook system. That is, we know how to build Drupal websites. More importantly, to succeed in the Drupal community we are required to be considerate, respectful, and collaborative. We, as a community, vigorously reject bigotry, racism, sexism, homophobia, and xenophobia. This, in my view, makes the world better.
What is more, I would argue that Drupal blurs traditional boundaries. While certainly there are market forces that determine how Drupal is constructed, powerful legal and cultural nonmarket forces push back. Some Drupal agencies exist to turn a profit, but do so working primarily with public sector or non-profit organizations. Drupal agencies can be seen as capitalist in the sense that they accumulate surplus value by "exploiting the working class," but socialist in the sense that they produce goods that are owned collectively. Some have stated goals to invest value back into the community and others are "benefit corporations," required to make the world a better place. While I am tempted to place new labels on the Drupal community, such as "post-capitalist," I find such terms to be of limited use, and I am far more interested in finding common ground that unites our community.
Drupal code has only limited value without the community, and our community stands for values that transcend our code. I participate in the Drupal community because I believe it represents ideals that are consistent with my own. One of the beliefs that we hold in high regard is "doing good." It would be difficult to convince me that people, such as George DeMet and Tiffany Farriss, Todd Ross Nienkerk, or Lev Tsypin, have anything but the best intentions in the way they run their businesses. More importantly, these individuals, like so many others in our community, actually do make the world a better place through their work, compassion, and advocacy.
In some respects, the well-intentioned subset of our community exemplifies what Luc Boltanski and Eve Chiapello describe as "the new spirit of capitalism." In their study of management textbooks, they find this "new spirit" is characterized by, among other things, a "high moral tone" (58), a belief that workers should "control themselves" (80), structures where managers are essentially replaced with customers (82), and where bureaucracy represents a kind of "totalitarianism and arbitrariness" that should be avoided (85). While Boltanski and Chiapello find many faults with this "new spirit," generally, I would suggest that is has become more important than ever to acknowledge the many benefits that the people and organizations in our community have for the world. While critique and criticism will surely be needed, we should also continue to celebrate the impact that our software and colleagues plays in efforts towards ending poverty, empowering independent journalists, defending the free and open Internet, and educating people. Even though Drupal has been used for nefarious purposes, and there are many reasons to critique the Drupal community, I feel emboldened knowing that when people came together to build websites for DeanSpace, the United Nations, Amnesty International, Greenpeace, Oxfam, the ACLU, the Electronic Frontier Foundation, National Public Radio, Free Press, and the White House, they choose Drupal.
More than just software, part of the reason we "stay for the community" is because we place such a high premium on human interaction. Drupal contributors create public goods (free software) that can be used by one person without reducing the availability to others. If the public relations departments of mega-corporations extol the value of business and markets, while criticizing government and fair labor, the Drupal community takes an alternative approach that values solidarity. In this sense, our democratic practices threaten unjust power. Throughout history people in power have pushed back against the democratizing effects of solidarity to defend their positions of power. In his 1776 magnum opus on political economy, Wealth of Nations, Adam Smith famously observed, "All for ourselves and nothing for other people, seems, in every age of the world, to have been the vile maxim of the masters of mankind." With every Drupal Camp, DrupalCon, code sprint, community summit, and user group meeting we gather together in solidarity. Let us not forget all we do to encourage hope and camaraderie.
If you are discouraged by a world that turns workers against each other and treats citizens as consumers, pushing them to the malls rather than the public library, remember that we as a Drupal community are pushing back against the "masters of mankind." In the 1970s, Buckley v. Valeo may have determined that money is a form of speech, but because we work together, Drupal becomes another kind of speech. Most of us (the working class) must sell our labor in return for a wage or salary. So what I am arguing is not for our community to become noncommercial or anti-commercial, but instead that we consider expanding our horizon of expectations to allow for a conception of Drupal as a political act. I want us to celebrate our community and stand up against hate, inequality, corruption, and depoliticization. If that idea makes you uncomfortable, then perhaps consider the words of the historian Howard Zinn and his suggestion that what matters are "the countless deeds of unknown people who lay the basis for the events of human history." I hope that we can find common ground, build on what we have accomplished, and organize against the forces that seek to divide us against ourselves.
I wanted to find a way to pull data from one Drupal 8 site to another, using JSON API to expose data on one site, and Drupal’s Migrate with a JSON source on another site to consume it. Much of what I wanted to do was undocumented and confusing, but it worked well, once I figured it out. Nevertheless, it took me several days to get everything working, so I thought I’d write up an article to explain how I solved the problem. Hopefully, this will save someone a lot of time in the future.
I ended up using the JSON API module, along with the REST modules in Drupal Core on the source site. On the target site, I used Migrate from Drupal Core 8.2.3 along with Migrate Plus and Migrate Tools.Why JSON API?
Drupal 8 Core ships with two ways to export JSON data. You can access data from any entity by appending ?_format=json to its path, but that means you have to know the path ahead of time, and you’d be pulling in one entity at a time, which is not efficient.
You could also use Views to create a JSON endpoint, but it might be difficult to configure it to include all the required data, especially all the data from related content, like images, authors, and related nodes. And you’d have to create a View for every possible collection of data that you want to make available. To further complicate things, there's an outstanding bug using GET with Views REST endpoints.
JSON API provides another solution. It puts the power in the hands of the data consumer. You don’t need to know the path of every individual entity, just the general path for a entity type, and bundle. For example: /api/node/article. From that one path, the consumer can select exactly what they want to retrieve just by altering the URL. For example, you can sort and filter the articles, limit the fields that are returned to a subset, and bring along any or all related entities in the same query. Because of all that flexibility, that is the solution I decided to use for my example. (The Drupal community plans to add JSON API to Core in the future.)
There’s a series of short videos on YouTube that demonstrate many of the configuration options and parameters that are available in Drupal’s JSON API.Prepare the Source Site
There is not much preparation needed for the source because of JSON API’s flexibility. My example is a simple Drupal 8 site with an article content type that has a body and field_image image field, the kind of thing core provides out of the box.
First, download and install the JSON API module. Then, create YAML configuration to “turn on” the JSON API. This could be done by creating a simple module that has YAML file(s) in /MODULE/config/optional. For instance, if you created a module called custom_jsonapi, a file that would expose node data might look like:filename: /MODULE/config/optional/rest.resource.entity.node.yml: id: entity.node plugin_id: 'entity:node' granularity: method configuration: GET: supported_formats: - json supported_auth: - basic_auth - cookie dependency: enforced: module: - custom_jsonapi
To expose users or taxonomy terms or comments, copy the above file, and change the name and id as necessary, like this:filename: /MODULE/config/optional/rest.resource.entity.taxonomy_term.yml: id: entity.taxonomy_term plugin_id: 'entity:taxonomy_term' granularity: method configuration: GET: supported_formats: - json supported_auth: - basic_auth - cookie dependency: enforced: module: - custom_jsonapi
That will support GET, or read-only access. If you wanted to update or post content you’d add POST or PATCH information. You could also switch out the authentication to something like OAuth, but for this article we’ll stick with the built-in basic and cookie authentication methods. If using basic authentication and the Basic Auth module isn’t already enabled, enable it.
Navigate to a URL like http://sourcesite.com/api/node/article?_format=api_json and confirm that JSON is being output at that URL.
That's it for the source.Prepare the Target Site
The target site should be running Drupal 8.2.3 or higher. There are changes to the way file imports work that won't work in earlier versions. It should already have a matching article content type and field_image field ready to accept the articles from the other site.
Enable the core Migrate module. Download and enable the Migrate Plus and Migrate Tools modules. Make sure to get the versions that are appropriate for the current version of core. Migrate Plus had 8.0 and 8.1 branches that only work with outdated versions of core, so currently you need version 8.2 of Migrate Plus.
To make it easier, and so I don’t forget how I got this working, I created a migration example as the Import Drupal module on Github. Download this module into your module repository. Edit the YAML files in the /config/optional directory of that module to alter the JSON source URL so it points to the domain for the source site created in the earlier step.
It is important to note that if you alter the YAML files after you first install the module, you'll have to uninstall and then reinstall the module to get Migrate to see the YAML changes.Tweaking the Feed Using JSON API
The primary path used for our migration is (where sourcesite.com is a valid site):http(s)://sourcesite.com/api/node/article?_format=api_json
This will display a JSON feed of all articles. The articles have related entities. The field_image field points to related images, and the uid/author field points to related users. To view the related images, we can alter the path as follows:http(s)://sourcesite.com/api/node/article?_format=api_json&include=field_image
That will add an included array to the feed that contains all the details about each of the related images. This way we won’t have to query again to get that information, it will all be available in the original feed. I created a gist with an example of what the JSON API output at this path would look like.
To include authors as well, the path would look like the following. In JSON API you can follow the related information down through as many levels as necessary:http(s)://sourcesite.com/api/node/article?_format=api_json&include=field_image,uid/author
Swapping out the domain in the example module may be the only change needed to the example module, and it's a good place to start. Read the JSON API module documentation to explore other changes you might want to make to that configuration to limit the fields that are returned, or sort or filter the list.
Manually test the path you end up with in your browser or with a tool like Postman to make sure you get valid JSON at that path.Migrating From JSON
I had a lot of trouble finding any documentation about how to migrate into Drupal 8 from a JSON source. I finally found some in the Migrate Plus module. The rest I figured out from my earlier work on the original JSON Source module (now deprecated) and by trial and error. Here’s the source section of the YAML I ended up with, when migrating from another Drupal 8 site that was using JSON API.source: plugin: url data_fetcher_plugin: http data_parser_plugin: json urls: http://sourcesite.com/api/node/article?_format=api_json ids: nid: type: integer item_selector: data/ fields: - name: nid label: 'Nid' selector: /attributes/nid - name: vid label: 'Vid' selector: /attributes/vid - name: uuid label: 'Uuid' selector: /attributes/uuid - name: title label: 'Title' selector: /attributes/title - name: created label: 'Created' selector: /attributes/created - name: changed label: 'Changed' selector: /attributes/changed - name: status label: 'Status' selector: /attributes/status - name: sticky label: 'Sticky' selector: /attributes/sticky - name: promote label: 'Promote' selector: /attributes/promote - name: default_langcode label: 'Default Langcode' selector: /attributes/default_langcode - name: path label: 'Path' selector: /attributes/path - name: body label: 'Body' selector: /attributes/body - name: uid label: 'Uid' selector: /relationships/uid - name: field_image label: 'Field image' selector: /relationships/field_image
One by one, I’ll clarify some of the critical elements in the source configuration.
File-based imports, like JSON and XML use the same pattern now. The main variation is the parser, and for JSON and XML, the parser is in the Migrate Plus module:source: plugin: url data_fetcher_plugin: http data_parser_plugin: json
The url is the place where the JSON is being served. There could be more than one URL, but in this case there is only one. Reading through multiple URLs is still pretty much untested, but I didn’t need that:urls: http://sourcesite.com/api/node/article?_format=api_json
We need to identify the unique id in the feed. When pulling nodes from Drupal, it’s the nid:ids: nid: type: integer
We have to tell Migrate where in the feed to look to find the data we want to read. A tool like Postman (mentioned above) helps figure out how the data is configured. When the source is using JSON API, it’s an array with a key of data:item_selector: data/
We also need to tell Migrate what the fields are. In the JSON API, they are nested below the main item selector, so they are prefixed using an xpath pattern to find them. The following configuration lets us refer to them later by a simple name instead of the full path to the field. I think the label would only come into play if you were using a UI:fields: - name: nid label: 'Nid' selector: /attributes/nid Setting up the Image Migration Process
For the simple example in the Github module we’ll just try to import nodes with their images. We’ll set the author to an existing author and ignore taxonomy. We’ll do this by creating two migrations against the JSON API endpoint, first one to pick up the related images, and then a second one to pick up the nodes.
Most fields in the image migration just need the same values they’re pulling in from the remote file, since they already have valid Drupal 8 values, but the uri value has a local URL that needs to be adjusted to point to the full path to the file source so the file can be downloaded or copied into the new Drupal site.
Recommendations for how best to migrate images have changed over time as Drupal 8 has matured. As of Drupal 8.2.3 there are two basic ways to process images, one for local images and a different one for remote images. The process steps are different than in earlier examples I found. There is not a lot of documentation about this. I finally found a Drupal.org thread where the file import changes were added to Drupal core and did some trial and error on my migration to get it working.
For remote images:source: ... constants: source_base_path: 'http://sourcesite.com/' process: filename: filename filemime: filemime status: status created: timestamp changed: timestamp uid: uid uuid: id source_full_path: plugin: concat delimiter: / source: - 'constants/source_base_path' - url uri: plugin: download source: - '@source_full_path' - uri guzzle_options: base_uri: 'constants/source_base_path'
For local images change it slightly:source: ... constants: source_base_path: 'http://sourcesite.com/' process: filename: filename filemime: filemime status: status created: timestamp changed: timestamp uid: uid uuid: id source_full_path: plugin: concat delimiter: / source: - 'constants/source_base_path' - url uri: plugin: file_copy source: - '@source_full_path' - uri
The above configuration works because the Drupal 8 source uri value is already in the Drupal 8 format, http://public:image.jpg. If migrating from a pre-Drupal 7 or non-Drupal source, that uri won’t exist in the source. In that case you would need to adjust the process for the uri value to something more like this:source: constants: is_public: true ... process: ... source_full_path: - plugin: concat delimiter: / source: - 'constants/source_base_path' - url - plugin: urlencode destination_full_path: plugin: file_uri source: - url - file_directory_path - temp_directory_path - 'constants/is_public' uri: plugin: file_copy source: - '@source_full_path' - '@destination_full_path' Run the Migration
Once you have the right information in the YAML files, enable the module. On the command line, type this:drush migrate-status
You should see two migrations available to run. The YAML files include migration dependencies and that will force them to run in the right order. To run them, type:drush mi --all
The first migration is import_drupal_images. This has to be run before import_drupal_articles, because field_image on each article is a reference to an image file. This image migration uses the path that includes the related image details, and just ignores the primary feed information.
The second migration is import_drupal_articles. This pulls in the article information using the same url, this time without the included images. When each article is pulled in, it is matched to the image that was pulled in previously.
You can run one migration at a time, or even just one item at a time, while testing this out:drush migrate-import import_drupal_images --limit=1
You can rollback and try again.drush migrate-rollback import_drupal_images
If all goes as it should, you should be able to navigate to the content list on your new site and see the content that Migrate pulled in, complete with image fields. There is more information about the Migrate API on Drupal.org.What Next?
There are lots of other things you could do to build on this. A Drupal 8 to Drupal 8 migration is easier than many other things, since the source data is generally already in the right format for the target. If you want to migrate in users or taxonomy terms along with the nodes, you would create separate migrations for each of them that would run before the node migration. In each of them, you’d adjust the include value in the JSON API path to pull the relevant information into the feed, then update the YAML file with the necessary steps to process the related entities.
You could also try pulling content from older versions of Drupal into a Drupal 8 site. If you want to pull everything from one Drupal 6 site into a new Drupal 8 site you would just use the built in Drupal to Drupal migration capabilities, but if you want to selectively pull some items from an earlier version of Drupal into a new Drupal 8 site this technique might be useful. The JSON API module won’t work on older Drupal versions, so the source data would have to be processed differently, depending on what you use to set up the older site to serve JSON. You might need to dig into the migration code built into Drupal core for Drupal to Drupal migrations to see how Drupal 6 or Drupal 7 data had to be massaged to get it into the right format for Drupal 8.
Finally, you can adapt the above techniques to pull any kind of non-Drupal JSON data into a Drupal 8 site. You’ll just have to adjust the selectors to match the format of the data source, and do more work in the process steps to massage the values into the format that Drupal 8 expects.
The Drupal 8 Migrate module and its contributed helpers are getting more and more polished, and figuring out how to pull in content from JSON sources could be a huge benefit for many sites. If you want to help move the Migrate effort forward, you can dig into the Migrate in core initiative and issues on Drupal.org.
In my last article, I talked about new options for setting up a development environment in Drupal 8. Having done that, I need to setup a workflow for development as well as a process for deploying changes. Additionally, for this project, I have a partner that I need to share changes with before they go live. It would be really nice for her to be able to preview these changes and push them live after review.
As mentioned in my last article, I have a pretty basic setup for this project. I am doing work on my local laptop, and I have a private repository on Github for my code, and two virtual hosts on my hosting provider. One is a preview site that is password-protected so that we can review changes as they go live, and one is the production website.undefined
There is no custom code at all in the Pinball Outreach Project website outside the theme (and precious little there), but there is a lot of custom configuration that needs to be pushed around. Additionally, some of that configuration is tough to test outside of a site that is publicly accessible. Thankfully, Drupal 8 brings the gift of CMI.The simplest workflow
I realize I may be biased, given my role as the former CMI initiative lead, but I have to say, the D8 configuration management system is an absolute joy. It allows a variety of workflows and performs precisely as advertised. I created a pretty simple workflow for this project, but one of the beauties of the system is that you can create a workflow as simple or complex as needed.
Using the built-in Configuration Synchronization tool that ships with Drupal 8 provides the simplest possible workflow. Go to:
...and download your site's entire configuration as a tarball. You can then go to:
...on the destination site and upload that tarball into the new system. Once you have uploaded your configuration, you are presented with a list of the items that have changed and have the opportunity to review each one.undefined undefined
In this example, I have changed the view called 'Press' to sort descending instead of ascending. If you are happy with these changes, then you can click Import All to integrate them into your site.
While this doesn't give you all the functionality a more technical user might require, it works and would be sufficient for a simpler site.My workflow
I wanted to have a little more control over my configuration and maintain the ability to experiment and roll those changes back if I decided I didn't like them. My process, which is still basic as deployment workflows go, works like this:
- I make some changes through the admin UI on my local development environment.
- I open up a terminal to this environment and run drush config-export -y from the project's root directory. This exports all configuration to your config export directory (see the last article in this series for details about how that is set up.)
- Again, in terminal, I run the git status command to check that my configuration changes are what I expect them to be. If all has gone well, I should see that some configuration files have been modified in my config export directory, and this configuration should only be related to the changes I just made.
- I add the changes to git (git add), commit (git commit -m) and push them (git push).
- Next, I SSH to the destination environment and pull the changes down (git pull).
- Finally, I run drush config-import -y from the project's root on the remote server. This command imports the configuration changes I pulled down from git.
While this might seem like a pretty simple workflow, it is incredibly powerful, especially if you are used to the Features workflows prevalent in Drupal 7. First off, it allows you to be as granular as you want with your commits. I can commit a change as simple as adjusting a View's sort order or as large as an entire collection of new content types. With my changes in version control, I can roll them back as easily as I can import them (mostly, some content type/field changes cannot be rolled back.) Keeping changes as simple as possible can also help minimize merge conflicts in projects with multiple developers.undefined
This process will work between any source environment and any destination environment, assuming the two environments are instances of the same site. Clearly, it is both ideal and easy to make changes locally and push them live, but that is not always the best option. For instance, while setting up Metatag module, I realized it would be much easier to test from a publicly accessible environment. So I went to the live site and tweaked my settings to where I wanted them, then exported and committed these changes and brought the changes back down to my local. In another case, I was on the phone with my partner who was viewing some changes on the preview site. As she was making comments and asking for changes, I made them until we were both happy with them. Then, I could merge those changes down to my local before pushing them live.
In many cases, this setup will not be workable. As the sole dev and site admin, it works for me because I know exactly what is going on all the time and I can make sure that the changes I'm making won't overwrite someone else's work. Nevertheless, there's no reason this model couldn't be expanded to work with multiple developers. For instance, you could lock down the live site so that its admin is read only (simple with a module like Config Read Only) and then come up with an automated or user-instantiated process to make those changes live. This could also pretty easily be expanded to a multi-developer environment.More advanced options
Here at Lullabot we have already started talking through some different options for our more advanced projects. In one case, we ended up going back to Features. The client already had a Features-based workflow for their D7 site and was reluctant to change to a totally new system. Additionally, they maintained a network of sites based on a common core repository or “distribution.” We needed to get off the ground quickly with something we already understood rather than figuring out a config workflow that would work. Features offered us that.
Alex Pott has proposed another workflow that involves shipping your config with an install profile. In this scenario, your configuration lives in your install profile, and you essentially rebuild your entire site from scratch when you push changes. This works especially well with advanced composer-based workflows in which your assets are scattered and imported as part of your build process. Additionally, this setup can get around some technical problems involving the way Drupal 8 assigns UUIDs to configuration. For more information on this, see the presentation he did with fellow Lullabot Matthew Tift at DrupalCon New Orleans.
As we get farther and farther into the Drupal 8 cycle, we will see a ton more workflows and processes around configuration management and deployment. Some will be use-case specific, some will end up becoming best practices, and some will probably just be weird. I wouldn't have it any other way because it means the configuration management system works for site owners and not the other way around.
Next in the series, I will talk about some interesting things D8 has enabled around theming and templating.
Header photo by Karl Lind Films
When I ask lead ergonomist and physical therapist Matthew Marino of Portland, Ore., “What is the best position to work from?” he replies, “the next position.” The human body was built to move, not to be still. Standing desks will not save us from “sitting is the new smoking,” or, as the guru of Barefoot Running, Christopher McDougall, wrote in a recent issue of Outside Magazine, Sitting Wrecks Your Body. More Standing Isn't the Solution. In fact, standing all day at a desk may be even harder on the heart than sitting, not to mention a recipe for varicose veins.
As a distributed company of developers and designers tied to our computers both for communication and for work, it’s important to find ways to incorporate movement into our day and to change positions regularly. Here are nine individual workstations that allow the Lullabots to remain “computer athletes” and one from a pro-ergonomist to show you how the real ergo nerds do it. Prepare to geek out on state-of-the-art sit-stand desks, treadmill desks, anti-fatigue mats, foam rollers, and theracanes, along with some nifty DIY creations to inspire your imagination.What kind of workspace do you have?
Amber Matz, Production Manager and Trainer, Drupalize.Me: I have an adjustable-height standing desk (the UPLIFT 975 Height-Adjustable Standing Pedestal Desk from The Human Solution) with a thick “anti-fatigue” mat. Sometimes I use this adjustable “sit-stand” stool to relieve my low back. All my equipment is clamped onto the desk so that I can raise it to eye-level, including this combined laptop/monitor arm mount stand. Since I do a lot of screen recording, I also have a microphone and tiny soundboard clamped on as well.undefined
Ben Chavet, Senior Systems Administrator: I currently have an adjustable-height desk. Before this, I had an L-shaped desk with one side at sitting height, and the other at standing height, which worked great when I only had a laptop to move back and forth. I made most of my workspace myself, except for the adjustable-height frame. My monitors were about 4-6 inches too short, which strained my neck, so I built a nice monitor stand to bring them up to a comfortable height.undefined
Juampy Novillo Requena, Senior Drupal Developer: In the mornings I go to a coworking space where I sit. I walk back and forth. At home, I have a standard desk. A couple of times per week I add a small desk on top to build a standing workspace. I don't spend more than four hours standing.undefined
Marissa Epstein, Senior UX Designer: I have a NextDesk Terra, an adjustable, motorized standing desk. When standing, I use a CumulusPro anti-fatigue mat. When the desk is lowered, I sit in an Aeron chair. It’s a little awkward sometimes, but I work on a combination of Macbook (on a Rain mStand) and iMac (on some cookbooks). I also recently converted a Confidence Power Plus treadmill so that it fits under my desk.undefined
Matt Marino, Owner of Optimum Performance Services, LLC and Lead Ergonomist and Physical Therapist with Briotix in Portland: I have home-office built-ins at my house which I didn’t want to rip out, so I installed an Ergotron LX sit-stand system with a grommet mount. The installation required some drilling and a custom glass top surface but otherwise was an easy install. I have a large Dell monitor on the arm. Currently I have a Kinesis Freestyle2 Blue keyboard, and DXT mouse on the tray, and Savant Elite2 triple pedal on the floor. There are many good keyboard and mouse options. For traveling, I like the SwiftpointGT mouse over my laptop trackpad. I have a Via Voss chair, a Via Swopper stool and a Focal Mogo to switch up my seating/perching options. My home office is large enough that I can move around, exercise, and stretch. I have plenty of natural light with no glare issues. I have a door to keep kids out when I need to put my head down and work. I like being able to walk around my house or my neighborhood when I take breaks and use the exercise equipment in the garage for a quick workout.undefined
Matthew Tift, Senior Drupal Developer: My desk is adjustable height, but I mostly stand. I have an adjustable height keyboard tray and my laptop sits on a stand so that the top of the screen is eye level. For the past decade or more, I’ve been using a vertical mouse and an adjustable split keyboard which significantly reduces pain in my hand and arms. Because I do a lot of audio conferences and recording, I have a Yeti microphone with a pop filter on a boom arm attached to my desk that allows me to stand or sit while recording.undefined
Mike Herchel, Front-end Developer: I have an electronic, adjustable-height standing desk. I can set the proper height for sitting and standing and then switch by pressing a button, and it will rise and fall. It's a Jarvis adjustable standing desk frame. I use a huge 80 x 36 inch (2M x 1M) door for my desktop. I have room to spread out.undefined
Sally Young, Senior Developer: I started with a sitting oneless desk. Then I added some ergomart arms so I could move to any height and stand up, as well as a rubber mat. Then I added a kneeling chair. It doesn't take up much space, and the lack of excess surfaces prevents me from storing non-essential items on my desk—I get distracted by messy surfaces.undefined
Seth Brown, Chief Operating Officer: I go back and forth between sitting on a Fitball, sitting on a Herman Miller Aeron Size C Chair, and walking at a treadmill desk. I secured the laptop cradle for the treadmill desk to the ceiling using All Thread so the height is adjustable and it prevents treadmill vibration from affecting my view.undefined What do you love about your workspace?
Amber: I like being able to record screencasts standing up. It might sound funny, but it’s easier to breathe and sustain my energy.
Joe: I have a lot of natural light. I can switch between standing (usually in the AM) and sitting (in the PM).
Marissa: It's a bigger desk than my last one, and I can keep it organized—there's a power strip attached to the underside of the desk, so all my cables are tidy. I feel like I have a comfortable amount of space. I love that I was able to make it my own: I covered the desk in art and favorites from my toy collection.
Mike: I have a unique situation where I don't work out of my house. I have some friends that rent me their home during the day while they go to their office jobs, providing me with a workspace that's completely separate from my family life. It also gets me into a routine where I have to get up, shower, and put on pants—this can be tough to do when you're working from home.
Seth: I love having the privacy to be on calls (my voice carries), the comfort of choosing my own tools and way of working, and the ability to walk on the treadmill during calls even if it's too cold or windy to do so outside.How does your workspace help you manage or avoid pain, fatigue, or discomfort?
Amber: It helps to have a choice of standing or sitting. I can’t stand for long periods of time without my back hurting, but I could say the same for sitting. So being able to adjust the height makes it easy to switch between standing and sitting (or half-standing, with the stool that I have).
Ben: I have problems with my knees, hips, and tailbone. So, I stand to give my tailbone relief, and I sit to give my knees and hips relief. It's a balancing act, and I notice the days that I don't get the right balance. Besides the physical benefits of alternating, I find that I focus better on certain tasks when I'm sitting vs. standing, and vice-versa.
Joe: The standing mat was a huge benefit for me. Without it, I was getting a lot of leg pain. Now I get none!
Juampy: I have a foot rest, which is useful when I am sitting. I also have a resting mat for my feet when I am standing.
Marissa: I stand roughly every 20 minutes each hour, which prevents me from getting stiff. I also have a yoga mat nearby, and little stretch breaks go a long way to relieving tightness.
Matt: Sit-stand transitions. Neutral postures. Ability to move around, exercise, stretch, and take breaks.
Matthew: There are lots of windows next to my desk, so I have a nice view of my yard. I switch back and forth between standing and sitting on a yoga ball throughout the day, with my screen always at eye level and my arms always at a 90-degree angle.
Sally: I'm currently undergoing physical therapy, which was my impetus to convert my desk to sit-stand. Keeping my body moving even slightly during the day has helped to significantly reduce the amount of pain I have down my neck and shoulder over time. When I sit down, I use a Herman Miller Mirra chair, and for kneeling I use a Varier Balans. I also use a mechanical keyboard and vertical mouse, which significantly reduces the fatigue on my hands.What problems remain?
Amber: The standing desk is not a cure-all. With my back issues, if I don’t stretch regularly, it’s just not comfortable to stand for a long period.
Joe: There is no memory setting on my standing desk, so I end up making a rough guess where it should go when I switch stances.
Matthew: I have not found a good place to put the yoga ball I use as a chair
Sally: The docking station for my laptop isn't ideal as occasionally I'll knock the power cable out, which deactivates clamshell mode, but I probably won't change it until the next new laptop I get. Also, my cat likes to knock things off my desk.Is there anything you would like to improve about your workspace?
Amber: I am still not completely satisfied with the chair or stool I have for my adjustable height desk. I am not sure what would be the best solution, and with chairs being as expensive as they are, it’s impractical to iterate and experiment. I have a comfy chair by the window that I resort to in those early mornings when I'm not quite awake yet, which I love.
Ben: I need a new chair. I split my time relatively evenly between sitting and standing. Even with a better chair, I think that would continue. But, I notice that my posture isn't great when I'm sitting and that I develop pain-points, which causes me to shift a lot. I could also probably use an anti-fatigue mat to stand on. My office is carpeted, and I tend to wear shoes when I stand so that it could be worse, but it could be better.
Joe: I want to have as few wires as possible. Mainly because it makes removing my laptop from the stand and moving around the house (or going out) easier. At the moment I have four things to unplug when I do this, which is tedious. The new Macbook seems to be an improvement (just a single USB Type-C connector).
Marissa: I’m thinking about buying a standing aid, like the Focal Upright Mogo. Supposedly the angle it positions you in is fabulous for posture.
Matt: I’d like an electric desk like the Jarvis with a monitor arm. Because my sit-stand system relies on arms, it blocks a ton of work surface area rendering it useless to me.
Matthew: Sometimes I listen to music through speakers, but during calls, I need to use headphones to avoid feedback, so I’m currently searching for an audio switch box that would allow me to alternate between speakers and headphones with a click of a button.What other things do you do to support your health and avoid injury?
Amber: I tend to alternate between standing and sitting and try to take regular walking breaks.
Ben: I take regular walks. I have an hour blocked off of my calendar every day to protect the time and get a reminder to get outside and walk. The movement helps my joints, and the time away from my desk helps clear my head.
Joe: I usually go to the gym four week days and do strength training. It's a good way to start the day for me and gets me out of the house. Climbing on the weekends gives me the strength in my forearms to avoid injuries from typing all day.
Juampy: I play squash, do yoga once a week and walk every day. If I don't move in a whole day, my body gets stiff.
Marissa: Besides standing, I see a chiropractor once a month and inconsistently do yoga. I try to walk on the treadmill during my few calls without video. Otherwise, not much.
Matt: Breaks, sit-stand transitions, walking, stretching, exercise, and Jedi training.
Matthew: Everyday around lunch time I take an hour break outside to completely clear my head and give my hands a rest—running, road biking when the weather is nice, fat biking in the winter, cyclocross to mix things up. When I decided to make this daily break a high priority, I started noticing many other benefits such as improved concentration while working and greater patience overall.
Sally: I do pilates, cycling and weightlifting regularly, as well as dancing. I some exercise equipment next to my desk. I'll often use a Deuserband to stretch while standing at my desk, or a theracane if I have any knots. If it's a particularly bad day, I'll take a break now and then to use a gridded foam roller.
Seth: I break up the middle of the day with a long, lunchtime workout. Don't sit for 8 hours straight! For me, having flex time allows me to plan a two-hour block for a mid-day exercise routine. If you have issues, seek out a physical therapist and build a workout tailored to address your specific issues. Everyone could use more core strength, but other adjustments are more subtle. You don't want to make overuse injuries worse by lifting weights, but there are often clever ways to strengthen your weaknesses without inflaming your RSI. You need the help of a physical therapist to figure this out.Do you have a favorite tech or software that encourages you to work in a healthy way?
Ben: I have a Fitbit, and initially was obsessed with hitting my 10,000 steps every day. Lately, though, it's an afterthought, but I do like to look at the day-to-day trends.
Juampy: Fitbit! Especially when you add friends and groups.
Marissa: My desk comes with an app called Pulse, that lets you set standing goals and pops up reminders. It suggests when I should stand and sit, and adds up my time for the day. I've had my Fitbit on since the day Lullabot got it for me! Definitely, a nice way to keep yourself from losing track of the big picture.
Matthew: I have RSI Break (Time Out for Mac users or hack together your own version) set to make my screen go black for 20 seconds every 20 minutes. During that 20 seconds I do yoga, stretches, quick walk around house, etc. Other times during the day I try to focus on an object at least 200 feet away for that 20 seconds. At first I found this practice to be enormously annoying, but I have found peace with regular breaks, especially since my vision has improved markedly and I am now basically pain free. For me, free software that forces me to pause regularly helps me keep my life in balance.
Sally: I use Runkeeper to track all my activities, as well as give and receive encouragement from friends.
Seth: I use Pomodoro Timer, working for 24 minutes and then taking a 6-minute break to stretch or roll out on a foam roller. I only take the break if I've been sitting the entire 24 minutes.What advice would give someone who wanted to create a more ergonomic workspace?
Ben: Start cheap, and iterate. Start by stacking things on books. Use cheap Ikea furniture to experiment with standing. Upgrade when it feels right, and don't be afraid to make adjustments over time.
Joe: Having a standing desk has done wonders for how well I can think.
Juampy: Try a standing desk for a couple of hours to start with.
Matthew: I have known a lot of people who have developed hand pain from mouse overuse, so I highly recommend a vertical mouse which I find much more natural. If you mostly keep your hands on the keyboard while you are working, then I would recommend a split keyboard.
Mike: I finished the door for my desk with multiple layers of polyurethane, and it came out looking bad. It's functional, but not too pretty. Standing desks are awesome. I highly recommend the one I have. Next time, I'll purchase the desktop from Ikea instead of make my own.
Seth: I believe in investing in a really good chair. You're going to spend as much time in your chair as you do on your mattress, maybe more, and you need comfort and lumbar support. I'm a big fan of spending the extra money for quality here. In addition... * Walking on a treadmill is great because I stay warm, even when it's really cold in the office, which means I don't hurt my wrists. * Strive for a desk/chair/keyboard alignment that allows your knees and elbows to form right angles. Keep the top of your monitor at eye level. You can't do these things with just a laptop. You need an extra monitor. Prop the monitor to just the right height using old textbooks or stacks of printer paper. * Switch from sitting to standing or sitting to treadmill as much as possible. * Walk on non-video calls. * Use a split keyboard over a standard keyboard and a trackpad over a mouse. Set your trackpad so you can touch to click rather than having to push it down. * Never cradle the phone between neck and shoulder especially not while typing. NOTHING will get you injured faster. * If you're exceptionally tall or short take exceptional precautions. The world isn't built for you by default.