What Vitruvius Can Teach Us About Web Design

What Vitruvius Can Teach Us About Web Design

What Vitruvius Can Teach Us About Web Design

Frederick O’Brien

2020-06-19T10:00:00+00:00 2020-06-21T05:04:10+00:00

There’s no escaping the ancient masters. Their shadows loom large over philosophy, literature, architecture, warfare, and… web design? Believe it or not, yes. Although Plato infamously omitted CSS Grid from from the final draft of The Republic, there is nonetheless plenty the old heads can teach us about web development.

Today’s lecture is about architecture, and how some of its core tenets apply to the worldwide web. Architectural terms are not unusual in web development, and for good reason. In many ways, web developers are digital architects. This piece will focus on Vitruvius, a Roman architect, and how his principles can and should be applied to websites.

This will focus in particular on the Vitruvian triad, three qualities essential to any building: durability (firmitas) , usefulness (utilitas), and beauty (venustas). Familiarity with these terms — and what they mean in practice — will help make your website better.


Marcus Vitruvius Pollio was a Roman architect, civil engineer, and author who lived during the first century BC. He is remembered mainly for his writings on architecture, De architectura. Addressing the then emperor Augustus, Vitruvius outlines his thoughts on architectural theory, history, and methods.

Drawing of Roman architect Marcus Vitruvius Pollio
Vitruvius posing for a LinkedIn headshot. (Large preview)

De architectura is the only treatise on architecture to survive from antiquity, and remains a design touchstone to this day. As you could probably guess, Leonardo da Vinci’s Vitruvian Man was inspired by Vitruvius’s writings about proportion.

For those of you interested in going down an architecture rabbit hole, the full text of De architecture is available for free on Project Gutenberg. This piece will not attempt to summarise the whole book. There are a couple of reasons for this. First, there’d be an awful lot to cover. Second, I haven’t totally lost sight of the fact this is a web design magazine. We will be honing in on the Vitruvian triad, a standard for design that applies well beyond architecture.

The ancients had a knack for reducing topics to their bare — you might say elemental — essentials. The Vitruvian triad is one such case. There are other architects worth studying, other design theories worth being familiar with, but Vitruvius offers a particularly neat ABC that applies just as well to the web as it does to temples.

The Vitruvian Triad

In De architectura, Vitruvius identified three qualities essential to any piece of architecture. In the centuries since they have established themselves as his ‘golden rules.’ If you want to make Vitruvius happy — which of course you do — whenever you make a thing you should strive to make it:

  • Useful (utilitas)
  • Durable (firmitas)
  • Beautiful (venustas)

Designing with these three things in mind will elevate your work. Having one of these qualities is nice; having two is good; and having all three together is divine. Divine seems like the best option. Let’s break down what each of the three qualities mean in principle, then how they can be applied to web design.

Useful (utilitas)

In principle

Buildings are designed and erected for a reason. Whatever that purpose is, it should always be an architect’s mind. If the structure does not meet its purpose then odds are it isn’t going to be very useful. A theatre with no stage has rather dropped the ball, for example.

According to Vitruvius, usefulness will be assured “when the arrangement of the apartments is faultless and presents no hindrance to use, and when each class of building is assigned to its suitable and appropriate exposure.”

You’ve heard this one before, albeit with different language. Vitruvius is the granddaddy of harping on about how form should follow function. Louis Sullivan, the ‘father of skyscrapers’, coined that particular term in 1896. Sullivan supposedly attributed the idea back to Vitruvius, although documentation of this is dubious. In any case, that’s what utilitas boils down to.

Photograph of the old Public Library of Cincinnati
Purpose: Library. All clear? (Large preview)

Different types of buildings have different requirements. A building designed with these requirements as an afterthought will likely disappoint. This may sound obvious, but there are enough white elephants in this world to warrant caution. Labyrinthine shopping centres and highly conductive metal domes in playgrounds may look cool in investor presentations, but they don’t wind up being terribly useful.

Screenshot of New York Times news article about a playground lawsuit
Don’t be the playground designer whose playground gives children second-degree burns. Full story in The New York Times. (Large preview)

This also means the individual parts of a structure should be logically connected. In other words, they should be simple to access and navigate. If a building is useful and easy to use that’s a very good start.


Utilitas also applies to web design. Every website has a purpose. That purpose may be practical, like a search engine or weather forecast, or it may be artistic, like an interactive story or graphic design portfolio. Whatever it is, it has a reason to exist, and if it is designed with that reason in mind it is more likely to be useful to anyone who visits the site.

An encyclopedia you would expect to be easy to search and navigate, with cleanly presented and properly cited information. Wikipedia, for example, ticks all of those boxes. It is the web equivalent of an enormous library, right down to the obscure sections and staff bickering behind the scenes. It was built with usefulness front and center, and so its core design has remained consistent in the years since its founding.

Alternatively, the purpose of a publication is to produce original content that is of value or interest to its readers. To be useful, a website’s publication would present said content in a vibrant and direct way, paying special attention to the reading experience across various devices. A website with wonderful content and bad design undermines its own usefulness.

Homepage screenshot of The Guardian newspaper
The Guardian is a newspaper. It’s purpose is to report the news. Its award-winning website doesn’t faff around with slogans or spectacle; it packs it full of content. (Large preview)

A clear purpose leads to clear design. If a purpose has you pulling in several different directions then the same will be true of the website. You can’t be all things to all people, and it is pointless to try. Usefulness tends to meet specific needs, not all needs.

When it comes to usefulness you can’t afford to treat websites as something abstract. Like buildings, websites are visited and used by people, and ought to be designed with them in mind above all others. Investors, advertisers, and all the other sordid actors will have their time, but if you let them in too early a site’s usefulness will be compromised. When a publication breaks up articles across multiple pages purely to inflate traffic numbers, its usefulness is reduced. When an e-commerce platform seems more concerned with shoving you down conversion funnels than with providing honest information about its products, its usefulness is reduced. In such cases, the purpose has become secondary, and the design suffers as a result.

Homepage screenshot of the DuckDuckGo search engine
We recognise the hallmarks of search engine design just like we recognise theatres, libraries, or sport stadiums. Their forms are shaped around their function. (Large preview)

Also, like buildings, websites should be easy to navigate. Ensuring the usefulness of a website requires thorough planning. Where the architect has floor plans and models, the web developer has sitemaps, wireframes, and more. These allow us to identify layout problems early and address them.

Looking at the design through different lenses is especially important here. Does the palette account for colour blindness and cultural differences? Colours mean different things in different places, after all. Is it easy to browse using keyboards and screen readers? Not everyone navigates the web the same way you do. Surely it’s better to be useful to as many people as possible? There is no good excuse for websites not to be both accessible and inclusive.

Durable (firmitas)

In principle

Firmitas boils down to the idea that things should be built to last. A fantastically useful structure that topples over after a couple of years would be widely regarded as a failure. A well-made building can last for centuries, even millenniums. Ironically, none of Vitruvius’s own buildings survive, but the point still stands.

This principle encompasses more aspects of architecture than might immediately come to mind.

Durability will be assured when foundations are carried down to the solid ground and materials wisely and liberally selected.
— Vitruvius

In other words, choose your destination carefully, lay deep foundations, and use appropriate materials.

Photograph of the Great Wall of China
With some sections well over 2,000 years old, it’s safe to say the Great Wall of China was built to last. Photograph by Andrea Leopardi. (Large preview)

We all instinctively understand longevity is a mark of good design. It reflects quality materials, meticulous planning, and loving maintenance. The Pantheon in Rome, or the Great Wall of China, are testaments to durable design, renowned as much for their longevity as for their majesty.

The principle also concerns environmental factors. Are buildings designed with due thought to the strains of weather, earthquakes, erosion, etc.? If not, it may not be a building for long…

Footage of the Tacoma Narrows Bridge shortly before its collapse
The Tacoma Narrows Bridge has its durability put to the test after engineers cut corners on cost. Spoiler: it collapsed.

It’s reassuring to know you can count on a structure not collapsing for a while, and in the long run, it usually winds up being cheaper. A durable building sits on strong foundations and uses materials appropriate to its purpose and its environment. Buildings that aren’t designed to last are typically glorified film sets. Before long, they are rubble.


Time seems to pass much faster on the web, but the principle of firmitas still applies. Given the endless turbulence of online life it makes sense to plant your flag in something sturdy. Out of the three qualities, it is the one least visible to users, but without it, everything else would fall apart.

This starts with under the hood considerations. The foundations must be strong. Where will the website go? Is the content management system the right fit? Can your web hosting provider handle the expected traffic (and more) and still run smoothly? As anyone who has migrated from one CMS to another can tell you, it’s worth getting it right the first time if possible.

A generic error message for websites with server issues
This is what a crumbling website looks like. (Large preview)

There is also the longevity of the web technologies you’re using. New frameworks may seem like a good idea at the time, but if a site needs to be around for years it may make sense to fall back on HTML, CSS, and JavaScript, as well as universally supported SEO markups like structured data. As in architecture, building things to last often means using established materials rather than newfangled ones.

Durability extends to design. Web pages have to bend and stretch and warp in ways that would make architects weep. A responsive website is a durable website. As new devices — foldables, for example — and markups enter come at us, websites need to be able to take them in stride. Architects don’t get to cross their arms and sulk about earthquakes, so why should web designers shy away from the hazards of the web? Great design faces up to environmental challenges; it doesn’t avoid them.

As a site grows its users will become familiar with its design. The more that happens the more of a headache it is to make wholesale changes. If a site is designed carefully from the start then renovations are more likely than rebuilds, and the appearance remains familiar even when it is updated. In this sense, a site’s durability is helped immeasurably by clear purpose. That in itself is a kind of bedrock, helping to keep sites sturdy in times of change. Even the best sites need updates from time to time.

Homepage screenshot of Smashing Magazine website
Smashing Magazine’s 2017 redesign solidified behind the scenes elements like content management, job boards, and ecommerce while keeping the front-end character familiar. (Large preview)

There is also the question of sustainability. Is due attention being paid to the commercial realities of the site? In other words, where is the box office? Be it paywalls, advertising, or membership systems, there’s no shame in incorporating these into the design process. They are not a site’s purpose, but they help make it durable.

Beautiful (venustas)

In principle

As Vitruvius says, “the eye is always in search of beauty.” It is a perfectly legitimate quality to aim for.

According to De architectura, beauty occurs “when the appearance of the work is pleasing and in good taste, and when its members are in due proportion according to correct principles of symmetry.”

As well as being useful and well made, buildings ought also to be pleasing to the eye. Some may even touch the heart.

An illustration for Vitruvius’s writings on architecture
If you want to design a good temple, Vitruvius is useful for that, too. (Large preview)

Vitruvius outlines several qualities that help make buildings beautiful. Symmetry and proportion were of particular interest to him (hence Da Vinci’s Vitruvuian Man). Obsessively incorporating shapes into everything predates graphic design by a few millennia.

Each element of a structure should be considered in relation to others near it, as well as to the environment that it is being built. Vitruvius sums up this interplay with one word: eurythmy, a Greek term for harmonious rhythm. (British pop duo Eurythmics drew their name from the same term, in case you were wondering.) Vitruvius defines it in an architectural context as follows:

Eurythmy is beauty and fitness in the adjustments of the members. This is found when the members of a work are of a height suited to their breadth, of a breadth suited to their length, and, in a word, when they all correspond symmetrically.

Like music, buildings have rhythm; their individual pieces forming into a kind of harmony. A beautiful building might be the carved marble equivalent of a Beach Boys chorus, while an ugly one is like nails on a chalkboard.

An example of McMansion Hell critiquing shoddy architecture
For those curious what beautiful architecture doesn’t look like, McMansion Hell is a good place to start. (Large preview)

As well as being well proportioned and symmetrical, individual pieces can enhance beauty in other ways. Good craftsmanship is beautiful, as is attention to detail. Materials appropriate to the structure are also beautiful — reflecting the sound judgment and good taste of the designer.

Ornamentation is acceptable, but it must complement the core design of the structure — think column engravings, paving patterns, etc. All these little details and considerations amount to the building as a whole. When they all fall together, it’s breathtaking.


Beautiful websites adhere to many of the same standards as architecture. Proportion and symmetry are mainstays of attractive design. Grid systems serve the same purpose of organizing content clearly and attractively. Beyond that, there are questions of color, typography, imagery, and more, all of which feed into a website’s beauty — or lack thereof.

To get the ball rolling, here are a handful of resources on Smashing Magazine alone:

