Thursday, August 26, 2021

Four Useful VSCode Extensions For Web Developers

 VS Code can be supercharged wuth hundreds of VS Code extensions

 

Inline Parameters

Which param is the array and which is the callback in PHP functions array_map and array_filter? I can never get it right. To avoid this confusion we can use Inline Parameters, which prints inline the names of the function parameters (for JavaScript, TypeScript, PHP, and Lua).

HTML End Tag Labels

With deeply nested <div> tags we can easily get lost, not knowing which is their ending </div>. HTML End Tag Labels helps us understand the structure of the HTML code, by having the class names of the opening tag be displayed next to its closing tag.

TO-DO Tree

You have something to do in your code, but you don’t have time for it now. Better do it later. Quick and easy reminder: add a “TODO” in your code. Fast forward 6 months, and you’ve accumulated 150 TODOs, and you need to take care of them. The Todo Tree will help you find all TODOs in your code.

Code Snippet Screenshots

You created some really beautiful code, and you want to share it with the world? You can take a screenshot, download it, go to Twitter, upload it and send it. Or you can select the code right within the editor, and have Snipped generate a beautiful image of it and send it straight to Twitter.

 These four extensions have proven very handy for my work with web development. What other useful extensions do you use? Let me know in the comments.

Monday, August 23, 2021

Creating An Interactive Gantt Chart Component With Vanilla JavaScript

  With a Gantt chart, you can visualize schedules and assign tasks. In this article, we will code a Gantt chart as a reusable Web component. We will focus on the architecture of the component, rendering the calendar with CSS Grid and managing the state of the draggable tasks with JavaScript Proxy Objects.

If you work with time data in your app, a graphical visualization as a calendar or Gantt chart is often very useful. At first glance, developing your own chart component seems quite complicated. Therefore, in this article, I will develop the foundation for a Gantt chart component whose appearance and functionality you can customize for any use case.

These are the basic features of the Gantt chart that I would like to implement:

  • The user can choose between two views: year/month or month/day.
  • The user can define the planning horizon by selecting a start date and an end date.
  • The chart renders a given list of jobs that can be moved by drag and drop. The changes are reflected in the state of the objects.
  • Below you can see the resulting Gantt chart in both views. In the monthly version, 

Below you can see the resulting Gantt chart in both views. In the monthly version, I have included three jobs as an example.

Sample Files And Instructions For Running The Code

You can find the full code snippets of this article in the following files:

Since the code contains JavaScript modules, you can only run the example from an HTTP server and not from the local file system. For testing on your local PC, I’d recommend the module live-server, which you can install via npm.

Basic Structure Of The Web Component

I decided to implement the Gantt chart as a web component. This allows us to create a custom HTML element, in my case <gantt-chart></gantt-chart>, which we can easily reuse anywhere on any HTML page.

You can find some basic information about developing web components in the MDN Web Docs. The following listing shows the structure of the component. It is inspired by the “counter” example from Alligator.io.

The component defines a template containing the HTML code needed to display the Gantt chart. For the complete CSS specifications, please refer to the sample files. The specific selection fields for year, month or date cannot be defined here yet, as they depend on the selected level of the view.

The selection elements are projected in by one of the two renderer classes instead. The same applies to the rendering of the actual Gantt chart into the element with the ID gantt-container, which is also handled by the responsible renderer class.

The class VanillaGanttChart now describes the behavior of our new HTML element. In the constructor, we first define our rough template as the shadow DOM of the element.

The component must be initialized with two arrays, jobs, and resources. The jobs array contains the tasks that are displayed in the chart as movable green bars. The resources array defines the individual rows in the chart where tasks can be assigned. In the screenshots above, for example, we have 4 resources labeled Task 1 to Task 4. The resources can therefore represent the individual tasks, but also people, vehicles, and other physical resources, allowing for a variety of use cases.

Currently, the YearMonthRenderer is used as the default renderer. As soon as the user selects a different level, the renderer is changed in the changeLevel method: First, the renderer-specific DOM elements and listeners are deleted from the Shadow DOM using the clear method of the old renderer. Then the new renderer is initialized with the existing jobs and resources and the rendering is started.

import {YearMonthRenderer} from './YearMonthRenderer.js';
import {DateTimeRenderer} from './DateTimeRenderer.js';

const template = document.createElement('template');

template.innerHTML = 
 `<style> … </style>

  <div id="gantt-settings">

    <select name="select-level" id="select-level">
      <option value="year-month">Month / Day</option>
      <option value="day">Day / Time</option>
    </select>

    <fieldset id="select-from">
      <legend>From</legend>
    </fieldset>

    <fieldset id="select-to">
      <legend>To</legend>
    </fieldset>
  </div>

  <div id="gantt-container">
  </div>`;

