emGee Software Solutions Custom Database Applications

Share this

Web Design

How To Stop Analysis Paralysis With Design

Smashing Magazine - Mon, 11/11/2019 - 02:30
How To Stop Analysis Paralysis With Design How To Stop Analysis Paralysis With Design Suzanne Scacca 2019-11-11T10:30:00+00:00 2019-11-11T11:16:28+00:00

As a web designer, you do your best to remove friction from the decision-making process. You place only one CTA above the fold. You keep interactive elements to a minimum. You make the menu only as large as it needs to be.

But what happens when the content itself causes analysis paralysis?

There’s an overabundance of choice all around the web, from e-commerce stores with thousands of products to content generation machines pushing out new posts every day. While you can’t do anything to stop the flood of information or items going out to your visitors, you can design your interfaces in a way that makes the decision-making process easier to bear. What’s more, you can help them walk away feeling more confident with their choice, too.

Let’s look at what it is about the psychology of choice that can be detrimental for conversions and what you can do to keep your PWA visitors from succumbing to it.

Why Analysis Paralysis Is Hurting Your Conversion Rate

Paralysis by analysis is what happens when someone finds a situation or decision too overwhelming or difficult. Despite thinking over the circumstances or options, they’re unable to make a clear choice, often leading to no action at all.

It’s the exact opposite of what we want to happen with our visitors and customers. And, yet, we see it all the time.

Take Amazon, with its hundreds of millions of products. Let’s say a shopper is looking for socks for an upcoming snowboarding trip. So, they search for “snowboard socks”:

A search for “snowboard socks” on Amazon yields 728 results. (Source: Amazon) (Large preview)

There are 728 matching results for snowboard socks. While that’s nothing compared to the size of Amazon’s marketplace, it’s still way too many results to sift through on one’s own.

So, the shopper decides to narrow their search down to “knee-high snowboard socks antimicrobial compression”, which hits all of the key features they’re looking for:

A search for “knee high snowboard socks antimicrobial compression” on Amazon yields 8 results. (Source: Amazon) (Large preview)

That takes the list of 728 products down to a more manageable 8. However, there are a number of problems with this.

For starters, Amazon doesn’t actually present only eight options. The first thing it shows is a banner with sponsored results:

Amazon displays sponsored products on a search results page before organic products. (Source: Amazon) (Large preview)

The next two rows do contain organic search results. However, the products either don’t have any reviews or high enough ratings to rave about.

To make matters worse, Amazon adds three more rows of sponsored products to the end of this page:

An Amazon search results page promising 8 results is full of sponsored products. (Source: Amazon) (Large preview)

Essentially, Amazon has tripled the number of products the shopper has to look at now. Not only that, but one could argue that it’s polluted the search process with so many paid products.

It’s just a poor experience all around.

It’s a similar story on mobile. The main difference is that, when the narrow search is applied, only five results remain. That said, Amazon continues to muddle search results by prioritizing sponsored posts. This is what the shopper sees above the fold:

Amazon search results display only sponsored products above the fold on mobile. (Source: Amazon) (Large preview)

Once the shopper scrolls, they’ll see two organic products (with no ratings, much less) before being shown yet another sponsored product:

Amazon fills mobile search results with paid product listings. (Source: Amazon) (Large preview)

What should have been a succinct product search page ends up running on and on with sponsored listings and Amazon recommendations. As you can imagine, this is an even bigger problem for mobile shoppers who don’t have the patience or time to waste.

How To Simplify Decision-making With Design

Psychologist Barry Schwartz gave a TED talk on this exact problem and explained how it doesn’t just lead to abandoned purchases, but to less satisfying purchases.

Essentially, Schwartz argues that too many choices cause consumers to:

  • Have too-high expectations whereby no option ever seems perfect or satisfying.
  • Focus on minute details or features they missed out on by not making a different choice.
  • Regret the option they settled on even if it proved to be the best.
  • Blame themselves for spending too much time analyzing a decision and still making the “wrong” choice.

In other words, an abundance of choice puts your audience in the wrong state of mind. And if your site or PWA can’t afford to process returns or watch visitors walk away at a rate that a company like Amazon can, then you can’t let paralysis analysis become part of the decision-making process to begin with.

Here are some things you can do to make decision-making more bearable, even with too many options available.

Prioritize Your “Big Rock”

There’s a productivity hack called the “Big Rocks” method. Essentially, it says that if you want to get more stuff done, you have to take on your biggest challenge or priority first thing. All of the smaller tasks and requests nagging at you get slotted in once you’ve tackled the most critical ones.

And now I’m suggesting you do something similar with your design.

Basically, what you want to do is this:

  • Look at all of the “stuff” you’re trying to put in front of your visitors.
  • Ask yourself (or your client): “Which one takes top priority right now?”
  • Then, stick it to the top of your home page.

Why do this? Well, for starters, it’s much less overwhelming to show one thing than to throw everything you have at your visitors right away — or to force them to dig around and figure out where to start. Plus, chances are good that there’s something especially pressing you want every visitor to see.

BarkShop shows us one way you might do this:

The home page of the BarkShop website displays a Halloween sale banner. (Source: BarkShop) (Large preview)

Notice how the top of the page isn’t littered with an inventory. Instead, the primary focus is on the Halloween sale.

This is clearly BarkShop’s big rock right now. If they don’t get their Halloween items out the door by October 31, they run the risk of losing money on the seasonal inventory. And while they could leave it up to their visitors to assume there are Halloween toys and treats available, why do that?

It’s hard enough showing up on a site like this and deciding what you’re going to buy for your dog this month. So, let your big rock become their guide.

You can see that it’s not just about the Halloween line either. Just below the banner, BarkShop has prioritized its top-trending toys. This is another trick you can use when designing product inventories and news sites. Display the most popular or top-rated/shared items first. There’s a greater likelihood they’re going to click on something that others have shown interest in than a bunch of random items they have to explore on their own.

Another way you might tackle big rocks in design is to go the way of Apple:

The Apple home page banner advertises only its iPhone 11 Pro. (Source: Apple) (Large preview)

Again, Apple could’ve shown a bunch of its iPhones and iPads here or pointed visitors to different categories of products and accessories to explore. Instead, it’s put its big rock right up front: the iPhone 11 Pro.

Sure, there are probably plenty of Apple customers who come here looking for older models. But what makes more sense?

  • Showing a bunch of similar-looking smartphone graphics that visitors are immediately put into analysis paralysis mode with?
  • Or showing them the latest model that everyone wants?

You can do this with other kinds of websites, too. Blogs, for instance, will use the sticky post feature to show off their “big rocks” to every visitor who stops by. This might be the most popular post of all time or it could be something relevant to something happening at the moment.

Whatever it is, there’s a conscious decision made to stop visitors in their tracks and give them a moment of calm before they have to enter decision-making mode.

Gate Off the Choices

While you want your visitors to know that there’s a plenitude of things available, you don’t need to tell them how much there is. It’s only going to add to the pressure of the decision-making process.

So, whenever you can, gate off the choices.

eHealth Insurance is a website where Americans can purchase health insurance for themselves or their companies. With a wide variety of healthcare providers and dozens of plans available for each, a service like this is necessary for insurance-wielding U.S. citizens.

The eHealth Insurance website gates off its insurance provider options and plans. (Source: eHealth Insurance) (Large preview)

The only decision it asks visitors to make is what kind of insurance they’re looking for. It then asks them to fill out a simple enough form. It’s what eHealth Insurance uses to pare down the options:

The eHealth Insurance form asks qualification questions of visitors to help list the right options. (Source: eHealth Insurance) (Large preview)

Once filled out, eHealth Insurance shows the user a list of providers and plans that are available in their area. This keeps the consumer from having to:

  1. Visit individual health insurance websites to do their own research.
  2. Sift through hundreds of options all at once (some of which they’d probably be ineligible for and others that would just be a bad fit).

Websites like these typically allow you to compare up to three items at once, making the decision-making process even simpler.

Another way to gate off your choices is by asking visitors to start narrowing their choices from the moment they arrive as Sotheby’s International Realty does:

The first thing the Sotheby’s International Realty PWA asks visitors to do is narrow down their search results. (Source: Sotheby’s International Realty) (Large preview)

This way, consumers aren’t distracted by all the great-looking properties or even the attractive prices. They’re still focused on taking action (e.g. finding a rental), but it’s more about taking baby steps towards the desired result which makes it much less intimidating. It’s also going to lead to a more satisfying result in the end as they won’t spend time looking at rentals they can’t afford, that don’t allow cats or that are too far away from their kids’ schools.

Sotheby’s helps visitors narrow their searches by location. (Source: Sotheby’s International Realty) (Large preview)

The next page of the Sotheby’s search process starts to show matching results, but not before letting them know that there are “55 Luxury Homes for Rent in London”. And if that number is just too much to handle, that’s fine. Directly to the right of that note is a filters widget.

Sotheby’s helps visitors narrow down their choices even further with comprehensive filters. (Source: Sotheby’s International Realty) (Large preview)

Sotheby’s filters are great. Not only are all the essentials covered, but it’s even divided up the filters by category.

Let’s recap how smooth this experience is going to be for already-anxious home-buyers or renters:

  • The first thing they see on the Sotheby’s home page is a search bar.
  • If they do the search, the next thing they see is the number of properties in the area.
  • If that number is too intimidating, the filters widget is there to help them narrow the list even more.

By keeping the rentals off of the home page and even away from the top of the fold of the internal page, Sotheby’s can control how calmly visitors go through the decision-making process.

Enable Side-by-side Comparison

Internally, there’s not a lot you can do about choice overload except giving your visitors a really great set of sorting and filtering tools. Even then, once they start to see lists of related products, recommendations on previous purchases and so on, the analysis paralysis is going to creep back in.

One thing you can do to make this less stressful is by including side-by-side comparisons.

It’s similar to laying out pricing plans side-by-side. Rather than make prospective customers review their options one-by-one, stack up the top few choices. Then, align the specifications so it’s as easy as looking across a row to weed something out because it doesn’t fit the budget or the product is too large.

Although Amazon doesn’t handle analysis paralysis flawlessly, I do like what it does with its side-by-side product comparisons:

Amazon shows a table of similar products to customers for easy comparison. (Source: Amazon) (Large preview)

I can’t tell you how many times I’ve struggled to make a decision on Amazon, only to discover one of these comparison tables and immediately been able to make up my mind. It’s just so much easier to see a bunch of lookalike products all at once and to say “This one definitely won’t fit in my kitchen” or “That’s the exact color I’m looking for”.

You can do this with other kinds of websites, too. Verizon Wireless, for example, uses a side-by-side comparison to make choosing between its plans easier.

Verizon Wireless displays the details for its 2GB wireless plan. (Source: Verizon Wireless) (Large preview)

There are scroller dots below this block that indicate to customers that there’s more to be found. All they have to do is scroll to reveal more plan options. And because the scroller breadcrumbs are kept to a reasonable amount, this doesn’t seem like that burdensome of a task.

The next block over, for instance, contains the information for the 4GB plan:

Verizon Wireless displays the details for its 4GB wireless plan. (Source: Verizon Wireless) (Large preview)

Even though the specs can’t be seen see side-by-side, the details are simply broken down and are consistently laid out. So, when someone moves from plan to plan, the same details are in the same place which makes flipping back and forth quite easy.

Another thing I really like about this is the summary provided at the top of each card. The 2GB one tells customers right away that it’s the best plan if you mostly talk and text whereas 4GB is better if you stream a lot of content and surf the web. This way, if all the technical details don’t mean much to customers, the layman’s summary will help them more confidently decide.

While I realize side-by-side comparisons might be something you’d normally try to avoid on mobile screens, these two examples show that it is possible to do so without introducing too much friction to the experience.

Wrapping Up

As I said before, you can’t do anything about scaling back the multitude of options your clients want to present their audiences with. If they want to sell thousands of products to customers that are demanding them, then good for them.

That said, the way you design around these options can have an impact on how well or poorly they’re received. Just remember what Barry Schwartz teaches us about the psychology of choice. If your visitors, users or customers walk away feeling overwhelmed, drained or disappointed with the experience, it’s going to cost you. So, be mindful of how much you present the options to them.

(ra, yk, il)
Categories: Web Design

What Newspapers Can Teach Us About Web Design

Smashing Magazine - Fri, 11/08/2019 - 03:30
What Newspapers Can Teach Us About Web Design What Newspapers Can Teach Us About Web Design Frederick O'Brien 2019-11-08T11:30:00+00:00 2019-11-11T11:16:28+00:00

It’s easy to get caught up in the latest trends in web design. Web technology is constantly improving, and today developers have a formidable range of features at their disposal. This makes for a forward-thinking, innovative space — as it should — but also one at risk of being unrooted. Every art has its ancient masters. In the case of websites, it’s newspapers.

When you dig into the basic principles of news design, overlaps with the web are frequent and oftentimes indistinguishable. Many web design best practices can be traced directly back to news design. When it comes down to it, websites are made for users to engage with, and hopefully return to. Newspapers have been playing that game for centuries, and winning.

Anyone with even a passing interest in web design stands to benefit from knowing how news design works, and why it works. This piece will examine several tenets of newspaper design and show their connection to best practice online. At the core of that connection is a principle childlike in its simplicity, one newspaper and web designers alike would do well to remember.

Hold The Home Page

Newspapers have been around since the 17th century. They’ve worked hard for their rules, and because their content changes daily the rules have to be abstract. Ninety-five percent of what we see in any given newspaper will not be there the next day. It is what don’t see that is essential for wrangling the contents of newspapers into shape.

This framework is what we’ll be looking at; some of the invisible rules that hold newspapers together. They are concerned mainly with form, and how readers process information. The parallels with web design will soon become clear, and hopefully the lessons too. Let’s start with an obvious one — above the fold.

Above The Fold

If you’ve worked on the web you’ve likely heard the phrase ‘above the fold,’ meaning the content you’re met with when you land on a web page. It is a newspaper term, and it dates back centuries. Due to their size newspapers are often stacked folded in half, so above the fold literally means the content visible above where they’re folded in half. It is the first thing potential readers see. It is often the one and only chance to make an impression, to get people to buy a copy because they just have to know more. If the newspaper isn’t worth picking up for the front page, what reason is there to think it’s worth picking up at all?

I’d buy that for a dollar! Credit: The New York Times. (Large preview)

The space above the fold is the domain of the lead story, the most important piece of information in the entire paper. It has to hook the reader. This usually equates to big headlines, key pieces of information, and striking imagery. That said, there is not a rigid format. Whatever grabs people’s attention without distorting the truth is on to a winner.

Above the fold is a newspaper’s first and most important answer to ‘the pub test’ — what you’d blurt out if you were telling someone the crux of the story in the boozer. If you had the chance to tell your friends men walked on the moon yesterday, you probably wouldn’t open with the brand of shoes involved. You’d sprint in and yell, “Men have walked on the moon!” That’s above the fold. It’s where newspapers condense the most important story (or stories) of the day to the key points.

The same applies to websites, which no doubt is why the terminology has carried over. ‘Above the fold’ in web design (which online means what you see before scrolling) is the website’s answer to the pub test. What’s the single most important thing people should know? Though this is particularly relevant to home pages, it applies everywhere.

Three guesses what Apple wants you to know about right now. (Large preview)

According to a study of 25 million browsers last year, ‘above the fold’ is comfortably the most viewed part of a web page, with engagement peaking just below. From news to ecommerce to social media, the same principle applies: get to the point.

If you’d like to read more above the fold and front pages generally, Newseum’s Front Page poster is a good place to start.

The Gutenberg Principle

So you’ve grabbed someone’s attention. Congratulations. You’ll need to know about the Gutenberg Principle — or Z-pattern. Championed by ‘the father of newspaper design’ Edmund C. Arnold (more on him later), the Gutenberg Principle is a good rule of thumb to follow when thinking about how people engage with a page of content, be it paper or pixels.

The Gutenberg Principle states that when faced with homogenous content, we start at the top left hand corner and finish at the bottom right hand corner, flicking from right to left as we go. This stems from an idea called reading gravity. We in the western world spend our lives reading from left to right, flicking down and to the left to get to the start of the next line. Newspaper design tends to ape that flow.

The Gutenberg diagram, courtesy of Steven Bradley. (Read his Smashing Magazine article here) (Large preview)

Take the New York Times front page shown earlier for example. Your eyes zig-zag with each line. Where does your eye flick after ‘PLANT FLAG’? Almost certainly to ‘Voice from Moon.’ Breaking this flow tends to be jarring for readers because it’s at odds with a lifetime of reading habits. How often do you see the lead story hugging the right hand side of the page rather than the left? Not often.

The same flow applies to web design. Steven Bradley’s Smashing Magazine article on compositional flow and rhythm explores the principle in an online context, and certainly deserves a read, but I would add that there’s huge value in looking at its application in print. This is a principle that was being applied for decades before the world wide web came along, after all. Any given shortlist of Society for News Design finalists will be a masterclass in content flow. Here are some recent winners to whet your appetite.

Now to be clear, reading gravity isn’t quite as binding as, say, gravity. The eagle eyed among you may have noticed the qualifier that this applies mostly to ‘homogenous’ content. What’s more, it isn’t based on something innate in human nature — it’s guided by language. In languages that read right to left (Arabic for example) the same principle applies, but it is flipped.

Right-to-left languages provide a mirror image of western newspaper layouts. Credit: Tarek Atrissi Design. (Large preview)

This mattered less in the day of print. Papers were generally limited to a geographical region and could reflect the primary language of that region’s audience. In the online realm anyone, anywhere could be visiting your website, so it’s not only valuable to understand the Gutenberg Principle, but to design websites that change shape depending on the language they’re being read in.

(Large preview) Al Jazeera flips its content based on the language it’s viewed in. (Large preview)

The Gutenberg Principle is not the only way people engage with content. Eye tracking studies have shown F-shaped patterns are also common online, for example, with more and more ‘hopping’ the further down the page readers go.

These patterns are all useful to know. They are not rules, just trends. Strong news design does not blindly adhere to the Z-pattern come what may; it uses it as a foundation. The same is true for web design. If in doubt, remember it, but don’t worship it. The human eye has an ingrained reading gravity, but great design leads rather than follows.

The adaptability of the web opens up amazing new possibilities for content presentation. The lessons of the Gutenberg Principle are starting points which can and should be played around with. The best rule breakers usually know exactly what the rules are.

For more information on the Gutenberg Principle follow the links below:


Every newspaper has a nameplate. It’s just about the only thing you can guarantee won’t change from edition to edition. It’s the bit at the top (or very occasionally, along the side) of the front page, and comprises of the publication’s name and logo.

A lot of these are iconic in their own right. The nameplates of publications like The Washington Post and The Sun are seared into the public consciousness. Nameplates are the branding, the bit that says, ‘We’re not that other newspaper. We’re this newspaper.’ It communicates who you are and what you’re about.

It also serves as a kind of directory. Newspapers often have teasers in their nameplates, pointing readers to stories that don’t quite warrant a spot on the front page, but are still worth knowing about. It’s a key player in the above the fold game. Stick around. Keep reading. There’s something here for you. Keeping in mind the Gutenberg Principle, the nameplate is likely the very first thing readers will see.

Newspapers and websites alike understand the value of nameplates for both branding and navigation. (Large preview)

Practically every website has a nameplate, only on websites we call it the header. Smashing Magazine has one, Amazon has one, Facebook has one. It’s weird for a website not to have one, and for it not to appear on every page. On the web every page has to have a bit of the front page about it. A lot of users arrive at a site via the root domain, but a lot don’t.

This is one reason why nameplates online tend to be busier than their print elders. They are able to do more, which is just as well given more is asked of them. But in news and web design the underlying purpose of the nameplate is the same: get the brand front and centre and guide users to something they’ll care about.

Grid Systems And Content Blocks

Newspapers are pure content. From cover to cover, they are packed with information, information which needs to be well organised and well presented. The grid system is foundational to newspaper design. As water shapes itself to a bowl, news content shapes itself to grid systems.

Columns are the most important element of this. Depending on a newspaper’s format (tabloid, broadsheet, etc.) it might have anywhere from four to fourteen columns. It is rare for the content of newspapers not to shape themselves to these columns one way or another. Text flows down a column then resumes in the next one. Images can span multiple columns, especially if they’re eye-catching.

Early publications, like this 1905 edition of Norwegian newspaper Dagbladet, often stuck very closely to their grid systems. (Large preview)

Newspapers have evolved beyond the strangely rigid stream of consciousness affairs you’ll find in earlier efforts like those above. Now it is generally accepted that newspaper content should be organised in blocks, with each story forming its own box. This is called modular layout, and there are several reasons why it is the standard.

First, it is easier to organise. If every story fits in a clean, tidy space, they can be rearranged with relative ease. When you’re trying to fit dozens (or hundreds) of stories into a finite space with the clock ticking, this is a godsend.

Second, it is clearer. Good information is only worth so much when it’s presented badly. Blocks create pages within pages, where each piece of information is distinct and easy to follow.

Modular layout in action in The Guardian. (Large preview)

These standards have always played a role in web design, but they are particularly useful to understand now we have CSS Grid at our disposal. Not only do newspaper grid systems offer guidance for arranging content neatly and clearly, they show how content blocks interact with each other, and with advertising. The wrong alignment can look very silly indeed, while the right arrangement is a joy to read.

As ever, there are differences. For example, online there are rarely jumps (when you reach the bottom of a column and continue reading at the top of the next one) because web pages can go down indefinitely. This kind of layout generally makes less sense online because it leads to readers scrolling up as well as down to get through a single piece of content, which is pretty counterintuitive. As Rachel Andrew demonstrates, jumps can be just the thing for listings and small amounts of content, but the practice is generally a product of print’s physical limitations. The main value of jumps in web design may well be for stacking blocks of content, rather than organising copy.

What’s more, both in print and online abandoning the grid system can be striking in its own right. Just as Dada art recoiled from aesthetic norms of the early 20th century, so do brutalist websites invert the grid system to offer something more… unconventional.

A Dada print by Dutch artist Theo van Doesburg. (Large preview) Yale School of Art sticking it to the man, man. (Large preview)

As noted already, to break the rules first you need to know them. For this and everything else, Tim Harrower’s The Newspaper Designer’s Handbook is a superb place to start. For a more sweeping introduction, Carrie Cousins’ Utilising Grids in Print Design over at Design Shack is excellent.

And how much does this all matter when you move over to the web? Well, more and more. CSS properties like Grid, Shapes, and Flexbox makes it easier than ever to both follow and break the rules of the grid system. Just as newspapers routinely venture outside the invisible lines of their wireframes, so too can websites push the boundaries of their own medium.

In his book Art Direction for the Web, Andy Clarke dives head first into the lessons of print media (and others), showing how advances in CSS can add whole new dimensions to the grid system. As Clarke himself puts it: For years we’ve told each other the web isn’t print. We’ve told ourselves the things we admire in other design media cannot — and sometimes should not — be used online. We needn’t think that anymore.

Hear, hear.

For more inspiration, watch Jen Simmons live code a print layout in CSS Grid at Smashing Conference 2019. Beautiful. And for a more in-depth history of the grid system and its usage, check out this ‘Grids Are Good’ presentation by Khoi Vinh and Mark Boulton.

Look Forward… But Look Backward First

The conventions above were forged by decades — in some cases centuries — of experience, and there’s plenty more where they came from. What they all essentially boil down to is understanding content, and how people are likely to engage with that content.

Newspapers at their best follow a cartoonishly simple principle: present information in ways that are as clear, as attractive, and as accessible as possible. That’s a worthy goal for any website. And don’t take my word for it. These ideas were championed by Edmund C. Arnold, the aforementioned father of modern newspaper design.’ Arnold designed or redesigned hundreds of newspapers during his career, including The Chicago Tribune, The Boston Globe, The National Observer, and Newsday.

Edmund C. Arnold, ‘the father of modern newspaper design.’ Credit: Josh Meltzer/The Roanoke Times. (Large preview)

He pushed for designers to have more influence, for newspapers to have flair as well as substance. He was also a journalist, and an academic, and wrote numerous books about newspaper design and typography. He knew his stuff. It is no coincidence that the Society for News Design (SND), of which he was a founding member in 1992, now holds two awards each year — one for news design, the other for digital.

Anyone keen to learn more about Arnold and his work could do a lot worse than starting with the resources below:

Newspaper designers are students of the web — so too should web designers be students of newspapers. As improvements in web technology open up new frontiers, it pays to know whether someone else has been here before. We are all looking for the same thing, after all. It’s all, fundamentally, the same language.

You can see this playing out in real time as newspapers adapt to the web. The gold standard of news design online at the moment is probably The New York Times, which was a finalist in the print and digital SND awards this year. What’s interesting about the Times online is the blend between classicism and innovation. The homepage still essentially looks like the front page of a print edition, while individual stories, like ‘The Plot to Subvert Democracy’, immerse themselves in the new possibilities of the web.

The New York Times blends best practice of news and web design to make something entirely new. (Large preview)

Or take a newspaper designer like Mario García — part of the generation after Edmund — who’s most recent book, The Story, was designed to be read on mobile phones. The best news designers relish change. The proof is in the pudding. (For those interested, García blogs daily about the overlap of news and web design.)

This, in a lot of ways, is the main takeaway of news design. Its top practitioners are not dogmatists — they are students. When asked at the twilight of his career what his advice was to the next generation of designers, Edmunc C. Arnold’s answer was not a series of rules. It was far simpler than that: know where you came from.

My message to young designers is this: look, kids, you can do better, but the only way to achieve your potential is to go back to — and understand — the basics. That sounds boring, but it’s reality.

Newspapers don’t hold all the keys to great web design, but understanding the principles that guide them can only benefit web designers. There are plenty of kindred spirits in those two worlds. I’m no web designer, but I recognise good web design when I see it in part because of what I know about newspapers. Purpose and style has a way of looking, well, stylish.

Web design guru Jeffrey Zeldman hit the nail on the head when he tweeted this more than a decade ago:

Content precedes design. Design in the absence of content is not design, it's decoration.

— zeldman (@zeldman) May 5, 2008

Vitaly Friedman was bowing to the same altar when he said, “Good design is about effective communication, not decoration at the expense of legibility.” Both he and Zeldman would find plenty of allies in the news design space. Few, if any, mediums have a richer history wedding content and design than newspapers do. That struggle is all they have.

To The As Yet Unimagined

It’s worth reiterating here that there are clear and undeniable differences between news design and web design. In newspapers the dimensions of the space are always the same, while websites must adapt to radically different screen sizes and devices. In newspapers what you see is what you get, while websites can hide all sorts of useful features out of sight until they’re prompted to appear. The aim of this piece is not to convince you that news and web design are the same. They are, however, often very similar. To be master of one does not make you master of the other, but it helps.

Perhaps this is why Friedman collated a selection of award-winning newspaper designs all the way back in 2008. Back then he rued the fact that print techniques weren’t applicable online. Back then CSS wasn’t sophisticated enough. Well, its is now, and that’s really exciting.

The process never ends. It can’t end. No newspaper or website worth its salt is ever truly ‘done.’ It is always evolving. Look at the first ever newspaper and the first ever website and it’s fair to say a lot has changed in both worlds since then:

1609 edition of Relation aller Fürnemmen und gedenckwürdigen Historien, widely considered the first newspaper. (Large preview) The first ever website. (Large preview)

Both formats have improved massively since those humble beginnings, and there’s an awful lot left to achieve. As C. Y. Gopinath traced out beautifully in 2016, the parameters are always changing; web technology, screen sizes, devices, internet speeds, you name it. In the mobile age maybe the nameplate belongs at the bottom. Who knows? It all lies ahead.

In many respects a torch has been passed from news design to web design. If developers can push forward with the knowledge of their elders on hand, they’ll achieve things previous generations couldn’t even have imagined. What an incredible opportunity. I can’t wait to see what they come up with.

(ra, yk, il)
Categories: Web Design

Meet “Inclusive Components”, A New Printed Book By Heydon Pickering

Smashing Magazine - Thu, 11/07/2019 - 04:30
Meet “Inclusive Components”, A New Printed Book By Heydon Pickering Meet “Inclusive Components”, A New Printed Book By Heydon Pickering Vitaly Friedman 2019-11-07T12:30:00+00:00 2019-11-11T11:16:28+00:00

The web is full of interfaces that leave people out. Of course, it’s not designers’ malicious intent or developers’ lack of empathy that bring us there. It’s just really difficult to foresee a wide range of situations in which our users might find themselves in. We need to build robust and reliable solutions in a world that’s inherently chaotic and unpredictable. Where do we even start?

Because we often build and deploy under tough deadlines, we tend to break accessibility without even noticing it. Our products become slower, clunkier and more painful to use — often simply unbearable for keyboard- and screen reader users, and as such fragile and vulnerable for legal disputes. Let’s fix it.

Meet Inclusive Components, our new handbook for building fully accessible websites and apps.

Heydon Pickering."> Because accessibility matters. We've teamed up with one-and-only Heydon Pickering to create a handbook for building accessible, inclusive interfaces. The eBook is finished, and it's being printed this very moment. About The Book

At its heart, Inclusive Components is a detailed, practical handbook for building fully accessible interfaces. The book examines 12 common interface patterns — accordions, tables, modals, notifications, tabs, toggles, and everything in-between — through the lens of inclusion. The result is accessible and robust components we author, plug in, and use daily.

For years, Heydon Pickering, a seasoned front-end developer with a focus on accessibility, has been writing about accessible solutions. We’ve teamed up with Heydon to produce a book with common challenges and solutions that he’s been refining over all these years.

For each component, the in-depth explorations are meticulously illustrated and all solutions are available as bulletproof code snippets, applicable to your work right away. Bonus: you’ll learn how to build your own accessible components with inclusive design in mind — all in a single book. Jump to table of contents.

332 pages. eBook already available as PDF, ePUB, Amazon Kindle. Printed book will be shipped early December. Written and designed by Heydon. Download a sample PDF (1.1 MB).