An aspect of venustas that is especially relevant to web design is how users can interact with it. As well as being nice to look at, websites have the potential to be playful, even surprising. It’s one thing to sit there and be admired, it’s another to invite visitors to become part of the beauty.

Screenshot of Bruno Simon’s portfolio website
Bruno Simon’s portfolio website invites visitors to drive around using their arrow keys. (Large preview)

Google’s interactive doodles are another good — and less daunting — example of this. Covering all manner of subjects, they invite users to play games, to learn, and to be entertained. It’s nice in its own right, and aligns with Google’s purpose as a source of information.

Example of a Google Doodle
Ironically, this is just a GIF of an interactive thing rather than the interactive thing itself, but you can see the full doodle and details of its making here. (Large preview)

With the web continuing its shift towards mobile-first experience, in which users can literally touch the websites they visit, it should be remembered that beauty pertains to all the senses — not just sight.

As for the ‘environment’, with web design that is the device it is being displayed on. Unlike buildings, websites don’t have the luxury of being one shape at all times. To be beautiful they must be responsive, shifting size and proportion to compliment the device. This is pleasing on its own, and done well the shape shifting itself becomes beautiful in its own way.

A Balancing Act

Vitruvius’s rules of utilitas, firmitas, and venustas have endured because they work, and they have endured as a triad because they work best together. Attaining all three is a balancing act. If they pull in different directions then the quality of whatever is being made will suffer. Beautiful but unuseable is poor design, for example. On the flip side, when they work together the result can be far greater than the sum of their parts.

As with architecture this requires a bird’s eye view. The pieces cannot be done one at a time, they must be done with the others in mind.

The architect, as soon as he has formed the conception, and before he begins the work, has a definite idea of the beauty, the convenience, and the propriety that will distinguish it.
— Vitruviuas

No doubt the details will change, but the harmony should not.

This extends to the people making a website. As with architecture websites typically have to balance the wants of a client, an architect, and a builder — not to mention investors, financiers, statisticians, and so on. For a website to be harmonious, so do the people responsible for building it.

None of this is to say that the three qualities are equally important regardless of the project — only that each should be given due thought in relation to the others. The usefulness of the Eiffel Tower seems fairly trivial, as does the beauty of the Hoover Dam, and that’s fine. If a website is made to be ornamental or temporary, it doesn’t have to be more than that. The natures of utilitas, firmitas, and venustas themselves change depending on the project. Like most rules worth following, don’t be afraid to bend — or even break — them when the mood takes you.

My Website Is A Temple

Web developers are the architects of the Internet, and websites are their buildings. Vitruvius makes a point of saying architects are not — and indeed cannot be — experts in every field. Instead, they are jacks of all trades (my phrasing, not his). For the triad to be achieved it is better to have a good grasp of many subjects than expertise in one:

Let him be educated, skillful with the pencil, instructed in geometry, know much history, have followed the philosophers with attention, understand music, have some knowledge of medicine, know the opinions of the jurists, and be acquainted with astronomy and the theory of the heavens.

The relevance of some of these is obvious, others less so, but it’s all valuable to architects and web developers alike. Geometry informs proportion and layout; history puts designs in context and ensures they are understood as they are meant to be; philosophy helps us to approach projects honestly and ethically; music awakens us to the role of sound; medicine gives thought to accessibility, and potential strains on the eye, ear, or even thumb; and law looms larger now than ever. The theory of the heavens might be a stretch, but you get the idea.

Here are yet more links to help you on your way:

Not that theory alone will get you there. There’s no substitute for learning through doing. As the Stanford Encyclopedia of Philosophy notes, “the Vitruvian picture of architecture is rooted in experiential knowledge of making, doing, and crafting.” Or better yet, as Vitruvius himself puts it: “Knowledge is the child of practice and theory.”

The Vitruvian triad is a worthy standard to use whether you’re building a coliseum or a portfolio website. Not everyone has the luxury of (or budget for) a team of experts, and even if we did, why deny ourselves of the breadth of knowledge that strong design requires? We can build Levittown or we can build Rome, and everything in between. A useful, durable, beautiful Internet sounds like a good deal to me.

Smashing Editorial (ra, yk, il)

A 5-step Plan for Video Production and Distribution

No video-marketing plan is complete until you know how your company will shoot and distribute that content to your audience of customers and prospects.

Video content marketing starts with goal setting, understanding your audience, identifying topics, and creating a schedule — often in the form of an editorial calendar. I addressed all of these steps in “A 4-step Plan for Video Marketing Success,” a recent article.

Once you’ve completed these first steps, it is time to produce, edit, and publish your videos. As with most content marketing, the aim is to make a connection with consumers.

In some cases, you can create a sense of reciprocity, wherein a consumer will watch a video from your business, recognize the video’s value, and feel a little indebted for your efforts. The next time that person needs a product your store sells, she may be more inclined to buy from your company.

What follows is a five-step plan for producing and distributing videos for content marketing.

<img aria-describedby="caption-attachment-351099" class="wp-image-351099 size-large" src="https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-570×380.jpg" alt="A man shoots a video with a DSLR camera. Photo: Stefano Intintoli.” width=”570″ height=”380″ srcset=”https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-570×380.jpg 570w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-300×200.jpg 300w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-768×512.jpg 768w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-150×100.jpg 150w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video-500×334.jpg 500w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/061620-making-video.jpg 1000w” sizes=”(max-width: 570px) 100vw, 570px”>

A man shoots a video with a DSLR camera. Photo: Stefano Intintoli.

1. Shoot Your Video

Whether you will be recording on an iPhone or a DSLR camera and whether you will do it yourself or use an agency, remember three essentials as you shoot and develop your company’s video.

  • Add real value.
  • Be consistent.
  • Make it sustainable.

Make videos that are useful, informative, or entertaining. They should be relevant to your audience. The viewer should be better for watching it.

Also, produce videos regularly. No single video meets all of a company’s content marketing goals. Rather, video marketing is an ongoing strategy to attract, engage, and retain your audience.

With consistency in mind, how you shoot the videos should be sustainable. Thus, if you have a small ecommerce operation without a lot of money, don’t hire an expensive advertising agency for your first video and try to shoot your second one using an inexpensive webcam.

Choose a video style, format, and production process that you can sustain.

For help with video production, consider taking a few courses on the YouTube Creators Academy. All of the courses are free and, in my experience, offer helpful advice about video production.

2. Edit for Distribution

Edit your videos based on the distribution channel.

For a video on YouTube, as an example, you probably want a 16:9 aspect ratio (i.e., horizontal) at a fairly high resolution. But if you are posting to Instagram TV, you may want a mobile-friendly 9:16 (vertical) aspect ratio. Or, for a video on your website, you may want both a horizontal and vertical version so that the aspect ratio changes based on the user’s device (i.e., mobile versus desktop) or device orientation.

Resizing or reorienting videos may require advanced editing skills. Thus you may need to outsource that task or use specialized software. For example, Adobe Premiere has recently added an auto reframing feature that can transform a 16:9 horizontal video into both a 1:1 square and a 9:16 vertical version.

Adobe Premiere can reframe a video to meet your distribution requirements.

Adobe Premiere can reframe a video to meet your distribution requirements.

3. Create a Transcript or Article

After you have created and edited your video, consider repurposing it in an article. One of the easiest ways to do this is to create and publish a transcript of the video.

There are many transcript-generation services, such as Rev.com. Transcripts may be unnecessary, however, for scripted videos.

Finally, you could always write an article related to the video, perhaps expanding on one key portion.

4. Publish

You could place your video on multiple platforms, not just YouTube. You could also publish it in different formats, such as a blog post with an embedded video or short clips on social media.

In other words, publishing is not necessarily a one-time event in a single format. Reuse and republish video content for a larger impact.

5. Ask for Feedback

Don’t be afraid to ask for feedback. This can be done on the distribution platform, such as YouTube or Instagram, or on your company’s website. The goal is to generate new content ideas to engage existing and potential customers.

Solving Common Cross-Platform Issues When Working With Flutter

Solving Common Cross-Platform Issues When Working With Flutter

Solving Common Cross-Platform Issues When Working With Flutter

Carmine Zaccagnino

2020-06-18T10:30:00+00:00 2020-06-18T23:34:04+00:00

I’ve seen a lot of confusion online regarding Web development with Flutter and, often, it’s sadly for the wrong reasons.

Specifically, people sometimes confuse it with the older Web-based mobile (and desktop) cross-platform frameworks, which basically were just Web pages running within browsers running within a wrapper app.

That was truly cross-platform in the sense that the interfaces were the same anyway because you only had access to the interfaces normally accessible on the Web.

Flutter isn’t that, though: it runs natively on each platform, and it means each app runs just like it would run if it were written in Java/Kotlin or Objective-C/Swift on Android and iOS, pretty much. You need to know that because this implies that you need to take care of the many differences between these very diverse platforms.

In this article, we’re going to see some of those differences and how to overcome them. More specifically, we’re going to talk about storage and UI differences, which are the ones that most often cause confusion to developers when writing Flutter code that they want to be cross-platform.

Example 1: Storage

I recently wrote on my blog about the need for a different approach to storing JWTs in Web apps when compared to mobile apps.

That is because of the different nature of the platforms’ storage options, and the need to know each and their native development tools.


When you write a Web app, the storage options you have are:

  1. downloading/uploading files to/from disk, which requires user interaction and is therefore only suitable for files meant to be read or created by the user;
  2. using cookies, which may or may not be accessible from JS (depending on whether or not they’re httpOnly) and are automatically sent along with requests to a given domain and saved when they come as part of a response;
  3. using JS localStorage and sessionStorage, accessible by any JS on the website, but only from JS that is part of the pages of that website.


The situation when it comes to mobile apps is completely different. The storage options are the following:

  1. local app documents or cache storage, accessible by that app;
  2. other local storage paths for user-created/readable files;
  3. NSUserDefaults and SharedPreferences respectively on iOS and Android for key-value storage;
  4. Keychain on iOS and KeyStore on Android for secure storage of, respectively, any data and cryptographic keys.

If you don’t know that, you’re going to make a mess of your implementations because you need to know what storage solution you’re actually using and what the advantages and drawbacks are.

Cross-Platform Solutions: An Initial Approach

Using the Flutter shared_preferences package uses localStorage on the Web, SharedPreferences on Android and NSUserDefaults on iOS. Those have completely different implications for your app, especially if you’re storing sensitive information like session tokens: localStorage can be read by the client, so it’s a problem if you’re vulnerable to XSS. Even though mobile apps aren’t really vulnerable to XSS, SharedPreferences and NSUserDefaults are not secure storage methods because they can be compromised on the client side since they are not secure storage and not encrypted. That’s because they are meant for user preferences, as mentioned here in the case of iOS and here in the Android documentation when talking about the Security library which is designed to provide wrappers to the SharedPreferences specifically to encrypt the data before storing it.

Secure Storage On Mobile

The only secure storage solutions on mobile are Keychain and KeyStore on iOS and Android respectively, whereas there is no secure storage on the Web.

The Keychain and KeyStore are very different in nature, though: Keychain is a generic credentials storage solution, whereas the KeyStore is used to store (and can generate) cryptographic keys, either symmetric keys or public/private keys.

This means that if, for instance, you need to store a session token, on iOS you can let the OS manage the encryption part and just send your token to the Keychain, whereas on Android it’s a bit more of a manual experience because you need to generate (not hard-code, that’s bad) a key, use it to encrypt the token, store the encrypted token in SharedPreferences and store the key in the KeyStore.

There are different approaches to that, as are most things in security, but the simplest is probably to use symmetric encryption, as there is no need for public key cryptography since your app both encrypts and decrypts the token.

Obviously, you don’t need to write mobile platform-specific code that does all of that, as there is a Flutter plugin that does all of that, for instance.

The Lack Of Secure Storage On the Web

That was, actually, the reason that compelled me to write this post. I wrote about using that package to store JWT on mobile apps and people wanted the Web version of that but, as I said, there is no secure storage on the Web. It doesn’t exist.

Does that mean your JWT has to be out in the open?

No, not at all. You can use httpOnly cookies, can’t you? Those aren’t accessible by JS and are sent only to your server. The issue with that is that they’re always sent to your server, even if one of your users clicks on a GET request URL on someone else’s website and that GET request has side effects you or your user won’t like. This actually works for other request types as well, it’s just more complicated. It’s called Cross-Site Request Forgery and you don’t want that. It’s among the web security threats mentioned in Mozilla’s MDN docs, where you can find a more complete explanation.