export default class VanillaGanttChart extends HTMLElement {

    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
      this.levelSelect = this.shadowRoot.querySelector('#select-level');
    }
 
    _resources = [];
    _jobs = [];
    _renderer;

    set resources(list){}
    get resources(){}
    set jobs(list){}
    get jobs(){}
    get level() {}
    set level(newValue) {} 
    get renderer(){}
    set renderer(r){}

    connectedCallback() {
      this.changeLevel = this.changeLevel.bind(this);

      this.levelSelect.addEventListener('change', this.changeLevel);
      this.level = "year-month";   

      this.renderer = new YearMonthRenderer(this.shadowRoot);
      this.renderer.dateFrom = new Date(2021,5,1);
      this.renderer.dateTo = new Date(2021,5,24);
      this.renderer.render();
    }

    disconnectedCallback() {  
      if(this.levelSelect)
        this.levelSelect.removeEventListener('change', this.changeLevel);
      if(this.renderer)
        this.renderer.clear();
    }

    changeLevel(){
      if(this.renderer)
        this.renderer.clear();

      var r;   

      if(this.level == "year-month"){
        r = new YearMonthRenderer(this.shadowRoot);    
      }else{
        r = new DateTimeRenderer(this.shadowRoot);
      }

      r.dateFrom = new Date(2021,5,1);
      r.dateTo = new Date(2021,5,24);
      r.resources = this.resources;
      r.jobs = this.jobs;
      r.render();
      this.renderer = r;
    }
  }
 
  window.customElements.define('gantt-chart', VanillaGanttChart);

Before we get deeper into the rendering process, I would like to give you an overview of the connections between the different scripts:

  • index.html is your web page where you can use the tag <gantt-chart></gantt-chart>
  • index.js is a script in which you initialize the instance of the web component that is associated with the Gantt chart used in index.html with the appropriate jobs and resources (of course you can also use multiple Gantt charts and thus multiple instances of the web component)
  • The component VanillaGanttChart delegates rendering to the two renderer classes YearMonthRenderer and DateTimeRenderer.

 

 

Rendering Of The Gantt chart With JavaScript And CSS Grid

In the following, we discuss the rendering process using the YearMonthRenderer as an example. Please note that I have used a so-called constructor function instead of the class keyword to define the class. This allows me to distinguish between public properties (this.render and this.clear) and private variables (defined with var).

The rendering of the chart is broken down into several sub-steps:

  1. initSettings
    Rendering of the controls which are used to define the planning horizon.
  2. initGantt
    Rendering of the Gantt chart, basically in four steps:
    • initFirstRow (draws 1 row with month names)
    • initSecondRow (draws 1 row with days of the month)
    • initGanttRows (draws 1 row for each resource with grid cells for each day of the month)
    • initJobs (positions the draggable jobs in the chart)
export function YearMonthRenderer(root){

    var shadowRoot = root;
    var names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];    
 
    this.resources=[];
    this.jobs = [];
 
    this.dateFrom = new Date();
    this.dateTo = new Date();

    //select elements
    var monthSelectFrom;
    var yearSelectFrom;
    var monthSelectTo;
    var yearSelectTo;

    var getYearFrom = function() {}
    var setYearFrom = function(newValue) {}

    var getYearTo = function() {}
    var setYearTo = function(newValue) {}

    var getMonthFrom = function() {}
    var setMonthFrom = function(newValue) {}

    var getMonthTo = function() {}
    var setMonthTo = function(newValue) {}  

    this.render = function(){
      this.clear();
      initSettings();
      initGantt();
    }

    //remove select elements and listeners, clear gantt-container 
    this.clear = function(){}

    //add HTML code for the settings area (select elements) to the shadow root, initialize associated DOM elements and assign them to the properties monthSelectFrom, monthSelectTo etc., initialize listeners for the select elements
    var initSettings = function(){}

    //add HTML code for the gantt chart area to the shadow root, position draggable jobs in the chart
    var initGantt = function(){}

    //used by initGantt: draw time axis of the chart, month names
    var initFirstRow = function(){}

    //used by initGantt: draw time axis of the chart, days of month
    var initSecondRow = function(){}

    //used by initGantt: draw the remaining grid of the chart
    var initGanttRows = function(){}.bind(this);

    //used by initGantt: position draggable jobs in the chart cells
    var initJobs = function(){}.bind(this);    

   //drop event listener for jobs
   var onJobDrop = function(ev){}.bind(this);

   //helper functions, see example files
   ...
}

Rendering The Grid

I recommend CSS Grid for drawing the diagram area because it makes it very easy to create multi-column layouts that adapt dynamically to the screen size.

In the first step, we have to determine the number of columns of the grid. In doing so, we refer to the first row of the chart which (in the case of the YearMonthRenderer) represents the individual months.

Consequently, we need:

  • one column for the names of the resources, e.g. with a fixed width of 100px.
  • one column for each month, of the same size and using the full space available.

This can be achieved with the setting 100px repeat(${n_months}, 1fr) for the property gridTemplateColumns of the chart container.

This is the initial part of the initGantt method:

var container = shadowRoot.querySelector("#gantt-container");
container.innerHTML = "";

var first_month = new Date(getYearFrom(), getMonthFrom(), 1);
var last_month = new Date(getYearTo(), getMonthTo(), 1);
 
//monthDiff is defined as a helper function at the end of the file
var n_months =  monthDiff(first_month, last_month)+1;
 
container.style.gridTemplateColumns = `100px repeat(${n_months},1fr)`;
 

After we have defined the outer columns, we can start filling the grid. Let’s stay with the example from the picture above. In the first row, I insert 3 divs with the classes gantt-row-resource and gantt-row-period. You can find them in the following snippet from the DOM inspector.