Print + eBook { "sku": "inclusive-components", "type": "Book", "price": "39.00", "sales_price": "29.00", "prices": [{ "amount": "39.00", "currency": "USD", "items": [ {"amount": "29.00", "type": "Book"}, {"amount": "10.00", "type": "E-Book"} ] }, { "amount": "39.00", "currency": "EUR", "items": [ {"amount": "29.00", "type": "Book"}, {"amount": "10.00", "type": "E-Book"} ] }, { "amount": "29.00", "currency": "USD", "items": [ {"amount": "22.00", "type": "Book"}, {"amount": "7.00", "type": "E-Book"} ] }, { "amount": "29.00", "currency": "EUR", "items": [ {"amount": "22.00", "type": "Book"}, {"amount": "7.00", "type": "E-Book"} ] } ] } $ 29.00 $ 39.00 Get Print + eBook

Quality hardcover. Free shipping worldwide, starting from early December.

eBook { "sku": "inclusive-components", "type": "E-Book", "price": "18.00", "sales_price": "15.00", "prices": [{ "amount": "18.00", "currency": "USD" }, { "amount": "18.00", "currency": "EUR" }, { "amount": "15.00", "currency": "USD" }, { "amount": "15.00", "currency": "EUR" } ] } $ 15.00 $ 18.00 Free! Get the eBook

DRM-free, of course. ePUB, Kindle, PDF.
Included with Smashing Membership.

Get the eBook

Download PDF, ePUB, Kindle.
Thanks for being smashing! ❤️

Table Of Contents

Each chapter tackles a single component, addressing how different and vulnerable people might read and interact with it, and how they can be better accommodated. Download a sample PDF (1.1 MB).

A preview of the book, with examples ranging from accordions to toggles, tables, notifications, dialogs etc. Download a sample PDF (1.1 MB). Large preview. About The Author

Heydon Pickering (@heydonworks) has worked with The Paciello Group, The BBC, Smashing Magazine, and Bulb Energy as a designer, engineer, writer, editor, and illustrator. He was shortlisted for Designer Of The Year in The Net Awards.

Heydon previously wrote Inclusive Design Patterns which sold over 10,000 copies. Proceeds from this title were donated to the ACLU and The Democratic Socialists Of America, to help these organizations fight fascism and create a more inclusive society.

Testimonials “Inclusive Components is a very deep and thorough explanation of development of accessible components with real world examples. Heydon Pickering shows several alternative approaches and explains pros and cons of each. It’s also a pleasure to read!”

Artem Sapegin, front-end developer, Wayfair “Inclusive Components is chock-full of practical and comprehensive advice on building accessible UI. It’s my go-to resource after the official WCAG and ARIA documentation. I’ve found it extremely helpful when building our design system!”

Sarah Federman, senior front-end developer “What Heydon achieves with his work on Inclusive Components is a pragmatic, friendly and approachable set of guides that help you to generate not just accessible components, but also resilient and progressive starting-points that will help you to build better websites and web apps in general. I often describe this work as crucial learning material for this exact reason.”

Andy Bell, independent designer & developer Why This Book Might Be For You

The devil is in the detail and often the things you do with good intentions can impose accessibility barriers unknowingly. Inclusive Components is for every front-end developer who wants to learn how to detect and address potential accessibility issues in their work. The book will teach you:

  1. How to use <button> elements, how to apply styles to your toggle buttons, and how to label them.
  2. How to create managed lists that allow users to create and delete content — in an inclusive way.
  3. How to address and resolve accessibility issues with navigation menus and submenus (aka “dropdowns”).
  4. How to create accessible and keyboard-friendly tooltips and toggletips.
  5. How to create a “dark mode” theme that’s both accessible and maintainable long-term.
  6. How to build an accessible content slider to prevent harm for motion-sensitive people.
  7. How to create inclusive notifications with live regions to communicate with your users through visual and aural channels simultaneously.
  8. How to create data tables that are semantically correct, responsive, and sortable.
  9. How to build accessible dialogs and modal dialogs with performance and inclusive design in mind.
  10. How to create and group inclusive cards (e.g. for teasers).
Technical Details Community Matters ❤️

With Inclusive Components, we've tried to create a very focused handbook with applicable, long-living solutions and strategies to create accessible and inclusive interfaces.

Our hope is that with Heydon's book, you will be able to make better design and coding decisions as you build your interfaces. Perhaps it will even become one of those reference books you'll reach to every time you need to build one of those common UI components.

Producing a book takes quite a bit of time, and we couldn't pull it off without the support of our wonderful community. A huge shout-out to Smashing Members for their ongoing support in our adventures. As a result, the eBook is and always will be free for Smashing Members. Plus, Members get a friendly discount when purchasing their printed copy.

Stay smashing, and thank you for your ongoing support, everyone!

Print + eBook { "sku": "inclusive-components", "type": "Book", "price": "39.00", "sales_price": "29.00", "prices": [{ "amount": "39.00", "currency": "USD", "items": [ {"amount": "29.00", "type": "Book"}, {"amount": "10.00", "type": "E-Book"} ] }, { "amount": "39.00", "currency": "EUR", "items": [ {"amount": "29.00", "type": "Book"}, {"amount": "10.00", "type": "E-Book"} ] }, { "amount": "29.00", "currency": "USD", "items": [ {"amount": "22.00", "type": "Book"}, {"amount": "7.00", "type": "E-Book"} ] }, { "amount": "29.00", "currency": "EUR", "items": [ {"amount": "22.00", "type": "Book"}, {"amount": "7.00", "type": "E-Book"} ] } ] } $ 29.00 $ 39.00 Get Print + eBook

Quality hardcover. Free shipping worldwide, starting from early December.

eBook { "sku": "inclusive-components", "type": "E-Book", "price": "18.00", "sales_price": "15.00", "prices": [{ "amount": "18.00", "currency": "USD" }, { "amount": "18.00", "currency": "EUR" }, { "amount": "15.00", "currency": "USD" }, { "amount": "15.00", "currency": "EUR" } ] } $ 15.00 $ 18.00 Free! Get the eBook

DRM-free, of course. ePUB, Kindle, PDF.
Included with Smashing Membership.

Get the eBook

Download PDF, ePUB, Kindle.
Thanks for being smashing! ❤️

Categories: Web Design

Inclusive Design And Accessibility: Live Stream With Heydon Pickering

Smashing Magazine - Thu, 11/07/2019 - 03:45
Inclusive Design And Accessibility: Live Stream With Heydon Pickering Inclusive Design And Accessibility: Live Stream With Heydon Pickering Vitaly Friedman 2019-11-07T13:45:59+02:00 2019-11-11T11:16:28+00:00

Accessibility can sometimes become an unfortunate afterthought as we race to meet deadlines and search for tips and tricks to meet client demands. We can cause problems for keyboard or screenreader users, and leave our products fragile and potentially vulnerable to legal action from people who find themselves locked out due to their accessibility needs. How can we get better?

One way to find out would be by joining our live stream with Heydon Pickering who will be sharing insights about the relationship between accessibility and design systems, and exploring how to build accessible components, and why he decided to write a book on accessible interface design patterns.

Live Stream On Inclusive Design: Nov 7, 5:00 PM GMT

The session will start today, November 7, at 6:00 PM Berlin time (12:00 PM New York time) — broadcasted live below! (If the video doesn’t play, you can also watch on YouTube.)

For a few years now, we’ve been running live sessions with respected professionals on Smashing TV — our video channel for our dear Smashing Members, who support our little team and our little adventures every month.

Starting from November, we’d like to try out something new. As the webinars have always been about sharing lessons learned with the community, we’d like to open them up to everybody, with Members having a chance to ask questions about the projects and their work right after the session.

From Smashing With Love

To help you stay on top of things, you can subscribe to our bi-weekly newsletter, in which we announce what’s happening in the Smashing universe. Each and every newsletter issue is written and edited with love and care. No third-party mailings or hidden advertising — promise!

You can also follow us on Twitter, Facebook, LinkedIn and even stay updated with our bi-weekly Smashing Podcast. Please do always feel free to reach out and share your thoughts with us — we love hearing from you!

(ra, il)
Categories: Web Design

Exploring New Ways To Manage Content In WordPress

Smashing Magazine - Thu, 11/07/2019 - 01:30
Exploring New Ways To Manage Content In WordPress Exploring New Ways To Manage Content In WordPress Leonardo Losoviz 2019-11-07T11:30:59+02:00 2019-11-11T11:16:28+00:00

The combination of WordPress’ versatility for managing data (since its database model supports the creation of different content models, easily extensible through meta attributes) and Gutenberg’s rich user interactions provide a powerful mechanism to create, edit and manage content.

In this article, I want to shine some light on these upgraded capabilities, exploring the new tools at our disposition and presenting several new ones to be released sometime in the future.

Existing Features

The following features are already part of Gutenberg-powered WordPress.

Create Once, Publish Everywhere

As I have described in my recent article “Create Once, Publish Everywhere” with WordPress, the block-based nature of Gutenberg enables it to enhance how content is organized/architected on the database, making it available on a granular basis (block by block) to any application running on any medium or platform (web, email, iOS/Android apps, VR/AR, home assistants, and so on). Content managed through Gutenberg can then become the single source of truth for all of our applications, allowing us to reduce the cost associated with re-formatting content to make it suitable for each required platform.

Copy/paste from Google Docs with (almost) perfect formatting

Whenever we need to collaborate with other people to create content, we will quite likely use online tools such as Google Docs, Dropbox Paper, Coda or others. These tools make it easy for different people to edit the content in a document concurrently and provide and incorporate feedback. If we are going to choose a Content Management System to store our content, we need to make sure that it works well with these tools.

Gutenberg does the job fairly well: When copying the content from a Google Doc and then pasting it into a Gutenberg blog post, the formatting is preserved, bullet lists are properly transformed to the list block, and images are inserted where they should. There may be a few inconsistencies (for instance different spacing across blocks and in the original document) however, for the most part, the process is fit for use.

Copy/pasting from GDoc preserves the format of the document. (Large preview) Crafting art direction

Several Gutenberg blocks support creating distinctive and engaging layouts and assisting the art direction of the site, to give it more personality and emphasize its identity. This way, even though we may base the site on a standard, plain-looking WordPress theme, we can customize the content’s appearance to make it stick out from the sea of sameness out there on the web. Let’s explore some of these blocks.

The Shape divider block allows to insert dividers in between two blocks. We can choose one among several basic shapes and customize its width, proportions and colors and then, with a bit of resourcefulness, create more intrinsic patterns from it. For instance, the divider below was created by first creating and customizing a divider, then flipping it both vertically and horizontally to mirror itself, then grouping these 2 halves so we can use it as a single unit (the grouping functionality will be available in core through the release of WordPress 5.3 next week, and is currently available through the Gutenberg plugin), and finally saving the grouped block as a reusable block so it can be used everywhere across the whole site:

The shape divider block connects, or breaks apart, components. (Large preview)

The Advanced columns and Row layout blocks allow to create row-based layouts, inside of which we can place nested blocks (i.e. any other Gutenberg block). They are highly configurable: They offer to define how many columns the row must have, with what padding, margin and proportion of width for each column, setting an image or custom color in the background, and several other attributes.

The row layout block allows to easily configure the proportion of width among columns. (Large preview)

We can also create grid-based layouts with predefined content. For instance, through the Post grid, Post carousel and Post masonry blocks we can display a list of posts in different ways, defining what attributes from each post to show (title, date, excerpt, author, and so on), and through the Advanced gallery block we can create beautiful image galleries.

Masonry gallery created with Advanced gallery block. (Large preview)

Some other blocks, such as Feature grid, allow to create grid layouts with predefined templates filled with custom content.

The feature grid block enables to add custom content inside of a grid layout. (Large preview)

These are just a sample of those blocks which can help us fill the content with visually attractive layouts and craft the art direction of our sites. To keep exploring possibilities, we can head to the directory of plugins offering blocks and check these out.

Assisting the user while editing content

Gutenberg assists the user when creating content through the following features:

Real-Time Preview

The Gutenberg editor gives a relatively accurate preview of how the content will look like in the website.

Error Warnings

Gutenberg makes the content creator be aware of accessibility concerns. For instance, if our content structure jumps from an <h2> header to an <h4> one without adding an <h3> tag in between, Gutenberg provides a warning message about this potential error. Similarly, when setting up the color of some text against its background color, if the contrast between the two colors is not clear enough then Gutenberg provides a warning message and helps fix the problem.

Suggesting/Executing Improvements

Blocks can connect to third-party services to analyze content and enhance it. For instance, a service could suggest how to improve the grammar of the content, provide alternative titles and tags for a better SEO, and even automatically translate the content to another language, as done by this plugin which automatically translates from English to Hindi as the user types.

New Features Under Implementation

The following features will hopefully/eventually be coming to Gutenberg in the future.

Snap to grid when resizing images

Contributors are already working on adding a grid system to Gutenberg which will, among other things, enable to resize images in an assisted manner by snapping it to the grid:

Snapping an image to grid (image from the GitHub issue). (Large preview) Inline installation of blocks

Sometimes, while we are writing a blog post, we find out that we need some functionality that we don’t have yet installed. Hence, we need to switch to the Plugins screen, search and install the corresponding plugin, and then go back to the blog post. This process adds friction to our content-writing workflow.

Wouldn’t it be nicer if we could install the required functionality right from within the editor itself, whenever we need to use it? Well, this proposal is already being implemented through this pull request (it first depends on blocks being installed on their own, i.e. without depending on being shipped through a plugin). Once merged, our content-writing workflow will not be impaired anymore, as visible in the mockup below.

Installing a block from within Gutenberg (image from the GitHub pull request). (Large preview)

Installing blocks directly from the editor could lead to unintended bloat, from making it too easy for the user to install blocks. To address this issue, after installing and using it, the block could be removed! This was not possible before Gutenberg, because if the plugin providing a shortcode (which was the way to render dynamic content inside the blog post before Gutenberg) was disabled, then the invocation of the shortcode would be rendered in the blog post (instead of the shortcode’s output), messing up our content. However, Gutenberg works differently: Blocks only save HTML content inside of the blog post (including HTML comments to store configuration attributes), so, if the block is disabled, its intended HTML output is still part of the blog post’s content. (Even though there may be problems if the block needs to load CSS assets which are not loaded anymore once the block is disabled. I am not aware how this issue will be handled.)

Page/Site builder

Currently Gutenberg can only be used for the creation of content inside a blog post or a page, however it will soon support the creation of any part of the website: Content-block areas can define the header, sidebars, footer or any section needed for our layouts. Automattic (the company behind WordPress.com) is already working on a plugin to add full site editing capabilities to its WordPress.com product, which should eventually be extensible to the open source WordPress software too.

Creating a new page with full site editing allows to select a page template. (Large preview) Real-time collaboration

Google Docs is incredibly useful to teams because it enables their members to work on the same document at the same time. Sometime in the future, Gutenberg will also incorporate a mechanism for real-time collaboration, allowing different people to work on the same blog post at the same time. This mechanism will (at least initially) be based on giving editing-locks to users on a block-by-block basis, as shown in the mockup image below.

Real-time collaboration through Gutenberg (image from the GitHub issue). (Large preview)

This feature will be particularly useful to online magazines (such as the New York Times and the like) since they may already have teams collaborating on a story (for instance, designers dealing with images, journalists, proofreaders and editors dealing with content, and others). Having real-time collaboration tools will enable these magazines to speed up their content-creation workflows and publish their articles faster.


WordPress core has never added support to translate content (it only supports translation of strings inside of core, plugin and theme files), but instead left this responsibility to plugins. Through Gutenberg, WordPress will finally add native support for this feature.

Translation is not a priority yet, so it has been targeted for Gutenberg phase 4, expected in the year 2020+. Since it is a long way off, there are yet no technical considerations of its implementation or mockups of its intended user experience. So we can only guess how it will be. Since it will be implemented after the real-time collaboration feature (described above), I would expect it will enable different people to translate the same blog post to different languages at the same time, block by block.

Inline media editing

Through the Media Library, WordPress already provides some image editing capabilities: resizing, cropping, rotating and flipping. These capabilities are very basic, and they are applied on to the image on a different screen, which creates some friction to the process of fitting the image into the blog post.

Through Gutenberg, the media-editing experience could be greatly enhanced: One one side, it could support editing the image in more advanced ways, such as applying effects or filters, altering the contrast, replacing colors, adding text as watermark, adding transparent regions, converting it to different formats, and others (for instance, Cloudinary provides an API to apply many transformations to an image, which could be perfectly accessed by a block). On the other side, the editing could happen inline, right where the image is placed inside the blog post. Then, for instance, if the image was added as an overlay against some background, and we add transparent regions to the image, we can visualize in real-time how the composite result looks like.

(I haven’t found any proposal to tackle this issue in Gutenberg’s GitHub repo, but I learned about this idea talking to some core contributors, who expected to be able to work on it some time in the future.)


Already being the most popular CMS (close to 35% of the web), WordPress has also the chance to offer the most compelling tools to manipulate content. This is because Gutenberg offers an appealing mechanism to create, edit and manage content: A single interface, simple to use, fairly powerful and versatile. With its new content management capabilities, WordPress can become the single source of truth of all our content, to power all our applications (websites, newsletters, apps, and so on) through APIs. Kudos to that!

(yk, il)
Categories: Web Design

Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)

Smashing Magazine - Wed, 11/06/2019 - 01:00
Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:00 2019-11-11T11:16:28+00:00

Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow) talk to each other. That is exactly why our text-adventure engine built in Node.js would not be complete without a way for the party members to be able to communicate with each other. And because this is indeed a text adventure, that form of communication will be presented in the form of a chat window.

So in this article, I’m going to explain how I added chat support for the text client as well as how I designed a quick chat server using Node.js.

Previous Parts Of This Series

  • Part 1: The Introduction
  • Part 2: Game Engine Server Design
  • Part 3: Creating The Terminal Client

Back To The Original Plan

Lack of design skills aside, this has been the original wireframe/mock-up for the text-based client we built in the previous part of the series:

(Large preview)

The right side of that image is meant for inter-player communications, and it’s been planned as a chat since the beginning. Then, during the development of this particular module (the text client), I managed to simplify it into the following:

(Large preview)

Yes, we already covered this image in the previous installment but our focus was the left half. Today, however, our focus will be on the right half of what you’re seeing there. In other words:

  • Adding the ability to reactively pull data from a third-party service and update a content window.
  • Adding support to the command interface for chat commands. Essentially changing the way commands work out of the box and adding support for things, such as “sending a message to the rest of the team”.
  • Create a basic chat server on the back-end that can facilitate team communication.

Let me start with the last one before moving on to how to modify our existing code.

Creating The Chat Server

Before even looking at any code, one of the first things one should do is to quickly define the scope of any new project. Particularly with this one, we need to make sure we don’t spend a lot of time working on features we might not need for our particular use case.

You see, all we need is for the party members to be able to send messages with each others, but when one thinks of a “chat server”, other features often come in mind (such as chat rooms, private messages, emojis and so on).

So in order to keep our work manageable and get something out that works, here is what the chat server module will actually do:

  • Allow for a single room per party. Meaning, the actual room for a party will be auto-created when the game itself is created and the first player starts playing. All subsequent party members will join the same room, automatically and without a choice.
  • There will not be support for private messages. There is no need to be secretive in your party. At least not in this first version. Users will only be able to send messages through the chat, nothing else.
  • And to make sure everyone is aware, the only notification sent to the entire party, will be when new players join the game. That’s all.

The following diagram shows the communication between servers and clients. As I mentioned, the mechanics are quite simple, so the most important bit to highlight here is the fact that we’re keeping conversations contained within the same party members:

(Large preview) The Tools For The Job

Given the above restrictions and the fact that all we need is a direct connection between the clients and the chat server, we’ll solve this problem with an old fashion socket. Or in other words, the main tool we’ll be using is socket.io (note that there are 3rd party services providing managed chat servers, for instance, but for the purposes of this, going there would the equivalent of killing a mosquito with a shotgun).

With socket.io we can establish a bidirectional, real-time, event-based communication between the server and the clients. Unlike what we did with the game engine, where we published a REST API, the socket connection provides a faster way of communication.

Which is exactly what we need, a quick way to connect clients and server, exchanging messages and sending broadcasts between them.

Designing A Chat Server

Although socket.io is quite magical when it comes to socket management, it’s not a full chat server, we still need to define some logic to use it.

For our particularly small list of features, the design of our server’s internal logic should look something like this:

  • The server will need to support at least two different event types:
    1. New message
      This one is obvious, we need to know when a new message from a client is received, so we’ll need support for this type of event.
    2. New user joined
      We’ll need this one just to make sure we can notify the entire party when a new user joins the chat room.
  • Internally, we’ll handle chat rooms, even though that concept will not be something public to clients. Instead, all they will send is the game ID (the ID players use to join the game). With this ID we’ll use socket.io’s rooms feature which handles individual rooms for us.
  • Because of how socket.io works, it keeps an in-memory session open that is automatically assigned to the socket created for each client. In other words, we have a variable automatically assigned to each individual client where we can store information, such as player names, and room assigned. We’ll be using this socket-session to handle some internal client-room associations.
A Note About In-Memory Sessions

In-memory storage is not always the best solution. For this particular example, I’m going with it because it simplifies the job. That being said, a good and easy improvement you could implement if you wanted to take this into a production-ready product would be to substitute it with a Redis instance. That way you keep the in-memory performance but add an extra layer of reliability in case something goes wrong and your process dies.

With all of that being said, let me show you the actual implementation.

The Implementation

Although the full project can be seen on GitHub, the most relevant code lies in the main file (index.js):

// Setup basic express server let express = require('express'); let config = require("config") let app = express(); let server = require('http').createServer(app); let io = require('socket.io')(server); let port = process.env.PORT || config.get('app.port'); server.listen(port, () => { console.log('Server listening at port %d', port); }); let numUsers = 0; io.on('connection', (socket) => { let addedUser = false; // when the client emits 'new message', this listens and executes socket.on(config.get('chat.events.NEWMSG'), (data, done) => { let room = socket.roomname if(!socket.roomname) { socket.emit(config.get('chat.events.NEWMSG'), "You're not part of a room yet") return done() } // we tell the client to execute 'new message' socket.to(socket.roomname).emit(config.get('chat.events.NEWMSG'), { room: room, username: socket.username, message: data }); done() }); socket.on(config.get('chat.events.JOINROOM'), (data, done) => { console.log("Requesting to join a room: ", data) socket.roomname = data.roomname socket.username = data.username socket.join(data.roomname, _ => { socket.to(data.roomname).emit(config.get('chat.events.NEWMSG'), { username: 'Game server', message: socket.username + ' has joined the party!' }) done(null, {joined: true}) }) }) // when the user disconnects.. perform this socket.on('disconnect', () => { if (addedUser) { --numUsers; // echo globally that this client has left socket.to(socket.roomname).emit('user left', { username: socket.username, numUsers: numUsers }); } }); });

That is all there is for this particular server. Simple right? A couple of notes:

  1. I’m using the config module to handle all my constants. I personally love this module, it simplifies my life every time I need to keep “magic numbers” out of my code. So everything from the list of accepted messages to the port the server will listen to are stored and accessed through it.
  2. There are two main events to pay attention to, just like I said before.
    • When a new message is received, which can be seen when we listen for config.get('chat.events.NEWMSG'). This code also makes sure you don’t accidentally try to send a message before joining a room. This shouldn’t happen if you implement the chat client correctly, but just in case these type of checks are always helpful when others are writing the clients for your services.
    • When a new user joins a room. You can see that event on the config.get('chat.events.JOINROOM') listener. In that case, all we do is add the user to the room (again, this is handled by socket.io, so all it takes is a single line of code) and then we broadcast to the room a message notifying who just joined. The key here is that by using the socket instance of the player joining, the broadcast will be sent to everyone in the room except the player. Again, behavior provided by socket.io, so we don’t have to add this in.

That is all there is to the server code, let’s now review how I integrated the client-side code into the text-client project.

Updating The Client Code

In order to integrate both, chat commands and game commands, the input box at the bottom of the screen will have to parse the player’s input and decide on what they’re trying to do.

The rule is simple: If the player is trying to send a message to the party, they’ll start the command with the word “chat”, otherwise, they won’t.

What Happens When Sending A Chat Message?

The following list of actions takes place when the user hits the ENTER key:

  1. Once a chat command is found, the code will trigger a new branch, where a chat client library will be used and a new message will be sent (emitted through the active socket connection) to the server.
  2. The server will emit the same message to all other players in the room.
  3. A callback (setup during boot-time) listening for new events from the server will be triggered. Depending on the event type (either a player sent a message, or a player just joined), we’ll display a message on the chat box (i.e the text box on the right).

The following diagram presents a graphic representation of the above steps; ideally, it should help visualize which components are involved in this process:

(Large preview) Reviewing The Code Changes

For a full list of changes and the entire code working, you should check the full repository on Github. Here, I’m quickly going to glance over some of the most relevant bits of code.

For example, setting up the main screen is where we now trigger the connection with the chat server and where we configure the callback for updating the chat box (red box on the top from the diagram above).

setUpChatBox: function() { let handler = require(this.elements["chatbox"].meta.handlerPath) handler.handle(this.UI.gamestate, (err, evt) => { if(err) { this.UI.setUpAlert(err) return this.UI.renderScreen() } if(evt.event == config.get('chatserver.commands.JOINROOM')) { this.elements["chatbox"].obj.insertBottom(["::You've joined the party chat room::"]) this.elements["chatbox"].obj.scroll((config.get("screens.main-ui.elements.gamebox.autoscrollspeed") ) + 1) } if(evt.event == config.get('chatserver.commands.SENDMSG')) { this.elements["chatbox"].obj.insertBottom([evt.msg.username + ' said :> ' + evt.msg.message]) this.elements["chatbox"].obj.scroll((config.get("screens.main-ui.elements.gamebox.autoscrollspeed") ) + 1) } this.UI.renderScreen() }) },

This method gets called from the init method, just like everything else. The main function for this code is to use the assigned handler (the chatbox handler) and call it’s handle method, which will connect to the chat server, and afterwards, setup the callback (which is also defined here) to be triggered when something happens (one of the two events we support).

The interesting logic from the above snippet is inside the callback, because it’s the logic used to update the chat box.

For completeness sake, the code that connects to the server and configures the callback shown above is the following:

const io = require('socket.io-client'), config = require("config"), logger = require("../utils/logger") // Use https or wss in production. let url = config.get("chatserver.url") let socket = io(url) module.exports = { connect2Room: function(gamestate, done) { socket.on(config.get('chatserver.commands.SENDMSG'), msg => { done(null, { event: config.get('chatserver.commands.SENDMSG'), msg: msg }) }) socket.emit(config.get("chatserver.commands.JOINROOM") , { roomname: gamestate.gameID, username: gamestate.playername }, _ => { logger.info("Room joined!") gamestate.inroom = true done(null, { event: config.get('chatserver.commands.JOINROOM') }) }) }, handleCommand: function(command, gamestate, done) { logger.info("Sending command to chatserver!") let message = command.split(" ").splice(1).join(" ") logger.info("Message to send: ", message) if(!gamestate.inroom) { //first time sending the message, so join the room first logger.info("Joining a room") let gameId = gamestate.game socket.emit(config.get("chatserver.commands.JOINROOM") , { roomname: gamestate.gameID, username: gamestate.playername }, _ => { logger.info("Room joined!") gamestate.inroom = true updateGameState = true logger.info("Updating game state ...") socket.emit(config.get("chatserver.commands.SENDMSG"), message, done) }) } else { logger.info("Sending message to chat server: ", message ) socket.emit(config.get("chatserver.commands.SENDMSG"), message, done) } } }

The connect2room method is the one called during setup of the main screen as I mentioned, you can see how we set up the handler for new messages and emit the event related to joining a room (which then triggers the same event being broadcasted to other players on the server-side).

The other method, handleCommand is the one that takes care of sending the chat message to the server (and it does so with a simple socket.emit). This one is executed when the commandHandler realizes a chat message is being sent. Here is the code for that logic:

module.exports = { handle: function(gamestate, text, done) { let command = text.trim() if(command.indexOf("chat") === 0) { //chat command chatServerClient.handleCommand(command, gamestate, done) } else { sendGameCommand(gamestate, text, done) } } }

That is the new code for the commandHandler, the sendGameCommand function is where the old code now is encapsulated (nothing changed there).

And that is it for the integration, again, fully working code can be downloaded and tested from the full repository.

Final Thoughts

This marks the end of the road for this project. If you stuck to it until the end, thanks for reading! The code is ready to be tested and played with, and if you happen to do so, please reach out and let me know what you thought about it.

Hopefully with this project, many old-time fans of the genre can get back to it and experience it in a way they never did.

Have fun playing (and coding)!

Further Reading on SmashingMag: (dm, yk, il)
Categories: Web Design

Smashing Podcast Episode 2 With Liz Elcoate: What’s So Great About Freelancing?

Smashing Magazine - Tue, 11/05/2019 - 06:00
Smashing Podcast Episode 2 With Liz Elcoate: What’s So Great About Freelancing? Smashing Podcast Episode 2 With Liz Elcoate: What’s So Great About Freelancing? Drew McLellan 2019-11-05T16:00:59+02:00 2019-11-11T11:16:28+00:00

In this episode of the Smashing Podcast we take a look a freelancing. What does it mean to be a freelance designer or developer? How do you structure your day? What are the ups and downs? Drew McLellan talks to experienced freelance brand designer Liz Elcoate to find out more.

Show Notes Transcript

Drew: She’s a UK based designer who specializes in building digital brands. She’s worked on campaigns with the likes of Great Ormond Street Hospital, the NSPCC, and the Brits. She’s also the host of The Elastic Brand podcast, all about digital brand design, and co-host of The Freelance Web, a podcast for freelancers working on the web.

Drew: We know she loves design and she loves podcasts, but did you know she once felled a tree using nothing but a mango? My smashing friends, please welcome Liz Elcoate.

Liz Elcoate: Hello, hi.

Drew: How are you?

Liz Elcoate: Do you know what, Drew? I’m smashing.

Drew: Of course you are.

Liz Elcoate: Nailed it.

Drew: I wanted to chat about freelancing with you today.

Liz Elcoate: Great.

Drew: You’re a freelance digital brand designer. Is that how you’d describe yourself?

Liz Elcoate: I think I was trying to start the term digital brand designer, but I realize now they’re just brand designers. I probably now just go by the term brand designer. Everyone was like, “What, a digital what?” I do brands that work both online and off now.

Drew: You don’t pigeonhole yourself exclusively to online stuff?

Liz Elcoate: No. I tend to work with a lot of agencies that are maybe tech agencies, digital agencies. Most of their branding would appear online. They’re not going to have huge offline print, billboards, and things like that. A good brand should work everywhere.

Drew: What does the day of a digital brand designer look like?

Liz Elcoate: Oh God, the truth or the …

Drew: If was to pack up my bags, move to a remote part of Scotland … I’m thinking maybe an island in Scotland. I’ll take my cat. I say I’m going to be a digital brand designer. I’d wait typically six to eight weeks for my broadband to get installed.

Liz Elcoate: Then it’d be rubbish, wouldn’t it?

Drew: Then it would be absolutely terrible. What would my day look like as a freelancer doing the sort of work that you do?

Liz Elcoate: Well, I guess I always start my day off with a dog walk, so you might start yours off with a cat walk possibly. A good dog walk out in the open air always gets me set up for the day. Then back to my desk, check emails, answer emails.

Liz Elcoate: I tend to do the creative work in the morning, because I just find that’s when I work best. I’ll do a couple of hours of really focused creative work. I’ll turn off my phone, turn off my email, and just really get my head down. I can achieve so much in that period of time, probably more than I would do later on in the day for a longer period of time.

Liz Elcoate: I do that, and then maybe check emails again, lunch, get away from my desk for a little while, and then the afternoon will be tidying up whatever has come in the morning, maybe writing for a magazine, maybe Smashing Magazine, or writing proposals, or planning workshops, stuff like that.

Liz Elcoate: The really creative stuff happens in the morning, and the writing and stuff happens in the afternoon, and also do a bit of admin in the afternoon as well. I’m one of those weird people who love admin. I’m so weird. I do tend to quite enjoy that.

Liz Elcoate: It’s just because it’s like math, there’s an answer, whereas I find the creative, it can be draining because it’s so open-ended.

Drew: I guess that’s one of the differences between doing freelance creative work and freelance technical work.

Liz Elcoate: Absolutely. Also, on the very rare occasions I actually code anything these days … and that’s never for clients. That’s only for personal work … is a joyous time, because there’s a right and a wrong way to do. I’m sure there’s lots of people out there who’d say, “Well, there’s many right ways to do these things.” With my knowledge, you do something and you have an answer. It’s so nice. It’s a real break from the creative.

Liz Elcoate: I did a workshop a couple of weeks ago in Ireland. It was a new workshop that I’ve not done before. It was five hours. It was a brand workshop, and I needed to really make sure that I answered all the questions that I needed answering, as well as making it engaging for the nine or 10 people who are involved in it, and relevant for them and fun as well.

Liz Elcoate: I loved writing it, but it wasn’t until that moment that I actually delivered it to them, and we got to the 2:00 PM mark and it was all over. I thought, “Actually, that worked out.” It was, again, that kind of like, “I’m not sure how this is going to go.”

Liz Elcoate: I think that’s the same with the design side of what I do. It’s, “Well, we’ll find out how successful this has been when we hear back from them.” It can be really draining. I think that’s why I really enjoy the admin side of things, and also writing as well seems to be more formulaic, and I have a little bit more confidence, I guess, doing that. I’m confident in what I do for a living, but you don’t know until that moment the client comes back to you.

Drew: You mentioned spending time writing proposals as one of the things you do in your afternoons. How much of your time is taken up in responding to proposals, and calling clients, and finding new work?

Liz Elcoate: Well, at the moment, a lot more than it used to be. I try to be a lot more proactive around those things now. I think it’s a challenge as a brand designer. It’s not quite as straight forward, I think, as with other parts of our industry, because branding is often a really big project for a company, and they don’t do it regularly.

Liz Elcoate: It’s not like, “We need updates to our site,” or “We want to change this part of our site,” or whatever. It’s sort of like, “We’ve had the same brand for four years, five years. We need an overhaul,” or “We’re a startup …” It’s a big decision for people.

Liz Elcoate: I’m not constantly bombarded with inquiries, but when people do inquire, it often means that they’re very serious about it and it’s a big financial commitment for them as well. It can be quite a traumatic experience for them, because they think they’re one thing, and they’re now discovering that they’re maybe something else.

Liz Elcoate: The proposals, to me, I probably write one or two every week or fortnight, but I really take time with them. They take me a couple of days, a couple of afternoons to write. I used to just bang out a quick proposal, just outlining what they need and what I can do for them, but I think a lot of people do that. It doesn’t set you apart.

Liz Elcoate: I was going to work with Christopher Murphy on a project, and he, in the end, didn’t end up coming in on the project, but we wrote a proposal together, and he just completely changed the way I wrote proposals. He changed them so professionally, really engaged the client and their needs. From that moment onwards, I was writing them like that.

Liz Elcoate: Anyone else who’s seen my proposals, if I bring in other people into projects, they’ll be like, “Wow, your proposal is a game changer.” I’m like, “Well, I can’t take any credit for that.” It really has made a difference. When I write them, I really make a concerted effort to make sure that they are very, very pertinent to that particular client.

Drew: Then do you send them off and hope for the best, or do you talk through on a call?

Liz Elcoate: If we’ve got to a proposal stage (because they’re a time-consuming commitment), I feel that I’ve got to a point where they’re very committed to me and maybe one or two other people. I know they’re not just fishing around a whole group of people, and we’ve probably had a video call by then as well.

Liz Elcoate: I’ll send the proposal over and I’ll say we can schedule a call to have a chat through. Sometimes they want to do that, and sometimes they’re like, “No, it’s fine. Don’t worry.” Then they just come back to me like a week later like, “Yes, great.”

Liz Elcoate: I tend to find that if I haven’t heard from them within a week, they’re not probably going to go with me. That’s always quite a red flag. If they come back three weeks later or a month later and say, “We want to work with you,” I think, “Okay, that’s taken a very long time. What’s this project going to pan out like if that’s how long it takes you to make that kind of decision?”

Liz Elcoate: Generally we have a chat through on a video call once that’s gone over.

Drew: I know from stuff I’ve done in the past, the turnaround time can really vary, can’t it, between you can have people who take a couple of hours to read through what you’ve sent and respond straight away, and sometimes you think a project is completely gone away, and then three months later-

Liz Elcoate: Yeah, I had one of those recently, actually. I had a really quite serious inquiry. Basically, they were like, “Yes, we want to go with you. Can you just put a proposal together?” I put the proposal together, sent it over, didn’t hear from them, chased them up, didn’t hear from them again, chased them up again.

Liz Elcoate: It was a good five weeks, and I thought, “Well I’ve not heard from them. This is definitely not going to happen. It’s a shame.” My email’s always very polite, but it said, “Just let me know if you don’t want to go with me, just so I know. Any feedback would be great.” Didn’t hear anything. They came back out of the blue not long ago and said, “Sorry, just being really busy.” You’re like, “Wow, oh my God.”

Liz Elcoate: I think as a freelancer, when you’re on your own, stuff comes in, you react to it, so you expect other people to work like that. I find when I work with maybe a company of one or a small agency, they do react really quickly. They don’t need to take time to think of stuff, but when I work with big agencies, they often take a good week.

Liz Elcoate: You have the person in charge of the project, but then they need to then go off to their stakeholders and have a chat with them about everything. They’re already busy, so they need to schedule a meeting, and it tends to be a bit longer. There’s no hard and fast rules, unfortunately.

Drew: Other than the more stakeholders there are involved, the longer everything is going to take.

Liz Elcoate: If there’s more than maybe two or three stakeholders involved, I’m always slightly dubious about the whole situation. I had one not long ago, and there was a board of 10 people involved in deciding about the direction the brand was going to go. It was just a long, painful, drawn-out process.

Liz Elcoate: They were a very mixed age group as well, and very different backgrounds, and it was as expected when that kind of thing happens.

Drew: I once did a project for a law firm partnership, where everyone in the law firm, there were about a dozen people who were all equal partners, obviously very bright, switched on people with their own opinions about how everything should go.

Drew: We managed to get the site developed, and it failed at the final hurdle of signing it off because they couldn’t get all 12 people to sign off, and it just never launched. Completely-finished website, and it just never launched.

Liz Elcoate: That is so sad. I always do try and say to clients that you need to have someone take the lead on it, and someone who can say to even the stakeholders, “Look, we’ve got to have a decision on this,” because it is impossible.

Liz Elcoate: I think when I used to work for the agency that I used to work for, we worked with a lot of schools. We’d sometimes have a board of governors involved, as well as the head-teacher, as well as three or four teachers who wanted to be involved as well.

Liz Elcoate: They were hugely different age ranges and experience. Those projects were the same as yours. It’s almost impossible to sign off in the end.

Drew: You’ve got a good number of years experience doing this, like me.

Liz Elcoate: I’m old. I’m old.

Drew: It’s a euphemistic way of, “Yes, we have a lot of experience in our respective fields.”

Liz Elcoate: Definitely.

Drew: Have you always been freelance, or did something come before that?

Liz Elcoate: Gosh, if we go back to the dawn of time, which is when I began my career, I worked for an Australian bank way back then, just in processing pensions and stuff like that, because I was having a crisis like, “I don’t know I want to do with my life.”

Liz Elcoate: Then I moved to working for a Danish company in marketing, which I really enjoyed. I enjoyed the creative side of that as well. I did art and fine art after school, and I hadn’t really done anything with that. I felt that within that role, I was starting to do a little bit more with that.

Liz Elcoate: Then this thing called web design started popping up. My sister said to me, “You really need to get in on this at the start.” I was like, “We’ll give it a go, maybe.” She’s like, “No, I really think it’s going to be big.”

Liz Elcoate: I did a little night course, and of course, the night course was terrible because they tried to teach everything in tables. By that point, we were getting to the HTML and CSS. I then went on the Adobe tutorial forum, or site, or whatever it was back then, and basically learned coding from there, and blindly just got some clients.

Liz Elcoate: It terrifies me now. I think I literally knew nothing. Did some quite hefty websites for people. I think this is quite common… I think a lot of people started off just going, “Yeah, I’ll do your website. Don’t know what I’m doing, but okay.” That’s kind of how I started it.

Liz Elcoate: Then the more I learned, the more I thought, “I don’t know anything at all.” I thought, “I need to get an actual job, an agency.” The first job I went for, a guy called Sean Johnson, who everybody might know now as my cohost of The Freelance Web, he was interviewing me for it. He loves to say, “I hired Liz into her first design job.” Miraculously, I got the job. That was just an amazing experience.

Liz Elcoate: After that, I worked with just a brilliant team of guys, who I’m still really good friends with all of them now, loved every minute. When I say guys, I mean men. There were no women in the kind of design … We worked with the development team, so we had to design, and then we would code up our CSS, HTML, code up the site, and then we’d pass that over to the developers who would build into their CMS.

Liz Elcoate: I worked with some amazing clients then as well. Stayed there for a few years, worked up to senior design executive, I think that was my title, which I never to this day really understood what that meant. It just was pay grades.

Liz Elcoate: Then because of my daughter, who was that time starting secondary school, and she was at a different part, away from where I worked, I was like, “I’m really struggling to do all the mum things, and do a full-time job and stuff.” I was raising her on my own and didn’t really have any kind of support network.

Liz Elcoate: I then was like, “I’m just going to go freelance, sounds easy.” Luckily, I went to my boss and said, “Look John,” who I’d really, really got on well with, “I can’t really do this full time anymore.”

Liz Elcoate: It was a very high-pressure job, because I was managing products from start to finish, and traveling all over the country, and then also doing designs. We had huge, crazy targets to hit every week, like a lot of these agencies, I think, at the time. The pressure was getting crazy. I’m trying to be a mum as well. I said, “Look, I’ve got to go freelance.” He said, “Will you freelance for us?” It was a brilliant start to my freelance career. I’m very lucky.

Liz Elcoate: We did that for a while, ended up parting ways, but by that point, I’d built a client base. Most of my clients then were, it was what we called web design then, which was UX now and UI. I’d done branding within that role at the agency, so it was something I was really confident with.

Liz Elcoate: That was part of the projects. They were full-service projects. They were branding, website, everything, print, design, the whole lot. I felt that I had a lot of strings to my bow, and then I went freelance. That was probably eight years ago, I think. I can’t believe I’ve been putting myself through this for eight years, but that time’s flown. That’s more from UX design to focusing more in on branding, I think.

Drew: Was it a good decision? Have you had a good eight years? Have you ever regretted it?

Liz Elcoate: That’s a really tough … I’ve regretted it a hundred times, at least. I can’t deny that and say … It’s been necessary because of just how my life is structured and stuff, how I’ve had to be there for my daughter. It’s been necessary, but it’s been tough. There’s times when I’ve been so tempted to go back to a full-time role, just to take that financial worry away. It’s tough being worried about money all the time.

Drew: That brings us on to a recent article you wrote for Smashing Magazine called Making Peace with the Feast or Famine of Freelancing. In that you’re talking about the stresses that the irregular nature of work can put on an individual freelancer, particularly when that work isn’t coming, and new inquiries aren’t coming in.

Drew: Was this something that you were aware of right from the start, or was it something that you discovered as time went on?

Liz Elcoate: What’s bizarre is that I think you’re always told to specialize, specialize, specialize. I did specialize. I went into specializing, into branding. As I said before, there’s not a huge amount of work constantly.

Liz Elcoate: If you’re a logo designer, and you’re doing 200 pounds a pop logos, there’s a lot of work out there for you, but I really wanted to do full branding. I guess I made the decision about a year ago. Before, I was doing design, which I guess was UX design, graphic design, print design. There’s always a lot more work coming in. The projects were probably not … Now when the products come in, they’re really good value projects. I think then it was a lot more regular small work.

Liz Elcoate: Everyone seems to dismiss that saying, “No, no, you need the big projects with all the money.” Actually, those small projects as well, do keep you ticking over. I think that I’ve found that I had really dropped the ball at the beginning of this year. I’d had a couple of really big projects, and then I’d had a last-minute project come in in February, and dropped everything to do it.

Liz Elcoate: It was a three-week turnaround, and it was doing some print design for company that I’ve worked with for years and years. They’re absolutely amazing, but they always have insane deadlines. They’re like, “We need to do all of this in three weeks’ time.”

Liz Elcoate: They pay amazingly, so it was one of those like, “Well I’m just going to drop everything.” For those three weeks, I was also house-sitting for my parents because they were in Australia. They have a massive farm, so I was looking after the farm and doing … so my whole days were just mad.

Liz Elcoate: At the end of that time, I also got ill. I went to Copenhagen, and I got quite ill with a bit of quite a serious health scare. For a month, I literally was laid on the sofa. Then at the end of that month, I was like, “I’m getting better,” and I had the results come back, and everything was okay.

Liz Elcoate: I was like, “Oh God, I need to get some work in right this second. Someone give me some work now.” It hasn’t been a problem I’ve had the whole time. I’ve definitely had times when it’s been quiet, and I’ve had a week or two and I’m like, “Ugh,” but this was a long period of time of real dawning on me that things were not great.

Drew: It seems to be one of those things, not just the financial pressure that a freelancer can feel if they haven’t got new inquiries coming in. There seems to be a lot of stress, and anxiety, and things, so that even if things are okay financially, even if you’ve got a bit of a buffer, it seems like there’s a disproportionate amount of stress that it puts on an individual, just with the worry. What did you learn about that in your research for the article?

Liz Elcoate: That was probably my biggest revelation during that time. I think that’s what I really wanted to write the article about, was that I had a buffer luckily, because I had done these three big projects. A bit like everybody, you have loads of work come in and you’re crazy. You invoice it all and you’re like, “Oh, I’m rich.” Then you forget that it has to last you for however long it is until the next project comes in.

Liz Elcoate: I had a buffer, but it was that slow dawning realization that nobody I was contacting wanted to work with me. Immediately, I think, as quite a sensitive person, a creative person, I assumed that was because my work wasn’t up to scratch, and I was really losing my touch, and maybe I was in the wrong industry.

Liz Elcoate: That was really painful, to start to realize that. I thought, “Well, this is all I do. This is all I can do. I’m terrible at what I do for a living.” Unfortunately, I’m not secretly a qualified doctor or lawyer. I can’t just fall back on those things. It takes a long time to become a lawyer, even if I wanted to be one.

Liz Elcoate: It was all that kind of thing. It was a day when I thought, “I think I need to write about this mental health side of this.” Money worry is definitely debilitating, but thinking, “Well, I’m never going to get any more work because everybody’s realized that I’m actually really bad at what I do,” was worse.

Liz Elcoate: I tweeted out about this, and it was just an overwhelming group of tweets that came in just saying, “Oh yeah, I feel exactly the same way,” from really the best designers we have in the industry saying it as well. From the outside, you assume that they’re doing really well, and they never have these problems, but they have times when it’s quiet, and it really affects their mental health as well.

Liz Elcoate: I was like, “I think other people need to realize that other people feel … everyone needs to know that other people feel like this as well, and that it’s perfectly normal to feel like that.”

Drew: In talking to people, did you discover any strategies that people had for coping with that situation?

Liz Elcoate: Yeah. It was great to talk to people about this. I find when I become that worried, I almost become catatonic with worry, whereas I can’t do anything else, because my whole mind is weighed down with this with worry. It would be a case of sitting at my desk all day, sending out emails.

Liz Elcoate: You’re reeking of desperation when you send out these kind of emails. People can tell it a mile off, and you’re not getting anything back. I’d do that for eight solid hours, and then I’d go and watch Netflix or whatever. I’d be like, “Oh my God.”

Liz Elcoate: So many people came up with so many great ideas, like side projects, creative projects, running, walking outside. Walking’s a big part of my life anyway. Up your gyming. If you like fitness, start going to the gym more, because that is only going to be beneficial. It gets you out of it. It gets you out of your head when you’re doing stuff like that.

Liz Elcoate: There’s a wonderful chap … let me just find his name … he got in contact. He lives in New York, Jesse Gardner. He created this wonderful project called Troy Stories, because he lived in Troy, in New York. He basically got desperate in the depths of worry about work and stuff.

Liz Elcoate: He’d started going out onto his surrounding area, and just talking to people, and photographing them, and just finding out their story. It’s just a beautiful project, it really is. His work’s gorgeous. I think it just saved his sanity, going out there, and connecting people, and hearing other people’s story.

Liz Elcoate: Then it’s not all about you then, is it? It’s about other people and their lives as well. There are some really, really good recommendations there, a lot of do some art, cook some food, do something creative.

Liz Elcoate: We’re creative people, generally, who are in this industry. I think when you’re telling yourself that, “Well, I’m rubbish at creativity. I can’t even get paid for it anymore,” to do something else creative is really helpful.

Drew: Underlying messaging in lots of those is just be productive. Find something that you can be doing that will keep you engaged and to keep the juices flowing.

Liz Elcoate: Yeah, and stop you worrying about this huge thing in your life as well. I think I was just spending eight hours a day just applying for jobs, applying for jobs that had nothing to do with what I did for a living, just applying for anything.

Liz Elcoate: It was crazy. I think I went a little bit crazy at the time. Then contacting people, “Have you got any work? Have you got any work?”, just all day. I think if I probably had done that an hour a day, or two hours a day … because you do still have to do that. You still have to look for work … and then spent the other time, I could have done my portfolio.

Liz Elcoate: There’s a million jobs I could have done at the time, that I just couldn’t get my head around. Now after having those conversations, really starting to put some of those into practice, they begin to really help.

Drew: In the article, you’ve put together a toolkit, a feast or famine toolkit, which is kind of like a nine-step program of things you can do that touch some of these. I think it’s a really great read, lots of good ideas in there, things like getting out into nature as you say, running, and walking, and those sorts of things. That’s certainly something I find really helps, even when I’m busy with lots of work.

Liz Elcoate: Absolutely. I think as well, these are all things we should be doing when we’re really busy. I think when you’re very, very busy, it’s very easy to just completely focus on that work and think, “I can’t do anything else. I just have to focus on this work.”

Liz Elcoate: That might drop off suddenly and you’re like, “I’m completely at a loss.” I think if you have these things in your life all the time, then it’s much less terrifying when suddenly, you’re like, “Well, I must start a hobby now, because things have gone quiet, or I must suddenly start running.”

Liz Elcoate: There’s a lot to be said for releasing endorphins through exercise. It can make you feel a hundred thousand times better. My daughter’s at uni now, and she’s under a lot of pressure doing her degree and stuff. I keep saying to her, “Just go to the gym.” She’s like, “I can’t. I’ve got so much reading to do.”

Liz Elcoate: “I went to the gym last night. Mum, I feel really great after going to the gym.” I’m like, “I’m not going to say I told you so.” She said, “I just feel so much happier.” I’m like, “Yeah, I think we’ve all proven that endorphins are good for you.” I really do think there’s some benefit in that.

Drew: I think as well there’s a lot of benefit. You talk about doing side projects, and taking up creative hobbies, and things. Of course, there’s value in not only fueling your creative mind, but also that some of those might turn into work in themselves.

Liz Elcoate: I totally agree, but I think there’s also, don’t start a side project with that in mind, because then it just becomes another chore. I think I’m definitely guilty of that. The minute that I come up with something I quite like to do, I think, “Well, how can I make money out of this?”

Liz Elcoate: I made marmalade the other weekend. I’ve never made marmalade in my life before. I thought, “Maybe this could be a sideline. This marmalade is really good.” I think, “No, you made it because you’re …” It’s one of those particular processes that you go through. Don’t start thinking this could be a business. I’m very bad at that.

Liz Elcoate: I think it’s great to have side projects, but I think the ones that do end up being successful and maybe becoming part of your career aren’t necessarily started with that goal in sight. I think the ones that are started with that goal in sight often don’t work, because they just become a real chore.

Liz Elcoate: Jessica Hische with her Drop Caps, I think she did that for pleasure and fun, and that’s become something she’s so well known for. I think if you set out going, “Well, I’m going to create these amazing things and hopefully it’ll turn into …” I think that sometimes then adds that further pressure.

Liz Elcoate: When I said pursue creative, they can be … I’m a real sad geek, and I really like doing even a puzzle or something, something that really is just mind numbingly, there’s no end, there’s no … well, there is, because you’ve completed the puzzle, but there’s no obvious creative like, “I can show everyone how great my puzzle is.” it’s like making marmalade. It’s just my numbing process, basically.

Drew: I guess there’s a happy medium with those as well for a creative person maybe doing some personal work, just something that where the inspiration takes them and something that they feel like doing. Sharing it on Dribbble might attract some attention that brings in some regular work.

Liz Elcoate: Yeah, absolutely. That really worked for me at the beginning of my career. Wow, this is really taxing the old memory. When I first went freelance I thought, “Okay, I’m going to create an amazing CV.” This is not such a thing these days. I think people are a bit snobby around CVs, but there used to be some really creative, amazing CVs.

Liz Elcoate: I was like, “Oh, I’m going to do that. I’ve got a bit of quiet time. I’m going to do that.” I just went to town and shared it on … I can’t remember, maybe it was Dribbble. That was probably around then. I actually did get quite a bit of work from that, just because it was really creative and I’d gone crazy.

Liz Elcoate: Now I feel like I’m more nervous about sharing those things. I think the more I’ve learned and the more embedded into the industry I’ve got, I’m now less keen to share those things. I think it’s because maybe the tone has changed a little bit on Twitter and things like that. People can really be very critical.

Liz Elcoate: I think back then … she sounds very old … back then it was more of a supportive like, “This is amazing,” kind of thing, rather than, “Well, I think you should do this. I personally wouldn’t have done that.”

Liz Elcoate: I think that has definitely worked for me in the past, going back to your point, just letting loose, and also maybe even do things without thinking. “Well, nobody’s ever going to see this, so let’s just go crazy.” It doesn’t matter. It can be all the worst things you’ve ever been taught not to do, but just go crazy, because they can reap amazing rewards.

Drew: We mentioned briefly about being too busy and when all the work then comes in. The stress is pretty much the same when the work’s piling up?

Liz Elcoate: Yeah. I got really poorly at the beginning of the year because of that. It had been a very quiet Christmas and being very worried, and then it exploded with work. As I said, I had agreed to do this stupid house sitting, which is always incredibly stressful.

Liz Elcoate: I actually made myself, I got quite poorly. It’s exactly the same. It’s just so familiar to a lot of freelancers, I think, this, “I’m too busy for anything else,” kind of thing when it gets to that. Then, “I must do it. I can’t possibly turn it down, or say that I can’t do it for a couple of weeks, because they might go somewhere else.”

Liz Elcoate: There’s this pressure to take it all on if it comes in. Then you could be managing four or five, £5,000 projects at once. That is extremely stressful in itself, because that isn’t something you’d really find in a workplace necessarily. You’d have a support team around you.

Liz Elcoate: I think as a freelancer, there’s also all the admin side of stuff, and all that kind of thing, and life that you have to do outside of work. That can be increasingly stressful, I think. Really, you should be managing your time better. I’m the last person to comment on this.

Liz Elcoate: I’m saying this to myself, “You should be managing your time better.” If clients are coming to you and saying, “We’ve got this deadline,” you’re in charge. You can say to them, “Actually no, if you really want me to do this, I can’t do this for a couple of weeks.”

Liz Elcoate: I think you do have to manage your time well. As a freelancer, you have to be very good at those kinds of things, a lot of things. You can’t just be a great designer. You have to be really good at managing your time and being motivated.

Liz Elcoate: You have to be a good boss to yourself, I think, and not an abusive boss, which I think a lot of us are quite abusive. We are like, “Stay at your desk all day. Have lunch at your desk.” There is no boss in the real world would ever be allowed to treat you like that at all.

Liz Elcoate: I think we have to be really good bosses to ourselves and have time outside of work. It’s so easy for it to be just work and then die in front of the TV in the evening, or X-Box, or whatever, or whatever the kids are playing on these days.

Drew: Liz, freelancing sounds awful.

Liz Elcoate: I know. It does, doesn’t it? Wow, how do I do it?

Drew: Is there anything good about it?

Liz Elcoate: There is so much good about it, like amazing people that I’ve met, amazing community that I’m part of online, having time to go and have really long walks with the dogs, or go and take a day off, or go to London, go and do that. The traveling that I get to do more and more as I get bigger projects is so exciting as well.

Liz Elcoate: Being able to write and get paid to write is a dream of mine. It’s amazing. I wouldn’t necessarily have that opportunity if I worked somewhere else. There’s so many good things about it. Seeing a project from start to finish through and it being successful is so satisfying.

Liz Elcoate: The workshop I mentioned earlier, writing that from scratch and then delivering it, and it being successful was such a high, it really was. Knowing I could engage nine people, 10 people for five hours and keep them interested in what we were doing was really, really exciting for me.

Liz Elcoate: There’s so many good things about it. You’re in charge of your own time. You’re in charge of what you do. It’s worth remembering that, because I think it’s really easy to just … you go freelancing because you want more control or autonomy, and then you just work exactly like you did in a job, exactly the same.

Liz Elcoate: You might as well have stayed in job and had a regular income if you’re going to do that. You need to be flexible and work which way works best for you.

Drew: I guess it’s that that flexibility that enables you to work around whatever family circumstances that-

Liz Elcoate: Yeah, absolutely. I’ve been lucky in that over the years, I’ve had great bosses and stuff, and they’ve always been really understanding about that I was a lone parent. I’ve been a lone parent since she was tiny.

Liz Elcoate: As she got older, weirdly, that became more of a challenge because she needed me to be there more often, particularly those teenage years when I think it’s painful and hard being a teenager, and you need your mum there and your dad there. To have that flexibility, to be able to spend that time with my daughter now is back on that. It’s just so lovely.

Liz Elcoate: The other thing we mustn’t underestimate is, we can go on holiday outside of school holiday times. That’s absolutely great. You can be really flexible with when you go on holiday, what you do with that kind of thing. I found with work, I was always pressured to go during the summer when it was a bit quieter, but it was always hideously expensive because everybody else was on holiday now.

Liz Elcoate: You can take Friday off and you can go to somewhere for the weekend. There’s so much good about it. I would not be doing it if I deep down didn’t prefer it to being employed. I think as well, it’s a long time since I was employed. It’s easy sometimes to look back with rose-tinted spectacles, but there’s a reason I went freelance.

Liz Elcoate: It was highly pressurized, and I really at times couldn’t see a way through the stress and pressure of it. There’s pressure with freelancing, but you can manage it yourself. You’ve not got somebody above telling you what to do.

Drew: Here at Smashing, we’re all about learning. With Smashing Magazine, and the books, and conferences, I think it’s an industry where we’ve got to be learning new stuff all the time. One of the things I like to ask the guests on the podcast is, what have you been learning in your work lately?

Liz Elcoate: Well, I’m really lucky. It’s very pertinent to what we’ve been discussing today, is that I’m learning to run a business. I’m learning to be a businesswoman, and not just a designer now, and doing that through reading and also through working with coaches.

Liz Elcoate: I’ve worked with a couple of coaches. I’ve worked with Paul Boag. I’m also working with Christopher Murphy as well, who’s helping me. It’s great saying I’m a brand designer and I like doing branding, but how do you turn that into a business which regularly pays the bills and regularly has work come in? I’m working through that in the moment, and it’s very exciting. I really love learning that side.

Liz Elcoate: It makes you feel so much more empowered and controlled, to be able to learn proper marketing, and proper networking, and how to target the people I want to work with, and identifying who I want to work with and stuff. It’s very empowering. I’ve been learning that.

Liz Elcoate: I’m also learning, really getting back into UX design and stuff because I love that. I love what I do. I love branding, but I really of enjoy the UX side of stuff as well. I’m brushing up on that and learning a bit more about that again. It’s something that I still had always done, but I’m like, “No, I need to really actively learn more about this now.”

Liz Elcoate: It’s exciting. Lots of learning going on here at the moment.

Drew: You’ve got a couple of podcasts.

Liz Elcoate: Yes, I have, thank you. I have The Elastic Brand, which is a podcast. It began about digital brand design, but I think through the course of doing it, I’ve realized talking to people that it’s brand design, as I said before. That’s really exciting for me.

Liz Elcoate: I get to talk to brilliant designers, not necessarily brand designers, but all kinds of different designers and marketing people, just discussing what all the aspects of a brand, like the storytelling, the brand values, and how your customers feel, and also things like accessibility, and inclusivity, and stuff, which aren’t things that have necessarily really come up in branding particularly.

Liz Elcoate: Then I have another podcast called The Freelance Web that’s been going on for a fair old time now, and we had a big hiatus for a while, but we’re doing again. We never get a chance to actually record, so when we do see each other, we record about eight back to back.

Liz Elcoate: That’s basically just talking about freelancing, which is ironic, looking at the article I wrote from the Smashing Mag about how rubbish I’d been at freelancing. We talk about what to do and what not to do. It’s basically just a conversation about what we’ve done.

Liz Elcoate: That’s with Sean, who is the guy responsible for hiring me into my first digital role, as he likes to tell people.

Drew: We have a lot to thank him for.

Liz Elcoate: So much. Do I? Do I really have a lot to … no, I do. I do, definitely. I’ve got those two.

Drew: Fantastic.

Liz Elcoate: Thank you.

Drew: If you, dear listener, would like to find out more about Liz or hire her to work on your digital brand, you can find her website at elizabethelcoate.com, and she’s @liz_e on Twitter. Her excellent Elastic Brand podcast and The Freelance Web are both available to find wherever you listen to your podcasts.

Drew: Liz, thank you for taking the time to talk to us. Do you have any parting words?

Liz Elcoate: Don’t let me put you off freelancing. It really is wonderful and rewarding, and everything that people say it is, as long as you’re proactive and you take time to look after yourself.

(dm, ra, il)
Categories: Web Design

Smashing Podcast Episode 1 With Andy Clarke: What Is Art Direction?

Smashing Magazine - Tue, 11/05/2019 - 04:30
Smashing Podcast Episode 1 With Andy Clarke: What Is Art Direction? Smashing Podcast Episode 1 With Andy Clarke: What Is Art Direction? Drew McLellan 2019-11-05T14:30:59+02:00 2019-11-11T11:16:28+00:00

The new Smashing Podcast is the perfect way to take a little bit of Smashing along with you on your morning commute, when working out at the gym, or just washing the dishes. We’ll be bringing you a new interview with a Smashing expert every two weeks, directly to your podcast player of choice. You can subscribe in your favorite app to get new episodes as soon as they’re ready, or just listen using the player below.

To get things off with a bang, we’re launching the first two episodes today. Each episode will be accompanied by a post (just like this one) with a full transcription of the interview here on Smashing Magazine.

In this inaugural episode, Drew McLellan talks to designer, author, and speaker Andy Clarke about Art Direction. What is it, and how can it be applied to our web design projects? We dig into the topic and see if we can get to the bottom of things.

Show Notes Transcript

Drew: He’s a well known designer, public speaker and author of numerous influential web design articles and books and has recently released his new book, Art Direction for the Web, with Smashing Magazine. Along with his wife, Sue, he founded and runs a web design studio, Stuff and Nonsense, in North Wales where he consults with companies big and small all around the world. You may know of his passion for gorillas but did you know that as a school child he was Junior National Bassoon Champion for three years in a row. My Smashing friends, it’s Andy Clarke. Andy, how are you today?

Andy Clarke: Eee, I’m smashing, lad.

Drew: So, as I mentioned your new book, Art Direction for the Web, is now available but obviously this isn’t your first book. Hard Boiled Web Design, that I’m sure people will know, and way back in the day, Transcending CSS. When did the idea for this particular book come about?

Andy Clarke: This was an interesting one because, like you say, this is number four in terms of books. Sue had always said that she’d hunt down and kill anybody that asked me to write another one because I am such a bastard when I’m writing books. I’m just not a nice person to be around and so I kind of didn’t ever want to do another, kind of, major book after Hard Boiled. So my original plan was actually to write three little, we called them shots in the whole, kind of Hard Boiled theme. Three kind of little 80 to 100 page, little shots. In the kind of the style of, or the length of, A Book Apart type length. Art Direction was going to be the first one and when I started to get into it which was way back at the beginning of, I think it the beginning of 2018 when I started it.

Andy Clarke: The more and more I kind of got into it, the more I realized that this, there was no way this was going to be a short book. All the things I wanted to talk about were just never going to fit. So I kind of threw the whole three shots idea out of the window and we just concentrated on doing this one. So I suppose the idea for this one came actually quite a few years ago even before a lot of the stuff that I talk about in the book in terms of what we can do with design and what we can do with CSS and all that kind of stuff was even a possibility. But it’s been a long time coming this one, I think it’s the kind of spiritual successor to some of the other stuff that I’ve done in the past. That sounds a bit grandiose, doesn’t it?

Drew: No, not at all. I mean, like many people, I’ve come into this field of building stuff for the web without any real formal background in, well, I’m a developer. I don’t really have a formal background in programming. I’ve just sort of picked it up as I go along and I certainly don’t have a formal background in anything to do with design. I’m not really familiar with the terminology and the concepts and the, a formal training would instill, particularly in design. So for people like me, when we talk about art direction, what exactly is art direction?

Andy Clarke: That’s an almost impossible question to answer because it means so many kind of different things at different levels. But I’m going to give an example. Do you remember back in, I mean we’re talking 15-odd years ago now but do you remember the adverts? In fact, for the show notes I’ll send you some links. But do you remember, there was an ad campaign called “The Cream of Manchester” for Boddingtons Beer. One of the things that they did, there was some really funny TV commercials but one of the things that they did incredibly successfully was a whole series of graphics which went on posters and various other things which were a glass of Boddingtons beer with the incredibly creamy head, which was the most important part of Boddingtons Beer and they shaped the head into all kinds of different things. So it looked like an ice cream and it looked like a quiff and it looked like all kinds of stuff. And what that did was it told the story of what was important about Boddingtons Beer through the medium of design. So it didn’t necessarily just say Boddingtons has a very creamy head. What it did was it showed you that through the visuals but then with the, in combination with the words, you got this very, very clever idea about what Boddingtons Beer was all about. And that, in one level, is art direction.

Andy Clarke: Let me give you another example. I can’t remember which magazine it was, now it might have been Rolling Stone. I can’t remember exactly which magazine cover it was now but a couple of years ago there was a very famous magazine cover and it was a picture of Donald Trump and they’d taken the barcode which normally sits in the bottom left or bottom right hand corner of the cover of the magazine and they’d put it on his top lip and made him look like Hitler. That’s art direction. That’s using design to convey a message to tell a story, to communicate something to an audience but through design.

Andy Clarke: And when we think about applying those things to the web, it is exactly the same kind of purpose but what we’re doing is we’re using all of those aspects of design. We’re using a layout. We’re using typography. We’re using color choices. We’re using all of these kind of design ingredients to do whatever it is that we’re trying to do online. So we might be telling a story of…a story through an editorial magazine or a news story or we might be telling a story about why you should buy my brand of power drill rather than somebody else’s brand of power drill. And it extends even into user experience because we’re really thinking about what is somebody feeling at this point? How do we communicate with them? How do we try and cheer them up, try and cool down. Do we want to be kind of quirky and delightful or do we want to be sort of more serious and conservative. And all of those aspects of evoking an emotional response in somebody is art direction.

Drew: Like accessibility, we often say that that really is the responsibility of everyone in the team but then in practice there tends to be an accessibility expert who really knows their stuff and can sort of help everyone review their work and push things forward. Is it the same with art direction? Is it something that everybody in a team should be looking at? Or is it something you hire in a big bright art director like yourself to come in and tell everyone what they should be doing?

Andy Clarke: No, it is exactly the sort of thing that everybody should be paying attention to. Every decision that we make in terms of design is an opportunity to tell a story. And that can be a big story or it can be a tiny story. And even things, for example, the style and the wording of microcopy can help to tell the story. Now, what we really need is not just everybody kind of paying attention to what that message is but we also need to know what the message is to begin with.

Andy Clarke: And one of the things that I think has been lacking over the last however many years when we’ve been kind of evolving the web as a medium is we’ve kind of moved away from this idea of the web as either a kind of creative medium or as a great medium for storytelling. And that’s the kind of thing if you go to an ad agency, then you’re not going to walk far through the door before you fall over an art director. But that’s not something that you generally find, it’s not a job title that tends to happen at digital agencies. It’s just, you’ll find UX people and project managers and developers and all manner of different, in parentheses, product designers. But the overall thinking about what message are we trying to convey, how do we implement that through design? But then there’s that kind of, what you would think of as creative direction but it is slightly different. Where somebody is basically just checking that everything is on brand, is on message, is part of telling that story.

Drew: As a developer, if I want to start getting involved in the art direction of my projects, where on earth do I start? Is this something that I can learn or do you have to be born this way?

Andy Clarke: I can’t think about the way you were born. You’ve landed on your head. No, it is something that can be taught and it is something which takes practice. So you don’t need to have gone to art school or studied advertising or whatever. I never did. I didn’t even do a graphic design degree back in the ‘80s. I was a failed painter. But it’s the kind of thing where, I think it’s a change of kind of, mindset a little bit. In thinking about, it’s not just about the practical aspects of designing a website but it’s also the thinking about, “Well, what are we trying to do?”

Andy Clarke: So let me give you an example, right. So Smashing Magazine, I did some early conceptual work with them for the redesign that we see right now. And the way that we did that was to basically just host a bunch of workshops where we all got together and we sat around a big table for a week and we did this kind of three or four times where really what we were trying to do was to get to the bottom of what the Smashing message was. And how Smashing wanted to be perceived and that was basically a great big roundtable exercise which was basically designed to just get the Smashing guys, Vitaly and Markus and others, thinking about what the real purpose of Smashing was and how they were going use design to communicate the unique kind of personality and attributes of Smashing.

Andy Clarke: And to help that along, we did a load of, kind of early rough design stuff. And then from what they learnt, they then turned to Dan Mall and said, “Right, we’ve got these words, we’ve got these, call them design principles if you like, that we want to then pull out through the design. We want to be bright and bold. We want the experience turned up to eleven. We want to be quirky” and all these kind of words that had come out of our early design discussions. And then he would then produce designs that sort of fitted with that brief.

Andy Clarke: And the interesting thing about that if we relate this back to your question where you’re saying “Where do I get involved?”, it’s, is, if we were kicking off a project for Notist, for example. The very obvious thing is that it does some things. It hosts your slide decks. It adds your speaker profile or whatever but those are just, they’re the things that it does. But your aspirations for that product are much, much more than just the bunch of practical things that it does. So from a brand and from an art direction point of view, yes, you want to be designing a product which is streamlined and simple to use and reliable and all of the stuff that it, kind of goes with it. But there’s a bigger picture and I would be speaking to you about what that purpose really is. Is it to inspire other speakers to get onstage? Is it to share information more widely? Is it to make talks that happen at remote conferences much, much more visible to people wherever they are in the world. There’s obviously a bigger thing going on in here.

Andy Clarke: And then once we’ve kind of understood what those real, kind of, what our real purpose was, then we can think about how do we convey that message through the design. And that’s where a designer would come in with a creative brief and then we would look at, well, what typography style is going to convey that message? What kind of layout? What kind of color scheme? What kind of graphics are going to really tell that story because you can easily just say the world’s most popular slide deck sharing site as, what’s that nasty one? Not Speaker Deck, the other one. SlideShare. Dreadful, absolutely dreadful. What we would look to do is something like Notist if we consider an art direction point of view is to consider, how do you want people to feel when you’re using the product and how do you want them to feel when they’re making the decision to choose your product over somebody else’s. And that’s essentially what it boils down to.

Drew: So it’s very much about how the brand, in a sense, is embodied in every little detail and every part of the design, both the sort of visual design and the functional design. Would that be accurate to say?

Andy Clarke: Yeah. Yeah, absolutely, and that should be the case with anything that we’re making. It’s why I get so disappointed when I see stuff which is not a gajillion miles away from framework default in terms of layout or button styles or type hierarchy or whatever it happens to be, all of these kind of design things. Because, to me that’s like completely missing the point of the design. Yeah, it might be a functional thing to use but does that make it nice?

Drew: So obviously modern websites are mostly spat out of a CMS into identical templates. So if kind of one of the jobs of art direction is to invoke this sort of emotional response to something on a page, can that be done through spitting out content into templates or can it be done by machine?

Andy Clarke: Well, if I had the solution to that problem, I’d be a very rich man because it is actually the problem that a massive amount of the web is struggling with. Whether it would be news outlets or magazine outlets or editorial or whatever. And it’s a question which comes up again and again and again. And actually the people that have really solved this problem best of all that I took to my knowledge it ProPublica who I talk quite a lot about in the book. And our old friend Rob Weychert basically designed the CMS implementation for ProPublica. And the way that they did it was that they said, “Right, okay, these are our foundations style, this is what the ProPublica website looks like and an article on that website looks like if I do nothing. This is what it is.” But obviously they want to be able to customize that in all kind of different ways whether it would be type or layout or color theme or anything else. What they did was very simply they just had a field in the CMS that they could inject custom CSS. And because they understood the cascade and they understood how CSS builds they would only then be able to overwrite certain things.

Andy Clarke: Now, not everybody’s going to want to go to the extent of custom designing articles in the way that ProPublica do. And they don’t art direct or over design everything. It is only these really kind of special pieces that they tend to do a really great art direction job on. But there are ways in which we can do this. One of the great, we always talk about separation of, or we used to talk about, it used to be the thing where we would separate content and structure and style and behavior. Now it seems like everybody piles everything into JavaScript but moving swiftly on. One of the things that you can do, is you can separate out the CSS logic. And as long as you don’t bake in the style of the page into the HTML, as long as you keep things flexible, you can then do an enormous amount, particularly when we’ve got things like CSS grid, flex box, which are kind of, almost like content independent in a way, and CSS variables.

Andy Clarke: So I’m working on site with a French football magazine which will hopefully be finished by the time this podcast goes out and that’s a question that we’re trying to solve right now. So what I’ve done over the last couple of weeks is I’ve designed probably about half a dozen different layout templates. Now, some pages are fixed. They’re never going to change, they’re never going to be wildly different. If you think about something like a league table or a list of results from a football Saturday then you’re not going to do an enormous amount with it. But when it comes to things like player profiles and team profiles and some of the more, kind of, involved content, what I’ve done is I’ve designed about half a dozen different layout combinations. All based on exactly the same CSS. And what I’m doing is I’m then extracting out certain things that, for want of a better word I’m calling themes. Just in terms of right, in this design, Design A, and I give them all names. I give, I’ve given the theme, I’ve named them after French football players. So if you want to, if you look at the Cantona design or Cantona theme, what do the headlines look like? What do the block quotes look like? What do the table headers look like? What do the buttons look like? There’s a specific style that goes into that theme which is independent of the layouts.

Andy Clarke: And the other thing which is independent of that theme is the six different color schemes that I’ve come up with. So basically by the end of the project, you’ll have a color layer, a theme layer and a layout layer that they are able then to kind of pick and choose. And that can be automated, it can be turned into toggle switches in the CMS or whatever it might happen to be. So there are ways of doing that.

Andy Clarke: Now that’s not a particularly kind of appropriate thing for, in terms of pure art direction but the same mechanics can then be used if we want to be saying right, “Well, we do want to customize this so let’s introduce these new fields.”

Drew: One of the examples in the book, quite early on of a, sort of art directed site is the UK government’s gov.uk site, which is excellent as a user of it. It’s a site I really enjoy using it but it’s not one that I would immediately think of as being art directed, in inverted commas. It’s not very visually rich. It’s quite sparse and not sparse in a minimalist way but sparse in a utilitarian way. Art direction doesn’t need to be flashy, I’m taking from that?

Andy Clarke: Well, I have spent years joking about gov.uk and I’ve always thought of gov.uk as being the website that design forgot. I’ve often said gov.uk, not known for its creative flair. And it was interesting, when I was doing a series of podcast interviews for the book, I was talking to Mark Porter, who used to be creative director at the Guardian. You can’t read a book about editorial design without Mark cropping up at some point. In fact, he’d be a great person for you to speak to on this podcast at some point to get a different perspective. And I was saying to Mark in our conversation, “Look, I can remember great art directed ad campaigns on TV, in magazines. We’ve talked about art direction in newspapers and print publications, etcetera, give me an example of what you think is great art direction on the web.” And I was absolutely stunned when Mark said, “Gov.uk.”

Andy Clarke: And it took a while to sink in but actually he was absolutely right because if art direction is about making people feel in a certain way then gov.uk does its job incredibly well. It doesn’t need to be flashy. It doesn’t need to be overly designed. It doesn’t need to push boundaries or do any of these things that you might associate with newfangled CSS grid webby stuff because it does what it does and it’s, the design is absolutely appropriate to, not only to the audience and what they want to do but also how gov.uk want people to feel when they’ve left the site. When you’ve gone on there and paid your car tax or looked up when your bin collection’s going to be or whether it’s safe to travel to Cameroon or…I leave that site reassured that I’ve been given the information that I was looking for in a thorough and professional way. I don’t think to myself, “Oh, is that site trustworthy?” And not just because its gov.uk but because the whole experience has just been designed to leave no unanswered questions in my brain.

Drew: Yes, it’s so, sort of simple. It gives you real confidence in the information you’ve found is correct or the process that you followed, there’s a very clear way through it so you feel like, “Yes, I’ve completed that successfully because it was unambiguous.”

Andy Clarke: Now, would I design certain things differently? You can bet your bottom dollar I would but would I want to think about improving typography? Yes. Would I want to get more granular in terms of typographic design so that we can improve the way that numerals look or dates look or tables of data look or whatever? Yes, absolutely there’s some things that I would look at there and say, “I want to improve the design of that aspect of gov.uk.” But in terms of the art direction, no, everything that they, that you see whether it’s intention or not in terms of, I don’t know whether there is an art director at gov.uk, but everything that you see just contributes to how people feel at the end of the experience and that’s good art direction.

Drew: The book itself is really beautiful. I’d seen the ebook version of it early on which is absolutely terrific and I recommend that. But then I had the pleasure of picking up an actual printed version and I really recommend the printed version even more. It’s, every sort of spread is as you’d expect, sort of custom designed and it’s just jampacked with loads of inspirational examples. And it’s so heavily illustrated, I mean there’s hardly a double page spread that’s all text. It’s all illustrated with stuff. It’s really great. To be honest, it’s not the sort of book, not knowing anything about art direction before our conversation, and before looking at, actually looking at the book. It’s something I wouldn’t have picked up thinking it was for me but once I started looking through it, I thought, “Yeah, this is really good.” Obviously, you’ve designed it, you’ve designed every spread by hand. What was that process like?

Andy Clarke: It was a lot of work. I mean, first of all, I just want to say an enormous thank you to my son, Alex, who actually typeset that entire book from start to finish. What we wanted to do when we set out to produce the book was to show off some inspiring stuff but we also wanted it to be incredibly relevant to people at various different stages or different areas or whatever. And Sue would be quite, sort of brutal with me and say, “Don’t forget to explain it this way. If somebody’s using Squarespace or Shopify or Bootstrap Grid or whatever, then you need to talk to those people as well.” So what I did was, I actually spent about three months designing a whole ton of different examples. And me being me, I had to kind of, everything had to be perfect. There had to be a theme so I kind of came up with this hard boiled based London gangster theme for an app and a website that kind of goes with it. And then everything kind of just spread on from there. What was interesting in terms of the actual design of all those examples was what you learn how to design in one part of the book you then learn how to build in another part of the book. So there is this kind of balance to it.

Andy Clarke: But then, so basically what would happen is, was that I came up with about half a dozen different layout scamps for the main body of the book. I was much, much more detailed on the, sort of the examples I didn’t design, some of the other examples from elsewhere on the web. But the general body of the book, I just did half a dozen, kind of just very simple box layout sketches. Alex would then interpret that and chapter by chapter we would then go through it. So literally every single page has been tweaked. And I haven’t done, I’ve never done a book that’s got, had that much attention to detail.

Drew: Yeah, it really shows and the end result is fantastic and I’ve been learning a lot from it. So something I always like to ask people. I’ve been learning about art direction, what have you been learning about lately? Is there anything in particular in your work and your projects that you’ve been learning and swatting up on?

Andy Clarke: Yeah. I’ve been really trying to get to grips with more advanced grid stuff. That’s something which I’ve been really trying to sort of push the boundaries of. And along with this kind of, because I’ve been experimenting with, “Here’s a great, here’s a quirky layout. How would we build that?” And along the way comes things like SVGs and making SVGs responsive and I actually learnt today that you can’t use the picture element with inline SVG. You have to use an IMG element if you want to swap one picture for another or one source for another in HTML. So my main, I’ve actually been going back to really just learn a hell of a lot more about code. I think that quite, you go through phases where there’s a huge amount to learn or it seems that way and there’s something new that you want to get to grips with. And then things kind of plateau out and you churn through the same stuff or you use the same patterns or the same kind of methodology for awhile and then there’s another spike. And I’m kind of in one of those spikes at the moment.

Drew: Obviously the book is available now. You’ve also been writing a series of articles for Smashing Magazine around some of the same sort of ideas, picking out some bits and bobs which we’ll link to in the show notes. But you’re also doing a webinar series, is that right?

Andy Clarke: Yeah, well, the articles in the webinar is all the same stuff so I called it Inspired Design Decisions. And it came about because I was actually in Magma Book Shop, which is a brilliant magazine book shop in London, before Christmas. I was with our friend, Al Power, and we were kind of thumbing through magazines and I was geeking out and going, “Oh, look at this beautiful quote. That layout looks amazing. Coo, I love the way that they’ve tied this image with the color of the text and blah, blah, blah.” And Al said, “Well, I’ve never really thought a bit like that. I’ve never really thought about lessons that we can learn from editorial design or magazine design or other things. And you just talk about it in ways that just make sense. You ought to write about this stuff.” So I don’t want to write another book at the moment because well, Sue would hunt down and kill anybody that asked me to. So the idea came about was, well, why not do a series of articles over the course of the year where I would touch on a particular topic and a particular piece of inspiration.

Andy Clarke: There’s three gone out now, so far. There’ll be four, maybe five by the time this podcast goes out. Each one is the webinar content with Q&A. Everybody that is a Smashing member also gets access to a really, really nicely designed PDF version of all of the articles and all the code that goes with it. And then what we do a month later is we’ll put that article out for free on the public Smashing Magazine website. And what we’ll do sometime next May, is we’ll collect all of those twelve articles together and we’ll re-edit them and get the continuity right and that’ll be another book that comes out, probably next April, May time.

Drew: That sounds great.

Andy Clarke: It’s a lot of fun.

Drew: If you, dear listener, would like to hear more from Andy, you can follow him on Twitter where he is @Malarkey and find examples of his work and hire him via his website, stuffandnonsense.co.uk. Art Direction for the Web is available now through Smashing at smashingmagazine.com/books and I commend it to you. Andy, do you have any parting words?

Andy Clarke: (Beep) to Brexit.

(dm, ra, il)
Categories: Web Design

The Essential Guide to Web Design for Thanksgiving

Autumn is notoriously famous for causing a seasonal affective disorder. It brings less sunny days, chilly mornings, and rains; however, it still has some happy moments, and Thanksgiving is...

The post The Essential Guide to Web Design for Thanksgiving appeared first on Onextrapixel.

Categories: Web Design

Build A Seamless Spreadsheet Import Experience With The Help Of Flatfile.io

Smashing Magazine - Tue, 11/05/2019 - 02:00
Build A Seamless Spreadsheet Import Experience With The Help Of Flatfile.io Build A Seamless Spreadsheet Import Experience With The Help Of Flatfile.io Suzanne Scacca 2019-11-05T12:00:59+02:00 2019-11-11T11:16:28+00:00

(This is a sponsored post.) If you’ve ever attempted to build a CSV importer before, you know how frustrating it is to dedicate valuable engineering time to this feature, only to watch your customers struggle with it.

In some cases, developers try to improve this experience by providing users with FAQs and tutorials that show them how to correctly use their importer. However, this merely shifts the burden from the product onto the user. The last thing users want is to sift through lengthy documentation or video tutorials to upload a simple spreadsheet.

Should it be your users’ job to figure out why your importer isn’t working correctly?

If you want to improve the experience users have with your product or service, you have to start with optimizing the experience of importing the data itself. Users rely on your product to extract value from it. Asking them to use a spreadsheet template, or to match their fields before they've even uploaded a file to your app is detrimental to their product experience and your team's resources.

Investing developer time to fix an existing data importer, or worse, building a CSV importer from scratch is a huge strain on resources. Let's look at Flatfile, which enables developers to integrate a robust CSV importer experience in as little as one day.

Common Problems With Typical CSV Import Experiences

Data import is often one of the first interactions users have with an app. Unfortunately, there are too many ways that this import feature can cause frustration.

For your users, an inefficient importer experience will cause them to wonder whether the product itself is worth using.

If the app can’t import my data easily, what the heck is going to happen once my data is finally uploaded? Do you really want you and your users to battle with these kinds of errors? (Source: Flatfile) (Large preview)

An inefficient data importer strains internal resources. Not only have you invested significant time trying to build what is essentially a second product for your app, now you’re spending time dealing with:

  • Emails and support tickets from frustrated users who can’t upload their data into your system.
  • Broken data, which your team has to manually clean before it’s usable in your database.
  • A never-ending string of inconsistent file uploads, due to lack of data normalization.

This is generally not a good position to be in, as users expect a seamless product experience from start to finish.

Worse, all that effort you spent building your importer could have been dedicated to building core product features your users need.

One of Flatfile’s clients spoke to them about the pain of building and maintaining a proprietary data importer for their real estate product. The client’s engineers spent about eight to ten hours per user, cleaning up and formatting incoming data. Sometimes these users would churn, wasting valuable development time.

There is no point in building a custom feature that's supposed to automate and streamline the import experience. Ultimately, this sets you up for maintenance headaches down the road with features that won’t scale with your product.

Wouldn’t it be better if there was an out-the-box CSV importer that could do this on its own?

Flatfile is what you need.

An illustration of some of the more frustrating data import experiences users have and how Flatfile fixes them. (Source: Flatfile) (Large preview)

Let’s look at some ways that importing data has gone awry and how it can be fixed when you let Flatfile do the heavy lifting.

Issue #1: Unclear Guidance

In some cases, users struggle with your data importer because they have no idea what to do with it. Here are some questions they may ask during a CSV import:

  • Does it accept XLS, XLSX, or XML file formats?
  • What do I do if my file is 97MB in size?
  • What if my file has special characters?
  • What happens if my columns don’t match?
  • How do I fix my data? Do I need to save a duplicate CSV and upload that file instead?
  • Can I update any incorrect data during import?
  • Do I need to download a template?

Unfortunately, unless your users are tech-savvy and spend a lot of time exporting and importing spreadsheets, they’re not going to think about these things until they're ready to provide their data.

It shouldn’t be up to your users to read through or watch a 15-minute tutorial on how to import spreadsheets into your product. Developers aren't spared either. Although engineers understand the complexities of importing data into an advanced system (like Microsoft Azure), there is still an exhaustive amount of content they need to understand before the first import even happens.

A highly technical product like Microsoft Azure attempts to reasonably present developer users with extensive documentation for importing data. (Source: Microsoft Azure) (Large preview)

Your data import experience should make it simple to upload CSV data without requiring users to take a mini course on it. The same goes for your understanding of how to build it.

Here is an example of a simplified CSV import solution for a CRM from Flatfile (you can ignore the code on the left-hand side for now):

A demonstration of how Flatfile helps developers simplify and clarify CSV import for users. (Source: Flatfile) (Large preview)

Notice how the preview of the importer shows a welcoming, yet basic setup. Your users would instantly know to:

  • Upload their data as a CSV or XLS.
  • Match their spreadsheet columns in the next step, if needed.
  • Click “Continue” to begin the CSV upload.

Part of this is because the standardized UI presents no obstacles while the synchronous guidance prepares users for what’s to come. This way, users won’t worry right off the bat if their data will be imported incorrectly.

Issue #2: Maxed-out Browser Memory Limits

Let's assume that your users have successfully exported their data from another system or compiled it into a CSV file on their own. Then, they initiate an upload using your product’s data importer.

However, after watching the upload progress for what feels like an eternity, they receive the dreaded “Upload Failed” message. This isn’t all that uncommon with traditional or self-made data importers.

It’s often why online forums and website support centers contain question-and-answer like this one on the Go1 website:

Go1’s support center answers the question “Why Has My CSV Upload Failed?”. (Source: Go1) (Large preview)

Or this one on the Nimble website:

Nimble’s support center answers the question 'Why am I getting an error message when uploading my CSV file?'. (Source: Nimble) (Large preview)

Or this one from Nurture’s knowledgebase:

Nurture’s Help & FAQs answers the question 'Why is my CSV file failing to load?'. (Source: Nurture) (Large preview)

Ultimately, it falls to your users to:

  • Accept that CSVs have a tendency to fail.
  • Debug what causes a failed CSV upload.
  • Figure out how to trim back their file size, rearrange their file, or download and use the product’s template in order to complete an upload.

Why should it be up to your users to figure out why your data importer failed? Shouldn’t you be the one to sort out the disconnect? Or, better yet, to build an importer that works without issue?

With Flatfile, you and your users won’t have to worry about things like file sizes or formats causing problems during import. For example, Flatfile helps you manage imported data via the browser or through a server-side process, enabling you to upload large CSV files without bothering your users. Another solution provided by Flatfile comes in the form of file-splitting.

A Flatfile demo that shows how you can reliably break up and import data from multiple files. (Source: Flatfile) (Large preview)

Flatfile allows users to import CSV data from multiple files intuitively, without dropping data or doing manual splitting.

In this demo, users are allowed to upload CSV files containing three different sets of data. Not only will this help make their files more manageable, but it’ll make it much easier for your product to ingest and organize the data on your backend.

Issue #3: Vague Errors

It’s not just vague upload instructions or stalled imports that are going to give your users a headache.

When the error message is vague, what is the user supposed to do with that? Without a specific explanation of the problem, your users are going to be stuck having to work through every possible fix until they find one that works (if any).

Take this reported issue with Jira:

Jira knowledgebase tries to help users that see the vague error message that reads “Unexpected failure occurred.” (Source: Jira) (Large preview)

The full error message reads:

Unexpected failure occurred. Importer will stop immediately. Data may be in an unstable state.

That’s not helpful. So, not only does the developer see a message calling their data “unstable”, but now they have to work through the issue from the scant details provided on this help page. The answer actually includes this as an explanation, which we can assume is only going to add to the frustration:

This happens because the JIRA Importers Plugin tries to validate if the issues are valid for importing, and when the validation fails the error above is thrown.

Essentially, the plugin is incapable of recognizing “Required” fields outside of the ones it deems as required. But rather than transmit that message in the importer, users have to figure that out from this resource.

Not only is there no explanation for why the CSV upload failed, but it then suggests that the data importer might’ve just goofed up (which won’t reflect well on your product experience). Chances are the importer isn’t going to accept the same file twice, so why bother suggesting a retry?

It’s not your users’ job to think here. CSV importers should be designed — error messages and all — to make this a quick and painless experience for your users.

Issue #4: Mapping Is Inefficient

The next source of frustration often appears when poor column-matching functionality is in place.

As an example, let’s say that a MailChimp user wants to load as many contact details into the email marketing software as they want. After all, it might be useful to have their business title or phone number on hand for future list segmentation.

This is how MailChimp’s CSV field-mapping system displays uploaded results. (Source: MailChimp) (Large preview)

The app doesn’t recognize three of the four columns in our file. In order to keep the unmatched column data, the user has to go through each field and manually assign a matching label that MailChimp accepts.

In this case, the only column that can be edited and matched is “Customer Name”. In this example, the user is going to lose the rest of their data.

We know what you’re thinking: “Why not just provide a pre-built spreadsheet template?” However, this is hardly a solution to the problem and will only create more work and frustration for your users.

The problem here lies within the product experience, not the user.

Historically, this has been a difficult and expensive project to take on, but that’s where Flatfile’s machine-learning, column-matching solution comes in handy.

ClickUp, powered by Flatfile, has leveraged this for its productivity web app.

The main data import modal for users that want to import tasks and projects into ClickUp. (Source: ClickUp) (Large preview)

For starters, this import modal is really well designed. Instructions are clearly provided as to what the user can upload. In addition, the manual option lets users preview what sort of data can be imported into the productivity software. This helps users preserve as much data as possible, rather than realize too late that the data importer didn’t recognize their columns and dropped the data out without any notice.

Flatfile streamlines column-matching as well:

Flatfile asks users to identify column names for accurate mapping. (Source: ClickUp) (Large preview)

This step asks users to indicate where their column names live. This way, the importer can more effectively match them with its own or add labels if they’re missing.

Next, users get a chance to confirm or reject Flatfile’s column matching suggestions:

Flatfile uses a smart column-matching system to automatically map users’ imported data. (Source: ClickUp) (Large preview)

On the left, they’ll find the columns and labels they imported. The white tab to the right provides them with automated column matching for ClickUp. So, “Task” will become “Task name”, “Assignee” will become “Task assignee(s)”, “Status” remains as is and so on.

If one of the labels in the CSV doesn’t have any match at all, the importer calls attention to it like this:

Flatfile calls attention to labels or values that don’t have an exact match in a product. (Source: ClickUp) (Large preview)

In this example, the Priority response of “High” was detected. But “Medium” was not. However, there’s no need for the user to guess what the correct replacement should be. The importer provides relevant options like “Urgent”, “Normal” and “Low” to replace it with.

Once all spreadsheet labels have been resolved, the user can easily “Confirm Mapping” or discard the column altogether if it’s proven unnecessary.

Users get a chance to confirm CSV labels and clean up the spreadsheet results before importing their data. (Source: ClickUp) (Large preview)

Finally, users get a chance to review any errors detected with their data:

Errors detected in ClickUp’s data import appear in red. (Source: ClickUp) (Large preview)

Flatfile highlights required fields that are empty, contain an obvious error or divert from the data model ClickUp specified in their back-end.

The user can rely on Flatfile’s detection system to find those import errors. The “Only show rows with problems” toggle in the left-hand corner makes it even easier to spot.

This keeps users from having to:

  • Review the original CSV file and fix errors before re-importing again.
  • Import the data and do the cleanup afterwards in the app.

How do you set up this system of column-mapping and error detection? Flatfile does most of the work for you.

There’s no need to build your data importer from-scratch with Flatfile. (Source: Flatfile)(Large preview)

Flatfile is configured via a JSON code snippet. Any fields or labels you specify in this code will be reflected in the importer. This allows for column-matching and even complex validation for things like normalizing phone numbers or date formats:

This Flatfile demo provides the pre-written JSON code on the left and a sample of the importer output on the right. (Source: Flatfile) (Large preview)

Flatfile has already been coded for you. You just need to align your data model with what you expect your users to import into your product.

Here’s a JSON snippet you might use to customize the Flatfile importer for a basic contact list:

An example from Flatfile on how to code in your own keys and labels for a basic contact list import. (Source: Flatfile) (Large preview)

You can then use validators to set strict rules for what can appear in the corresponding fields:

An example from Flatfile on how to code in complex validators including regex for CSV imports. (Source: Flatfile) (Large preview)

Bottom line:

It’s not easy building a data importer yourself. Integrating Flatfile allows you to focus on other core features of your product’s experience, knowing that the CSV import experience is taken care of.

Wrapping Up

One of the reasons we build SaaS products is so users can effectively manage their businesses without the costly overhead of outsourcing to a third party or the costly practice of trying to implement everything themselves.

However, just because you know how to build a feature that addresses those needs, doesn’t mean you should, or want to, build an importer.

Of all the things that can stand in the way of you getting and retaining users in your app, don’t let something like importing data be the reason for customer frustration or churn. You can see how easy it is for users to become soured on the slightest inconvenience with common CSV import errors. Take advantage of a tool like Flatfile whose sole focus is designing faster and more seamless CSV import experiences for your users, teams and products.

(ms, ra, yk, il)
Categories: Web Design

Creating Online Environments That Work Well For Older Users

Smashing Magazine - Mon, 11/04/2019 - 03:00
Creating Online Environments That Work Well For Older Users Creating Online Environments That Work Well For Older Users Barry Rueger 2019-11-04T13:00:59+02:00 2019-11-11T11:16:28+00:00

With the single exception of my 94-year-old mother, I don’t know a single person over the age of 65 who doesn’t have a smartphone, computer, or tablet, and usually all three.

I’m well past sixty, and have worked my way through punch cards, a C-64, many versions of Windows, Apple and Linux. I know at least a few people over seventy who have a programming background or who have spent a lot of time doing graphic design and computer music composition on various machines.

That’s why I’m always amazed to read comments like these:

“Amazon Echo has been particularly popular with the older generations, as it allows them to interact with technology and the Internet in a natural, personal way, rather than via a computer.”

We are the generation that invented and grew up with personal computers. It’s absurd to suggest that we are less capable of using technology. In other words, you can’t complain about old people not understanding tech, and then also complain that they’ve taken over Facebook and Twitter.

Even though we’re as tech-savvy as anyone else, older users have some specific needs that web designers and programmers should consider. None of them are particularly difficult to accommodate, but they can be critical for our use and enjoyment of the Internet. As a bonus, you’ll be designing environments that will also work for you when you get older. “Older” meaning “past forty”.

Text Is Preferred, As Are Grammar And Spelling

I’ve been online since the 300 baud BBS days in the mid-80s, but like most people over fifty, I spent the first half of my life relying on books, newspapers, and magazines for almost all my information needs. I prefer text over video because I can absorb and retain information faster by reading than by watching YouTube. Unless it’s something hands-on like a car repair, I’ll ignore any search result that points to a video.

I routinely skip past pages that are mostly big pictures with short captions. If you’re showcasing professional photography or artwork that’s fine, but for most things, I’m looking for well-written copy with images to complement or expand on the text. A well-chosen image can certainly improve a web page, but it’s the written word that draws me in.

Because I grew up reading and writing text, I also care a lot about how well it’s written. Just because you’ve created thousands of tweets or forum posts does not mean that you’re a professional caliber writer. I’ve been writing for decades and know that I still have some skills that could be improved. If you don’t have writing chops you need to hire a real writer to create your copy, and hopefully a real editor to fix what the writer misses. If your page hasn’t been spellchecked and proofread, you’ll lose me pretty fast.

A typical older computer user (Source: Wikimedia Štěpán Pech) (Large preview) Black And White Please

Any Internet user over the age of sixty will complain that many pages are impossible to read — as are food packages and the tiny printed ‘Quick Start Guides’ that have replaced user manuals.

It’s not because we don’t appreciate current design choices, or because we’re behind the technological curve. It’s because so many web designers have decided that pale gray type on an equally pale field is something that looks good. At age twenty, that may seem like a valid choice, but as the rest of us age, our eyesight changes for the worse. After age forty, eyesight deteriorates enough that we need black text on a white page.

The American Optometric Association describes this deterioration:

“Beginning in the early to mid-40s, many adults may start to have problems seeing clearly at close distances, especially when reading and working on the computer. This is among the most common problems adults develop between ages 41 to 60. This normal change in the eye’s focusing ability, called presbyopia, will continue to progress over time.”

As well as presbyopia, most people will eventually deal with one or more of cataracts, macular degeneration, a deterioration of color vision, or a loss of peripheral vision. On top of that, we’re dealing with the inevitable and unstoppable loss of synapses, with the nerve cells that carry information to the brain disappearing one by one.

None of this is in any way unusual — it’s just part of the aging process and sooner or later affects everyone. Although cataracts can be repaired with new lenses, and many of us have reading glasses, most of these conditions are irreversible.

Recommended reading: Using Low Vision As My Tool To Help Me Teach WordPress

Unfortunately, for those of us with declining eyesight, there are a lot of web designers that seem unaware of any of this. A quick Google search will turn up years of debate about black versus grey text, most of which boils down to young guys saying “I can read this pale text just fine,” and old-timers replying, “But I can’t!”

This is not about who’s right or wrong; it’s about creating web content that everyone can use. Just accept that if you want 50+ aged visitors, you need a contrast ratio of at least 4.5 to 1 between text and a text’s background. (This is defined in the Web Content Accessibility Guidelines 2.0 (WCAG).) A good guideline is that on a white background text should be #959595 or darker for larger typefaces, and #767676 for smaller print. If you really need to have a gray background, the text needs to be darker than this.

Black on white is still preferred. (Large preview)

As well as offering us high contrast black-and-white type, you need to think carefully about the size of the typefaces you use. Fine print may be acceptable on a car rental contract that no-one looks at, but it will send website visitors back to Google to find a source that they can actually read.

What size is good? A 2011 article at this very site by writer D. Bnonn Tennant suggests 16 pixels, and he explains in detail why this is the accepted minimum. In a nutshell: because that’s the size that web browsers are designed to display and it’s a size that most people can read easily on their device. Some designers suggest that you set your base font size to 100%, and let the browser present a font size that most users will be able to easily read on that device. On a desktop monitor, 100% defaults to — you guessed it — 16 pixels.

At this point, someone will usually say that users can just zoom. Tennant counters this easily:

The users who will most need to adjust their settings usually don’t know how. And the users who do... well, they’ll probably just take the easier path by hitting the “Back” button. ...Our personal tastes are not more important than best practices in usability.

Note: All of the above are general recommendations for text size. If you’re really serious about the science of vision and screens, you need to read Robert Mohns’ “What’s the best font size for the web? Well, it depends.”.)

Have Reasonable Tech Expectations

Before computers, I spent many weekends constantly upgrading and tweaking my 1969 Dodge Charger to get maximum performance, and when I started using and building PCs that DIY zeal carried over. Somewhere around the turn of the century, I stopped doing that. One reason was that it had become boring, but more importantly, it just wasn’t needed anymore. Unless your target audiences are gamers or niche groups like animators, it’s likely that computer upgrades happen every few years — not every few months.

I’m not alone in stretching the lifespan of my hardware, and older users are more likely to keep their computers until they are truly at the end of life. Although the common guideline is to replace computers every four years, according to Statista five to six years is the norm.

Depending on your target audience, you might also consider the number of people who hold on to systems much longer than that. I don’t need the biggest, fastest, and newest machine on the block, and my wife held on to her Windows XP machine until three years ago because “every time that you do an upgrade it breaks something.” When her motherboard gave up the ghost, she moved to an HP Envy Laptop that has mostly proved her right — it’s been one long battle with Windows 10.

Dell E6400. Still my daily driver. (Large preview)

I recently abandoned Gmail. For the last year or so, that single Chrome tab would invariably consume every scrap of my 4 gigs of RAM and grind my trusty Dell laptop to a halt. Changing Gmail for Thunderbird means that I don’t need to upgrade the memory (or anything else) and I’ll squeeze another couple of years out of this machine. For my uses (which are primarily web browsing and writing), I am perfectly productive using the applications that installed with Linux, and I honestly can’t see that changing. If your website demands too many resources I’ll go somewhere else, and this is true of a lot of older users that are happy with their existing, older tech.

My advice is to test on older, slower, less capable machines to see how your work looks and performs. If the site moves slower than molasses, you might look for ways to improve things.

Understand Our Expectations

Mine is the generation that invented personal computing and the Internet. Our experience has been that every year the Internet will get easier, more reliable, and more enjoyable. Sadly, that hasn’t been the case for a while now.

I can remember being one of the first people in my town with high-speed DSL Internet, and being amazed that web pages now appeared in a flash instead of taking seconds to load on a dial-up connection. My expectation is still that a website should load completely in a couple of seconds, but these days far too many sites take twenty, thirty, or sixty seconds to load all of the ads, pop-ups, clickbait, and gimmicks. That kind of lagging performance is enough to drive me away. I don’t think that I should have to wait for a website to load and if you can’t find a way around that, you’ve lost me.

With a cable connection that promises 150 megabytes per second download speeds, I feel that every webpage should load completely in a second or two. If some part of your page still hasn’t arrived after a few seconds, I’ll leave. When the text that I’m reading suddenly disappears two inches down the page to accommodate a slow-loading ad, my first instinct is to click the Back button and look elsewhere.

Older users understand that time is valuable. We’re conscious that we have only a finite number of years, days, and hours left, and not wasting our time shows that we’re respected. If your site takes forever to load or is “down for maintenance” more than once a year, or if it expects us to jump through multiple log-in hoops every time that we visit, we’ll go somewhere else that’s faster and easier.

If It Ain’t Broke, Don’t Fix It

Part of the reason why Amazon.com has taken over the retail world is because over the last decade the user experience has remained consistent and predictable. Despite adding Prime, and video streaming, and the whole AWS empire, the process of searching for a product, choosing it, and buying it really hasn’t changed. For many of us, that’s what keeps us coming back even if we might question some of Amazon’s corporate behavior. We know the site, and we know that we can do our shopping quickly and painlessly.

If your site works fine for us today, resist the urge to reinvent it. The first concern of every web designer should be how well a site functions, not whether it uses the newest and coolest technology. Before making changes, think long and hard about whether you’re breaking something that works just fine.

If you take the time to really consider these suggestions, you’ll likely realize that they don’t just benefit older people. Anything that makes your site easier to read, easier to use, and which gives visitors a consistent experience is a positive thing. Improvements to accommodate older, slower equipment will also make your site faster for people using bleeding-edge tech. And as a bonus, a lot of these ideas also help you to build a site that works well for people with legally defined disabilities. Design that acknowledges accessibility makes a website that works better for everyone.

Extra Resources

For really useful guidance in this area, I’ll suggest that you stay away from forums and discussion boards. Instead, check out some of the longer, and more evidence-based articles that look at these questions in more detail.

(dm, yk, il)
Categories: Web Design

Skeuomorphism is Still Alive – Examples of Food Websites

There are many good examples of food websites. From goliaths of the industry such as Starbucks or Coca-Cola to less-known local bistros, we can stumble upon stunning restaurant branding...

The post Skeuomorphism is Still Alive – Examples of Food Websites appeared first on Onextrapixel.

Categories: Web Design

Things We Can’t (Yet) Do In CSS

Smashing Magazine - Fri, 11/01/2019 - 08:00
Things We Can’t (Yet) Do In CSS Things We Can’t (Yet) Do In CSS Rachel Andrew 2019-11-01T17:00:00+02:00 2019-11-11T11:16:28+00:00

Building “magazine-style layouts” by using CSS Grid has become something of a pastime of CSS fans, keen to play with the capabilities of new Grid Layout. It’s something I’ve done myself as well as with people who’ve attended my workshops. However, I always have to pick the layouts carefully because, in truth, there are a number of very common print layout patterns that we can’t currently do on the web.

In a lot of cases, however, we can do these things with CSS —just not on the web. If you have read some of my previous articles, such as “Designing For Print With CSS”, you’ll be aware that CSS is also used for print formatting via user agents designed for outputting to PDF. These user agents have often implemented specifications or extensions to specifications that have never been implemented in continuous media, such as the scrolling and non-paged content that we have on the web.

In addition, we have some CSS specifications that haven’t yet been implemented by a browser or have only been implemented in an experimental way on one browser. We also have some things which are just at the discussion phase, perhaps as a note in the current level of a spec as to where we might take it in future.

So while most of my articles are about things we can do, this one is about things we can’t but that perhaps we might be able to do in the future. Take a look.

Floating Things From Specific Points

On the web, a floated element is taken out of flow and following text wraps around it (due to the line boxes of the following text becoming shortened). Therefore, you only have the option to float a thing to the left or right.

In print, however, you often need to float items to specific places on the page. For example, by floating an element to the top or bottom of a page.

When creating a printed document, you define the size of your pages by using the @page rule, and then your content flows into those pages. By increasing the amount of content or the font size of the text, more pages will be created. Therefore, you might have an element that you know you want to display at the top of the page it appears in, but don’t know exactly on which page it will be.

The CSS Specification that deals with this behavior is called Page Floats. Your image would display in the normal flow of the content — just as on the web — except that the content is fragmented into pages. When the page with the image is encountered, the image is moved out of the normal flow and floated to the top of the page where it appears on. (Content that would have been above the image will display below it and normal flow resumes.)

img { float-reference: page; float: top; } On the left is the image in normal flow, using Page Floats it can be made to appear at the top of the page with the rest of the content coming after it (Large preview)

There is an issue raised against the Page Floats specification to rename it, as there are use cases for this kind of pattern continuous media, e.g. in a multicolumn layout. Currently, if you float an item inside a column, it behaves in the same way as a float in regular normal flow. Assuming there is room, the line boxes of the following items will be shortened and text will wrap around the float within the column.

By using a “page float”, we could float an item to the top of the column that could give you much more control over the placement of elements within the flow of content in a multicolumn context.

Columns are essentially just like pages; we fragment our content between column boxes in the same way that we fragment our content between pages. Therefore, a more generic name would make sense in terms of this behavior being the same for columns and pages.

There are more examples of Page Floats in the excellent exploration of the subject, “Paged Media Approaches: Page Floats” by Julie Blanc.

Overflow In The Block Dimension For Multicol

The concept of “page” floats, would be even more necessary if we were to implement block dimension overflow columns in Multicol. Currently, if you fix the height of a multicol container, additional columns will be created in the inline direction causing an inline scrollbar.

See the Pen Smashing Multicol: overflow columns by Rachel Andrew (@rachelandrew) on CodePen.

See the Pen Smashing Multicol: overflow columns by Rachel Andrew (@rachelandrew) on CodePen.

As I describe in my article “When And How To Use Multiple-Column Layout”, in the CSS Working Group we have considered how we might specify overflow in the block dimension. This would allow us to fix the height of the multicol container in the block dimension, and if there was more content that could fit, create another row of columns below and fill that with content.

How does this tie into Page Floats? Well, in this scenario, you would want more control over where images and other elements end up in these rows of columns. I wouldn’t want, for example, an image to have one line of text below it before the content, and then fragmented to form the next row of columns. Page Floats would enable me to specify that images in that situation would be floated to the bottom of the column or to the top of the first column in the new row.

Spanning n Columns

In the next version of Firefox (Firefox 71), the column-span property from the Multiple-Column Layout specification is implemented, meaning that all of our web browsers implement column-span. The column-span property can take one of two values, all or none. If the value is all, it spans all of the columns; if it is none (which is the initial value), it doesn’t span.

What about multi-column layouts with elements that span some columns? This is a pattern I find in print design quite frequently. The spanning element will generally be at the top or bottom of the page, shortening the columns below or above it.

A quote spans two columns in this article (Large preview)

This is not currently possible on the web, and we don’t have a spec yet for this behavior, however, some print user agents have already implemented an extension to the spec to do this. By using Prince, I can use the following CSS to span two columns:

img { float: column-top-corner; column-span: 2; }

This would enable an element to be floated to the top corner using the Prince version of Page Floats, and then span two of the columns. The rest of the content flows into column boxes as is normal when using multicol. In Prince, the spanning of some columns is tied to floated elements; non-floated elements behave as per the Level 1 multicol spec and can only span all or none.

Specifying this raises some interesting issues. Currently, when we introduce a spanner in multicol, the spanning element essentially creates a row of column boxes above it, and a row of column boxes below. The content doesn’t jump over the spanning element and continue — as you can see in his next CodePen.

See the Pen Smashing Multicol: column-span by Rachel Andrew (@rachelandrew) on CodePen.

See the Pen Smashing Multicol: column-span by Rachel Andrew (@rachelandrew) on CodePen.

What should happen if we have an item spanning two out of three columns that is placed in the middle of the content? In many of the print examples I have seen, the content jumps the spanner when encountering these partial spans, rather than behaving as multicol does today.

In this example, the column content jumps over the spanner and continues. (Large preview)

There are further explorations of column-spanning and extensions ot floats in the CSS Figures Living Idea document. In an older post of mine, I also explored some of these ideas, “Thinking About Page Floats, Figures, Regions And Grids”.

Different Sized Columns In Multicol

Both Flexbox and Grid Layout give us the ability to do columns which are of different sizes that remain in proportion to one another as they flex. Multicol, however, can only split content into equal-sized columns. It is common in print design to have columns of unequal sizes.

Now that Flexbox and Grid have this behavior it makes sense that multicol should follow suit and allow for different column sizes. Perhaps something to consider for level 2 of the Multicol specification.

Text Wrapping All Sides Of An Element

You will have trouble opening a magazine and not spotting something like the image below. Content wrapping all sides of a quote, callout or image. It is a very common pattern and seems reasonable as a pattern we might want to use on the web.

Content wrapping three sides of a floated element in this article in Monocle (Large preview)

We do have a CSS Specification that enables this behavior. CSS Exclusions, at one time bundled with the CSS Shapes specification as CSS Exclusions and Shapes, defines the wrap-flow and wrap-through properties. Exclusions doesn’t define positioning. Instead, you would use it with another positioning method — most likely CSS Grid Layout. This enables a pattern such as in the image below (taken in IE11):

Exclusions in Internet Explorer 11 (Large preview)

Note: If you have a pre-Chromium Edge or Internet Explorer 11 installed, see the CodePen example.

The above example works in Internet Explorer 11 (or pre-Chromium Edge) using the -ms prefixed grid version. Internet Explorer is the only browser to have attempted to implement the property. I am very keen to see implementations of exclusions. I think it solves a number of issues that we have with editorial layouts on the web.

Note: For more, see my post “Editorial Layouts, Exclusions and Grid” or read this issue on the CSS Working Group Drafts repository.

Disconnected Text Flows

Print design often includes content that flows in a similar way to multicol, however, the content boxes are not connected to each other.

You can see an example below from the magazine Monocle:

The content of this article flows between two boxes (Large preview)

This is very difficult to do on the web. If you know how much content you are likely to have, you can make these layouts using Grid in many cases. However, they are then fairly fragile; they rely on us understanding how much content we have and in breaking it up into separate HTML elements. This will usually require us to wrap chunks of content in a div in order to have an element to position on the grid.

A more ideal scenario would be to keep the article as one (properly marked-up thread of content) which could flow into defined areas in the layout.

An article which is then displayed in disconnected areas of the grid

We do have a specification that details something like this: the CSS Regions specification. This was implemented in IE10 (and is therefore in pre-Chromium Edge), and was also in Chrome and WebKit before being removed. Can I use shows the state of affairs.

Can I Use CSS Regions (Large preview)

There were some significant issues with the Regions specification in that it required HTML elements to be present to flow the content into. Unlike multicol, in which anonymous column boxes are generated to hold the content, Regions requires an existing HTML element to host the content. So while you did get the nice behavior of content flowing through these disconnected boxes, you still had to work out how many boxes you needed and create empty divs to hold that content.

Your solution for more content than would fit would be to have a final auto-sized element to “mop up” this extra content without a home. This doesn’t seem like a very elegant solution!

For more information on the problems with the Regions spec as it currently stands, see “CSS Regions Considered Harmful.”

A Future For Regions?

I would be very keen to see something like Regions make a comeback. I think that we know more now about the sorts of layouts that we want to build — now that we have Grid Layout. Regions would enable a sensibly marked-up article to flow through defined boxes in a grid layout, and enable exactly the sort of layouts we see in magazines. From the very simple — skipping a center column that contains a quote or image — to complex sets of boxes and images.

In the Paged Media specification, we have a model for a defined box which is duplicated over and over to create as many pages as needed for the content we have — you don’t need to define those pages upfront. In the developing idea for block dimension overflow columns in multicol, we are considering a model where new rows of columns can be created, as many as are needed until we run out of content. Could we see a future for Regions where we can define a pattern of areas and keep repeating that pattern until we run out of content to fill it?

The article is flowed into the layout, once all the boxes are filled the pattern repeats

Whatever solution is found for Regions, it would reply on solid support for Fragmentation in browsers. Once you break your content across Regions, you will be keen to avoid things like a heading becoming the last thing in a Region — with the associated content somewhere completely disconnected. As with the multicol ideas, I think it would also require support for Page Floats so that we’re able to better control how certain elements display in a Region and stop orphan lines displaying below an image as the content fragments to another Region. In addition Regions would add to the potential of confusing content re-ordering on the web, therefore I think there are a number of related things to get right before we could see a robust and elegant solution to this problem.

Share Your Use Cases

I would love to know if you have use cases for any of the above types of layouts, or if there are other layouts you would love to do but are impossible (or only possible in a fragile way). Let me know in the comments — or even better — write up the issue on your own site and drop a link into the comments section below. Adding new features to CSS starts with understanding what the use cases and requirements are.

You can also follow the discussion on all CSS specifications at the CSS Working Group GitHub repo and Issues List.

Categories: Web Design

Signs Your Website Feels More Like A Haunted House Than A Welcoming Home

Smashing Magazine - Thu, 10/31/2019 - 03:30
Signs Your Website Feels More Like A Haunted House Than A Welcoming Home Signs Your Website Feels More Like A Haunted House Than A Welcoming Home Suzanne Scacca 2019-10-31T12:30:59+02:00 2019-11-11T11:16:28+00:00

When building a website or PWA, no one ever thinks, “I really hope my visitors run away in fear!” Yet, one wrong move could make a visit to your website seem like a nightmarish walk through a haunted house instead of an awe-inspiring tour of a new home.

To be clear, I’m not talking about dark color palettes or blood-red typography that might remind someone of something they’d seen in a horror movie. If those kinds of design choices make sense and don’t intrude on readability, go for it! What I’m talking about are those ominous feelings emitted by the design and content of a website — similar to the ones someone might feel when walking through a haunted house.

Dr. Frank T. McAndrew answered the question “What Makes a House Feel Haunted?” in an article on Psychology Today back in 2015. He explains:

“From a psychological point of view, the standard features of haunted houses trigger feelings of dread because they push buttons in our brains that evolved long before houses even existed. These alarm buttons warn us of potential danger and motivate us to proceed with caution.”

When a visitor shows up on your website, the last thing you want is for them to be wary of moving through it. You want your website to give off a welcoming and safe vibe; not one that makes visitors wonder what’s lurking around the corner.

So, today, I want to look at some ways in which a website might be giving your visitors the heebie-jeebies and what you can do to eliminate those haunted house-like elements from the experience.

Four Signs Your Website Feels Like A Haunted House

In a lot of ways, a website is like your home. You add comfortable furnishings to it. You make it feel warm and inviting. And you clean up before anyone comes over, so they’re not freaked out by the accumulated dust or clutter.

If you keep that in the back of your mind (i.e. your website = your home), you can avoid these scary missteps as you design websites (as well as PWAs and mobile apps) for your clients.

  1. It Feels Abandoned
  2. It’s Too Confusing
  3. It Looks Too Low Budget
  4. It Looks Unsafe
1. It Feels Abandoned

There’s a video game and movie called Silent Hill that’s based on Centralia, a real ghost town in Pennsylvania. Decades ago, there was a coal mine fire in the town that led to toxic conditions like the gas and smoke that billow up from the ground to this day.

It’s an element the video game designers and cinematographers latched onto when creating their own eerily abandoned setting for Silent Hill:

A still from the movie Silent Hill, featuring the toxic smoke that Centralia is known for. (Source: GIPHY)

Eventually, Centralia was condemned due to the dangers posed by the fire and the resulting toxicity. Today, there are only a few residents who remain in town.

While there are some tourists who venture to Centralia out of curiosity, they don’t stay long. And why would they? The town is unlivable and it’s devoid of any meaningful experiences.

Your website may be sending similar signals if it’s:

  • Too simple in design,
  • Too outdated looking,
  • Devoid of useful content,
  • Seemingly uncared for,
  • Powered only by a basic chatbot,
  • Missing contact details or a working contact form.

The Blockbuster website (which I can’t believe still exists) is a good example of the kinds of signals a website might send to visitors if it were abandoned:

The Blockbuster website has become nothing but a single landing page owned by DISH. (Source: Blockbuster) (Large preview)

The copyright on this website is from 2017, which is why the design of the site isn’t as bad as one might expect it to be. Even the mobile counterpart is responsive:

The nearly defunct Blockbuster still has a decent looking and mobile responsive website. (Source: Blockbuster) (Large preview)

That said, this website is nothing but a husk of what it once was in its heyday.

For example, this is what shows when someone clicks on “Blockbuster Store Location”:

The Blockbuster website advertises a location, but the pop-up leaves visitors with more questions than answers. (Source: Blockbuster) (Large preview)

If I had arrived at this site hoping to find a local video store to rent a movie from, I’d be confused by this pop-up. Does the store actually exist at 211 NE Revere Ave? What’s going to happen when I call the number? And why are they telling me I don’t have to leave the couch?

What DISH should’ve done when buying out Blockbuster is to take ownership of this domain, but then direct it to their own website. As it stands now, it feels as though there’s no one on the other side of this website and there’s no point in keeping it alive (much like the business itself).

It’s these kinds of questions and that eerie feeling of “What’s going on here????” that you want to keep your visitors from experiencing.

2. It’s Too Confusing

Another hallmark of a haunted house is excessive confusion. This is something that real-life serial killer H. H. Holmes mastered with his “Murder Castle”.

“This edifice became Holmes’ booby-trapped Murder Castle. The space featured soundproof rooms, secret passages and a disorienting maze of hallways and staircases. The rooms were also outfitted with trapdoors over chutes that dropped Holmes’ unsuspecting victims to the building’s basement.”


Interestingly, there is a term in the field of environmental psychology related to this particular quality of a space: legibility.

Essentially, if a space (like a home or a website) has clear pathways and a logical organization, it’s much easier for visitors to get oriented. Not only that, if a layout mirrors that of other spaces, it assists in recognizability and comfort. That sounds a lot like the legibility and navigability of a website, right?

Obviously, you don’t want your visitors to feel as though they’re going to get lost in your website or like they’re trapped within the walls of it. There are a number of things that could make them feel this way though:

  • Poor color contrasts,
  • Jarring typography or animations,
  • Excessively deep navigation without a trail of breadcrumbs,
  • Disappearing navigation,
  • Infinite scroll,
  • Incessant pop-ups and disruptions that won’t go away no matter how many times they’re dismissed,
  • An unclear or confusing call-to-action that makes them wonder what happens when they click it.

Let’s look at an example.

How many of you would feel confident pursuing any of the paths (links) available to you on the ARNGREN website?

The ARNGREN website is littered with excessive links and not enough organization. (Source: ARNGREN) (Large preview)

This is what appears when you click on the “PEDALS” image/link in the top-middle of the ARNGREN home page:

An example of one of ARNGREN’s product/category pages. (Source: ARNGREN) (Large preview)

As you can see, the “Index” disappears from the left, so the only option visitors have is to click the home page link or hit the browser “Back” button to depart from the path they’ve taken.

Then there’s the page itself which scrolls on and on, showing off more pictures of bicycles and scooters. There are occasional descriptions and links that appear, but it’s really nothing more than a painful rabbit hole to fall down:

A disorganized and poorly designed page on the ARNGREN website. (Source: ARNGREN) (Large preview)

This website is exactly how I expect visitors of H. H. Holmes’ Murder Castle felt when they first stepped inside those confusing hallways or fell through one of his trap doors. There’s no rhyme or reason to any of the pages and it almost feels as dangerous to backtrack as it is to move forward.

If you’d like to avoid taking your visitors on such a harrowing journey, focus on creating a clear and open path that’s easy to traverse and to get off of when they want to.

3. It Looks Too Low Budget

It’s not just real haunted houses you want to avoid emulating. You should also steer clear of certain types of haunted house attractions.

I’m what you might call a horror addict. I watch scary movies all year long. I take haunted tours every time I visit a new city. And I spend a good chunk of the months of September and October going to haunted house attractions.

As you can imagine, I’ve seen some really impressive haunted houses, and I’ve seen some that are really poorly done.

This, for instance, is an encounter I had with a street actor at Halloween Horror Nights:

That’s me trying not to giggle too hard at the Halloween Horror Nights scare actor. (Source: Halloween Horror Nights) (Large preview)

Although I have a slightly cowered stance, you can see that I'm laughing. That’s because I could see his face through the holes of his mask.

Now, this by no means is a low budget haunted house/Halloween event. And this actor deserves all sorts of kudos for walking around steamy hot Florida in that getup and on stilts, no less. But I will say that being there in the daytime where I could see through the mask did deflate my enthusiasm. It also had me wondering if the rest of the experience would be as disappointing. (For the record, it wasn’t.)

You definitely don’t want your visitors noticing flaws, odd design choices and other errors on your site. Then, wondering why the company behind it didn’t put more money into design and development.

If your website looks cheesy, overdone or like it was cheaply thrown together, you’re going to have a big problem on your hands. The rest of the web has set a very high bar for what a website should look like and how it should work. Fail to live up to those expectations and you’ll find that people will start to question the legitimacy or worth of the business behind it.

For instance, this is the website for Yale University’s School of Art:

This is the home page of the School of Art at Yale University. (Source: Yale University School of Art) (Large preview)

I thought it was a joke, that somehow I’d landed on someone pretending to be Yale University at yale.net instead of yale.edu. But I was wrong. This is the real website of the art department at the Ivy League university.

So, I dug a little further, hoping that somewhere on this subdomain would be an explanation of why this website sucked so much. This is what I found:

The Yale School of Art explains why their website / wiki looks the way it does. (Source: Yale University School of Art) (Large preview)

Let me point you to the most revealing parts of the explanation. First, they explain that this site is an open-source wiki:

It is a wiki, meaning that every graduate student, staff person, and faculty member of the School can change this website’s content or add to it at any time.

Next, they warn you that you may be shocked by what you see:

As you move through it you may, in consequence of such openness, encounter content that surprises you or with which you don’t agree. That will be the sign that this website reflects life in our institution in all its heterogeneous dimensions.

Considering the editor of this page used a negative review from Facebook as the repeating background image, there must be some inside joke here. In fact, when I looked into it further, it seems as though this school has had a tradition of scary web design choices as far back as 2010. So, they obviously know what they’re doing.

Here’s the thing though: even if you’re designing for someone with as well-known a reputation as Yale, building something that looks like it was thrown together in Paint back in 2001 is no way to go. There’s no exception for design this bad and I don’t think your visitors will be happy that you wasted their time either.

I realize this might help with the virality of a site, but it’ll do nothing for the credibility of it. All you’ll end up with is a few thrill seekers stumbling through in search of a good laugh or shock. What you need instead is visitors who feel comfortable and confident enough to convert.

4. It Looks Unsafe

The last thing that might leave people feeling unsettled is a lack of security (or at least the perception of none).

One of the things I often get asked by people who don’t like scary movies or going to haunted houses is:

“But aren’t you scared?”

Of course, I’m scared! I enjoy all of this horror stuff because I can do so safely from a distance. I know that the scare actors in a haunted house aren’t going to hurt me and I know that Michael Myers isn’t going to pop out of my TV screen and butcher me in the middle of the night. Plus, it’s a much more enjoyable way to get my cardio in without having to hit the treadmill.

A still of Michael Myers sneaking up on Laurie Strode in Halloween. (Source: GIPHY)

I think for some people, though, they don’t have that same sense of security when partaking in activities like these, which is why they steer clear. And this is something you need to be extra careful about when it comes to your website. Specifically, be mindful of:

  • Installing SSL certificates on every website.
  • Using security badges at checkout.
  • Preventing 404 errors.
  • Fixing faulty contact forms.
  • Blocking spam in comment sections and forums.
  • Monitoring for server downtime.
  • Repairing the white screen of death.

Let’s look at an example of a website that sends a number of red flags pertaining to security. This is RoadKill T-Shirts:

This is the home page of the RoadKill T-Shirts website. (Source: RoadKill T-Shirts) (Large preview)

At first glance, you might think this e-commerce website is okay. The design is outdated, but it’s a low-end tee-shirt shop. Visitors can’t be expecting too much from the design.

But then you move over to your mobile device and realize it’s not responsive:

The RoadKill T-Shirts website is not mobile responsive. (Source: RoadKill T-Shirts) (Large preview)

That said, there may be some visitors who are able to look past these design missteps, especially if there’s a tee shirt decal they really want.

One of the first red flags that should stop them in their tracks though is the “Not Secure” notice in their browser window. Although there is a GoDaddy security seal at the very bottom of the checkout page, I’m not all that sure I’d trust that to protect my purchase as a consumer either.

The RoadKill T-Shirts website includes a GoDaddy security seal at checkout. (Source: RoadKill T-Shirts) (Large preview)

Then, there’s the matter of the contact form. I was curious to see how secure users would feel about filling in contact information without submitting a payment, so I forced an error:

What the RoadKill T-Shirts contact form looks like when an error occurs. (Source: RoadKill T-Shirts) (Large preview)

I’m happy to see that the failure to fill in required fields triggered such a response. However, here’s what happens to the bottom of the form as a result:

RoadKill T-Shirts error-filled contact form leads to a hidden “Submit” button. (Source: RoadKill T-Shirts) (Large preview)

Users can tab down to reveal the “Submit” button. However, what if your visitors don’t know that they can do that? They may just end up abandoning the form and the website altogether if something as simple as the contact form is so fraught with error.

There are a variety of ways a website might seem unsafe to visitors, so do what you can to fortify it on the backend and then provide trust marks on the frontend to put their minds at ease.

Wrapping Up

When a visitor enters your website, what do you want their first thought to be?

“Oh great! There’s the product I was looking for!”


“Hmmm... Maybe I should go back to Google and see if there’s a different place to buy this product from.”

There are so many ways to give your visitors pause when they visit a website. But if you start looking at your website like a home, you can avoid the common pitfalls that make a website feel more like a haunted house than a warm and welcome homecoming.

(ra, yk, il)
Categories: Web Design

Creativity Sparks Shining Through The Fog (November 2019 Wallpapers Edition)

Smashing Magazine - Thu, 10/31/2019 - 03:00
Creativity Sparks Shining Through The Fog (November 2019 Wallpapers Edition) Creativity Sparks Shining Through The Fog (November 2019 Wallpapers Edition) Cosima Mielke 2019-10-31T12:00:00+02:00 2019-11-11T11:16:28+00:00

The fascinating world of aviation, classic movies, sweet childhood memories — these are just some of the things that inspired artists and designers from across the globe to participate in our wallpapers challenge this time around.

The monthly challenge has been going on for more than nine years already and we are very thankful to everyone who tickles their creativity each month anew to keep the steady stream of wallpapers flowing and caters for some colorful inspiration with their artwork — no matter how gray the weather outside might be.

The wallpapers in this collection come in versions with and without a calendar for November 2019, so it’s up to you to decide if you want to keep things minimalistic or have an overview of the month at a glance. As a bonus goodie, we also compiled a little best-of from past November editions at the end of the post. Maybe you’ll rediscover some long-forgotten favorites in there? Happy November!

Please note that:

  • All images can be clicked on and lead to the preview of the wallpaper,
  • We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.
Submit your wallpaper

We are always looking for designers and artists to be featured in our wallpapers posts. So if you have an idea for a December wallpaper, please don’t hesitate to submit your design. We’d love to see what you’ll come up with. Join in! →

International Civil Aviation Day

“On December 7, we mark International Civil Aviation Day, celebrating those who prove day by day that the sky really is the limit. As the engine of global connectivity, civil aviation is now, more than ever, a symbol of social and economic progress and a vehicle of international understanding. This monthly calendar is our sign of gratitude to those who dedicate their lives to enabling everyone to reach their dreams.” — Designed by PopArt Studio from Serbia.

Don’t Let Gray Win

“Let’s take extra care of colors during the autumn months. November might be gray and rainy. Outside. Don’t let it inside. Take a good book, prepare a hot ginger tea, and cover your knees with a bright woolen plaid.” — Designed by Tartanify from France.

Before Sunset In Paris

“The inspiration came from the movies of Woody Allen and his amazing cinematography, the framing idea came from the polaroid photos.” — Designed by João Pinto from Portugal.


“November is the month of my birth so it reminds me of so many good things. The scent and the beautiful red colors of pomegranate seeds. The beauty of their trees with tiny leaves. The magical colors of autumn take me to the orchards on the farm and my family together under the sun and clouds. Laughings and pumpkins on the floor while the sheets were hung to dry on the clothesline. Cousins playing and collecting leaves. Sweet November.” — Designed by Carmen Navalhas from Portugal.

Seasonal Sunsets

“Fall is such a beautiful time of year so I designed a wallpaper inspired by fall’s seasonal colors and amazing sunsets.” — Designed by Kassandra Escoe from Maryland.

No-Shave November

“The goal of No-Shave November is to grow awareness by embracing our hair, which many cancer patients lose, and letting it grow wild and free. Donate the money you typically spend on shaving and grooming to educate about cancer prevention, save lives, and aid those fighting the battle.” — Designed by Tatiana Ignatieva from Portugal.

Fishing At Sunset

“November is a month for calm. It’s cold and we enjoy fishing with lions.” — Designed by Veronica Valenzuela from Spain.

The Power Of Imagination

Designed by Ricardo Gimenes from Sweden.

Oldies But Goodies

Some things are just too good to gather dust. Hidden in our wallpaper archives we rediscovered some November favorites from past years. Ready for a trip back in time? (Please note that these designs don’t come with a calendar.)

Outer Space

“This November, we are inspired by the nature around us and the universe above us, so we created an out-of-this-world calendar. Now, let us all stop for a second and contemplate on preserving our forests, let us send birds of passage off to warmer places, and let us think to ourselves — if not on Earth, could we find a home somewhere else in outer space?” — Designed by PopArt Studio from Serbia.


“I don’t know anyone who hasn’t enjoyed a cold night looking at the stars.” — Designed by Ema Rede from Portugal.

The Kind Soul

“Kindness drives humanity. Be kind. Be humble. Be humane. Be the best of yourself!” — Designed by Color Mean Creative Studio from Dubai.

Autumn Darkness

“‘When autumn darkness falls, what we will remember are the small acts of kindness: a cake, a hug, an invitation to talk, and every single rose. These are all expressions of a nation coming together and caring about its people.’ (Jens Stoltenberg)” — Designed by Dipanjan Karmakar from India.

Tempestuous November

“By the end of autumn, ferocious Poseidon will part from tinted clouds and timid breeze. After this uneven clash, the sky once more becomes pellucid just in time for imminent luminous snow.” — Designed by Ana Masnikosa from Belgrade, Serbia.

Peanut Butter Jelly Time!

“November is the Peanut Butter Month so I decided to make a wallpaper around that. As everyone knows peanut butter goes really well with some jelly so I made two sandwiches, one with peanut butter and one with jelly. Together they make the best combination. I also think peanut butter tastes pretty good so that’s why I chose this for my wallpaper.” — Designed by Senne Mommens from Belgium.

Music From Nature

Designed by StarAdmin from India.

The Most Productive Month

“Working hard or hardly working? What will your work stats look like in November?” Designed by Photo Stats from Sweden.

Curious Squirrel

Designed by Saul Wauters from Belgium.

Fall Breeze

“The colorful leaves and cool breeze that make you want to snuggle in your couch at home inspired me to create this fall design.” — Designed by Allison Coyle from the United States.

Autumn In Paris

Designed by Lia Pantazi from Greece.

World Kindness Day

“World Kindness Day is November 13, and I wanted to share this saying to remind others to never underestimate the power of a kind word.” — Designed by Shawna Armstrong from the United States.

Coffee Time

“It’s the time for being at home and enjoying the small things… I love having a coffee while watching the rain outside my window.” — Designed by Veronica Valenzuela from Spain.

Thanks & Giving

“Wishing everyone a holiday season filled with both Thanks & Giving!” — Designed by Jordan Thoma from the United States.

On The Edge Of Forever

“November has always reminded me of the famous Guns N’ Roses song, so I’ve decided to look at its meaning from a different perspective. The story in my picture takes place somewhere in space, where a young guy beholds a majestic meteor shower and wonders about the mysteries of the universe.” — Designed by Aliona Voitenko from Ukraine.

November Ingredients

“Whether or not you celebrate Thanksgiving, there’s certain things that always make the harvest season special. As a Floridian, I’m a big fan of any signs that the weather might be cooling down soon, too!” — Designed by Dorothy Timmer from the United States.

All Lines Point To November

“November often means rain and cold temps, but there’s beauty to be found in that as I found in this moment — the wet lines lead the way.” — Designed by Aisha Souto-Maior, Paris-based, NY-bred.

Simple Leaves

Designed by Nicky Somers from Belgium.


“It’s cold in November, so you have to stay closer. Also: Inktober and American Horror Story.” — Designed by Anja Sturm from Germany.

The Collection Of Birds

“The collection of birds are my travels. At each destination I buy a wood, bronze, stone bird, anything the local bazaars sell. I have all gathered at a modest vitrine in my house. I have so much loved my collection that, after taking pictures of them, I designed each one, then created a wallpaper and overdressed a wall of my living room. Now my thought is making them as a desktop wallpaper and give them to you as a gift.” — Designed by Natasha Kamou from Greece.

First Icicles Of The Coming Winter

Designed by Aleksandra Sivoronova from Latvia.

Autumn Impression

Designed by Agnieszka Malarczyk from Poland.


“Here is a wallpaper that celebrates the arrival of spring in the southern hemisphere.” Designed by Finxduvey from Argentina.

Join In Next Month!

Thank you to all designers for their participation. Join in next month!

Categories: Web Design

Writing A Multiplayer Text Adventure Engine In Node.js: Creating The Terminal Client (Part 3)

Smashing Magazine - Wed, 10/30/2019 - 04:00
Writing A Multiplayer Text Adventure Engine In Node.js: Creating The Terminal Client (Part 3) Writing A Multiplayer Text Adventure Engine In Node.js: Creating The Terminal Client (Part 3) Fernando Doglio 2019-10-30T13:00:59+02:00 2019-11-11T11:16:28+00:00

I first showed you how to define a project such as this one, and gave you the basics of the architecture as well as the mechanics behind the game engine. Then, I showed you the basic implementation of the engine — a basic REST API that allows you to traverse a JSON-defined world.

Today, I’m going to be showing you how to create an old-school text client for our API by using nothing other than Node.js.

Other Parts Of This Series

  • Part 1: The Introduction
  • Part 2: Game Engine Server Design
  • Part 4: Adding Chat Into Our Game

Reviewing The Original Design

When I first proposed a basic wireframe for the UI, I proposed four sections on the screen:

(Large preview)

Although in theory that looks right, I missed the fact that switching between sending game commands and text messages would be a pain, so instead of having our players switching manually, we’ll have our command parser make sure it is capable of discerning whether we’re trying to communicate with the game or our friends.

So, instead of having four sections in our screen, we’ll now have three:

(Large preview)

That is an actual screenshot of the final game client. You can see the game screen on the left, and the chat on the right, with a single, common input box at the bottom. The module we’re using allows us to customize colors and some basic effects. You’ll be able to clone this code from Github and do what you want with the look and feel.

One caveat though: Although the above screenshot shows the chat working as part of the application, we’ll keep this article focused on setting up the project and defining a framework where we can create a dynamic text-UI based application. We’ll focus on adding chat support on the next and final chapter of this series.

The Tools We’ll Need

Although there are many libraries out there that let us create CLI tools with Node.js, adding a text-based UI is a completely different beast to tame. Particularly, I was able to find only one (very complete, mind you) library that would let me do exactly what I wanted: Blessed.

This library is very powerful and provides a lot of features we won’t be using for this project (such as casting shadows, drag&drop, and others). It basically re-implements the entire ncurses library (a C library which allows developers to create text-based UIs) which has no Node.js bindings, and it does so directly in JavaScript; so, if we had to, we could very well check out its internal code (something I wouldn’t recommend unless you absolutely had to).

Although the documentation for Blessed is quite extensive, it mainly consists of individual details about each method provided (as opposed to having tutorials explaining how to actually use those methods together) and it is lacking examples everywhere, so it might be difficult to dig into it if you have to understand how a particular method works. With that being said, once you understand it for one, everything works the same way, which is a big plus since not every library or even language (I’m looking at you, PHP) has a consistent syntax.

But documentation aside; the big plus for this library is that it works based on JSON options. For example, if you wanted to draw a box on the top right corner of the screen, you would do something like this:

var box = blessed.box({ top: ‘0', right: '0', width: '50%', height: '50%', content: 'Hello {bold}world{/bold}!', tags: true, border: { type: 'line' }, style: { fg: 'white', bg: 'magenta', border: { fg: '#f0f0f0' }, hover: { bg: 'green' } } });

As you can imagine, other aspects of the box are defined there as well (such as it’s size), which can perfectly be dynamic based on the terminal’s size, type of border and colors — even for hover events. If you’ve done front-end development at some point, you’ll find a lot of overlap between the two.

The point I’m trying to make here is that everything regarding the representation of the box is configured through the JSON object passed to the box method. That, to me, is perfect because I can easily extract that content into a configuration file, and create a business logic capable of reading it and deciding which elements to draw on screen. Most importantly, it will help us get a glimpse of how they’ll look once they’ve been drawn.

This will be the base for the entire UI aspect of this module (more on that in a second!).

Architecture Of The Module

The main architecture of this module relies entirely on the UI widgets which we’ll be showing. A group of these widgets is considered a screen, and all these screens are defined in a single JSON file (which you can find inside the /config folder).

This file has over 250 lines, so showing it here makes no sense. You can look at the full file online, but a small snippet from it looks like this:

"screens": { "main-options": { "file": "./main-options.js", "elements": { "username-request": { "type": "input-prompt", "params": { "position": { "top": "0%", "left": "0%", "width": "100%", "height": "25%" }, "content": "Input your username: ", "inputOnFocus": true, "border": { "type": "line" }, "style": { "fg": "white", "bg": "blue", "border": { "fg": "#f0f0f0" }, "hover": { "bg": "green" } } } }, "options": { "type": "window", "params": { "position": { "top": "25%", "left": "0%", "width": "100%", "height": "50%" }, "content": "Please select an option: \n1. Join an existing game.\n2. Create a new game", "border": { "type": "line" }, "style": { //... } } }, "input": { "type": "input", "handlerPath": "../lib/main-options-handler", //... } } }

The “screens” element will contain the list of screens inside the application. Each screen contains a list of widgets (which I’ll cover in a bit) and every widget has its blesses-specific definition and related handler files (when applicable).

You can see how every “params” element (inside a particular widget) represents the actual set of parameters expected by the methods we saw earlier. The rest of the keys defined there help provide context about what type of widgets to render and their behavior.

A few points of interest:

Screen Handlers

Every screen element has file property which references the code associated to that screen. This code is nothing but an object that must have an init method (the initialization logic for that particular screen takes place inside of it). Particularly, the main UI engine, will call that init method of every screen, which in turn, should be responsible for initializing whatever logic it may need (i.e setting up the input boxes events).

The following is the code for the main screen, where the application requests the player to select an option to either start a brand new game or join an existing one:

const logger = require("../utils/logger") module.exports = { init: function(elements, UI) { this.elements = elements this.UI = UI this.id = "main-options" this.setInput() }, moveToIDRequest: function(handler) { return this.UI.loadScreen('id-requests', (err, ) => { }) }, createNewGame: function(handler) { handler.createNewGame(this.UI.gamestate.APIKEY, (err, gameData) => { this.UI.gamestate.gameID = gameData._id handler.joinGame(this.UI.gamestate, (err) => { return this.UI.loadScreen('main-ui', { flashmessage: "You've joined game " + this.UI.gamestate.gameID + " successfully" }, (err, ) => { }) }) }) }, setInput: function() { let handler = require(this.elements["input"].meta.handlerPath) let input = this.elements["input"].obj let usernameRequest = this.elements['username-request'].obj let usernameRequestMeta = this.elements['username-request'].meta let question = usernameRequestMeta.params.content.trim() usernameRequest.setValue(question) this.UI.renderScreen() let validOptions = { 1: this.moveToIDRequest.bind(this), 2: this.createNewGame.bind(this) } usernameRequest.on('submit', (username) => { logger.info("Username:" +username) logger.info("Playername: " + username.replace(question, '')) this.UI.gamestate.playername = username.replace(question, '') input.focus() input.on('submit', (data) => { let command = input.getValue() if(!validOptions[+command]) { this.UI.setUpAlert("Invalid option: " + command) return this.UI.renderScreen() } return validOptions[+command](handler) }) }) return input } }

As you can see, the init method calls the setupInput method which basically configures the right callback to handle user input. That callback holds the logic to decide what to do based on the user’s input (either 1 or 2).

Widget Handlers

Some of the widgets (usually input widgets) have a handlerPath property, which references the file containing the logic behind that particular component. This is not the same as the previous screen handler. These don’t care about the UI components that much. Instead, they handle the glue logic between the UI and whatever library we’re using to interact with external services (such as the game engine’s API).

Widget Types

Another minor addition to the JSON definition of the widgets is their types. Instead of going with the names Blessed defined for them, I’m creating new ones in order to give me more wiggle room when it comes to their behavior. After all, a window widget might not always “just display information”, or an input box might not always work the same way.

This was mostly a preemptive move, just to ensure I have that ability if I ever need it in the future, but as you’re about to see, I’m not using that many different types of components anyway.

Multiple Screens

Though the main screen is the one I showed you in the screenshot above, the game requires a few other screens in order to request things such as your player name or whether you’re creating a brand new game session or even joining an existing one. The way I handled that was, again, through the definition of all these screens in the same JSON file. And to move from one screen into the next one, we use the logic inside the screen handler files.

We can do this simply by using the following line of code:

this.UI.loadScreen('main-ui', (err ) => { if(err) this.UI.setUpAlert(err) })

I’ll show you more details about the UI property in a second, but I’m just using that loadScreen method to re-render the screen and picking the right components off of the JSON file using the string passed as parameter. Very straightforward.

Code Samples

It’s now time to check out the meat and potatoes of this article: the code samples. I’m just going to highlight what I think are the small gems inside it, but you can always take a look at the full source code directly in the repository anytime.

Using Config Files To Auto Generate The UI

I’ve already covered part of this, but I think it’s worth exploring the details behind this generator. The gist behind it (file index.js inside the /ui folder) is that it is a wrapper around the Blessed object. And the most interesting method inside it, is the loadScreen method.

This method grabs the configuration (through the config module) for one specific screen and goes through its content, trying to generate the right widgets based on each element’s type.

loadScreen: function(sname, extras, done) { if(typeof extras == "function") { done = extras } let screen = config.get('screens.' + sname) let screenElems = {} if(this.screenElements.length > 0) { //remove previous screen this.screenElements.map( e => e.detach()) this.screen.realloc() } Object.keys(screen.elements).forEach( eName => { let elemObj = null let element = screen.elements[eName] if(element.type == 'window') { elemObj = this.setUpWindow(element) } if(element.type == 'input') { elemObj = this.setUpInputBox(element) } if(element.type == 'input-prompt') { elemObj = this.setUpInputBox(element) } screenElems[eName] = { meta: element, obj: elemObj } }) if(typeof extras === 'object' && extras.flashmessage) { this.setUpAlert(extras.flashmessage) } this.renderScreen() let logicPath = require(screen.file) logicPath.init(screenElems, this) done() },

As you can see, the code is a bit lengthy, but the logic behind it is simple:

  1. It loads the configuration for the current specific screen;
  2. Cleans up any previously existing widgets;
  3. Goes over every widget and instantiates it;
  4. If an extra alert was passed as a flash message (which is basically a concept I stole from Web Dev in which you setup a message to be shown on screen until the next refresh);
  5. Render the actual screen;
  6. And finally, require the screen handler and execute it’s “init” method.

That’s it! You can check out the rest of the methods — they’re mostly related to individual widgets and how to render them.

Communication Between UI And Business Logic

Although in the grand scale, the UI, the back-end and the chat server all have a somewhat layered-based communication; the front end itself needs at least a two-layered internal architecture in which the pure UI elements interact with a set of functions that represent the core logic inside this particular project.

The following diagram shows the internal architecture for the text client we’re building:

(Large preview)

Let me explain it a bit further. As I mentioned above, the loadScreenMethod will create UI presentations of the widgets (these are Blessed objects). But they are contained as part of the screen logic object which is where we set up the basic events (such as onSubmit for input boxes).

Allow me to give you a practical example. Here is the first screen you see when starting the UI client:

(Large preview)

There are three sections on this screen:

  1. Username request,
  2. Menu options / information,
  3. Input screen for the menu options.

Basically, what we want to do is to request the username and then ask them to pick one of the two options (either starting up a brand new game or joining an existing one).

The code that takes care of that is the following:

module.exports = { init: function(elements, UI) { this.elements = elements this.UI = UI this.id = "main-options" this.setInput() }, moveToIDRequest: function(handler) { return this.UI.loadScreen('id-requests', (err, ) => { }) }, createNewGame: function(handler) { handler.createNewGame(this.UI.gamestate.APIKEY, (err, gameData) => { this.UI.gamestate.gameID = gameData._id handler.joinGame(this.UI.gamestate, (err) => { return this.UI.loadScreen('main-ui', { flashmessage: "You've joined game " + this.UI.gamestate.gameID + " successfully" }, (err, ) => { }) }) }) }, setInput: function() { let handler = require(this.elements["input"].meta.handlerPath) let input = this.elements["input"].obj let usernameRequest = this.elements['username-request'].obj let usernameRequestMeta = this.elements['username-request'].meta let question = usernameRequestMeta.params.content.trim() usernameRequest.setValue(question) this.UI.renderScreen() let validOptions = { 1: this.moveToIDRequest.bind(this), 2: this.createNewGame.bind(this) } usernameRequest.on('submit', (username) => { logger.info("Username:" +username) logger.info("Playername: " + username.replace(question, '')) this.UI.gamestate.playername = username.replace(question, '') input.focus() input.on('submit', (data) => { let command = input.getValue() if(!validOptions[+command]) { this.UI.setUpAlert("Invalid option: " + command) return this.UI.renderScreen() } return validOptions[+command](handler) }) }) return input } }

I know that’s a lot of code, but just focus on the init method. The last thing it does is to call the setInput method which takes care of adding the right events to the right input boxes.

Therefore, with these lines:

let handler = require(this.elements["input"].meta.handlerPath) let input = this.elements["input"].obj let usernameRequest = this.elements['username-request'].obj let usernameRequestMeta = this.elements['username-request'].meta let question = usernameRequestMeta.params.content.trim()

We’re accessing the Blessed objects and getting their references, so that we can later set up the submit events. So after we submit the username, we’re switching focus to the second input box (literally with input.focus() ).

Depending on what option we choose from the menu, we’re calling either of the methods:

  • createNewGame: creates a new game by interacting with its associated handler;
  • moveToIDRequest: renders the next screen in charge of requesting the game ID to join.
Communication With The Game Engine

Last but certainly not least (and following the above example), if you hit 2, you’ll notice that the method createNewGame uses the handler’s methods createNewGame and then joinGame (joining the game right after creating it).

Both these methods are meant to simplify the interaction with the Game Engine’s API. Here is the code for this screen’s handler:

const request = require("request"), config = require("config"), apiClient = require("./apiClient") let API = config.get("api") module.exports = { joinGame: function(apikey, gameId, cb) { apiClient.joinGame(apikey, gameId, cb) }, createNewGame: function(apikey, cb) { request.post(API.url + API.endpoints.games + "?apikey=" + apikey, { //creating game body: { cartridgeid: config.get("app.game.cartdrigename") }, json: true }, (err, resp, body) => { cb(null, body) }) } }

There you see two different ways to handle this behavior. The first method actually uses the apiClient class, which again, wraps the interactions with the GameEngine into yet another layer of abstraction.

The second method though performs the action directly by sending a POST request to the correct URL with the right payload. Nothing fancy is done afterwards; we’re just sending the body of the response back to the UI logic.

Note: If you’re interested in the full version of the source code for this client, you can check it out here.

Final Words

This is it for the text-based client for our text adventure. I covered:

  • How to structure a client application;
  • How I used Blessed as the core tech for creating the presentation layer;
  • How to structure the interaction with the back-end services from a complex client;
  • And hopefully, with the full repository available.

And while the UI might not look exactly like the original version did, it does fulfill its purpose. Hopefully, this article gave you an idea of how to architect such an endeavor and you were inclined to try it for yourself in the future. Blessed is definitely a very powerful tool, but you’ll have to have patience with it while learning how to use it and how to navigate through their docs.

In the next and final part, I’ll cover how I added the chat server both on the back-end as well as for this text client.

See you on the next one!

Other Parts Of This Series

  • Part 1: The Introduction
  • Part 2: Game Engine Server Design
  • Part 4: Adding Chat Into Our Game

(dm, yk, il)
Categories: Web Design

Speed Up Your Website With WebP

Smashing Magazine - Tue, 10/29/2019 - 03:30
Speed Up Your Website With WebP Speed Up Your Website With WebP Suzanne Scacca 2019-10-29T12:30:59+02:00 2019-11-11T11:16:28+00:00

(This is a sponsored post.) Spend enough time running websites through PageSpeed Insights and you’ll notice that Google has a major beef with traditional image formats like JPG, PNG and even GIF. As well it should.

Even if you resize your images to the exact specifications of your website and run them through a compressor, they can still put a strain on performance and run up bandwidth usage. Worse, all of that image manipulation can compromise the resulting quality.

Considering how important images are to web design, this isn’t an element we can dispose of so easily nor can we afford to cut corners when it comes to optimizing them. So, what’s the solution?

Here’s what Google suggests:

PageSpeed Insights demonstrates how much storage and bandwidth websites stand to save with WebP. (Source: PageSpeed Insights) (Large preview)

Years ago, Google aimed to put a stop to this problem by creating a next-gen image format called WebP. You can see in this screenshot from PageSpeed Insights that Google recommends using WebP and other next-gen formats to significantly reduce the size of your images while preserving their quality.

And if .75 seconds doesn’t seem like much to you (at least in this example), it could make a big difference in the lives of your visitors, the people who sit there wondering how long is too long to wait. Just one less second of loading could make a world of difference to your conversion rate.

But is WebP the best solution for this problem? Today, we’re going to examine:

What is WebP?

Google developed WebP back in 2010 after acquiring a company called On2 Technologies. On2 had worked on a number of video compression technologies, which ended up serving as the basis for Google’s new audiovisual format WebM and next-gen image format WebP.

Originally, WebP used lossy compression in an attempt to create smaller yet still high-quality images for the web.

If .75 seconds doesn’t seem like much to you, it could make a big difference in the lives of your visitors, the people who sit there wondering how long is too long to wait.

“ Lossy Compression For WebP

Lossy compression is a form of compression used to greatly reduce the file sizes of JPGs and GIFs. In order to make that happen, though, some of the data (pixels) from the file needs to be dropped out or “lost”. This, in turn, leads to some degradation of the quality of the image, though it’s not always noticeable.

WebP entered the picture with a much more efficient use of lossy compression (which I’ll explain below) and became the much-needed successor to JPG.

You can see a great demonstration of this difference as KeyCDN compares the difference in file sizes of a compressed JPG vs. WebP:

KeyCDN shows how five images differ in size between the original, a compressed JPG and a WebP. (Source: KeyCDN) (Large preview)

Notice how significant a difference this is in terms of file size, even after the JPG has been compressed to a comparable quality. As Adrian James explains here, though, you have to be careful with WebP compression.

“Compression settings don’t match up one-to-one with JPEG. Don’t expect a 50%-quality JPEG to match a 50%-quality WebP. Quality drops pretty sharply on the WebP scale, so start at a high quality and work your way down.”

Considering how much more file sizes shrink with WebP compared to JPG, though, that shouldn’t be too much of a sticking point. It’s just something to think about if you’re considering pushing the limits of what WebP can do even further.

Now, as time passed, Google continued to develop WebP technology, eventually getting it to a point where it would support not just true-color web graphics, but also XMP metadata, color profiles, tiling, animation, and transparency.

Eventually, Google brought lossless compression to WebP, turning it into a viable contender for PNG, too.

Lossless Compression For WebP

Lossless compression does not degrade image quality the way lossy does. Instead, it achieves smaller file sizes by removing excess metadata from the backend of the file. This way, the quality of the image remains intact while reducing its size. That said, lossless compression can’t achieve the kinds of file sizes lossy compression can.

That was until WebP’s lossless compression came along.

You can see some beautiful examples of how WebP’s lossy and lossless compression stands up against PNG in Google’s WebP galleries:

The Google WebP Galleries show how PNG images compare in quality and size to compressed WebPs. (Source: Google) (Large preview)

If there’s any degradation in the quality of the WebP images, it’s going to be barely noticeable to your visitors. The only thing they’re really going to notice is how quickly your site loads.

What Are The Advantages Of Using WebP?

It’s not enough to say that WebP is “better” than JPG and PNG. It’s important to understand the mechanics of how WebP works and why it’s so beneficial to use over other file formats as a result.

With traditional image formats, compression always results in a tradeoff.

JPG lossy compression leads to degradation of the clarity and fineness of an image. Once applied, it cannot be reversed.

WebP lossy compression, on the other hand, uses what’s known as prediction coding to more accurately adjust the pixels in an image. As Google explains, there are other factors at work, too:

“Block adaptive quantization makes a big difference, too. Filtering helps at mid/low bitrates. Boolean arithmetic encoding provides 5%-10% compression gains compared to Huffman encoding.”

On average, Google estimates that WebP lossy compression results in files that are between 25% and 34% smaller than JPGs of the same quality.

As for PNG lossless compression, it does work well in maintaining the quality of an image, but it doesn’t have as significant an impact on image size as its JPG counterpart. And certainly not when compared to WebP.

WebP handles this type of compression more efficiently and effectively. This is due to the variety of compression techniques used as well as entropy encoding applied to images. Again, Google explains how it works:

“The transforms applied to the image include spatial prediction of pixels, color space transform, using locally emerging palettes, packing multiple pixels into one pixel and alpha replacement.”

On average, Google estimates that WebP lossless compression results in files that are roughly 26% smaller than PNGs of the same quality.

That’s not all. WebP has the ability to do something that no other file formats can do. Designers can use WebP lossy encoding on RGB colors and lossless encoding on images with transparent backgrounds (alpha channel).

Animated images, otherwise served in GIF format, also benefit from WebP compression systems. There are a number of reasons for this:

GIF WebP Compression Lossless Lossless + lossy RBG Color Support 8-bit 24-bit Alpha Channel Support 1-bit 8-bit

As a result of this powerful combo of lossless and lossy compression, animated videos can get down to much smaller sizes than their GIF counterparts.

Google estimates the average reduction to be about 64% of the original size of a GIF when using lossy compression and 19% when using lossless.

Needless to say, there’s nothing that can beat WebP when it comes to speed while maintaining image integrity.

“ Acceptance Of WebP Among Browsers, Devices And CMS

As you can imagine, when WebP was first released, it was only supported by Google’s browsers and devices. Over time, though, other platforms have begun to provide support for WebP images.

That said, WebP still doesn’t have universal support, which can cause problems for web designers who use this image format by default.

Let’s take a look at where you can expect full acceptance of your WebP images, where you won’t and then we’ll discuss what you can do to get around this hiccup.

As of writing this in 2019, Can I use… has accounted for the following platforms that support WebP:

‘Can I Use’ breaks down which browsers and versions of those browsers provide support for WebP. (Source: Can I use...) (Large preview)

The latest versions of the following platforms are supported:

  • Edge
  • Firefox
  • Chrome
  • Opera
  • Opera Mini
  • Android Browser
  • Opera Mobile
  • Chrome for Android
  • Firefox for Android
  • UC Browser for Android
  • Samsung Internet
  • QQ Browser
  • Baidu Browser

The platforms that continue to hold back support are:

  • Internet Explorer
  • Safari
  • iOS Safari
  • KaiOS Browser

It’s not just browsers that are on the fence about WebP. Image editing software and content management systems are, too.

ImageMagick, Pixelmator and GIMP all support WebP, for instance. Sketch enables users to export files as WebP. And for software that doesn’t natively support WebP, like Photoshop, users can usually install a plugin which will allow them to open and save files as WebP.

Content management systems are in a similar spot. Some have taken the lead in moving their users over to WebP, whether they uploaded their files in that format or not. Shopify and Wix are two site builders that automatically convert and serve images in WebP format.

Although there are other platforms that don’t natively support WebP, there are usually extensions or plugins you can use to upload WebP images or convert uploaded ones into this next-gen format.

WordPress is one of those platforms. Drupal is another popular CMS that provides users with WebP modules that add WebP support. Magento is yet another.

It’s pretty rare not to find some sort of add-on support for WebP. The only example that I’m aware of that doesn’t accept it is Squarespace.

Challenges Of Converting And Delivering WebP

Okay, so WebP doesn’t have 100% support on the web. Not yet anyway. That’s okay. For the most part, we have some sort of workaround in terms of adding support to the tools we use to design and build websites.

But what do we do about the browser piece? If our visitors show up on an iOS device, how do we make sure they’re still served an image if our default image is WebP?

First, you need to know how to convert images into WebP.

Last year, front end developer Jeremy Wagner wrote up a guide for Smashing Magazine on this very topic. In it, he covers how to convert to WebP using:

  • Sketch,
  • Photoshop,
  • The command line,
  • Bash,
  • Node.js,
  • gulp,
  • Grunt,
  • webpack.

Any of these options will help you convert your PNGs and JPGs into WebPs. Your image editing software will only get you halfway to your destination though.

It’ll handle the conversion, but it won’t help you modify your origin server so that it knows when to deliver WebPs and when to deliver a traditional image format to visitors.

Some of these methods let you dictate how your server delivers images based on the restraints of your visitors’ browsers. Still, it takes a bit of work to modify the origin servers to make this happen. If you’re not comfortable doing that or you don’t want to deal with it, KeyCDN has a solution.

The Solution: Simplify WebP Delivery With KeyCDN

KeyCDN understands how important it is to have a website that loads at lightning-fast speeds. It’s what KeyCDN is in the business to do. That’s why it’s no surprise that it’s developed a built-in WebP caching and image processing solution that helps developers more easily deliver the right file formats to visitors.

What Is WebP Caching?

Caching is an integral part of keeping any website running fast. And WebP caching is only going to make it better. Essentially, it’s a form of content negotiation that takes place in the HTTP header.

It works like this:

Someone visits a website that has KeyCDN’s WebP caching enabled. The visitor’s browser sends an accept HTTP header as part of the request to the server with a list of asset types it prefers. But rather than go to the origin server (at the web host), the request is processed by the edge server (at KeyCDN). The edge server reviews the list of acceptable file types and sends a content-type header in response.

Here’s an example of how that might look:

curl -I 'https://ip.keycdn.com/example.jpg' -H 'accept: image/webp' HTTP/2 200 server: keycdn-engine date: Thu, 06 Jun 2019 08:29:50 GMT content-type: image/webp content-length: 56734 last-modified: Tue, 14 May 2019 23:36:28 GMT etag: "5cdb50fc-1040a" expires: Thu, 13 Jun 2019 08:29:50 GMT cache-control: max-age=604800 x-ip: 1 x-ip-info: osz=56734 odim=700x467 ofmt=webp x-cache: HIT x-shield: active x-edge-location: chzh access-control-allow-origin: * accept-ranges: bytes

An example of a content-type request that KeyCDN sends to browsers that accept WebP. (Source: KeyCDN)

So, for Google Chrome visitors, the content-type: image/webp would automatically be accepted and the cached WebP assets would be delivered to the browser.

For Safari users, on the other hand, the request would go unaccepted. But that’s okay. Your CDN will know which file format to send instead. In the first line in the example above, you can see that the original image format is JPG, so that’s the version of the file that would be delivered.

As you can see, there’s no need to modify the origin server or prepare multiple versions of your files in order to account for WebP compatibility. KeyCDN WebP caching handles all of it.

How Do You Use KeyCDN WebP Caching?

There are two ways in which KeyCDN users can take advantage of the WebP caching feature.

Image Processing Through KeyCDN

The first requires nothing more than flipping a switch and turning on KeyCDN’s image processing. Once enabled, the accept request header will automatically load.

You can, of course, use the image processing service for more than just WebP caching. You can use it to adjust the size, crop, rotation, blur, and other physical attributes of your delivered images. But if you’re trying to simplify your image delivery system and simply want to speed things up with WebP, just enable the feature and let KeyCDN do the work.

WebP Caching Through Your Origin Server

Let’s say that you generated your own WebP image assets. You can still reap the benefits of KeyCDN’s WebP caching solution.

To do this, you’ll need to correctly generate your WebPs. Again, here’s a link to the guide that shows you how to do that.

It’s then up to you to configure your origin server so that it only delivers WebPs when accept: image/webp is present. KeyCDN provides some examples of how you’ll do this with Nginx:

# http config block map $http_accept $webp_ext { default ""; "~*webp" ".webp"; } # server config block location ~* ^(/path/to/your/images/.+)\.(png|jpg)$ { set $img_path $1; add_header Vary Accept; try_files $img_path$webp_ext $uri =404; }

KeyCDN demonstrates how you can modify the origin server with Nginx to deliver your own cached WebP assets. (Source: KeyCDN)

And with Apache:

<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_ACCEPT} image/webp RewriteCond %{DOCUMENT_ROOT}/$1.webp -f RewriteRule ^(path/to/your/images.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1] </IfModule> <IfModule mod_headers.c> Header append Vary Accept env=REDIRECT_accept </IfModule> AddType image/webp .webp

KeyCDN demonstrates how you can modify the origin server with Apache to deliver your own cached WebP assets. (Source: KeyCDN)

Obviously, this option gives you more control over managing your image formats and how they’re served to visitors. That said, if you’re new to using WebP, KeyCDN’s automated WebP caching and image processing is probably your best bet.

An Alternative For WordPress And Magento Designers

If you design websites in WordPress or Magento, KeyCDN has plugins you can use to add WebP support and caching.

For WordPress, you’ll use KeyCDN’s custom Cache Enabler along with Optimus.

The Cache Enabler plugin offers delivery support for WebPs in WordPress. (Source: Cache Enabler) (Large preview)

Cache Enabler checks to see if your images have a WebP version. If it exists and the visitor’s browser supports it, that’s what it will deliver in the cached file. If it doesn’t exist, then it’ll simply turn to the JPG, PNG or GIF that’s there.

Magento developers have a simplified workaround for converting and delivering WebP, too. First, you’ll need to install the Webp extension. Then, you’ll have to configure the WebP binaries on your server.

Wrapping Up

There’s a reason why Google went to the trouble of developing a new image format and why more and more browsers, design systems and content management systems are supporting it.

Images can cause a lot of problems for websites that have otherwise been built to be lean and mean. If they’re not uploaded at the right size, if they’re not compressed and if caching isn’t enabled, your images could be the reason that your website’s speed is driving visitors away.

But with WebP, your website is sure to load more quickly. What’s more, there doesn’t need to be a tradeoff between image quality (or quantity!) in order to gain that speed. WebP efficiently compresses files while preserving the integrity of the image content.

If you’re really struggling to increase the speed of your website then WebP should be the next tool you turn to for help.

(ms, ra, il)
Categories: Web Design

Writing Asynchronous Tasks In Modern JavaScript

Smashing Magazine - Fri, 10/25/2019 - 03:30
Writing Asynchronous Tasks In Modern JavaScript Writing Asynchronous Tasks In Modern JavaScript Jeremias Menichelli 2019-10-25T12:30:59+02:00 2019-10-29T11:47:34+00:00

JavaScript has two main characteristics as a programming language, both important to understand how our code will work. First is its synchronous nature, which means the code will run line after line, almost as you read it, and secondly that it is single-threaded, only one command is being executed at any time.

As the language evolved, new artifacts appeared in the scene to allow asynchronous execution; developers tried different approaches while solving more complicated algorithms and data flows, which led to the emergence of new interfaces and patterns around them.

Synchronous Execution And The Observer Pattern

As mentioned in the introduction, JavaScript runs the code you write line by line, most of the time. Even in its first years, the language had exceptions to this rule, though they were a few and you might know them already: HTTP Requests, DOM events and time intervals.

If we add an event listener to respond to the click of an element from the user, it doesn’t matter what the language interpreter is running it will stop, run the code we wrote in the listener callback and then go back to its normal flow.

Same with an interval or a network request, addEventListener, setTimeout, and XMLHttpRequest were the first artifacts to access to asynchronous execution for web developers.

Though these were exceptions of synchronous execution in JavaScript, it’s crucial to understand that the language is still single-threaded. We can break this synchronicity but the interpreter still will run one line of code at a time.

For example, let’s check out a network request.

var request = new XMLHttpRequest(); request.open('GET', '//some.api.at/server', true); // observe for server response request.onreadystatechange = function() { if (request.readyState === 4 && xhr.status === 200) { console.log(request.responseText); } } request.send();

No matter what is happening, by the time the server comes back, the method assigned to onreadystatechange gets called before taking back the program’s code sequence.

Something similar happens when reacting to user interaction.

const button = document.querySelector('button'); // observe for user interaction button.addEventListener('click', function(e) { console.log('user click just happened!'); })

You might notice that we are hooking up to an external event and passing a callback, telling the code what to do when it takes place. Over a decade ago, “What is a callback?” was a pretty much-expected interview question because this pattern was everywhere in most codebases.

In each case mentioned, we are responding to an external event. A certain interval of time reached, a user action or a server response. We weren’t able to create an asynchronous task per se, we always observed occurrences happening outside of our reach.

This is why code shaped this way is called the Observer Pattern, which is better represented by the addEventListener interface in this case. Soon event emitters libraries or frameworks exposing this pattern flourished.

Node.js And Event Emitters

A good example is Node.js which page describes itself as “an asynchronous event-driven JavaScript runtime”, so event emitters and callback were first-class citizens. It even had an EventEmitter constructor already implemented.

const EventEmitter = require('events'); const emitter = new EventEmitter(); // respond to events emitter.on('greeting', (message) => console.log(message)); // send events emitter.emit('greeting', 'Hi there!');

This was not only the to-go approach for asynchronous execution but a core pattern and convention of its ecosystem. Node.js opened a new era of writing JavaScript in a different environment — even outside the web. As a consequence, other asynchronous situations were possible, like creating new directories or writing files.

const { mkdir, writeFile } = require('fs'); const styles = 'body { background: #ffdead; }'; mkdir('./assets/', (error) => { if (!error) { writeFile('assets/main.css', styles, 'utf-8', (error) => { if (!error) console.log('stylesheet created'); }) } })

You might notice that callbacks receive an error as a first argument, if a response data is expected, it goes as a second argument. This was called Error-first Callback Pattern, which became a convention that authors and contributors adopted for their own packages and libraries.

Promises And The Endless Callback Chain

As web development faced more complex problems to solve, the need for better asynchronous artifacts appeared. If we look at the last code snippet, we can see a repeated callback chaining which doesn’t scale well as the number tasks increase.

For example, let’s add only two more steps, file reading and styles preprocessing.

const { mkdir, writeFile, readFile } = require('fs'); const less = require('less') readFile('./main.less', 'utf-8', (error, data) => { if (error) throw error less.render(data, (lessError, output) => { if (lessError) throw lessError mkdir('./assets/', (dirError) => { if (dirError) throw dirError writeFile('assets/main.css', output.css, 'utf-8', (writeError) => { if (writeError) throw writeError console.log('stylesheet created'); }) }) }) })

We can see how as the program we are writing gets more complex the code becomes harder to follow for the human eye due to multiple callback chaining and repeated error handling.

Promises, Wrappers And Chain Patterns

Promises didn’t receive much attention when they were first announced as the new addition to the JavaScript language, they aren’t a new concept as other languages had similar implementations decades before. Truth is, they turned out to change a lot the semantics and structure of most of the projects I worked on since its appearance.

Promises not only introduced a built-in solution for developers to write asynchronous code but also opened a new stage in web development serving as the construction base of later new features of the web spec like fetch.

Migrating a method from a callback approach to a promise-based one became more and more usual in projects (such as libraries and browsers), and even Node.js started slowly migrating to them.

Let’s, for example, wrap Node’s readFile method:

const { readFile } = require('fs'); const asyncReadFile = (path, options) => { return new Promise((resolve, reject) => { readFile(path, options, (error, data) => { if (error) reject(error); else resolve(data); }) }); }

Here we obscure the callback by executing inside a Promise constructor, calling resolve when the method result is successful, and reject when the error object is defined.

When a method returns a Promise object we can follow its successful resolution by passing a function to then, its argument is the value which the promise was resolved, in this case, data.

If an error was thrown during the method the catch function will be called, if present.

Note: If you need to understand more in-depth how Promises work, I recommend Jake Archibald’s “JavaScript Promises: An Introduction” article which he wrote on Google’s web development blog.

Now we can use these new methods and avoid callback chains.

asyncRead('./main.less', 'utf-8') .then(data => console.log('file content', data)) .catch(error => console.error('something went wrong', error))

Having a native way to create asynchronous tasks and a clear interface to follow up its possible results enabled the industry to move out of the Observer Pattern. Promise-based ones seemed to solve the unreadable and prone-to-error code.

As a better syntax highlighting or clearer error messages help while coding, a code that is easier to reason becomes more predictable for the developer reading it, with a better picture of the execution path the easier to catch a possible pitfall.

Promises adoption was so global in the community that Node.js rapidly release built-in versions of its I/O methods to return Promise objects like importing them file operations from fs.promises.

It even provided a promisify util to wrap any function which followed the Error-first Callback Pattern and transform it into a Promise-based one.

But do Promises help in all cases?

Let’s re-imagine our style preprocessing task written with Promises.

const { mkdir, writeFile, readFile } = require('fs').promises; const less = require('less') readFile('./main.less', 'utf-8') .then(less.render) .then(result => mkdir('./assets') .then(writeFile('assets/main.css', result.css, 'utf-8')) ) .catch(error => console.error(error))

There is a clear reduction of redundancy in the code, especially around the error handling as we now rely on catch, but Promises somehow failed to deliver a clear code indentation that directly relates to the concatenation of actions.

This is actually achieved on the first then statement after readFile is called. What happens after these lines is the need to create a new scope where we can first make the directory, to later write the result in a file. This causes a break into the indentation rhythm, not making it easy to determinate the instructions sequence at first glance.

A way to solve this is to pre-baked a custom method that handles this and allows the correct concatenation of the method, but we would be introducing one more depth of complexity to a code that already seems to have what it needs to achieve the task we want.

Note: Take in count this is an example program, and we are in control around some of the methods and they all follow an industry convention, but that’s not always the case. With more complex concatenations or the introduction of a library with a different shape, our code style can easily break.

Gladly, the JavaScript community learned again from other language syntaxes and added a notation that helps a lot around these cases where asynchronous tasks concatenation is not as pleasant or straight-forward to read as synchronous code is.

Async And Await

A Promise is defined as an unresolved value at execution time, and creating an instance of a Promise is an explicit call of this artifact.

const { mkdir, writeFile, readFile } = require('fs').promises; const less = require('less') readFile('./main.less', 'utf-8') .then(less.render) .then(result => mkdir('./assets') .then(writeFile('assets/main.css', result.css, 'utf-8')) ) .catch(error => console.error(error))

Inside an async method, we can use the await reserved word to determinate the resolution of a Promise before continuing its execution.

Let’s revisit or code snippet using this syntax.

const { mkdir, writeFile, readFile } = require('fs').promises; const less = require('less') async function processLess() { const content = await readFile('./main.less', 'utf-8') const result = await less.render(content) await mkdir('./assets') await writeFile('assets/main.css', result.css, 'utf-8') } processLess()

Note: Notice that we needed to move all our code to a method because we can’t use await outside the scope of an async function today.

Every time an async method finds an await statement, it will stop executing until the proceeding value or promise gets resolved.

There’s a clear consequence of using async/await notation, despite its asynchronous execution, the code looks as if it was synchronous, which is something we developers are more used to see and reason around.

What about error handling? For it, we use statements that have been present for a long time in the language, try and catch.

const { mkdir, writeFile, readFile } = require('fs').promises; const less = require('less') async function processLess() { const content = await readFile('./main.less', 'utf-8') const result = await less.render(content) await mkdir('./assets') await writeFile('assets/main.css', result.css, 'utf-8') } try { processLess() } catch (e) { console.error(e) }

We rest assured any error thrown in the process will be handled by the code inside the catch statement. We have a centric place that takes care of error handling, but now we have a code that is easier to read and follow.

Having consequent actions that returned value doesn’t need to be stored in variables like mkdir that don’t break the code rhythm; there’s also no need to create a new scope to access the value of result in a later step.

It’s safe to say Promises were a fundamental artifact introduced in the language, necessary to enable async/await notation in JavaScript, which you can use on both modern browsers and latest versions of Node.js.

Note: Recently in JSConf, Ryan Dahl, creator and first contributor of Node, regretted not sticking to Promises on its early development mostly because the goal of Node was to create event-driven servers and file management which the Observer pattern served better for.


The introduction of Promises into the web development world came to change the way we queue actions in our code and changed how we reason about our code execution and how we author libraries and packages.

But moving away from chains of callback is harder to solve, I think that having to pass a method to then didn’t help us to move away from the train of thought after years of being accustomed to the Observer Pattern and approaches adopted by major vendors in the community like Node.js.

As Nolan Lawson says in his excellent article about wrong uses in Promise concatenations, old callback habits die hard! He later explains how to escape some of these pitfalls.

I believe Promises were needed as a middle step to allow a natural way to generate asynchronous tasks but didn’t help us much to move forward on better code patterns, sometimes you actually need a more adaptable and improved language syntax.

As we try to solve more complex puzzles using JavaScript, we see the need for a more mature language and we experiment with architectures and patterns we weren’t used to seeing on the web before.

We still don’t know how the ECMAScript spec will look in years as we are always extending the JavaScript governance outside the web and try to solve more complicated puzzles.

It’s hard to say now what exactly we will need from the language for some of these puzzles to turn into simpler programs, but I’m happy with how the web and JavaScript itself are moving things, trying to adapt to challenges and new environments. I feel right now JavaScript is a more asynchronous friendly place than when I started writing code in a browser over a decade ago.

Further Reading (dm, il)
Categories: Web Design

Create A Bookmarking Application With FaunaDB, Netlify And 11ty

Smashing Magazine - Thu, 10/24/2019 - 04:30
Create A Bookmarking Application With FaunaDB, Netlify And 11ty Create A Bookmarking Application With FaunaDB, Netlify And 11ty Bryan Robinson 2019-10-24T13:30:59+02:00 2019-10-29T11:47:34+00:00

The JAMstack (JavaScript, APIs and Markup) revolution is in full swing. Static sites are secure, fast, reliable and fun to work on. At the heart of the JAMstack are static site generators (SSGs) that store your data as flat files: Markdown, YAML, JSON, HTML, and so on. Sometimes, managing data this way can be overly complicated. Sometimes, we still need a database.

With that in mind, Netlify — a static site host and FaunaDB — a serverless cloud database — collaborated to make combining both systems easier. 

Why A Bookmarking Site?

The JAMstack is great for many professional uses, but one of my favorite aspects of this set of technology is its low barrier to entry for personal tools and projects.

There are plenty of good products on the market for most applications I could come up with, but none would be exactly set up for me. None would give me full control over my content. None would come without a cost (monetary or informational).

With that in mind, we can create our own mini-services using JAMstack methods. In this case, we’ll be creating a site to store and publish any interesting articles I come across in my daily technology reading.

I spend a lot of time reading articles that have been shared on Twitter. When I like one, I hit the “heart” icon. Then, within a few days, it’s nearly impossible to find with the influx of new favorites. I want to build something as close to the ease of the “heart,” but that I own and control.

How are we going to do that? I’m glad you asked.

Interested in getting the code? You can grab it on Github or just deploy straight to Netlify from that repository! Take a look at the finished product here. Our Technologies Hosting And Serverless Functions: Netlify

For hosting and serverless functions, we’ll be utilizing Netlify. As an added bonus, with the new collaboration mentioned above, Netlify’s CLI — “Netlify Dev” — will automatically connect to FaunaDB and store our API keys as environment variables.

Database: FaunaDB

FaunaDB is a “serverless” NoSQL database. We’ll be using it to store our bookmarks data.

Static Site Generator: 11ty

I’m a big believer in HTML. Because of this, the tutorial won’t be using front-end JavaScript to render our bookmarks. Instead, we’ll utilize 11ty as a static site generator. 11ty has built-in data functionality that makes fetching data from an API as easy as writing a couple of short JavaScript functions.

iOS Shortcuts

We’ll need an easy way to post data to our database. In this case, we’ll use iOS’s Shortcuts app. This could be converted to an Android or desktop JavaScript bookmarklet, as well.

Setting Up FaunaDB Via Netlify Dev

Whether you have already signed up for FaunaDB or you need to create a new account, the easiest way to set up a link between FaunaDB and Netlify is via Netlify’s CLI: Netlify Dev. You can find full instructions from FaunaDB here or follow along below.

Netlify Dev running in the final project with our environment variable names showing (Large preview)

If you don’t already have this installed, you can run the following command in Terminal:

npm install netlify-cli -g

From within your project directory, run through the following commands:

netlify init // This will connect your project to a Netlify project netlify addons:create fauna // This will install the FaunaDB "addon" netlify addons:auth fauna // This command will run you through connecting your account or setting up an account

Once this is all connected, you can run netlify dev in your project. This will run any build scripts we set up, but also connect to the Netlify and FaunaDB services and grab any necessary environment variables. Handy!

Creating Our First Data

From here, we’ll log into FaunaDB and create our first data set. We’ll start by creating a new Database called “bookmarks.” Inside a Database, we have Collections, Documents and Indexes.

A screenshot of the FaunaDB console with data (Large preview)

A Collection is a categorized group of data. Each piece of data takes the form of a Document. A Document is a “single, changeable record within a FaunaDB database,” according to Fauna’s documentation. You can think of Collections as a traditional database table and a Document as a row.

For our application, we need one Collection, which we’ll call “links.” Each document within the “links” Collection will be a simple JSON object with three properties. To start, we’ll add a new Document that we’ll use to build our first data fetch.

{   "url": "https://css-irl.info/debugging-css-grid-part-2-what-the-fraction/",   "pageTitle": "CSS { In Real Life } | Debugging CSS Grid – Part 2: What the Fr(action)?",   "description": "CSS In Real Life is a blog covering CSS topics and useful snippets on the web’s most beautiful language. Published by Michelle Barker, front end developer at Ordoo and CSS superfan." }

This creates the basis for the information we’ll need to pull from our bookmarks as well as provides us with our first set of data to pull into our template.

If you’re like me, you want to see the fruits of your labor right away. Let’s get something on the page!

Installing 11ty And Pulling Data Into A Template

Since we want the bookmarks to be rendered in HTML and not fetched by the browser, we’ll need something to do the rendering. There are many great ways of doing it, but for ease and power, I love using the 11ty static site generator.

Since 11ty is a JavaScript static site generator, we can install it via NPM.

npm install --save @11ty/eleventy

From that installation, we can run eleventy or eleventy --serve in our project to get up and running.

Netlify Dev will often detect 11ty as a requirement and run the command for us. To have this work - and make sure we’re ready to deploy, we can also create “serve” and “build” commands in our package.json.

"scripts": { "build": "npx eleventy", "serve": "npx eleventy --serve" } 11ty’s Data Files

Most static site generators have an idea of a “data file” built-in. Usually, these files will be JSON or YAML files that allow you to add extra information to your site.

In 11ty, you can use JSON data files or JavaScript data files. By utilizing a JavaScript file, we can actually make our API calls and return the data directly into a template.

By default, 11ty wants data files stored in a _data directory. You can then access the data by using the file name as a variable in your templates. In our case, we’ll create a file at _data/bookmarks.js and access that via the {{ bookmarks }} variable name.

If you want to dig deeper into data file configuration, you can read through examples in the 11ty documentation or check out this tutorial on using 11ty data files with the Meetup API.

The file will be a JavaScript module. So in order to have anything work, we need to export either our data or a function. In our case, we’ll export a function.

module.exports = async function() { const data = mapBookmarks(await getBookmarks()); return data.reverse() }

Let’s break that down. We have two functions doing our main work here: mapBookmarks() and getBookmarks(). 

The getBookmarks() function will go fetch our data from our FaunaDB database and mapBookmarks() will take an array of bookmarks and restructure it to work better for our template.

Let’s dig deeper into getBookmarks().


First, we’ll need to install and initialize an instance of the FaunaDB JavaScript driver.

npm install --save faunadb

Now that we’ve installed it, let’s add it to the top of our data file. This code is straight from Fauna’s docs.

// Requires the Fauna module and sets up the query module, which we can use to create custom queries. const faunadb = require('faunadb'), q = faunadb.query; // Once required, we need a new instance with our secret var adminClient = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET });

After that, we can create our function. We’ll start by building our first query using built-in methods on the driver. This first bit of code will return the database references we can use to get full data for all of our bookmarked links. We use the Paginate method, as a helper to manage cursor state should we decide to paginate the data before handing it to 11ty. In our case, we’ll just return all the references.

In this example, I’m assuming you installed and connected FaunaDB via the Netlify Dev CLI. Using this process, you get local environment variables of the FaunaDB secrets. If you didn’t install it this way or aren’t running netlify dev in your project, you’ll need a package like dotenv to create the environment variables. You’ll also need to add your environment variables to your Netlify site configuration to make deploys work later.

adminClient.query(q.Paginate(        q.Match( // Match the reference below            q.Ref("indexes/all_links") // Reference to match, in this case, our all_links index        )    ))    .then( response => { ... })

This code will return an array of all of our links in reference form. We can now build a query list to send to our database.

adminClient.query(...) .then((response) => { const linkRefs = response.data; // Get just the references for the links from the response const getAllLinksDataQuery = linkRefs.map((ref) => { return q.Get(ref) // Return a Get query based on the reference passed in    }) return adminClient.query(getAllLinksDataQuery).then(ret => { return ret // Return an array of all the links with full data        })    }).catch(...)

From here, we just need to clean up the data returned. That’s where mapBookmarks() comes in!


In this function, we deal with two aspects of the data.

First, we get a free dateTime in FaunaDB. For any data created, there’s a timestamp (ts) property. It’s not formatted in a way that makes Liquid’s default date filter happy, so let’s fix that.

function mapBookmarks(data) { return data.map(bookmark => { const dateTime = new Date(bookmark.ts / 1000); ... }) }

With that out of the way, we can build a new object for our data. In this case, it will have a time property, and we’ll use the Spread operator to destructure our data object to make them all live at one level.

function mapBookmarks(data) { return data.map(bookmark => { const dateTime = new Date(bookmark.ts / 1000); return { time: dateTime, ...bookmark.data } }) }

Here’s our data before our function:

{ ref: Ref(Collection("links"), "244778237839802888"), ts: 1569697568650000, data: { url: 'https://sample.com', pageTitle: 'Sample title', description: 'An escaped description goes here' } }

Here’s our data after our function:

{ time: 1569697568650, url: 'https://sample.com', pageTitle: 'Sample title' description: 'An escaped description goes here' }

Now, we’ve got well-formatted data that’s ready for our template!

Let’s write a simple template. We’ll loop through our bookmarks and validate that each has a pageTitle and a url so we don’t look silly.

<div class="bookmarks"> {% for link in bookmarks %} {% if link.url and link.pageTitle %} // confirms there’s both title AND url for safety <div class="bookmark"> <h2><a href="{{ link.url }}">{{ link.pageTitle }}</a></h2> <p>Saved on {{ link.time | date: "%b %d, %Y" }}</p> {% if link.description != "" %} <p>{{ link.description }}</p> {% endif %} </div> {% endif %} {% endfor %} </div>

We’re now ingesting and displaying data from FaunaDB. Let’s take a moment and think about how nice it is that this renders out pure HTML and there’s no need to fetch data on the client side!

But that’s not really enough to make this a useful app for us. Let’s figure out a better way than adding a bookmark in the FaunaDB console.

Enter Netlify Functions

Netlify’s Functions add-on is one of the easier ways to deploy AWS lambda functions. Since there’s no configuration step, it’s perfect for DIY projects where you just want to write the code.

This function will live at a URL in your project that looks like this: https://myproject.com/.netlify/functions/bookmarks assuming the file we create in our functions folder is bookmarks.js.

Basic Flow
  1. Pass a URL as a query parameter to our function URL.
  2. Use the function to load the URL and scrape the page’s title and description if available.
  3. Format the details for FaunaDB.
  4. Push the details to our FaunaDB Collection.
  5. Rebuild the site.

We’ve got a few packages we’ll need as we build this out. We’ll use the netlify-lambda CLI to build our functions locally. request-promise is the package we’ll use for making requests. Cheerio.js is the package we’ll use to scrape specific items from our requested page (think jQuery for Node). And finally, we’ll need FaunaDb (which should already be installed.

npm install --save netlify-lambda request-promise cheerio

Once that’s installed, let’s configure our project to build and serve the functions locally.

We’ll modify our “build” and “serve” scripts in our package.json to look like this:

"scripts": { "build": "npx netlify-lambda build lambda --config ./webpack.functions.js && npx eleventy", "serve": "npx netlify-lambda build lambda --config ./webpack.functions.js && npx eleventy --serve" }

Warning: There’s an error with Fauna’s NodeJS driver when compiling with Webpack, which Netlify’s Functions use to build. To get around this, we need to define a configuration file for Webpack. You can save the following code to a newor existing — webpack.config.js.

const webpack = require('webpack'); module.exports = { plugins: [ new webpack.DefinePlugin({ "global.GENTLY": false }) ] };

Once this file exists, when we use the netlify-lambda command, we’ll need to tell it to run from this configuration. This is why our “serve” and “build scripts use the --config value for that command.

Function Housekeeping

In order to keep our main Function file as clean as possible, we’ll create our functions in a separate bookmarks directory and import them into our main Function file.

import { getDetails, saveBookmark } from "./bookmarks/create"; getDetails(url)

The getDetails() function will take a URL, passed in from our exported handler. From there, we’ll reach out to the site at that URL and grab relevant parts of the page to store as data for our bookmark.

We start by requiring the NPM packages we need:

const rp = require('request-promise'); const cheerio = require('cheerio');

Then, we’ll use the request-promise module to return an HTML string for the requested page and pass that into cheerio to give us a very jQuery-esque interface.

const getDetails = async function(url) { const data = rp(url).then(function(htmlString) { const $ = cheerio.load(htmlString); ... }

From here, we need to get the page title and a meta description. To do that, we’ll use selectors like you would in jQuery. 

Note: In this code, we use 'head > title' as the selector to get the title of the page. If you don’t specify this, you may end up getting <title> tags inside of all SVGs on the page, which is less than ideal.

const getDetails = async function(url) { const data = rp(url).then(function(htmlString) { const $ = cheerio.load(htmlString); const title = $('head > title').text(); // Get the text inside the tag const description = $('meta[name="description"]').attr('content'); // Get the text of the content attribute // Return out the data in the structure we expect return { pageTitle: title, description: description }; }); return data //return to our main function }

With data in hand, it’s time to send our bookmark off to our Collection in FaunaDB!


For our save function, we’ll want to pass the details we acquired from getDetails as well as the URL as a singular object. The Spread operator strikes again!

const savedResponse = await saveBookmark({url, ...details});

In our create.js file, we also need to require and setup our FaunaDB driver. This should look very familiar from our 11ty data file.

const faunadb = require('faunadb'), q = faunadb.query; const adminClient = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET });

Once we’ve got that out of the way, we can code.

First, we need to format our details into a data structure that Fauna is expecting for our query. Fauna expects an object with a data property containing the data we wish to store.

const saveBookmark = async function(details) { const data = {    data: details }; ... }

Then we’ll open a new query to add to our Collection. In this case, we’ll use our query helper and use the Create method. Create() takes two arguments. First is the Collection in which we want to store our data and the second is the data itself.

After we save, we return either success or failure to our handler.

const saveBookmark = async function(details) { const data = { data: details }; return adminClient.query(q.Create(q.Collection("links"), data)) .then((response) => { /* Success! return the response with statusCode 200 */ return { statusCode: 200, body: JSON.stringify(response) } }).catch((error) => { /* Error! return the error with statusCode 400 */ return { statusCode: 400, body: JSON.stringify(error) } }) }

Let’s take a look at the full Function file.

import { getDetails, saveBookmark } from "./bookmarks/create"; import { rebuildSite } from "./utilities/rebuild"; // For rebuilding the site (more on that in a minute) exports.handler = async function(event, context) { try { const url = event.queryStringParameters.url; // Grab the URL const details = await getDetails(url); // Get the details of the page const savedResponse = await saveBookmark({url, ...details}); //Save the URL and the details to Fauna if (savedResponse.statusCode === 200) { // If successful, return success and trigger a Netlify build await rebuildSite(); return { statusCode: 200, body: savedResponse.body } } else { return savedResponse //or else return the error } } catch (err) { return { statusCode: 500, body: `Error: ${err}` }; } }; rebuildSite()

The discerning eye will notice that we have one more function imported into our handler: rebuildSite(). This function will use Netlify’s Deploy Hook functionality to rebuild our site from the new data every time we submit a new — successful — bookmark save.

In your site’s settings in Netlify, you can access your Build & Deploy settings and create a new “Build Hook.” Hooks have a name that appears in the Deploy section and an option for a non-master branch to deploy if you so wish. In our case, we’ll name it “new_link” and deploy our master branch.

A visual reference for the Netlify Admin’s build hook setup (Large preview)

From there, we just need to send a POST request to the URL provided.

We need a way of making requests and since we’ve already installed request-promise, we’ll continue to use that package by requiring it at the top of our file.

const rp = require('request-promise'); const rebuildSite = async function() { var options = { method: 'POST', uri: 'https://api.netlify.com/build_hooks/5d7fa6175504dfd43377688c', body: {}, json: true }; const returned = await rp(options).then(function(res) { console.log('Successfully hit webhook', res); }).catch(function(err) { console.log('Error:', err); }); return returned } A demo of the Netlify Function setup and the iOS Shortcut setup combined Setting Up An iOS Shortcut

So, we have a database, a way to display data and a function to add data, but we’re still not very user-friendly.

Netlify provides URLs for our Lambda functions, but they’re not fun to type into a mobile device. We’d also have to pass a URL as a query parameter into it. That’s a LOT of effort. How can we make this as little effort as possible?

A visual reference for the setup for our Shortcut functionality (Large preview)

Apple’s Shortcuts app allows the building of custom items to go into your share sheet. Inside these shortcuts, we can send various types of requests of data collected in the share process.

Here’s the step-by-step Shortcut:

  1. Accept any items and store that item in a “text” block.
  2. Pass that text into a “Scripting” block to URL encode (just in case).
  3. Pass that string into a URL block with our Netlify Function’s URL and a query parameter of url.
  4. From “Network” use a “Get contents” block to POST to JSON to our URL.
  5. Optional: From “Scripting” “Show” the contents of the last step (to confirm the data we’re sending).

To access this from the sharing menu, we open up the settings for this Shortcut and toggle on the “Show in Share Sheet” option.

As of iOS13, these share “Actions” are able to be favorited and moved to a high position in the dialog.

We now have a working “app” for sharing bookmarks across multiple platforms!

Go The Extra Mile!

If you’re inspired to try this yourself, there are a lot of other possibilities to add functionality. The joy of the DIY web is that you can make these sorts of applications work for you. Here are a few ideas:

  1. Use a faux “API key” for quick authentication, so other users don’t post to your site (mine uses an API key, so don’t try to post to it!).
  2. Add tag functionality to organize bookmarks.
  3. Add an RSS feed for your site so that others can subscribe.
  4. Send out a weekly roundup email programmatically for links that you’ve added.

Really, the sky is the limit, so start experimenting!

(dm, yk)
Categories: Web Design

Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)

Smashing Magazine - Wed, 10/23/2019 - 05:00
Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:00 2019-10-29T11:47:34+00:00

After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should be a familiar scene for anyone who has ever worked with an eager client who dreams about an ideal product but needs to be restraint by the development team.

Once features have been implemented and tested, your team will start noticing that some characteristics might differ from the original plan, and that’s alright. Simply notify, adjust, and go on. So, without further ado, allow me to first explain what has changed from the original plan.

Battle Mechanics

This is probably the biggest change from the original plan. I know I said I was going to go with a D&D-esque implementation in which each PC and NPC involved would get an initiative value and after that, we would run a turn-based combat. It was a nice idea, but implementing it on a REST-based service is a bit complicated since you can’t initiate the communication from the server side, nor maintain status between calls.

So instead, I will take advantage of the simplified mechanics of REST and use that to simplify our battle mechanics. The implemented version will be player-based instead of party-based, and will allow players to attack NPCs (Non-Player Characters). If their attack succeeds, the NPCs will be killed or else they will attack back by either damaging or killing the player.

Whether an attack succeeds or fails will be determined by the type of weapon used and the weaknesses an NPC might have. So basically, if the monster you’re trying to kill is weak against your weapon, it dies. Otherwise, it’ll be unaffected and — most likely — very angry.


If you paid close attention to the JSON game definition from my previous article, you might’ve noticed the trigger’s definition found on scene items. A particular one involved updating the game status (statusUpdate). During implementation, I realized having it working as a toggle provided limited freedom. You see, in the way it was implemented (from an idiomatic point of view), you were able to set a status but unsetting it wasn’t an option. So instead, I’ve replaced this trigger effect with two new ones: addStatus and removeStatus. These will allow you to define exactly when these effects can take place — if at all. I feel this is a lot easier to understand and reason about.

This means that the triggers now look like this:

"triggers": [ { "action": "pickup", "effect":{ "addStatus": "has light", "target": "game" } }, { "action": "drop", "effect": { "removeStatus": "has light", "target": "game" } } ]

When picking up the item, we’re setting up a status, and when dropping it, we’re removing it. This way, having multiple game-level status indicators is completely possible and easy to manage.

The Implementation

With those updates out of the way, we can start covering the actual implementation. From an architectural point of view, nothing changed; we’re still building a REST API that will contain the main game engine’s logic.

The Tech Stack

For this particular project, the modules I’m going to be using are the following:

Module Description Express.js Obviously, I’ll be using Express to be the base for the entire engine. Winston Everything in regards to logging will be handled by Winston. Config Every constant and environment-dependant variable will be handled by the config.js module, which greatly simplifies the task of accessing them. Mongoose This will be our ORM. I will model all resources using Mongoose Models and use that to interact directly with the database. uuid We’ll need to generate some unique IDs — this module will help us with that task.

As for other technologies used aside from Node.js, we have MongoDB and Redis. I like to use Mongo due to the lack of schema required. That simple fact allows me to think about my code and the data formats, without having to worry about updating the structure of my tables, schema migrations or conflicting data types.

Regarding Redis, I tend to use it as a support system as much as I can in my projects and this case is no different. I will be using Redis for everything that can be considered volatile information, such as party member numbers, command requests, and other types of data that are small enough and volatile enough to not merit permanent storage.

I’m also going to be using Redis’ key expiration feature to auto manage some aspects of the flow (more on this shortly).

API Definition

Before moving into client-server interaction and data-flow definitions I want to go over the endpoints defined for this API. They aren’t that many, mostly we need to comply with the main features described in Part 1:

Feature Description Join a game A player will be able to join a game by specifying the game’s ID. Create a new game A player can also create a new game instance. The engine should return an ID, so that others can use it to join. Return scene This feature should return the current scene where the party is located. Basically, it’ll return the description, with all of the associated information (possible actions, objects in it, etc.). Interact with scene This is going to be one of the most complex ones, because it will take a command from the client and perform that action — things like move, push, take, look, read, to name just a few. Check inventory Although this is a way to interact with the game, it does not directly relate to the scene. So, checking the inventory for each player will be considered a different action. Register client application The above actions require a valid client to execute them. This endpoint will verify the client application and return a Client ID that will be used for authentication purposes on subsequent requests.

The above list translates into the following list of endpoints:

Verb Endpoint Description POST /clients Client applications will require to get a Client ID key using this endpoint. POST /games New game instances are created using this endpoint by the client applications. POST /games/:id Once the game is created, this endpoint will enable party members to join it and start playing. GET /games/:id/:playername This endpoint will return the current game state for a particular player. POST /games/:id/:playername/commands Finally, with this endpoint, the client application will be able to submit commands (in other words, this endpoint will be used to play).

Let me go into a bit more detail about some of the concepts I described in the previous list.

Client Apps

The client applications will need to register into the system to start using it. All endpoints (except for the first one on the list) are secured and will require a valid application key to be sent with the request. In order to obtain that key, client apps need to simply request one. Once provided, they will last for as long as they are used, or will expire after a month of not being used. This behavior is controlled by storing the key in Redis and setting a one-month long TTL to it.

Game Instance

Creating a new game basically means creating a new instance of a particular game. This new instance will contain a copy of all of the scenes and their content. Any modifications done to the game will only affect the party. This way, many groups can play the same game on their own individual way.

Player’s Game State

This is similar to the previous one, but unique to each player. While the game instance holds the game state for the entire party, the player’s game state holds the current status for one particular player. Mainly, this holds inventory, position, current scene and HP (health points).

Player Commands

Once everything is set up and the client application has registered and joined a game, it can start sending commands. The implemented commands in this version of the engine include: move, look, pickup and attack.

  • The move command will allow you to traverse the map. You’ll be able to specify the direction you want to move towards and the engine will let you know the result. If you take a quick glimpse at Part 1, you can see the approach I took to handle maps. (In short, the map is represented as a graph, where each node represents a room or scene and is only connected to other nodes that represent adjacent rooms.)

    The distance between nodes is also present in the representation and coupled with the standard speed a player has; going from room to room might not be as simple as stating your command, but you’ll also have to traverse the distance. In practice, this means that going from one room to the other might require several move commands). The other interesting aspect of this command comes from the fact that this engine is meant to support multiplayer parties, and the party can’t be split (at least not at this time).

    Therefore, the solution for this is similar to a voting system: every party member will send a move command request whenever they want. Once more than half of them have done so, the most requested direction will be used.
  • look is quite different from move. It allows the player to specify a direction, an item or NPC they want to inspect. The key logic behind this command, comes into consideration when you think about status-dependant descriptions.

    For example, let’s say that you enter a new room, but it’s completely dark (you don’t see anything), and you move forward while ignoring it. A few rooms later, you pick up a lit torch from a wall. So now you can go back and re-inspect that dark room. Since you’ve picked up the torch, you now can see inside of it, and be able to interact with any of the items and NPCs you find in there.

    This is achieved by maintaining a game wide and player specific set of status attributes and allowing the game creator to specify several descriptions for our status-dependant elements in the JSON file. Every description is then equipped with a default text and a set of conditional ones, depending on the current status. The latter are optional; the only one that is mandatory is the default value.

    Additionally, this command has a short-hand version for look at room: look around; that is because players will be trying to inspect a room very often, so providing a short-hand (or alias) command that is easier to type makes a lot of sense.
  • The pickup command plays a very important role for the gameplay. This command takes care of adding items into the players inventory or their hands (if they’re free). In order to understand where each item is meant to be stored, their definition has a “destination” property that specifies if it is meant for the inventory or the player’s hands. Anything that is successfully picked up from the scene is then removed from it, updating the game instance’s version of the game.
  • The use command will allow you to affect the environment using items in your inventory. For instance, picking up a key in a room will allow you to use it to open a locked door in another room.
  • There is a special command, one that is not gameplay-related, but instead a helper command meant to obtain particular information, such as the current game ID or the player’s name. This command is called get, and the players can use it to query the game engine. For example: get gameid.
  • Finally, the last command implemented for this version of the engine is the attack command. I already covered this one; basically, you’ll have to specify your target and the weapon you’re attacking it with. That way the system will be able to check the target’s weaknesses and determine the output of your attack.
Client-Engine Interaction

In order to understand how to use the above-listed endpoints, let me show you how any would-be-client can interact with our new API.

Step Description Register client First things first, the client application needs to request an API key to be able to access all other endpoints. In order to get that key, it needs to register on our platform. The only parameter to provide is the name of the app, that’s all. Create a game After the API key is obtained, the first thing to do (assuming this is a brand new interaction) is to create a brand new game instance. Think about it this way: the JSON file I created in my last post contains the game’s definition, but we need to create an instance of it just for you and your party (think classes and objects, same deal). You can do with that instance whatever you want, and it will not affect other parties. Join the game After creating the game, you’ll get a game ID back from the engine. You can then use that game ID to join the instance using your unique username. Unless you join the game, you can’t play, because joining the game will also create a game state instance for you alone. This will be where your inventory, your position and your basic stats are saved in relation to the game you’re playing. You could potentially be playing several games at the same time, and in each one have independent states. Send commands In other words: play the game. The final step is to start sending commands. The amount of commands available was already covered, and it can be easily extended (more on this in a bit). Everytime you send a command, the game will return the new game state for your client to update your view accordingly. Let’s Get Our Hands Dirty

I’ve gone over as much design as I can, in the hopes that that information will help you understand the following part, so let’s get into the nuts and bolts of the game engine.

Note: I will not be showing you the full code in this article since it’s quite big and not all of it is interesting. Instead, I’ll show the more relevant parts and link to the full repository in case you want more details.

The Main File

First things first: this is an Express project and it’s based boilerplate code was generated using Express’ own generator, so the app.js file should be familiar to you. I just want to go over two tweaks I like to do on that code to simplify my work.

First, I add the following snippet to automate the inclusion of new route files:

const requireDir = require("require-dir") const routes = requireDir("./routes") //... Object.keys(routes).forEach( (file) => { let cnt = routes[file] app.use('/' + file, cnt) })

It’s quite simple really, but it removes the need to manually require each route files you create in the future. By the way, require-dir is a simple module that takes care of auto-requiring every file inside a folder. That’s it.

The other change I like to do is to tweak my error handler just a little bit. I should really start using something more robust, but for the needs at hand, I feel like this gets the work done:

// error handler app.use(function(err, req, res, next) { // render the error page if(typeof err === "string") { err = { status: 500, message: err } } res.status(err.status || 500); let errorObj = { error: true, msg: err.message, errCode: err.status || 500 } if(err.trace) { errorObj.trace = err.trace } res.json(errorObj); });

The above code takes care of the different types of error messages we might have to deal with — either full objects, actual error objects thrown by Javascript or simple error messages without any other context. This code will take it all and format it into a standard format.

Handling Commands

This is another one of those aspects of the engine that had to be easy to extend. In a project like this one, it makes total sense to assume new commands will pop up in the future. If there is something you want to avoid, then that would probably be avoid making changes on the base code when trying to add something new three or four months in the future.

No amount of code comments will make the task of modifying code you haven’t touched (or even thought about) in several months easy, so the priority is to avoid as many changes as possible. Lucky for us, there are a few patterns we can implement to solve this. In particular, I used a mixture of the Command and the Factory patterns.

I basically encapsulated the behavior of each command inside a single class which inherits from a BaseCommand class that contains the generic code to all commands. At the same time, I added a CommandParser module that grabs the string sent by the client and returns the actual command to execute.

The parser is very simple since all implemented commands now have the actual command as to their first word (i.e. “move north”, “pick up knife”, and so on) it’s a simple matter of splitting the string and getting the first part:

const requireDir = require("require-dir") const validCommands = requireDir('./commands') class CommandParser { constructor(command) { this.command = command } normalizeAction(strAct) { strAct = strAct.toLowerCase().split(" ")[0] return strAct } verifyCommand() { if(!this.command) return false if(!this.command.action) return false if(!this.command.context) return false let action = this.normalizeAction(this.command.action) if(validCommands[action]) { return validCommands[action] } return false } parse() { let validCommand = this.verifyCommand() if(validCommand) { let cmdObj = new validCommand(this.command) return cmdObj } else { return false } } }

Note: I’m using the require-dir module once again to simplify the inclusion of any existing and new command classes. I simply add it to the folder and the entire system is able to pick it up and use it.

With that being said, there are many ways this can be improved; for instance, by being able to add synonym support for our commands would be a great feature (so saying “move north”, “go north” or even “walk north” would mean the same). That is something that we could centralize in this class and affect all commands at the same time.

I won’t go into details on any of the commands because, again, that’s too much code to show here, but you can see in the following route code how I managed to generalize that handling of the existing (and any future) commands:

/** Interaction with a particular scene */ router.post('/:id/:playername/:scene', function(req, res, next) { let command = req.body command.context = { gameId: req.params.id, playername: req.params.playername, } let parser = new CommandParser(command) let commandObj = parser.parse() //return the command instance if(!commandObj) return next({ //error handling status: 400, errorCode: config.get("errorCodes.invalidCommand"), message: "Unknown command" }) commandObj.run((err, result) => { //execute the command if(err) return next(err) res.json(result) }) })

All commands only require the run method — anything else is extra and meant for internal use.

I encourage you to go and review the entire source code (even download it and play with it if you like!). In the next part of this series, I’ll show you the actual client implemention and interaction of this API.

Closing Thoughts

I may not have covered a lot of my code here, but I still hope that the article was helpful to show you how I tackle projects — even after the initial design phase. I feel like a lot of people try to start coding as their first response to a new idea and that sometimes can end up discouraging to a developer since there is no real plan set nor any goals to achieve — other than having the final product ready (and that is too big of a milestone to tackle from day 1). So again, my hope with these articles is to share a different way to go about working solo (or as part of a small group) on big projects.

I hope you’ve enjoyed the read! Please feel free to leave a comment below with any type of suggestions or recommendations, I’d love to read what you think and if you’re eager to start testing the API with your own client-side code.

See you on the next one!

(dm, yk, il)
Categories: Web Design