There are prevention methods. The most common one is having two tokens, actually: one of them getting to the client as an httpOnly cookie, the other as part of the response. The latter has to be stored in localStorage and not in cookies because we don’t want it to be sent automatically to the server.

Solving Both

What if you have both a mobile app and a Web app?

That can be dealt with in one of two ways:

  1. Use the same backend endpoint, but manually get and send the cookies using the cookie-related HTTP headers;
  2. Create a separate non-Web backend endpoint that generates different token than either token used by the Web app and then allow for regular JWT authorization if the client is able to provide the mobile-only token.

Running Different Code On Different Platforms

Now, let’s see how we can run different code on different platforms in order to be able to compensate for the differences.

Creating A Flutter Plugin

Especially to solve the problem of storage, one way you can do that is with a plugin package: plugins provide a common Dart interface and can run different code on different platforms, including native platform-specific Kotlin/Java or Swift/Objective-C code. Developing packages and plugins is rather complex, but it’s explained in many places on the Web and elsewhere (for example in Flutter books), including the official Flutter documentation.

For mobile platforms, for instance, there already is a secure storage plugin, and that’s flutter_secure_storage, for which you can find an example of usage here, but that doesn’t work on the Web, for example.

On the other hand, for simple key-value storage that also works on the web, there’s a cross-platform Google-developed first-party plugin package called shared_preferences, which has a Web-specific component called shared_preferences_web which uses NSUserDefaults, SharedPreferences or localStorage depending on the platform.

TargetPlatform on Flutter

After importing package:flutter/foundation.dart, you can compare Theme.of(context).platform to the values:

  • TargetPlatform.android
  • TargetPlatform.iOS
  • TargetPlatform.linux
  • TargetPlatform.windows
  • TargetPlatform.macOS
  • TargetPlatform.fuchsia

and write your functions so that, for each platform you want to support, they do the appropriate thing. This will come especially useful for the next example of platform difference, and that is differences in how widgets are displayed on different platforms.

For that use case, in particular, there is also a reasonably popular flutter_platform_widgets plugin, which simplifies the development of platform-aware widgets.

Example 2: Differences In How The Same Widget Is Displayed

You can’t just write cross-platform code and pretend a browser, a phone, a computer, and a smartwatch are the same thing — unless you want your Android and iOS app to be a WebView and your desktop app to be built with Electron. There are plenty of reasons not to do that, and it’s not the point of this piece to convince you to use frameworks like Flutter instead that keep your app native, with all the performance and user experience advantages that come with it, while allowing you to write code that is going to be the same for all platforms most of the time.

That requires care and attention, though, and at least a basic knowledge of the platforms you want to support, their actual native APIs, and all of that. React Native users need to pay even more attention to that because that framework uses the built-in OS widgets, so you actually need to pay even more attention to how the app looks by testing it extensively on both platforms, without being able to switch between iOS and Material widget on the fly like it’s possible with Flutter.

What Changes Without Your Request

There are some aspects of the UI of your app that are automatically changed when you switch platforms. This section also mentions what changes between Flutter and React Native in this respect.

Between Android And iOS (Flutter)

Flutter is capable of rendering Material widgets on iOS (and Cupertino (iOS-like) widgets on Android), but what it DOESN’T do is show exactly the same thing on Android and iOS: Material theming especially adapts to the conventions of each platform.

For instance, navigation animations and transitions and default fonts are different, but those don’t impact your app that much.

What may affect some of your choices when it comes to aesthetics or UX is the fact that some static elements also change. Specifically, some icons change between the two platforms, app bar titles are in the middle on iOS and on the left on Android (on the left of the available space in case there is a back button or the button to open a Drawer (explained here in the Material Design guidelines and also known as a hamburger menu). Here’s what a Material app with a Drawer looks like on Android:

image of an Android app showing where the app bar title appears on Flutter Android Material apps
Material app running on Android: the AppBar title is in the left side of the available space. (Large preview)

And what the same, very simple, Material app looks like on iOS:

image of an iOS app showing where the app bar title appears on Flutter iOS Material apps
Material app running on iOS: the AppBar title is in the middle. (Large preview)
Between Mobile and Web and With Screen Notches (Flutter)

On the Web there is a bit of a different situation, as mentioned also in this Smashing article about Responsive Web Development with Flutter: in particular, in addition to having to optimize for bigger screens and account for the way people expect to navigate through your site — which is the main focus of that article — you have to worry about the fact that sometimes widgets are placed outside of the browser window. Also, some phones have notches in the top part of their screen or other impediments to the correct viewing of your app because of some sort of obstruction.

Both of these problems can be avoided by wrapping your widgets in a SafeArea widget, which is a particular kind of padding widget which makes sure your widgets fall into a place where they can actually be displayed without anything impeding the users’ ability to see them, be it a hardware or software constraint.

In React Native

React Native requires much more attention and a much deeper knowledge of each platform, in addition to requiring you to run the iOS Simulator as well as the Android Emulator at the very least in order to be able to test your app on both platforms: it’s not the same and it converts its JavaScript UI elements to platform-specific widgets. In other words, your React Native apps will always look like iOS — with Cupertino UI elements as they are sometimes called — and your Android apps will always look like regular Material Design Android apps because it’s using the platform’s widgets.

The difference here is that Flutter renders its widgets with its own low-level rendering engine, which means you can test both app versions on one platform.

Getting Around That Issue

Unless you’re going for something very specific, your app is supposed to look different on different platforms otherwise some of your users will be unhappy.

Just like you shouldn’t simply ship a mobile app to the web (as I wrote in the aforementioned Smashing post), you shouldn’t ship an app full of Cupertino widgets to Android users, for example, because it’s going to be confusing for the most part. On the other hand, having the chance to actually run an app that has widgets that are meant for another platform allows you to test the app and show it to people in both versions without having to use two devices for that necessarily.

The Other Side: Using The Wrong Widgets For The Right Reasons

But that also means that you can do most of your Flutter development on a Linux or Windows workstation without sacrificing the experience of your iOS users, and then just build the app for the other platform and not have to worry about thoroughly testing it.

Next Steps

Cross-platform frameworks are awesome, but they shift responsibility to you, the developer, to understand how each platform works and how to make sure your app adapts and is pleasant to use for your users. Other small things to consider may be, for example, using different descriptions for what might be in essence the same thing if there are different conventions on different platforms.

It’s great to not have to build the two (or more) apps separately using different languages, but you still need to keep in mind you are, in essence, building more than one app and that requires thinking about each of the apps you are building.

Further Resources

Smashing Editorial (ra, yk, il)

6 Ways to Convert New Visitors to Email Subscribers

Many online merchants have experienced traffic surges due to the pandemic. Converting that new traffic to immediate purchases can be challenging. The next best option is enticing visitors to subscribe to your email communications.

In this post, I’ll offer tips for converting new visitors into email subscribers.

Converting Visitors to Subscribers

Find the source of current subscribers. Email subscribers come from dozens of sources. The first objective is to identify the top referring channels.

To do this, create a conversion goal in Google Analytics (Conversions > Goals) for your email sign-up or confirmation page. Check the sources of the most subscribers and the most purchases — they may be different.

Once you’ve identified the referring channels, look at the paths of those visitors on your site that led to the sign-up. Knowing those behaviors can help focus your optimization efforts.

Typical sources of new subscribers include:

  • Social media posts,
  • Articles and other free content,
  • Organic search traffic,
  • Paid search traffic,
  • Display ads,
  • Affiliate sites,
  • Contests or promotions.

Target the sources that produce the most subscribers.

Provide an incentive. Email subscribers are valuable. Thus offering an incentive can be worth the effort and expense. Strong incentives, in my experience, are:

  • Contests or giveaways,
  • Gift or cart starter,
  • Exclusive subscriber-only content,
  • Discounts and free shipping,
  • Rewards program.

Feedback and notifications. Requesting feedback such as surveys, product reviews, or quizzes can encourage sign-ups, as can notifications, as in:

  • Availability of out-of-stock items,
  • New product launches,
  • Nearby store openings,
  • Holiday shipping deadlines.

Increase sign-up locations. Adding more opportunities for a visitor to sign up will ultimately help conversions. Email sign up boxes should be easy to locate on every page of your site. Shoppers know to scroll to the bottom of a page to access info such as “about us,” shipping, and customer service. It’s a good place for an email sign-up, too.

Wayfair includes an email sign-up on the lower portion of each page.

Wayfair includes an email sign-up on the lower portion of each page.

Use pop-ups. Capturing email addresses via pop-ups is popular because it works. To maximize effectiveness, however, consider the following.


  • Do place pop-ups at the end of content or page exit.
  • Do present a clear call to action with creative imagery.
  • Do request feedback or engagement.
  • Do test! What works for one site may not work for others. Optimize sign-ups with non-stop testing.


  • Don’t throw a pop-up immediately when a visitor lands on a page.
  • Don’t take up the entire screen with the pop-up.
  • Don’t block device-controlled autofill as it streamlines the process for the user.
  • Don’t ask for too much information.

This example below, from Salt Strong, an online fishing club, is a pop-up that engages the visitor with a quiz before requesting an email address.

<img aria-describedby="caption-attachment-351121" class="wp-image-351121 size-full" src="https://www.practicalecommerce.com/wp-content/uploads/2020/06/Salt-Strong-email-sign-up-quiz.jpg" alt="The pop-up for Salt Strong engages visitors with a quiz before requesting an email address. Source: Optinmonster.” width=”342″ height=”530″ srcset=”https://www.practicalecommerce.com/wp-content/uploads/2020/06/Salt-Strong-email-sign-up-quiz.jpg 342w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/Salt-Strong-email-sign-up-quiz-194×300.jpg 194w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/Salt-Strong-email-sign-up-quiz-150×232.jpg 150w, https://www.practicalecommerce.com/wp-content/uploads/2020/06/Salt-Strong-email-sign-up-quiz-323×500.jpg 323w” sizes=”(max-width: 342px) 100vw, 342px”>

The pop-up for Salt Strong engages visitors with a quiz before requesting an email address. Source: Optinmonster.

Find partners. Look for opportunities to partner with your affiliates, sites with complementary content or products, and co-registration options. Opt-Intelligence and AddShoppers, for example, can promote your email sign-up to a network of potential partners.


It’s important to grow email sign-ups. But the key is quality, relevant subscribers that will not unsubscribe. Check your analytics to understand the sources of unsubscribes. (An unsubscribe confirmation page can facilitate.)

A critical data point is comparing the subscribe and unsubscribe dates. If the dates are close, try to determine where the subscriber came from. He could be taking advantage of a lucrative offer — not long-term engagement.

Mirage JS Deep Dive: Using Mirage JS And Cypress For UI Testing (Part 4)

Mirage JS Deep Dive: Using Mirage JS And Cypress For UI Testing (Part 4)

Mirage JS Deep Dive: Using Mirage JS And Cypress For UI Testing (Part 4)

Kelvin Omereshone

2020-06-17T10:30:00+00:00 2020-06-17T23:33:57+00:00

One of my favorite quotes about software testing is from the Flutter documentation. It says:

“How can you ensure that your app continues to work as you add more features or change existing functionality? By writing tests.”

On that note, this last part of the Mirage JS Deep Dive series will focus on using Mirage to test your JavaScript front-end application.

Note: This article assumes a Cypress environment. Cypress is a testing framework for UI testing. You can, however, transfer the knowledge here to whatever UI testing environment or framework you use.

Read Previous Parts Of The Series:

  • Part 1: Understanding Mirage JS Models And Associations
  • Part 2: Understanding Factories, Fixtures And Serializers
  • Part 3: Understanding Timing, Response And Passthrough

UI Tests Primer

UI or User Interface test is a form of acceptance testing done to verify the user flows of your front-end application. The emphasis of these kinds of software tests is on the end-user that is the actual person who will be interacting with your web application on a variety of devices ranging from desktops, laptops to mobile devices. These users would be interfacing or interacting with your application using input devices such as a keyboard, mouse, or touch screens. UI tests, therefore, are written to mimic the user interaction with your application as close as possible.

Let’s take an e-commerce website for example. A typical UI test scenario would be:

  • The user can view the list of products when visiting the homepage.

Other UI test scenarios might be:

  • The user can see the name of a product on the product’s detail page.
  • The user can click on the “add to cart” button.
  • The user can checkout.

You get the idea, right?

In making UI Tests, you will mostly be relying on your back-end states, i.e. did it return the products or an error? The role Mirage plays in this is to make those server states available for you to tweak as you need. So instead of making an actual request to your production server in your UI tests, you make the request to Mirage mock server.

For the remaining part of this article, we will be performing UI tests on a fictitious e-commerce web application UI. So let’s get started.

Our First UI Test

As earlier stated, this article assumes a Cypress environment. Cypress makes testing UI on the web fast and easy. You could simulate clicks and navigation and you can programmatically visit routes in your application. See the docs for more on Cypress.

So, assuming Cypress and Mirage are available to us, let’s start off by defining a proxy function for your API request. We can do so in the support/index.js file of our Cypress setup. Just paste the following code in:

// cypress/support/index.js
Cypress.on("window:before:load", (win) => { win.handleFromCypress = function (request) { return fetch(request.url, { method: request.method, headers: request.requestHeaders, body: request.requestBody, }).then((res) => { let content = res.headers.map["content-type"] === "application/json" ? res.json() : res.text() return new Promise((resolve) => { content.then((body) => resolve([res.status, res.headers, body])) }) }) }

Then, in your app bootstrapping file (main.js for Vue, index.js for React), we’ll use Mirage to proxy your app’s API requests to the handleFromCypress function only when Cypress is running. Here is the code for that:

import { Server, Response } from "miragejs" if (window.Cypress) { new Server({ environment: "test", routes() { let methods = ["get", "put", "patch", "post", "delete"] methods.forEach((method) => { this[method]("/*", async (schema, request) => { let [status, headers, body] = await window.handleFromCypress(request) return new Response(status, headers, body) }) }) }, })

With that setup, anytime Cypress is running, your app knows to use Mirage as the mock server for all API requests.

Let’s continue writing some UI tests. We’ll begin by testing our homepage to see if it has 5 products displayed. To do this in Cypress, we need to create a homepage.test.js file in the tests folder in the root of your project directory. Next, we’ll tell Cypress to do the following:

  • Visit the homepage i.e / route
  • Then assert if it has li elements with the class of product and also checks if they are 5 in numbers.

Here is the code:

// homepage.test.js
it('shows the products', () => { cy.visit('/'); cy.get('li.product').should('have.length', 5);

You might have guessed that this test would fail because we don’t have a production server returning 5 products to our front-end application. So what do we do? We mock out the server in Mirage! If we bring in Mirage, it can intercept all network calls in our tests. Let’s do this below and start the Mirage server before each test in the beforeEach function and also shut it down in the afterEach function. The beforeEach and afterEach functions are both provided by Cypress and they were made available so you could run code before and after each test run in your test suite — hence the name. So let’s see the code for this:

// homepage.test.js
import { Server } from "miragejs" let server beforeEach(() => { server = new Server()
}) afterEach(() => { server.shutdown()
}) it("shows the products", function () { cy.visit("/") cy.get("li.product").should("have.length", 5)

Okay, we are getting somewhere; we have imported the Server from Mirage and we are starting it and shutting it down in beforeEach and afterEach functions respectively. Let’s go about mocking our product resource.

// homepage.test.js
import { Server, Model } from 'miragejs'; let server; beforeEach(() => { server = new Server({ models: { product: Model, }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) => { return products.all(); }); }, });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { cy.visit('/'); cy.get('li.product').should('have.length', 5);

Note: You can always take a peek at the previous parts of this series if you don’t understand the Mirage bits of the above code snippet.

  • Part 1: Understanding Mirage JS Models And Associations
  • Part 2: Understanding Factories, Fixtures And Serializers
  • Part 3: Understanding Timing, Response And Passthrough

Okay, we have started fleshing out our Server instance by creating the product model and also by creating the route handler for the /api/products route. However, if we run our tests, it will fail because we don’t have any products in the Mirage database yet.

Let’s populate the Mirage database with some products. In order to do this, we could have used the create() method on our server instance, but creating 5 products by hand seems pretty tedious. There should be a better way.

Ah yes, there is. Let’s utilize factories (as explained in the second part of this series). We’ll need to create our product factory like so:

// homepage.test.js
import { Server, Model, Factory } from 'miragejs'; let server; beforeEach(() => { server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}` } }) }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) => { return products.all(); }); }, });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { cy.visit('/'); cy.get('li.product').should('have.length', 5);

Then, finally, we’ll use createList() to quickly create the 5 products that our test needs to pass.

Let’s do this:

// homepage.test.js
import { Server, Model, Factory } from 'miragejs'; let server; beforeEach(() => { server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}` } }) }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) => { return products.all(); }); }, });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { server.createList("product", 5) cy.visit('/'); cy.get('li.product').should('have.length', 5);

So when we run our test, it passes!

Note: After each test, Mirage’s server is shutdown and reset, so none of this state will leak across tests.

Avoiding Multiple Mirage Server

If you have been following along this series, you’d notice when we were using Mirage in development to intercept our network requests; we had a server.js file in the root of our app where we set up Mirage. In the spirit of DRY (Don’t Repeat Yourself), I think it would be good to utilize that server instance instead of having two separate instances of Mirage for both development and testing. To do this (in case you don’t have a server.js file already), just create one in your project src directory.

Note: Your structure will differ if you are using a JavaScript framework but the general idea is to setup up the server.js file in the src root of your project.

So with this new structure, we’ll export a function in server.js that is responsible for creating our Mirage server instance. Let’s do that:

// src/server.js export function makeServer() { /* Mirage code goes here */}

Let’s complete the implementation of the makeServer function by removing the Mirage JS server we created in homepage.test.js and adding it to the makeServer function body:

import { Server, Model, Factory } from 'miragejs'; export function makeServer() { let server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}`; }, }), }, routes() { this.namespace = 'api'; this.get('/products', ({ products }) => { return products.all(); }); }, seeds(server) { server.createList('product', 5); }, }); return server;

Now all you have to do is import makeServer in your test. Using a single Mirage Server instance is cleaner; this way you don’t have to maintain two server instances for both development and test environments.

After importing the makeServer function, our test should now look like this:

import { makeServer } from '/path/to/server'; let server; beforeEach(() => { server = makeServer();
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);

So we now have a central Mirage server that serves us in both development and testing. You can also use the makeServer function to start Mirage in development (see first part of this series).

Your Mirage code should not find it’s way into production. Therefore, depending on your build setup, you would need to only start Mirage during development mode.

Note: Read my article on how to set up API Mocking with Mirage and Vue.js to see how I did that in Vue so you could replicate in whatever front-end framework you use.

Testing Environment

Mirage has two environments: development (default) and test. In development mode, the Mirage server will have a default response time of 400ms(which you can customize. See the third article of this series for that), logs all server responses to the console, and loads the development seeds.

However, in the test environment, we have:

  • 0 delays to keep our tests fast
  • Mirage suppresses all logs so as not to pollute your CI logs
  • Mirage will also ignore the seeds() function so that your seed data can be used solely for development but won’t leak into your tests. This helps keep your tests deterministic.

Let’s update our makeServer so we can have the benefit of the test environment. To do that, we’ll make it accept an object with the environment option(we will default it to development and override it in our test). Our server.js should now look like this:

// src/server.js
import { Server, Model, Factory } from 'miragejs'; export function makeServer({ environment = 'development' } = {}) { let server = new Server({ environment, models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}`; }, }), }, routes() { this.namespace = 'api'; this.get('/products', ({ products }) => { return products.all(); }); }, seeds(server) { server.createList('product', 5); }, }); return server;