In the second row, I use the same three divs to keep the vertical alignment. However, the month divs get child elements for the individual days of the month.

<div id="gantt-container"
  style="grid-template-columns: 100px repeat(2, 1fr);">
  <div class="gantt-row-resource"></div>
  <div class="gantt-row-period">Jun 2021</div>
  <div class="gantt-row-period">Jul 2021</div>
  <div class="gantt-row-resource"></div>
  <div class="gantt-row-period">
    <div class="gantt-row-period">1</div>
    <div class="gantt-row-period">2</div>
    <div class="gantt-row-period">3</div>
    <div class="gantt-row-period">4</div>
    <div class="gantt-row-period">5</div>
    <div class="gantt-row-period">6</div>
    <div class="gantt-row-period">7</div>
    <div class="gantt-row-period">8</div>
    <div class="gantt-row-period">9</div>
    <div class="gantt-row-period">10</div>
  ...
  </div>
  ...
</div>

For the child elements to be arranged horizontally as well, we need the setting display: grid for the class gantt-row-period. In addition, we do not know exactly how many columns are required for the individual months (28, 30, or 31). Therefore, I use the setting grid-auto-columns. With the value minmax(20px, 1fr); I can ensure that a minimum width of 20px is maintained and that otherwise the available space is fully utilized:

#gantt-container {
  display: grid;
}

.gantt-row-resource {
  background-color: whitesmoke;
  color: rgba(0, 0, 0, 0.726);
  border: 1px solid rgb(133, 129, 129);
  text-align: center;
}

.gantt-row-period {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(20px, 1fr);
  background-color: whitesmoke;
  color: rgba(0, 0, 0, 0.726);
  border: 1px solid rgb(133, 129, 129);
  text-align: center;
}

The remaining rows are generated according to the second row, however as empty cells.

Here is the JavaScript code for generating the individual grid cells of the first row. The methods initSecondRow and initGanttRows have a similar structure.

var initFirstRow = function(){

  if(checkElements()){
        var container = shadowRoot.querySelector("#gantt-container");

        var first_month = new Date(getYearFrom(), getMonthFrom(), 1);
        var last_month = new Date(getYearTo(), getMonthTo(), 1);
 
        var resource = document.createElement("div");
        resource.className = "gantt-row-resource";
        container.appendChild(resource);   
 
        var month = new Date(first_month);

        for(month; month <= last_month; month.setMonth(month.getMonth()+1)){    
          var period = document.createElement("div");
          period.className = "gantt-row-period";
          period.innerHTML = names[month.getMonth()] + " " + month.getFullYear();
          container.appendChild(period);
        }
  }
}

Rendering The Jobs

Now each job has to be drawn into the diagram at the correct position. For this I make use of the HTML data attributes: every grid cell in the main chart area is associated with the two attributes data-resource and data-date indicating the position on the horizontal and vertical axis of the chart (see function initGanttRows in the files YearMonthRenderer.js and DateTimeRenderer.js).

 

Let’s now see what this means for the function initJobs. With the help of the function querySelector, it is now quite easy to find the grid cell into which a job should be placed.

The next challenge is to determine the correct width for a job element. Depending on the selected view, each grid cell represents a unit of one day (level month/day) or one hour (level day/time). Since each job is the child element of a cell, the job duration of 1 unit (day or hour) corresponds to a width of 1*100%, the duration of 2 units corresponds to a width of 2*100%, and so on. This makes it possible to use the CSS calc function to dynamically set the width of a job element, as shown in the following listing.

var initJobs = function(){

    this.jobs.forEach(job => {

        var date_string = formatDate(job.start);

        var ganttElement = shadowRoot.querySelector(`div[data-resource="${job.resource}"][data-date="${date_string}"]`);

        if(ganttElement){

          var jobElement = document.createElement("div");
          jobElement.className="job";
          jobElement.id = job.id;

          //helper function dayDiff - get difference between start and end in days
          var d = dayDiff(job.start, job.end);           
          
          //d --> number of grid cells covered by job + sum of borderWidths
          jobElement.style.width = "calc("+(d*100)+"% + "+ d+"px)";
          jobElement.draggable = "true";

          jobElement.ondragstart = function(ev){
              //the id is used to identify the job when it is dropped
              ev.dataTransfer.setData("job", ev.target.id); 
          };

          ganttElement.appendChild(jobElement);
        }
    });
  }.bind(this);

In order to make a job draggable, there are three steps required:

  • Set the property draggable of the job element to true (see listing above).
  • Define an event handler for the event ondragstart of the job element (see listing above).
  • Define an event handler for the event ondrop for the grid cells of the Gantt chart, which are the possible drop targets of the job element (see function initGanttRows in the file YearMonthRenderer.js).

The event handler for the event ondrop is defined as follows:

var onJobDrop = function(ev){
 
      // basic null checks
      if (checkElements()) {
 
        ev.preventDefault(); 
 
        // drop target = grid cell, where the job is about to be dropped
        var gantt_item = ev.target;
        
        // prevent that a job is appended to another job and not to a grid cell
        if (ev.target.classList.contains("job")) {
          gantt_item = ev.target.parentNode;
        }
        
        // identify the dragged job
        var data = ev.dataTransfer.getData("job");               
        var jobElement = shadowRoot.getElementById(data);  
        
        // drop the job
        gantt_item.appendChild(jobElement);
 
        // update the properties of the job object
        var job = this.jobs.find(j => j.id == data );
 
        var start = new Date(gantt_item.getAttribute("data-date"));
        var end = new Date(start);
        end.setDate(start.getDate()+dayDiff(job.start, job.end));
 
        job.start = start;
        job.end = end;
        job.resource = gantt_item.getAttribute("data-resource");
      }
    }.bind(this);

All changes to the job data made by drag and drop are thus reflected in the list jobs of the Gantt chart component.

Integrating The Gantt Chart Component In Your Application

You can use the tag <gantt-chart></gantt-chart> anywhere in the HTML files of your application (in my case in the file index.html) under the following conditions:

  • The script VanillaGanttChart.js must be integrated as a module so that the tag is interpreted correctly.
  • You need a separate script in which the Gantt chart is initialized with jobs and resources (in my case the file index.js).
<!DOCTYPE html>
<html>
 <head>
   <meta charset="UTF-8"/>
   <title>Gantt chart - Vanilla JS</title>
   <script type="module" src="VanillaGanttChart.js"></script>   
 </head>
    
 <body>
 
  <gantt-chart id="g1"></gantt-chart> 
 
  <script type="module" src="index.js"></script>
 </body> 
</html>

For example, in my case the file index.js looks as follows:

import VanillaGanttChart from "./VanillaGanttChart.js";
 
var chart = document.querySelector("#g1");
 
chart.jobs = [
    {id: "j1", start: new Date("2021/6/1"), end: new Date("2021/6/4"), resource: 1},
    {id: "j2", start: new Date("2021/6/4"), end: new Date("2021/6/13"), resource: 2},
    {id: "j3", start: new Date("2021/6/13"), end: new Date("2021/6/21"), resource: 3},
];
 
chart.resources = [{id:1, name: "Task 1"}, {id:2, name: "Task 2"}, {id:3, name: "Task 3"}, {id:4, name: "Task 4"}];

However, there is still one requirement open: when the user makes changes by dragging jobs in the Gantt chart, the respective changes in the property values of the jobs should be reflected in the list outside the component.

We can achieve this with the use of JavaScript Proxy Objects: Each job is nested in a proxy object, which we provide with a so-called validator. It becomes active as soon as a property of the object is changed (function set of the validator) or retrieved (function get of the validator). In the set function of the validator, we can store code that is executed whenever the start time or the resource of a task is changed.

The following listing shows a different version of the file index.js. Now a list of proxy objects is assigned to the Gantt chart component instead of the original jobs. In the validator set I use a simple console output to show that I have been notified of a property change.

import VanillaGanttChart from "./VanillaGanttChart.js";
 
var chart = document.querySelector("#g1");
 
var jobs = [
    {id: "j1", start: new Date("2021/6/1"), end: new Date("2021/6/4"), resource: 1},
    {id: "j2", start: new Date("2021/6/4"), end: new Date("2021/6/13"), resource: 2},
    {id: "j3", start: new Date("2021/6/13"), end: new Date("2021/6/21"), resource: 3},
];
var p_jobs = [];
 
chart.resources = [{id:1, name: "Task 1"}, {id:2, name: "Task 2"}, {id:3, name: "Task 3"}, {id:4, name: "Task 4"}];
 
jobs.forEach(job => {
 
    var validator = {
        set: function(obj, prop, value) {
 
          console.log("Job " + obj.id + ": " + prop + " was changed to " + value);
          console.log();
 
          obj[prop] = value;
          return true;
        },
 
        get: function(obj, prop){
 
            return obj[prop];
        }
    };
 
    var p_job = new Proxy(job, validator);
    p_jobs.push(p_job);
});
 
chart.jobs = p_jobs;

Outlook

The Gantt chart is an example that shows how you can use the technologies of Web Components, CSS Grid, and JavaScript Proxy to develop a custom HTML element with a somewhat more complex graphical interface. You are welcome to develop the project further and/or use it in your own projects together with other JavaScript frameworks.

How To Build An Ethical User Research Practice At Any Organization

 Through a simple step-by-step approach, you can build an ethical practice within your organization that will ensure you’re respecting the dignity and welfare of your research participants. In this article, we will discuss ethics and ethical principles as the ruling standards to guide our user research.

Ethics are an important part of human-computer interaction because they keep people at the heart of the design process. Unethical practices at companies lead to the creation of technology that we all use but often neglect the influence of those intended to serve. As seen in the discussions about privacy at Facebook and AI-powered imaging at Google among other examples, when there are no ethical considerations during the creation of technology then the interaction between humans is compromised.

A real interaction between computers and humans starts at technological conception by understanding users through a sound and ethical user research discipline.

What Are “Ethics” And Why Should I Care? #

To understand why we should build an ethical user research practice at our organizations, we’ll start with the basics. What are ethics anyway?

Ethics are the moral standards by which a person (or in this context, a company or team) should govern the behavior or the conduct of an activity. Ethical user research should then be about protecting the dignity, rights, and welfare of the participants from whom we are asking so much information or data. If we aren’t proactive and prescriptive about our own standards as a research team, we could unconsciously be biased, demoralizing, exclusive, or even in breach of the law.

