Tag Archives: project

Thumbnail

Lessons Learned While Developing WordPress Plugins




Lessons Learned While Developing WordPress Plugins

Jakub Mikita



Every WordPress plugin developer struggles with tough problems and code that’s difficult to maintain. We spend late nights supporting our users and tear out our hair when an upgrade breaks our plugin. Let me show you how to make it easier.

In this article, I’ll share my five years of experience developing WordPress plugins. The first plugin I wrote was a simple marketing plugin. It displayed a call to action (CTA) button with Google’s search phrase. Since then, I’ve written another 11 free plugins, and I maintain almost all of them. I’ve written around 40 plugins for my clients, from really small ones to one that have been maintained for over a year now.

Measuring Performance With Heatmaps

Heatmaps can show you the exact spots that receive the most engagement on a given page. Find out why they’re so efficient for your marketing goals and how they can be integrated with your WordPress site. Read article →

Good development and support lead to more downloads. More downloads mean more money and a better reputation. This article will show you the lessons I’ve learned and the mistakes I’ve made, so that you can improve your plugin development.

1. Solve A Problem

If your plugin doesn’t solve a problem, it won’t get downloaded. It’s as simple as that.

Take the Advanced Cron Manager plugin (8,000+ active installations). It helps WordPress users who are having a hard time debugging their cron. The plugin was written out of a need — I needed something to help myself. I didn’t need to market this one, because people already needed it. It scratched their itch.

On the other hand, there’s the Bug — fly on the screen plugin (70+ active installations). It randomly simulates a fly on the screen. It doesn’t really solve a problem, so it’s not going to have a huge audience. It was a fun plugin to develop, though.

Focus on a problem. When people don’t see their SEO performing well, they install an SEO plugin. When people want to speed up their website, they install a caching plugin. When people can’t find a solution to their problem, then they find a developer who writes a solution for them.

As David Hehenberger attests in his article about writing a successful plugin, need is a key factor in the WordPress user’s decision of whether to install a particular plugin.

If you have an opportunity to solve someone’s problem, take a chance.

2. Support Your Product

“3 out of 5 Americans would try a new brand or company for a better service experience. 7 out of 10 said they were willing to spend more with companies they believe provide excellent service.”

— Nykki Yeager

Don’t neglect your support. Don’t treat it like a must, but more like an opportunity.

Good-quality support is critical in order for your plugin to grow. Even a plugin with the best code will get some support tickets. The more people who use your plugin, the more tickets you’ll get. A better user experience will get you fewer tickets, but you will never reach inbox 0.

Every time someone posts a message in a support forum, I get an email notification immediately, and I respond as soon as I can. It pays off. The vast majority of my good reviews were earned because of the support. This is a side effect: Good support often translates to 5-star reviews.

When you provide excellent support, people start to trust you and your product. And a plugin is a product, even if it’s completely free and open-source.

Good support is more complex than about writing a short answer once a day. When your plugin gains traction, you’ll get several tickets per day. It’s a lot easier to manage if you’re proactive and answer customers’ questions before they even ask.

Here’s a list of some actions you can take:

  • Create an FAQ section in your repository.
  • Pin the “Before you ask” thread at the top of your support forum, highlighting the troubleshooting tips and FAQ.
  • Make sure your plugin is simple to use and that users know what they should do after they install it. UX is important.
  • Analyze the support questions and fix the pain points. Set up a board where people can vote for the features they want.
  • Create a video showing how the plugin works, and add it to your plugin’s main page in the WordPress.org repository.

It doesn’t really matter what software you use to support your product. The WordPress.org’s official support forum works just as well as email or your own support system. I use WordPress.org’s forum for the free plugins and my own system for the premium plugins.

3. Don’t Use Composer

Composer is package-manager software. A repository of packages is hosted on packagist.org, and you can easily download them to your project. It’s like NPM or Bower for PHP. Managing your third-party packages the way Composer does is a good practice, but don’t use it in your WordPress project.

I know, I dropped a bomb. Let me explain.

Composer is great software. I use it myself, but not in public WordPress projects. The problem lies in conflicts. WordPress doesn’t have any global package manager, so each and every plugin has to load dependencies of their own. When two plugins load the same dependency, it causes a fatal error.

There isn’t really an ideal solution to this problem, but Composer makes it worse. You can bundle the dependency in your source manually and always check whether you are safe to load it.

Composer’s issue with WordPress plugins is still not solved, and there won’t be any viable solution to this problem in the near future. The problem was raised many years ago, and, as you can read in WP Tavern’s article, many developers are trying to solve it, without any luck.

The best you can do is to make sure that the conditions and environment are good to run your code.

4. Reasonably Support Old PHP Versions

Don’t support very old versions of PHP, like 5.2. The security issues and maintenance aren’t worth it, and you’re not going to earn more installations from those older versions.


The Notification plugin’s usage on PHP versions from May 2018. (Large preview)

Go with PHP 5.6 as a minimal requirement, even though official support will be dropped by the end of 2018. WordPress itself requires PHP 7.2.

There’s a movement that discourages support of legacy PHP versions. The Yoast team released the Whip library, which you can include in your plugin and which displays to your users important information about their PHP version and why they should upgrade.

Tell your users which versions you do support, and make sure their website doesn’t break after your plugin is installed on too low a version.

5. Focus On Quality Code

Writing good code is tough in the beginning. It takes time to learn the “SOLID” principles and design patterns and to change old coding habits.

It once took me three days to display a simple string in WordPress, when I decided to rewrite one of my plugins using better coding practices. It was frustrating knowing that it should have taken 30 minutes. Switching my mindset was painful but worth it.

Why was it so hard? Because you start writing code that seems at first to be overkill and not very intuitive. I kept asking myself, “Is this really needed?” For example, you have to separate the logic into different classes and make sure each is responsible for a single thing. You also have to separate classes for the translation, custom post type registration, assets management, form handlers, etc. Then, you compose the bigger structures out of the simple small objects. That’s called dependency injection. That’s very different from having “front end” and “admin” classes, where you cram all your code.

The other counterintuitive practice was to keep all actions and filters outside of the constructor method. This way, you’re not invoking any actions while creating the objects, which is very helpful for unit testing. You also have better control over which methods are executed and when. I wish I knew this before I wrote a project with an infinite loop caused by the actions in the constructor methods. Those kinds of bugs are hard to trace and hard to fix. The project had to be refactored.

The above are but a few examples, but you should get to know the SOLID principles. These are valid for any system and any coding language.

When you follow all of the best practices, you reach the point where every new feature just fits in. You don’t have to tweak anything or make any exceptions to the existing code. It’s amazing. Instead of getting more complex, your code just gets more advanced, without losing flexibility.

Also, format your code properly, and make sure every member of your team follows a standard. Standards will make your code predictable and easier to read and test. WordPress has its own standards, which you can implement in your projects.

6. Test Your Plugin Ahead Of Time

I learned this lesson the hard way. Lack of testing led me to release a new version of a plugin with a fatal error. Twice. Both times, I got a 1-star rating, which I couldn’t turn into a positive review.

You can test manually or automatically. Travis CI is a continuous testing product that integrates with GitHub. I’ve built a really simple test suite for my Notification plugin that just checks whether the plugin can boot properly on every PHP version. This way, I can be sure the plugin is error-free, and I don’t have to pay much attention to testing it in every environment.

Each automated test takes a fraction of a second. 100 automated tests will take about 10 minutes to complete, whereas manual testing needs about 2 minutes for each case.

The more time you invest in testing your plugin up front, the more it will save you in the long run.