Also note that we are passing the environment option to the Mirage server instance using the ES6 property shorthand. Now with this in place, let’s update our test to override the environment value to test. Our test now looks like this:

import { makeServer } from '/path/to/server'; let server; beforeEach(() => { server = makeServer({ environment: 'test' });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);

AAA Testing

Mirage encourages a standard for testing called the triple-A or AAA testing approach. This stands for Arrange, Act and Assert. You could see this structure in our above test already:

it("shows all the products", function () { // ARRANGE server.createList("product", 5) // ACT cy.visit("/") // ASSERT cy.get("li.product").should("have.length", 5)

You might need to break this pattern but 9 times out of 10 it should work just fine for your tests.

Let’s Test Errors

So far, we’ve tested our homepage to see if it has 5 products, however, what if the server is down or something went wrong with fetching the products? We don’t need to wait for the server to be down to work on how our UI would look like in such a case. We can simply simulate that scenario with Mirage.

Let’s return a 500 (Server error) when the user is on the homepage. As we have seen in a previous article, to customize Mirage responses we make use of the Response class. Let’s import it and write our test.

import { Response } from "miragejs" it('shows an error when fetching products fails', function() { server.get('/products', () => { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");

What a world of flexibility! We just override the response Mirage would return in order to test how our UI would display if it failed fetching products. Our overall homepage.test.js file would now look like this:

// homepage.test.js
import { Response } from 'miragejs';
import { makeServer } from 'path/to/server'; let server; beforeEach(() => { server = makeServer({ environment: 'test' });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);
}); it('shows an error when fetching products fails', function() { server.get('/products', () => { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");

Note the modification we did to the /api/products handler only lives in our test. That means it works as we previously define when you are in development mode.

So when we run our tests, both should pass.

Note: I believe its worthy of noting that the elements we are querying for in Cypress should exist in your front-end UI. Cypress doesn’t create HTML elements for you.

Testing The Product Detail Page

Finally, let’s test the UI of the product detail page. So this is what we are testing for:

  • User can see the product name on the product detail page

Let’s get to it. First, we create a new test to test this user flow.

Here is the test:

it("shows the product’s name on the detail route", function() { let product = this.server.create('product', { name: 'Korg Piano', }); cy.visit(`/${product.id}`); cy.get('h1').should('contain', 'Korg Piano');

Your homepage.test.js should finally look like this.

// homepage.test.js
import { Response } from 'miragejs';
import { makeServer } from 'path/to/server; let server; beforeEach(() => { server = makeServer({ environment: 'test' });
}); afterEach(() => { server.shutdown();
}); it('shows the products', function() { console.log(server); server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);
}); it('shows an error when fetching products fails', function() { server.get('/products', () => { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");
}); it("shows the product’s name on the detail route", function() { let product = server.create('product', { name: 'Korg Piano', }); cy.visit(`/${product.id}`); cy.get('h1').should('contain', 'Korg Piano');

When you run your tests, all three should pass.

Wrapping Up

It’s been fun showing you the inners of Mirage JS in this series. I hope you have been better equipped to start having a better front-end development experience by using Mirage to mock out your back-end server. I also hope you’ll use the knowledge from this article to write more acceptance/UI/end-to-end tests for your front-end applications.

  • Part 1: Understanding Mirage JS Models And Associations
  • Part 2: Understanding Factories, Fixtures And Serializers
  • Part 3: Understanding Timing, Response And Passthrough
  • Part 4: Using Mirage JS And Cypress For UI Testing
Smashing Editorial (ra, il)

3 Data Visualization Tools — Basic to Robust

Charts and maps can increase the effectiveness and expressiveness of data. Microsoft Excel in 1985 was the first of many visualization tools to help communicate data, such as big-picture executive-level reports and detailed weekly dashboards.

Many visualization tools have emerged since then. In this article, I will evaluate three of them — Excel, Tableau, and Datawrapper — based on (i) pricing, (ii) level of training needed, and (iii) ability to generate professional-level charts quickly.

To illustrate, I’ll create the same graph on each of the three tools based on a Statista data set, below.

Ecommerce Platforms
Global Market Share
(Source: Statista)
Market Share %
April 2020
Squarespace Online Stores17.69
Weebly eCommerce2.25
SAP Commerce Cloud1.6

Microsoft Excel

Microsoft Excel is widely used for data visualization. Here is how I visualized the data after a bit of editing.

Microsoft Excel is widely used for data visualization. Its price, via Microsoft 365 Business, is affordable for most any business.

Microsoft Excel is widely used for data visualization. Its price, via Microsoft 365 Business, is affordable for most any business.

  • Pricing. Microsoft 365 Business is inexpensive compared to other tools. The price is $5 to $20 per user per month with an annual commitment. The $5 option includes Excel, Word, and PowerPoint. The higher-end versions also include Outlook, Publisher, and Access.
  • Level of training needed. Most office-type employees have at least a basic knowledge of Excel. They might not know how to create dashboards or an interactive visualization, but they are likely familiar with the process of generating charts.
  • Ability to quickly generate professional charts. The default Excel charts are outdated and tend to be cluttered, include redundant design elements and low-contrast colors, which are inaccessible for visually-impaired users. One can always customize and improve the design, however, but it requires more effort.


Tableau was founded in 2003. It quickly became a data-visualization leader and innovator. Tableau is the leading business intelligence software, with, reportedly, at 12.3 percent U.S. market share. Tableau’s software resides on a user’s computer.  There’s also a cloud-based version.

Here is the same Statista data in Tableau, visualized almost identically to the Excel version, above.

Tableau is the leading business intelligence software. The tool is robust and relatively easy to use.

Tableau is the leading business intelligence software. The tool is robust and relatively easy to use.

  • Pricing. Tableau offers three pricing options: (i) Viewer is $12 per user per month, (ii) Explorer is $35 per user per month, and (iii) Creator is $70 per user per month. Note that these prices include Tableau Desktop and Tableau Server. Desktop is the tool to build visualizations; Server is the cloud-based platform to publish and share those visualizations.
  • Level of training needed. Tableau is a drag-and-drop tool. It’s relatively easy to learn. Users can drag “dimensions” (qualitative values) and “measures” (numerical values) into the appropriate locations (for colors and shapes) and select a chart from a substantial built-in library. Tableau offers extensive, free online training.
  • Ability to quickly generate professional charts. Tableau has many more visualization features than Excel. For example, when the user drags a measure or dimension into the color mark, Tableau automatically recommends an overall color palette with appropriate contrasts. The chart templates are cleaner and better designed than Excel. Users can replicate an Excel chart in Tableau, as in my examples above. The difference is that Excel requires more time in editing and composing charts in terms of color, shape, position, and type.


Datawrapper is a cloud-based visualization tool with more features than Excel but not as many as Tableau. Here is the Datawrapper version of the Statista data.

Datawrapper is cloud-based. It has more features than Excel but not as many as Tableau.

Datawrapper is cloud-based. It has more features than Excel but not as many as Tableau.

  • Pricing. Datawrapper offers a free version that includes Datawrapper branding, such as in my example above. The Custom version, without the Datawrapper branding, is €499 per month. The price for the Enterprise version is not published; interested prospects must reach out to the company. The free version has limited design features and fewer chart types. The Custom version is more robust. The Enterprise version offers even more functionalities.
  • Level of training needed. I created the chart above in Datawrapper with no training. The process involved four steps, called “Upload Data,” “Check & Describe,” “Visualize,” and “Publish & Embed.” Datawrapper offers support via email. Among the three tools, Datawrapper was the most intuitive and required the least amount of training.
Creating charts in Datawrapper involves four steps: "Upload Data," "Check & Describe," "Visualize," and "Publish & Embed."

Creating charts in Datawrapper involves four steps: “Upload Data,” “Check & Describe,” “Visualize,” and “Publish & Embed.”

  • Ability to quickly generate professional charts. Like Tableau, Datawrapper incorporates compelling design and offers many chart and map options. All visualizations are highly customizable, although the free version is more limited than Custom and Enterprise.

Better Reducers With Immer

Better Reducers With Immer

Better Reducers With Immer

Chidi Orji

2020-06-16T12:30:00+00:00 2020-06-16T23:05:51+00:00

As a React developer, you should be already familiar with the principle that state should not be mutated directly. You might be wondering what that means (most of us had that confusion when we started out).

This tutorial will do justice to that: you will understand what immutable state is and the need for it. You’ll also learn how to use Immer to work with immutable state and the benefits of using it.
You can find the code in this article in this Github repo.

Immutability In JavaScript And Why It Matters

Immer.js is a tiny JavaScript library was written by Michel Weststrate whose stated mission is to allow you “to work with immutable state in a more convenient way.”

But before diving into Immer, let’s quickly have a refresher about immutability in JavaScript and why it matters in a React application.

The latest ECMAScript (aka JavaScript) standard defines nine built-in data types. Of these nine types, there are six that are referred to as primitive values/types. These six primitives are undefined, number, string, boolean, bigint, and symbol. A simple check with JavaScript’s typeof operator will reveal the types of these data types.

console.log(typeof 5) // number
console.log(typeof 'name') // string
console.log(typeof (1 < 2)) // boolean
console.log(typeof undefined) // undefined
console.log(typeof Symbol('js')) // symbol
console.log(typeof BigInt(900719925474)) // bigint

A primitive is a value that is not an object and has no methods. Most important to our present discussion is the fact that a primitive’s value cannot be changed once it is created. Thus, primitives are said to be immutable.

The remaining three types are null, object, and function. We can also check their types using the typeof operator.

console.log(typeof null) // object
console.log(typeof [0, 1]) // object
console.log(typeof {name: 'name'}) // object
const f = () => ({})
console.log(typeof f) // function

These types are mutable. This means that their values can be changed at any time after they are created.

You might be wondering why I have the array [0, 1] up there. Well, in JavaScriptland, an array is simply a special type of object. In case you’re also wondering about null and how it is different from undefined. undefined simply means that we haven’t set a value for a variable while null is a special case for objects. If you know something should be an object but the object is not there, you simply return null.

To illustrate with a simple example, try running the code below in your browser console.

console.log('aeiou'.match(/[x]/gi)) // null
console.log('xyzabc'.match(/[x]/gi)) // [ 'x' ]

String.prototype.match should return an array, which is an object type. When it can’t find such an object, it returns null. Returning undefined wouldn’t make sense here either.

Enough with that. Let’s return to discussing immutability.

According to the MDN docs:

“All types except objects define immutable values (that is, values which can’t be changed).”

This statement includes functions because they are a special type of JavaScript object. See function definition here.

Let’s take a quick look at what mutable and immutable data types mean in practice. Try running the below code in your browser console.

let a = 5;
let b = a
console.log(`a: ${a}; b: ${b}`) // a: 5; b: 5
b = 7
console.log(`a: ${a}; b: ${b}`) // a: 5; b: 7

Our results show that even though b is “derived” from a, changing the value of b doesn’t affect the value of a. This arises from the fact that when the JavaScript engine executes the statement b = a, it creates a new, separate memory location, puts 5 in there, and points b at that location.

What about objects? Consider the below code.

let c = { name: 'some name'}
let d = c;
console.log(`c: ${JSON.stringify(c)}; d: ${JSON.stringify(d)}`) // {"name":"some name"}; d: {"name":"some name"}
d.name = 'new name'
console.log(`c: ${JSON.stringify(c)}; d: ${JSON.stringify(d)}`) // {"name":"new name"}; d: {"name":"new name"}

We can see that changing the name property via variable d also changes it in c. This arises from the fact that when the JavaScript engine executes the statement, c = { name: 'some name' }, the JavaScript engine creates a space in memory, puts the object inside, and points c at it. Then, when it executes the statement d = c, the JavaScript engine just points d to the same location. It doesn’t create a new memory location. Thus any changes to the items in d is implicitly an operation on the items in c. Without much effort, we can see why this is trouble in the making.

Imagine you were developing a React application and somewhere you want to show the user’s name as some name by reading from variable c. But somewhere else you had introduced a bug in your code by manipulating the object d. This would result in the user’s name appearing as new name. If c and d were primitives we wouldn’t have that problem. But primitives are too simple for the kinds of state a typical React application has to maintain.

This is about the major reasons why it is important to maintain an immutable state in your application. I encourage you to check out a few other considerations by reading this short section from the Immutable.js README: the case for immutability.

Having understood why we need immutability in a React application, let’s now take a look at how Immer tackles the problem with its produce function.

Immer’s produce Function

Immer’s core API is very small, and the main function you’ll be working with is the produce function. produce simply takes an initial state and a callback that defines how the state should be mutated. The callback itself receives a draft (identical, but still a copy) copy of the state to which it makes all the intended update. Finally, it produces a new, immutable state with all the changes applied.

The general pattern for this sort of state update is:

// produce signature
produce(state, callback) => nextState

Let’s see how this works in practice.

import produce from 'immer' const initState = { pets: ['dog', 'cat'], packages: [ { name: 'react', installed: true }, { name: 'redux', installed: true }, ],
} // to add a new package
const newPackage = { name: 'immer', installed: false } const nextState = produce(initState, draft => { draft.packages.push(newPackage)

In the above code, we simply pass the starting state and a callback that specifies how we want the mutations to happen. It’s as simple as that. We don’t need to touch any other part of the state. It leaves initState untouched and structurally shares those parts of the state that we didn’t touch between the starting and the new states. One such part in our state is the pets array. The produced nextState is an immutable state tree that has the changes we’ve made as well as the parts we didn’t modify.

Armed with this simple, but useful knowledge, let’s take a look at how produce can help us simplify our React reducers.

Writing Reducers With Immer

Suppose we have the state object defined below

const initState = { pets: ['dog', 'cat'], packages: [ { name: 'react', installed: true }, { name: 'redux', installed: true }, ],

And we wanted to add a new object, and on a subsequent step, set its installed key to true

const newPackage = { name: 'immer', installed: false };

If we were to do this the usual way with JavaScripts object and array spread syntax, our state reducer might look like below.

const updateReducer = (state = initState, action) => { switch (action.type) { case 'ADD_PACKAGE': return { ...state, packages: [...state.packages, action.package], }; case 'UPDATE_INSTALLED': return { ...state, packages: state.packages.map(pack => pack.name === action.name ? { ...pack, installed: action.installed } : pack ), }; default: return state; }

We can see that this is unnecessarily verbose and prone to mistakes for this relatively simple state object. We also have to touch every part of the state, which is unnecessary. Let’s see how we can simplify this with Immer.

const updateReducerWithProduce = (state = initState, action) => produce(state, draft => { switch (action.type) { case 'ADD_PACKAGE': draft.packages.push(action.package); break; case 'UPDATE_INSTALLED': { const package = draft.packages.filter(p => p.name === action.name)[0]; if (package) package.installed = action.installed; break; } default: break; } });

And with a few lines of code, we have greatly simplified our reducer. Also, if we fall into the default case, Immer just returns the draft state without us needing to do anything. Notice how there is less boilerplate code and the elimination of state spreading. With Immer, we only concern ourselves with the part of the state that we want to update. If we can’t find such an item, as in the `UPDATE_INSTALLED` action, we simply move on without touching anything else. The `produce` function also lends itself to currying. Passing a callback as the first argument to `produce` is intended to be used for currying. The signature of the curried `produce` is

//curried produce signature
produce(callback) => (state) => nextState

Let’s see how we can update our earlier state with a curried produce. Our curried produce would look like this:

const curriedProduce = produce((draft, action) => { switch (action.type) { case 'ADD_PACKAGE': draft.packages.push(action.package); break; case 'SET_INSTALLED': { const package = draft.packages.filter(p => p.name === action.name)[0]; if (package) package.installed = action.installed; break; } default: break; }

The curried produce function accepts a function as its first argument and returns a curried produce that only now requires a state from which to produce the next state. The first argument of the function is the draft state (which will be derived from the state to be passed when calling this curried produce). Then follows every number of arguments we wish to pass to the function.

All we need to do now to use this function is to pass in the state from which we want to produce the next state and the action object like so.

// add a new package to the starting state
const nextState = curriedProduce(initState, { type: 'ADD_PACKAGE', package: newPackage,
}); // update an item in the recently produced state
const nextState2 = curriedProduce(nextState, { type: 'SET_INSTALLED', name: 'immer', installed: true,

Note that in a React application when using the useReducer hook, we don’t need to pass the state explicitly as I’ve done above because it takes care of that.

You might be wondering, would Immer be getting a hook, like everything in React these days? Well, you’re in company with good news. Immer has two hooks for working with state: the useImmer and the useImmerReducer hooks. Let’s see how they work.

Using The useImmer And useImmerReducer Hooks

The best description of the useImmer hook comes from the use-immer README itself.

useImmer(initialState) is very similar to useState. The function returns a tuple, the first value of the tuple is the current state, the second is the updater function, which accepts an immer producer function, in which the draft can be mutated freely, until the producer ends and the changes will be made immutable and become the next state.

To make use of these hooks, you have to install them separately, in addition to the main Immer libarary.

yarn add immer use-immer

In code terms, the useImmer hook looks like below

import React from "react";
import { useImmer } from "use-immer"; const initState = {}
const [ data, updateData ] = useImmer(initState)

And it’s as simple as that. You could say it’s React’s useState but with a bit of steroid. To use the update function is very simple. It receives the draft state and you can modify it as much as you want like below.

// make changes to data
updateData(draft => { // modify the draft as much as you want.

The creator of Immer has provided a codesandbox example which you can play around with to see how it works.

useImmerReducer is similarly simple to use if you’ve used React’s useReducer hook. It has a similar signature. Let’s see what that looks like in code terms.

import React from "react";
import { useImmerReducer } from "use-immer"; const initState = {}
const reducer = (draft, action) => { switch(action.type) { default: break; }
} const [data, dataDispatch] = useImmerReducer(reducer, initState);

We can see that the reducer receives a draft state which we can modify as much as we want. There’s also a codesandbox example here for you to experiment with.

And that is how simple it is to use Immer hooks. But in case you’re still wondering why you should use Immer in your project, here’s a summary of some of the most important reasons I’ve found for using Immer.

Why You Should Use Immer

If you’ve written state management logic for any length of time you’ll quickly appreciate the simplicity Immer offers. But that is not the only benefit Immer offers.

When you use Immer, you end up writing less boilerplate code as we have seen with relatively simple reducers. This also makes deep updates relatively easy.

With libraries such as Immutable.js, you have to learn a new API to reap the benefits of immutability. But with Immer you achieve the same thing with normal JavaScript Objects, Arrays, Sets, and Maps. There’s nothing new to learn.

Immer also provides structural sharing by default. This simply means that when you make changes to a state object, Immer automatically shares the unchanged parts of the state between the new state and the previous state.

With Immer, you also get automatic object freezing which means that you cannot make changes to the produced state. For instance, when I started using Immer, I tried to apply the sort method on an array of objects returned by Immer’s produce function. It threw an error telling me I can’t make any changes to the array. I had to apply the array slice method before applying sort. Once again, the produced nextState is an immutable state tree.

Immer is also strongly typed and very small at just 3KB when gzipped.


When it comes to managing state updates, using Immer is a no-brainer for me. It’s a very lightweight library that lets you keep using all the things you’ve learned about JavaScript without trying to learn something entirely new. I encourage you to install it in your project and start using it right away. You can add use it in existing projects and incrementally update your reducers.

I’d also encourage you to read the Immer introductory blog post by Michael Weststrate. The part I find especially interesting is the “How does Immer work?” section which explains how Immer leverages language features such as proxies and concepts such as copy-on-write.

I’d also encourage you to take a look at this blog post: Immutability in JavaScript: A Contratian View where the author, Steven de Salas, presents his thoughts about the merits of pursuing immutability.

I hope that with the things you’ve learned in this post you can start using Immer right away.

  1. use-immer, GitHub
  2. Immer, GitHub
  3. function, MDN web docs, Mozilla
  4. proxy, MDN web docs, Mozilla
  5. Object (computer science), Wikipedia
  6. Immutability in JS,” Orji Chidi Matthew, GitHub
  7. ECMAScript Data Types and Values,” Ecma International
  8. Immutable collections for JavaScript, Immutable.js , GitHub
  9. The case for Immutability,” Immutable.js , GitHub
Smashing Editorial (ks, ra, il)

Smashing Podcast Episode 18 With Mina Markham: How Can I Learn React?

Smashing Podcast Episode 18 With Mina Markham: How Can I Learn React?

Smashing Podcast Episode 18 With Mina Markham: How Can I Learn React?

Drew McLellan

2020-06-16T05:00:00+00:00 2020-06-22T07:05:58+00:00

Photo of Mina MarkhamIn this episode of the Smashing Podcast, we’re talking about learning React. What’s React like to work with, and how can experienced developers get started? I spoke to Mina Markham to find out.

Show Notes

Weekly Update


Drew McLellan: She is a front-end architect, conference speaker and organizer, and lover of design systems. Her work on the Pantsuit patent library for Hillary Clinton’s Hillary for America presidential campaign marked a watershed for design systems within the industry and was featured on publications, such as Wired, Fast Company, and Communication Arts. Like many of us, she writes code for a living, currently as a senior engineer at Slack. So we know she’s a talented and forward thinking developer, but did you know she was once mistaken for Patrick Swayze? My smashing friends, please welcome Mina Markham. Hi Mina. How are you?

Mina Markham: I’m smashing.

Drew: Good to hear. Now, sometimes on the Smashing Podcast, we talk to people about the subject that they’re best known for. And sometimes it’s fun just to talk about something a bit tangential. Now, I could chat to you all day about pattern libraries, design systems, the amazing work you’ve done in that particular area, and I could talk to you about subjects that you’ve perhaps spoken about, events, such as the Event Apart, things like art direction. And we could obviously talk about CSS until the cows come home. But you tweeted a few days ago, and I realized that we’re actually both in the same boat in that we’re both experienced front-end engineers and we’re both recently started working with React. So before we get onto React itself, where were you coming to up to this point? Had you been working with other libraries and frameworks for JavaScript development?

Mina: No, actually I’ve been doing mostly vanilla JavaScript for a while. And before that, of course I got into JavaScript. Let me rephrase that. I started working with Java script using jQuery because it made the most sense to me. It was something that was very easily for me to parse to figure out what was happening. And then from there I backtracked to doing just vanilla, plain JavaScript, ESX, and I hadn’t really gotten too much into the framework wars. I had no, like I had no favorite. I had no dog in the fight. I was like, “For you, React, whatever. I don’t really care.” But times change.

Drew: And in this sort of way of working with vanilla JavaScript, because I’ve done a lot of that myself as well. I’ve worked with various frameworks. I’ve done a lot with jQuery back in the day. I worked with YUI, Yahoo User Interface Library. Had you felt many of the pain points that something like React’s architecture tries to address?

Mina: I don’t think I ever had. I spent most of my career making websites versus web apps and things like that. So everything I did was pretty static up to a certain extent. So I never really had to deal with state management, things like that. So the pain points that React attempts to solve I had never really applied to the kind of work that I did.

Drew: Generally speaking, what’s the sort of nature of the projects that you’ve with React so far?

Mina: It was actually only been the one project, which I’m currently working on and I can’t give away too many details because public company and all that good stuff.

Drew: Of course.

Mina: But essentially what I’m trying to do is I’m trying to use React to, it’s a very interactive sort of product where I need people to be able to enter in and save data at a certain state and then manipulate it and generate something else with said data. And that’s just something that it’s not simple DOM manipulation at that point. It really is a lot of more complex, front-end manage of data and managing the state of said data. So there really was no other alternative but to use some kind of library that attempts to solve that problem. I knew I wouldn’t be able to get past with just plain JavaScript. I contemplated maybe handling somethings on the server side, but again, due to the very interactive nature of what I’m working with, it need to be in the client. And so we already use React at Slack for various other things. And so I was like, “Okay, well we just should go ahead and adopt the same thing that the rest of the parent the companies are using and go from there.”

Drew: One of the things that I’m always seems to be a pain point with people picking up React is getting to grips with the tool chain that’s needed to get things working, Webpack being an obvious elephant in the room. Have you had to do much configuration of the tool chain or like me if you had the luxury of teammates doing it for you?

Mina: Oh, I love the infrastructure team at Slack the data. The front-end infrastructure team at Slack, they handled all of that. I didn’t have to think about it. It was great. Because I tried to learn React before in the past. Usually the way I learn best is by actually working and implementing on things. And we use React to build a lot of hillaryclinton.com back in 2016. So it’s not like I’ve never worked with people who use it. It’s just my work never directly needed me to get involved. But that code base was very complex and very sophisticated, and there was so much happening that there’s such a barrier to entry to try to learn anything in there if you didn’t already know how React and Redux and all of that works, which I didn’t. So I wasn’t really effective in learning in that environment.

Mina: Luckily, here I do have people to like take away a little bit more of the complex bits of it. I don’t have to worry about the Webpack config at all. That’s been set up. That’s been tried and tested and ready to go. I am in a similar boat where we also use Redux in addition to React, which I didn’t realize were two different things. I didn’t know which part handled which. Dropping into a code base like that, it was a little disorienting because I didn’t realize that they were all the same thing. I had people who were seasoned React developers telling me, “Oh, we also are using Redux, which makes it a little bit harder for you to really learn what React all can do if you’re starting from scratch.” And I never quite knew what they meant by that because I didn’t know what they were talking about.

Mina: To answer your original question, I am still having a little bit more of a little bit barrier to entry, because it’s not just learning React. I’m having to learn React and also how to use the Redux store. So those two things at the same time can be a little much.

Drew: Yeah, I’ve found exactly the same thing coming into an existing code base as my first React project that uses Redux. And I think as is the nature of any of these sort of technologies when they’re young, they iterate really quickly, and what’s best practice at one point, 6 months later has moved on and there’s a different way of doing things. And when you have a code base that spans many years, you can sometimes have different styles of implementing things in there. It doesn’t always keep sync. And of course, if you’re following a tutorial or whatever to learn, you’re reading books, you’re using resources, they will be in the most modern version of how to do things. And that doesn’t necessarily nit to what you see when you look at an existing, mature product. Is that something you’d experienced at all, or have you managed to keep your code base really up to date?

Mina: I think that is something that I definitely have been experiencing. When I tried to learn how to do React on my own, I looked at various tutorials and things like that. And I noticed, or at least people have told me who have worked who have been working with me that some of the things that we do or kind of anti-pattern or not quite how things work now, because this code base is slightly, well mature us relative, but it’s a few years old. And so there are some ways that I guess are easier to do things than the way we’re doing them currently because this was written years ago. So it’s a little bit of a treadmill trying to keep up with current times and make sure I want to do things the best way, but also I don’t want to break an established code base because I want to play around with stuff.

Drew: Obviously, one of the things with React that people like you and I are coming to it, it can feel a bit jarring as this whole thing with JSX. Are you using JSX in your project?

Mina: We are. I am using JSX.

Drew: Have you made peace with that?

Mina: I fell like a little small piece of me dies every time I open one of those files. It still feels sacrilege to put my HTML in the JavaScript file. I know that’s kind of revolutionary and the whole point, but it just feels off to me that I’m writing my markup in a JavaScript file. I’ve made peace with it, but every time I do it, I’m just like, “…” Separation concerns, it is a thing. I’d like it back, please.

Drew: It’s a valid point, isn’t it? My background when I was starting to work more seriously with JavaScript, and this was probably when I was back at Yahoo, things were very much on the model of server rendered HTML pages and then taking a progressive enhancement approach, layering JavaScript on top to enhance the interface. And if the state of something in the interface needed to change, your code had to know about all the parts of the interface that it needed to update, which obviously leads you to a tightly coupled approach with these big monolithic views where the code you write needs to know about all the other code around it. And I guess that doesn’t really lend itself to a componentized approach which you would take when working with a pattern library or a design system, which is more to your area of particular expertise. I guess, React lends itself more to that approach, does it?

Mina: I think it does, especially with the being able to couple the very specific CSS to one JSX or one React component. And so that way it makes it much easier to separate or only take what you need for the library and leave the rest, whereas a pattern library or design system that attempts to do something more monolithic with just one big style CSS file or something like that, it does make it a lot difficult. You kind of have to take it all or nothing. So I do appreciate that React allows us to do more individualized, more componentized way of development, even if I still wish there was a way for me to do truly separate my presentation layer and my content layer from my interactivity layer. But maybe that’s just me being a little bit old school in that sense.

Drew: I definitely feel the pain there. The idea is that, come and correct me if I’m wrong, my understanding is that rather than separating the technologies, the CSS, and the JavaScript, and the HTML, it’s separating the functionality. So everything that is one component all exist together-

Mina: Yeah.

Drew: … which I guess is useful if that component then is no longer needed. You can just delete it, and it’s gone, and it doesn’t leave a footprint around your app. That’s not always the case with CSS though. How are you working with CSS with React? Have You looked at things like styled-components or anything like that?

Mina: No, we haven’t. I’ve heard of styled-components, but I’ve never quite really investigated them very fully to be perfectly honest. So the way that we’re working with CSS with React is we write Less, and we just have a Less file attached to each individual component that gets imported into that component. And then it gets bonded up via Webpack and served to the client.

Drew: Are you using a system like BEM or something to turn namespace?

Mina: Yeah. We’re using BEM for namespacing, although the adherence to it is kind of varied depending on who’s writing what. But we try to use a BEM namespacing pattern to make it a little bit clearer what the purpose of each individual class and component is.

Drew: And does that seem to be working successfully for you?

Mina: I think so. Occasionally it kind of has the same old problem of I sometimes don’t know how to name something. After a while daily things has always and will always be a difficult thing for master. So that’s the only issue I have with is I occasionally I have no idea what I should call a particular component.

Drew: Definitely. That’s a constant battle, isn’t it, how to out the name things?

Mina: Yeah.

Drew: I always end up when working on a new feature or something like that, you give a component and all the classes and everything the name that the feature has got at the moment. And then by the time you come to launch, it’s been renamed something else. So you have references to the old name in the code and the interface has the new name. And …

Mina: I try to always name things based on the function or the purpose of it versus things that are a little bit more ephemeral, because it’s less likely that the actual purpose of this component will change. I forgot to mention, but in addition to using BEM, I guess we use BEMITs if you’re familiar with that. It’s basically the ITCSS plus BEM, both of which were created by Harry Roberts. So I use Hungarian notation to denote whether or not something is a component, versus a layout object, versus like a larger pattern comprised of multiple components. And then from there we use the BEM convention to signify like the block element and all that.

Drew: And have you had to do much refactoring and deleting of components and things in your code base and had to deal with the issue of CSS getting left behind?

Mina: Yeah. So the non-React part of my job, of maintaining slack.com is that’s all just a bunch of Less files that are being compiled for CSS. And I guarantee you, there’s a lot of zombie code in there, because we definitely iterate above things a lot in the time I’ve been there. And we don’t always have time to go back and do the cleanup versus when we redesign a page or something. So it’s overdue for an audit, I’ll say that.

Drew: This is something that we’ve just been looking at in our React project, looking at how we approach CSS. At the moment, we have a few big, global CSS files for the whole of the app, and we do get this situation where our bundle size is just growing, and growing, and growing and never gets any smaller, even though things do get removed. So we’ve been looking at things like styled-components, Tailwind as well is another option that we’re really seriously considering. Have you looked at tailwind much?

Mina: I haven’t looked at it a lot. I’ve been curious about it, but again, I’ve never really had time to dig in to actually see if it’s something that I want to try to bring into our code base.

Drew: I was actually quite surprised, because like you, I’m a bit old school with how to do these things. I like nice separation of concerns. And I like to write my CSS in CSS, and of course the approach with Tailwind is you have all these class names, which feel a bit like inline styles that you’re applying. And if it feels dirty.

Mina: Yeah.

Drew: And I volunteered within the team, we each which took a technology to investigate if they’d be a good fit for our problems, and I volunteered to look at Tailwind because I was absolutely certain I was going to hate it.

Mina: No, no.

Drew: But it turns out I actually think it solves a lot of problems. I was quite impressed.

Mina: Yeah. I’ve sort of come around to a similar way of thinking, because I in the past would much prefer to have one class comprise all of the styles I needed for a particular component and not do a class per property, as I believe Tailwind does or languages like it do. For the similar reasons, it felt very much like, “Well, I’m just running inline CSS at this point. Why would I do this?” But as I’ve been developing more and more, inside of our Slack design system, I created a bunch of what I call utility classes that do things like add a bit of margin with a pattern. I’ve noticed that more and more, I’m using those classes in addition to the component classes. So I’m like, “Okay, well maybe I should revisit this whole to doing a CSS as a one declaration at a time.” I don’t know if I’d go that far, but it’s definitely worth considering.

Drew: Computing seems to flip flop in terms of trends between thin clients and fat clients solutions. We started with mainframes with terminals, and then the PC era with windows and office and all these sort of big applications. And they were all getting really slow, and than the web came along, and that was just a browser, and all the work was being done on the server. And it was all fast and snappy again. And now we’ve gone back to putting all that work back in the browser with everything being done with JavaScript, things like React and the JAMstack approach where we’re back to a sort of fat client. I sometimes worry that we’re asking too much of the browser. Is this a mistake? Are we asking too much of the browser trying to do all this stuff in React?

Mina: I want to say yes with the caveat of, again, my experience is very much contained to mostly static websites. I don’t do a lot of product development. So maybe in that realm, this makes more sense. But from my perspective, I feel like we’re a lot of the times using a hatchet when we just need a butter knife. I don’t know why we need put all this in the browser, put so much work and so much pressure on the client. I feel like we could do this much simpler. One of the things that always made me a little hesitant to use React, or I say hesitant, but what I mean when it made me viscerally angry and I actively opposed, was when I would go to a website and literally nothing would render because there was one error or something, Like, “Really? The entire page is broken because one function broke down?”

Mina: It just kind of annoyed me that a lot of times it was an all or nothing approach. One of the talks that I gave at AEA in the past and other places in the past was talking about how to include progressive enhancement and not just your development, but also of art direction and design of sites. And I would point out specifically examples of websites that didn’t do progressive enhancement or any kind of graceful degradation. It was like either you have the JavaScript running in the browser or you get absolutely nothing. And it would be like just a simple site that represent information about the history of web design, which was one of the sites actually talked about, the history of web design from like 1990 until now. It was a beautiful website with lots of timelines, animation of things. But it also could have been rendered statically with just a list. There were steps in between showing nothing and showing that beautifully enhanced experience that I think got lost because of the way we’ve been approaching modern web development now.

Drew: So would you say there are absolutely some categories of projects that suit a solution like React and some where it really shouldn’t be used and you should be using more traditional methods?

Mina: I think that if your site particularly is mostly static, it was just serving up information, I guess I don’t understand why you need a project like React to render something that doesn’t have a lot of interaction beyond just DOM manipulation. I guess I don’t see what benefit you get from that. Again, I may not be working on the appropriate projects. I may not just have seen or found that use case, but I’m having a hard time seeing if it’s just mostly static site, presenting content, not a lot interaction, not a lot of interaction beyond manipulated DOM and doing animations. I don’t see how having a React library helps you accomplish that goal.

Drew: It’s interesting because I’m not bad talking it because I haven’t actually used it, but I see a lot of Gatsby projects and Gatsby being a static site generator that uses a React front-end in it. And I see all the examples of the themes and things they have available are all content based sites, or blogs, and a recipe site, and a portfolio, and these sort of things. And there’s something I think actually that this isn’t necessarily the right fit for something like React. Why isn’t this being statically rendered and then progressively enhance?

Mina: Yeah.

Drew: It’s not software.

Mina: Yeah. I haven’t actually used Gatsby either. I’ve heard plenty of great things about it, but that’s probably one of the examples I would think of where I’m like, “Okay, I guess I’m just not seeing why that tool is necessary to do that particular job.” Again, I don’t know. Maybe it’s just because more people are comfortable writing in React when they are writing new something else, and it’s just providing a tool that meets people where they are. I’ve heard great things about static site generators that use React for people who have used them and love them, but it’s not a use case that I would have immediately been like, “Oh, that makes sense.”

Drew: It seems like there’s always been this battle between what we would call a website and what you might call a web app. And the chasm between the two seems to be getting wider, and wider, and wider, whereas a progressive enhancement approach tries to bridge the gap by taking something static and adding JavaScript and adding interactivity. It seems that things like React are ideally suited for software that you’re running in the browser. Would you agree with that?

Mina: I would definitely agree with that because it feels like it’s was built for that type of environment; it was built for running software. It was built by Facebook for Facebook. So it was built for a product. It was built for running whatever you call a web app in the browser and not necessarily for the type of work that, as I mentioned, I’m used to doing. So I think in those scenarios, it definitely makes a lot of sense to use it if you’re building a more complex, more sophisticated piece of software that’s meant to run inside of a browser. But if you’re building a marketing site or whatever, I guess I would still struggle to see why it will be necessary there.

Drew: So are we giving people permission to still build decent, statically rendered websites?

Mina: I would love to see more of that happen. I feel like that’s kind of gotten lost and it’s sort of lost its, if it ever was cool or whatever. I feel like we’ve lost that part of web development. It’s so funny: you and I both said that we’re kind of old school, and I laugh at that because I’ve actually been doing web development for, what, six years now? How am I old school? It hasn’t been that long for me. And yet somehow I’m part of the old guard who doesn’t like new and shiny things. I don’t get it.

Drew: So in fact React has actually existed for the whole time that you’ve been a web developer.

Mina: Maybe I just have an old soul. I don’t know.

Drew: I think that’s probably the case. I’ve not looked personally at, there are service side rendered approaches you can take with React apps. Have you experienced any of those?

Mina: I haven’t experienced any them. I briefly looked into them for the project I’m currently working on, because I feel like there’s parts of the operation that would work better on a server versus in the clients. But I think because of my limited knowledge and the fact that the code base is a little more complicated than I can understand, I wasn’t quite able to figure out how to make that part work. I would love to figure it out eventually, but I spent a day digging into it. I was like, “You know what? I’m not grokking this away I need to be. So I’m just going to back up and take a different route.”

Drew: Yeah. I think we’ve all been there.

Mina: Yeah. I went down a path. I was like, “Oh, this is dark and scary. Let’s reverse. Let’s reverse.”

Drew: Step away from the code.

Mina: Yes.

Drew: So you’ve been very diplomatic and polite about React so far. I sense that there’s some tension bubbling under the surface a bit. Come on. Tell us what you really feel.

Mina: I have been polite and diplomatic, mostly because the Reacts fan base can be a little mean sometimes, and I would rather not have them come for me. So please, React is great. It’s wonderful. Use it for what you want to use it for. I kid, but even that tweet that you mentioned at the beginning of this podcast where I think what you said is that I don’t hate it. I don’t love it, but I don’t hate it. Even that statement, I got people, there was no vitriol, but it was more they where ready to leap to the defense and say, “Well, I love it because X, Y, Z.” I’m like, “I didn’t say it was bad. I just said that I’m meh about the whole thing.” But apparently being meh is not okay. I have to love it.

Mina: So that’s why I probably have been a bit more diplomatic than I would ordinarily be, just because I don’t want people to think that I’m bad mouthing it, because I’m not. It has a place in more web development. It serves a function. It does its job well. People love it. It’s just not a tool that I’ve ever had or wanted to use until now.

Drew: Yeah. Things can get very tribal, can’t they, with people feeling like they have to take one side or another, and you’re either absolutely for something or absolutely against something? And I’m not sure it serves a good purpose, and I don’t think it really moves us forward as an industry and as a community to do that.

Mina: Yeah. It’s really odd. It’s fascinating to watch from just a sociological standpoint, but it’s often just really like weird to observe. It’s like I’m not allowed to just be, like I said, neutral about certain things. I have to have a strong opinion, which is I don’t think healthy. What’s the term, “Strong opinions, loosely held?” That’s kind of the way I go about things. I feel strongly about certain things, but it’s not like you can’t change my mind. Where I feel like some people, their identity gets wrapped up into certain aspects of it ,that if you are not for whatever they’ve chosen to identify with, it’s a personal slight versus just, I don’t care about this particular topic, or tool, or whatever.

Drew: Yes. I don’t know if it’s made worse by the fact that we all are sort of tending to specialize a lot more in particular parts of the stack. And I know there are people who are React developers. They would call themselves a React developer because that’s what they work in. And they wouldn’t necessarily write any vanilla Java script or wouldn’t use Vue or whatever. React is their world. So I guess it almost feels like an attack on their entire career to say, “I don’t like React.” Well, they’re really invested in making you like React or whatever the technology may be.

Mina: I will admit to being one of those people in the past. Actually, probably it was mostly about SASS, I believe. I was very much on the team of doing SASS as a preprocessor and all other preprocessors are trash. I don’t want to talk about them. I don’t want to deal with them. And I realized that was a very narrow way to look at things. Use the appropriate tool for the job. Whatever makes you more productive, that’s the right tool. It doesn’t really matter what it is.

Drew: Are there any technologies that we work with that don’t have that sort of tribal feel? Is there anything that people are just happy to use or not use? I can’t think of anything.

Mina: Wow. No one has opinions about markup, actually.

Drew: No.

Mina: I feel like no one has opinions about like actual HTML and just markup, just like, “It’s there.” They use it. But people have strong opinions about CSS and how it’s either terrible or wonderful, and the preprocessor wars that don’t really happen all that much anymore, and then of course, all of the tribalism within the various JavaScript libraries.

Drew: So you would say your journey so far with React is still just, “It’s a tool. It does its job?”

Mina: It went from a curiosity to active and visceral dislike because of how prevalent it was and how I unnecessary I thought that that prevalence was to meh. I’m now with meh, which again does not mean I hate it. It just means …

Drew: I think that’s a good place to be. I think we’re probably all sort of stronger as technologists if we understand the value of a particular technology for its purpose. We can evaluate what is good for what circumstance and pick the right tool for the job.

Mina: Yeah. And that’s kind of where I’ve arrived at this point in my career where I don’t get really invested in any particular language, or technology, or whatever, because it’s like, “Just whatever tool is most appropriate for what you’re trying to do, then use that.” I’ve learned that there’s a place for everything; there’s a time and a place to do everything. And up until recently, there was no real time or place for me to use this React librarian, and now there is.

Drew: I think that’s a good place to be. So I’ve been learning all about React lately as you have in the day job. Is there anything else that you’ve been learning about lately?

Mina: I’ve actually learned ironically, which is I think another language that has originated at Facebook, I’ve been doing a lot of Hack development, mostly because that’s what I use at Slack, at my day job. Learning Hack paved the way for me to get more comfortable using React because they follow very similar patterns, except one is server side and one’s not. So that, along with just in general, I’ve been learning more about the back-end and how that works for various different reasons. And I’ve been stretching myself for the past couple years and getting more and more outside of my comfortable zone. Design systems, libraries, that’s very much my world, and I feel very good and comfortable in that world. But I’m stepping outside of it and doing a lot more server side logic, and API development, and data modeling, and all of that. I’ve been doing a lot on that for the past year as well.

Drew: I find that the more I understand about the whole stack about back-end stuff in front-end stuff, each one helps my knowledge of the other. I find I write better front-end code by having written back-end code and understanding-

Mina: Yeah. I think I feel the same way. Now that I have a better idea of, like we said, the whole stack of how we get from the data to the end client. I find that I’m thinking about the entire pipeline no matter what part I’m actually working in. I’m thinking about what’s the best way to structure this API so that when I get to the template, I don’t have to do so much manipulating of the data that I receive on that end of it. It’s definitely made me overall a better engineer, I feel like it

Drew: If you, dear listener, would like to hear more from Mina, you can follow her on Twitter where she’s @MinaMarkham and find her personal site at mina.codes. Thanks for joining us today, Mina. Do you have any parting words?

Mina: Have a smashing night?

Drew: Great.

Smashing Editorial (il)

14 Marketplaces to Hire Freelance Designers, Developers, Writers, Marketers, More

Here is a list of marketplaces to hire freelance designers, developers, writers, finance professionals, social media marketers, and more. There are general marketplaces with huge pools of workers in hundreds of fields as well as specialized marketplaces focused on areas such as design, Amazon stores, and even expert consulting.




Upwork (formerly Elance-oDesk), is one of the most popular freelance marketplaces. The platform includes unlimited proposals, built-in collaboration tools, work history verification, and reviews. Categories include “Web,” “Mobile Dev,” “Design,” “Writing,” “Data Science & Analysis,” “Sales & Marketing,” and more. Browse the marketplace to find professionals, pre-packaged projects, or use Upwork staff to find the help you need. Advanced features include dedicated project assistance, project promotion, project tracking, and reporting. Price: Free to post a job. Premium service plans start at $49.99 per month.

Amazon Mechanical Turk

Amazon Mechanical Turk

Amazon Mechanical Turk

Amazon Mechanical Turk (MTurk) is a crowdsourcing marketplace enabling individuals and businesses (known as Requesters) to engage a 24/7, globally distributed workforce (known as Workers) to perform human intelligence tasks (HITs). The Requester site provides a broad set of sample templates to get started creating HITs for Workers to complete. Workers use MTurk to find assignments, submit responses, and manage their accounts. Price: 20 percent of the reward and bonus amount paid to Workers.

Jungle Scout Market

Jungle Scout Market

Jungle Scout Market

Jungle Scout Market is a marketplace that connects Amazon sellers with expert freelancers. All freelancers are prequalified and specialize in all areas of FBA and Vendor Central, including product photography, listing creation, listing optimization, product research, pay-per-click management, graphic design, coaching, legal services, and more. The marketplace is part of the Jungle Scout platform, which provides data, insights, and tools to sell on Amazon. Price: a 5-percent fee on all orders.




Fiverr is a popular marketplace, connecting businesses with freelancers offering digital services in 300-plus categories. Fiverr lets you browse the selection of freelancers, and place orders in just one click. A service on Fiverr is called a “gig.” (Originally, all gigs cost $5.) Only registered users can buy and sell on Fiverr, which also offers Fiverr Pro for higher-quality services. Price: All purchases are subject to a service fee of $2 up to $40 of purchases, and 5 percent on purchases above $40.




Gigster helps companies create custom software. The Gigster Talent Network fills development roles in under 10 days, from a group of 1,000-plus members with advanced skillsets, including artificial intelligence, machine learning, React, Kubernetes, and more. Contact for pricing.




Clarity is a community of advisors to guide entrepreneurs and their growing businesses. Search through the experts to find the right one. Set a time for the call and specify your reason. Invite up to eight others from your team to join the call. A conference line is provided. After the call, pay the expert’s per-minute rate and leave a rating and review.




Guru is another popular marketplace for freelancers, with 2 million service providers, including 500,000 developers and 300,000 designers. Post a job for free. Manage multiple freelancers for the same job in separate workrooms. Manage files, team members, communication, and payments in one place. Price: 2.9-percent handling fee. However, the fee is refunded if you pay via e-check or wire transfer.




Outsourcely is a platform for hiring remote freelancers with an emphasis on long-term projects. Outsourcely does not take a percentage of a worker’s pay, so you should be getting the most work for your cost. Engage teams in 14 primary categories, including web development, web design, video editing, writing, customer service, software development, and more. Manage workers with real-time communication, including instant private chat and live video. Outsourcely also uses a third-party work history verification system to ensure employers can review profiles. Price: Plans start at $19 per month.




Freelancer claims to be the largest freelancing and crowdsourcing marketplace by the number of users and projects, connecting nearly 45 million employers and freelancers from over 247 countries. Hire freelancers to do work in areas such as software development, writing, data entry, and design — as well as engineering, sciences, sales and marketing, accounting, and legal services. It’s free to post your project. Use the desktop app to track progress, monitor hours, and communicate. Use the mobile app for on-the-go messaging and updates. Release payments according to a schedule of your goals, or pay only upon completion. Price: 3 percent of the job (fixed rate or hourly).




Toptal, a derivation of “top talent,” focuses on working with freelancers who are experts in their fields. Each applicant to the Toptal must pass a screening process (two to five weeks to complete) to measure expertise, professionalism, and communication skills. The network offers expert designers, developers, financial analysts, project managers, product managers, and more. Contact for pricing.

Envato Studio

Envato Studio

Envato Studio

Envato Studio, part of the Envato network that includes ThemeForest and Tuts+, is a freelance marketplace of hand-picked designers, developers, and digital talent — for logo design, web development, video production, and more. Compare prices, portfolios, and community recommendations to find the expertise you need. Manage your job with inbuilt messaging and job management tools. Quickly purchase Express Jobs, offered by freelancers and agencies for quick installation without customization. Price: Envato Studio does not charge a processing fee on top of the freelancer’s invoice.




99designs is a platform to find designers in logo and brand identity, web and app design, advertising, and more. You can run a contest with fixed-priced packages and pick your favorite design. You can also hire a designer from over 90 skillsets. Filter designers by category, level, recent activity, and search terms. Price: 5-percent platform fee.




DesignCrowd is another design marketplace to run a contest or search freelancers for hire. The platform hosts over 800,000 designers. Set project packages with a budget starting from $99 and turnaround times for as little as three days. DesignCrowd includes a money-back guarantee for design contests. Price: 4-percent transaction fee and a posting fee up to $129.




Textbroker is a marketplace for freelance writers. Outsource product descriptions, blog posts, press releases, social media posts, news stories, and technical articles. Add your target keywords to the order dashboard. Create an open order available to over 100,000 writers, commission an author with a direct order, or use a team order for hand-picked practitioners. Price: Starts at 1.5 cents per word.

A 4-step Plan for Video Marketing Success

Videos are a potent way for ecommerce businesses to build lasting, profitable customer relationships.

YouTube, for example, reaches more viewers on mobile devices alone than the total U.S. audience of any television network. Overall, in 2020, more than 2 billion logged-in users visit YouTube each month, according to the company’s press page.

Add to this the growth of other video platforms, including Facebook, Instagram TV, and TikTok.

What follows are four steps — before you film — for successful video marketing.

1. Set Goals

Content marketing offers a lot of room for creativity. But it is not shooting fun videos with friends or trying to be an amateur filmmaker. It is the act of promoting a business, encouraging sales, and generating profit.

Your content marketing should have a defined goal, including key performance indicators.

For example, maybe your videos are meant to develop an audience on YouTube or Instagram, as more subscribers could mean more shoppers.

As an example, Michael’s, an omnichannel craft-supply retailer, has roughly 230,000 YouTube subscribers. The company’s videos include links to the products mentioned in the video. If she likes the project being described, the viewer is likely to click the link and purchase products.

In the example below, Michael’s might be using the number of YouTube subscribers as a KPI. The company could also add tracking code to the link in the YouTube description and learn how often those clicks generate a sale. Finally, Michael’s could monitor watch time (the number of minutes users spend on their videos) as a KPI of engagement.

Michael's includes a product link in the description for many of its videos on YouTube. The company can track KPIs such as subscribers, video watch time, and clicks.

Michael’s includes a product link in the description for many of its videos on YouTube. The company can track KPIs such as subscribers, video watch time, and clicks.

2. Understand the Audience

Understanding your audience is especially important with content marketing. Consider, for example, two articles unrelated to ecommerce.

The first article, “Planning a Summer RV Vacation: For Airstreamers or Anyone,” was published on June 9, 2020, on the Airstream blog. It is content marketing for Airstream, the travel-trailer brand. The audience is likely to be recreational-vehicle enthusiasts. The article offers several tips for planning an RV vacation in light of the recent Covid-19 pandemic.

“Start planning your summer camping trip now so you’ll be ready once restrictions lift in your area. We’ll walk you through destinations, packing, and more,” the article begins.

The Airstream blog's audience is made up of folks who enjoy recreational vehicles.

The Airstream blog’s audience consists of folks who enjoy recreational vehicles.

The second example, “When Work From Home Means Working From an RV,” was published on June 8, 2020, in The Wall Street Journal. Its readers are likely to be investors who might want to buy stock in Thor Industries, which makes Airstream.

This article explained how the pandemic has the potential to increase Airstream sales as some buyers try to use Airstreams as home offices or seek travel alternatives to airplanes and hotels.

The Wall Street Journal's audience is investors and business professionals who might be interested in the market for RVs, not vacations.

The Wall Street Journal’s audience is investors and business professionals who might be interested in the market for RVs, not vacations.

Now imagine if these two articles were switched. What if Airstream has published the investor-focused article on its blog? It would not have been as meaningful for vacation-planners.

3. Identify Topics

Once you know the audience, start to identify engaging topics. There are a few ways to do this.

Keyword research is a foundational tactic for search engine optimization. It’s also helpful for understanding what your audience searches for when you’re trying to identify content topics.

Use your intuition. If your ecommerce store specializes in, say, restored antique axes, hatchets, and tomahawks, you will probably be safe trusting your intuition when it tells you to make videos about ax making and repairing.

Similarly, if your ecommerce store sells spices, sauces, and rubs for barbeque, you might want to take an idea from “5 Content Marketing Ideas for July 2020,” my recent post, since your intuition is that your audience might be interested in a backyard vacation centered on grilling.

If your business sells products for barbeque, a video about planning a backyard vacation that includes grilling makes sense for your audience.

If your business sells products for barbeque, a video about planning a backyard vacation that includes grilling makes sense for your audience.

Focus on your products. Sometimes those products can spark compelling content marketing ideas.

4. Create an Editorial Calendar

Imagine an online store that sells automotive parts and accessories. The company’s audience is do-it-yourself vehicle owners who love their cars and getting their hands dirty.

This auto parts store has decided to launch a video series called “Quick Automotive Tips,” wherein a professional mechanic offers advice for tackling specific maintenance tasks.

If the store wanted to release an automotive tip each Friday, it would need to plan the video, prepare the script or at least make a list of topics, and include time to edit. Thus, showing up at a shop on Friday morning and interrupting a mechanic won’t do.

What’s more, it could make sense to record several videos at a time. But doing that requires a schedule of when each video will be released. You can plan for a few weeks or even a few months.

I’ve addressed planning and scheduling content, at “Developing a Content-marketing Editorial Calendar for Ecommerce” and “Manage Your Business Blog with a Kanban Board.”

See “A 5-step Plan for Video Production and Distribution.”