Here are a few examples of unethical practices:

  • Not recruiting a diverse and inclusive sample.
  • Not informing participants of study requirements or potential harm.
  • Misplacing or not tracking participant data or identifiable information.
  • Misgendering or reinforcing stereotypes in reports, personas, or prototypes.

You may be wondering why you specifically should care. Doesn’t somebody else in the organization focus on ethics? Isn’t there an ethics Internal Review Board (IRB) that is better suited for this? Unfortunately in the user experience industry, that answer is usually no.

While many companies rely on their own Ethics or HR departments to set governing moral standards, their scope typically only relates to their business’ product offerings, services to customers, internal processes, and functions. Rarely, if ever, do these departments take into account the specialty of user research.

For example, try and recall the last time your team’s processes were audited for compliance against the company’s ethical standards. For this reason, it’s really up to each of us; it’s up to each and every practitioner to set standards to which ourselves, our teams, and our company should be held accountable.

Unfortunately, many organizations may not have the resources to fund such training, nor provide the time needed to invest in it. Even if your organization did have the time and resources to provide such training, then what? How do you get started leveraging ethics in your user research practice to influence how you do your work in a way that upholds a set of guiding standards? It all starts with a Code of Ethics.

“I do not believe in the immortality of the individual, and I consider ethics to be an exclusively human concern with no superhuman authority behind it.”

— Albert Einstein

 

A Code Of Ethics: The Backbone Of Ethical Practice

Now that you understand why ethics matter for user research, and why it’s critical that you take it upon yourself to create them for your team, it would certainly help knowing where to start. To begin influencing your work with a set of ethical standards, you need to start by defining what your standards even are.

Starting with a Code versus diving headfirst into changing templates, tools, and processes that allow you to start from a reference point. A Code affords you with a checklist to ensure that with each new process, each new tool or each new study conducted follows your agreed-upon moral standards.

Once you create your own code of ethics, you might notice an improvement not only in your team’s work and performance but also in the team’s culture as well. As UX practitioners, we know empathy is an important part of the design process. Providing a deeper connection and purpose in the work we do and those who we do it with fosters a more inclusive environment, and thoughtful team members as a result.

How To Create Your Own Code Of Ethics #

Creating a code of ethics takes only a few thoughtful steps, and from there you will have the backbone for influencing your work through a set of aligned standards. If you’re ready to invest in building a better, more ethical future for your team, your practice, and your organization, read on.

1. Commit To Ethics As A Practice #

While it may sound silly or downright obvious, this is one of the most important and often most difficult of steps to truly accomplish. The thing is, to do things correctly aligned to any set of standards means being more thoughtful and taking the necessary steps and time to get it right.

While not monumental, ethical practice is an investment. It takes effort and time to evaluate your process, templates, tools, vendors, and ways of working in order to tweak or even overhaul them in order to align with your ethical principles or moral standards.

That said, building an ethical research practice makes good business sense, which means the time and effort is well spent when you purposely recruit diverse voices, respect their rights to information security and impartially represent them within your company’s walls.

2. Explore Existing Academic And Industry Examples #

Why reinvent the wheel when we already have so many inspiring starting points? Once you’re committed to ethics, you should explore other relevant examples of research ethics in the wild. Many organizations proudly share their own code of ethics with the public, serving as a worthy starting point for your own.

It would benefit any team conducting this desk research to include both academic as well as industry examples. Academia tends to include IRBs, which I find are rarely practical for industry — it’s up to us to uphold the ethics of our practice, as previously mentioned.

Here are some great examples to get you started:

Take a ‘researcher approach’ to reviewing these examples by keeping a log of each organization’s ethical principles or guidelines. Put them each into a long word document or spreadsheet and collate across 15-20 examples. You’ll definitely notice a few strong patterns and a lot of overlap. These overlaps and key themes will serve as a jumping-off point for developing your own principles, relevant to your team, organization, and industry.

3. Familiarize Yourself With Relevant Laws #

Whether only relevant to your state, union, or industry, you’ll want to make sure you’re intimately familiar with relevant laws and regulations that force compliance around a certain level of ethical practice.

For example, the General Data Protection Regulation (GDPR) and the California Consumer Privacy Act (CCPA) both have strict rules surrounding how organizations may collect, store and secure consumer data. This not only applies to how companies do business but how they conduct research as well! If you live in the European Union or the state of California and are not yet familiar with these laws, I highly recommend you start reading today.

These regulations are actually quite profound as they almost codify ethics into law, requiring organizations to be compliant or otherwise face penalties such as fines or legal action. While these laws are based on ethical practice, they are still bare-bones and don’t cover the full spectrum of participant welfare or dignity, which are paramount when consumers are in your charge during the course of your research.

Some industries have their own regulations or legal practices which safeguard consumer data even more tightly than GDPR or CCPA. You may be familiar with the Health Insurance Portability and Accountability Act (HIPPA), which protects sensitive patient health information from being disclosed without consent or knowledge.

Many may not be familiar with other specific protections such as Customer Network Proprietary Information (CPNI) which safeguards the type, quantity, configuration, or location of telecommunications and interconnected services you use. Being mindful and educated about your industry’s specific regulations will not only keep you out of trouble but will provide yet another input into creating your own ethical user research principles.