To get started with automated testing, you can use the WP-CLI \`wp scaffold plugin-test\` command, which installs all of the configuration you need.

7. Document Your Work

It’s a cliche that developers don’t like to write documentation. It’s the most boring part of the development process, but a little goes a long way.

Write self-documenting code. Pay attention to variable, function and class names. Don’t make any complicated structures, like cascades that can’t be read easily.

Another way to document code is to use the “doc block”, which is a comment for every file, function and class. If you write how the function works and what it does, it will be so much easier to understand when you need to debug it six months from now. WordPress Coding Standards covers this part by forcing you to write the doc blocks.

Using both techniques will save you the time of writing the documentation, but the code documentation is not going to be read by everyone.

For the end user, you have to write high-quality, short and easy-to-read articles explaining how the system works and how to use it. Videos are even better; many people prefer to watch a short tutorial than read an article. They are not going to look at the code, so make their lives easier. Good documentation also reduces support tickets.

Conclusion

These seven rules have helped me develop good-quality products, which are starting to be a core business at BracketSpace. I hope they’ll help you in your journey with WordPress plugins as well.

Let me know in the comments what your golden development rule is or whether you’ve found any of the above particularly helpful.

Smashing Editorial
(il, ra, yk)


Link:  

Lessons Learned While Developing WordPress Plugins

Thumbnail

Building Mobile Apps Using React Native And WordPress




Building Mobile Apps Using React Native And WordPress

Muhammad Muhsin



As web developers, you might have thought that mobile app development calls for a fresh learning curve with another programming language. Perhaps Java and Swift need to be added to your skill set to hit the ground running with both iOS and Android, and that might bog you down.

But this article has you in for a surprise! We will look at building an e-commerce application for iOS and Android using the WooCommerce platform as our backend. This would be an ideal starting point for anyone willing to get into native cross-platform development.

A Brief History Of Cross-Platform Development

It’s 2011, and we see the beginning of hybrid mobile app development. Frameworks like Apache Cordova, PhoneGap, and Ionic Framework slowly emerge. Everything looks good, and web developers are eagerly coding away mobile apps with their existing knowledge.

However, mobile apps still looked like mobile versions of websites. No native designs like Android’s material design or iOS’s flat look. Navigation worked similar to the web and transitions were not buttery smooth. Users were not satisfied with apps built using the hybrid approach and dreamt of the native experience.

Fast forward to March 2015, and React Native appears on the scene. Developers are able to build truly native cross-platform applications using React, a favorite JavaScript library for many developers. They are now easily able to learn a small library on top of what they know with JavaScript. With this knowledge, developers are now targeting the web, iOS and Android.

Furthermore, changes done to the code during development are loaded onto the testing devices almost instantly! This used to take several minutes when we had native development through other approaches. Developers are able to enjoy the instant feedback they used to love with web development.

React developers are more than happy to be able to use existing patterns they have followed into a new platform altogether. In fact, they are targeting two more platforms with what they already know very well.

This is all good for front-end development. But what choices do we have for back-end technology? Do we still have to learn a new language or framework?

The WordPress REST API

In late 2016, WordPress released the much awaited REST API to its core, and opened the doors for solutions with decoupled backends.

So, if you already have a WordPress and WooCommerce website and wish to retain exactly the same offerings and user profiles across your website and native app, this article is for you!

Assumptions Made In This Article

I will walk you through using your WordPress skill to build a mobile app with a WooCommerce store using React Native. The article assumes:

  • You are familiar with the different WordPress APIs, at least at a beginner level.
  • You are familiar with the basics of React.
  • You have a WordPress development server ready. I use Ubuntu with Apache.
  • You have an Android or an iOS device to test with Expo.

What We Will Build In This Tutorial

The project we are going to build through this article is a fashion store app. The app will have the following functionalities:

  • Shop page listing all products,
  • Single product page with details of the selected item,
  • ‘Add to cart’ feature,
  • ‘Show items in cart’ feature,
  • ‘Remove item from cart’ feature.

This article aims to inspire you to use this project as a starting point to build complex mobile apps using React Native.

Note: For the full application, you can visit my project on Github and clone it.

Getting Started With Our Project

We will begin building the app as per the official React Native documentation. Having installed Node on your development environment, open up the command prompt and type in the following command to install the Create React Native App globally.

npm install -g create-react-native-app

Next, we can create our project

create-react-native-app react-native-woocommerce-store

This will create a new React Native project which we can test with Expo.

Next, we will need to install the Expo app on our mobile device which we want to test. It is available for both iOS and Android.

On having installed the Expo app, we can run npm start on our development machine.

cd react-native-woocommerce-store

npm start


Starting a React Native project through the command line via Expo. (Large preview)

After that, you can scan the QR code through the Expo app or enter the given URL in the app’s search bar. This will run the basic ‘Hello World’ app in the mobile. We can now edit App.js to make instant changes to the app running on the phone.

Alternatively, you can run the app on an emulator. But for brevity and accuracy, we will cover running it on an actual device.

Next, let’s install all the required packages for the app using this command:

npm install -s axios react-native-htmlview react-navigation react-redux redux redux-thunk

Setting Up A WordPress Site

Since this article is about creating a React Native app, we will not go into details about creating a WordPress site. Please refer to this article on how to install WordPress on Ubuntu. As WooCommerce REST API requires HTTPS, please make sure it is set up using Let’s Encrypt. Please refer to this article for a how-to guide.

We are not creating a WordPress installation on localhost since we will be running the app on a mobile device, and also since HTTPS is needed.

Once WordPress and HTTPS are successfully set up, we can install the WooCommerce plugin on the site.


Installing the WooCommerce plugin to our WordPress installation. (Large preview)

After installing and activating the plugin, continue with the WooCommerce store setup by following the wizard. After the wizard is complete, click on ‘Return to dashboard.’

You will be greeted by another prompt.


Adding example products to WooCommerce. (Large preview)

Click on ‘Let’s go‘ to ‘Add example products’. This will save us the time to create our own products to display in the app.

Constants File

To load our store’s products from the WooCommerce REST API, we need the relevant keys in place inside our app. For this purpose, we can have a constans.js file.

First create a folder called ‘src’ and create subfolders inside as follows:


Create the file ‘Constants.js’ within the constans folder. (Large preview)

Now, let’s generate the keys for WooCommerce. In the WordPress dashboard, navigate to WooCommerce → Settings → API → Keys/Apps and click on ‘Add Key.’

Next create a Read Only key with name React Native. Copy over the Consumer Key and Consumer Secret to the constants.js file as follows:

const Constants = 
   URL: 
wc: 'https://woocommerce-store.on-its-way.com/wp-json/wc/v2/'
   ,
   Keys: 
ConsumerKey: 'CONSUMER_KEY_HERE',
ConsumerSecret: 'CONSUMER_SECRET_HERE'
   
}
export default Constants;

Starting With React Navigation

React Navigation is a community solution to navigating between the different screens and is a standalone library. It allows developers to set up the screens of the React Native app with just a few lines of code.

There are different navigation methods within React Navigation:

  • Stack,
  • Switch,
  • Tabs,
  • Drawer,
  • and more.

For our Application we will use a combination of StackNavigation and DrawerNavigation to navigate between the different screens. StackNavigation is similar to how browser history works on the web. We are using this since it provides an interface for the header and the header navigation icons. It has push and pop similar to stacks in data structures. Push means we add a new screen to the top of the Navigation Stack. Pop removes a screen from the stack.

The code shows that the StackNavigation, in fact, houses the DrawerNavigation within itself. It also takes properties for the header style and header buttons. We are placing the navigation drawer button to the left and the shopping cart button to the right. The drawer button switches the drawer on and off whereas the cart button takes the user to the shopping cart screen.

const StackNavigation = StackNavigator(
 DrawerNavigation:  screen: DrawerNavigation 
}, 
   headerMode: 'float',
   navigationOptions: ( navigation, screenProps ) => (
     headerStyle:  backgroundColor: '#4C3E54' ,
     headerTintColor: 'white',
     headerLeft: drawerButton(navigation),
     headerRight: cartButton(navigation, screenProps)
   })
 });

const drawerButton = (navigation) => (
 <Text
   style= padding: 15, color: 'white' }
   onPress=() => 
     if (navigation.state.index === 0) 
       navigation.navigate('DrawerOpen')
      else 
       navigation.navigate('DrawerClose')
     
   }
   }> (
 <Text style= padding: 15, color: 'white' }
   onPress=() =>  navigation.navigate('CartPage') }
 >
   <EvilIcons name="cart" size=30 />
   screenProps.cartCount
 </Text>
);

DrawerNavigation on the other hands provides for the side drawer which will allow us to navigate between Home, Shop, and Cart. The DrawerNavigator lists the different screens that the user can visit, namely Home page, Products page, Product page, and Cart page. It also has a property which will take the Drawer container: the sliding menu which opens up when clicking the hamburger menu.

const DrawerNavigation = DrawerNavigator(
 Home: 
   screen: HomePage,
   navigationOptions: 
     title: "RN WC Store"
   
 },
 Products: 
   screen: Products,
   navigationOptions: 
     title: "Shop"
   
 },
 Product: 
   screen: Product,
   navigationOptions: ( navigation ) => (
     title: navigation.state.params.product.name
   ),
 },
 CartPage: 
   screen: CartPage,
   navigationOptions: 
     title: "Cart"
   
 }
}, 
   contentComponent: DrawerContainer
 );

#


Left: The Home page (homepage.js). Right: The open drawer (DrawerContainer.js).

Injecting The Redux Store To App.js

Since we are using Redux in this app, we have to inject the store into our app. We do this with the help of the Provider component.

const store = configureStore();

class App extends React.Component 
 render() 
   return (
     <Provider store=store>    
       <ConnectedApp />    
     </Provider>    
   )
 }
}

We will then have a ConnectedApp component so that we can have the cart count in the header.

class CA extends React.Component 
 render() 
   const cart = 
     cartCount: this.props.cart.length
   
   return (
     <StackNavigation screenProps=cart />
   );
 }
}

function mapStateToProps(state) 
 return 
   cart: state.cart
 ;
}

const ConnectedApp = connect(mapStateToProps, null)(CA);

Redux Store, Actions, And Reducers

In Redux, we have three different parts:

  1. Store
    Holds the whole state of your entire application. The only way to change state is to dispatch an action to it.
  2. Actions
    A plain object that represents an intention to change the state.
  3. Reducers
    A function that accepts a state and an action type and returns a new state.

These three components of Redux help us achieve a predictable state for the entire app. For simplicity, we will look at how the products are fetched and saved in the Redux store.

First of all, let’s look at the code for creating the store:

let middleware = [thunk];

export default function configureStore() 
    return createStore(
        RootReducer,
        applyMiddleware(...middleware)
    );

Next, the products action is responsible for fetching the products from the remote website.

export function getProducts() 
   return (dispatch) => 
       const url = `$Constants.URL.wcproducts?per_page=100&consumer_key=$Constants.Keys.ConsumerKey&consumer_secret=$Constants.Keys.ConsumerSecret`
      
       return axios.get(url).then(response => 
           dispatch(
               type: types.GET_PRODUCTS_SUCCESS,
               products: response.data
           
       )}).catch(err => 
           console.log(err.error);
       )
   };
}

The products reducer is responsible for returning the payload of data and whether it needs to be modified.

export default function (state = InitialState.products, action) 
    switch (action.type) 
        case types.GET_PRODUCTS_SUCCESS:
            return action.products;
        default:
            return state;
    
}

Displaying The WooCommerce Shop

The products.js file is our Shop page. It basically displays the list of products from WooCommerce.

class ProductsList extends Component 

 componentDidMount() 
   this.props.ProductAction.getProducts(); 
 

 _keyExtractor = (item, index) => item.id;

 render() 
   const  navigate  = this.props.navigation;
   const Items = (
     <FlatList contentContainerStyle=styles.list numColumns=2
       data=this.props.products  
       keyExtractor=this._keyExtractor
       renderItem=
         ( item ) => (
           <TouchableHighlight style= width: '50%' } onPress=() => navigate("Product",  product: item )} underlayColor="white">
             <View style=styles.view >
               <Image style=styles.image source= uri: item.images[0].src } />
               <Text style=styles.text>item.name</Text>
             </View>
           </TouchableHighlight>
         )
       }
     />
   );
   return (
     <ScrollView>
       this.props.products.length ? Items :
         <View style= alignItems: 'center', justifyContent: 'center' }>
           <Image style=styles.loader source=LoadingAnimation />
         </View>
       }
     </ScrollView>
   );
 }
}

this.props.ProductAction.getProducts() and this.props.products are possible because of mapStateToProps and mapDispatchToProps.


Products listing screen. (Large preview)

mapStateToProps and mapDispatchToProps

State is the Redux store and Dispatch is the actions we fire. Both of these will be exposed as props in the component.

function mapStateToProps(state) 
 return 
   products: state.products
 ;
}
function mapDispatchToProps(dispatch) 
 return 
   ProductAction: bindActionCreators(ProductAction, dispatch)
 ;
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductsList);

Styles

In React, Native styles are generally defined on the same page. It’s similar to CSS, but we use camelCase properties instead of hyphenated properties.

const styles = StyleSheet.create(
 list: 
   flexDirection: 'column'
 ,
 view: 
   padding: 10
 ,
 loader: 
   width: 200,
   height: 200,
   alignItems: 'center',
   justifyContent: 'center',
 ,
 image: 
   width: 150,
   height: 150
 ,
 text: 
   textAlign: 'center',
   fontSize: 20,
   padding: 5
 
});

Single Product Page

This page contains details of a selected product. It shows the user the name, price, and description of the product. It also has the ‘Add to cart’ function.


Single product page. (Large preview)

Cart Page

This screen shows the list of items in the cart. The action has the functions getCart, addToCart, and removeFromCart. The reducer handles the actions likewise. Identification of actions is done through actionTypes — constants which describe the action that are stored in a separate file.

export const GET_PRODUCTS_SUCCESS = 'GET_PRODUCTS_SUCCESS'
export const GET_PRODUCTS_FAILED = 'GET_PRODUCTS_FAILED';

export const GET_CART_SUCCESS = 'GET_CART_SUCCESS';
export const ADD_TO_CART_SUCCESS = 'ADD_TO_CART_SUCCESS';
export const REMOVE_FROM_CART_SUCCESS = 'REMOVE_FROM_CART_SUCCESS';

This is the code for the CartPage component:

class CartPage extends React.Component 

 componentDidMount() 
   this.props.CartAction.getCart();
 

 _keyExtractor = (item, index) => item.id;

 removeItem(item) 
   this.props.CartAction.removeFromCart(item);
 

 render() 
   const  cart  = this.props;
   console.log('render cart', cart)

   if (cart && cart.length > 0) {
     const Items = <FlatList contentContainerStyle=styles.list
       data=cart
       keyExtractor=this._keyExtractor
       renderItem=( item ) =>
         <View style=styles.lineItem >
           <Image style=styles.image source= uri: item.image } />
           <Text style=styles.text>item.name</Text>
           <Text style=styles.text>item.quantity</Text>
           <TouchableOpacity style= marginLeft: 'auto' } onPress=() => this.removeItem(item)><Entypo name="cross" size=30 /></TouchableOpacity>
         </View>
       }
     />;
     return (
       <View style=styles.container>
         Items
       </View>
     )
   } else {
     return (
       <View style=styles.container>
         <Text>Cart is empty!</Text>
       </View>
     )
   }
 }
}

As you can see, we are using a FlatList to iterate through the cart items. It takes in an array and creates a list of items to be displayed on the screen.


#


Left: The cart page when it has items in it. Right: The cart page when it is empty.

Conclusion

You can configure information about the app such as name and icon in the app.json file. The app can be published after npm installing exp.

To sum up:

  • We now have a decent e-commerce application with React Native;
  • Expo can be used to run the project on a smartphone;
  • Existing backend technologies such as WordPress can be used;
  • Redux can be used for managing the state of the entire app;
  • Web developers, especially React developers can leverage this knowledge to build bigger apps.

For the full application, you can visit my project on Github and clone it. Feel free to fork it and improve it further. As an exercise, you can continue building more features into the project such as:

  • Checkout page,
  • Authentication,
  • Storing the cart data in AsyncStorage so that closing the app does not clear the cart.
Smashing Editorial
(da, lf, ra, yk, il)


More here: 

Building Mobile Apps Using React Native And WordPress

Thumbnail

Contributing To MDN Web Docs




Contributing To MDN Web Docs

Rachel Andrew



MDN Web Docs has been documenting the web platform for over twelve years and is now a cross-platform effort with contributions and an Advisory Board with members from Google, Microsoft and Samsung as well as those representing Firefox. Something that is fundamental to MDN is that it is a huge community effort, with the web community helping to create and maintain the documentation. In this article, I’m going to give you some pointers as to the places where you can help contribute to MDN and exactly how to do so.

If you haven’t contributed to an open source project before, MDN is a brilliant place to start. Skills needed range from copyediting, translating from English to other languages, HTML and CSS skills for creating Interactive Examples, or an interest in browser compatibility for updating Browser Compatibility data. What you don’t need to do is to write a whole lot of code to contribute. It’s very straightforward, and an excellent way to give back to the community if you have ever found these docs useful.

Contributing To The Documentation Pages

The first place you might want to contribute is to the MDN docs themselves. MDN is a wiki, so you can log in and start to help by correcting or adding to any of the documentation for CSS, HTML, JavaScript or any of the other parts of the web platform covered by MDN.

To start editing, you need to log in using GitHub. As is usual with a wiki, any editors of a page are listed, and this section will use your GitHub username. If you look at any of the pages on MDN contributors are listed at the bottom of the page, the below image shows the current contributors to the page on CSS Grid Layout.


A list showing names of people who contributed to this page


The contributors to the CSS Grid Layout page. (Large preview)

What Might You Edit?

Things that you might consider as an editor are fixing obvious typos and grammatical errors. If you are a good proofreader and copyeditor, then you may well be able to improve the readability of the docs by fixing any spelling or other errors that you spot.

You might also spot a technical error, or somewhere the specs have changed and where an update or clarification would be useful. With the huge range of web platform features covered by MDN and the rate of change, it is very easy for things to get out of date, if you spot something – fix it!

You may be able to use some specific knowledge you have to add additional information. For example, Eric Bailey has been adding Accessibility Concerns sections to many pages. This is a brilliant effort to highlight the things we should be thinking about when using a certain thing.


A screenshot of the Accessibility Concerns section


This section highlights the things we should be aware of when using background-color. (Large preview)

Another place you could add to a page is in adding “See also” links. These could be links to other parts of MDN, or to external resources. When adding external resources, these should be highly relevant to the property, element or technique being described by that document. A good candidate would be a tutorial which demonstrates how to use that feature, something which would give a reader searching for information a valuable next step.

How To Edit A Document?

Once you are logged in you will see a link to Edit on pages in MDN, clicking this will take you into a WYSIWYG editor for editing content. Your first few edits are likely to be small changes, in which case you should be able to follow your nose and edit the text. If you are making extensive edits, then it would be worth taking a look at the style guide first. There is also a guide to using the WYSIWYG Editor.

After making your edit, you can Preview and then Publish. Before publishing it is a good idea to explain what you added and why using the Revision Comment field.


Screenshot of this field in the edit form


Add a comment using the Revision Comment field. (Large preview)

Language Translations

Those of us with English as a first language are incredibly fortunate when it comes to information on the web, being able to get pretty much all of the information that we could ever want in our own language. If you are able to translate English language pages into other languages, then you can help to translate MDN Web Docs, making all of this information available to more people.


A screenshot showing the drop-down translations list


Translations available for the background-color page. (Large preview)

If you click on the language icon on any page, you can see which languages that information has been translated into, and you can add your own translations following the information on the page Translating MDN Pages.

Interactive Examples

The Interactive Examples on MDN, are the examples that you will see at the top of many pages of MDN, such as this one for the grid-area property.


Screenshot of an Interactive Example


The Interactive Example for the grid-area property. (Large preview)

These examples allow visitors to MDN to try out various values for CSS properties or try out a JavaScript function, right there on MDN without needing to head into a development environment to do so. The project to add these examples has been in progress for around a year, you can read about the project and progress to date in the post Bringing Interactive Examples to MDN.

The content for these Interactive Examples is held in the Interactive Examples GitHub repository. For example, if you wanted to locate the example for grid-area, you would find it in that repo under live-examples/css-examples/grid. Under that folder, you will find two files for grid-area, an HTML and a CSS file.

grid-area.html


<section id="example-choice-list" class="example-choice-list large" data-property="grid-area">
    <div class="example-choice" initial-choice="true">
        <pre><code class="language-css">grid-area: a;</code></pre>
        <button type="button" class="copy hidden" aria-hidden="true">
        <span class="visually-hidden">Copy to Clipboard</span>
        </button>
    </div>
    
    <div class="example-choice">
        <pre><code class="language-css">grid-area: b;</code></pre>
        <button type="button" class="copy hidden" aria-hidden="true">
        <span class="visually-hidden">Copy to Clipboard</span>
        </button>
    </div>
    
    <div class="example-choice">
        <pre><code class="language-css">grid-area: c;</code></pre>
        <button type="button" class="copy hidden" aria-hidden="true">
        <span class="visually-hidden">Copy to Clipboard</span>
        </button>
    </div> 
    
    <div class="example-choice">
        <pre><code class="language-css">grid-area: 2 / 1 / 2 / 4;</code></pre>
        <button type="button" class="copy hidden" aria-hidden="true">
        <span class="visually-hidden">Copy to Clipboard</span>
        </button>
    </div> 
</section>
    
<div id="output" class="output large hidden">
    <section id="default-example" class="default-example">
        <div class="example-container">
            <div id="example-element" class="transition-all">Example</div>
        </div>
    </section>
</div>

grid.area.css


.example-container 
    background-color: #eee;
    border: .75em solid;
    padding: .75em;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: repeat(3, minmax(40px, auto));
    grid-template-areas: 
    "a a a"
    "b c c"
    "b c c";
    grid-gap: 10px;
    width: 200px;
    
    
    .example-container > div 
    background-color: rgba(0, 0, 255, 0.2);
    border: 3px solid blue;
    
    
    example-element 
    background-color: rgba(255, 0, 200, 0.2);
    border: 3px solid rebeccapurple;
    

An Interactive Example is just a small demo, which uses some standard classes and IDs in order that the framework can pick up the example and make it interactive, where the values can be changed by a visitor to the page who wants to quickly see how it works. To add or edit an Interactive Example, first fork the Interactive Examples repo, clone it to your machine and follow the instructions on the Contributing page to install the required packages from npm and be able to build and test examples locally.

Then create a branch and edit or create your new example. Once you are happy with it, send a Pull Request to the Interactive Examples repo to ask for your example to be reviewed. In order to keep the examples consistent, reviews are fairly nitpicky but should point out the changes you need to make in a clear way, so you can update your example and have it approved, merged and added to an MDN page.


Screenshot of a tweet asking for help with HTML examples


MDN looking for help with HTML Interactive Examples. (Large preview)

With pretty much all of CSS now covered (in addition to the JavaScript examples), MDN is now looking for help to build the HTML examples. There are instructions as to how to get started in a post on the MDN Discourse Forum. Check out that post as it gives links to a Google doc that you can use to indicate that you are working on a particular example, as well as some other useful information.

The Interactive Examples are incredibly useful for people exploring the web platform, so adding to the project is an excellent way to contribute. Contributing to CSS or HTML examples requires knowledge of CSS and HTML, plus the ability to think up a clear demonstration. This last point is often the hardest part, I’ve created a lot of CSS Interactive Examples and spent more time thinking up the best example for each property than I do actually writing the code.

Browser Compat Data

Fairly recently the browser compatibility data listed on MDN Pages has begun to be updated through the Browser Compatibility Project. This project is developing browser compat data in JSON format, which can display the compatibility tables on MDN but also be useful data for other purposes.


An example screenshot of the old tables on MDN


The Old Browser Compat Tables on MDN. (Large preview)


An example screenshot of the new tables on MDN


The New Browser Compat Tables on MDN. (Large preview)

The Browser Compatibility Data is on GitHub, and if you find a page that has incorrect information or is still using the old tables, you can submit a Pull Request. The repository contains contribution information, however, the simplest way to start is to edit an existing example. I recently updated the information for the CSS shape-outside property. The property already had some data in the new format, but it was incomplete and incorrect.

To edit this data, I first forked the Browser Compat Data so that I had my own fork. I then cloned that to my machine and created a new branch to make my changes in.

Once I had my new branch, I found the JSON file for shape-outside and was able to make my edits. I already had a good idea about browser support for the property; I also used the live example on the shape-outside MDN page to test to see support when I wasn’t sure. Therefore making the edits was a case of working through the file, checking the version numbers listed for support of the property and updating those which were incorrect.

As the file is in JSON format is pretty straightforward to edit in any text editor. The .editorconfig file explains the simple formatting rules for these documents. There are also some helpful tips in this checklist.

Once you have made your edits, you can commit your changes, push your branch to your fork and then make a Pull Request to the Browser Compat Data repository. It’s likely that, as with the live examples, the reviewer will have some changes for you to make. In my PR for the Shapes data I had a few errors in how I had flagged the data and needed to make some changes to links. These were simple to make, and then my PR was merged.

Get Started

You can get started simply by picking something to add to and starting work on it in many cases. If you have any questions or need some help with any of this, then the MDN Discourse forum is a good place to post. MDN is the place I go to look up information, the place I send new developers and experienced developers alike, and its strength is the fact that we can all work to make it better.

If you have never made a Pull Request on a project before, it is a very friendly place to make that first PR and, as I hope I have shown, there are ways to contribute that don’t require writing any code at all. A very valuable skill for any documentation project is that of writing, editing and translating as these skills can help to make technical documentation easier to read and accessible to more people around the world.

Smashing Editorial
(il)


Read this article:

Contributing To MDN Web Docs

Thumbnail

Building A Serverless Contact Form For Your Static Site




Building A Serverless Contact Form For Your Static Site

Brian Holt



Static site generators provide a fast and simple alternative to Content Management Systems (CMS) like WordPress. There’s no server or database setup, just a build process and simple HTML, CSS, and JavaScript. Unfortunately, without a server, it’s easy to hit their limits quickly. For instance, in adding a contact form.

With the rise of serverless architecture adding a contact form to your static site doesn’t need to be the reason to switch to a CMS anymore. It’s possible to get the best of both worlds: a static site with a serverless back-end for the contact form (that you don’t need to maintain). Maybe best of all, in low-traffic sites, like portfolios, the high limits of many serverless providers make these services completely free!

In this article, you’ll learn the basics of Amazon Web Services (AWS) Lambda and Simple Email Service (SES) APIs to build your own static site mailer on the Serverless Framework. The full service will take form data submitted from an AJAX request, hit the Lambda endpoint, parse the data to build the SES parameters, send the email address, and return a response for our users. I’ll guide you through getting Serverless set up for the first time through deployment. It should take under an hour to complete, so let’s get started!

The static site form, sending the message to the Lambda endpoint and returning a response to the user.
The static site form, sending the message to the Lambda endpoint and returning a response to the user.

Setting Up

There are minimal prerequisites in getting started with Serverless technology. For our purposes, it’s simply a Node Environment with Yarn, the Serverless Framework, and an AWS account.

Setting Up The Project


The Serverless Framework web site. Useful for installation and documentation.


The Serverless Framework web site. Useful for installation and documentation.

We use Yarn to install the Serverless Framework to a local directory.

  1. Create a new directory to host the project.
  2. Navigate to the directory in your command line interface.
  3. Run yarn init to create a package.json file for this project.
  4. Run yarn add serverless to install the framework locally.
  5. Run yarn serverless create --template aws-nodejs --name static-site-mailer to create a Node service template and name it static-site-mailer.

Our project is setup but we won’t be able to do anything until we set up our AWS services.

Setting Up An Amazon Web Services Account, Credentials, And Simple Email Service


The Amazon Web Services sign up page, which includes a generous free tier, enabling our project to be entirely free.


The Amazon Web Services sign up page, which includes a generous free tier, enabling our project to be entirely free.

The Serverless Framework has recorded a video walk-through for setting up AWS credentials, but I’ve listed the steps here as well.

  1. Sign Up for an AWS account or log in if you already have one.
  2. In the AWS search bar, search for “IAM”.
  3. On the IAM page, click on “Users” on the sidebar, then the “Add user” button.
  4. On the Add user page, give the user a name – something like “serverless” is appropriate. Check “Programmatic access” under Access type then click next.
  5. On the permissions screen, click on the “Attach existing policies directly” tab, search for “AdministratorAccess” in the list, check it, and click next.
  6. On the review screen you should see your user name, with “Programmatic access”, and “AdministratorAccess”, then create the user.
  7. The confirmation screen shows the user “Access key ID” and “Secret access key”, you’ll need these to provide the Serverless Framework with access. In your CLI, type yarn sls config credentials --provider aws --key YOUR_ACCESS_KEY_ID --secret YOUR_SECRET_ACCESS_KEY, replacing YOUR_ACCESS_KEY_ID and YOUR_SECRET_ACCESS_KEY with the keys on the confirmation screen.

Your credentials are configured now, but while we’re in the AWS console let’s set up Simple Email Service.

  1. Click Console Home in the top left corner to go home.
  2. On the home page, in the AWS search bar, search for “Simple Email Service”.
  3. On the SES Home page, click on “Email Addresses” in the sidebar.
  4. On the Email Addresses listing page, click the “Verify a New Email Address” button.
  5. In the dialog window, type your email address then click “Verify This Email Address”.
  6. You’ll receive an email in moments containing a link to verify the address. Click on the link to complete the process.

Now that our accounts are made, let’s take a peek at the Serverless template files.

Setting Up The Serverless Framework

Running serverless create creates two files: handler.js which contains the Lambda function, and serverless.yml which is the configuration file for the entire Serverless Architecture. Within the configuration file, you can specify as many handlers as you’d like, and each one will map to a new function that can interact with other functions. In this project, we’ll only create a single handler, but in a full Serverless Architecture, you’d have several of the various functions of the service.


The default file structure generated from the Serverless Framework containing handler.js and serverless.yml.


The default file structure generated from the Serverless Framework containing handler.js and serverless.yml.

In handler.js, you’ll see a single exported function named hello. This is currently the main (and only) function. It, along with all Node handlers, take three parameters:

  • event
    This can be thought of as the input data for the function.
  • context object
    This contains the runtime information of the Lambda function.
  • callback
    An optional parameter to return information to the caller.
// handler.js

'use strict';

module.exports.hello = (event, context, callback) => 
  const response = 
    statusCode: 200,
    body: JSON.stringify(
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    ),
  };

  callback(null, response);
};

At the bottom of hello, there’s a callback. It’s an optional argument to return a response, but if it’s not explicitly called, it will implicitly return with null. The callback takes two parameters:

  • Error error
    For providing error information for when the Lambda itself fails. When the Lambda succeeds, null should be passed into this parameter.
  • Object result
    For providing a response object. It must be JSON.stringify compatible. If there’s a parameter in the error field, this field is ignored.

Our static site will send our form data in the event body and the callback will return a response for our user to see.

In serverless.yml you’ll see the name of the service, provider information, and the functions.

# serverless.yml

service: static-site-mailer

provider:
  name: aws
  runtime: nodejs6.10

functions:
  hello:
    handler: handler.hello

How the function names in serverless.yml map to handler.js.


How the function names in serverless.yml map to handler.js.

Notice the mapping between the hello function and the handler? We can name our file and function anything and as long as it maps to the configuration it will work. Let’s rename our function to staticSiteMailer.

# serverless.yml

functions:
  staticSiteMailer:
    handler: handler.staticSiteMailer
// handler.js

module.exports.staticSiteMailer = (event, context, callback) => 
  ...
;

Lambda functions need permission to interact with other AWS infrastructure. Before we can send an email, we need to allow SES to do so. In serverless.yml, under provider.iamRoleStatements add the permission.

# serverless.yml

provider:
  name: aws
  runtime: nodejs6.10
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "ses:SendEmail"
      Resource: ["*"]

Since we need a URL for our form action, we need to add HTTP events to our function. In serverless.yml we create a path, specify the method as post, and set CORS to true for security.

functions:
  staticSiteMailer:
    handler: handler.staticSiteMailer
    events:
      - http:
          method: post
          path: static-site-mailer
          cors: true

Our updated serverless.yml and handler.js files should look like:

# serverless.yml

service: static-site-mailer

provider:
  name: aws
  runtime: nodejs6.10

functions:
  staticSiteMailer:
    handler: handler.staticSiteMailer
    events:
      - http:
          method: post
          path: static-site-mailer
          cors: true

provider:
  name: aws
  runtime: nodejs6.10
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "ses:SendEmail"
      Resource: ["*"]
// handler.js

'use strict';

module.exports.staticSiteMailer = (event, context, callback) => 
  const response = 
    statusCode: 200,
    body: JSON.stringify(
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    ),
  };

  callback(null, response);
};

Our Serverless Architecture is setup, so let’s deploy it and test it. You’ll get a simple JSON response.

yarn sls deploy --verbose
yarn sls invoke --function staticSiteMailer


    "statusCode": 200,
    "body": ""message":"Go Serverless v1.0! Your function executed successfully!","input":}"
}

The return response from invoking our brand new serverless function.


The return response from invoking our brand new serverless function.

Creating The HTML Form

Our Lambda function input and form output need to match, so before we build the function we’ll build the form and capture its output. We keep it simple with name, email, and message fields. We’ll add the form action once we’ve deployed our serverless architecture and got our URL, but we know it will be a POST request so we can add that in. At the end of the form, we add a paragraph tag for displaying response messages to the user which we’ll update on the submission callback.

<form action=" SERVICE URL }" method="POST">
  <label>
    Name
    <input type="text" name="name" required>
  </label>
  <label>
    Email
    <input type="email" name="reply_to" required>
  </label>
  <label>
    Message:
    <textarea name="message" required></textarea>
  </label>
  <button type="submit">Send Message</button>
</form>
<p id="js-form-response"></p>

To capture the output we add a submit handler to the form, turn our form parameters into an object, and send stringified JSON to our Lambda function. In the Lambda function we use JSON.parse() to read our data. Alternatively, you could use jQuery’s Serialize or query-string to send and parse the form parameters as a query string but JSON.stringify() and JSON.parse() are native.

(() => 
  const form = document.querySelector('form');
  const formResponse = document.querySelector('js-form-response');

  form.onsubmit = e => 
    e.preventDefault();

    // Prepare data to send
    const data = ;
    const formElements = Array.from(form);
    formElements.map(input => (data[input.name] = input.value));

    // Log what our lambda function will receive
    console.log(JSON.stringify(data));
  };
})();

Go ahead and submit your form then capture the console output. We’ll use it in our Lambda function next.


Capturing the form data in a console log.


Capturing the form data in a console log.

Invoking Lambda Functions

Especially during development, we need to test our function does what we expect. The Serverless Framework provides the invoke and invoke local command to trigger your function from live and development environments respectively. Both commands require the function name passed through, in our case staticSiteMailer.

yarn sls invoke local --function staticSiteMailer

To pass mock data into our function, create a new file named data.json with the captured console output under a body key within a JSON object. It should look something like:

// data.json


  "body": ""name": "Sender Name","reply_to": "sender@email.com","message": "Sender message""
}

To invoke the function with the local data, pass the --path argument along with the path to the file.

yarn sls invoke local --function staticSiteMailer --path data.json

An updated return response from our serverless function when we pass it JSON data.


An updated return response from our serverless function when we pass it JSON data.

You’ll see a similar response to before, but the input key will contain the event we mocked. Let’s use our mock data to send an email using Simple Email Service!

Sending An Email With Simple Email Service

We’re going to replace the staticSiteMailer function with a call to a private sendEmail function. For now you can comment out or remove the template code and replace it with:

// hander.js

function sendEmail(formData, callback) 
  // Build the SES parameters
  // Send the email


module.exports.staticSiteMailer = (event, context, callback) => 
  const formData = JSON.parse(event.body);

  sendEmail(formData, function(err, data) 
    if (err) 
      console.log(err, err.stack);
     else 
      console.log(data);
    
  });
};

First, we parse the event.body to capture the form data, then we pass it to a private sendEmail function. sendEmail is responsible for sending the email, and the callback function will return a failure or success response with err or data. In our case, we can simply log the error or data since we’ll be replacing this with the Lambda callback in a moment.

Amazon provides a convenient SDK, aws-sdk, for connecting their services with Lambda functions. Many of their services, including SES, are part of it. We add it to the project with yarn add aws-sdk and import it into the top the handler file.

// handler.js

const AWS = require('aws-sdk');
const SES = new AWS.SES();

In our private sendEmail function, we build the SES.sendEmail parameters from the parsed form data and use the callback to return a response to the caller. The parameters require the following as an object:

  • Source
    The email address SES is sending from.
  • ReplyToAddresses
    An array of email addresses added to the reply to the field in the email.
  • Destination
    An object that must contain at least one ToAddresses, CcAddresses, or BccAddresses. Each field takes an array of email addresses that correspond to the to, cc, and bcc fields respectively.
  • Message
    An object which contains the Body and Subject.

Since formData is an object we can call our form fields directly like formData.message, build our parameters, and send it. We pass your SES-verified email to Source and Destination.ToAddresses. As long as the email is verified you can pass anything here, including different email addresses. We pluck our reply_to, message, and name off our formData object to fill in the ReplyToAddresses and Message.Body.Text.Data fields.

// handler.js
function sendEmail(formData, callback) 
  const emailParams = 
    Source: 'your_email@example.com', // SES SENDING EMAIL
    ReplyToAddresses: [formData.reply_to],
    Destination: 
      ToAddresses: ['your_email@example.com'], // SES RECEIVING EMAIL
    ,
    Message: 
      Body: 
        Text: 
          Charset: 'UTF-8',
          Data: `$formData.messagennName: $formData.namenEmail: $formData.reply_to`,
        },
      },
      Subject: 
        Charset: 'UTF-8',
        Data: 'New message from your_site.com',
      ,
    },
  };

  SES.sendEmail(emailParams, callback);
}

SES.sendEmail will send the email and our callback will return a response. Invoking the local function will send an email to your verified address.

yarn sls invoke local --function testMailer --path data.json

The return response from SES.sendEmail when it succeeds.


The return response from SES.sendEmail when it succeeds.

Returning A Response From The Handler

Our function sends an email using the command line, but that’s not how our users will interact with it. We need to return a response to our AJAX form submission. If it fails, we should return an appropriate statusCode as well as the err.message. When it succeeds, the 200 statusCode is sufficient, but we’ll return the mailer response in the body as well. In staticSiteMailer we build our response data and replace our sendEmail callback function with the Lambda callback.

// handler.js

module.exports.staticSiteMailer = (event, context, callback) => 
  const formData = JSON.parse(event.body);

  sendEmail(formData, function(err, data) 
    const response = 
      statusCode: err ? 500 : 200,
      headers: 
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': 'https://your-domain.com',
      ,
      body: JSON.stringify(
        message: err ? err.message : data,
      ),
    };

    callback(null, response);
  });
};

Our Lambda callback now returns both success and failure messages from SES.sendEmail. We build the response with checks if err is present so our response is consistent. The Lambda callback function itself passes null in the error argument field and the response as the second. We want to pass errors onwards, but if the Lambda itself fails, its callback will be implicitly called with the error response.

In the headers, you’ll need to replace Access-Control-Allow-Origin with your own domain. This will prevent any other domains from using your service and potentially racking up an AWS bill in your name! And I don’t cover it in this article, but it’s possible to set-up Lambda to use your own domain. You’ll need to have an SSL/TLS certificate uploaded to Amazon. The Serverless Framework team wrote a fantastic tutorial on how to do so.

Invoking the local function will now send an email and return the appropriate response.

yarn sls invoke local --function testMailer --path data.json

The return response from our serverless function, containing the SES.sendEmail return response in the body.


The return response from our serverless function, containing the SES.sendEmail return response in the body.

Calling The Lambda Function From The Form

Our service is complete! To deploy it run yarn sls deploy -v. Once it’s deployed you’ll get a URL that looks something like https://r4nd0mh45h.execute-api.us-east-1.amazonaws.com/dev/static-site-mailer which you can add to the form action. Next, we create the AJAX request and return the response to the user.

(() => 
  const form = document.querySelector('form');
  const formResponse = document.querySelector('js-form-response');

  form.onsubmit = e => 
    e.preventDefault();

    // Prepare data to send
    const data = ;
    const formElements = Array.from(form);
    formElements.map(input => (data[input.name] = input.value));

    // Log what our lambda function will receive
    console.log(JSON.stringify(data));

    // Construct an HTTP request
    var xhr = new XMLHttpRequest();
    xhr.open(form.method, form.action, true);
    xhr.setRequestHeader('Accept', 'application/json; charset=utf-8');
    xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');

    // Send the collected data as JSON
    xhr.send(JSON.stringify(data));

    // Callback function
    xhr.onloadend = response => 
      if (response.target.status === 200) 
        // The form submission was successful
        form.reset();
        formResponse.innerHTML = 'Thanks for the message. I’ll be in touch shortly.';
       else 
        // The form submission failed
        formResponse.innerHTML = 'Something went wrong';
        console.error(JSON.parse(response.target.response).message);
      
    };
  };
})();

In the AJAX callback, we check the status code with response.target.status. If it’s anything other than 200 we can show an error message to the user, otherwise let them know the message was sent. Since our Lambda returns stringified JSON we can parse the body message with JSON.parse(response.target.response).message. It’s especially useful to log the error.

You should be able to submit your form entirely from your static site!

The static site form, sending the message to the Lambda endpoint and returning a response to the user.
The static site form, sending the message to the Lambda endpoint and returning a response to the user.

Next Steps

Adding a contact form to your static is easy with the Serverless Framework and AWS. There’s room for improvement in our code, like adding form validation with a honeypot, preventing AJAX calls for invalid forms and improving the UX if the response, but this is enough to get started. You can see some of these improvements within the static site mailer repo I’ve created. I hope I’ve inspired you to try out Serverless yourself!

Smashing Editorial
(lf, ra, il)


See original article here:

Building A Serverless Contact Form For Your Static Site

Thumbnail

Working Together: How Designers And Developers Can Communicate To Create Better Projects




Working Together: How Designers And Developers Can Communicate To Create Better Projects

Rachel Andrew



Among the most popular suggestions on Smashing Magazine’s Content User Suggestions board is the need of learning more about the interaction and communication between designers and developers. There are probably several articles worth of very specific things that could be covered here, but I thought I would kick things off with a general post rounding up some experiences on the subject.

Given the wide range of skills held by the line-up at our upcoming SmashingConf Toronto — a fully live, no-slides-allowed event, I decided to solicit some feedback. I’ve wrapped those up with my own experience of 20 years working alongside designers and other developers. I hope you will add your own experiences in the comments.

Some tips work best when you can be in the same room as your team, and others are helpful for the remote worker or freelancer. What shines through all of the advice, however, is the need to respect each other, and the fact that everyone is working to try and create the best outcome for the project.

Working Remotely And Staying Connected

The nomadic lifestyle is not right for everyone, but the only way to know for sure is to try. If you can afford to take the risk, go for it. Javier Cuello shares his experience and insights from his four years of travel and work. Read article →

For many years, my own web development company operated as an outsourced web development provider for design agencies. This involved doing everything from front-end development to implementing e-commerce and custom content management solutions. Our direct client was the designer or design agency who had brought us on board to help with the development aspect of the work, however, in an ideal situation, we would be part of the team working to deliver a great end result to the end client.

Sometimes this relationship worked well. We would feel a valued part of the team, our ideas and experience would count, we would work with the designers to come up with the best solution within budgetary, time, and other constraints.

In many cases, however, no attempt was made to form a team. The design agency would throw a picture of a website as a PDF file over the fence to us, then move on to work on their next project. There was little room for collaboration, and often the designer who had created the files was busy on some other work when we came back with questions.

It was an unsatisfactory way to work for everyone. We would be frustrated because we did not have a chance to help ensure that what was designed was possible to be built in a performant and accessible way, within the time and budget agreed on. The designer of the project would be frustrated: Why were these developers asking so many questions? Can they not just build the website as I have designed? Why are the fonts not the size I wanted?

The Waterfall versus Agile argument might be raised here. The situation where a PDF is thrown over the fence is often cited as an example of how bad a Waterfall approach is. Still, working in a fully Agile way is often not possible for teams made of freelancers or separate parties doing different parts of the work. Therefore, in reading these suggestions, look at them through the lens of the projects you work on. However, try not to completely discount something as unworkable because you can’t use the full process. There are often things we can take without needing to fully adopt one methodology or another.

Setting Up A Project For Success

I came to realize that very often the success of failure of the collaboration started before we even won the project, with the way in which we proposed the working relationship. We had to explain upfront that experience had taught us that the approach of us being handed a PDF, quoting and returning a website did not give the best results.

Projects that were successful had a far more iterative approach. It might not be possible to have us work alongside the designers or in a more Agile way. However, having a number of rounds of design and development with time for feedback from each side went a long way to prevent the frustrations of a method where work was completed by each side independently.

Creating Working Relationships

Having longer-term relationships with an agency, spanning a number of projects worked well. We got to know the designers, learned how they worked, could anticipate their questions and ensure that we answered them upfront. We were able to share development knowledge, the things that made a design easier or harder to implement which would, therefore, have an impact on time and budget. They were able to communicate better with us in order to explain why a certain design element was vital, even if it was going to add complexity.

For many freelance designers and developers, and also for those people who work for a distributed company, communication can become mostly text-based. This can make it particularly hard to build relationships. There might be a lot of communication — by email, in Slack, or through messages on a project management platform such as Basecamp. However, all of these methods leave us without the visual cues we might pick up from in-person meetings. An email we see as to the point may come across to the reader as if we are angry. The quick-fire nature of tools such as Slack might leave us committing in writing something which we would not say to that person while looking into their eyes!

Freelance data scientist Nadieh Bremer will talk to us about visualizing data in Toronto. She has learned that meeting people face to face — or at least having a video call — is important. She told me:

Nadieh Bremer

“As a remote freelancer, I know that to interact well with my clients I really need to have a video call (stress on the video) I need to see their face and facial/body interactions and they need to see mine. For clients that I have within public transport distance, I used to travel there for a first ‘getting to know each other/see if we can do a project’ meeting, which would take loads of time. But I noticed for my clients abroad (that I can’t visit anyway) that a first client call (again, make sure it’s a video-call) works more than good enough.

It’s the perfect way to weed out the clients that need other skills that I can give, those that are looking for a cheap deal, and those where I just felt something wasn’t quite clicking or I’m not enthusiastic about the project after they’ve given me a better explanation. So these days I also ask my clients in the Netherlands, where I live, that might want to do a first meeting to have it online (and once we get on to an actual contract I can come by if it’s beneficial).”

Working In The Open

Working in the open (with the project frequently deployed to a staging server that everyone had access to see), helped to support an iterative approach to development. I found that it was important to support that live version with explanations and notes of what to look at and test and what was still half finished. If I just invited people to look at it without that information we would get lists of fixes to make to unfinished features, which is a waste of time for the person doing the reporting. However, a live staging version, plus notes in a collaboration tool such as Basecamp meant that we could deploy sections and post asking for feedback on specific things. This helped to keep everyone up to date and part of the project even if — as was often the case for designers in an agency — they had a number of other projects to work on.

There are collaboration tools to help designers to share their work too. Asking for recommendations on Twitter gave me suggestions for Zeplin, Invision, Figma, and Adobe XD. Showing work in progress to a developer can help them to catch things that might be tricky before they are signed off by the client. By sharing the goal behind a particular design feature within the team, a way forward can be devised that meets the goal without blowing the budget.


Screenshot of the Zeplin homepage


Zeplin is a collaboration tool for developers and designers

Scope Creep And Change Requests

The thing about working in the open is that people then start to have ideas (which should be a positive thing), however, most timescales and budgets are not infinite! This means you need to learn to deal with scope creep and change requests in a way that maintains a good working relationship.

We would often get requests for things that were trivial to implement with a message saying how sorry they were about this huge change and requests for incredibly time-consuming things with an assumption it would be quick. Someone who is not a specialist has no idea how long anything will take. Why should they? It is important to remember this rather than getting frustrated about the big changes that are being asked for. Have a conversation about the change, explain why it is more complex than it might appear, and try to work out whether this is a vital addition or change, or just a nice idea that someone has had.

If the change is not essential, then it may be enough to log it somewhere as a phase two request, demonstrating that it has been heard and won’t be forgotten. If the big change is still being requested, we would outline the time it would take and give options. This might mean dropping some other feature if a project has a fixed budget and tight deadline. If there was flexibility then we could outline the implications on both costs and end date.

With regard to costs and timescales, we learned early on to pad our project quotes in order that we could absorb some small changes without needing to increase costs or delay completion. This helped with the relationship between the agency and ourselves as they didn’t feel as if they were being constantly nickel and dimed. Small changes were expected as part of the process of development. I also never wrote these up in a quote as contingency, as a client would read that and think they should be able to get the project done without dipping into the contingency. I just added the time to the quote for the overall project. If the project ran smoothly and we didn’t need that time and money, then the client got a smaller bill. No one is ever unhappy about being invoiced for less than they expected!

This approach can work even for people working in-house. Adding some time to your estimates means that you can absorb small changes without needing to extend the timescales. It helps working relationships if you are someone who is able to say yes as often as possible.

This does require that you become adept at estimating timescales. This is a skill you can develop by logging your time to achieve your work, even if you don’t need to log your time for work purposes. While many of the things you design or develop will be unique, and seem impossible to estimate, by consistently logging your time you will generally find that your ballpark estimates become more accurate as you make yourself aware of how long things really take.

Respect

Aaron Draplin will be bringing tales from his career in design to Toronto, and responded with the thought that it comes down to respect for your colleague’s craft:

Aaron Draplin

“It all comes down to respect for your colleague’s craft, and sort of knowing your place and precisely where you fit into the project. When working with a developer, I surrender to them in a creative way, and then, defuse whatever power play they might try to make on me by leading the charges with constructive design advice, lightning-fast email replies and generally keeping the spirit upbeat. It’s an odd offense to play. I’m not down with the adversarial stuff. I’m quick to remind them we are all in the same boat, and, who’s paying their paycheck. And that’s not me. It’s the client. I’ll forever be on their team, you know? We make the stuff for the client. Not just me. Not ‘my team’. We do it together. This simple methodology has always gone a long way for me.”

I love this, it underpins everything that this article discusses. Think back to any working relationship that has gone bad, how many of those involved you feeling as if the other person just didn’t understand your point of view or the things you believe are important? Most reasonable people understand that compromise has to be made, it is when it appears that your point of view is not considered that frustration sets in.

There are sometimes situations where a decision is being made, and your experience tells you it is going to result in a bad outcome for the project, yet you are overruled. On a few occasions, decisions were made that I believed so poor; I asked for the decision and our objection to it be put in writing, in order that we could not be held accountable for any bad outcome in future. This is not something you should feel the need to do often, however, it is quite powerful and sometimes results in the decision being reversed. An example would be of a client who keeps insisting on doing something that would cause an accessibility problem for a section of their potential audience. If explaining the issue does not help, and the client insists on continuing, ask for that decision in writing in order to document your professional advice.

Learning The Language

I recently had the chance to bring my CSS Layout Workshop not to my usual groups of front-end developers but instead to a group of UX designers. Many of the attendees were there not to improve their front-end development skills, but more to understand enough of how modern CSS Layout worked that they could have better conversations with the developers who built their designs. Many of them had also spent years being told that certain things were not possible on the web, but were realizing that the possibilities in CSS were changing through things like CSS Grid. They were learning some CSS not necessarily to become proficient in shipping it to production, but so they could share a common language with developers.

There are often debates on whether “designers should learn to code.” In reality, I think we all need to learn something of the language, skills, and priorities of the other people on our teams. As Aaron reminded us, we are all on the same team, we are making stuff together. Designers should learn something about code just as developers should also learn something of design. This gives us more of a shared language and understanding.

Seb Lee-Delisle, who will speak on the subject of Hack to the Future in Toronto, agrees:

Seb Lee-Delisle

“I have basically made a career out of being both technical and creative so I strongly feel that the more crossover the better. Obviously what I do now is wonderfully free of the constraints of client work but even so, I do think that if you can blur those edges, it’s gonna be good for you. It’s why I speak at design conferences and encourage designers to play with creative coding, and I speak at tech conferences to persuade coders to improve their visual acuity. Also with creative coding. :) It’s good because not only do I get to work across both disciplines, but also I get to annoy both designers and coders in equal measure.”

I have found that introducing designers to browser DevTools (in particular the layout tools in Firefox and also to various code generators on the web) has been helpful. By being able to test ideas out without writing code, helps a designer who isn’t confident in writing code to have better conversations with their developer colleagues. Playing with tools such as gradient generators, clip-path or animation tools can also help designers see what is possible on the web today.


Screenshot of Animista


Animista has demos of different styles of animation

We are also seeing a number of tools that can help people create websites in a more visual way. Developers can sometimes turn their noses up about the code output of such tools, and it’s true they probably won’t be the best choice for the production code of a large project. However, they can be an excellent way for everyone to prototype ideas, without needing to write code. Those prototypes can then be turned into robust, permanent and scalable versions for production.

An important tip for developers is to refrain from commenting on the code quality of prototypes from members of the team who do not ship production code! Stick to what the prototype is showing as opposed to how it has been built.

A Practical Suggestion To Make Things Visual

Eva-Lotta Lamm will be speaking in Toronto about Sketching and perhaps unsurprisingly passed on practical tips for helping conversation by visualizing the problem to support a conversation.

Eva-Lotta Lamm

Creating a shared picture of a problem or a solution is a simple but powerful tool to create understanding and make sure they everybody is talking about the same thing.

Visualizing a problem can reach from quick sketches on a whiteboard to more complex diagrams, like customer journey diagrams or service blueprints.

But even just spatially distributing words on a surface adds a valuable layer of meaning. Something as simple as arranging post-its on a whiteboard in different ways can help us to see relationships, notice patterns, find gaps and spot outliers or anomalies. If we add simple structural elements (like arrows, connectors, frames, and dividers) and some sketches into the mix, the relationships become even more obvious.

Visualising a problem creates context and builds a structural frame that future information, questions, and ideas can be added to in a ‘systematic’ way.

Visuals are great to support a conversation, especially when the conversation is ‘messy’ and several people involved.

When we visualize a conversation, we create an external memory of the content, that is visible to everybody and that can easily be referred back to. We don’t have to hold everything in our mind. This frees up space in everybody’s mind to think and talk about other things without the fear of forgetting something important. Visuals also give us something concrete to hold on to and to follow along while listening to complex or abstract information.

When we have a visual map, we can point to particular pieces of content — a simple but powerful way to make sure everybody is talking about the same thing. And when referring back to something discussed earlier, the map automatically reminds us of the context and the connections to surrounding topics.

When we sketch out a problem, a solution or an idea the way we see it (literally) changes. Every time we express a thought in a different medium, we are forced to shape it in a specific way, which allows us to observe and analyze it from different angles.

Visualising forces us to make decisions about a problem that words alone don’t. We have to decide where to place each element, decide on its shape, size, its boldness, and color. We have to decide what we sketch and what we write. All these decisions require a deeper understanding of the problem and make important questions surface fairly quickly.

All in all, supporting your collaboration by making it more visual works like a catalyst for faster and better understanding.

Working in this way is obviously easier if your team is working in the same room. For distributed teams and freelancers, there are alternatives to communicate in ways other than words, e.g. by making a quick Screencast to demonstrate an issue, or even sketching and photographing a diagram can be incredibly helpful. There are collaborative tools such as Milanote, Mural, and Niice; such tools can help with the process Eva-Lotta described even if people can’t be in the same room.


Screenshot of the Niice website


Niice helps you to collect and discuss ideas

I’m very non-visual and have had to learn how useful these other methods of communication are to the people I work with. I have been guilty on many occasions of forgetting that just because I don’t personally find something useful, it is still helpful to other people. It is certainly a good idea to change how you are trying to communicate an idea if it becomes obvious that you are talking at cross-purposes.

Over To You

As with most things, there are many ways to work together. Even for remote teams, there is a range of tools which can help break down barriers to collaborating in a more visual way. However, no tool is able to fix problems caused by a lack of respect for the work of the rest of the team. A good relationship starts with the ability for all of us to take a step back from our strongly held opinions, listen to our colleagues, and learn to compromise. We can then choose tools and workflows which help to support that understanding that we are all on the same team, all trying to do a great job, and all have important viewpoints and experience to bring to the project.

I would love to hear your own experiences working together in the same room or remotely. What has worked well — or not worked at all! Tools, techniques, and lessons learned are all welcome in the comments. If you would be keen to see tutorials about specific tools or workflows mentioned here, perhaps add a suggestion to our User Suggestions board, too.

Smashing Editorial
(il)


Follow this link: 

Working Together: How Designers And Developers Can Communicate To Create Better Projects

Smart Responsive UX Design Patterns

Full-day workshop • April 16th
In this brand new workshop, Vitaly Friedman will cover practical techniques, clever tricks and useful strategies you need to be aware of when working on responsive websites. From responsive modules to clever navigation patterns and web form design techniques; the workshop will provide you with everything you need to know today to start designing better responsive experiences tomorrow.
Most techniques are borrowed from mid-size and large-scale real-life projects, such as large eCommerce projects, online magazines and web applications.

See the article here:

Smart Responsive UX Design Patterns

Automating Your Feature Testing With Selenium WebDriver




Automating Your Feature Testing With Selenium WebDriver

Nils Schütte



This article is for web developers who wish to spend less time testing the front end of their web applications but still want to be confident that every feature works fine. It will save you time by automating repetitive online tasks with Selenium WebDriver. You will find a step-by-step example for automating and testing the login function of WordPress, but you can also adapt the example for any other login form.

What Is Selenium And How Can It Help You?

Selenium is a framework for the automated testing of web applications. Using Selenium, you can basically automate every task in your browser as if a real person were to execute the task. The interface used to send commands to the different browsers is called Selenium WebDriver. Implementations of this interface are available for every major browser, including Mozilla Firefox, Google Chrome and Internet Explorer.

Automating Your Feature Testing With Selenium WebDriver

Which type of web developer are you? Are you the disciplined type who tests all key features of your web application after each deployment. If so, you are probably annoyed by how much time this repetitive testing consumes. Or are you the type who just doesn’t bother with testing key features and always thinks, “I should test more, but I’d rather develop new stuff.” If so, you probably only find bugs by chance or when your client or boss complains about them.

I have been working for a well-known online retailer in Germany for quite a while, and I always belonged to the second category: It was so exciting to think of new features for the online shop, and I didn’t like at all going over all of the previous features again after each new software deployment. So, the strategy was more or less to hope that all key features would work.

One day, we had a serious drop in our conversion rate and started digging in our web analytics tools to find the source of this drop. It took quite a while before we found out that our checkout did not work properly since the previous software deployment.

This was the day when I started to do some research about automating our testing process of web applications, and I stumbled upon Selenium and its WebDriver. Selenium is basically a framework that allows you to automate web browsers. WebDriver is the name of the key interface that allows you to send commands to all major browsers (mobile and desktop) and work with them as a real user would.

Preparing The First Test With Selenium WebDriver

First, I was a little skeptical of whether Selenium would suit my needs because the framework is most commonly used in Java, and I am certainly not a Java expert. Later, I learned that being a Java expert is not necessary to take advantage of the power of the Selenium framework.

As a simple first test, I tested the login of one of my WordPress projects. Why WordPress? Just because using the WordPress login form is an example that everybody can follow more easily than if I were to refer to some custom web application.

What do you need to start using Selenium WebDriver? Because I decided to use the most common implementation of Selenium in Java, I needed to set up my little Java environment.

If you want to follow my example, you can use the Java environment of your choice. If you haven’t set one up yet, I suggest installing Eclipse and making sure you are able to run a simple “Hello world” script in Java.

Because I wanted to test the login in Chrome, I made sure that the Chrome browser was already installed on my machine. That’s all I did in preparation.

Downloading The ChromeDriver

All major browsers provide their own implementation of the WebDriver interface. Because I wanted to test the WordPress login in Chrome, I needed to get the WebDriver implementation of Chrome: ChromeDriver.

I extracted the ZIP archive and stored the executable file chromedriver.exe in a location that I could remember for later.

Setting Up Our Selenium Project In Eclipse

The steps I took in Eclipse are probably pretty basic to someone who works a lot with Java and Eclipse. But for those like me, who are not so familiar with this, I will go over the individual steps:

  1. Open Eclipse.
  2. Click the “New” icon.
    Creating a new project in Eclipse
    Creating a new project in Eclipse
  3. Choose the wizard to create a new “Java Project,” and click “Next.”
    Chosing the java-project wizard
    Choose the java-project wizard.
  4. Give your project a name, and click “Finish.”
    Eclipse project wizard
    The eclipse project wizard
  5. Now you should see your new Java project on the left side of the screen.
    Java project successfully created
    We successfully created a project to run the Selenium WebDriver.

Adding The Selenium Library To Our Project

Now we have our Java project, but Selenium is still missing. So, next, we need to bring the Selenium framework into our Java project. Here are the steps I took:

  1. Download the latest version of the Java Selenium library.

    Downloading the Selenium library
    Download the Selenium library.
  2. Extract the archive, and store the folder in a place you can remember easily.
  3. Go back to Eclipse, and go to “Project” → “Properties.”
    Eclipse Properties
    Go to properties to integrate the Selenium WebDriver in you project.
  4. In the dialog, go to “Java Build Path” and then to register “Libraries.”
  5. Click on “Add External JARs.”
    Adding the Selenium lib to your Java build path.
    Add the Selenium lib to your Java build path.
  6. Navigate to the just downloaded folder with the Selenium library. Highlight all .jar files and click “Open.”
    Selecting the correct files of the Selenium lib.
    Select all files of the lib to add to your project.
  7. Repeat this for all .jar files in the subfolder libs as well.
  8. Eventually, you should see all .jar files in the libraries of your project:
    Selenium WebDriver framework successfully integrated into your project
    The Selenium WebDriver framework has now been successfully integrated into your project!

That’s it! Everything we’ve done until now is a one-time task. You could use this project now for all of your different tests, and you wouldn’t need to do the whole setup process for every test case again. Kind of neat, isn’t it?

Creating Our Testing Class And Letting It Open the Chrome Browser

Now we have our Selenium project, but what next? To see whether it works at all, I wanted to try something really simple, like just opening my Chrome browser.

To do this, I needed to create a new Java class from which I could execute my first test case. Into this executable class, I copied a few Java code lines, and believe it or not, it worked! Magically, the Chrome browser opened and, after a few seconds, closed all by itself.

Try it yourself:

  1. Click on the “New” button again (while you are in your new project’s folder).
    New class in eclipse
    Create a new class to run the Selenium WebDriver.
  2. Choose the “Class” wizard, and click “Next.”
    New class wizard in eclipse
    Choose the Java class wizard to create a new class.
  3. Name your class (for example, “RunTest”), and click “Finish.”
    Eclipse Java Class wizard
    The eclipse Java Class wizard.
  4. Replace all code in your new class with the following code. The only thing you need to change is the path to chromedriver.exe on your computer:
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    
    /**
     * @author Nils Schuette via frontendtest.org
     */
    public class RunTest 
        static WebDriver webDriver;
        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(final String[] args) throws InterruptedException 
            // Telling the system where to find the chrome driver
            System.setProperty(
                    "webdriver.chrome.driver",
                    "C:/PATH/TO/chromedriver.exe");
    
            // Open the Chrome browser
            webDriver = new ChromeDriver();
    
            // Waiting a bit before closing
            Thread.sleep(7000);
    
            // Closing the browser and WebDriver
            webDriver.close();
            webDriver.quit();
        
    }
    
  5. Save your file, and click on the play button to run your code.
    Run Eclipse project
    Running your first Selenium WebDriver project.
  6. If you have done everything correctly, the code should open a new instance of the Chrome browser and close it shortly thereafter.
    Chrome Browser blank window
    The Chrome Browser opens itself magically. (Large preview)

Testing The WordPress Admin Login

Now I was optimistic that I could automate my first little feature test. I wanted the browser to navigate to one of my WordPress projects, login to the admin area and verify that the login was successful. So, what commands did I need to look up?

  1. Navigate to the login form,
  2. Locate the input fields,
  3. Type the username and password into the input fields,
  4. Hit the login button,
  5. Compare the current page’s headline to see if the login was successful.

Again, after I had done all the necessary updates to my code and clicked on the run button in Eclipse, my browser started to magically work itself through the WordPress login. I successfully ran my first automated website test!

If you want to try this yourself, replace all of the code of your Java class with the following. I will go through the code in detail afterwards. Before executing the code, you must replace four values with your own:

  1. The location of your chromedriver.exe file (as above),

  2. The URL of the WordPress admin account that you want to test,

  3. The WordPress username,

  4. The WordPress password.

Then, save and let it run again. It will open Chrome, navigate to the login of your WordPress website, login and check whether the h1 headline of the current page is “Dashboard.”

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

/**
 * @author Nils Schuette via frontendtest.org
 */
public class RunTest 
    static WebDriver webDriver;
    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(final String[] args) throws InterruptedException 
        // Telling the system where to find the chrome driver
        System.setProperty(
                "webdriver.chrome.driver",
                "C:/PATH/TO/chromedriver.exe");

        // Open the Chrome browser
        webDriver = new ChromeDriver();

        // Maximize the browser window
        webDriver.manage().window().maximize();

        if (testWordpresslogin()) 
            System.out.println("Test WordPress Login: Passed");
         else 
            System.out.println("Test WordPress Login: Failed");

        

        // Close the browser and WebDriver
        webDriver.close();
        webDriver.quit();
    }

    private static boolean testWordpresslogin() 
        try 
            // Open google.com
            webDriver.navigate().to("https://www.YOUR-SITE.org/wp-admin/");

            // Type in the username
            webDriver.findElement(By.id("user_login")).sendKeys("YOUR_USERNAME");

            // Type in the password
            webDriver.findElement(By.id("user_pass")).sendKeys("YOUR_PASSWORD");

            // Click the Submit button
            webDriver.findElement(By.id("wp-submit")).click();

            // Wait a little bit (7000 milliseconds)
            Thread.sleep(7000);

            // Check whether the h1 equals “Dashboard”
            if (webDriver.findElement(By.tagName("h1")).getText()
                    .equals("Dashboard")) 
                return true;
             else 
                return false;
            

        // If anything goes wrong, return false.
        } catch (final Exception e) 
            System.out.println(e.getClass().toString());
            return false;
        
    }
}

If you have done everything correctly, your output in the Eclipse console should look something like this:

Eclipse console test result.
The Eclipse console states that our first test has passed. (Large preview)

Understanding The Code

Because you are probably a web developer and have at least a basic understanding of other programming languages, I am sure you already grasp the basic idea of the code: We have created a separate method, testWordpressLogin, for the specific test case that is called from our main method.

Depending on whether the method returns true or false, you will get an output in your console telling you whether this specific test passed or failed.

This is not necessary, but this way you can easily add many more test cases to this class and still have readable code.

Now, step by step, here is what happens in our little program:

  1. First, we tell our program where it can find the specific WebDriver for Chrome.
    System.setProperty("webdriver.chrome.driver","C:/PATH/TO/chromedriver.exe");
  2. We open the Chrome browser and maximize the browser window.
    webDriver = new ChromeDriver();
    webDriver.manage().window().maximize();
  3. This is where we jump into our submethod and check whether it returns true or false.
    if (testWordpresslogin()) …
  4. The following part in our submethod might not be intuitive to understand:
    The try…catch… blocks. If everything goes as expected, only the code in try… will be executed, but if anything goes wrong while executing try…, then the execution continuous in catch{}. Whenever you try to locate an element with findElement and the browser is not able to locate this element, it will throw an exception and execute the code in catch…. In my example, the test will be marked as “failed” whenever something goes wrong and the catch{} is executed.
  5. In the submethod, we start by navigating to our WordPress admin area and locating the fields for the username and the password by looking for their IDs. Also, we type the given values in these fields.
    webDriver.navigate().to("https://www.YOUR-SITE.org/wp-admin/");
    webDriver.findElement(By.id("user_login")).sendKeys("YOUR_USERNAME");
    webDriver.findElement(By.id("user_pass")).sendKeys("YOUR_PASSWORD");

    Wordpress login form
    Selenium fills out our login form
  6. After filling in the login form, we locate the submit button by its ID and click it.
    webDriver.findElement(By.id("wp-submit")).click();
  7. In order to follow the test visually, I include a 7-second pause here (7000 milliseconds = 7 seconds).
    Thread.sleep(7000);
  8. If the login is successful, the h1 headline of the current page should now be “Dashboard,” referring to the WordPress admin area. Because the h1 headline should exist only once on every page, I have used the tag name here to locate the element. In most other cases, the tag name is not a good locator because an HTML tag name is rarely unique on a web page. After locating the h1, we extract the text of the element with getText() and check whether it is equal to the string “Dashboard.” If the login is not successful, we would not find “Dashboard” as the current h1. Therefore, I’ve decided to use the h1 to check whether the login is successful.
    if (webDriver.findElement(By.tagName("h1")).getText().equals("Dashboard")) 
        
            return true;
         else 
            return false;
        
    

    Wordpress Dashboard
    Letting the WebDriver check, whether we have arrived on the Dashboard: Test passed! (Large preview)
  9. If anything has gone wrong in the previous part of the submethod, the program would have jumped directly to the following part. The catch block will print the type of exception that happened to the console and afterwards return false to the main method.
    catch (final Exception e) 
                System.out.println(e.getClass().toString());
                return false;
            

Adapting The Test Case

This is where it gets interesting if you want to adapt and add test cases of your own. You can see that we always call methods of the webDriver object to do something with the Chrome browser.

First, we maximize the window:

webDriver.manage().window().maximize();

Then, in a separate method, we navigate to our WordPress admin area:

webDriver.navigate().to("https://www.YOUR-SITE.org/wp-admin/");

There are other methods of the webDriver object we can use. Besides the two above, you will probably use this one a lot:

webDriver.findElement(By. …)

The findElement method helps us find different elements in the DOM. There are different options to find elements:

  • By.id
  • By.cssSelector
  • By.className
  • By.linkText
  • By.name
  • By.xpath

If possible, I recommend using By.id because the ID of an element should always be unique (unlike, for example, the className), and it is usually not affected if the structure of your DOM changes (unlike, say, the xPath).

Note: You can read more about the different options for locating elements with WebDriver over here.

As soon as you get ahold of an element using the findElement method, you can call the different available methods of the element. The most common ones are sendKeys, click and getText.

We’re using sendKeys to fill in the login form:

webDriver.findElement(By.id("user_login")).sendKeys("YOUR_USERNAME");

We have used click to submit the login form by clicking on the submit button:

webDriver.findElement(By.id("wp-submit")).click();

And getText has been used to check what text is in the h1 after the submit button is clicked:

webDriver.findElement(By.tagName("h1")).getText()

Note: Be sure to check out all the available methods that you can use with an element.

Conclusion

Ever since I discovered the power of Selenium WebDriver, my life as a web developer has changed. I simply love it. The deeper I dive into the framework, the more possibilities I discover — running one test simultaneously in Chrome, Internet Explorer and Firefox or even on my smartphone, or taking screenshots automatically of different pages and comparing them. Today, I use Selenium WebDriver not only for testing purposes, but also to automate repetitive tasks on the web. Whenever I see an opportunity to automate my work on the web, I simply copy my initial WebDriver project and adapt it to the next task.

If you think that Selenium WebDriver is for you, I recommend looking at Selenium’s documentation to find out about all of the possibilities of Selenium (such as running tasks simultaneously on several (mobile) devices with Selenium Grid).

I look forward to hearing whether you find WebDriver as useful as I do!

Smashing Editorial
(rb, ra, al, il)


Original link: 

Automating Your Feature Testing With Selenium WebDriver

Finding UX Research Participants




Finding UX Research Participants

For UX designers and design teams, research with stakeholders and users is critical. However, accessing research participants isn’t as easy as it sounds. For both professional and amateur researchers finding people to participate in studies can be an elusive task. We often hear about studies and their findings, but we don’t hear as often how researchers recruit study participants.

Researchers can choose from a variety ways to find participants. Many factors determine the best method to use. This includes resources such as time and money, the research method you’re using, the type or characteristics of participants you want to recruit, and the accessibility of these types of participants. In this post, I’ll remove some of the mystery and provide guidance to those interested in recruiting participants for qualitative UX studies.


Potential research participants are everywhere, if you know what to look for.


Potential research participants are everywhere, if you know what to look for.

Incentives

You can use incentives to increase the likelihood of participation in any of these methods of recruitment. Use of incentives is usually a personal choice. Do you feel incentivized participants provide skewed or biased data? I don’t have any issues with providing incentives. An incentive can be a small token of appreciation ($5 gift card) or something more substantial ($200 or more depending on time needed and type of participant.

I’ve provided guidance for each method based on my experience with incentives.

Identifying And Interviewing Key Internal Stakeholders

You gain insight when you interview key colleagues, clients, and other relevant stakeholders of a project. Particularly at the beginning of a project. This is a great opportunity to understand everyone’s role, what their vision and hopes are for a project or product, and how you might incorporate their experience into the rest of the project. You can increase buy-in and make people feel like part of the process by including stakeholder interviews in any project. I use the term internal stakeholder broadly to describe individuals who have a vested interest in a product or project who are connected to your organization or the product in some way. Many of these internal stakeholders might also be users of the product you are interviewing them about.

When To Use It

You can always look for opportunities to interview stakeholders and colleagues to learn more. This is especially useful at the beginning of a project. You can learn expectations for a product, background information on what led to the current status of the project, and goals and hopes for the future. Checking in with stakeholders throughout a project will keep them aware of how things are progressing and allow you to get their feedback. I’ve found this is helpful for building trust with stakeholders and making them feel included in the process.

How You Might Do It

You can often arrange interviews with key stakeholders yourself if they are internal to your company. You’ll identify who is relevant to your project, including project team members, and invite them to an interview. You can contact them to schedule a time, or look to schedule using your company’s shared calendar platform (e.g., Outlook or G Suite). You should know ahead of time how long you need to schedule and how you will interview the participant (in-person or remote) so you can share this information with them at scheduling.

Identifying and interviewing stakeholders becomes more complicated when you don’t have direct access to scheduling yourself. If your project team is part of a larger organization, you might need to ask colleagues in other departments to help identify and schedule stakeholders. If you are on a project team with outside partners or have external stakeholders, you will often need someone to facilitate identification and scheduling of interviews. I’ll cover some additional challenges for recruiting stakeholders and others through your clients in the identifying participants through a client section.

Positive Aspects

Gain insight into roles, backgrounds, and history of stakeholders’ involvement with a product or issue, potentially quick to schedule, low to no cost outside of time, can be done remote or in-person, talking to customer/user-facing stakeholders might provide some insight into what users think of a product.

Negative Aspects

Difficult to identify everyone you want to participate, might include people at high-levels who are hard to reach, scheduling if not doing it yourself, scaling down if resources are limited, does not replace research with users, many stakeholders are too close to their product to be objective.

Incentives

I typically don’t provide an incentive if internal stakeholders are participating during work hours.

Case Study

I worked on a project with a bank that wanted to design an online onboarding experience for new customers. We needed to understand what the current (non-digital) onboarding experience was. We wanted to document available resources to pull into the onboarding experience. Lastly, we needed to build trust with partners who we were going to rely on to champion the experience we created.

We relied on word of mouth to learn who we needed to speak with. First, we interviewed the people we were closest to and asked them who else they considered necessary for us to speak with. We spoke with people in numerous US states, both remotely and in-person. We were able to speak with 30 people in three weeks (this was not a project we were dedicating full time). Occasionally, we spoke to people who were not relevant to our specific purpose. There were two key reasons we were given names of some folks who weren’t relevant:

  • They were higher up executives with little knowledge of what we were exploring
  • The people referring them didn’t understand/effectively convey what we were trying to accomplish, so they volunteered to participate in something not aligned with their role

We found our most common difficulties were in scheduling and getting people to reply to our initial emails. We were trying to schedule an hour to speak with people who spend most of their days traveling and in meetings. Many of them had personal assistants managing their calendars. Some didn’t have an opening to speak with us for weeks after our initial request. Most people did want to make the time to speak with us. They viewed our project as one with high strategic importance in the long-term health of their company. We also had many people reschedule due to unforeseen conflicts involving client needs arising.

We were able to paint a clearer picture of the bank’s onboarding experience and what resources were available. We were able to understand what (some) of the leadership viewed as the potential future for an onboarding experience with new customers and what their perceptions of shortcomings were for the current onboarding experience. We were able to identify gaps in knowledge that required additional future research and education. We made connections with critical internal advocates who walked away with a better understanding and appreciation of the experience we were creating. We would not have been able to achieve these outcomes through a survey or through other means of recruiting participants. Later, we were able to approach these same stakeholders to have them provide feedback on the designs for the onboarding experience we created.

Identifying Participants Through A Client

Many potential research participants are unavailable to the general public. You will find situations where you don’t have direct access to recruiting relevant participants. This is particularly true if you work for a design consultancy/studio, or as part of a shared services team within a large organization. For example, if your client is a widget manufacturer and their product is a widget warehouse product supply application, you will need to access their staff in order to understand their current pain points and needs. You won’t have an easy time finding relevant participants using the population you have access to. You want to conduct research and usability testing with participants who will become the end user of the application, which again means you’d need to access this population through your client.

When To Use It

In addition to the reasons given in the previous section for recruiting stakeholders, when you have to reach specific populations, need opinions from specific people, and want to make your client-stakeholders feel like part of the process. When you don’t have direct insight or access to critical research participants when you are looking to build relationships beyond the project team you are working with, when you want to include a diverse set of individuals covering relevant areas of the product you’re working on.

How To Do It

Work closely with your client or person you are collaborating with to identify the right people for the project you are on. Your project will dictate the exact specifications of roles you need. This includes Product Owners, VPs, Business Analysts, and Users. I often provide a script or email language for my clients to use for recruiting participants. I explain the purpose of the research, how you were made aware of the participant (e.g., Jane from accounting gave me your information) how long the conversation is expected to take, potential dates of availability, incentive (if any), prep work required (if any).

You should provide your client with a screener clearly stating:

  • How many of each type of participant you want to participate
  • Details you want to know ahead of time (e.g., years using the product, industry)
  • Factors leading to disqualification from the study (e.g., less than one year of experience with the product)

Bonus: Many organizations keep data on their users. Your client might be able to screen their database and provide you research participants. However, when I’ve used this in the past, there are often many permissions required and processes to gain access to customers. This can add a significant amount of time to your project.

I am always clear to my clients that scheduling participants is one of the largest hurdles to a project’s timeline. Working with others’ schedules is complicated. You should make it clear to your clients how to recruit, and the need to start recruiting as soon as possible.

Positive Aspects

You get specific people close to a project or product, you learn about long-term and short-term goals directly from the people you work with, you are able to ask to follow up questions that might inform projects well beyond your current relationship, you learn the history of the product or organization, you can reach relevant people you don’t have direct access to, you gain insight into roles, backgrounds, and history of stakeholders’ and users’ involvement with an issue, you will find talking directly to the users of the product provides context and texture you wouldn’t find from someone without similar knowledge.

Negative Aspects

This can be time-consuming, requires a clear communication of purpose, you might end up talking to people less relevant if your client doesn’t screen effectively, less control over scheduling, lack of control over how information is shared with participants.

Incentives – I typically don’t provide an incentive if they are from the client and participating during work hours. I’d provide an incentive if they have recruited users who are coming in on an off day or outside of work hours. You might also have a larger incentive but only give it to a couple randomly selected participants.

Case Study

I worked for a team looking at redesigning a digital report for a large mortgage lender. Many other banks and loan providers do business under the umbrella of this company. We needed to identify a specific type of user, one who: worked for a bank under the parent company and used the report as part of their daily tasks.

The client wanted us to interview 30 individuals with roles interacting with the report. They identified a handful of these individuals upfront, and then put out a call for participation to identify the remaining individuals. There were numerous layers of communication through relationship managers as well as permissions and disclosures the client needed to handle with each participant.

We were able to complete over 30 remote (over the phone) interviews in the month we were allotted to collect data. Our client arranged and scheduled each interview. Our most common difficulties were similar to those I gave in the previous case study, scheduling and relevancy of participants. We were interviewing people who spend their entire workday running the report and using the data to inform their decisions; busy people with limited flexibility of daytime work hours. We made ourselves available at any time a participant had availability in order to solve this. This created drawbacks in scheduling other meetings unrelated to working on the project.

Some of our participants forwarded the invitation to others they thought should be on the interview as well. We would find this out when more than one person would join the call. We were initially caught off guard when we had a call intended for one person take place with four participants at once. We created a separate multi-participant protocol to account for this occurring on future calls, which it did. I recommend expecting this to happen regardless of who is recruiting your participants. It’s difficult to control what happens, once you send out an invitation to the wild.

We used data from our interviews to understand the current behaviors, frustrations, and needs of users. We also presented later participants with sample designs in order to get feedback on report layout and feature changes. We delivered a redesigned report that exceeded client expectations and became a reference piece in their quest to get further funding for research and design projects.

Paying A Recruitment Firm (When You Have An Accessible Population)

Recruitment firms offer services ranging from participant screening and recruitment, facilities to conduct research, recording your sessions, and much more. You can use a recruitment firm when you are conducting research with populations you believe you can reach through contact with the general public. For example, if you are conducting usability testing on an online banking application. You can expect most people familiar with banking transactions (e.g., making a deposit or bill pay) should successfully use your application. Even if they don’t currently use your bank.

I’ve used a number of firms over the past few years. Most of them offer similar services.


Recruitment firms often provide facilities for interviews or usability testing.


Recruitment firms often provide facilities for interviews or usability testing.

When To Use It

When you don’t have direct access to potential participants when you want to have a third party screen your participants, when your sample is available through the general public, when you want to have someone handle recruitment, scheduling, and day-of-research preparation.

How To Do It

You will need to create the screener the recruiter will use. You decide in advance how many of each type of participant you will want. You’ll want to include a number of “floaters” in your recruitment as well. Floaters are people who meet the requirements of the study and are willing to show up for participation in case some of the other participants don’t show up. Floaters are typically compensated at higher levels because they are committing to spend two or three hours sitting around in case they are needed.

You’ll also need to provide the screener with enough advance notice as the recruiter requires. I’ve found this is two weeks in advance for most studies, and three weeks in advance for more complex studies. All recruitment firms offer participants an incentive, usually cash, to participate in a study. You will have to be ok with the fact your participants are receiving money to participate. I haven’t found this to be problematic, but you should be prepared to defend why you don’t think this will add any additional bias to your data.

Positive Aspects

Very detailed screening, don’t have to find people, often have a facility you can use, will record audio and video as needed, will recruit additional participants in case some don’t show up.

Negative Aspects

Cost, the time needed in advance if you have a difficult to reach population, participants trying to game the system.

Incentives – Recruitment firms almost always compensate the people they recruit. You will pay the recruitment firm a set fee they pay to participants.

Case Study

I worked for a team wanting to define the digital needs and behaviors of specific types of Financial Advisors. The client did not want to expose their brand during any of the research, so they did not want to facilitate the recruitment. The client wanted the interviews to pull participants from more than one major city in the US. We worked with a recruitment firm to identify and recruit participants, as well as to conduct the interview sessions.

We worked with the client to create a detailed screener with items meant to refine the population to the specific participants we wanted for the study. The recruitment firm asked for three weeks to find 15 participants for the first city in our study. The usual turn around when working with the firm was two weeks with less specialized participants. We were also advised to provide a higher incentive, over double what we typically offered, due to the probability we were asking participants to step away from work and the perceived value of their time.

We were able to interview 15 participants over the course of two days. We found a few of the participants didn’t actually meet the qualifications we’d screened for. They had manipulated their responses to qualify. Our client was unhappy with this. We were able to use the floaters to replace the participants who didn’t truly qualify. We were also able to get a refund on what we’d paid to recruit the unqualified participants.

Ultimately, we reached our goal of interviewing the right number of participants in the right amount of time, and produced a report on needs and behaviors for our client.

We would not have been able to access this population without the use of the recruitment firm. The client was unwilling to expose their brand and therefore unwilling to identify participants from their contact list. We would have spent more time and money than the project allowed if we were left to recruit participants. We don’t have contact lists or the ability to easily identify specialized populations through our own resources. We still experienced frustration with the lack of initial quality participants the recruitment firm provided. In general, we’ve had positive experiences with recruitment firms, but the more specialized the population, the more likely you will find some duds.

Guerilla Recruiting (When You Want To Find People In The Wild)

You can utilize public spaces to recruit potential study participants. Guerilla research is a term for quick and dirty research conducted with people as they go about their daily tasks (in the wild so to speak). The term is meant to reflect a context in which you are pressed for resources. However, you can benefit from using this method of recruiting even when you have resources for other methods. Sometimes collecting data from people when they are in specific settings is the most appropriate method.


You can find plenty of potential users in the wild.


You can find plenty of potential users in the wild.

You should determine a space you want to recruit participants for a logical reason. Let’s say you’re designing a smartphone application meant to help people track their workouts at the gym. You would want to recruit participants from that setting, entering or exiting the gym. If you wanted to test out a new form of electronic payment, you’d want to be present in a setting where transactions take place.

When To Use It

When you have little time or budget, when you have access to relevant populations, when you only want to get quick feedback from a few people, when you can spend 20 minutes or less per participant, when you have a product related to a specific physical space (e.g., an art museum tour application).

How To Do It

Find a location, get permission if needed, create a script. I’ve previously written a detailed article on the specifics of recruiting participants in public.

Positive Aspects

Quick execution, the potential for multiple locations if you have the resources, small or large sample sizes, accessing relevant populations, compatible with multiple research methods.

Negative Aspects

Little ability for screening, approaching people takes practice and skill, potentially inclement weather if outside, a lot of standing around.

Incentives

I’d base the incentive on the amount of time and type of activity. For example, I might give a product discount code for something taking a minute or less. A $5 gift card if you are taking a few minutes of their time.

Case Study

I worked on a project examining the use of technology in library settings. Specifically, we wanted to understand the usability of a system for finding and locating materials within the library. We wanted to work with people who use a library. We needed to test inside of the library because the last part of testing involved physically locating the material.

We sent two researchers to spend multiple days at the library while it was open for patrons. We stood with clipboards at the entrance of the library. We asked patrons if they would spend a few minutes with us participating in our study. We then observed them using the system to search for an item and asked them to locate the material based on where the system told them it should be located.

Our biggest challenge was long periods of time where there were no new patrons coming into the library. We wanted to complete 30 to 40 sessions using three different scenarios. We had budgeted to spend one week onsite to get this many responses. We had to extend our timeline for the following week to reach our goal.

We were able to suggest improvements in the interface, terminology, and an explanation of where materials were located. We would not have had similar findings if we hadn’t been on location at a library and we might not have had as valuable insights if we used people who were not library patrons.

Friends And Family (Low On Time And Budget)

Sometimes, you might have very little opportunity to engage in research. There are many reasons for this, time, budget, or your working for a client who refuses to allow research as part of the project plan. The designers I’ve worked with still want to have some type of feedback to shape their thinking. You can still look to gather some meaningful data from those you have closest access to. Perhaps you are on a project where you are working on a product that is relevant to your coworkers or friends you have easy access to. You might ask a few of them to participate in interviews about the product.

Friends and family are the definition of a convenience sample, and should only be used when no other options exist. This is the most biased and least rigorous way of collecting data. However, you can still benefit from insights into experiences you might otherwise not get. You can use friends and family to participate in interviews or usability testing as a means of accessing informing your design. I strongly recommend conducting additional research, using one of the other methods of finding participants, as your design progresses.

When To Use It

As a last resort, when you have no budget, little time, yet you want to know something about the context or users you are designing for when you have access to relevant people to participate in the study. Background information of your participants.

How To Do It

Reach out to others you and your team know; you can include social media to distribute the call to participate, schedule a time to speak or send an email explaining what you’re asking participants to do (you can also distribute survey links this way)
Positive – you will get some feedback, almost instant, low budget

Negative Aspects

Most limited pool of participants, possibly less reach, you’re are relying on favors, less ability to screen for specific characteristics, introducing a larger bias due to familiarity with participants.

Incentives

I would incentivize based on time and budget. A $25 gift card is much less expensive than what you’d pay for a participant from a recruitment firm, but friends and family might find this amount acceptable for up to an hour of time.

Case Study

I was part of a project team responding to a (paid) request for proposals (RFP) from a major vacation industry company. We had two weeks to turn around our response, including design concepts to show our thinking. Most of our team had no experience in using the services from this specific industry. We needed to find out more information to help inform our response. We didn’t have the resources to undertake our typical research process of finding and interviewing stakeholders or representative end users. Instead, we reached out to friends and family members who stated they’d had experience in this vacation activity within the past three years.

We emailed our staff and asked if anyone had friends or family members with this qualification who’d be willing to engage in brief phone conversations about their experience. We conducted interviews with seven people over the course of the next two days. Our designers were able to use the insights we gained to better understand the types of needs users might have while vacationing. Our concepts attempted to address some of the issues our participants stated existed when they had experienced while vacationing.

Although we didn’t win the long-term work, our team was able to place among the top candidates. We credited the participation of friends and family in our research as part of what helped our design stand out in a positive way. We were later awarded separate work from the team we presented to for the initial RFP.

The table below provides a summary of key characteristics for each participant recruitment method I’ve covered in this article.

Time Cost Ability to pre-screen participants Ability to access participants
Stakeholder Slow Low Easy Easy
Client Recruits Slow Low Difficult Difficult
Recruitment Firm Slow High Easy Varies – harder to reach specific populations
Guerilla Recruiting Fast Free Difficult Easy
Friends & Family Fast Free Moderate Easy depending on topic

Table 1: Characteristics of common research participant recruitment methods

Conclusion

We need to access users and potential users in order to effectively conduct research. I’ve covered a number of common ways you can find research participants. Each has certain strengths and weaknesses. You’ll want to become familiar with each of these and adapt your approach based on your product, budget, and timeline.

Smashing Editorial
(cc, ra, il)


Source:

Finding UX Research Participants

Why Web Application Maintenance Should Be More Of A Thing

Traditional software developers have been hiding a secret from us in plain sight. It’s not even a disputed fact. It’s part of their business model.

It doesn’t matter if we’re talking about high-end enterprise software vendors or smaller software houses that write the tools that we all use day to day in our jobs or businesses. It’s right there front and center. Additional costs that they don’t hide and that we’ve become accustomed paying.

So what is this secret?

Well, a lot of traditional software vendors make more money from maintaining the software that they write than they do in the initial sale.

Not convinced?

A quick search on the term “Total Cost of Ownership” will provide you with lots of similar definitions like this one from Gartner (emphasis mine):

[TCO is] the cost to implement, operate, support & maintain or extend, and decommission an application.

Furthermore, this paper by Stanford university asserts that maintenance normally amounts to 60% to 90% of the TCO of a software product.

It’s worth letting that sink in for a minute. They make well over the initial purchase price by selling ongoing support and maintenance plans.

We Don’t Push Maintenance

The problem as I see it is that in the web development industry, web application maintenance isn’t something that we focus on. We might put it in our proposals because we like the idea of a monthly retainer, but they will likely cover simple housekeeping tasks or new feature requests.

It is not unheard of to hide essential upgrades and optimizations within our quotes for later iterations because we‘re not confident that the client will want to pay for the things that we see as essential improvements. We try and get them in through the back door. Or in other words, we are not open and transparent that, just like more traditional software, these applications need maintaining.

Regardless of the reasons why, it is becoming clear that we are storing up problems for the future. The software applications we’re building are here for the long-term. We need to be thinking like traditional software vendors. Our software will still be running for 10 or 15 years from now, and it should be kept well maintained.

So, how can we change this? How do we all as an industry ensure that our clients are protected so that things stay secure and up to date? Equally, how do we get to take a share of the maintenance pie?

What Is Maintenance?

In their 2012 paper Effective Application Maintenance, Heather Smith and James McKeen define maintenance as (emphasis is mine):

Porting an application to a new server, interfacing with a different operating system, upgrading to a newer release, altering a tax table, or complying with new regulations—all necessitate application — maintenance. As a result, maintenance is focused on upgrading an application to ensure it remains productive and/or cost effective. The definition of application maintenance preferred by the focus group is — any modification of an application to correct faults; to improve performance; or to adapt the application to a changed environment or changed requirements. Thus, adding new functionality to an existing application (i.e., enhancement) is not, strictly speaking, considered maintenance.

In other words, maintenance is essential work that needs to be carried out on a software application so it can continue to reliably and securely function.

It is not adding new features. It is not checking log files or ensuring backups have ran (these are housekeeping tasks). It is working on the code and the underlying platform to ensure that things are up to date, that it performs as its users would expect and that the lights stay on.

Here are a few examples:

  • Technology and Platform Changes
    Third-party libraries need updating. The underlying language requires an update, e.g. PHP 5.6 to PHP 7.1 Modern operating systems send out updates regularly. Keeping on top of this is maintenance and at times will also require changes to the code base as the old ways of doing certain things become deprecated.

  • Scaling
    As the application grows, there will be resource issues. Routines within the code that worked fine with 10,000 transactions per day struggle with 10,000 per hour. The application needs to be monitored, but also action needs to be taken when alerts are triggered.

  • Bug Fixing
    Obvious but worth making explicit. The software has bugs, and they need fixing. Even if you include a small period of free bug fixes after shipping a project, at some point the client will need to start paying for these.

Hard To Sell?

Interestingly, when I discuss this with my peers, they feel that it is difficult to convince clients that they need maintenance. They are concerned that their clients don’t have the budget and they don’t want to come across as too expensive.

Well, here’s the thing: it’s actually a pretty easy sell. We’re dealing with business people, and we simply need to be talking to them about maintenance in commercial terms. Business people understand that assets require maintenance or they’ll become liabilities. It’s just another standard ongoing monthly overhead. A cost of doing business. We just need to be putting this in our proposals and making sure that we follow up on it.

An extremely effective method is to offer a retainer that incorporates maintenance at its core but also bundles a lot of extra value for the client, things like:

  • Reporting on progress vs. KPIs (e.g. traffic, conversions, search volumes)
  • Limited ‘free’ time each month for small tweaks to the site
  • Reporting on downtime, server updates or development work completed
  • Access to you or specific members of your team by phone to answer questions

Indeed, you can make the retainer save the client money and pay for itself. A good example of this would be a client’s requirement to get a simple report or export from the database each month for offline processing.

You could quote for a number of development days to build out a — probably more complex than initially assumed — reporting user interface or alternatively point the client to your retainer. Include within it a task each month for a developer to manually run a pre-set SQL query to manually provide the same data.

A trivial task for you or your team; lots of value to your client.

A Practical Example

You’ll, of course, have your own way of writing proposals but here are a couple of snippets from an example pitch.

In the section of your proposal where you might paint your vision for the future, you can add something about maintenance. Use this as an opportunity to plant the seed about forming a long-term relationship.

You are looking to minimize long-term risk.

You want to ensure that your application performs well, that it remains secure and that it is easy to work on.

You also understand how important maintenance is for any business asset.

Later on, in the deliverables section, you can add a part about maintenance either as a stand-alone option or bundled in with an ongoing retainer.

In the following example, we keep it simple and bundle it in with a pre-paid development retainer:

We strongly advocate that all clients consider maintenance to be an essential overhead for their website. Modern web applications require maintenance and just like your house or your car; you keep your asset maintained to reduce the tangible risk that they become liabilities later on.

As a client who is sensibly keen to keep on top of the application’s maintenance as well as getting new features added, we’d suggest N days per month (as a starting point) for general maintenance and development retainer.

We’d spread things out so that a developer is working on your system at least [some period per week/month] giving you the distinct advantage of having a developer able to switch to something more important should issues arise during the [same period]. Depending upon your priorities that time could all be spent on new feature work or divided with maintenance, it’s your call. We normally suggest a 75%/25% split between new features and important maintenance.

As previously mentioned, this is also a great opportunity to lump maintenance in with other value-added ongoing services like performance reporting, conducting housekeeping tasks like checking backups and maybe a monthly call to discuss progress and priorities.

What you’ll probably find is that after you land the work, the retainer is then not mentioned again. This is understandable as there is lots for you and your client to be considering at the beginning of a project, but as the project is wrapping up is a great time to re-introduce it as part of your project offboarding process.

Whether this is talking about phase 2 or simply introducing final invoices and handing over, remind them about maintenance. Remind them of ongoing training, reporting, and being available for support. Make the push for a retainer, remembering to talk in those same commercial terms: their new asset needs maintaining to stay shiny.

Can Maintenance Be Annoying?

A common misconception is that maintenance retainers can become an additional burden. The concern is that clients will be constantly ringing you up and asking for small tweaks as part of your retainer. This is a particular concern for smaller teams or solo consultants.

It is not usually the case, though. Maybe at the beginning, the client will have a list of snags that need working through, but this is par for the course; if you’re experienced, then you’re expecting it. These are easily managed by improving communication channels (use an issue tracker) and lumping all requests together, i.e, working on them in a single hit.

As the application matures, you’ll drop into a tick-over mode. This is where the retainer becomes particularly valuable to both parties. It obviously depends on how you’ve structured the retainer but from your perspective, you are striving to remind the client each month how valuable you are. You can send them your monthly report, tell them how you fixed a slowdown in that routine and that the server was patched for this week’s global OS exploit.

You were, of course, also available to work on a number of new requested features that were additionally chargeable. From your client’s perspective, they see that you are there, they see progress, and they get to remove “worry about the website” from their list. Clearly, ‘those clients’ do exist, though, so the most important thing is to get your retainer wording right and manage expectations accordingly.

If your client is expecting the moon on the stick for a low monthly fee, push back or renegotiate. Paying you to do — say — two hours maintenance and housekeeping per month in amongst providing a monthly report and other ancillary tasks is exactly that; it’s not a blank cheque to make lots of ad-hoc changes. Remind them what is included and what isn’t.

How Do We Make Maintenance Easier?

Finally, to ensure the best value for your clients and to make your life easier, use some of these tactics when building your applications.

Long-Term Support (LTS)

  • Use technology platforms with well documented LTS releases and upgrade paths.
  • Ongoing OS, language, framework and CMS upgrades should be expected and factored in for all projects so tracking an LTS version is a no-brainer.
  • Everything should be running on a supported version. Big alarm bells should be ringing if this is not the case.

Good Project Hygiene

  • Have maintenance tasks publicly in your feature backlog or issue tracking system and agree on priorities with your client. Don’t hide the maintenance tasks away.
  • Code level and functional tests allow you to keep an eye on particularly problematic code and will help when pulling modules out for refactoring.
  • Monitor the application and understand where the bottlenecks and errors are. Any issues can get added to the development backlog and prioritized accordingly.
  • Monitor support requests. Are end users providing you with useful feedback that could indicate maintenance requirements?

The Application Should Be Portable

  • Any developer should be able to get the system up and running easily locally — not just you! Use virtual servers or containers to ensure that development versions of the applications are identical to production.
  • The application should be well documented. At a minimum, the provisioning and deployment workflows and any special incantations required to deploy to live should be written down.

Maintenance Is A Genuine Win-Win

Maintenance is the work we need to do on an application so it can safely stand still. It is a standard business cost. On average 75% of the total cost of ownership over a software application’s lifetime.

As professionals, we have a duty of care to be educating our clients about maintenance from the outset. There is a huge opportunity here for additional income while providing tangible value to your clients. You get to keep an ongoing commercial relationship and will be the first person they turn to when they have new requirements.

Continuing to provide value through your retainer will build up trust with the client. You’ll get a platform to suggest enhancements or new features. Work that you have a great chance of winning. Your client reduces their lifetime costs, they reduce their risk, and they get to stop worrying about performance or security.

Do yourself, your client and our entire industry a favor: help make web application maintenance become more of a thing.

Smashing Editorial
(rb, ra, hj, il)

View this article: 

Why Web Application Maintenance Should Be More Of A Thing

An Introductory Guide To Business Insurance For Designers And Developers

At some point in your career, most web designers and developers can relate to issues with scope creep, unexpected project delays, client relationships breaking down, and unpaid invoices. The good news is that there’s an insurance policy to help with these scenarios. In the UK, we call it “professional indemnity insurance.” Elsewhere, it can be called “professional liability” or “errors and omissions insurance.”

Let’s explore what this insurance is and how it’s designed to keep web professionals in business. I’ll also be sharing real stories of businesses who were glad they had insurance.

What Is Professional Indemnity Insurance?

Professional indemnity insurance protects your business from screw-ups and problem clients.

Let’s say a client threatens legal action, claims loss of income or damages due to a service you provided. Even if you’re in the wrong, professional indemnity steps in to ensure the consequences to your business aren’t crippling.

A creative agency working on a project together


A creative agency working on a project together. (Large preview)

It’s also important to distinguish what professional indemnity insurance isn’t. After all, business insurance is an umbrella term for different types of cover. One of those covers is public liability insurance — or general liability insurance as it’s known in the US.

Public liability insures your business against claims of:

  • physical injury to clients and members of the public
  • accidents on your work premises
  • damage to third-party property.

This is a popular cover for those who have clients visit their office or those who work from client premises. However, in this article, we’re focusing exclusively on professional indemnity.

How Can Insurance Help Me If I’m A Designer Or Developer?

Business insurance isn’t often talked about in web circles. I think it’s because insurers have focused their products and user experience on traditional industries. A lot of the information out there isn’t relevant to those of us working in digital.

To add to that, people don’t equate working with a computer as being a danger or massive liability. Especially when you have all of your clients sign a contract. This can lull designers and developers into a false sense of security. A common objection I hear from web professionals when talking about insurance is:

I can’t cause any damage as a web designer. For anything that does go wrong, I have a clause in my contract that says I’m not liable.

Firstly, I have to debunk the myth of not needing to have insurance because you work with a contract. Contracts don’t alleviate you from liability. They’re useful for laying the foundation of what duties are expected of both parties, but insurance steps into action when those duties come into question.

With every scenario I’m sharing today, they all had the following in common:

  • A contract was signed by both parties.
  • They had years of experience in their profession.
  • They were professionally insured, but never expected to have to use their insurance.

Below are real stories of how professional indemnity insurance helped these designers and developers.

Scope Creep

A developer built a web platform to spec, but the client complained of missing functionality.

The developer agreed to build the perceived missing functionality for a further fee, but the client believed it should have been included in the initial build. Not only did the client refuse to pay the remaining invoice, but they threatened legal action if the developer didn’t cooperate.

Having professional indemnity insurance meant that the developer had a team of legal experts behind him. They helped the developer communicate with his client to avoid the problem escalating.

The developer’s professional indemnity policy also had a mitigation costs clause. This meant the insurer paid the amount owed to him by his client, which was thousands of pounds.

Project Delays

Designers and developers often work to tight deadlines. Missing deadlines can cause problems if the project has an important launch date.

A creative agency was hired to design a website, but the project started to unravel. Key members of the team left part way through the project and the pace of the work being completed slowed down.

While the website was delivered in time for launch, it was missing a lot of major features. The client said it wasn’t fit for purpose.

After wasting money on a marketing campaign for the launch, the client refused to pay the final invoice. They also incurred extra expenses from hiring new contractors to complete the website’s missing features.

The client threatened to involve solicitors if the agency pursued payment.

The unpaid invoice was settled by the insurer under the mitigation costs clause of their professional indemnity policy. The insurer also provided the agency with legal advisors to confirm with the client that the project is considered at an end.

Client Relationships Breaking Down

This is a common catalyst for professional indemnity claims. Even if we spot a few amber flags, we like to believe we can make our client relationships work and projects run smoothly. However scary it is, sometimes you have to burn bridges with a client.

A designer did this when working with a client they felt didn’t respect them. An ever-changing scope, long hours, and poor pay lead to a breakdown in the relationship. What had started off as a promising project was now a strained working relationship and source of stress. The designer decided to walk away from the project.

Unfortunately, that wasn’t the end of things. The client wanted to be reimbursed for the money they had already paid to the designer. They also wanted damages for the loss of income due to a delayed launch and compensation for hiring other contractors to complete the project.

A team of legal experts was arranged by the insurer to deal with the designer’s client. A settlement was agreed out of court, which was also covered by the insurer.

What Does A Professional Indemnity Policy Insure Against?

Professional indemnity insurance is a meaty policy, so it isn’t feasible to cover every scenario here. At its core, it’s designed to put your business back in the same financial position after a loss as it was in before a loss. As you can see from the stories above, a loss can be legal fees, client damages, compensation or even unpaid invoices. However, this has to stem from a client expressing dissatisfaction with your work.

While all professional indemnity policies differ, let’s look at some of the key features you can expect to see.

Defence Costs

If a client makes a claim against you, your professional indemnity policy will pay the defence costs. This isn’t just for situations that have escalated to court. Insurers want to solve problems before they get to that stage, so they’ll provide a team of legal experts to help negotiate terms with your client.

Intellectual Property Infringement

Web and graphic designers are vulnerable to arguments over copyright infringement, whereas developers could get into disputes over who owns the code. This clause covers claims against copyright infringement, trademarks, slogans, and even domain names.

Mitigation Costs

If you read the stories above, you’ll have seen mitigation costs mentioned where unpaid invoices were paid by the insurer. If a client is dissatisfied with your work, refuses to pay any or all your fees and threatens to bring a claim against you, professional indemnity may pay the amount owed to you by your client. This is only if the insurer believes it will avoid a claim for a greater amount.

Negligence

Negligence covers a broad spectrum, but think of this as a warranty for any mistakes you make that lead to an unhappy client.

Unintentional Breach Of Contract

Breach of contract can take many forms. It could be something as simple as failing to deliver a project on time or not meeting the client’s expectations. Any breach of contract may entitle the client to make a claim against you.

A web developer working on his laptop


A web developer working on his laptop. (Large preview)

Some Practical Tips For Buying Insurance

The first question people ask when it comes to buying insurance is, “How much should I insure my business for?”. The level of cover will typically start at £100,000 and can go well into the millions. It can be a difficult question to answer, but there are factors that can help you arrive at a reasonable figure.

Client Contracts

If your client contract has an insurance clause, it’s usually for £1,000,000 of professional indemnity. This is the base level of cover a client would expect. It’s the most common level of cover I see businesses buy.

Types of Clients

What type of clients are you working with? Is it large corporations with in-house legal teams, or local small businesses? It’s not unwise to assume the larger companies pose a bigger threat, therefore should have a higher level of cover. You may also find that larger companies will have an insurance clause in their contract.

Type Of Work You Do

A developer building a payment platform will potentially face a bigger risk than somebody designing a website to showcase a restaurant’s menu. Does your work involve dealing with sensitive information or higher-cost products? Are businesses depending on your service to generate income for them?

If it feels like I’ve skirted around answering this, it’s because there isn’t a straightforward figure. A lot of insurers will simply tell you to buy what you’ve budgeted for. If in doubt, consider a base level of £1,000,000 and periodically evaluate your clients and type of work you do. Most insurers allow you to make a mid-term adjustment part way through your policy to increase your level of cover.

Other than the cost of insurance, there are a few other factors to be aware of when buying insurance.

Insuring More Than One Activity

The web is a multi-disciplinary industry. You should be looking for a policy that can cover your various activities. A web developer may also provide web hosting. A designer may also offer consulting services. If you fall outside of the typical box, you might find it useful talking to a broker or using a service like With Jack where your policy can be customized instead of using an online comparison site.

Insuring Your Work Worldwide

By default, professional indemnity policies in the UK exclude US jurisdiction. If you’re working with US clients under US contract law, look for an insurer that can lift the jurisdictional limit from your policy, so you’re insured worldwide. Just beware that it will increase your premium.

Your Policy Can Adapt To Your Needs

Insurance can be flexible. Don’t delay buying insurance because you’re thinking of switching from sole trader to Limited company down the line, or because you’re waiting to add a new service to your business. A good insurance company will allow you to adjust your policy, adapting it as your business changes and grows.

How Insurance Can Help You Build A Bulletproof Business

Whenever I see newcomers ask for advice on starting their business in the web industry, I see a lot of suggestions that look like this:

  • “Get an accountant immediately.”
  • “Build a network!”
  • “Have your clients sign a contract.”
  • “Monitor your cashflow!”

This is all great advice, of course, but rarely do I see anybody mentioning getting insured. Insurance should be a crucial part of any professional designer or developer’s toolbox.

Offering your professional services to clients comes with a degree of risk. It’s your responsibility to mitigate that risk. You have to be confident that — if something does go wrong — you can get back to work quickly. There can be issues with mistakes in your work, a relationship going sour or a client claiming they’re unhappy with your service. It doesn’t matter how good you are, these things happen!

This is why I’m sharing these stories — to highlight the importance of being insured. I want to get web professionals not just thinking about insurance, but understanding it. Insurance is something we don’t necessarily want to budget for or consider, yet as professionals, we have to. The stories above show how critical it can be.

So yes, work with a contract. Monitor your cash flow. Have an accountant manage your bookkeeping, but also get insured. There’s little point in building your business only for one problem client or mistake to take it away from you.

Smashing Editorial
(ra, yk, il)

Excerpt from: 

An Introductory Guide To Business Insurance For Designers And Developers