4. Brainstorm Your Core Principles As A Team

Now the fun part! Whether your team is distributed or co-located, you’ll want to use what you’ve learned in steps 2 and 3 in order to brainstorm what principles you want to codify into your own code of ethics. There truly is no right or wrong way to do this, however, following a typical ideation workshop framework will really help add rigor to the process.

Start by affinity mapping your industry and academic examples using sticky notes, google slides or miro/mural board. Working as a team, identify the overlaps across multiple organizations by grouping the principles you feel are similar or otherwise saying the same thing. If you feel two principles are intertwined or tightly related, however, still distinct then by all means include both in the same principle.

For example “Diversity” or “Inclusion” have distinct goals, however, they’re often grouped together as “Diversity, Equity And Inclusion.” If there is strong disagreement between one or more principles that some feel should be combined while others feel should be separate, then run a dot-voting prioritization exercise. Each team member gets a dot and is allowed to cast their vote to either group or keep separate.

Then incorporate industry, state, or special laws/regulations from your research in step 3. Start by identifying any overlaps with your existing principles. If there’s overlap, simply build onto your existing principle! If you find a piece of the law is unique or demands its own dedicated principle, then by all means codify it that way!

Lastly, take a step back and look at your ethical principles as a whole set. Ideally, you would have no more than 10, no less than 4 principles — more than 10 and they’ll be hard to keep track of; less than 4 and creating specific and relevant examples when creating your Ethical Code will be difficult.

The goal is to have specific enough principles where everyone on the team can think of 2-3 examples of exactly how to apply that principle to their everyday work, without being overly general or vague. If you feel you have too many, consider if there are any overlaps or relationships between two or more and combine them accordingly into a larger principle.

Here’re example principles after going through the exercises above:

  • Sensitivity And No Harm,
  • Honesty And Transparency,
  • Confidentiality And Data,
  • Accuracy And Impartiality,
  • Diversity, Equity And Inclusion.

Once you’ve determined your high-level principles and feel good about them as a team, it’s time to make it real and draft your Code of Ethics.

5. Draft Your Code For Feedback #

In order to make your Code of Ethics more easily understood, actionable and impactful, you’ll need to expand on each principle with three key components:

  1. A brief description
    This should expound upon the principle itself and provide more detail in its definition and intention. What does honesty mean in the content of user research? When defining this principle, it’s important to note why it’s relevant in the first place and why it is a moral standard. Within this description, you’ll also want to take a moment to identify who the principle is intended for. A team that follows an honorable Code of Ethics is no doubt benefiting its research participants, but it may also apply to internal processes and stakeholder teams as well.
  2. Bulleted agreements
    Perhaps the most important piece of the Code is where it would benefit you to get specific and directly relate to the user research practice at your organization. These agreements should not only exemplify the principle itself but provide more clarity as to how the team may apply the principle in their everyday work. In a way, these become somewhat of a checklist of tactics you’ll execute every time you plan, recruit for, conduct, and report on research.
  3. A few examples
    Like that which is provided below, examples help paint a full picture of the principle in action. You want to be careful to frame your example in the context of an ethical problem, then showcase the appropriate solution which clearly ties to an agreement of the principle. Even better if you have real past experiences that you can use as examples!

Putting these components of the Code together is a great place to have a roundtable discussion about the definition of each principle as well as individual researcher’s past experiences in unique ethical situations. It becomes extraordinarily fruitful to then have an open conversation around what the team believes should be the most appropriate definition, agreements, and examples. This process not only builds collective buy-in for the Code but also deepens everyone’s understanding of each principle as well.

Here’s an example principle in action:

  • Honesty And Transparency
    Maintains the integrity of our individual researchers and our research work. This principle applied not only to participants but also internally when discussing study design or findings.
    • Inform participants of study requirements upfront;
    • Inform participants where their data is going and how it will generally be used;
    • Explain any purposeful manipulation at a session’s end;
    • Explain the pros and cons of methodologies, and study limitations to internal stakeholders.
Example:
When designing a study with biometrics, devices with sensors need to be worn by participants. It should be communicated to participants that they will be wearing devices on or close to the skin which may cause minor irritation. The researcher should clearly explain why and where they’ll be needed in the study.

6. Implement Feedback And Finalize

When you have your first pass at your Code of Ethics and it shares collective buy-in from members of the team, it’s time to get some external validation from partner teams before considering it final.

In this step, you should schedule meetings with your points of contact from the legal and ethics departments within your organization in order to share the great work you’ve done as well as to check to make sure you’re not missing anything. It’s important to make sure you have this second pair of eyes because these groups are responsible for upholding ethics across the business and have deep knowledge of CCPA, GDPR, and other regulations which may affect your final Code.

Be warned that if you don’t already work closely with these teams, you may need to first introduce them to the type of work you do and the purpose of your team. This could mean two separate meetings; an introduction meeting may be needed to explain your team and a follow-on meeting to deep dive into your Code of Ethics.

If they’re unfamiliar with or not aware of any user research currently being done, they may already have strong concerns regarding privacy law. Remind them that’s why you’re creating this Code and why you’ve reached out to them — to ensure everyone is on the same page!

Putting It Into Practice

Now that you have a strong Code of Ethics that has internal and external team support, you’ll want to put it to work. The following are examples of where your Code of Ethics directly affects the processes, tools, and practices of your team. This is the part where the investment really comes in as each of these could take hours or even days to set the foundation for.

If you don’t proceed beyond this point and stop only when you’ve made your Code, then you run the risk of never really practicing what you’ve created. While the following isn’t quite ‘set it and forget it,’ rest assured the majority of the work is upfront in building the documentation vs. the ongoing maintenance and practice. Keep in mind these are great starting points, however, you may have other areas which could be improved using your new principles!

Screeners And Recruitment

Assuming you have an ethical principle-centered around or associated with Diversity, Equity, and Inclusion (DE&I), updating your screener questionnaire template and recruitment practices will help ensure every study accounts for the diversity and uniqueness of the customers for whom you serve.

In screener questionnaires, care should be taken in the administration and wording of questions relating to race, ethnicity, and gender. Because people identify in different and unique ways, these questions are asked and what responses you allow should reflect that flexibility. While there is plenty of literature out there to help you with crafting most demographics related questions, here are some ethical considerations:

  • Before asking for personal information such as gender or race, provide a very brief explanation as to why you’re asking for it in the first place. Providing this context can ease the minds of those who fear their information may be used for exploitation.
  • Allow ‘select all that apply’ checkbox answer options. Many may identify as mixed-race or on a spectrum of gender — providing them with multiple ways of identification more accurately represents them.
  • Provide a ‘prefer not to answer’ option for those who don’t feel comfortable disclosing this information.
  • For race, be exhaustive with the answer options to account for diverse classification and to avoid misrepresentation.
  • For gender, include ‘non-binary’ and ‘prefer to self identify’ options to accommodate those who don’t identify within a fixed gender.

In addition to screener wording, the individuals or team responsible for study recruitment efforts should make a purposeful effort to recruit a diverse group, even for small sizes for qualitative research. When working with recruitment firms or advanced panel tools, this should be relatively straightforward.

However, committing to diversity may mean canceling a few sessions and re-recruiting if your first round of recruitment efforts result in 910 participants being middle-aged white men, for example.

Data Retention And Management

Participants often provide sensitive, personally identifiable information that they may expect will be kept private and secure. This may even be a requirement of the law, as per the aforementioned regulations (GDPR And CCPA). In order to do this, you will need to create a comprehensive Data Retention Policy for all types of information that you’re collecting from participants. While there are many GDPR And CCPA templates and resources available to help you create your own policy, the key questions that must be asked are:

  • What data are you collecting?
  • Are you storing it? Why/for what purpose?
  • How long are you storing it for before deletion?
  • How is this data being secured?
  • Who, if anyone else, has access to this data?

Once you create your own Data And Retention policy, be sure to gain alignment with your own Legal team to ensure it meets the standards of local or federal requirements — especially in regards to specialized data related to CPNI or HIPPA. Then, share and train your team to uphold this policy, explaining the importance of safeguarding sensitive participant information.

An easy but effective way to hold everyone accountable to this policy is to include a ‘Data Retention Plan’ section within every Test Plan document which outlines what data is being collected during the course of the research, how it will be used, if it will be stored, and how it is being protected. For example, an in-situ contextual inquiry where COVID-19 vaccination status is being discussed, you’d want to document:

Data Instrument Retention Plan Notes
Name And Likeness Video/Audio Recording And Recruitment firm Codify as ID # Identification is not important. Participant will be anonymized.
Mailing Address Recruitment Firm Delete after data collection Only needed for moderator’s arrival during the study.
Vaccination StatusVideo/Audio RecordingMaintain for 6 monthsNeeded to create personas. Data not needed after study completion.

 

 

A key component of ethical user research is keeping the participant comfortable and informed at all times in order to protect their dignity and welfare. This may be done by providing them proper documentation and a forum in which to address questions or concerns that they may have prior to the study.

In addition, if a body of work is internally safeguarded or confidential, you may wish that the participants remain undisclosed. Non-disclosure Agreements must not be lengthy legal documents that are difficult to follow and require an advanced degree to read and understand.

There is more than one way to write an Informed Consent document, however, the key components are mostly the same:

  • Begin by thanking the participant for their consideration of participating in the study.
  • Explain the topic of the study at a high level by providing just enough detail to build an understanding of the subject matter.
  • Provide a clear, bulleted list of expectations or activities the participant will be required to participate in during their session.
  • Disclose any potential risk of harm, danger, or manipulation as part of the study.
  • Remind them of the time commitment for the session, any follow on activities after the study, and the nature of the incentive for their involvement.
  • End with a clear request to provide written consent of the above, including both their signature as well as today’s date.

It is paramount that participants are able to deny or withdraw their consent at any time, without warning or reason and without penalty — informed consent is useless if the participant is penalized or coerced into providing and maintaining their consent.

At times, our research may touch on triggering, emotional topics. Other times, there may be sudden emergencies that come up in the middle of the session. When these things happen, the participant should feel empowered to take a break or step away without fear of losing their incentive or fear of any form of retaliation.

Internal Representation: Reports, Prototypes And Personas

Ethical user research extends beyond the study and data collection, permeating into our internal artifacts that may be used for many months afterward. While there are more examples than will be covered here, the primary three areas where ethical considerations should be top of mind are in your findings reports, design prototypes, and especially in your user personas.

Findings Reports

When reporting a study’s findings, care should be taken to be as representative and impartial as you were during the design and administration of the study itself so that the audience or readers of the report have the full, accurate picture of what was learned and how.

  • Provide a ‘study setup’ section of the report which outlines a brief, but robust study methodology description. Include both Pros and Cons of the study method so that you’re being transparent in its limitations and reach.
  • Include a ‘participants’ section of the report which includes a bulleted list of the participant attributes. If necessary, include any footnotes around a limitation of diversity (i.e. if against all efforts you recruited 30 women of 40 total participants, this should be noted).
  • When using photos, avoid participant’s faces (likeness, PII) unless you’ve been provided explicit consent to do so from the participant. This is especially important when discussing personal or sensitive topics.
  • Use direct quotes, audio recordings, or photos from a range of participants to reflect and promote the diversity of your recruit. This provides the fullest picture of who you spoke with during the study.
  • Don’t paraphrase direct quotes nor infer too heavily without solid context or understanding. This maintains impartiality and avoids unconscious bias.
  • Avoid reporting demographic information for individual qualitative findings as it may inadvertently support institutionalized biases or stigma (i.e. 2 male Caucasians said X, 1 black woman said Y). It is best practice to segment by demographics only with quantitative samples where meaningful differences may be found through statistical analysis.

User Personas

A common framework for communicating generative user research findings is the user persona — an archetypical representation of a group of users that exhibit similar attitudes and behaviors. While incredibly powerful for making design decisions for months or even a year after the completion of research, they’re just as powerful in reinforcing gender, age, or racial stereotypes.

Care should be taken in the crafting of user personas so that they uphold their humanizing character while avoiding enforcing bias. While there are other resources for creating agnostic user persons, here are a few highlights:

  • Try to avoid using human names altogether. Using human names often promote biased stereotypes given strong societal expectations around different gender roles, positions of authority, or occupational status. Instead, you may lean into pithy 2-3 word titles which better exemplify who your Personas are (i.e. ‘Cautious Comparer,’ or ‘Impulsive Spender’).
  • Use gender-neutral and culturally diverse names. If you insist on using names in order to humanize the personas, use gender-neutral names to fight the unconscious gender bias. There are also many cultures and backgrounds with which your users may identify — using only names from western European etymology may incidentally erase their unique identity. Using names from diverse etymology helps fight this bias. Here are a few examples of gender-neutral, culturally diverse names: Adrian, Armani, Brett, Devon, Kai, Krishna, Maren, Noor, Nilam, Sam, Jaylin, Jordan, Yoshi.
  • As with the above, leverage artistic visualizations which exemplify the Persona more accurately than a fictitious image or photo. For example, in a Persona for a car manufacturer, it is much more telling to see a weighted scale with a dollar sign on one side and the word ‘safety’ on the other side than it is to see a stock photo of a worried looking person in the front seat. Using photos or illustrations for Personas further stigmatizes race, gender, and body type. If insistent on using humanizing imagery, consider artful illustrations which are ambiguous in gender, race, and body types in order to remain inclusive.
  • Do not include disability status unless this was directly part of your research or you’re creating a set of personas specifically focused on people of varying abilities or with a focus on intersectionality. Consider if this level of information or detail is important for the product you’re creating. While the goal of including this information may be with good intentions, you may be misrepresenting already marginalized communities.
  • Try and avoid gender, race, sexual orientation, or other demographics that are more akin to segmentation analysis and not user personas. Personas should be representations of like-attitudes and especially behaviors which often transcend basic demographics.

As apparent by the above guidance, creating Personas tows a very fine line between creating a useful fictitious archetype and promoting bias and stigma. The latter is highly unethical and leads to false assumptions and even worse design and content strategy decisions.

Design Prototypes

Similar to the above guidance given to User Personas, the same care should be taken with users personified through prototype designs. Often we create situations or scenarios to stress test the content and interaction design of our systems by placing a fictitious character at the heart of our mock-ups.

Consider leveraging the gender-neutral and culturally diverse names above for use within your prototypes (i.e. the account name of an authenticated user). For account or profile images, leverage artistic illustrations, or a diverse range of stock photography to depict your users. When creating designs where multiple individuals will be represented, take a step back to ensure diversity in the holistic group rather than a focus on one gender, race, culture, or body type.

Bringing It All Together

Ethical user research isn’t only the right thing to do but it makes good business sense. Principles of ethical conduct guide our decision-making, keeping us out of trouble and holding us accountable to our users and society.

By influencing your practices, templates, and processes with a foundation of ethical principles you will show your team and your organization that you value the dignity and welfare of your users. Building an ethical user research practice at any organization is not inherently difficult, however, requires upfront and ongoing conscious investment in order to do so effectively.

It’s up to us to put the humans we design for at the center of our own business practices and create a true form of human-computer interaction. No one will do this work for us. Noone will hold us accountable. After all, ethics (especially in our field) are an exclusively human concern with no superhuman authority behind it.

Are you ready to make a difference?