Articles on Smashing Magazine — For Web Designers And Developers https://www.smashingmagazine.com/ Recent content in Articles on Smashing Magazine — For Web Designers And Developers Tue, 23 May 2023 10:33:29 GMT https://validator.w3.org/feed/docs/rss2.html manual en Articles on Smashing Magazine — For Web Designers And Developers https://www.smashingmagazine.com/images/favicon/app-icon-512x512.png https://www.smashingmagazine.com/ All rights reserved 2023, Smashing Media AG Development Design UX Mobile Front-end <![CDATA[Smashing Podcast Episode 61 With Rachel Andrew: What Is Web Platform Baseline?]]> https://smashingmagazine.com/2023/05/smashing-podcast-episode-61/ https://smashingmagazine.com/2023/05/smashing-podcast-episode-61/ Tue, 23 May 2023 08:00:00 GMT In this episode of the Smashing Podcast, we’re talking about Web Platform Baseline. What is it, and how can it help determine your browser support policy? Drew McLellan talks to expert Rachel Andrew to find out.

Show Notes

Weekly Update

Transcript

Drew: Shes a web developer and technical writer and editor. Shes currently working for Google on the Chrome team where shes a staff technical writer and content lead for web.dev and developer.chrome.com. Prior to Google, she spent 20 years as a freelancer and business owner and shes written almost countless books and articles where she excels at taking complex technical subjects and making them more readily understandable. Shes also an experienced conference speaker, able to deliver a technical talk to teach an audience about CSS layouts or a keynote to inspire them drawing from her wealth of experience developing for the web. So we know shes an experienced technical writer, teacher and developer, but did you know she once taught a Canada goose to make a bourbon cocktail? My smashing friends, please welcome back Rachel Andrew. Hi Rachel, how are you?

Rachel: I’m smashing.

Drew: Welcome back to the podcast. Its been a couple of years and theres been a change of day-to-day role for you.

Rachel: Yes, yes. I guess last time I was here it was mid pandemic and I was still editor-in-chief of Smashing Magazine and yes, these days I’m over at Google on the DevRel team with my content team sort of helping to get good docs and information out to our developers about things on the web platform.

Drew: So still in the realms of helping people learn about the web platform and assisting their busy lives, trying to keep a pace of all the new technologies and developments?

Rachel: Yes. Yeah, its kind of a perfect role for someone who spent most of their life sort of explaining things to web developers. So yeah, its great and within a really great team of people who were very dedicated to talking about all this new stuff.

Drew: So speaking of new developments and also Google, last week was Google I/O 2023, which is always an exciting time for us tech nerds because there are all sorts of announcements and updates from Google. With Google being such a large contributor to the web platform, it then becomes an exciting time to see whats been worked on for the web in particular and see what might be coming out next. I feel like we’re in a place with a web platform where its continuing to develop a fantastic pace at the moment.

Rachel: Yeah.

Drew: Those of us who have been working in the industry for a while remember the years when nothing was added in terms of browser capabilities, I mean sometimes years at a time. You were working on the web back then. Was it frustrating that things weren’t getting added or did it just make it easier to keep up?

Rachel: I think it was frustrating. You know, when we had, we had five years between IE6 and IE7 so that was kind of five years that the web platform just basically stopped because so many people were using IE6, although there were new other browsers around you couldn’t really use all the new stuff that they were putting into the browser because the majority of people coming to your website were in a browser that didn’t support it. So I think it was very frustrating because thats a very, very long time, especially when IE6 had all sorts of bugs and issues as well so that we weren’t getting fixes to things.

Rachel: It wasn’t even new features. We were dealing with problems, like bits of your content disappearing for no apparent reason. So yeah, it was frustrating, but it was very stable. Buggy but at least the bugs that we could list them, there were websites that listed all of the IE6 CSS problems, so you’d hit one and you’d be like, oh yeah, thats that. I know how to fix that. So we all became pretty expert in dealing with browser bugs basically and knowing what they were.

Drew: I remember things like Peekaboo, was it Peekaboo bug was that era.

Rachel: Yes.

Drew: And what was the website that listed them, listed them all? I can’t remember its name now, but the list of known bugs just got longer and longer and longer over time to the point where it became difficult to find the one you were, the particular bug you were experiencing because the list was so long. We were in a place back then where the dominant browser, which was Internet Explorer at the time, was the browser that was seeing the least technical innovation but that doesn’t mean there was no technical innovation because there was a broader ecosystem, but was it ever possible to use new bits of CSS that were appearing in things like Firefox? Is that something we could do when the dominant browser was so far behind?

Rachel: It was pretty hard. I mean, I think all the ideas of things like polyfills and also there was a lot of us kind of pushing the progressive enhancement story as well and saying, look, its fine, your website doesn’t need to look the same in all browsers. I think I’ve been saying that for most of my life at this point. And that was a big thing at the time because people were just sort of A/B test in the browsers, you know, there was no... you’re sensing off to your client and they would just open it in another browser and be like, "Oh no, this is wrong 'cause its three pixels out on this other browser."

Rachel: And that was very, very common. People would talk about pixel perfect and what they would typically mean is it should be exactly the same as the PDF or whatever that you were working from or the Photoshop file and all of the browsers that they were aware of, or at least both browsers typically. So I think it was quite difficult to push the web forward at the time, you got quite a lot of resistance and you’d often have to just do it anyway and hope you’d get away with it quite a lot of the time.

Drew: We don’t seem to see that so much these days where clients or anyone really is looking at a web experience side by side in two different browsers and saying, oh, they’re not quite the same. Is that because browsers are much more standardized now and they do look the same or have the expectations changed, do you think, because of so many devices that we’re looking at, the fact that mobile devices and tablets and so many different screen sizes that has that expectation gone away?

Rachel: Yeah, I think its a bit of both, isn’t it? I think the web browser is how we do everything these days and its less of a separate bit of software, its just kind of how you use your computer and a lot of the time and I think theres less of an awareness of, oh, we should be checking this for someone who isn’t a developer, we should be checking this in the different browsers. Far more likely, I think, would be someone saying, "This doesn’t work well on my phone." 'Cause they’ll get the email saying, oh look at the new site, and they’re probably on their phone when they get that email and they’ll open it on their phone and then they find, oh, somethings overlaying something or its hard to get to something because of a toolbar or whatever.

Rachel: So I think its far more likely that a client is going to be coming back with that kind of problem. Maybe they’ve got an older version, an older phone that they’ve not updated and its got an older version of software on it or whatever than doing that kind of desktop A/B testing that used to be really common, even with a fairly non-technical client, they would’ve been told by someone that they should make sure it works in these browsers and so they would be doing that checking.

Drew: Yeah, I mean clients would come along to those of us who are building sites for them and they would say, right, we need this site built and it needs to work in IE6 or it needs to work in IE7 and they’d have these very definitive browser versions that things had to work in. And now between, as you mentioned, between IE6 and IE7, there was a multiple year gap, so that constraint from the client could have, it could massively impact your sort of choice of technology or design, couldn’t it?

Rachel: Oh, absolutely. Yeah, I mean that was just sort of fairly standard when you were building sites and at the time I was building sites for clients that would be on the spec for the site would be which browsers that you had to support and you would be expected to test it in those browsers and if it worked in those browsers, that was all good. That was the line that you were following.

Drew: Yeah, I guess even things, even that things were pretty limited. It was a fairly easy decision to make to say these are the browsers that we’re supporting. Its got to work in IE7 for whatever reason.

Rachel: Yeah.

Drew: It was fairly clear cut, but these days I don’t think I could even tell you what version of Chrome or Firefox or Safari I’m running or if thats the latest, I’m presuming its the latest, but its not so clear cut and straightforward now, is it?

Rachel: Right, yeah. You don’t even notice that the things update. They just update and you don’t realize if thats a major version or just some say security release thats come out that you need to update to. I don’t think most people know which features landed in which version of a browser. We used to know. We used to know exactly what was available in each browser, so it’d be like, "Oh great, this project is IE8 and therefore I’ve got, I don’t know, display table" or something that landed in that browser.

Rachel: We used to know. These days we don’t know. I know I spend all of my time documenting this stuff and writing about whats new in the web platform and even so, I’m fairly hazy. If you said to me, "Oh, what was in Chrome 113?" And I’ve just done the work on that, I’d be like, "Err, was that in that one or was that in the beta?" So the average developer then you’re not going to be able to keep track of all that stuff. Theres so much stuff landing all the time.

Drew: So it makes the situation quite difficult, doesn’t it, when you might have sometimes contracts with people you’re building stuff for and certainly expectations that theres going to be a level of browser support but its not, if you don’t know what versions things are and they move really quickly, it can be really difficult to pin down to a targeted browser version. And this is, I believe its the crux of the problem thats addressed by one of the big announcements at Google I/O. How do we figure out whats safe to use?

Rachel: Yeah, and so this is something we’ve been thinking about actually for as long as I’ve been at Google is we’ve been thinking of this top pain point that we hear from developers that they struggle to keep up with the web platform and they struggle to know what is safe to use, what is okay to roll out in production without worrying about it. Typically developers will be building for the latest versions of a site and then suddenly they’ll realize that, oh, this is broken over here and they just don't, they didn’t realize that and to actually figure out the browser support involves going kind of property-by-property, feature-by-feature to say, can I use our MDN and looking at the compatibility data. Its all out there, but you have to do that on a feature-by-feature basis.

Rachel: And so we’re kind of thinking about this issue and it always comes up, we talk to a lot of developers and it always comes up as the top problem and so we’re thinking about how we can resolve that. And thats what kind of came to this idea of, well, can we create this line and say that everything thats passed this line has interoperability, is kind of safe to use without worrying about it. And thats where this idea of Baseline came from, to have this kind of moving line that includes all of the features that are interoperable and don’t have any major standout issues. And thats what we’re calling Baseline.

Rachel: And the whole project is its not just a Google thing, this comes from the Web DX community group. So we’re working with other browsers and other people on defining this and kind of coming up with the feature groupings so that we can try and create this clarity for developers that they’ve got a sort of line where they can say, they can look at that and say, oh yes, this thing is in Baseline and therefore I know its going to work everywhere in the most modern browsers.

Drew: So instead of saying this, we’re supporting these particular browsers, you’re saying this is a core feature set thats common across all the currently available browsers. This is a safe set of features and its that set that I’m going to be developing for compatibility with.

Rachel: Right, yeah. And that sort of takes that requirement to figure out each individual feature for, and also because we get partial implementations of stuff all the time on the platform and its like, so the kind of feature grouping part of this, it is the big piece of work really to actually identify, does the feature completely work everywhere because sometimes there will be support for things. I think one of the things that, an obvious thing that people understand is the gap property in where in Flexbox and Grid and so on. Now you could test for that. You could test for where the gap was supported and a browser would say yes because it was supported in grid layout even when it wasn’t supported in flex layout and therefore there was no way to check for this. And it was quite confusing for people if they were just doing that test. So I think theres these sort of groupings of things is also quite useful. So the things that are in Baseline are things that do work as a feature, even if that does actually involve various moving parts.

Drew: Yes, because theres been a trend from the sort of latest CSS specs to be, whats the word, sort of unifying some of the properties isn’t there rather than-

Rachel: Yes.

Drew:span> ... rather than having individual properties that do the same thing in different context, using the same-

Rachel: Right.

Drew:span> ... keywords across different uses.

Rachel: Yeah, so things like alignment, fragmentation, we’ve got these specifications that deal with sort of alignment across all of the different layout specs, which is great because it means that say if you want to switch from a flex to a grid layout or whatever, all the alignment stuff should work in the same way, but does mean that we potentially get these partial implementations and thats quite difficult to understand. So yeah, I think its things like that and so that theres an awful lot actually goes into the creation of this sort of feature set grouping and we’re not all the way there yet. We’re hoping to get most of CSS and JavaScript done by the end of the year because its actually quite a job just to figure out how things all fit together.

Drew: So its almost like instead of targeting a version of any particular browser, we’re targeting a version of the web platform. We’re saying-

Rachel: Yeah.

Drew:span> ... look at the web platform as it is here today, these are the things that are universal, that are reliable to use and thats what we’re going to support. And anything that falls out of that boundary included because the implementation might be patchy.

Rachel: Right, yeah. It might need a bit more care. And its not saying to people, oh, you can’t ever use these things, but if you know its not in Baseline then maybe theres some things you need to think about there and it might be fine for your project or it might be that it has a good fallback or its something that is polyfillable but those are things that you do need to think about on a case-by-case basis rather than just, this should be fine to use.

Drew: I think most of us are familiar with sites like canIuse.com, which you mentioned briefly before. Is this just replicating information that already exists or is it different from can I use?

Rachel: I think its different in that, so something that can I use does, and also the MDN BCD data, they work very much on a sort of feature-by-feature basis. They don’t actually cover all of the web platform. Theres definitely, certainly Can I use has made some decisions in terms of how to group certain things. I have a long standing open issue to split out fragmentation from multicar for example, because they’re bundled together, making multicar look harder to use than it actually is because there are fragmentation bugs in there.

Rachel: So they’ve done some of the same stuff, but what we haven’t got there is this sort of full view of the platform and this idea of this is within Baseline, this is out, you still have to go to each thing and make those decisions. Ideally we’re hoping, I mean as MDN are using Baseline on feature pages, they’re rolling that out at the moment. Its probably saying that we’re hoping that Can I use, we’ll also be able to use and say, "Oh, this feature is in Baseline" as well as that more fine grained data.

Drew: And how do you make that decision to say that yes, this, not only is this supported but this is widely supported enough that we can include it in Baseline. How do you make that distinction?

Rachel: So at the moment we’re going back the last two major versions of browsers and theres been a lot of debate about that. As you can imagine. Its something thats great to [inaudible 00:17:38]. The fact is I think the line will always be wrong for if we say this is the line, two versions back, a lot of people are saying, "Oh, you should use minor versions of Safari" because we’ve seen some massive features going in doc releases because of the way that Safari do their versioning because obviously a main version of Firefox and Chrome, thats every month we’ve got a new main version. And so thats obviously up for debate. Some people are saying we should go further back. Other people are pointing out the fact that just because Chrome has updated, all of the browsers are derivatives that use chromium, they might not have updated. So I think the line will always be wrong, I think.

Rachel: But what it does give is this sort of stable view onto things. And the other thing that we’re planning to do as part of this is to have these kind of moments in time. So at the end of the year we’re going to say, right this cut is where we are at that point is going to be Baseline 24 and that will be a static line. That will be whats in Baseline at this point in time. And then in a years time we’ll do Baseline 25. And I think an interesting thing then will be the difference between those two points because I think a conservative web team could say, "Right, I am sticking with Baseline 24" even though maybe they’re well into 25, we’re sticking with this. But the things between those two lines then I think become the things that you might want to make judgments on rather than having to look at the entire web platform and say, "Oh, can I use this? Can I use that?" And say, "Well, we’re going to use this yearly cut of Baseline." And then the things that came after that that are in Baseline as it moves forward we’ll take a look at and see, oh, I can polyfill that or this is fine as a progressive enhancement.

Drew: It puts me in mind slightly of things like Ubuntu Linux distribution and their long-term support releases that they do.

Rachel: Right.

Drew: They’ll say, "This is the one that we offer long-term support. Its stable, its reliable to use." And so you might adopt that and that doesn’t mean that you wouldn’t necessarily install a couple of key extra, more frequently updated packages or whatever, but you know that the system that you’re working with is sort of frozen in time and supported and is a known quantity going forward.

Rachel: Yeah.

Drew: I guess those who work in very regulated industries who sort of frequently go under contract with customers or suppliers, whatever, to say they’ll provide compatibility with certain browsers as it is at the moment. Surely this would be a very welcome change because these are actually more concrete measures that support can be tied to and its a stability thats more in line with the stability of a binding agreement than an arbitrary version number that some nerd in Silicon Valley might attach to a build of a browser.

Rachel: Right.

Drew: So you can say our platform is targeting Baseline 24 and you could keep that way for three, four years maybe.

Rachel: Yeah.

Drew: And then review it and update.

Rachel: Yeah, I like that. I like that stuff, yeah, the idea, this is a sort of stable thing and I think that that yearly release will become, I think, quite important. So I think I can see libraries and frameworks and so on tying themselves essentially to a stable release, one of the yearly cuts and then moving on. And I think it should be really interesting as well being able to see, well actually how has the platform moved on between those two yearly points? We don’t really have a look at that at the moment. I mean you could work it out, but it’d be quite a lot of work. It’d be nice just to be able to see that and see how things are changing.

Drew: I always enjoy a list of features that are included in whatever. Heres things that you can use that you won't, perhaps weren’t aware of. And I can see how a big list of Baseline features might highlight different things that an individual developer might not be aware of that-

Rachel: Yeah.

Drew:span> ... have arrived on the web platform and are ready to be used.

Rachel: Yeah, I mean the awareness is a big thing. I mean, I’ve been doing, me and a colleague as well have been doing talks, whats new on the web platform type talks and typically introducing things that are interoperable. And every time there will be people saying, "Oh, I never knew you could do that", or "I never knew that worked. I thought that was an experimental thing." And then realizing that its actually a feature thats in all engines. And I think that thats very, very common. So I think thats the other sort of side of this is that it also raises awareness of features that now are interoperable, that people have got an idea that the web platform moves incredibly slowly.

Rachel: I think particularly people like us who’ve been doing this for a long time and remember those days. And so people are very surprised, you know, you still see people saying about a new feature, "Oh well it’ll be five years before I can use that." And yet you’re looking at things like container queries and cascade layers. All of these things landed cross browser very, very quickly, which is great. And I think thats a story that this can help tell as well.

Drew: So this was a big announcement from Chrome at the big Google I/O conference, but you mentioned its not just a Google thing is it, there are other parties involved. So who is deciding whats in the collective Baseline? What parties are involved in this?

Rachel: Right, yeah, so I mean obviously we partnered very closely with Mozilla and MDN in launching this. So that actually during the developer keynote we launched this on web.dev and on MDN at the same time on a select number of pages because we haven’t got a full feature site yet. But it was nice to actually show what it would look like rather than it being a kind of theoretical thing. And also MDN published a blog post about it too and their thinking. But yeah, the work has been done within the Web DX community group and that group has representatives from all of the browsers and various other people including interested developers.

Rachel: Anyone can join that group and be part of those discussions. So thats where we’re also asking people to go and comment on this stuff rather than, I mean people are very welcome to come and talk to me about it, but in terms of getting sort of information out there and discussed by the wider group, raise issues on the Web DX community group site because thats where the people are who are making the decisions. And at the moment its just fantastic to be getting the feedback into that group so that we can actually see is this solving a problem, what problems maybe we’ve missed and be able to talk about that.

Drew: So its a broader community effort, but it just so happens that the major players Google, Mozilla and everything are putting a lot of time and effort into it and really backing it as an idea.

Rachel: Yeah, yeah. And I think thats something that as DevRel, you know, as developer relations, thats kind of what we do. We try and bridge the gap between browser engineers and spec writers and the developer community. And so I think thats something that we can do as DevRel for the web is to actually bring forward these things that we think might help and see where we can take them.

Drew: Now I’ve heard about the Interop 2022 and now 2023 initiatives. Does Baseline relate to Interop at all? Or maybe you could talk us through that where it fits in?

Rachel: Yeah, I mean its kind of the same group of people certainly as Google who are involved with those projects. So the Interop project takes a set of features that if its based on web platform tests, so it takes a set of features that have some sort of interoperability problem. So it might be that they don’t work in one or more browsers or they have sort of bugs that are causing pupil problems. So we’ve got this set of features and then over the year all of the engines work to implement or fix those things. So we’ve kind of got a score, a scoreboard where you can go and look and see how everyones doing.

Rachel: So the Interop project works to fix known issues, either make things interoperable or fix books and things that look on paper like they work, but have some sort of problems. And so that project is getting more things essentially into Baseline. So they’re linked in that way and they’re a lot of the very similar people are working together on those from the browsers. So I think in terms of the relationships there and the fact that Interop did bring, for the first time, all of the vendors together in this sort of common goal to make the platform better, theres definitely a link there in terms of this is what we care about. Whereas Baselines kind of from the other side, its saying, well, okay, what is there? What is interoperable? What can we already use? So yeah, hopefully things like Interop will help to add more things to Baseline as we go along.

Drew: So it is basically just identifying things that could potentially go into Baseline, might be nearly there, and then swarming on those features to get them across the line and get them interoperable and usable on the platform because they’re seen as important or significant in some way.

Rachel: Yeah, and I mean we know that that developers aren’t going to use things in general unless they are available across all engines. So its kind of in everyones interest to work together to get to that point because then people use the stuff that we’re building so that, yeah, its said so they kind of work very well together. And I think its just this sort of spirit of collaboration and trying to make things better for developers.

Drew: We’ve talked about how developers might target, in past, a browser version and now we’re saying would target Baseline, but it works the other way around, doesn’t it? If the frameworks and the tools that we are using as dependencies in our projects, they can also declare that as a level of support. Is that right?

Rachel: Yeah, absolutely. I think thats something that we’d love to see how a framework or whatever you could say, everything that is used by this framework is Baseline or is Baseline 24 or what have you. Thats going to give a lot of clarity to developers to not then need to fish around in the framework and find out what they’re doing to make sure 'cause if you’ve got to do a certain level of browser support in your project, you need to make sure that everything you use also has that level of browser support so that it could definitely make that a lot clearer.

Rachel: And I think also things like publishing articles. One of the things that frustrates people, and I know as someone who writes and edits a lot of content, is if people get halfway through an article and then they find something that is experimental or is so new or only works in Chrome or whatever, thats really frustrating because you think, oh, I’ve found the thing that helps me solve my problem. You’re working through it and then you’re like, oh, thats not coming 'til next year. And so have been able to put on an article, everything in this article is in Baseline. That gives you a lot of confidence to go forward. So I think theres lots of uses for this out in the community and thats something we really hope will happen, that just to give that kind of clarity to developers.

Drew: Its that last section of an article, isn’t it? You’re reading along about some interesting technology and then it comes to the section of how you might work around it for the browsers that don’t support it.

Rachel: Yeah.

Drew: I thought-

Rachel: Exactly.

Drew:span> ... we were into a good thing here.

Rachel: Yeah, 'cause when you’re searching, you’re searching to solve a problem, things come up. Its very frustrating if you realize that its a year away or other browsers have said we’re not doing that or whatever, you know? So yeah, I think theres a lot of opportunities for clarity for people who are writing and for developers of libraries and frameworks to actually just make it very obvious to developers what the status is.

Drew: And things like WordPress themes for example, or any of these sorts of things where you’re taking somebody elses code and making it part of your project to know that what level of support in terms of web functionality is in that is invaluable. I guess it would make sense for things like tools that any tool that gives you code to embed into your site, be that a Stripe checkout or a live chat widget or any of those sorts of things, I guess it would make sense for them to declare their state of compatibility too.

Rachel: Yeah, yeah, its just kind of a shorthand. It saves you having to do all of that investigating for each thing that you use. And we know that every website these days has tons and tons of third party stuff in it. We’re not all sitting down with Notepad anymore and carefully crafting our websites. So I think anything that makes that easier and allows people to show the status of things is really helpful.

Drew: It actually is a really simple concept, isn’t it, to say heres the set of features, they’re well supported, we’re giving it a label, we’re documenting it. Its actually so simple, its really rather genius I think. Its some amazing work thats been done there by everyone involved.

Rachel: Yeah, I think it speaks to a lot of what I’ve thought about over many years in terms of that kind of clarity. And thats always been my thing is making things clear to people, making things seem straightforward rather than trying to make things complex. And so I really love being able to be involved with this and bring it forward.

Drew: The HTML spec for example has a process for an element or an attribute to be deprecated. So things get removed from the spec as they become obsolete or they’re replaced by a newer specification. Is it possible for features to drop out of Baseline once they’ve been included?

Rachel: It could be possible. Its one of the things we’ve talked about a lot. I think really the devil will definitely be in the detail with all this stuff. And thats one of the things is well what happens if something essentially gets broken? Maybe one engine does something which causes a problem with something. There is a possibility that yes, we’d have to remove something. Thats definitely something we’ve talked about. I mean hopefully browsers aren’t going around breaking stable features, but it is a possibility or something might get deprecated although we tend not to fully remove things from the web platform very often. Its more that we say, "Yeah, maybe don’t use this," but there is a possibility that something that is in Baseline could start to have a problem because of something that one of the engines does.

Drew: I guess then thats one area where these sort of yearly cuts as you’ve described them, become sort of quite useful in that something might have appeared in Baseline 24 but then in Baseline 30 it might be gone and there is a way of having a distinction there.

Rachel: Yeah, and it would also highlight that stuff I think a lot more clearly than we have a way of doing at the moment because I think hard to know what things have actually been deprecated on the platform. A lot of things that are deprecated are things that are only in one engine and therefore would never have been in Baseline in the first place. But yeah, it is possible as things move forward that that would happen and it would make it clearer.

Drew: And such as the way of the web, we do deprecate things, but as you say, they don’t ever go away really.

Rachel: Yeah.

Drew: We don't-

Rachel: I was just saying maybe don’t [inaudible 00:33:42].

Drew:span> ... tend to remove things, you know, can still use the, I’m guessing you can still use HTML font tags because we don’t break things once they’re standardized.

Rachel: Yeah.

Drew: Even though nobody would ever recommend using them, they’re still going to work in your browser because sites have been developed to that standard and the browser-

Rachel: Yeah.

Drew:span> ... will continue to support it. I guess, in a way, theres Baseline forms a little bit of a positive pressure. If a feature does get broken, then the fact that it was in Baseline and the whole community is relying on it being there is a factor in prioritizing what gets worked on by that particular maintainer of that browser engine. They’re going to see that, no, this is important, we need to fix it pretty quick.

Rachel: Yeah.

Drew: So hopefully its a sort of positive pressure in that regard. There seems to be so much really in development and coming to the web platform. Are there any particular things that you’re really looking forward to seeing becoming interoperable in the coming months?

Rachel: Yeah, I mean theres a bunch of interesting stuff. I’ve always been interested in the things that look at things that developers are already doing. So they’re using JavaScript to do it, or what have you, and then having them built into the platform because obviously things that are built into the platform we can build in things like accessibility and also performance. Things that tend to perform an awful lot better if they’re a built-in feature as opposed to being JavaScript on top. So theres sort of interesting stuff from the open UI group. The next thing that is about to land in Chrome is the Popover API. And of course popovers are something like everybodys building all the time.

Drew: Yeah.

Rachel: And I think a lot of these open UI things are very much those sorts of features that pretty much every developer, every front end developer has built on numerous occasions. And every front end developer has tried to solve the accessibility issues and the performance issues and the sort of weird bugs that come up when they interact with other things. And so the fact that these are getting actually built into browsers, I think, is very exciting because it just, its a bunch of work you don’t have to do and its probably going to have better accessibility and so on than most people are going to be able to manage for themselves and it gives something to build on top of as well, you know, can add things to them.

Rachel: So yeah, so I’m excited to see Popover and in a similar sort of vein is the work on scroll-driven animations because thats a thing that people like to do and is very hard to do well, you know, having things that animate on scroll and that, again, is something that is coming in. It should be in Chrome 115. So it’s, again, its these things that we’re doing on the front end of the web and we’re actually able then to build into the browser. I’m always very keen to see those 'cause I think they solve a lot of problems.

Drew: Yeah, definitely. I mean anywhere where a developer has to mimic something that you think is native browser UI and you’re trying to build it yourself, there are so many places to go wrong, aren’t there?

Rachel: Yeah.

Drew: If you’ve ever had any of your work through an accessibility audit, you know that its things like modal dialogues and all these sort of things that constantly will contain flaws that need to be addressed because theres just so many things to think about in terms of keyboard focus and clicking away and all these different subtleties that you need to make sure that you take care of, that is, as much as anything, as much as it being bad for accessibility, if you get it wrong, its a massive waste of time for all us developers doing this all ourselves over and over again when it just makes sense. Most apps will have some sort of modal or popover functionality. So yeah, it makes complete sense for it to be part of the platform implemented by the browser vendors in a way where its accessible and its just a good solid layer to then build on top of in terms of styling and yeah-

Rachel: Yeah.

Drew:span> ... it makes total sense. Its a exciting way to see the platform go.

Rachel: Yeah and I think, because the other thing with everyone building their own thing is that a lot of people don’t build their own thing, they rely on a third party thing and quite often things people are relying on are actually really old and they haven’t been updated to, they might have issues with accessibility or whatever and they haven’t really been updated for more modern browsers. And so its sort of, I think the more that people can use whats built into the browser, the sort of better experience that the end user of the site is likely to have.

Drew: So your team at Google maintains a bunch of resources to help developers keep up-to-date with the web platform. What are those resources and where should people go to look and find things? What would they expect to find there?

Rachel: Yeah, so we’ve got web.dev and developer.chrome.com are our two sites that DevRel own. It used to be, back in the day, when I sort of arrived, there was a real mixture of things on each site and a sort of thing that was commonly said was that Chrome were using web.dev to pretend things that were only in Chrome were stable APIs, lets say I don’t think anyone ever intended to pretend that. I think there was just a slightly disorganized content strategy. So as kind of part of the preparation for Baseline, because I wanted to make sure that we could be clear because if we’re talking about developer clarity, its pretty bad if all of our stuffs in a mess. I started moving content. And so now, certainly all the newer content, there may be some older stuff that we haven’t tracked down, but the newer content, if you go to web.dev, you should really be seeing stuff about stable APIs.

Rachel: So things that are interoperable and also things that are coming onto the platform. I do a sort of whats new on the web platform that includes some new stuff from all engines. So that kind of looking at what the broader landscape is and also things like our best practices. So things like about performance, which while some of the tooling is Chrome-only, raising the performance of your site, it is going to help in all engines. So thats whats there on web.dev. So thats kind of the practical side of things. You’re building a website, you want some advice. Thats what we’re doing there. And I try very hard to make that about the web, not about Chrome and thats the sort of content there.

Rachel: But obviously we are a team thats supporting Chrome and supporting the things that Chromes releasing and so we do that over on developer.chrome.com. So thats going to be your new APIs. You want to find out about popover thats landing, there’ll be an article about that soon. So all the things that Chrome is doing for the web, essentially you can find on developer.chrome.com. So that will be experimental things or Chrome-only things, things that are Chrome-only for now, all that stuff is there. And I hope that brings a bit of clarity to our content and that we’re not trying to pretend anything. We’re just trying to be clear about what we’re doing and how well supported it is.

Drew: Great. So we’ve been learning all about Web Platform Baseline. What have you been learning about lately, Rachel?

Rachel: Theres always something interesting to learn about. I’ve done a couple of things. I’ve been learning Python because its a language that I, for whatever reason, never learned. I’ve learned various languages over the years, but I do less web development these days and more kind of comparing of data sets and Python is the language that a lot of that stuff is done in. So its quite fun to learn new language anyway and its useful for the sort of stuff I tend to find myself doing these days.

Rachel: And I’ve also been thinking a bit about the whole generative AI space and in particular as a content lead, how do we prepare our content to make it more useful to those kind of models because theres a lot of stuff about asking questions of a chatbot and so on. And so I’ve been kind of just starting to read around that subject a little bit and start to see, well, if we’re preparing content, how can we be making that more useful for that kind of thing and that interaction?

Drew: If you, dear listener would like to hear more from Rachel, you can find her on the web at rachelandrew.co.uk where you’ll find links to her socials, her writing and numerous other projects. And you can find her writing regularly about the web platform at web.dev. Thanks for joining us today, Rachel. Did you have any parting words?

Rachel: Let us know about Baseline. Comment and raise some issues, or just join in the chat on the Web DX community group, on the GitHub repo there. We’d really like to hear what you think. This is, we’ve been talking about it internally for a long time and so now we’ve got it out there and I think the work starts now and the discussion with the community starts now. And so we’re all very, very excited to read the feedback and find out what you think.

Resources

]]>
hello@smashingmagazine.com (Drew McLellan)
<![CDATA[Practical Design Tips And Guidelines For Beginner Designers]]> https://smashingmagazine.com/2023/05/practical-design-tips-guidelines-beginner-designers/ https://smashingmagazine.com/2023/05/practical-design-tips-guidelines-beginner-designers/ Mon, 22 May 2023 11:00:00 GMT As someone who has worked with beginner designers for decades, I have observed a certain common problem. They often get overwhelmed with design tasks such as creating presentations, a personal website, mocking up an app idea, or even making menus or cards. It’s not due to a lack of ability and skills but rather because of unfamiliarity with the rules and systems that graphic designers are trained to understand.

To fill this gap, I have compiled some simple principles that are quick and easy to learn yet can greatly enhance any design project. In this article, we’ll focus on the four key elements of good design. Here they are:

  1. Structure,
  2. Spacing,
  3. Rhythm,
  4. Contrast.

By learning these simple concepts, anyone should be able to create effective designs that not only look good but also cater to diverse audiences, including those with disabilities. Are you ready to learn the power of these fundamental design concepts? If yes, follow me along!

Structure

Structure helps people absorb information. You see the toolbar before you can discern any individual tool in it. You recognize a form before you can identify a specific field in it. The proper structure helps you access information faster. It’s the main menu, the selection screen, before you dive in.

Let’s review an example. Imagine you are making a registration page for a webinar. The webinar page should contain the following information:

  • The event title,
  • A short synopsis,
  • The price of admission,
  • The time and date of the event,
  • The name of the host,
  • A photo of the host,
  • A short bio for the host,
  • Some social links for the host,
  • A register button,
  • A call-out: “Join me live!”.

Ask yourself, if you had to group those things into several groups/buckets, what would those be? How would you name each group/bucket? Here are the groups I would make, and it might not be precisely how you would group the information, but that’s OK; the idea is to just give you a start!

Headline Host Logistics
Call-out Host name Event date
Title Host photo Time & duration
Synopsis Host bio Price
Social links Register button

Now that we have those buckets let’s continue: In what order do we want the audience to ingest them? My choice would be the headline first, then the logistics, with the big register button. I would keep the host information more as a detour, something optional to dive into if you would like to learn more.

Compare these two versions. Isn’t it easier to ingest the information in the one on the right?

As you can see, the structure of the information greatly influences your ability to absorb it. I will go one step further. I believe beauty is an artifact of well-organized information.

In short, don’t try to make something beautiful. Try to make something well-organized, and watch the beauty emerge!

“A well-designed, user-friendly information architecture ensures that users spend less time and effort searching for information and are successful in finding what they need. Key information-architecture tasks include identifying common features in content, forming groups of similar information objects, and linking documents to other documents on the same topic.”

— Anastasia Stefanuk, “The Importance of Information Architecture to UX Design
Spacing

Spacing in graphic design refers to the arrangement of elements within a layout. Proper spacing can make your designs more visually appealing and easier for viewers to comprehend. It helps direct attention, creates hierarchy, and improves legibility.

Let’s look at another example. On the left, all the gaps are the same. On the right, the spacing is influenced by the structure. The inner group elements are more tightly grouped, creating a visible “scaffolding” for the content.

In print, space is expensive because the paper is not free. This is why in the past, only “luxury magazines” could afford those beautiful margins and airy layouts. Nowadays, white space is virtually free. Luxury for everybody!

"White space is the area between design elements. It is also the space within individual design elements, including the space between typography glyphs (readable characters). Despite its name, white space does not need to be white. It can be any color, texture, pattern, or even a background image. White space is a great tool to balance design elements and better organize content to improve the visual communication experience.”

— Mads Soegaard, “The Power of White Space in Design

The Space Must Flow

Consistent spacing around elements gives visual harmony and unity to your work. It ensures a coherent look across all the components of your design. This is because irregular gaps draw the viewer’s attention away from the main focus, which is counterproductive. By maintaining even spacing between all objects, you allow the content to communicate without interference.

Here are some tips for creating a nice flowing space between and around elements.

Centering In A Box

Sometimes you need to put an image (like a logo, for example) inside a box. In this case, leave at least half its shortest dimension as a minimum margin. E.g., if the image is wide, use half its height as a minimum margin. If the image is tall, use half its width.

Vertically Centering Text

Most of the text mass sits between the baseline and the top of the lowercase letters — squint your eyes slightly, and you will see what I mean. When vertically centering text, a good rule of thumb is to center the lowercase letters’ height. In the designer speech, it is called the “x-height.” Some typefaces might need a tiny vertical adjustment, but we’re going for simple here.

“Why is it called ‘x’ height? Because the letter ‘x’ is the only letter in the alphabet that has all its terminals touch both the baseline and the meanline, with no extending points. Curved letters such as a, c, e, o, r, or s usually pass the font’s x-height slightly.”

— Sirine Matta, “What Are Cap Height and X Height in Typography?

Text In A Shape

When centering text inside a box (like a button or a label), you need to use the height of the lowercase letters to do the centering and make sure there is the same amount of space all around the text, not just above and below.

Centering Polygons

When centering a polygon, center the circle passing by each point instead of centering the box around the polygon. Once again, this will ensure the space around the shape is nice and uniform.

Nested Rounded Boxes

The rounded boxes are great. They don’t have sharp edges. They feel more human, more organic as if these digital shapes have been sanded down or eroded, like pebbles.

However, when putting a rounded box into another one, a mistake I have seen often is to use the same border-radius on the box outside and the box inside. If you do this, the band (represented here with a colored gradient) will not have a consistent width. Instead, you need to use proportional radius when doing such rounded box nesting.

Rhythm

Human eyes get bored quickly. To keep their interest, you need to give them something new to parse and explore at regular intervals. But you don’t want to make it too hard either, too “new” every time — just a gentle walk along an interesting variety of patterns.

Rhythm contributes to a smooth flow that engages and holds the viewer’s interest while communicating effectively. A visual rhythm also provides directional cues to guide readers through the content.

Well, if you think about it, your slide deck is the same thing, and so is your portfolio, your app onboarding flow, and so many other things. Create variety constrained by a simple set of rules. Start with just left and right, and maybe one day, try using thirds if you feel comfortable. It’s not hard, you’ll see!

“Rhythm in art and design refers to a relationship between elements that creates a sense of harmony. Rhythm can be seen in patterns, in relationships between colors and shapes, and in repetitions of lines and forms. Rhythms help to guide the viewer’s eye around a piece rather than allowing the eye to settle on a particular focal point.”

— “Rhythm,” part of the “Principles of Design” BBC series

Repetition Is Key To A Rhythm

Repetition is key to a rhythm. Reusing elements such as colors, shapes, and text styles can create a sense of unity and coherence within your designs, making them feel more organized and visually appealing. It also makes your choices more intentional.

For example, I call a book-end any element that can be repeated to signal the beginning and the end of something. Shapes and colors are a great way to express creativity and bring some life to your content! It helps to tell your audience that a topic has ended in a nice and subtle way.

The repetition of certain visual elements creates patterns that catch our eye, engage our brains, and hold our interest, which can make any design feel more dynamic, expressive, and aesthetically pleasing. Find the guitar riff of your content; find the chorus!

Here is a meta example. These are the elements I reused throughout this article to create a sense of unity between all the illustrations. I had to pick some colors, decide on a style for the arrows, and make many more design choices. A bigger version of this is usually called a design system.

Reading Rhythm

When you are feeding words into people’s retinas, you need to find the right compromise between the size of the text chunks and the effort required to move the eye to the next line. That sounds mechanical because it kind of is. Too long a line, and it is hard to locate the beginning of the next line. Too short a line, and your reading gets interrupted too often for an eye carriage return.

I usually find that between eight and twelve words per line are a good goal for the main text block. Just count the words in a couple of sentences — no need to be too strict. Also, keep in mind that it’s a good rule for English, but other languages might have different sweet spots. For a sidebar, a caption, or something narrower, you can aim for five to six words.

Try reading some text in the example. You will see how much easier it is for your eyes to follow when the lines are not too long!

Before going further, I’d like to quote Gary Provost, an American writer and writing instructor, whose words on rhythm are spot-on:

“This sentence has five words. Here are five more words. Five-word sentences are fine. But several together become monotonous. Listen to what is happening. The writing is getting boring. The sound of it drones. It’s like a stuck record. The ear demands some variety. Now listen. I vary the sentence length, and I create music. Music. The writing sings. It has a pleasant rhythm, a lilt, a harmony. I use short sentences. And I use sentences of medium length. And sometimes, when I am certain the reader is rested, I will engage him with a sentence of considerable length, a sentence that burns with energy and builds with all the impetus of a crescendo, the roll of the drums, the crash of the cymbals–sounds that say listen to this, it is important.”

Gary Provost

Not So Justified

Justified text appears aligned on both sides. This is a very desirable attribute, but it’s very hard for it to happen naturally. Editing and design tools all do a pretty bad job of creating justified text that looks good. Instead, you will need to fine-tune letter spacing, word spacing, use good hyphenation, and sometimes even rewrite your text. Your job is to avoid text gaps that will hurt the pace of reading.

So, unless you spend the time to do the work manually, I suggest that you use left-aligned text instead. The price to pay for this shiny right edge is not worth it!

Contrast

Contrast refers to the use of differences (in color, size, shape, weight, direction, or texture) to attract attention, create hierarchy, enhance readability, and even evoke emotions like calm or energy. If a rhythm is the beat, contrast is the melody.

Mind The Low Contrast

To ensure your content is accessible to everybody, including people with visual impairments, text on a colored background should have enough contrast to be easily readable. There are plenty of apps or plugins that can calculate that for you (I’ve included a few references at the end of the article, check Further Reading). For now, all you really need to know is that a contrast ratio of 4.5 or higher is recommended.

Text Size Contrast

Text size can be used as a very convenient tool for structuring information. A well-structured text can significantly lower the effort required for the viewer to ingest the information. The contrast between each heading level should be high enough for the structure to be visible.

If possible, a consistent ratio between different header levels usually looks more elegant. In general, the weight of the text (bold, regular, light) decreases as the level increases.

Text Weight Contrast

Sometimes, the typeface you are using comes with many weights, like medium, semi-bold, light, and so on. In those cases, it’s usually recommended to skip one weight when pairing them to create enough contrast between them.

Avoid Unintentional Contrast

Combining text with an icon can help comprehension, improve visual appeal, or increase the importance of an element. However, always make sure the thickness of the text matches the thickness of the icon. That will make it feel as if it were part of the typeface. It does look more elegant, but it also saves your audience from even thinking about it, which is a recurring theme in graphic design. Good design is invisible!

“Although we can’t help but notice poor design, good design is much harder to detect. We’d go even further: good design is invisible. This raises a logical question: what, then, is good design? Is it when form follows function? Is it the perfect arrangement of design elements on a modernist grid? Is it 24-point headings and 8-point body text? Is it a solid set of principles that you work to every time on every job? The answer might surprise you — good design is all of this. And none of it.”

— Damien Stanyer, “Why is good design invisible?
Conclusion

That might have surprised you, but creating and iterating on designs isn’t about making things pretty. Your job as a designer is to lower the cognitive load for people to ingest the information, create a rhythm that keeps your viewer engaged, and make sure everybody can access the content.

“The most important advice I would give to emerging designers — even those that have already won awards — is that learning never stops. You can always improve your craft, whether you’ve won one award or twenty. Remember, you’re never going to be an expert in everything. I have worked on so many things, from book design to exhibition design, hospitality, tech, and everything in between — and I’ve taken something new from the experience every time. Now I’m the executive creative director at a global agency, and I still find myself learning something new every day.”

— Lisa Smith, “Learning Never Stops

Next time you are faced with the need to design something, I hope those tips will make you feel a little bit more confident and comfortable! And remember, everybody can be a designer, but every designer has a lot to learn and to keep learning. It’s a process that never stops.

Further Reading

I created a list of additional resources about the topics that I have tried to cover briefly so far. (And if you think this list is missing something of value, please do leave a comment at the end of the article. Thank you! 💖)

]]>
hello@smashingmagazine.com (Laurent Baumann)
<![CDATA[How To Deal With Big Tooling Upgrades In Large Organizations]]> https://smashingmagazine.com/2023/05/big-tooling-upgrades-large-organizations/ https://smashingmagazine.com/2023/05/big-tooling-upgrades-large-organizations/ Wed, 17 May 2023 10:00:00 GMT If you work in software development, you probably know a thing or two about using and maintaining third-party packages. While third-party tooling has its fair share of downsides, there are plenty of advantages as well. The efficiency you get from code that someone else has already written speeds up development and is hard to deny. Sure, there are all sorts of considerations to take in before plopping code from a third party — accessibility, technical debt, and security, to name a few — but the benefits may make taking on those considerations worthwhile for your team.

Upgrades are also part of that set of considerations. Usually, your team may treat this sort of maintenance as a simple task or chore: upgrading dependencies and (automatically) validating that all of the features keep functioning as expected. You probably even have automated checks for keeping all package versions up to date.

But what if the third-party tooling you adopt is big? I mean big, big. That’s common in large organizations. I happen to work for a fairly large organization that leverages big third-party resources, and upgrading those tools is never as simple as running a package update and moving on. I thought I’d share what’s involved in that process because there are many moving pieces that require ample planning, strategy, and coordination. Our team has learned a lot about the process that I hope will benefit you and your team as well.

Some Context On My Organization

I work for Jumbo Supermarkten in the Jumbo Tech Campus (JTC), which is a department of over 350 developers working in agile teams on a range of digital products that help facilitate our core grocery and e-commerce processes.

We have a variety of responsibilities, where 70% of the work is allocated to the primary objectives for each team, and the remaining 30% is dedicated to anything a team wants, as long as it is beneficial to the JTC, which is very useful if you want to deliver value outside of your own team.

When we look at maintaining tooling and packages, balancing the goals of each team with the goals of JTC means that teams effectively maintain their own codebases while also collectively maintaining internally shared codebases that serve as the tooling and foundation of our applications.

Centralized Code As A Bottleneck

To build our applications with consistent standards, we rely on an internal design system and the component library we call Kompas (Dutch for “Compass”). We have built this system ourselves and rely on Vue to render our components and build interactions. Kompas is a hard dependency for virtually all of our applications to ensure uniformity.

This project was not allocated to a dedicated team. Instead, we adopted a strategy that introduced plenty of guidance to allow all front-end developers to contribute. Any developer can add new components to the library as well as features to existing components and keep everything in sync with the designs.

Teams normally work on business features since product owners love delivering customer value. The way we set up our process would allow a team to, in one sprint:

  • Make the required change in Kompas,
  • Have it reviewed by peers from both inside and outside a particular team,
  • Publish the latest version of the component library, and
  • Use that version in that team’s own application to deliver to the end user.

We can only do this with automation on repetitive processes — linting, formatting, quality assurance, testing, visual comparisons, and publishing — in order to provide enough room for developers to contribute to the process. Our component library is very much a living document of our design system, with multiple minor releases and patches a week. With semantic versioning, we can keep our own applications up to date easily and with confidence.

For bigger undertakings, such as setting up visual snapshot tests, we established temporary working groups alongside our existing teams that we called “front-end chapters” where members join on a voluntary basis. In these meetings, we discuss what needs to be done, and in the available 30% of free time we are allotted, the members of these teams carry out the work and report back to the chapter.

As you can imagine, we’ve spent a lot of time and effort ensuring the quality and making it a reliable part of our landscape.

This all began when Vue was in Version 2. That’s the version we baked into Kompas, which means we effectively forced our whole application landscape to follow suit. This worked perfectly for us; people could focus on their team’s needs while leaning on the support of the entire front-end chapter that works on Kompas.

Following the Vue ecosystem that we introduced, Vuex and Nuxt became part of our environment. And then Vue 3 was announced, and it was a massive breaking change from Vue 2! With the announcement, the end-of-life date for Vue 2 was set for December 31, 2023. We still have some time as of this writing, but the news had a massive impact that cascaded throughout our organization.

We Needed A Strategy

We needed to upgrade Vue from 2 to 3. The first thing that we needed to figure out was when we could reasonably start the process. To assess and strategize, we formed a small virtual team of developers consisting of members from various teams so that multiple perspectives were represented.

We figured that there would be a period of time when we would need to support both versions in order to allow time for migrating between teams. It would be nearly impossible to orchestrate a monolithic release. Thus, we prefer gradual incrementing over massive sweeping changes. On the other hand, having to maintain two versions of Vue for, basically, the same business feature presented costs in time and complexity.

So, in order to execute this process as responsibly as possible, we set out to figure out when we could start, taking into account the longevity of maintaining two codebases while getting early experience from upgrading. We started to map the different tech stacks for each team and plotted out potential bottlenecks for the sake of making the process of our work as widely visible as possible. At this time, our organization had a very flat structure, so we also needed to get internal stakeholders (i.e., product owners, architects, and managers) involved and convey the effect this upgrade would have on teams across the board.

Creating A Map

With our starting point set, we move on to establish a direction. Not having a dedicated team did pose some challenges because it meant that we needed to align everybody in a democratic way. This is, in Dutch culture, also known as polderen:

We try to find consensus in a way where everybody is equally happy, or unhappy, about the final direction.

And this can be challenging in a department that consists of many cultures!

One thing we knew we could rely on was the published best practices from official Vue resources to guide our decision-making process. Referencing the documentation, we did notice opportunities for incremental upgrades. The release of Vue 2.7 (Naruto) was really helpful in the sense that it backported features from Vue 3 back to a Vue 2-compatible version.

We also noted that in our landscape, not all applications were actually using Nuxt. A stable release of Nuxt 3 would be a prerequisite for those applications to even be considered for migration since the Vue major version is tightly coupled with the Nuxt major version. Luckily, some applications in our landscape are standalone Vue apps. These are ideal candidates for the first Vue 3-compatible components.

But first, we would need to have components that were compatible with Vue 3.

The Big Divide

By this point, we were confident enough to get to work. We had a plan and clear strategy, after all. The first order of business was to make sure that our component library was compatible with Vue 3, preferably while minimizing duplicative efforts.

We found a really nice way of doing this:

We created a new workspace called “Kompas-next” next to the regular components folder, which was scaffolded out using Vue 3. Then we imported the components from the original library.

This only works because:

  • The backported features in Vue 2.7 allowed us to move closer toward the Vue 3 composition API (among other things).
  • The component syntax between Vue 2 and Vue 3 isn’t radically different anymore.
  • Vue Demi allowed us to convert components, one by one, to be compatible with both versions.
  • We made sure that Kompas-next runs isolated tests to ensure stability.

We did have to slightly modify each and every component to adapt to the new standards. We’ll get to that process in a minute.

That said, we were able to publish two versions of our component library: one that is compatible with Vue 2 (Kompas) and one that is compatible with Vue 3 (Kompas-next). This, in turn, meant that the teams that did not have Nuxt as a dependency could potentially start migrating!

Getting Organized

Up to this point, most of the groundwork had been done in a relatively small team. We were in charge of the investigations, communication, and alignment. But we still needed to get stuff done — a lot of stuff!

With every developer being able to contribute, we came to an agreement that fits with the way everybody was already contributing to the component library:

If you touch a component that is not yet compatible, convert it to be compliant with both Vue 2 and Vue 3 using Vue-demi. Add the existing component with tests to the imports of the Kompas-next folder.

Having communicated this strategy early in the process, we immediately saw the Kompas-next library growing. The Vue core team has put so much effort into closing the gap between the two versions, which made our lives much easier.

Feedback From Early Adopters

The teams that were not blocked by a Nuxt 3 release could spend their time migrating their complete app to Vue 3, providing feedback along the way on how we were setting up our packages and converting components.

Seeing the first applications using Vue 3 was a milestone we could all be proud of since we managed to reach it together, collaboratively, and with a united strategy. The strategy worked for us because it closely resembled the way we were already working.

There were indeed some components that were not migrated using this strategy, which indicated to us that they were stale in terms of development. We reasoned that “stale” equals “stable” and that it would be perfectly fine to migrate them by manual assignment and distribution since we can expect it to be close to a one-off migration per component.

We also started to add Vue 3-specific capabilities to our component library, such as our own composables. I think that’s a nice testament to the investment and adoption by our front-end chapter.

With the component library now supporting Vue, we cleared a significant migration hurdle in our organization. We enabled teams to start migrating to Vue 3, and we encouraged new applications to use the latest standards. As a result, we could start thinking about a deprecation path for our Vue 2 codebase. We were cautiously optimistic and aligned the end-of-life date for Kompas with the same date for Vue 2: December 31, 2023.

So, yes, we are not yet finished and still have work to do. In fact, we had…

Two (Minor) Elephants In The Room

To support communication between micro-applications that run on our e-commerce domain, we had resorted to using Vuex in the past. We used to register stores globally so other applications could dispatch actions and retrieve a shared state. This is now gradually being migrated in the sense that we are replacing Vuex with Pinia for internal state management.

For cross-app communication, we are in the process of decoupling Vuex as an external interface and promoting the use of custom events tied to a specific domain. This prevents us from locking ourselves out of future state management tooling.

We are also in the process of preparing our Nuxt applications to be cleared for migration as well. Within our e-commerce domain, we’ve been building specific modules that take a lot of overhead out of our hands: They handle tasks like setting meta headers, security, and analytics. These are being rewritten to use plugins rather than modules. The impact of this breaking change is smaller because it is limited to the teams that use these modules. We see that these teams are using a similar strategy, albeit on a smaller scale, to organize and structure the tasks at hand.

Looking Back

I believe we have a few key takeaways from how we upgraded (and continue to upgrade) from one version of a large third-party resource to another within our large network of teams and shared codebases. I believe the lessons we learned are relevant beyond Vue and can be applied to the processes of other large organizations migrating between versions of a core piece of architecture.

Let’s review what we learned:

  • Ensure the transition period is clear and as short as possible.
  • Facilitate breaking the work down into small steps that progress iteratively and solicit feedback from those involved in the process as early and as often as possible.
  • Onboard key stakeholders to make sure your team has ample time and resources to do the work.
  • Define a strategy that fits with your organization’s culture.
  • Foster a collaborative mindset and establish clear communication between teams.
  • Celebrate wins, even the smallest ones!
The Work Is Never Done, Really

As I mentioned earlier, maintenance is a never-ending piece of the software development process. As Vue creator Evan You stated in the State of the Vuenion 2023, Vue plans to ship more frequent updates and releases. This will keep impacting our work, but that’s okay. We have a plan and blueprint for future releases.

We’re not there yet, but we now know how to get there!

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Joran Quinten)
<![CDATA[Design Patterns Are A Better Way To Collaborate On Your Design System]]> https://smashingmagazine.com/2023/05/design-patterns-collaborate-design-system/ https://smashingmagazine.com/2023/05/design-patterns-collaborate-design-system/ Tue, 16 May 2023 11:00:00 GMT True collaboration to create or maintain a design system is really important to making superb product design, but working with other humans is always tricky. The collaborative nature of a design system can have a lot of pitfalls. In its best form, it is the product of close alignment between developers and designers, but it doesn’t always happen that way.

Some painful memories:

  • A brilliant designer I worked with made a gorgeous new set of elements and examples for the company to use, but the other designers in the company ran into many situations where it was more expedient to just copy and remake (i.e., detach) the component. The design system was used less and less since contributing to it was always a lower priority than working on a product opportunity.
  • A developer I worked with built the design system components such that the padding in every text input, button, and so on always had to be the same in every layout, leading to awkward results when (for example) a button included double-byte characters, only icons, or just longer labels.
  • I did a lot of work on variations of nested components (button bar, toggle buttons, segmented controls) that were designed to use the same style properties as base components (like a button), but the developers I was working with made brand new components for each that didn’t. So, I had to document and specify the many, many identical sets of style values for many, many sets of slightly different components.

The list goes on. I’m sure you have your own examples.

Getting Aligned

I’ve worked in many kinds of teams, in large companies and start-ups, where these collaboration issues kept getting in the way, even (or especially) with very talented and smart individual contributors. Getting aligned with my teammates doesn’t happen automatically or just because we go to lots of meetings. In fact, it’s very easy to start a project together and get pretty far into it before finding out we all had very different ideas about what we were doing. When it comes to complex questions of re-using an existing component vs. making something new or how to stay on the same page without blocking each other, alignment takes practice for any team.

The method for making design systems I’ll talk about probably works best in environments where you are a sole designer (or among a small number of designers) on a cross-functional team, including front-end or full-stack developers, led by a product owner. You might collaborate with other designers in other teams, but this is your “first team.” In this context, you have a lot of freedom but also a lot of responsibility.

You need an idea for nurturing the design system that doesn’t depend on organizational mandates or a specific “process” and one you can apply yourself. After all, a design system is a product with users, and we know how to balance the user’s needs with product opportunities, right? (Yes!)

The approach described below is not common or widely used, but in my experience, it has solved many team collaboration problems, including:

  • Eliminating the “hand-off” step: a truly perverse mini-waterfall built into many relationships between designers and developers.
  • Ensuring that all designers and developers contribute to the design system as a part of regular product work.
  • Connecting design systems to product impact: measurably speeding things up by making more reusable elements and modules in design and development.
A New Use For An Old Idea

What has worked for me in these kinds of teams is a twist on an old idea: design patterns. Elsewhere, design patterns are described as “a toolkit of solutions to common problems” (Refactoring.Guru) or “description or template for how to solve a problem that can be used in many different situations” (SourceMaking). My favorite definition of the concept is from The Timeless Way of Building:

“Even the most complicated, sophisticated things are defined by a small number of composable patterns.”

— Christopher Alexander

You probably don’t think of your own design activities as a “pattern-making” practice, but the idea has a lot of very useful overlap with the practice of making a design system. The trick is to collaborate with your team to find the design patterns in your own product design, the parts that repeat in different variations that you can reuse. Once you find them, they are a powerful tool for making design systems work with a team.

Design Patterns For Design Systems

To see how, first, let’s get specific about the definition of “design pattern” in our product design context. Let’s call a “design element” a small isolated component like a “button,” “chip,” or “card,” and let’s describe a design pattern as a reusable combination of elements for a purpose, a larger module that can do some product experience work on its own.

The elements are the focus of the design systems in most companies I have worked at, and creating them is important and a lot of work. I am sorry to say, however,

Having a good set of elements doesn’t help you get the value out of a design system, save you much time, or by itself ensure designers and engineers are aligned.

For this reason (and the availability of great existing elements from Tailwind, Bulma, Skeleton, or of course, MUI) I have de-emphasized them in my own work, often just restyling elements created by others. The elements are important, and you do need a set that everyone uses, but they don’t do the work of implementing a feature or valuable experience.

You might be thinking that many of these systems do come with combinations of elements, like the “pre-built components” that MUI ships with for a “Data Grid” or the “blueprints” in the Salesforce Lightning Web system for a “List Builder.” Are these the patterns that can help us?

Unfortunately, they are not. These are patterns for sure, but they probably aren’t useful as-is for you. Your product has its own needs. You can use them as a starting point, but in my experience, it takes longer to rework them into something that solves the problem.

To be useful for you, a design pattern has to come out of and express some reusable part of your particular product experience — those parts of the design you find yourself making again and again.

Here are some examples of these useful, product-specific design patterns in products:

  • A tile in a TV app, which people use to browse things to watch in lists. This is sort of a “card” pattern, but not really! Every streaming service has its own particular kind of tile and includes different content and controls that suit that product best.

  • A dashboard meter in a data-visualization app like Google Analytics. Again, this is sort of a “panel” pattern, but not really! Each part of the dashboard might have different kinds of meters, with titles, category labels, “big numbers,” charts, text snippets, or filtering controls, and the number of elements in a meter varies by app.
  • A tree view in a social genealogy app that lets users see relationships between people in a way that adapts for display on small devices. Some products focus on researching your family, others on visualizing relationships.

In each of these cases, designers and developers made their own product-specific patterns. Those patterns are valuable because once a team has defined them, the next project that the team does gets easier. They develop and grow a kit of parts that save them time (and that they can polish and refine). The patterns, not the elements, are the heart of this (better) kind of design system.

Taking this a step further, I would say that a lesson from these patterns is that

All designers and developers can make their design system better and more effective by focusing on patterns first (instead of the elements), making sure that each is completely reusable and polished for any context in their product.

Pattern work can be a fully integrated part of both getting some immediate work done and maintaining a design system.

Design Patterns For Collaboration

This kind of design pattern activity can be a direct path for designers and developers to collaborate, to align the way things are designed with the way they are built, and vice-versa. For that purpose, a pattern does not have to be a polished design. It can be a rough outline or wireframe that designers and developers make together. It needs no special skills and can be started and iterated on by all. And collaborating on this form of a design pattern makes it possible for designers and developers to work in parallel.

That’s all pretty abstract. It’s easier just to try an example.

A Design Pattern Story

Let’s say that we’re on a team together, working on an app called “WeTrip.”

The product opportunity comes from the reality we have all probably dealt with: when a group of people or a family travels together, they usually have a lot of trouble deciding what to do or where to eat.

This app makes group travel easier by giving people an easy way to propose and vote on the plan for each day. Instead of having to have long conversations that feature such sentences as “I dunno, what do you want to do?” travelers have a tool so people can have less trouble with the logistics of a vacation or a trip.

The app has some seed funding, but in order to survive needs some “minimum viable” version of itself to prove that it’s something needed and valuable. Everyone on the team wants to get going! Nobody wants to be waiting for a design.

The designers, engineers, and product people all meet and pick the names of some basic objects and their properties. They start with a “Person,” someone on the trip who votes on places to go together for a meal or sightseeing. They sketch things out on a whiteboard.

This is their first pattern.

They move on, describing things like a “Place,” a location someone wants to visit.

And an “Occasion” pattern, a time the group will do things together like eat, and so on.

The process can work with a physical whiteboard, shared document, collaboration app, or whatever. All that is important is that everyone participates so they are aligned and get the details they need to start work.

With this rough outline, they can see that some of the parts of these patterns are elements they can pull from existing design systems.

They decided to use some restyled MUI elements. Those have defined properties (named attributes of a component, like “color” or “content”) already and will be a nice shortcut. They pull them into Figma (their design tool of choice) and development (a React web app with the MUI library as a dependency). They add some of these MUI elements and their standard properties to each pattern.

For each pattern, they create a page in a shared Notion document that everyone can edit and update. They start by adding properties from the MUI elements they’ve chosen.

The team combines the properties from the MUI elements with others they’ve sketched out and flattens the properties a bit. They group the properties so that it’s clear what is most important and secondary.

The Figma component will have a different variant for each important property (like activity or actionsAvalable). And each of the element properties will become part of the component in development, of course. In this way, the design and development are aligned — not necessarily completely the same in every detail, but in the ways that matter, moving in the same direction.

The team talks about more ideas for each pattern. Adding properties doesn’t mean they will appear in the final design, just that an idea could be part of the experience, so it’s a low-stakes conversation where final decisions don’t need to be made.

After going through the same process for the “Place” and “Occasion” patterns, the designers and developers have a lot of what they need to make progress. They have agreed on the names of things and what the important properties are. The patterns are defined in a form that the whole team can see and edit, and they start work.

An engineer might stub out a “Person” component like the one below while a designer is sketching it out in Figma with no bottlenecks.

Of course, the engineers figure out that there are some properties they need that they missed at first, like a presence property for a user (after all, in order to know how to show a user notification, it helps to know if that user is using the app right now or a notification would be better). They add that to the document and message the rest of the team.

At the same time, the designers are fleshing out the patterns, using the MUI Figma library where possible, and adding new components where needed. When the team sees the addition of a presence property to the Person pattern, they decide to make a presence indicator and group it with the primary elements. As long as they are keeping the simple pattern document up to date, there is no handoff or waiting around.

Sometimes there are big questions to resolve about the experience. But that is the occasion for the next meeting about what the primary views in the app should be.

The team meets again and comes up with a “People” view (a list of people on the trip, with their status), a “Schedule” view (with a list of occasions and the plan for each day), and a “Proposals” view (to see and propose places to go) — more design patterns. For this pattern documentation, one of the product owners wants to use a wireframing tool instead of an outline (as in the previous example). That’s fine. Pretty much anything works to describe patterns as long as it shows elements and groups (and it’s what a team likes using).

In these patterns, lists of Person, Occasion, and Place patterns are nested inside of each view. It becomes clear that there will have to be two versions of a Person pattern in the app, so the property is added to that pattern.

As they work, if an engineer gets a little ahead of whatever design work exists, they can either use standard MUI components or add a proposal to the patterns document. And designers can add new components if the design starts to need them. All parties are able to make changes without blocking each other.

Organizational Needs

Now, I should pause here to note that there are plenty of teams where this kind of pattern definition is not the primary product definition activity and where other stakeholders (engineering managers and so on) have a say in how the design system is built. Not all teams are small and have as much ownership. Even in larger companies, however, I believe design patterns can be very useful and help make a case for development work (since they show how the design system is helping teams get things done). But in those contexts, design patterns may be small parts of other organizational processes and not as important overall.

In this small team, the struggle to justify time on a design system is for a different reason: there’s a great temptation to put it off because everyone wants very badly to ship something sooner, and it feels “extra.” But every member of the team also knows that the minute they want to iterate on their product, that work will be easier if they have created a design system, and so they keep their good practice going.

Putting It All Together

Once the patterns are established as a way for the entire team to collaborate, final designs and views come together more quickly (because the entire team was able to start together and finish together). The visual design happens at the end rather than being a bottleneck before people can start work.

Integrating Patterns In Product Planning

As working with patterns becomes more established and mature, patterns can be broken out into separate repositories and polished on their own, either as a separate library in Figma or a set of modules in development. If a team gets larger, there might even be an official owner for each pattern who handles bugs or polishes details.

Each pattern properties list can be turned into an API once a module is trustworthy to use in new design and development. In the WeTrip example, the scrolling list of places for today is reused in a search results view when it’s added later.

Since patterns are by their nature only the reusable parts that save designers and developers time, patterns can make working on the design system something with a hard-core product improvement impact. Re-use can be captured as a key metric and a factor in prioritization. The amount of reusable work being generated can be tracked automatically in design and development tools (much like test coverage).

If the reuse of patterns becomes common enough that it needs careful management, patterns can become part of a federated module build process (like what is built into WebPack 5). In short: patterns lend themselves very well to being part of the toolchain of many modern development processes.

Your Turn

I imagine that there are many teams that already practice some of these concepts in the collaboration between design and development, and I am very eager to hear about that! It has been a happy improvement as a method for myself and the people I have worked with, and I would love to hear your stories.

For others, I hope this has been a good introduction to a vision for you and your team of an alternate reality where you can seamlessly collaborate on design systems without as many pitfalls. I wish the best to you and your team as you find your way to such harmony and a happy design outcome!

]]>
hello@smashingmagazine.com (Ben Clemens)
<![CDATA[Solving Media Object Float Issues With CSS Block Formatting Contexts]]> https://smashingmagazine.com/2023/05/media-object-float-issues-css-block-formatting-contexts/ https://smashingmagazine.com/2023/05/media-object-float-issues-css-block-formatting-contexts/ Mon, 15 May 2023 13:00:00 GMT Let’s imagine we’re making a small component. It can be anything, really, but let’s use a media object as an example. Nicole Sullivan had a solid definition of media objects from way back in 2010, and you probably already know the pattern well: some form of media (often an image) on the left and text beside it on the right. The media could be an image or a video, for example.

This is the basic HTML for the layout, minimized for brevity:

<section class="container">
  <article class="float-left">
    <img src="https://picsum.photos/100">
      <p>I've never had to cook or clean since I discovered Xyz. They perform all my tasks for me. I recommend them.</p>
      <h3>Dan Somore</h3>
  </article>

  <!-- more articles -->

</section>

This HTML gives us a <section> element that is the container for four <article> elements, where each one is a testimonial container that holds an <img> and a <div> with a block of text — our media objects.

Let’s apply some light styling in CSS:

/* Give the parent container breathing room */
.container {
  padding: 20px;
}

/* 
  Styles for each testimonial container 
  Each container is floated left
*/
.float-left {
  border: 2px solid blue;
  background-color: transparent;
  float: left;
  width: 45%;
  min-height: 150px;
  margin-bottom: 20px;
  margin-right: 20px;
}

/* Testimonial images are floated left */
img {
  float: left;
  margin-right: 10px;
}

This code is by no means perfect. In fact, it introduces the wrapping and overflow issues we’re about to discuss. We will look at these issues together before getting into solutions.

Issue 1: Height Collapsing

When an element is floated in its container, it exits its normal document flow and into a floated position, making no contributions to the container’s height. In a container of many floated media objects, the container element’s height is collapsed to contain only non-floated elements. The collapsed height might be inconspicuous in containers without a border or non-floated elements and could disrupt the layout of other elements after a media object container. However, this issue can be easily discovered if there is a non-floated element in the container, among other floated elements.

Let’s add a border to the parent container to see the height-collapsing effect.

The height of the content is what influences the height of the testimonial container. If the image were in the container’s flow, it would be taller than the text, and the container would adjust to it. But, alas, that’s not the case since we introduced a block formatting context when floating the image.

The popular solution with a single line of CSS on the testimonial’s parent container:


.container {
  overflow: auto;
}

The BFC this generates establishes a new document flow within the page’s root element, containing all the container's child elements, including floated media objects. It effectively prevents the testimonial elements from being displaced beyond the parent container’s borders — no extra divs or pseudo-elements are needed like the clearfix approach.

See the Pen Float Solutions: overflow: auto [forked] by Geoff Graham.

That certainly gets the job done! But I want to show you one more way to do this because I believe it’s the best of the bunch.

The Best Solution: display: flow-root

display: flow-root was introduced to address inconsistencies associated with using overflow for generating BFCs. In fact, display: flow-root was explicitly designed to produce BFC, while the overflow property is designed to manage content that surpasses its container. Consequently, overflow can induce unintended side effects, from unwanted scrollbars to data loss.

That’s why I recommend using display: flow-root. It is meant to create a BFC when you need it, whereas the other solutions are more like workarounds.

Conclusion

CSS block formatting contexts are great because they allow you to leave the main document flow, allowing elements to interact differently in a layout. But, of course, those different interactions can feel like buggy behavior if you’re unaware that you’re actually working in a different formatting context.

This is exactly why we have modern layout techniques like Flexbox and Grid. Before we had them, floats were a nice trick for faking columns. But the BFC they created wasn’t so nice. Hence clever workarounds like the clearfix to create a BFC to wrangle the other BFC.

Perhaps the bigger takeaway from all this, though, is to evaluate your layout strategy. If you’re reaching for a float, is it really the best option for what you’re trying to do? Because if so, you may as well embrace the natural text-wrapping behavior rather than trying to fight it. And if you don’t want to fight it, that’s a sure sign you ought to reach for a more modern layout technique, like Flexbox or Grid.

Resources

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Gabriel Shoyombo)
<![CDATA[Designing Sticky Menus: UX Guidelines]]> https://smashingmagazine.com/2023/05/sticky-menus-ux-guidelines/ https://smashingmagazine.com/2023/05/sticky-menus-ux-guidelines/ Fri, 12 May 2023 11:00:00 GMT We often rely on sticky headers to point user’s attention to critical features or calls to action. Think of sidebar navigation, CTAs, sticky headers and footers, “fixed” rows or columns in tables, and floating buttons. We’ve already looked into mobile navigation patterns in Smart Interface Design Patterns, but sticky menus deserve a closer look.

As users scroll, a sticky menu always stays in sight. And typically, it’s considered to be a good feature, especially if the menus are frequently used and especially if we want to speed up navigation.

However, sticky menus also come with a few disadvantages. In his recent article on Sticky Menus Are Problematic, And What To Do Instead, Adam Silver argues about some common usability issues of sticky menus — and how to solve them. Let’s take a closer look.

When Sticky Menus Are Useful

How do we decide if a menu should be sticky or not? This depends on the primary job of a page. If it’s designed to primarily convey information and we don’t expect a lot of navigation, then sticky menus aren’t very helpful.

However, if we expect users to navigate between different views on a page a lot and stay on the page while doing so — as it often is on long landing pages, product pages, and filters — then having access to navigation, A-Z or tabs can be very helpful.

Also, when users compare features in a data table, sticky headers help them verify that they always look at the right piece of data. That’s where sticky headers or columns can help and aid understanding. That’s why sticky bars are so frequently used in eCommerce, and in my experience, they improve the discoverability of content and speed of interaction.

Keep Sticky Headers Small, But Large Enough To Avoid Rage Taps

The downside of sticky menus is that they typically make it more difficult for users to explore the page as they obscure content. Full-width bars on mobile and desktop are common, but they need to be compact, especially on narrow screens. And they need to accommodate for accessible tap sizes to prevent rage taps and rage clicks.

Typically, that means we can’t have more than five items in the sticky bar navigation. The choice of the items displayed in the sticky menu should be informed by the most important tasks that users need to perform on the website. If you have more than five items, you probably might need to look into some sort of an overflow menu, as displayed by Samsung.

Whenever users have to deal with forms on a page on mobile, consider replacing sticky menus with accordions. Virtual keyboards typically take up to 60% of the screen, and with a sticky bar in view, filling in a form quickly becomes nothing short of impossible.

Accessibility Issues of Sticky Menus

By their nature, sticky menus always live on top of the content and often cause accessibility issues. They break when users zoom in. They often block the content for keyboard users who tab through the content. They obscure links and other focusable elements. And there is often not enough contrast between the menu and the content area.

Whenever we implement a sticky menu, we need to make sure that focusable elements are still visible with a sticky menu in action. And this also goes for internal page anchors that need to account for the sticky bar with the scroll-padding property in CSS.

Avoid Multiple Scrollbars Of Long Sticky Menus

When sticky menus become lengthy, the last items on the list become difficult to access. We could make them visible with some sort of an overflow menu, but often they appear as scrollable panes, causing multiple scroll bars.

Not only does this behavior cause discoverability issues, but it’s also often a cause for mistakes and repetitive actions on a page. Ideally, we would prevent it by keeping the number of items short, but often it’s not possible or can’t be managed properly.

A way out is to show the menu as an accordion instead in situations when the space is limited, especially on mobile devices. That’s what we do at Smashing Magazine in the checkout, with a button that reveals and hides the contents of the cart when needed.

Partially Persistent Menus

Because sticky menus often take up too much space, we could reveal them when needed and hide them when a user is focused on the content. That’s the idea behind partially persistent headers: as a user starts scrolling down, the menu disappears, but then any scrolling up prompts the menu to appear again.

The issue with this pattern is that sometimes users just want to jump back to a previous section of the page or double-check some details in a previous paragraph, and the menu often gets in the way. Page Laubheimer from NN/Group recommends using a slide-in animation that is roughly 300–400ms long and will preserve the natural feel without being distracting.

Alternatives To Sticky Menus

In some situations, we might not need a sticky menu after all. We can avoid their downsides with shorter pages, or lengthy pages which repeat relevant calls-to-actions or navigation within the page.

We could display a table of contents on the top of the page and bring the user’s attention to the table of contents with a back-to-top link at the bottom of the page.

Wrapping Up

Whenever the job of the page is to help users act, save, and compare, or we expect users to rely on navigation a lot, we might consider displaying sticky navigation. They are most harmful when there isn’t enough space anyway, as it often is with forms on mobile devices.

Sticky menus do come at a cost, as we need to account for usability and accessibility issues, especially for zooming, keyboard navigation, and anchor jumps. Add them if you need them, but be careful in plugging them in by default.

We need to prioritize what matters and remove what doesn’t. And too often, the focus should lie entirely on content and not navigation.

You can find more details on navigation UX in the video library on Smart Interface Design Patterns 🍣 — with a live UX training that’s coming up in September this year.

Further Resources

Of course, the techniques listed above barely scratch the surface. Here are wonderful articles around sticky headers, from design considerations to technical implementations:

]]>
hello@smashingmagazine.com (Vitaly Friedman)
<![CDATA[How To Boost Your Design Workflow With Setapp]]> https://smashingmagazine.com/2023/05/boost-design-workflow-setapp/ https://smashingmagazine.com/2023/05/boost-design-workflow-setapp/ Thu, 11 May 2023 14:00:00 GMT This article is a sponsored by MacPaw Inc.

As someone who wears multiple hats, it is challenging to balance a full-time job, freelance projects, and all sorts of creative endeavors.

This is how I started off: By day, I’m a full-time product designer. By night, I juggle all sorts of freelance work and creative projects.

I am currently self-employed. However, there are challenges that come with being my own boss: Working with clients, sales and negotiation, invoicing, building a personal brand, crafting a content strategy, time tracking, project management… The list goes on.

Trying to keep up with everything used to be tough. No matter how hard I tried, my to-do list always seemed never-ending. I was constantly feeling overwhelmed.

I thought to myself, “There’s got to be a better way.”

After analyzing my workflow, I realized that many tasks could be simplified or automated so that I could save time, focus on high-value tasks, and work fewer hours.

After years of trial and error, I discovered a range of tools and strategies that helped me save time and stay organized to focus on what really matters.

The apps mentioned in this guide are available on Setapp. Whether you’re a Mac user or not, these hacks will help you get more done in less time and improve your quality of life. I hope you find value in this guide.

Streamline Your Workflow With the Best Apps

You can use Setapp to access 240+ apps on your Mac and iPhone under a single monthly subscription.

Personally, I use Setapp to do three things:

  1. Try out apps that could help save time. Some of these apps cost more than Setapp’s subscription, so it’s a relief that I do not need to pay for each one individually.
  2. For apps that I only need to use occasionally, I can quickly install and uninstall them as needed, with no extra cost. This saves me precious space on my Mac and ensures that I’m not cluttering up my system with unnecessary apps.
  3. Since Setapp’s library is updated regularly, I always get to try out new apps to further enhance my workflow.
Track Time & Eliminate Distractions

As a freelance designer, I need to track how much time I spend on each project to calculate my billable hours. I used to manually create events on my calendar and calculate the hours spent on each project. It’s a waste of time, and sadly, it is inaccurate.

To solve this problem, you can use Timemator to track your time accurately and minimize distractions.

With Timemator, you can set up auto time-tracking rules for specific apps, files, or websites. For example, you can set rules so that the timer starts tracking when you work on a specific project on Figma or Adobe Photoshop.

The timer runs quietly in the background so that you can stay focused without any interruptions. You no longer need to manually start or pause the timer.

Pro tip: Use it to reduce distractions! Set up auto-tracking to track how much time you spend on meetings, talking to teammates or clients on Slack, or watching Netflix.

To help you identify where you’ve spent your time, Timemator gives detailed reports and analytics so you can reduce or eliminate time-wasting activities and get more done in less time.

The Only Font Manager You Need

As designers, we all know that font selection can make or break a creative project.

I was frustrated with Font Book (the default font manager on MacOS). It wasn’t user-friendly. Searching and comparing fonts was a chore.

I found Typeface to be useful — especially when you need to quickly browse through your font collection, customize the preview text and size in real-time, and compare to see how different fonts look side-by-side.

Over the years, I have saved up a huge font library. Typeface is able to load all my fonts quickly and remove duplicate fonts that bloat up my computer. It supports variable fonts and OpenType font features and has robust features for the busy designer.

For fonts you don’t use often, you can choose to activate them only when necessary. This way, your computer stays clean and fast.

As a bonus, you can also easily organize fonts into custom collections or tags.

Fastest Way To Create Device Mockups

When designing, we often need to create high-quality, professional-looking phone, tablet, and computer mockups to showcase our designs.

I used to spend hours searching for device mockup templates and launch Adobe Photoshop in order to use those templates. The whole process was time-consuming, so I switched to a tool called Mockuuups Studio.

All you need to do is drag and drop a screenshot of your website or app into it, pick a scene, and it will generate thousands of mockups. It’s pretty neat.

You can filter through scenes, models, and devices to find the perfect mockup for your digital product. Then, add hands, overlays, realistic shadows, or backgrounds to your device mockups. In the example above, I have filtered ‘iPhone’ mockups only.

Since it’s cloud-based, you can access it anywhere and collaborate with your teammates in real time too.

To further speed up your workflow, you can use their Figma, Sketch, or Adobe XD plugin. This is their Figma plugin:

Create Screenshots & Screen Recordings, Fast

When presenting designs (especially when working remotely), I take screenshots and screen recordings for my clients every day.

But instead of using the default Mac screenshot tool, CleanShot X is a better solution. This is an essential tool for every Mac user.

To quickly take a screenshot, use this shortcut key on your Mac: Command + Shift + 4.

This tool gives you the convenience to record MP4 or GIF with your desktop icons hidden, capture scrollable content, and annotate, highlight, or blur screenshots to hide sensitive personal information.

An example of how I annotate my screenshots:

I’ve used this tool for years with zero complaints. This tool will make your life easier when sharing screenshots with clients or on social media.

A cool feature you’ll also love: You can capture and copy any text, so you’ll never have to manually retype it again!

Your workflow will become much more streamlined and efficient since you no longer get bogged down in the technical details.

Never Waste Time Searching For Meeting Links Again

It’s challenging to keep track of various meetings, their details, and attendees, especially when switching between Google Meet, Zoom, your email inbox, and calendars.

To solve this problem, you can use Meeter to schedule or join meetings with one click right from the menu bar on your Mac.

It supports Google Meet, Zoom, and Microsoft Teams. When you want to join a meeting, you no longer have to waste time searching for meeting links, then copy and paste the link into the browser. Instead, you can now focus on being present in every meeting.

The tool allows you to directly call your FaceTime contacts and phone numbers and jump into recurring calls from the menu bar too. Pretty simple!

Save Time With Spotlight On Mac

When working with multiple files and apps on your Mac, you need to be able to quickly find and access them instead of navigating through different folders.

With Spotlight, you can do these things quickly. While this is not an app, it’s one of the most powerful features on Mac that can save you plenty of time.

To open Spotlight, simply hit Command + Spacebar on your keyboard and start typing.

Then, try these on Spotlight:

  • Perform quick calculations.
    No need to open a calculator app. Simply type in your calculation in Spotlight and hit enter. It’s that easy.
  • Search for apps.
    Quickly find any app on your Mac.
  • Search the internet.
    Type your search term, and it will launch your default browser with the search results. You’ve just saved a few clicks.
  • Find files or folders.
    Type in the name of the file or folder, and you have it.

  • Check the weather.
    Type “weather” followed by your location, and it will give you up-to-date information on the current weather conditions and forecast.

Cool, right? Learning how to use Spotlight effectively is a game-changer. Give it a try, and see how much time you can save.

Design Accessible Interfaces

As a product designer who also builds websites for clients, it’s a challenge to find and create the perfect color palettes while working on multiple projects at once. In the past, I've had to rely on a combination of tools like swatch libraries and notes to keep track of my palettes.

If you’re a designer or a developer, you’ll love Sip — a powerful color picker that can help you design beautiful and accessible interfaces easily.

With Sip, you can quickly grab colors right from the Mac menu bar and drop them into any design or development tool, including Adobe Photoshop, Figma, and Sketch. This makes it easy to create custom color palettes that match the client’s brand.

You can create and save custom color palettes, and the quick access menu that floats on the side of your desktop gives you quick access to your color palettes.

Currently, it supports 24 of the most popular color formats in the industry, like Android XML, CSS hex, RGB, and CMYK.

Now, my favorite feature is Sip’s Contrast Checker. In the example below, you can use the color picker to check the contrast between the gray text and white background, ensuring that it meets accessibility standards and is legible for all users.

Tip: Always make sure the contrast between the text and background is greater than or equal to 4.5:1 for small text and 3:1 for large text. If the color contrast fails, click on the ‘FIX’ button to improve it!

Declutter Your Mac’s Menu Bar

If you have a bunch of apps running on your Mac, your menu bar may be cluttered with all sorts of icons and notifications.

Just like physical clutter, digital clutter takes up mental space and affects your focus, too! To solve this problem, you can use Bartender.

Bartender allows you to organize your menu bar icons into neat and tidy groups or hide them completely — as simple as that. You can collapse your menu bar icons into a customizable dropdown menu so it remains clutter-free.

In the above example, most of my menu icons are hidden, except Figma and the battery level indicator.

After using it for over a month, I am able to focus better. It’s one of those subtle quality-of-life improvements that can have a big impact on your productivity and mindset.

Wrapping Up

I wish I had discovered these tools sooner!

The apps I’ve shared above are available on Setapp. With a single monthly subscription, you get access to 240+ Mac and iPhone apps. They offer a free 7-day trial, so you can try it out and decide if it’s right for you.

These tools have completely transformed my workflow and helped me become more productive and less stressed. I hope that these tools will do the same for you so you can make the most of your time. After all, time is a limited resource, and it's up to us to use it wisely.

Thank you for reading. Have a productive day!

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Rachel How)
<![CDATA[A Guide To Redux Toolkit With TypeScript]]> https://smashingmagazine.com/2023/05/guide-redux-toolkit-typescript/ https://smashingmagazine.com/2023/05/guide-redux-toolkit-typescript/ Wed, 10 May 2023 10:00:00 GMT If you are a React developer working on a complex application, you will need to use global state management for your app at some point. React Redux is one of the most popular libraries for state management used by many developers. However, React Redux has a complex setup process that I’ve found inefficient, not to mention it requires a lot of boilerplate code. The official developer of Redux developed the Redux Toolkit to simplify the process.

This article is for those with enough knowledge of React and TypeScript to work with Redux.

About Redux

Redux is the global state management library for React applications. If you have used useState() hooks for managing your app state, you will find it hard to access the state when you need it in the other parts of the application. With useState() hooks, the state can be passed from the parent component to the child, and you will be stuck with the problem of prop drilling if you need to pass it to multiple children. That’s where Redux comes in to manage the application state.

Introducing Redux Toolkit

Redux Toolkit is a set of opinionated and standardised tools that simplify application development using the Redux state management library.

The primary benefit of using Redux Toolkit is that it removes the overhead of writing a lot of boilerplates like you’d have to do with plain Redux.

It eliminates the need to write standard Redux setup code, such as defining actions, reducers, and store configuration, which can be a significant amount of code to write and maintain.

Jerry Navi has a great tutorial that shows the full Redux setup process.

Why I Prefer Redux Toolkit Over Redux

The Redux Toolkit has several key features which make me use this library over plain Redux:

  1. Defining reducers
    With Redux Toolkit, you can specify a slice with a few lines of code to define a reducer instead of defining actions and reducers separately, like Redux.
  2. Immutability helpers
    Redux Toolkit includes a set of utility functions that make it easy to update objects and arrays in an immutable way. This makes writing code that follows the Redux principles of immutability simpler.
  3. Built-in middleware
    Redux Toolkit includes built-in middleware that can handle asynchronous request tasks.
  4. DevTools integration
    Redux Toolkit includes integration with the Redux DevTools browser extension, which makes it easier to debug and analyse Redux code.
Using Redux Toolkit To Build A Project Issue Tracker

I think the best way to explain the value and benefits of using Redux Toolkit is simply to show them to you in a real-world context. So, let’s develop an app with it that is designed to create and track GitHub issues.

You can follow along with the code examples as we go and reference the full code anytime by grabbing it from GitHub. There is also a live deployment of this example that you can check out.

Start creating a new React app with the following command:

yarn create react-app project_issue_tracker --template typescript

This generates a folder for our project with the basic files we need for development. The –template typescript part of the command is used to add TypeScript to the stack.

Now, let’s install the dependencies packages required for our project and build the primary UI for the application before we implement Redux Toolkit. First, navigate to the project_issue_tracker project folder we just created:

cd project_issue_tracker

Then run the following command to install Material UI and Emotion, where the former is a design library we can use to style components, and the latter enables writing CSS in JavaScript files.

yarn add @mui/material @emotion/react @emotion/styled

Now we can install Redix Toolkit and Redux itself:

yarn add @reduxjs/toolkit react-redux

We have everything we need to start developing! We can start by building the user interface.

Developing The User Interface

In this section, we will be developing the UI of the app. Open the main project folder and create a new components subfolder directly in the root. Inside this new folder, create a new file called ProjectCard.tsx. This is where we will write the code for a ProjectCard component that contains information about an open issue in the project issue tracker.

Let’s import some design elements from the Material UI package we installed to the new /components/ProjectCard.tsx file to get us started:

import React from "react";
import { Typography, Grid, Stack, Paper} from "@mui/material";
interface IProps {
    issueTitle: string
}
const ProjectCard : React.FC<IProps> = ({ issueTitle }) => {
    return(
        <div className="project_card">
            <Paper elevation={1} sx={{p: '10px', m:'1rem'}}>
                <Grid container spacing={2}>
                    <Grid item xs={12} md={6}>
                        <Stack spacing={2}>
                            <Typography variant="h6" sx={{fontWeight: 'bold'}}>
                                Issue Title: {issueTitle}
                            </Typography>
                            <Stack direction='row' spacing={2}>
                                <Typography variant="body1">
                                    Opened: yesterday
                                </Typography>
                                <Typography variant="body1">
                                    Priority: medium
                                </Typography>
                            </Stack>
                        </Stack>
                    </Grid>
                </Grid>
            </Paper>
        </div>
    )
}
export default ProjectCard;

This creates the project card that displays an issue title, issue priority level, and the time the issue was “opened.” Notice that we are using an issueTitle prop that will be passed to the ProjectCard component to render the issue with a provided title.

Now, let’s create the component for the app’s HomePage to display all the issues. We’ll add a small form to the page for submitting new issues that contain a text field for entering the issue name and a button to submit the form. We can do that by opening up the src/HomePage.tsx file in the project folder and importing React’s useState hook, a few more styled elements from Material UI, and the ProjectCard component we set up earlier:

import React, { useState } from "react";
import { Box, Typography, TextField, Stack, Button } from "@mui/material";
import ProjectCard from "./components/ProjectCard";
const HomePage = () => {
    const [textInput, setTextInput] = useState('');
    const handleTextInputChange = (e:any) => {
        setTextInput(e.target.value);
    };
    return(
        <div className="home_page">
            <Box sx={{ml: '5rem', mr: '5rem'}}>
                <Typography variant="h4" sx={{textAlign: 'center'}}>
                    Project Issue Tracker
                </Typography>
                <Box sx={{display: 'flex'}}>
                    <Stack spacing={2}>
                        <Typography variant="h5">
                            Add new issue
                        </Typography>
                        <TextField 
                        id="outlined-basic" 
                        label="Title" 
                        variant="outlined" 
                        onChange={handleTextInputChange}
                        value={textInput}
                        />
                        <Button variant="contained">Submit</Button>
                    </Stack>
                </Box>
                <Box sx={{ml: '1rem', mt: '3rem'}}>
                    <Typography variant="h5" >
                        Opened issue
                    </Typography>
                        <ProjectCard issueTitle="Bug: Issue 1" />
                        <ProjectCard issueTitle="Bug: Issue 2" />
                </Box>
            </Box>
        </div>
    )
}
export default HomePage;

This results in a new HomePage component that a user can interact with to add new issues by entering an issue name in a form text input. When the issue is submitted, a new ProjectCard component is added to the HomePage, which acts as an index for viewing all open issues.

The only thing left for the interface is to render the HomePage, which we can do by adding it to the App.tsx file. The full code is available here on GitHub.

Using Redux Toolkit

Now that our UI is finalised, we can move on to implementing Redux Toolkit to manage the state of this app. We will use Redux Toolkit to manage the state of the ProjectCard list by storing all the issues in a store that can be accessed from anywhere in the application.

Before we move to the actual implementation, let’s understand a few Redux Toolkit concepts to help understand what we’re implementing:

  1. createSlice
    This function makes it easy to define the reducer, actions, and the initialState under one object. Unlike the plain redux, you don’t need to use a switch for actions and need to define the actions separately. This function accepts an object as a name (i.e., the name of the slice) and the initial state of the store and the reducer, where you define all the reducers along with their action types.
  2. configureStore
    This function is an abstraction for the Redux createStore() function. It removes the dependency of defining reducers separately and creating a store again. This way, the store is configured automatically and can be passed to the Provider.
  3. createAsyncThunk
    This function simplifies making asynchronous calls. It automatically dispatches many different actions for managing the state of the calls and provides a standardised way to handle errors.

Let’s implement all of this! We will create the issueReducer with an addIssue() action that adds any new submitted issue to the projectIssues store. This can be done by creating a new file in src/redux/ called IssueReducer.ts with this code:

// Part 1
import { createSlice, PayloadAction } from "@reduxjs/toolkit"

// Part 2
export interface IssueInitialState {
    projectIssues: string[]
}
const initialState: IssueInitialState = {
    projectIssues: []
}

// Part 3
export const issueSlice = createSlice({
    name: 'issue',
    initialState,
    reducers: {
        addIssue: (state, action: PayloadAction<string>) => {
            state.projectIssues = [...state.projectIssues, action.payload]
        }
    }
})

// Part 4
export const { addIssue } = issueSlice.actions
export default issueSlice.reducer

Let’s understand each part of the code. First, we are importing the necessary functions from the Redux @reduxjs/toolkit package.

Then, we create the type definition of our initial state and initialise the initialState for the issueReducer. The initialState has a projectIssues[] list that will be used to store all the submitted issues. We can have as many properties defined in the initialState as we need for the application.

Thirdly, we are defining the issueSlice using Redux Toolkit’s createSlice function, which has the logic of the issueReducer as well as the different actions associated with it. createSlice accepts an object with a few properties, including:

  • name: the name of the slice,
  • initialState: the initial state of the reducer function,
  • reducers: an object that accepts different actions we want to define for our reducer.

The slice name for the issueReducer is issueSlice. The initalState of it is defined, and a single adIssue action is associated with it. The addIssue action is dispatched whenever a new issue is submitted. We can have other actions defined, too, if the app requires it, but this is all we need for this example.

Finally, in the last part of the code, we export the actions associated with our reducer and the issueSlice reducer. We have fully implemented our issueReducer, which stores all the submitted issues by dispatching the addIssue action.

Now let’s configure the issueReducer in our store so we can use it in the app. Create a new file in src/redux/ called index.ts, and add the following code:

import { configureStore } from "@reduxjs/toolkit";
import IssueReducer from "./IssueReducer";
export const store = configureStore({
    reducer: {
        issue: IssueReducer
    }
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

This code configures and creates the store using the configureStore() function that accepts a reducer where we can pass all of the different reducers.

We are done adding the reducer and configuring the store with Redux Toolkit. Let’s do the final step of passing the store to our app. Start by updating the App.tsx file to pass the store using the Provider:

import React from 'react';
import { Provider } from "react-redux"
import { store } from './redux';
import HomePage from './HomePage';
function App() {
    return (
        <div className="App">
            <Provider store={store}>
                <HomePage />
            </Provider>
        </div>
     );
}
export default App;

Here, you can see that we are importing the store and directly passing through the Provider. We don’t need to write anything extra to create a store or configure DevTools like we would using plain Redux. This is definitely one of the ways Redux Toolkit streamlines things.

OK, we have successfully set up a store and a reducer for our app with Redux Toolkit. Let’s use our app now and see if it works. To quickly sum things up, the dispatch() function is used to dispatch any actions to the store, and useSelector() is used for accessing any state properties.

We will dispatch the addIssue action when the form button is clicked:

const handleClick = () => {
    dispatch(addIssue(textInput))
}

To access the projectIssue list stored in our reducer store, we can make use of useSelector() like this:

const issueList = useSelector((state: RootState) => state.issue.projectIssues)

Finally, we can render all the issues by map()-ping the issueList to the ProjectCard component:

{
    issueList.map((issue) => {
        return(
            <ProjectCard issueTitle={issue} />
        )
    })
}

The final code for HomePage.tsx looks like this:

import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "./redux/index"
import { Box, Typography, TextField, Stack, Button } from "@mui/material";
import ProjectCard from "./components/ProjectCard";
import { addIssue } from "./redux/IssueReducer";
const HomePage = () => {
    const dispatch = useDispatch();
    const issueList = useSelector((state: RootState) => state.issue.projectIssues)
    const [textInput, setTextInput] = useState('');
    const handleTextInputChange = (e:any) => {
        setTextInput(e.target.value);
    };
    const handleClick = () => {
        dispatch(addIssue(textInput))
    }
    return(
        <div className="home_page">
            <Box sx={{ml: '5rem', mr: '5rem'}}>
                <Typography variant="h4" sx={{textAlign: 'center'}}>
                    Project Issue Tracker
                </Typography>
                <Box sx={{display: 'flex'}}>
                    <Stack spacing={2}>
                        <Typography variant="h5">
                            Add new issue
                        </Typography>
                        <TextField 
                        id="outlined-basic" 
                        label="Title" 
                        variant="outlined" 
                        onChange={handleTextInputChange}
                        value={textInput}
                        />
                        <Button variant="contained" onClick={handleClick}>Submit</Button>
                    </Stack>
                </Box>
                <Box sx={{ml: '1rem', mt: '3rem'}}>
                    <Typography variant="h5" >
                        Opened issue
                    </Typography>
                    {
                        issueList.map((issue) => {
                            return(
                                <ProjectCard issueTitle={issue} />
                            )
                        })
                    }
                </Box>
            </Box>
        </div>
    )
}
export default HomePage;

Now, when we add and submit an issue using the form, that issue will be rendered on the homepage.

This section covered how to define any reducer and how they’re used in the app. The following section will cover how Redux Toolkit makes asynchronous calls a relatively simple task.

Making Asynchronous Calls With Redux Toolkit

We implemented our store to save and render any newly added issue to our app. What if we want to call GitHub API for any repository and list all the issues of it in our app? In this section, we will see how to use the createAsyncThunk() API with the slice to get data and render all the repository issues using an API call.

I always prefer to use the createAsyncThunk() API of the redux toolkit because it standardises the way different states are handled, such as loading, error, and fulfilled. Another reason is that we don’t need to add extra configurations for the middleware.

Let’s add the code for creating a GithubIssue reducer first before we break it down to understand what’s happening. Add a new GithubIssueReducer.ts file in the /redux folder and add this code:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
export const fetchIssues = createAsyncThunk<string[], void, { rejectValue: string }>(
  "githubIssue/fetchIssues",
  async (_, thunkAPI) => {
    try {
      const response = await fetch("https://api.github.com/repos/github/hub/issues");
      const data = await response.json();
      const issues = data.map((issue: { title: string }) => issue.title);
      return issues;
    } catch (error) {
      return thunkAPI.rejectWithValue("Failed to fetch issues.");
    }
  }
);
interface IssuesState {
  issues: string[];
  loading: boolean;
  error: string | null;
}
const initialState: IssuesState = {
  issues: [],
  loading: false,
  error: null,
};
export const issuesSliceGithub = createSlice({
  name: 'github_issues',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchIssues.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchIssues.fulfilled, (state, action) => {
        state.loading = false;
        state.issues = action.payload;
      })
      .addCase(fetchIssues.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message || 'Something went wrong';
      });
  },
});
export default issuesSliceGithub.reducer;

Let’s understand the fetchIssues part first:

  1. We are using the createAsyncThunk() API provided by the Redux Toolkit. It helps create asynchronous actions and handles the app’s loading and error states.
  2. The action type name is the first argument passed to createAsyncThunk(). The specific action type name we have defined is githubIssue/fetchIssues.
  3. The second argument is a function that returns a Promise, which resolves to the value that dispatches the action. This is when the asynchronous function fetches data from a GitHub API endpoint and maps the response data to a list of issue titles.
  4. The third argument is an object that contains configuration options for the async thunk. In this case, we have specified that the async thunk will not be dispatched with any arguments (hence the void type) and that if the Promise returned by the async function is rejected, the async thunk will return an action with a rejected status along with a rejectValue property that contains the string “Failed to fetch issues.”

When this action is dispatched, the API calls will be made, and the githubIssuesList data will be stored. We can follow this exact same sequence of steps to make any API calls we need.

The second section of the code is similar to what we used when we created the issueSlice, but with three differences:

  1. extraReducers
    This object contains the reducers logic for the reducers not defined in the createSlice reducers object. It takes a builder object where different cases can be added using addCase for specific action types.
  2. addCase
    This method on the builder object creates a new case for the reducer function.
  3. API call states
    The callback function passed to the addCase method is dispatched by createAsyncThunk(), which updates the different store objects based on the API call states (pending, fulfilled, and error).

We can now use the GithubIssue reducer actions and the store in our app. Let’s add the GithubIssueReducer to our store first. Update the /redux/index.ts file with this code:


import { configureStore } from "@reduxjs/toolkit";
import { useDispatch } from "react-redux";
import IssueReducer from "./IssueReducer";
import GithubIssueReducer from "./GithubIssueReducer";
export const store = configureStore({
    reducer: {
        issue: IssueReducer,
        githubIssue: GithubIssueReducer
    }
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()

We just added the GithubIssueReducer to our store with the name mapped to githubIssue. We can now use this reducer in our HomePage component to dispatch the fetchIssues() and populate our page with all the issues received from the GitHub API repo.

import React, { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { useAppDispatch, RootState, AppDispatch } from "./redux/index";
import { Box, Typography, TextField, Stack, Button } from "@mui/material";
import ProjectCard from "./components/ProjectCard";
import { addIssue } from "./redux/IssueReducer";
import { fetchIssues } from "./redux/GithubIssueReducer";
const HomePage = () => {
    const dispatch: AppDispatch = useAppDispatch();
    const [textInput, setTextInput] = useState('');
    const githubIssueList = useSelector((state: RootState) => state.githubIssue.issues)
    const loading = useSelector((state: RootState) => state.githubIssue.loading);
    const error = useSelector((state: RootState) => state.githubIssue.error);
    useEffect(() => {
        dispatch(fetchIssues())
      }, [dispatch]);

    if (loading) {
      return <div>Loading...</div>;
    }

    if (error) {
      return <div>Error: {error}</div>;
    }
    const handleTextInputChange = (e:any) => {
        setTextInput(e.target.value);
    };
    const handleClick = () => {
        console.log(textInput)
        dispatch(addIssue(textInput))
    }
    return(
        <div className="home_page">
            <Box sx={{ml: '5rem', mr: '5rem'}}>
                <Typography variant="h4" sx={{textAlign: 'center'}}>
                    Project Issue Tracker
                </Typography>
                <Box sx={{display: 'flex'}}>
                    <Stack spacing={2}>
                        <Typography variant="h5">
                            Add new issue
                        </Typography>
                        <TextField 
                        id="outlined-basic" 
                        label="Title" 
                        variant="outlined" 
                        onChange={handleTextInputChange}
                        value={textInput}
                        />
                        <Button variant="contained" onClick={handleClick}>Submit</Button>
                    </Stack>
                </Box>
                <Box sx={{ml: '1rem', mt: '3rem'}}>
                    <Typography variant="h5" >
                        Opened issue
                    </Typography>
                    {
                        githubIssueList?.map((issue : string) => {
                            return(
                                <ProjectCard issueTitle={issue} />
                            )
                        })
                    }
                </Box>
            </Box>
        </div>
    )
}
export default HomePage;

This updates the code in HomePage.tsx with two minor changes:

  1. We dispatch fetchIssue and use the createAsync() action to make the API calls under the useEffect hook.
  2. We use the loading and error states when the component renders.

Now, when loading the app, you will first see the “Loading” text rendered, and once the API call is fulfilled, the issuesList will be populated with all the titles of GitHub issues fetched from the repo.

Once again, the complete code for this project can be found on GitHub. You can also check out a live deployment of the app, which displays all the issues fetched from GitHub.

Conclusion

There we have it! We used Redux Toolkit in a React TypeScript application to build a fully functional project issue tracker that syncs with GitHub and allows us to create new issues directly from the app.

We learned many of the foundational concepts of Redux Toolkit, such as defining reducers, immutability helpers, built-in middleware, and DevTools integration. I hope you feel powered to use Redux Toolkit effectively in your projects. With Redux Toolkit, you can improve the performance and scalability of your React applications by effectively managing the global state.

Further Reading on Smashing Magazine

]]>
hello@smashingmagazine.com (Deepak Kumar)
<![CDATA[How To Use AI Tools To Skyrocket Your Programming Productivity]]> https://smashingmagazine.com/2023/05/ai-tools-skyrocket-programming-productivity/ https://smashingmagazine.com/2023/05/ai-tools-skyrocket-programming-productivity/ Tue, 09 May 2023 09:00:00 GMT Programming is fun. At least, that’s the relationship I would love to have with programming. However, we all know that with the thrills and joys of programming, there comes a multitude of struggles, unforeseen problems, and long hours of coding. Not to mention — too much coffee.

If only there were a way to cut out all of the menial struggles programmers face daily and bring them straight to the things they should be spending their energy on thinking and doing, such as critical problem-solving, creating better designs, and testing their creations.

Well, in recent times, we’ve been introduced to exactly that.

The start of this year marked the dawn of a huge shift towards Artificial Intelligence (AI) as a means of completing tasks, saving time, and improving our systems. There is a whole new realm of use cases with the rise of AI and its potential to seriously impact our lives in a positive manner.

While many have concerns swirling about AI taking over jobs (and yes, programmers have been raised up), I take an entirely different perspective. I believe that AI has the ability to skyrocket your productivity in programming like nothing before, and over the last couple of months, I have been able to reap the benefits of this growing wave.

Today, I want to share this knowledge with you and the ways that I have been using AI to supersize my programming output and productivity so that you’ll be able to do the same.

Case Study: ChatGPT

If you have missed much of the recent news, let me get you up to speed and share with you the main inspiration for this guide. In late November 2022, OpenAI announced its latest chatbot — ChatGPT, which took the world by storm with over a million sign-ups in its first week.

It was an extremely powerful tool that had never been seen before, blowing people away with its capabilities and responses. Want a 30-word summary of a 1000-word article? Throw it in, and in a few seconds, you’ve just saved yourself a long read. Need an email sales copy for a programming book that teaches you how to code in O(1) speed, written in the style of Kent Beck? Again, it will be back to you in a few seconds. The list of ChatGPT use cases goes on.

However, as a programmer, what really got me excited was ChatGPT’s ability to understand and write code. GPT-3, the model that ChatGPT runs on, has been trained on a wide range of text, including programming languages and code excerpts. As a result, it can generate code snippets and explanations within a matter of seconds.

While there are many AI tools other than ChatGPT that can help programmers boost their productivity, such as Youchat and Cogram, I will be looking at ChatGPT as the main tool for this guide, due to the fact that it is publicly available for free at OpenAI’s website and that it has a very gentle learning curve for a wide range of applications.

And again, before we continue, I would like to re-emphasize that

AI tools such as ChatGPT are meant to streamline your workflow, not take over and replace your thinking and problem-solving.

That being said, let’s see how I used ChatGPT to skyrocket my programming productivity.

Common Problems And How ChatGPT Can Help

To help shine a light on this topic, I have compiled five of the most common ways that I have used ChatGPT to overcome problems that any programmer would experience daily. Those five problems are the following:

  1. Programmer’s block,
  2. Long hours of debugging,
  3. Understanding long documentation,
  4. Developer testing,
  5. Code optimization.

It’s a lot to cover, but I’ll give you real-life examples so that you will be able to take the knowledge from this guide and use it to your own advantage. Let’s jump straight in.

Programmer’s Block

Programmer’s block is the programmer’s equivalent of writer’s block and is one of the most common problems that many programmers, myself included, face regularly. When tasked with a significant programming job, such as getting started with building a multiple-page website in HTML, CSS, and JavaScript, it’s easy to get caught in the weeds of not knowing where to start.

Or you could be knee-deep in a coding project and hit a roadblock in finding a solution for a problem. It’s often a frustrating scenario to be in.

ChatGPT has been an excellent solution for that. Let’s look at the example above in having programmer’s block before embarking on a large programming task. Suppose I’m looking to start a new project. After surfing for software company ideas, I decided to develop a sleek and modern online store in HTML, CSS, and JavaScript to sell my latest programming book.

While ChatGPT won’t be able to hit the mark in producing the entire project, a great way to use it is to generate the skeleton for you to begin. Throwing in a detailed prompt for the task, this is what you get:

Prompt: Can you provide a basic structure for a sleek and modern single online store landing page, with red as the main color, for my new programming book in HTML and CSS?

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Your Book Title</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <nav>
      <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <section>
      <h1>Programming book title</h1>
      <p>A comprehensive guide to becoming a proficient programmer</p>
      <button>Learn More</button>
    </section>
    <section>
      <h2>Features of the Book:</h2>
      <ul>
        <li>Step-by-step tutorials for learning core programming concepts</li>
        <li>In-depth explanations of commonly used programming languages</li>
        <li>Hands-on exercises and real-world projects to reinforce learning</li>
        <li>Case studies to illustrate the application of programming in various industries</li>
        <li>Tips and tricks for efficient and effective programming practices</li>
      </ul>
    </section>
  </main>
  <footer>
    <p>Copyright 2023</p>
  </footer>
</body>

style.css

body {
  font-family: Arial, sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0;
  padding: 0;
}

header, footer {
  background-color: red;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 50px;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
}

nav ul {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

nav a {
  color: white;
  display: block;
  padding: 10px 20px;
  text-decoration: none;
}

main {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  height: calc(100vh - 100px);
}

section {
  max-width: 800px;
  padding: 40px;
  margin-top: 100px;
  text-align: center;
  background-color: white;
  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
  border-radius: 10px;
  margin-bottom: 20px;
  margin-left: auto;
  margin-right: auto;
}

h2 {
  margin-top: 40px;
}

ul {
  list-style: none;
  margin-top: 20px;
  padding-left: 0;
}

li {
  margin-bottom: 10px;
}

That gives us the following template to start our work with:

Nothing impressive, but it does provide a great starting point as opposed to a blank HTML file.

Now, of course, I would highly recommend that the most you create with this is the barebones structure. We are using these tools to abstract away menial tasks like creating the HTML structure so that you can focus on more important things like implementing your own CSS styles and HTML features.

HTML and CSS templates are already widely-used concepts. However, with AI, we can now create more personalized templates and basic code structures, getting us from staring at a blank HTML file to a workable skeleton in a matter of minutes.

Use it to create a starting platform for you to get over your programmer’s block, but for the fine details and exact features, your programming knowledge will still be irreplaceable.

Nevertheless, I have been using it to get numerous programming projects up and running. I had this sentence-length counter made from scratch easily within an hour by creating the base template and adding on what I wanted after. I find that being able to jump-start that process makes my programming workflow much more streamlined and enjoyable.

Long Hours Of Debugging

Another common frustration every programmer knows is debugging. Debugging is an extremely time-intensive aspect of programming that can often be very draining and leave programmers at roadblocks, which is detrimental to a productive programming session.

Fortunately, AI is able to cut out a lot of the frustration of debugging, while at the same time, it does not replace the job of programmers in having strong fundamentals in knowing how to debug. At the current time, most AI tools are not able to spot every single flaw in your code and suggest the correct changes to make; hence, it is still essential that you are capable of debugging code.

However, AI is a great supplementary tool to your debugging skills in two main ways:

  1. Understanding runtime errors;
  2. Providing context-aware suggestions.

Understanding Runtime Errors

When faced with errors that you have never seen before in your code, a common reaction would be to hit Google and spend the next chunk of your time surfing through forums and guides to try and find a specific answer for something like the following:

Uncaught TypeError: Cannot read property 'value' of undefined.

Rather than spending your time frantically searching the web, a simple prompt can provide everything you would need for the most part.

Providing Context-Aware Suggestions

The other way in which I’ve been able to get help from ChatGPT for debugging is through its context-aware suggestions for errors. Traditionally, even though we may find the answers for what our program’s bugs are online, it is oftentimes difficult to put the errors and solutions into context.

Here is how ChatGPT handles both of these scenarios with a simple prompt.

Prompt: I found the error “Uncaught TypeError: Cannot read property value of undefined.” in my Python code. How do I resolve it?

With this, I have been able to cut out a lot of time that I would have been spending surfing for answers and turn that time into producing error-free code. While you still have to have good knowledge in knowing how to implement these fixes, using AI as a supplementary tool in your debugging arsenal can provide a huge boost in your programming productivity.

Understanding Long Documentation

Another fantastic way to use AI tools to your advantage is by streamlining long documentation into digestible information that comes when having to use APIs or libraries. As a Natural Language Processing model, this is where ChatGPT excels.

Imagine you’re working on a new web development project, but want to use Flask for the first time. Traditionally, you might spend hours scrolling through pages of dense documentation from Flask, trying to find the precise information you need.

With a tool like ChatGPT, you’ll be able to streamline this problem and save an immense amount of time in the following ways:

  • Generate concise summaries
    You’ll be able to automatically summarize long code documentation, making it easier to quickly understand the key points without having to read through the entire document.
  • Answer specific questions
    ChatGPT can answer specific questions about the code documentation, allowing you to quickly find the information you need without having to search through the entire document.
  • Explain technical terms
    If you are having trouble understanding some terms in the documentation, rather than navigating back to extensive forum threads, ChatGPT can explain technical terms in simple language, making it easier for non-technical team members to understand the code documentation.
  • Provide examples
    Similarly to debugging, you can get relatable examples for each code concept in the documentation, making it easier for you to understand how the code works and how you can apply it to your own projects.
  • Generate code snippets
    ChatGPT can generate code snippets based on the code documentation, allowing you to experiment with use cases and tailor the examples to your specific needs.

It’s like having a search engine that can understand the context of your query and provide the most relevant information. You’ll no longer be bogged down by pages of text, and you can focus on writing and testing your code. Personally, I have been able to blast through numerous libraries, understand and apply them for my own needs in a fraction of the time I normally would.

Developer Testing

Developer testing is one of the cornerstone skills that a programmer or developer must have in order to create bulletproof programs and applications. However, even for experienced programmers, a common problem in developer testing is that you won’t know what you don’t know.

What that means is that in your created test cases, you might miss certain aspects of your program or application that could go unnoticed until it reaches a larger audience. Oftentimes, to avoid that scenario, we could spend hours on end trying to bulletproof our code to ensure that it covers all its bases.

However, this is a great way that I’ve been able to incorporate AI into my workflow as well.

Having AI suggest tests that cover all edge cases is a great way to provide an objective and well-rounded testing phase for your projects.

It also does so in a fraction of the time you would spend.

For example, you are working on the same product landing page for your programming book from earlier. Now, I’ve created a proper product page that involves a form with the following fields for you to process:

script.js

// Get references to the form elements.
const form = document.getElementById("payment-form");
const cardNumber = document.getElementById("card-number");
const expiryDate = document.getElementById("expiry-date");
const cvv = document.getElementById("cvv");
const submitButton = document.getElementById("submit-button");

// Handle form submission.
form.addEventListener("submit", (event) => {
  event.preventDefault();

  // Disable the submit button to prevent multiple submissions.
  submitButton.disabled = true;

  // Create an object to hold the form data.
  const formData = {
    cardNumber: cardNumber.value,
    expiryDate: expiryDate.value,
    cvv: cvv.value,
  };

  // Perform client-side validation on the form data
  if (!validateFormData(formData)) {
    // If the data is invalid, re-enable the submit button and return
    submitButton.disabled = false;
    return;
  }

  // Send the form data to the server.
  // The following is just an example and should not be used in a real-world scenario
  // as it lacks security measures and proper payment gateway integration.
  fetch("/charge", {
    method: "POST",
    body: JSON.stringify(formData),
    headers: {
      "Content-Type": "application/json",
    },
  })
    .then((response) => response.json())
    .then((data) => {
      // Handle the server response.
      if (data.success) {
        // Payment was successful.
        alert("Payment successful!");
      } else {
        // Payment failed.
        alert("Payment failed. Please try again.");
        submitButton.disabled = false;
      }
    })
    .catch((error) => {
      console.error(error);
      alert("An error occurred. Please try again.");
      submitButton.disabled = false;
    });
});

// Perform client-side validation on the form data.
function validateFormData(data) {
  // Example validation checks.
  if (!data.cardNumber || data.cardNumber.length !== 16) {
    alert("Please enter a valid card number.");
    return false;
  }
  if (!data.expiryDate || data.expiryDate.length !== 5) {
    alert("Please enter a valid expiry date in the format MM/YY.");
    return false;
  }
  if (!data.cvv || data.cvv.length !== 3) {
    alert("Please enter a valid CVV.");
    return false;
  }
  return true;
}

Knowing that there are many invalid inputs that customers might use, you want to create some test cases to validate your form’s functionalities. Rather than spending copious amounts of time coming up with numerous test cases, let’s let AI identify any edge cases we missed to bulletproof our tests.

Prompt: Can you help to come up with some edge cases to ensure that the form does not accept any invalid inputs in collecting payment details?

test.js

// Test Case 1: Check if form doesn't submit when fields are empty.
document.querySelector("form").addEventListener("submit", function(e) {
  e.preventDefault();
  var name = document.querySelector("input[name='name']").value;
  var address = document.querySelector("input[name='address']").value;
  var cardNumber = document.querySelector("input[name='card-number']").value;
  var expiryDate = document.querySelector("input[name='expiry-date']").value;
  var cvv = document.querySelector("input[name='cvv']").value;

  if (!name || !address || !cardNumber || !expiryDate || !cvv) {
    alert("All fields are required");
    return;
  }

  // Check if all the fields contain valid inputs.
  if (!validateName(name) || !validateAddress(address) || !validateCardNumber(cardNumber) || !validateExpiryDate(expiryDate) || !validateCVV(cvv)) {
    return;
  }

  // Continue with payment processing.
});

// Test Case 2: Check if name input is valid.
function validateName(name) {
  var nameRegEx = /^[a-zA-Z ]+$/;
  if (!nameRegEx.test(name)) {
    alert("Invalid name. Please enter a valid name");
    return false;
  }
  return true;
}

// Test Case 3: Check if address input is valid.
function validateAddress(address) {
  var addressRegEx = /^[a-zA-Z0-9\s,'-]*$/;
  if (!addressRegEx.test(address)) {
    alert("Invalid address. Please enter a valid address");
    return false;
  }
  return true;
}

// Test Case 4: Check if card number input is valid.
function validateCardNumber(cardNumber) {
  var cardNumberRegEx = /^\d{16}$/;
  if (!cardNumberRegEx.test(cardNumber)) {
    alert("Invalid card number. Please enter a valid card number");
    return false;
  }
  return true;
}

The need to create all sorts of test cases, which is usually a daunting and repetitive task, after a while of working on the same project, can make programming feel very menial. However, with the assistance of AI, this process can be streamlined and, at the same time, improved to cover more bases in your developer testing.

Code Optimization

As it stands, AI still has a long way to go in helping to optimize code and can’t actually do the optimization itself. However, it can still help to provide some useful insights and give some pointers to improving your programming. Here are the most common ways that I have used ChatGPT in optimizing my code for performance:

  • Code Suggestions
    Most simply, it can suggest code snippets or alternative solutions to improve the performance of your existing code.
  • Best Practices
    Having been trained on a wide range of code patterns, ChatGPT can help you follow best practices for coding and software design, leading to more efficient and optimized code.
  • Refactoring
    It helps to reorganize existing code to improve its efficiency and maintainability without affecting its functionality.
  • Knowledge Sharing
    There are many scenarios where your code can be implemented simply through a single import or with other programming languages, libraries, and frameworks. ChatGPT’s suggestions help ensure you are making informed decisions on the best implementations for your needs.

Of course, the bulk of these still requires you to optimize your code manually. However, using AI to gain insights and suggestions for this can be a great way to improve your productivity and produce higher-quality code.

AI Is Amazing, But It Does Have Its Limitations

Now that we have seen what AI can do for you and your programming productivity, I would imagine you are bubbling with ideas on how you are going to start implementing these in your programming workflows.

However, it is essential to keep in mind that these models are fairly new and still have a long way to go regarding reliability and accuracy. These are just some of the limitations that AI, specifically, ChatGPT, has:

  • Limited Understanding
    AI algorithms like ChatGPT have a limited understanding of code and may not fully understand the implications and trade-offs of certain programming decisions.
  • Training Data Limitations
    The quality and relevance of AI algorithms’ output depend on the quality and scope of the training data. For example, ChatGPT was only trained on data dating to 2021. Any updates in programming languages since then may not be reflected.
  • Bias
    AI algorithms can be biased towards specific patterns or solutions based on the data they were trained on, leading to suboptimal or incorrect code suggestions.
  • Lack of Context
    AI algorithms may struggle to understand the context and the desired outcome of a specific coding task, leading to generic or irrelevant advice. While this can be minimized with specific prompts, it is still difficult to generate solutions to more complicated problems.

Nevertheless, these limitations are a small price for the multitude of benefits that AI tools provide. While I am an advocate of using AI to boost your programming productivity, keeping in mind these limitations are crucial when using AI in your workflows as it is important to ensure that the information or code you are producing is reliable, especially if you are using it in a professional setting.

With the current limitations, AI should only be used as a means to assist your current skills, not to replace them. Hence, with that in mind, use it tactfully and sparingly to achieve a good balance in boosting your productivity but not detracting from your skills as a programmer.

How Else Will AI Improve Programmers’ Lives?

While I have mainly talked about the technical aspects of programming that AI can help in, there are many other areas where AI can help to make your life as a programmer much easier.

We are just at the tip of the iceberg in this incoming wave of AI. Many new use cases for AI appear every day with the potential to improve programmers’ lives even further. In the future, we are likely to see many new integrations of AI in many of our daily software uses as programmers.

There already exists general writing software, which could be useful for programmers in creating code and API documentation. These have been around for a while and have become widely accepted as a tool that helps, not replaces.

General productivity and notetaking tools that use AI have also been a big hit, especially for programming students who have to plow through large amounts of information every day. All in all, where there is a labor-intensive task that can be resolved, AI will likely be making headway in those areas.

Wrapping Up

To wrap things up, I will end with a reminder from the opening of this guide. I believe that there is massive potential in becoming well-versed with AI, not as a means to replace our work, but as a means to improve it.

With the right knowledge of what you can and, more importantly, cannot do, AI can be an extremely valuable skill to have in your programming arsenal and will undoubtedly save you copious amounts of time if used correctly.

Hence, rather than fearing the incoming wave of new AI technology, I encourage you to embrace it. Take the knowledge you have learned from the guide and tailor it to your own needs and uses. Every programmer’s workflows are different, but with the right principles and a good knowledge of the limitations of AI, the benefits are equally available to everyone.

So all that’s left for you to do is to reap the supersized benefits that come with integrating AI into your current workflows and see your programming productivity skyrocket as it has for me. And if there’s one thing to remember, it’s to use AI as your assistant, not your replacement.

]]>
hello@smashingmagazine.com (Shane Duggan)
<![CDATA[The Safest Way To Hide Your API Keys When Using React]]> https://smashingmagazine.com/2023/05/safest-way-hide-api-keys-react/ https://smashingmagazine.com/2023/05/safest-way-hide-api-keys-react/ Mon, 08 May 2023 13:00:00 GMT Back in the day, developers had to write all sorts of custom code to get different applications to communicate with each other. But, these days, Application Programming Interfaces (APIs) make it so much easier. APIs provide you with everything you need to interact with different applications smoothly and efficiently, most commonly where one application requests data from the other application.

While APIs offer numerous benefits, they also present a significant risk to your application security. That is why it is essential to learn about their vulnerabilities and how to protect them. In this article, we’ll delve into the wonderful world of API keys, discuss why you should protect your API keys, and look at the best ways to do so when using React.

What Are API Keys?

If you recently signed up for an API, you will get an API key. Think of API keys as secret passwords that prove to the provider that it is you or your app that’s attempting to access the API. While some APIs are free, others charge a cost for access, and because most API keys have zero expiration date, it is frightening not to be concerned about the safety of your keys.

Why Do API Keys Need To Be Protected?

Protecting your API keys is crucial for guaranteeing the security and integrity of your application. Here are some reasons why you ought to guard your API keys:

  • To prevent unauthorized API requests.
    If someone obtains your API key, they can use it to make unauthorized requests, which could have serious ramifications, especially if your API contains sensitive data.
  • Financial insecurity.
    Some APIs come with a financial cost. And if someone gains access to your API key and exceeds your budget requests, you may be stuck with a hefty bill which could cost you a ton and jeopardize your financial stability.
  • Data theft, manipulation, or deletion.
    If a malicious person obtains access to your API key, they may steal, manipulate, delete, or use your data for their purposes.
Best Practices For Hiding API Keys In A React Application

Now that you understand why API keys must be protected, let’s take a look at some methods for hiding API keys and how to integrate them into your React application.

Environment Variables

Environment variables (env) are used to store information about the environment in which a program is running. It enables you to hide sensitive data from your application code, such as API keys, tokens, passwords, and just any other data you’d like to keep hidden from the public.

One of the most popular env packages you can use in your React application to hide sensitive data is the dotenv package. To get started:

  1. Navigate to your react application directory and run the command below.
    npm install dotenv --save
    
  2. Outside of the src folder in your project root directory, create a new file called .env.

  3. In your .env file, add the API key and its corresponding value in the following format:
    // for CRA applications
    REACT_APP_API_KEY = A1234567890B0987654321C ------ correct
    
    // for Vite applications
    VITE_SOME_KEY = 12345GATGAT34562CDRSCEEG3T  ------ correct
    
  4. Save the .env file and avoid sharing it publicly or committing it to version control.
  5. You can now use the env object to access your environment variables in your React application.
    // for CRA applications
    'X-RapidAPI-Key':process.env.REACT_APP_API_KEY
    // for Vite  applications
    'X-RapidAPI-Key':import.meta.env.VITE_SOME_KEY
    
  6. Restart your application for the changes to take effect.

However, running your project on your local computer is only the beginning. At some point, you may need to upload your code to GitHub, which could potentially expose your .env file. So what to do then? You can consider using the .gitignore file to hide it.

The .gitignore File

The .gitignore file is a text file that instructs Git to ignore files that have not yet been added to the repository when it’s pushed to the repo. To do this, add the .env to the .gitignore file before moving forward to staging your commits and pushing your code to GitHub.

// .gitignore
# dependencies
/node_modules
/.pnp
.pnp.js

# api keys
.env

Keep in mind that at any time you decide to host your projects using any hosting platforms, like Vercel or Netlify, you are to provide your environment variables in your project settings and, soon after, redeploy your app to view the changes.

Back-end Proxy Server

While environment variables can be an excellent way to protect your API keys, remember that they can still be compromised. Your keys can still be stolen if an attacker inspects your bundled code in the browser. So, what then can you do? Use a back-end proxy server.

A back-end proxy server acts as an intermediary between your client application and your server application. Instead of directly accessing the API from the front end, the front end sends a request to the back-end proxy server; the proxy server then retrieves the API key and makes the request to the API. Once the response is received, it removes the API key before returning the response to the front end. This way, your API key will never appear in your front-end code, and no one will be able to steal your API key by inspecting your code. Great! Now let’s take a look at how we can go about this:

  1. Install necessary packages.
    To get started, you need to install some packages such as Express, CORS, Axios, and Nodemon. To do this, navigate to the directory containing your React project and execute the following command:
    npm install express cors axios nodemon
    
  2. Create a back-end server file.
    In your project root directory, outside your src folder, create a JavaScript file that will contain all of your requests to the API.

  3. Initialize dependencies and set up an endpoint.
    In your backend server file, initialize the installed dependencies and set up an endpoint that will make a GET request to the third-party API and return the response data on the listened port. Here is an example code snippet:
    // defining the server port
    const port = 5000
    
    // initializing installed dependencies
    const express = require('express')
    require('dotenv').config()
    const axios = require('axios')
    const app = express()
    const cors = require('cors')
    app.use(cors())
    
    // listening for port 5000
    app.listen(5000, ()=> console.log(Server is running on ${port} ))
    
    // API request
    app.get('/', (req,res)=>{
    const options = { method: 'GET', url: 'https://wft-geo-db.p.rapidapi.com/v1/geo/adminDivisions', headers: { 'X-RapidAPI-Key':process.env.REACT_APP_API_KEY, 'X-RapidAPI-Host': 'wft-geo-db.p.rapidapi.com' } }; axios.request(options).then(function (response) { res.json(response.data); }).catch(function (error) { console.error(error); }); }
  4. Add a script tag in your package.json file that will run the back-end proxy server.

  5. Kickstart the back-end server by running the command below and then, in this case, navigate to localhost:5000.
    npm run start:backend
    
  6. Make a request to the backend server (http://localhost:5000/) from the front end instead of directly to the API endpoint. Here’s an illustration:
    import axios from "axios";
    import {useState, useEffect} from "react"
    
    function App() {
    
      const [data, setData] = useState(null)
    
      useEffect(()=>{
        const options = {
          method: 'GET',
          url: "http://localhost:5000",
        }
        axios.request(options)
        .then(function (response) {
            setData(response.data.data)
        })
        .catch(function (error) {
            console.error(error);
        })
    }, []) console.log(data) return ( <main className="App"> <h1>How to Create a Backend Proxy Server for Your API Keys</h1> {data && data.map((result)=>( <section key ={result.id}> <h4>Name:{result.name}</h4> <p>Population:{result.population}</p> <p>Region:{result.region}</p> <p>Latitude:{result.latitude}</p> <p>Longitude:{result.longitude}</p> </section> ))} </main> ) } export default App;

Okay, there you have it! By following these steps, you'll be able to hide your API keys using a back-end proxy server in your React application.

Key Management Service

Even though environment variables and the back-end proxy server allow you to safely hide your API keys online, you are still not completely safe. You may have friends or foes around you who can access your computer and steal your API key. That is why data encryption is essential.

With a key management service provider, you can encrypt, use, and manage your API keys. There are tons of key management services that you can integrate into your React application, but to keep things simple, I will only mention a few:

  • AWS Secrets Manager
    The AWS Secrets Manager is a secret management service provided by Amazon Web Services. It enables you to store and retrieve secrets such as database credentials, API keys, and other sensitive information programmatically via API calls to the AWS Secret Manager service. There are a ton of resources that can get you started in no time.
  • Google Cloud Secret Manager
    The Google Cloud Secret Manager is a key management service provided and fully managed by the Google Cloud Platform. It is capable of storing, managing, and accessing sensitive data such as API keys, passwords, and certificates. The best part is that it seamlessly integrates with Google’s back-end-as-a-service features, making it an excellent choice for any developer looking for an easy solution.
  • Azure Key Vault
    The Azure Key Vault is a cloud-based service provided by Microsoft Azure that allows you to seamlessly store and manage a variety of secrets, including passwords, API keys, database connection strings, and other sensitive data that you don’t want to expose directly in your application code.

There are more key management services available, and you can choose to go with any of the ones mentioned above. But if you want to go with a service that wasn’t mentioned, that’s perfectly fine as well.

Tips For Ensuring Security For Your API Keys

You have everything you need to keep your API keys and data secure. So, if you have existing projects in which you have accidentally exposed your API keys, don’t worry; I've put together some handy tips to help you identify and fix flaws in your React application codebase:

  1. Review your existing codebase and identify any hardcoded API key that needs to be hidden.
  2. Use environment variables with .gitignore to securely store your API keys. This will help to prevent accidental exposure of your keys and enable easier management across different environments.
  3. To add an extra layer of security, consider using a back-end proxy server to protect your API keys, and, for advanced security needs, a key management tool would do the job.
Conclusion

Awesome! You can now protect your API keys in React like a pro and be confident that your application data is safe and secure. Whether you use environment variables, a back-end proxy server, or a key management tool, they will keep your API keys safe from prying eyes.

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Jessica Joseph)
<![CDATA[Learning JavaScript With Imagination]]> https://smashingmagazine.com/2023/05/learning-javascript-with-imagination/ https://smashingmagazine.com/2023/05/learning-javascript-with-imagination/ Fri, 05 May 2023 09:00:00 GMT Many years ago, I set my sights on becoming a senior developer. I achieved that goal! I wish I could say it was a matter of hard work and perseverance, but no, that wasn’t enough. JavaScript stood in my way, and it was while grappling with it that I came across one silly sentence in Marijn Habernecker’s classic book, Eloquent JavaScript. On the topic of variables, it says:

“You should imagine bindings as tentacles rather than boxes. They do not contain values; they grasp them — two bindings can refer to the same value.”

— Marijn Habernecker

An analogy like this falls into the category of childish comparisons meant mostly for raw beginners to understand basic concepts. They are fun and entertaining but not something that will turn you into a senior developer.

But it struck me. Even in a small way, this childish metaphor made me a better developer. It fixed a fundamental misunderstanding: we don’t put values in variables. If variables did behave like buckets or containers, how could this be true?

const count1 = 10;
const count2 = count1;

How is it possible to have the same 10 value in two different buckets? The same thing can’t be in two places at the same time, right?!

But the octopus metaphor solved this dilemma for me. Two tentacles can certainly grab the same value! It’s a visualization that reveals the underlying nature of values! Give me all of the world’s computer science literature on variables at my fingertips, and it would not be as useful to me as this imaginary octopus.

Why can’t all of JavaScript be like this?

My Search For More Visual Learning Material

I noticed a frustrating gap between doing the simple loop and function exercises you find in most beginner courses and actually building programs.

The problem? I still wasn’t at the level where I could decipher reams of dry technical text. I wanted more octopuses!

So, I looked everywhere for them. I scanned the internet for visual and abstract learning resources: Google, YouTube, Medium, TikTok, and every book I could possibly find. I discovered most “visual learning” material fits into one of three groups.

First is a gamified learning experience, like the learn-while-playing platforms CodeCombat and ElevatorSaga. While wonderfully creative and full of stories and characters that help you build real programs with real-world patterns, this type of learning is procedural. The focus is on using concepts rather than diving into what they are.

The second group is the graphically represented syntax or technical explanation. Ever seen an array of apple and orange emojis? Or diagrams of the event loop? These can break down scary concepts into an easier-to-digest visual medium. They can be powerful visual aids that transform dense technical jargon. Examples include Lydia Hallie’s brilliant “JavaScript Visualized” series as well as cheat sheets like this one from Ram Maheshwari.

The third group is closer to what I sought: the analogy-driven learning experience. Developers love a good analogy. We use them all the time in blog posts and video tutorials. They help explain very technical concepts. One resource I found, CodeAnalogies, is particularly impressive, with analogies for everything from content distribution networks to MVC frameworks.

But analogy-driven learning has limitations for me. All of the analogies were disconnected! They had no relation to one another. They were great for wrapping my head around an isolated topic but not for seeing the big picture. The thing with JavaScript is that everything is connected. How can a newspaper analogy for objects be extended to describe prototypal inheritance?

Finally, I came to realize the thing I wanted most was something memorable. I wanted to consolidate everything I was learning into a visual format that was easy to recall when I needed it — whether in an interview or while writing code. Unfortunately, most analogies are entirely forgettable. How many dog, cat, and banana arrays can one take?

Building My Own Visual Representations

There was only one solution to this: create my own visual representations for my JavaScript knowledge tree. But first, I needed to figure out how to make something stick in my memory.

I’ve always had an interest in mnemonic memory methods. These are memory “hacks,” such as the “memory palace”. They help visually encode large amounts of information for easier recall. World memory competitors use it to remember the order of multiple decks of cards and random number sequences.

The basic principle is this: You can take any idea and turn it into an image. For example, an array could be an ocean stingray. That’s good, but still not enough. The trick is to make the mental image as weird, funny, and ridiculous as possible. Images that are out of the ordinary are what stick to memory.

My First Big Lesson

So, here is one of my very first mnemonic representations of JavaScript arrays:

I was so proud of this. We have a stingray street vendor selling fruit, reminding me that arrays hold data. He has a special square device for picking up individual items that represent the square bracket syntax for selecting items. He has a monocle to remind me that arrays have methods for searching. He has a cowboy lasso that refers to loops, and so on.

It’s a fun depiction. But I was trying to learn JavaScript to land a job! If this ridiculous monocled stingray didn’t make me a better developer, it defeated the purpose. The ultimate test: would I use this image of an array streetseller as a point of reference while coding? Nope. It turned out to be entirely, utterly useless.

I didn’t need a way to remember the term array. Knowing they have methods to search does not tell me how I can perform searches. Even a Swiss Army knife tail with all the main array methods like .sort(), .push(), and .unshift() proved pointless with a two-second Google search.

This was trickier than I thought. I learned my first big lesson:

We can’t learn a programming language using pure mnemonic methods because memorizing the lists of things does not help you understand the underlying concepts.

My Second Big Lesson

After much reflection and many, many more failed attempts, I tried to represent something I had always struggled with: functions. What would the makeup of a function look like? I came up with this pretty poor representation:

At the top, we have silly paratroopers that represent parameters. We send parameters through the entrance, ( ), and they end up in a contained pool (i.e., the function body). They start arguing, and that’s how we can remember arguments.

Unfortunately, this went into the failure bucket, too. Representing syntax isn’t helpful. It’s better to gain familiarity through lots of practice writing it. There were also dangerous flaws in the analogy. It suggested parameters and arguments are the same; the only difference is their place.

An abstraction like this with flawed theory baked into it would actually make me a worse developer! I needed to dig deeper into what things really are.

The Breakthrough

The solution was to go atomic. Focusing on the smallest concept would give me the first layer I could use to paint a picture of JavaScript. I circled back to our friendly octopus, where this all began.

What were the tentacles grasping? Values!

Values are often glossed over and don’t seem like the key to unlocking the mysteries of JavaScript. But this simple idea was a breakthrough for me: if the code flows, we can imagine the flowing as an ocean or river. What do we find in this flow? Islands!

Values are the islands, and each island has a set location and size. That was it! It was exactly what I was looking for. It still didn’t improve my skills as a developer. But I knew it had potential.

From Analogies To Models

Layer upon layer, I began to build up a vision of JavaScript by focusing on what things are and how they are related to other things. First came islands. Then came genies, evil sorcerers, flying ships, and turtle pilots. My excitement grew as the smaller layers, the fundamentals, could be combined to produce a big-picture understanding of more complex topics like closures.

Each image was not a simple analogy. It was a mental model — a way of thinking. It provided a lens to interpret each concept but required imagination. I call them imagimodels.

I knew from my past attempts that focusing on lists is ineffective. The secret lies in what things are rather than what they do. When I think about it, that was my problem with learning JavaScript all along. I had no issue eventually getting something to work. The problem was I mostly didn’t have the faintest idea why.

Growing A Memorable, Multi-Layered Universe

With this approach, an abstracted world of JavaScript was erected:

This image helps me identify fundamental JavaScript concepts for assignment, local scope, and primitive values. Of course, it is not a standalone image, and you won’t be able to identify these concepts without context. It requires a story to weave JavaScript and analogy together.

A narrative is what drove the other concepts into the picture, quite literally. Here, we can see a closure:

The next image uses mnemonic methods for remembering useful terminology. Unlike arrays and parameters, “execution context” felt like something I would read in an IBM manual from the 1970s. It was a scary term that deserved a scary representation.

I found a connection between “execution context” and the phrase “executor got hex,” which inspired an illustration of a medieval-style executioner holding an axe in one hand and a hex, or sorcerer’s spell, in the other.

Why the spell? It’s not random. It builds on previous existing layers representing other sub-concepts. The spell is tied to our understanding of a function invocation and makes you think of wizards and sorcerers, right? And it is the parenthesis in every function call.

This begs the question, what is a function? Is it the result of the hex or the execution? Is it the invocation itself? Only a firm understanding of objects would help me identify what really is going on here.

As you can see, the visual layers build upon one another, like a tree with a central trunk branching out in different directions. It’s the knowledge tree I wanted — not one containing every detail about JavaScript, but a central, unified mnemonic resource that could be compared and evaluated against, added to, argued over, and above all, retrieved when I needed it.

I call my illustrations of JavaScript concepts “The Great Sync”, and I use them to continue to grow my understanding. It is also something I now use to teach others.

A Celebration Of Alternative Learning Approaches

Was it all sunshine and daisies for my JavaScript learning journey from this point on? Did building this world make me ace every JavaScript quiz I needed to pass to get that senior-level job?

Nope! I wish the best of luck to anyone who thinks they can learn JavaScript simply by looking at a few pictures.

My biggest takeaway from all my learning efforts is this: Despite The Great Sync solving so many of my personal struggles with the language, is it any better than any single one of the resources I mentioned? Does it have any use without actual coding — the tireless, painful process of trying to get your code to work? Certainly not.

It is one tool, among many, to “see” JavaScript differently and escape the confinement of a code editor or YouTube tutorial.

All of these approaches celebrate the variety and infinite creative potential of the learning experience. And the more we have, the more learners who are stuck on JavaScript can discover new routes to understanding.

Further Reading on Smashing Magazine

]]>
hello@smashingmagazine.com (Kylo Robinson)
<![CDATA[The Growing Need For Effective Password Management]]> https://smashingmagazine.com/2023/05/effective-password-management/ https://smashingmagazine.com/2023/05/effective-password-management/ Thu, 04 May 2023 12:00:00 GMT This article is a sponsored by Passwork

As businesses rely more on digital services and platforms, the number of passwords and access credentials employees need to remember has grown exponentially. This can lead to the use of weak or duplicated passwords, posing a significant security risk. A centralized and secure password management system is essential for mitigating these risks and ensuring that sensitive information remains protected.

Self-Hosted vs. Cloud-Based Password Management Solutions

When it comes to password management solutions, businesses have two primary options: self-hosted and cloud-based. While both have their merits, self-hosted solutions often provide a higher level of control and customization.

Advantages Of Self-Hosted Solutions

  • Greater control
    A self-hosted solution allows administrators to have complete control over the password management infrastructure, enabling them to customize it according to their company’s needs;
  • Enhanced security
    By hosting the password management system on the company’s own servers, businesses can ensure that their sensitive data remains within their control, reducing the risks associated with third-party providers;
  • Compliance
    Self-hosted solutions make it easier for companies to meet industry-specific compliance requirements and data protection regulations.

Limitations Of Cloud-Based Solutions

  • Dependency on third-party providers
    With cloud-based solutions, businesses rely on external providers for the security and availability of their data. This can lead to potential vulnerabilities and the risk of data breaches;
  • Limited customisation
    Cloud-based solutions often have predefined features and settings, which may not align with a company’s unique requirements.
Collaborative Password Management In Companies

In a company setting, employees often need to share passwords and access credentials for various applications and services. A collaborative password management system enables the secure sharing of these credentials, improving productivity and security.

Secure Sharing

Collaborative password management systems, like Passwork, provide secure sharing options, allowing employees to share access credentials with colleagues without exposing sensitive data to unauthorized users. This is the kind of feature that a company needs for frictionless sharing in a collaborative environment, but without exposing sensitive information as you might through another platform, like email. This way, sharing happens securely through the password app’s service.

Permission Management

To maintain control over who can access and modify shared passwords, a collaborative password management system should offer granular permission management. Administrators can assign different levels of access to individual users or groups, ensuring that employees have access to the information they need without compromising security.

Another benefit of permission management is that it provides you with an easy path to knowing who has access to certain information, as well as an easy way to assign and revoke permissions on an individual and group level.

Version Control

Have you ever created a new password for a service, then needed to reference the past password? There’s nothing worse than losing a password when you need it in a pinch, and in an environment where multiple users can update and modify shared passwords, version control becomes essential. Collaborative password management systems should provide a history of changes made to shared credentials, enabling administrators to track modifications and revert to previous versions if needed.

Access Rights Segregation

To ensure that sensitive data remains protected, companies should implement access rights segregation within their password management system. This involves dividing users into different groups based on their roles and responsibilities and assigning appropriate access permissions accordingly.

Role-Based Access Control (RBAC)

RBAC is a widely used method for implementing access rights segregation. With RBAC, administrators can create roles that represent different job functions within the company and assign appropriate permissions to each role. Users are then assigned to roles, ensuring that they only have access to the information they need to perform their tasks.

Attribute-Based Access Control (ABAC)

ABAC is a more flexible approach to access control, where permissions are granted based on a user’s attributes (e.g., job title, department, location, and so on) rather than predefined roles. This allows for greater customization and scalability, as administrators can create complex access rules that adapt to changing business requirements.

Auditing And Monitoring Activity

To maintain a secure password management system, administrators must be able to monitor and audit user activity. This sort of transparency allows you to know exactly who changed something at a particular point in time so you can take corrective action. This includes tracking changes to passwords, monitoring access attempts, and identifying potential security threats.

Activity Logging

A comprehensive password management system should log all user activity, including access attempts, password modifications, and sharing events. This information can be invaluable for detecting unauthorized access, troubleshooting issues, and conducting security audits.

For example, it’s nice to have a way to see who has used a particular password and when they used it, especially for troubleshooting permissions.

Real-Time Notifications

In addition to logging activity, real-time alerts can help administrators quickly identify and respond to potential security threats. A password management system that provides real-time notifications for suspicious activity, such as multiple failed login attempts or unauthorized password changes, can be instrumental in preventing data breaches.

Reporting

Generating reports on user activity, password strength, and compliance can help administrators assess the overall health of their password management system and identify areas for improvement. Regularly reviewing these reports can also ensure that the company remains compliant with relevant industry regulations and best practices.

Best Practices For Implementing A Password Management System

To ensure the success of a password management system, it’s crucial to follow best practices for implementation and ongoing maintenance. You want to ensure that your passwords are managed in a way that is safe for everyone in your company while adhering to compliance guidelines for a secure environment.

First, Choose The Right Solution

Selecting the right password management system for your company is essential. Consider factors such as the size of your organization, the level of customization required, and your preferred hosting option (self-hosted vs. cloud-based) when evaluating solutions. Passwork, for example, offers a self-hosted solution with robust collaboration features, making it a suitable option for businesses looking for greater control and customization.

Next, Train Employees

Employee training is crucial for the successful adoption of a password management system. Ensure that all users understand how to use the system, the importance of password security, and company policies related to password management.

Regularly Review And Update Policies

As your business evolves, your password management policies should adapt accordingly. Regularly review and update your policies to ensure that they continue to meet your organization’s needs and maintain compliance with industry regulations.

Monitor And Audit System Activity

Stay vigilant by regularly monitoring and auditing your password management system. This will help you identify potential security threats and ensure that your system remains secure and up-to-date.

Password Policy Best Practices

To maintain a secure password management system, it’s essential to establish strong password policies and ensure that employees follow best practices.

Password Length And Complexity

A strong password policy should require a minimum password length and a combination of characters, including upper and lower case letters, numbers, and special characters. This helps to increase password entropy, making it more difficult for attackers to guess or crack passwords using brute force methods.

Password Expiration And Rotation

Regularly changing passwords can help to minimise the risk of unauthorized access, especially in cases where passwords have been compromised without the knowledge of the organization. Implementing a password expiration policy that requires users to change their passwords at regular intervals can enhance security.

Two-Factor Authentication (2FA)

In addition to strong password policies, implementing two-factor authentication can provide an additional layer of security. By requiring users to provide a second form of verification, such as a code sent to a mobile device, 2FA reduces the risk of unauthorized access even if a password is compromised.

Prevent Reused Passwords

Employees should be discouraged from using the same password across multiple accounts and services. Encourage the use of unique passwords for each account to minimise the risk of unauthorized access in case one password is compromised.

Integrations And Compatibility

An effective password management system should be compatible with various platforms, applications, and services that your company uses. This ensures seamless integration and streamlined access management.

Single Sign-On (SSO)

SSO enables users to access multiple applications and services with a single set of credentials.

By integrating your password management system with SSO, you can simplify the login process for employees, reducing the need for multiple passwords and improving security.

Browser Extensions and Mobile Apps

A password management system that offers browser extensions and mobile apps can help ensure that employees have access to their passwords and credentials wherever they are. This enhances productivity and encourages the adoption of the password management system.

Custom Integrations

Depending on your company’s requirements, you may need to integrate your password management system with other tools, such as ticketing systems, customer relationship management platforms, or identity and access management solutions. Ensure that the password management system you choose is flexible and allows for custom integrations. Make sure that the password management system you decide to use has the flexibility to connect with the other services you rely on for your business.

Backup And Disaster Recovery

A robust password management system should include backup and disaster recovery features to ensure the availability and integrity of your organization’s passwords and credentials.

Regular Backups

Implement a backup policy that includes regular backups of your password management system’s data. This helps to protect against data loss due to hardware failures, accidental deletions, or other unforeseen issues.

Encrypted Backups

Backups should be encrypted to protect the sensitive data they contain. Ensure that your password management system supports encrypted backups and uses strong encryption algorithms to safeguard your data.

Disaster Recovery Plan

Develop a disaster recovery plan that outlines the steps to be taken in case of a system failure, data breach, or other security incidents. This plan should include procedures for restoring data from backups, as well as measures to prevent further damage or unauthorized access.

Evaluating And Selecting A Password Management Solution

When choosing a password management system, it’s important to thoroughly evaluate potential solutions and select the one that best meets your organization’s needs.

Security Features

Assess the security features offered by each solution, such as encryption algorithms, two-factor authentication support, and activity monitoring capabilities. Ensure that the solution adheres to industry standards and best practices for data security.

Scalability

Consider the scalability of the password management system, especially if your organization is growing or has plans for expansion. The solution should be able to handle an increasing number of users and passwords without compromising performance or security.

Ease of Use

User adoption is crucial for the success of a password management system. Evaluate the user interface and overall ease of use of each solution, as this can have a significant impact on employee adoption and satisfaction.

Cost

Consider the total cost of ownership for each password management system, including initial implementation costs, ongoing maintenance, and any additional fees for upgrades or add-on features. Be sure to weigh these costs against the potential benefits and savings offered by a more secure and efficient password management process.

Ongoing Maintenance And Support

Once your password management system is in place, it’s essential to keep it up-to-date and ensure that users receive the necessary support.

Software Updates

Regularly update your password management system to benefit from the latest security patches, feature enhancements, and bug fixes. This helps to maintain the stability and security of the system.

User Support

Provide user support for your password management system, including training materials, FAQs, and access to technical assistance when needed. This ensures that employees can effectively use the system and resolve any issues that may arise.

Periodic Security Assessments

Conduct periodic security assessments of your password management system to identify any potential vulnerabilities and ensure that it continues to meet your organization’s security requirements. This may include penetration testing, vulnerability scanning, and other security assessments.

Conclusion

Organizing password management in a company is a critical task for system administrators. By selecting the right solution, implementing access rights segregation, fostering collaboration, and actively monitoring and auditing the system, administrators can create a secure and efficient password management environment. Additionally, establishing strong password policies, ensuring like Passwork, can offer businesses greater control and customization, providing a solid foundation for effective password management.

By following the best practices outlined in this guide, system administrators can enhance their organization’s overall security posture while improving productivity and streamlining access management.

]]>
hello@smashingmagazine.com (Iliya Garakh)
<![CDATA[Smashing Podcast Episode 60 With Mei Zhang: How Do You Design A Design Process?]]> https://smashingmagazine.com/2023/05/smashing-podcast-episode-60/ https://smashingmagazine.com/2023/05/smashing-podcast-episode-60/ Tue, 02 May 2023 12:00:00 GMT We’re talking about the process of design. How do you build a process to enable your best work? Vitaly Friedman talks to designer Mei Zhang to find out.

Show Notes

Weekly Update

Transcript

Vitaly Friedman: She’s a senior UX designer and a UX consultant with a strong product and strategy background. As a kid, she was busy creating arts and fell in love with UX while studying industrial design in college. She has spent her career developing design systems and solving problems for e-commerce products that are loved by millions of people around the world. Now, she also loves helping designers uncover root causes, explore multiple directions, and identify sweet spots between user and business.

Vitaly: She’s currently working with Booking.com and resides in Amsterdam, Netherlands. Of course, she is a cat person, as it often is in the Smashing Podcast. And in her spare time, she can be found painting, skiing, serving her cats — there are a couple — writing on her design blog and learning about design, business, leadership and management. We know she’s a wonderful UX designer, but did you know that she used to swim in order to participate in the Olympics? That was one of her dreams, which unfortunately didn’t come true. However, help her have a lung capacity of over 5,000, which is a big deal. My Smashing friends, please welcome Mei Zhang. Hello, Mei. How are you feeling today?

Mei Zhang: Hello. Hi, everyone. I’m smashing.

Vitaly: Oh, that’s wonderful to hear. How are you? Is it cold out there in Amsterdam these days or is it sunny?

Mei: Luckily, it was sunny in the couple of days. In the past couple of days.

Vitaly: So, it’s better. I have to ask this story. Swimming in the Olympics. Why did you decide to do this? Because I guess you were playing with design and UX already at this point. Or was it before or prior to design?

Mei: Oh.

Vitaly: Why did you decide to take on this challenge?

Mei: It was definitely before the design career. I was in my elementary school and I fall in love with swimming. And as a ambitious little girl who want to have some targets. So I need to compete for the Olympics because this is something very challenging. But unfortunately, I didn’t go through the competition. But I think it definitely gave me something, make me a stronger person. Not only physically, but also mentally. So I really appreciated that.

Vitaly: I have no doubt at all. We’ll probably bring up — I’ll probably bring up this question about how it in the end influenced your UX and design career. But maybe before we dive into that. And maybe you could share a story about how did you even end up in this design and UX world? Maybe you could share a bit about your journey and what brought you where you are today.

Mei: I think what brought me where I am today is the iPhone 4. I got iPhone 4 as a gift at the first year of my college and then I get to learn about human-computer interaction which published by Apple. And another fun fact, the human-computer interaction guidelines are already there in 1987. That is what I remember. Whoa, it’s a long history of something that I have never heard about. I start studying basically X design by myself. I just genuinely really interested in the fancy interactions at that time. What CSS can do for you.

Mei: I was also a Smashing Magazine fan. I follow all your articles and try to do something with CSS and JavaScript. And I think also during my study, people start discussing about what you want as a career after graduation, what industry you would like to join. I was lost at that time, but I know I love UX design and I’m good at it because all my school project was related somehow to human-computer interaction. And, I think, at that time, the IT industry also was booming because people started having Facebook. I think that somehow made me feel like maybe that is something that has a future. So, that is basically my journey into UX design.

Vitaly: But then, you ended up where you are here today. And you have all this. I always reminded of all this UX methodologists and methods and all the ways. And you have created these incredible mind maps as well. But all the things that you potentially need to keep in mind as a UX designer when you are working on a product or on a project. And maybe before we dive there, maybe we could speak a bit more particularly about breaking complexity into something that’s more manageable.

Vitaly: I know that you’ve been working or you are working on relatively or quite complex products. And again, just given this huge amount of all the different methods and options available to you as a UX designer, how do you choose your path? Or specifically, maybe, how do you start when you have a really complex. Maybe an enterprise product or maybe B2B or maybe anything that’s complicated and you need to break it down. How do you do that? What would be your process? And maybe also, your methods to make sense of it all?

Mei: Such a great question. I would guess the first step is always find what is the real problem. What we are designing for. To deep dive into the problems and find the root cause. That is definitely the first step I would choose because the problems also help the designers or people around you to define the process because with different problems you might need different methodologies. And also, the second step will also be identifying the stakeholders. As you mentioned, you have people around you who are genuinely interested or who are in charge of the project. Identify the people around you and what they need.

Mei: The outcome is not only the end product that deliver to the users, but also to. Let’s say it in the simple way. Make your stakeholders happy. I think those are the two basic principles for navigating through what methodologies that I pick. And also, you need to look at availabilities as well. That is, usually happens in the real life work. Maybe for example, you don’t have data for some project. But also, it’s impossible to collect that. Maybe you need to find another method that could answer the same questions that is available.

Vitaly: But then I’m also wondering: you also mentioned data. I’m actually quite wondering because I feel like very often, I end up in this dilemma with teams I’m working with. Where there is a person or there is a team, they have a very strong design vision. This is how it should be. It’s usually based on research and usually going to be very much focused on user needs or customer needs. A very customer-centric view. But then sometimes, it clashes against the business idea of how things should be and the business direction of where the company wants to go. And sometimes, I feel that there is this really strong tension between where the designer wants to go and what the, let’s say, A/B testing tells.

Vitaly: And maybe, testing is such a short-term thing. Where you test if it works now and then. It might be a good thing, of course, to improve things and that will drive conversion, though. But where do you see? How do you see this resolving? How do you get to this balance between doing something? Because again, we run A/B tests and this performs better than this. Against the big design, the grandiose, so to say, design vision that exists in designers’ heads based on user needs and based on business needs.

Mei: First of all, I don’t think those two A/B tests. Let’s say A/B testing and a great vision in the designer’s head is something that cannot exist together. I think they can co-exist because A/B testing is just one of methodologies to validate the concept. It’s the small steps to take you towards a big vision. It’s not a easy task, but it’s the designers who need to guide the product managers or guide your team towards the vision. That is actually sometimes underestimated by the outside because we have a lot of things showed to us designers because we are visionaries.

Mei: We have a vision, so we need to take that through. What I usually do is first, definitely have a great relationship with your product managers because you are actually working together as a whole to reach the vision. They are more business of course, and they are more data-driven or metrics-driven. But on the other hand, you are the user advocate. Build a good relationship and trust with your product managers and work together on a daily basis. It shouldn’t be like, "Ah, I don’t agree with you". Or something like this. But more be like, "Let’s sit together and make a great thing or make a great product."

Mei: And I think sometimes, I also feel like it’s really important to have a businessman side as a designer. Especially if you are working for an organization that’s aimed for profit, your responsibility is also to keep the business running. The business goal is also your goal as a designer, as well. Your responsibility is to craft a great user experience that will improve the business or make the business stronger. For example, learn about business metrics, understand the view from the product side. And also, sometimes I find what is helpful for me is to define user behavior metrics because for A/B testing.

Mei: Sometimes you, say that, maybe some business metrics doesn’t increase but the user behavior metrics were improving. You can also use this as a argument to get things through. It’s not only about A/B testing. It has to be improving business. But if you can prove that it’s going to improve the user experience and the user experience can lead into long-term business growth, then that will happen. And also, I think what I’m doing very often in the past is also to break the vision into smaller pieces that is experimentable.

Mei: In this case, it’s also help as a designer to validate your ideas. I know we are all, as a designer, we’re all proud of our ideas and we believe that’s going to work. And most of the time, of course it’s going to work, but we also need to use data and argument to support our ideas. I would say it is something. It definitely bring a lot of positive side from A/B testing to build a vision.

Vitaly: The reason why I brought this up actually because I’m just coming from a project where this has become a big issue. Where essentially, it seems like there is this very strong tension between, again, the ideas of we need to do something now and drive conversion up now. But again, we also need to think about the long-term goals. And very often, what happens is you might be improving things by showing a new set of popup very prominent and then a bit more prominent, then a bit more flashy and then even more flashy. But then it’s actually going to hurt your long-term goals. I actually want to maybe dig a little bit deeper. When you speak about user behavior metrics or any ways to capture the quality of the design work basically done. Could you maybe share a few of them that would be most important in your work?

Mei: I’m thinking about something related to the example you just gave about the flashing popup. One example I can think of right now is that, in the past, I also had experience where the product was pushing for metrics. They’re making things rainbowy or flashy. I think definitely what helped was to conduct user interviews to understand what is user’s point of view of that. They’ll be like, "Oh, I think this brand was just to trick me." They also understand the black UX part or the bad. Sorry. The bad UX pattern that try to trick them into something.

Mei: And also, something help me as well is to look into the long-term user flow because they tend to only focus on one metrics and improve that. But have you looked through the whole flow? Maybe the click rate went up, but in the end, less people are converting. Then you cannot say that this is a good solution. You just. Try to find different metrics that can, to build your argument with the product. And also, try to, in your daily basis, try to make your product manager or your product colleagues to more understand what is a good user experience.

Mei: Because I work with all kinds of product managers and some are like you mentioned in that case. Really focusing on one metrics and don’t care the UI. And there are also product managers who really understand what is UX experience. I want to do something good for the long run. Try to also influence your product managers to understand what is good for the long run. Because in the end, someone has to clean up the bad UX in the end because that will lead into something in the future.

Vitaly: Absolutely. I think it also heavily depends on the culture that the company has, the organization has and how the teams are organized. And sometimes, you see that there are. Whenever everything is siloed, you will end up in the situation where a silo would have very specific goals and they don’t even know what the other teams are doing. Or how their things that they may be performing or they’re working on in the vertical effect everyone else. This is more probably a slightly broader question in there, as well.

Vitaly: Maybe you could also share a bit of insight about some of the really complex challenges that you are facing at this moment. And something that you’re working on that, I would say, keep you awake at night. Hopefully not, but maybe there are some things. Just get sense about what you’re working on as well at the moment.

Mei: I couldn’t share details of product strategy with you inside.

Vitaly: Sure.

Mei: Because of the NDA stuff with my current employer, but I will say, the current challenge definitely about how to level up your people skills and communications as a designer through your career. Because I’m running a very big project right now. Basically, more than 30 stakeholders on the play. I really need to learn connecting people. How I can connect with people first by establishing yourself with your activities in your field. And also, to connect people and find the right person for the right question.

Mei: And also, at this point, you need to try to work through other people. I don’t know how to put it in the beautiful way, but more enable others to contribute to the project. In this sense, you need to really articulate the project and the impact of this project. So you can onboard people and to create a win-win situation where they can learn something from the project or they can do product improvement in their services, project as well — so if they would like to be onboarded and work with you.

Mei: Think that was about communication, connecting the people. But the most challenging part is leading the whole project. You need to be super organized, which I was not that great before. You need to have a roadmap of this project and keep updating this every day. So you can visualize what is going on. What are the updates, and also identify the key stakeholder for each phase of the project, of the activities. And how to communicate with them. And you need to visualize them, document them to help you organize the whole project. I guess that was the most challenging part for me.

Vitaly: That doesn’t sound like a lot of moving pixels around in Figma, though.

Mei: Which, I actually missed that part as well. I’m not sure if this is a common case, but I guess so. When you are running a big project where we are not in the phase of creating new ideas and Figma files. It’s more communicating, documenting, pitching or about the project.

Vitaly: This is just a normal state of things, I guess, all the time. Guess I become this person who would move away from, well, sketch at the time and Figma to spreadsheets. I don’t know. Much of my life these days is basically organizing things and also documents in Dropbox Paper or Google Doc. Just organizing things in a way that’s available, accessible to everyone else. It also goes, for example, for organizing meetings. I actually decided to take a design approach to design the best meetings experience. And this is really difficult, I think.

Vitaly: In general, processes which involve people be hard, of course. I’m also just curious about your take on the process because I know that you. Meetings including, for example. Because I know that you often say that you need to design your design process. And this is, very much plays. It’s a melody, beautiful melody to my ears because this is what I’ve been doing to some degree, I guess, for the last couple of years. I’m wondering though, how do you mean that? We’re designing the process. We need to figure out the right way of working for us, for the team, as well.

Vitaly: How do we design meetings? How do we? Do we do stand-ups? Do we do written stand-ups? When do we do retros? How often do we do this and that? Maybe you could share a few things that tend to work better for you that you learned working well. And something that you definitely advise as a consultant, as well, companies do really stay away from when it comes to design process.

Mei: I can quickly tell what companies should stay away for, in terms of a design process.

Vitaly: Sure.

Mei: Is to, for the sake of having a design process, to have a design process. Regardless of what problem you are trying to solve. I still remember in my career there was a company who really want to have a persona. I’m like, "Why we are going to create the personas?" They were like, "Oh, because everybody’s having a personas for this project and it’s a key important deliverable for understanding our customers. So we need this persona." So I’m like, "But do you have any?" I trying to explain persona is more you need to conduct interviews.

Mei: You need to gather datas and then you come up with someone that represents the key problems or key pain point of your customers. It’s not like you just create a persona out of a workshop with some people, internal colleagues of your company. So they’re like, "Oh, okay. Then we need to gather data or we need to have a lot of insight of the persona." But we couldn’t because they don’t have infrastructure to try user behavior. So I’m like, "No worries, just interview eight customers. It’s a good number. And try to find what are the common pain point or what’s a common desire or need they have? And then you have a persona."

Mei: That is something I learned through my career. Oh, you shouldn’t just say, "Oh, this thing looks fancy, the personas or something else. Oh, customer journey map, we need that." It’s not what you’re trying to understand and what do you have. And based on those two aspect, to try to find a methodology that really serve your needs or can help you move forward. This is definitely not advised for people or company. I think what I definitely enjoyed is to design, as you mentioned, design your own design process. Because when I was studying UX design, we have this design thinking process and everyone tried to follow.

Mei: Define a problem and try to understand and create something, iterate. I was also one of them trying, really into that. But then, when I start working I found, this is not always the case. You need to find what is the most important phase of the project. For example, if you are tackling a very complex problem and you don’t even understand what exact problem it is, then you need to spend a lot of effort in defining the problem phase. Or if it is a project really focused on deliverables, we need to shape a marketing video or we need to shape the design within two weeks. Then, maybe you need to spend more energy in the executing phase of the design.

Mei: While we are working, it’s very hard to have everything. To have a very complete design process where you have a solid deliverables for every phases. But you need to figure out which phase is the most important based on the needs and the problem and try to shift your energy there. But that doesn’t mean that you should skip some process. You can still have them, but it’s more trying to say what you have already have and not create new words on there. I think that’s what I learned from design your own design process.

Vitaly: That’s fine. You also, I always keep coming back to this. I don’t even know why. But I always feel that many of the colleagues I’m speaking to, they’re always just don’t even know how to navigate that space of UX methods and models and process. And sometimes, it feels like there is this huge amount of all these different things that very different companies are doing. And they’re inventing for themselves or using some of their other established, already established methods. Luckily, and fortunately for all of us, you have created two mind maps. Which I found really useful to be able to navigate the space in a bit more predictable way. Maybe you could tell a bit more about this and how it helps you in your work.

Mei: A very good question. At the beginning, I was just writing them down for myself. It’s more like library where what is available there and you can grab them as a building block to build up your own design process. But it’s not like something can mapped out the how of those design process and those methodologies and what it can bring. What I’m trying to say is to be flexible about your design process. To not just see the articles and I need this and this in exploration phase. But maybe you don’t need it based on your problem or what you are trying to design. Try to be flexible.

Mei: And also, I will say sometimes it’s more of the experience you get. When you are first time. For example, if you are conducting a user interview at first time or maybe you are doing a survey first time. It’s more you start learning how this methodology work and how you can improve based on the methodology. But then, as you try multiple methodologies in your career, you can reflect on. Well, this can help and what do I need to conduct this methodology? And then if you keep reflecting on them, it will help you in the future to decide, do I need this methodology in my design process? Will this fit the timeline? Will this fit the requirements? Will this be the best methodology to answer the business questions?

Mei: Then you start reflecting and then you can say, "Then, I don’t need this. Oh, I really need this methodology." It’s more, if you haven’t had a lot of experience, try to try them out. Even if you are not working or you are just doing an internship. But try things out to understand how those methodology work. And then, later on, you can. You get a next experience, then you can decide when to use what. So that would be my take.

Vitaly: That’s interesting because I think that to many of us, it’s... I don’t know... Many companies have the process. This is the process that they’re following through. It doesn’t matter what department. Doesn’t matter what their designers are working on. There is the process. This is how we work here kind of thing. And what I’m hearing from you is that basically you might need to be adaptive there. So if you are, say, switching from one design team that you’re working with or another team that maybe have different experience.

Vitaly: Maybe have different preferences. Maybe most of them are working remote. Maybe most of them are hybrid in one way or the other. So adjusting the methodology and the process based on the team that you have. The only thing that’s required there to get it right and to do it well is to know and be comfortable with the different techniques and different methods that are out there. Does that make sense? Is that pretty much what you do?

Mei: Yes, thanks. Yeah, definitely. That is a very great summary of what I just said.

Vitaly: But I think it is also very interesting because it can be quite challenging. Do you find yourself sometimes maybe stuck because you have a particular way of approaching a particular problem with the design team? But then you might have very different levels of experience on the team? You might feel like we need to do something because we might not be able to get things done in time. Or we are not moving along fast enough and I need to switch gears and move something to another methods.

Vitaly: The reason why I’m asking or what I’m asking here is that not only do we need to be able to switch and be adaptive moving from one team to another in your process. But also, as the process is in place, do you feel like sometimes you need to shift gears and change things and plug in something else because what you have is not working?

Mei: Yeah, definitely. I think a very great question. This is a daily life of designer, I guess.

Vitaly: The sad life of a designer, isn’t it?

Mei: Yeah, the sad. We have a dream design process defined before project or before we start working on something and maybe one month later something changed. Then you need to be flexible and adapt to it. We decided to collect user data because the PM was super into quantitative data and we need that. But our source was not available at that time. So we need to really think about, what can we do? Because we are not going to run the survey anymore as a design team or. What I did, I think it’s a really good step. I was also not super experienced at time. I’m the newbie in the company.

Mei: I bring this to the design team. So I never feel shy that if I couldn’t solve them myself, I should consult with other colleague. Then we start doing some root analysis. Why we need this survey? Because we want to discover problems. We don’t have a clear problem. We want to discover the problem. Then do something to also discover the problems without the researcher that can help us send the survey. Then we said, "Maybe we can do a diary study with UserTesting.com. We can set this up together."

Mei: So we did, in the end, a diary study. Those two methodologies actually serve the same purpose in the end. I guess you need to shift when you can, I think, maybe try to have another methodology that can give you the same insight or maybe. Also sometimes, just trust your gut feelings.

Vitaly: Sure.

Mei: If some data is not available, you can validate them later.

Vitaly: That’s right. But Mei, I have to ask a very provoking question at this point. And I’m sure that some of the listeners listening here will be, "What is this? What is he asking?" I do have to ask, do you think that chaos could also be a process? The reason why I’m asking is if you have a relatively small team. Imagine you have maybe two, three designers. You do not have this. And surely, we need to have research. We need to use some methods to make things work. Sometimes, you see companies trying to over organize things.

Vitaly: If you have a team of two or three, do you need daily stand-ups? Doesn’t seem necessary because people are there in the room talking all the time, anyway. It’s not like you have this big organization where you have five departments all doing different pieces and all that. Sometimes, I see companies feeling very comfortable in being extremely unorganized. Being chaotic. Not even having proper documentation and nothing. Obviously, the problem is that you actually end up with the knowledge being stuck with these people. If somebody leaves, that’s obviously an issue. Onboarding is a problem. But they feel like you can be very productive and very successful without having a proper process and pretty much a chaotic environment.

Mei: To be honest, I have to say that I agree with you.

Vitaly: Oh.

Mei: I think to not have a well established progress or being chaotic may be the norm for designers. Because we are creative beings. Sometimes, you get ideas or you discover something just randomly while understanding your customers, users. But I would say totally agree with you. If you have a small team and you are working very closely on a daily basis, you might not need to follow a design process super strictly. It’s more like, "we are in the understanding phase, then what can we do?" And we discuss together. It’s more like you just need the rough framework to guide you through. And the iteration will also be very fast-paced. You don’t need to go through everything then iterate again. Totally agree with. Another point, I feel like the design process is sometimes also more for the non-designers. Your product stakeholders in the organization or people who are not in your project or another designer who don’t have any background knowledge. It’s more for them to help to organize your self-process or just it’s for your own deliverable. Your ideas that work. To have it to communicate to the outside. That is what I have to say.

Vitaly: That makes perfect sense. Well, as we’re wrapping up here, I do have to ask you of course. But this is a question that I’m asking everyone and I’m really curious about your answer as well. Do you have a particular dream project? A really complicated challenge? A really complicated UX? I don’t know. Monolithic challenge that is probably so hard that it’s pretty, almost impossible to think about it? Just to give you an idea, some of my colleagues when trying to answer this question, they start thinking about, "Oh, I would love to design some, I don’t know. A deck or I don’t know. A control center for Rocket Science Center or anything like that."

Vitaly: Some other would say, "I just want to be able to work with United Nations." It goes really different ways. I’m just curious, do you have a particular dream project or dream task maybe or dream challenge that you would love to tackle one day?

Mei: I will say, I will go for the second direction. I really want to work for the sustainability topic or some project for NGOs because I have been spending my career working for E-commerce company. I really want to contribute to some non-profit organizations that, for example, sustainability or a turtles saving organization. I think what I can help them is my experience in E-commerce to convert people. Maybe I can convert more people doing the good stuff. That would be something I’d definitely love to work on in the future.

Vitaly: Maybe just totally ruining the arc, the story arc of the podcast. I do have to hook onto the thing that you mentioned about E-commerce because I’m just really curious. I spent quite a bit of time around E-commerce as well. Maybe you could share a few stories about things that you learned by working in E-commerce. Thing that’s how customers think or some important things to keep in mind when it comes to E-commerce UX in general.

Mei: I think what I have learned is your customers are smarter than you thought. That is what I have learned. Sometimes, you try to trick them. Sorry. Another dark part in UX I’m talking about. You think you can convert them somehow, but actually they know. They know what you are doing. It’s not the customer of 10 years ago on the E-commerce platform compared to right now. They’re very press sensitive. They compare with multiple competitors. They compare and they make the right decision for them. And that is also related to what we talk in the beginning of the podcast.

Mei: You have to focus on the long run to create a great experience for the long run. To bring them benefit in the long run because they understand everything. And you cannot. If you got them converted once, you might not get them converted the second time and they might leave you if they have really bad experience. I think right now the E-commerce world is really competitive, but also that is good for the customers because they have multiple choices and then they have learned everything. I think that is what I have learned from the E-commerce experience. The customers, they also grow as you grow.

Vitaly: We’ve been learning about UX and design today, but if there is one thing that I do have to ask, Mei because I know that Mei is very much interested in the something that maybe bothers or excites or inspires all of us. Who knows? I know that you’ve been playing with ChatGPT and AI in general, Mei. Do you see? I don’t know. Do you see this wonderful tool, AI as an opponent to us? Something that we need to fight or something that we’re going to embed in our daily workflow and just make the best use of it? How do you use AI today?

Mei: Very good questions. I think, we should see AI as our friends. We’re holding hands together.

Vitaly: Good friends.

Mei: And help us.

Vitaly: The best friends or?

Mei: Good friend.

Vitaly: Good friends.

Mei: Good friends for now before they replace our job, which will happen, I guess. Recently, I started using ChatGPT to write write documentations or write presentations for me. It’s still, you need to write down, get the key point and then ChatGPT will help you generate a good sentence. It saves your time as a designer. You could spend more time in Figma or creating new ideas or creating something or dreaming vision for your company for the coming three years. I think definitely AI saves our time and make sure we can concentrate on works that requires more creativity.

Vitaly: But I do have to ask a follow-up question. Do you think, Mei, that AI is creative?

Mei: I think, to some extent. They are creative based on basically data and stuff that already exist or they could find on the internet. But they might not be able to dream further. Maybe predict human in 10 years. But I’m not sure. I’m not a expert in AI. I would say they are creative to some extent, but it’s also up to us to think about, do we want them to be creative or not?

Vitaly: That’s a good question. Maybe, we can resolve this issue once and for good once we ask ChatGPT if it thinks it is creative. And if so, then it should better prove it to us. Well, if you, dear listener, would like to hear more from Mei, you can find her LinkedIn where she’s at, Mei Zhang, and also Medium. Medium.com/ThisisMei, if I’m not mistaken. Well, thank you so much for joining us today, Mei. Do you have any parting words of wisdom to the future generations who are going to listen to this very podcast 25 years from now thinking, "What are they talking about? Everything is AI anyway now."

Mei: What I want to share is definitely know AI is something not new, but something innovative in our generation right now. Designers are using ChatGPT to create their daily slides. But I would like to talk to the future generations to maybe being creative or follow your intuitations is something that cannot be replaced by AI. I think I really treasure. I think designers should be really treasured because we have the power that might not be able to replace by any machines and stuff because we are human. We are caring and we are always creative and we can connect the dots. That is something you should develop or treasure as a skill. I think that is something I would like to tell to the future generations.

]]>
hello@smashingmagazine.com (Drew McLellan)
<![CDATA[Make Your May Magnificent (2023 Wallpapers Edition)]]> https://smashingmagazine.com/2023/04/desktop-wallpaper-calendars-may-2023/ https://smashingmagazine.com/2023/04/desktop-wallpaper-calendars-may-2023/ Sun, 30 Apr 2023 15:00:00 GMT Let’s welcome May with some new wallpapers! For over twelve years, we’ve challenged you, our dear readers, to create wallpaper calendars for our monthly wallpapers posts. No matter if you’re into lettering, illustration, or photography, the series is the perfect opportunity to create a small artwork and share it with people from all around the world — to brighten up someone’s day, cater for some fresh inspiration, or to put your creative skills to the test. Of course, it wasn’t any different this time around.

In this collection, you’ll find desktop and mobile wallpapers for May 2023, created with love by artists and designers who took on the challenge. They all come in versions with and without a calendar and can be downloaded for free. As a little bonus goodie, we also compiled a selection of timeless May favorites from our archives at the end of this post. Thank you to everyone who tickled their ideas and shared their designs with us this month! Happy May!

  • You can click on every image to see a larger preview,
  • 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 a wallpaper!
    Did you know that you could get featured in our next wallpapers post, too? We are always looking for creative talent.
The Mushroom Band

“My daughter asked me to draw a band of mushrooms. Here it is!” — Designed by Vlad Gerasimov from Georgia.

ARRR2-D2

Designed by Ricardo Gimenes from Sweden.

Blast Off!

“Calling all space cadets, it’s time to celebrate National Astronaut Day! Today we honor the fearless explorers who venture beyond our planet and boldly go where no one has gone before.” — Designed by PopArt Studio from Serbia.

May Your May Be Magnificent

“May should be as bright and colorful as this calendar! That’s why our designers chose these juicy colors. We also have other options in our selection of May calendars.” — Designed by MasterBundles from Ukraine.

Chill Out

“Summer chill is a relaxed and carefree vibe that is often associated with the summer season. It is a time when people slow down and enjoy the warm weather. The atmosphere is laid-back and easy-going, with a focus on having fun and creating happy memories.” — Designed by Kasturi Palmal from India.

Moving Montains

“The month of May is a moving moment. I’m only writing this to set attention to the letter ‘M’! The ‘M’ inspired me, and my idea for the wallpaper was to make mountains, smooth mountains, of course.” — Designed by Philippe Brouard from France.

Think Outside The Fox

Designed by Ricardo Gimenes from Sweden.

Casablanca Style

“We spent spring in Casablanca. Enjoying the sunset while admiring the Hassan II Mosque.” — Designed by Veronica Valenzuela from Spain.

Me, Myself, And I

“The wallpaper is a reflection on Francisco Goya’s The Third of May, 1808, a painting with a powerful anti-war statement.” — Designed by Bhabna Basak from India.

Stop Child Labor

“Children should have the opportunity to learn, play, and grow in a safe environment and not be forced to work at a young age. As individuals, we can also make a difference by supporting companies that have strict policies against child labor and by raising awareness about this issue in our communities. By working together, we can help to create a world where every child has the opportunity to reach their full potential, free from the burden of labor. So I designed this wallpaper to raise my voice about this issue. Hope you like it!” — Designed by Hrishikesh Shome from India.

Oldies But Goodies

From bold to delicate, from minimalist to funny, below you’ll find some May favorites from our archives that are just too good to be forgotten. Which one is yours? (Please note that these wallpapers don’t come with a calendar.)

Hello May

“The longing for warmth, flowers in bloom, and new beginnings is finally over as we welcome the month of May. From celebrating nature on the days of turtles and birds to marking the days of our favorite wine and macarons, the historical celebrations of the International Workers’ Day, Cinco de Mayo, and Victory Day, to the unforgettable ‘May the Fourth be with you’. May is a time of celebration — so make every May day count!” — Designed by PopArt Studio from Serbia.

The Monolith

Designed by Ricardo Gimenes from Sweden.

Blooming May

“In spring, especially in May, we all want bright colors and lightness, which was not there in winter. Our designers decided to convey these feelings in the May calendar.” — Designed by MasterBundles from Ukraine.

Understand Yourself

“Sunsets in May are the best way to understand who you are and where you are heading. Let’s think more!” — Designed by Igor Izhik from Canada.

Poppies Paradise

Designed by Nathalie Ouederni from France.

Lake Deck

“I wanted to make a big painterly vista with some mountains and a deck and such.” — Designed by Mike Healy from Australia.

Today, Yesterday, Or Tomorrow

Designed by Alma Hoffmann from the United States.

April Showers Bring Magnolia Flowers

“April and May are usually when everything starts to bloom, especially the magnolia trees. I live in an area where there are many and when the wind blows, the petals make it look like snow is falling.” — Designed by Sarah Masucci from the United States.

Spring Gracefulness

“We don’t usually count the breaths we take, but observing nature in May, we can’t count our breaths being taken away.” — Designed by Ana Masnikosa from Belgrade, Serbia.

Make A Wish

Designed by Julia Versinina from Chicago, USA.

All Is Possible In May

“Edwin Way Teale once said that ‘[t]he world’s favorite season is the spring. All things seem possible in May.’ Now that the entire nature is clothed with grass and branches full of blossoms that will grow into fruit, we cannot help going out and enjoying every scent, every sound, every joyful movement of nature’s creatures. Make this May the best so far!” — Designed by PopArt Studio from Serbia.

Rainy Days

“Winter is nearly here in my part of the world and I think rainy days should be spent at home with a good book!” — Designed by Tazi Design from Australia.

Birds Of May

“Inspired by a little-known ‘holiday’ on May 4th known as ‘Bird Day’. It is the first holiday in the United States celebrating birds. Hurray for birds!” — Designed by Clarity Creative Group from Orlando, FL.

Be On Your Bike!

“May is National Bike Month! So, instead of hopping in your car, grab your bike and go. Our whole family loves that we live in our bike-friendly community. So, bike to work, to school, to the store, or to the park — sometimes it is faster. Not only is it good for the environment, but it is great exercise!” — Designed by Karen Frolo from the United States.

Add Color To Your Life!

“This month is dedicated to flowers, to join us and brighten our days giving a little more color to our daily life.” — Designed by Verónica Valenzuela from Spain.

Always Seek Knowledge

“‘As knowledge increases, wonder deepens.’ (Charles Morgan) So I tried to create an illustration based on this.” — Designed by Bisakha Datta from India.

Welcome May With An Ice Cream!

“May is the last month of spring, the weather is getting hotter every day and it starts to feel almost like summer. So, the best thing to cool ourselves and bring summer closer is to… welcome May with an ice cream!” — Designed by WebOlution from Greece.

Game Boy

Designed by Sander Geenen from Belgium.

Colorful

Designed by <a href=https://www.lotum.de>Lotum from Germany.

<a href=https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/e8daeb22-0fff-4b2a-b51a-2a6202c6e26e/may-12-colorful-31-full.png>

Tentacles

Designed by Julie Lapointe from Canada.

Sweet Lily Of The Valley

“The ‘lily of the valley’ came earlier this year. In France, we celebrate the month of May with this plant.” — Designed by Philippe Brouard from France.

Geo

Designed by Amanda Focht from the United States.

Love Japanese Food

Designed by Ricardo Gimenes from Sweden.

May The Force Be With You

“Yoda is my favorite Star Wars character and ‘may’ has funny double meaning.” — Designed by Antun Hirsman from Croatia.

Enjoy May!

“Springtime, especially Maytime, is my favorite time of the year. And I like popsicles — so it’s obvious isn’t it?” — Designed by Steffen Weiß from Germany.

Celestial Longitude Of 45°

“Lixia is the 7th solar term according to the traditional East Asian calendars, which divide a year into 24 solar terms. It signifies the beginning of summer in East Asian cultures. Usually begins around May 5 and ends around May 21.” — Designed by Hong, Zi-Cing from Taiwan.

]]>
hello@smashingmagazine.com (Cosima Mielke)
<![CDATA[Write Better CSS By Borrowing Ideas From JavaScript Functions]]> https://smashingmagazine.com/2023/04/write-better-css-borrow-ideas-javascript-functions/ https://smashingmagazine.com/2023/04/write-better-css-borrow-ideas-javascript-functions/ Fri, 28 Apr 2023 08:00:00 GMT I like to think of writing CSS, like writing functions that describe how your layouts respond to change. When we forget the principles of writing a good function, here’s some of what can happen:

  • We lose time.
    When we have to worry about side effects, changes take longer.
  • We create bugs.
    My favorite example is an online store where the “Buy” buttons were hidden due to misuse of viewport units.
  • We build fewer features.
    When changes are scary and time-consuming, they often don’t happen.

Let’s look at how we can borrow best practices and ideas from writing good JavaScript functions for writing CSS that is easy to use, free from unwanted side effects, and resilient to change.

Avoiding Unwanted Side Effects

When you change something in your system, it shouldn’t change something else by surprise. That’s as true for CSS as it is for JavaScript functions.

Let’s look at this arrow icon in a circle as an example:

It looks fine, but let’s say we want a narrower arrow icon:

Now the containing circle is squished! This is an example of an unwanted side effect. Using a narrower arrow ruins the shape of the circle.

If we inspect the element in DevTools, we can see that the shape of the containing circle depends on the size of the inner icon and the padding around the icon.

Ideally, the interior icon shouldn’t change the shape of the containing circle. Here’s a demo of how to fix the squished icon:

The CSS sets max-width: 900px on the container, and each card gets a little breathing room with padding: 5vw. This may look fine on the surface, but there’s a problem: the container has an upper bound while the padding doesn’t. As the screen gets wider, the content gets crushed.

See the Pen Example of padding crushing content [forked] by Yaphi.

Possible solutions include:

  • Using viewport or container breakpoints to keep the padding under control,
  • Using the CSS min() function to set an upper bound on the padding, or
  • Using fixed units, such as pixels, that won’t grow indefinitely with the window.

What these solutions have in common is that they account for what happens when the viewport width changes. Similarly, we can avoid many CSS problems by considering the layout as output and anticipating what could happen when the inputs change.

Ahmad Shadeed has a great name for this technique: Defensive CSS. The idea is that we can “future-proof” styles by thinking about them as inputs that output a UI and anticipating situations that would diminish the output’s usability.

Conclusion

Coding a layout isn’t about laying things out on a page but describing how they respond to change. For that reason, it’s risky to treat CSS like constants rather than functions.

Fortunately, the same ideas that help us write good functions can help us write good CSS, namely:

  • Avoid unwanted side effects.
  • Use the right parameters.
  • Consider how inputs change outputs.

What ties these ideas together is a question I hope you’ll ask yourself the next time you write CSS, How should this layout respond to change?

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Yaphi Berhanu)
<![CDATA[Accessible Target Sizes Cheatsheet]]> https://smashingmagazine.com/2023/04/accessible-tap-target-sizes-rage-taps-clicks/ https://smashingmagazine.com/2023/04/accessible-tap-target-sizes-rage-taps-clicks/ Thu, 27 Apr 2023 12:00:00 GMT Rage taps are annoying and frustrating. These wonderful occurrences in our interface when we need to tap twice or sometimes three times to continue our journeys. Of course, sometimes they happen because the website is too slow, but sometimes it’s the target size of interactive elements that is the culprit.

So how big should our interactive elements be these days? What would be a reliable size for icons, links and buttons — in navigation and on mobile? How do we make it more difficult for our users to make mistakes? Let’s take a look.

Note: You can find a whole video chapter on designing for touch in Smart Interface Design Patterns as well — along with 30 other chapters all around UX and design patterns.

Target Sizes Cheatsheet

One of the common recommendations for target sizes on mobile is 44×44px. This is a little bit misleading because screen pixels, or at least device-independent pixels (dips) are scaled to a multiple of the display resolution. So pixels are different on different screens, and when we have a conversation about sizes, we probably should be speaking about dips, rather than pixels.

Depending on where an element appears on the screen, it needs more or less padding. In general, we are very precise in our input in the center of the screen, but we are least precise on the edges of the screen (both on the top and at the bottom).

Accordion to Steven Hoober’s research in his book on Touch Design For Mobile Interfaces, to minimize rage taps, we need to aim for 11mm (or 31pt / 42px) on the top of the screen, and 12mm (or 34pt / 46px) at the bottom of the screen. In the center though, we could potentially go as low as 7mm (or 20pt / 27px). This includes both the width and padding of an interactive element.

How do point units translate to CSS pixels or Android/iOS units? Fortunately, Steven Hoober provides a helpful conversion table to help you translate from points to px and em units, Android SPs or DPs, iOS points and Windows DIP or px.

Not All Pixels Are The Same

As we’ve seen above, target sizes change depending on where components appear on the screen. It’s worth noting that according to the WCAG 2.1 AAA level requirements, all targets should measure at least 44 by 44px, except if the target is in a sentence or block of text. For such exceptions, we could be using 27px as a goal, but in general, the larger, the better.

For sticky menus at the top or bottom of the screen, we should probably aim for around 44–46px boxes, or preferably even more. However, for links that appear on the screen as the user scrolls down the page, we probably will be able to avoid most issues with smaller components.

This is also why we probably will be able to place at most five items in the bottom tabs on a mobile phone. Instead, we might need to use a bottom sheet that would slide up from down as an overlay on top of the screen.

Prefer “Actions” Button To Single Icons For Data Tables

Complex tables typically have hover actions that appear once a user starts hovering over a particular row. They typically include everything from highlight and export to move and delete.

In testing, showing icons on hover produces too many mistakes: not only do users often accidentally jump to a wrong row as they navigate horizontally towards the icons. They also make mistakes by accidentally clicking on the wrong spot and starting all over again.

To avoid rage clicks, it might be a good idea to test how well an “Actions” buttons or a “Split”-Button would perform instead. Indeed, that button could live on every row, would open on tap/click, and wouldn’t close automatically. It might not be ideal for every use case, but it definitely gives users more sense of control as they need to take action in a row.

Provide An Assistant For Complex Manipulations

With complex manipulation, such as rotation of an image, or selection of a small part of a larger area, we often rely on pinch and zoom or zoom in/out buttons. These options, of course, work, but they easily become a bit tedious to use for very precise manipulations — especially if used for a while.

Instead, we can attach a little handle to allow users to move their selection within the object faster and with more precision. This is how Tylko allows users to customize their shelves on mobile. Zooming is supported as well, but it’s not necessary to select one of the areas.

When Multiple Taps Are Better Than One

But what do we do if some tap areas have to be small? Perhaps we can’t reserve 27×27px for each icon — for example, when we suggest a color selection in an eCommerce site? Well, in that case, one option to consider would be to prompt a “proper” selection of colors with one additional tap. This might be a bit slower in interaction, but way more accurate.

Fewer rage clicks: Grønland Color Picker Microinteraction, designed by Mykolas Puodžiūnas. (Large preview) Always Maximize Clickable Area

Whenever possible, encapsulate the entire element, along with enough padding to ensure that you hit the magical 42–46px size to prevent rage taps for good. This typically means adding enough padding for icons but also preferring full-width or full-height bars for accordions and navigation.

Ahmad Shadeed presents a few useful examples of using spacing to increase clickable areas and prevent rage clicks. Any Lupe provides even more suggestions in her article on accessible target sizes.

Wrapping Up

When designing for touch today, we need to use at least 27×27px for small links or icons in the content area and at least 44×44px for icons at the top and at the bottom of the page.

Personally, I would always go up to 30×30px and 48×48px to make sure mistakes are really difficult to make. And, of course, always use full width or full height for the clickable areas. Hopefully, this will help us remove any possible rage taps from our websites altogether — and many of your users will sincerely appreciate it indeed.

You can find more details on navigation UX in the video library on Smart Interface Design Patterns 🍣 — with a live UX training that’s coming up in September this year.

Useful Resources

There are a few wonderful resources on accessible target sizes that might be helpful if you’d like to dive deeper in the topic:

]]>
hello@smashingmagazine.com (Vitaly Friedman)
<![CDATA[The Potentially Dangerous Non-Accessibility Of Cookie Notices]]> https://smashingmagazine.com/2023/04/potentially-dangerous-non-accessibility-cookie-notices/ https://smashingmagazine.com/2023/04/potentially-dangerous-non-accessibility-cookie-notices/ Mon, 24 Apr 2023 08:00:00 GMT No matter what your stance is on them, no matter what your perspective is on data protection, web advertisement, setting cookies, EU’s General Data Protection Regulation (GDPR), and privacy preferences, cookie consent widgets (or “cookie banners”) are a reality on the web today.

For this reason, it is worth looking into how accessible and usable these banners are or can be. They have become, for better or worse, a component of the majority of today’s websites. Even more, cookie banners are often the first thing a user encounters. And, of course, they are part of every site of a webpage once they are implemented.

Sometimes, cookie banners are a technical necessity because of the page’s feature set or because of advertisements on the page. Even more often, cookie banners are not built by the front-end team but are a ready-made solution, like UserCentrics or others.

Before I explain why the cookie banner deserves special attention regarding its accessibility, let’s quickly explain how the current gold standard of web accessibility, Web Content Accessibility Guidelines (WCAG) Version 2.1, works.

WCAG consists of principles, guidelines, and success criteria. The latter are testable steps to check against a webpage. For example:

  • “Is the main language of the document set?”
  • “Does this non-text content have a suitable text alternative?”
  • “Is it perceivable where my focus is when I’m using the web presence with the keyboard (or another tech that emulates keyboard presses)?”

You may have noticed that these are “yes or no” questions. Accordingly, this means that the final verdict of any given success criterion is either “pass” or “fail.”

Additionally, conformance to WCAG, as defined by the W3C (the governing body of the Web), means that none of its success criteria is allowed to “fail” when the whole document needs to be conformant:

“Conformance to a standard means that you meet or satisfy the ‘requirements’ of the standard. In WCAG 2.0, the ‘requirements’ are the Success Criteria. To conform to WCAG 2.0, you need to satisfy the Success Criteria, that is, there is no content which violates the Success Criteria.”

W3C Working Group Note

No nuance here. Going back to our cookie consent interface, this means that the banner (or any other component) alone has the potential to negatively affect the WCAG conformance of an entire web project.

WCAG conformance could be a big legal deal for many websites, whether part of the public sector in the European Union or the United States, as it is considered to fall under non-discrimination or market access laws or overall human rights to access to information. Webpages frequently must adhere to directives and regulations that directly or indirectly refer to WCAG, often its newest version, and conformance to its level AA standards. Therefore, all the following WCAG criteria are viewed through this lens, being fully aware that they are only a mere starting point when it comes to true web accessibility. On top of that, cookie consent interfaces are implemented on every subpage of a website, consequently harming accessibility and conformance throughout an entire website.

So, in order to not let a faulty cookie banner interface drag down your page’s conformance with accessibility laws and, more importantly, not exclude users from accessing and exercising their rights, let’s list what to look for, what to configure, and what to build properly in the first place.

Contrast Errors

This is especially relevant when it comes to important controls such as the setting of cookies or the overall acceptance of the recommended cookie set. It is crucial that form controls and text can be sufficiently perceived. Unsurprisingly, a solid contrast is also important for WCAG in general. Namely, in success criteria 1.4.3 and 1.4.11, both define contrast boundaries.

What To Do

When you are using a ready-made cookie management solution, try to influence the colors (if possible, potentially in your cookie vendor’s settings) and make sure interactive controls have sufficient color contrast.

Additionally, if your website relies on a dedicated contrast mode for WCAG conformance, check whether it extends to (or influences) the cookie management interface. I have seen cases in my accessibility auditor practice where this was not considered, and an inaccessible (often branded) color combination was used in the cookie interface, thinking the contrast mode takes care of every color-related violation. But the contrast setting of the website did not affect the third-party cookie banner due to it being, well, third-party and loaded from external sources or after the contrast mode had done its work, resulting in a “Fail” on WCAG’s contrast-related success criteria.

Pseudo Buttons

Another cookie banner issue can be one thing that is, unfortunately, an error pattern that you can find outside of cookie management: divs or spans with click events posing as links or buttons. These controls may be styled like buttons but lack the semantic information of a button.

On top of that, these controls usually aren’t keyboard focusable. Hence, many serious barriers and WCAG violations are occurring all at once. If we were about to imagine the most “pseudo” button, e.g., a div with a click handler, this would at least violate success criteria 2.1.1 (Keyboard), because it is neither reachable nor “activatable,” and 4.1.2 (Name, Role, Value) because it doesn’t “introduce” itself as a button and lacks a programmatic label.

What To Do

The easiest thing to do, assuming you have built the cookie management interface yourself, is to replace those above-mentioned pseudo buttons with real <button> elements because it provides semantics, focusability, and even keyboard event handlers for free. But even if we don’t talk literally about buttons, the pattern is the same: check your cookie prompt for interactive elements that are built with elements that are only styled to look like “the real thing” but consist of non-semantic divs and spans. This is a red flag for you to implement native interactive elements, like a, button, or input instead.

The situation gets a lot tougher, of course, when these semantic errors are in a third-party script and are, therefore, beyond your direct influence and control. Understandably, we have to leave the engineering side of things and start to dive into politics of some sort. If you work within an organization where the decision of cookie management infrastructure is outside your control, you have to escalate matters to your supervisors and managers (especially, but not only when your web projects have to adhere to accessibility laws).

Three abstract steps have to happen:

  1. Your organization has to become aware of the barrier and potential legal risk — “up” to the powers that have the influence to change technical decisions like these.
  2. As a consequence, the vendor that provided the faulty cookie banner has to be contacted about the issue.
  3. A form of pressure should be applied by your organization — not just for your own sake but also regarding all the other web pages where the faulty cookie banner negatively influences accessibility and conformance.

In a possible fourth step, your company or agency should reflect on its vending process for third-party services and the HTML (and possible barriers) that come with it.

Unlabeled Form Fields

When you think about it, the main user control that one could imagine for cookie management widgets is a form control: You can select which set of cookies you are willing to accept by interacting with checkboxes in a form element. And, of course, it is important that checkbox inputs are built in the correct way.

Alas, that is not always the case. While a checkbox and its label may visually appear adjacent, the checkbox can lack a programmatic label. This adds unnecessary confusion and barriers to the interface and also a failure of success criterion 1.3.1 when you look into the web accessibility standard.

What To Do

The most solid strategy to connect form inputs with their corresponding labels is to:

  1. Use a label element for the label (obviously).
  2. Establish an id on the respective input you want to label.
  3. Add a for attribute, filling it with the control’s id you created in the last step.

This also works for inputs of all types, like textareas and selects. Here’s an example of how a properly labeled checkbox could look:

<input type="checkbox" id="marketing-cookies" />
<label for="marketing-cookies">Accept marketing cookies</label>

If you can’t directly influence the HTML of the cookie banner’s code, the situation is comparable to the situation around pseudo buttons. Make sure that necessary pressure is applied to your cookie service provider to fix the problem. All of their customers will thank you for it, and even more so the people who visit their sites.

Broken Dialog Semantics (Or None At All)

Quite a few cookie banners are actually cookie dialogs, and of the modal kind. Modal, in the context of a dialog, means that such a window blocks everything but itself, leaving only itself accessible. That is, at least, the theory. But quite some cookie management dialogs do “want to be as aggressive,” presenting as a modal part of the interface but have no according semantics and behavior, which would violate WCAG success criterion 4.1.

What To Do

Up until recently, the recommendation was to build a dialog with WAI-ARIA roles and states and implement focus management yourself (or use Kitty Giraudel’s great a11y-dialog) component).

But the situation has (mostly) changed for the better. Lately, the native <dialog> element has matured to the point where it’s being recommended in most contexts as long as it is used reasonably. A great win for accessibility, in my opinion. The past way of building (modal) dialogs had so many moving parts and factors (roles, states, focus behaviors) to think about and implement manually that it was quite difficult to get it right. Now creating a dialog means using an aptly-named HTML element (and initializing it with .showModal() if you think the cookie dialog needs to be interface-blocking).

What I’ve written so far is, of course, also valid when you cannot influence a third party’s code, and what I wrote earlier about comparable situations and potential cookie consent barriers is valid as well. If you detect errors in the third-party script you are implementing (such as no focus trapping, no dialog role, no aria-modal="true" — and if everything else points towards “modalness”), escalate things internally and educate the decision-making powers about web accessibility consequences. Maybe even educate the third-party developers that things concerning modals have gotten a lot better recently.

Cookie Banners Are Hard To Find In The First Place

There are three typical places where you can usually find cookie consent interfaces, at least visually:

  1. As a modal dialog, i.e., in the middle or — more rarely — corners of the viewport;
  2. On top, sometimes in a fixed manner;
  3. At the bottom of the viewport, sometimes also somewhat positioned in a fixed way.

But what matters way more for some people is how easy it is to find, should they go on a hunt for it. A great way of presenting this very problem is a presentation that accessibility specialist Léonie Watson gave some time ago. Léonie is a seasoned screen reader user, and her presentation showcases a bunch of webpages and how the placement and “findability” of cookie banners influence the screen reader experiences, particularly as it is related to privacy. Hampering the ability to find important content in a document can, for example, negatively affect WCAG 1.3.2 (Meaningful Sequence).

What To Do

In Léonie’s presentation, the best practices for cookie notice findability become very clear, especially in the last example:

  • Place the banner preferably at the top of the document.
  • Use a headline in the cookie banner and make it either visible or visually hidden to help screen reader users “get a grasp about the webpage” and allow them to navigate by headings.
  • Build a bridge back to proper dialog semantics by making sure that if a dialog is meant to be the “exclusive” part of the interface, it uses appropriate semantic and state descriptions (see above for details).

When we’re talking about changing third-party code, I reckon you know the drill by now. Try to influence this code indirectly on the “political level” because direct control is not possible.

Conclusion

Hopefully, two things emerged while reading this article:

  1. Awareness of the issue, namely, that an often unloved stepchild interface element has the potential to make it harder for some people to manage their privacy settings and, on top of that, to even pose a legal risk.
  2. A sense of how you can possibly remediate barriers you encounter when working with a cookie management banner. The direct way is described in a certain detail in the details I provided earlier and often has to do with code, styling, or overall education on how to prevent this in the future. The indirect way leads to a path of either setting the consent interface up properly or influencing the inner and outer politics of your vendor scripts. And again, there is the aspect of educating everyone involved. This time, structured information may be aimed at the powers that be in your organization, showing them that their choice of service providers may have unintended consequences.

But regardless of whether you and your team manage to fix accessibility bugs directly or indirectly in your cookie consent interfaces, you can see their ubiquity and component architecture as an advantage. By getting the accessibility right in one place, you influence many other pages (or even foreign websites) for the better.

If you want to extend your horizon regarding the user experience side of cookie banners and learn about how you can actually turn privacy settings into a pleasant and respectful involvement with at least EU laws, please proceed to Vitaly’s smashing read, “Privacy UX: Better Cookie Consent Experiences”.

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Marcus Herrmann)
<![CDATA[Exploring The Potential Of Web Workers For Multithreading On The Web]]> https://smashingmagazine.com/2023/04/potential-web-workers-multithreading-web/ https://smashingmagazine.com/2023/04/potential-web-workers-multithreading-web/ Fri, 21 Apr 2023 10:00:00 GMT Web Workers are a powerful feature of modern web development and were introduced as part of the HTML5 specification in 2009. They were designed to provide a way to execute JavaScript code in the background, separate from the main execution thread of a web page, in order to improve performance and responsiveness.

The main thread is the single execution context that is responsible for rendering the UI, executing JavaScript code, and handling user interactions. In other words, JavaScript is “single-threaded”. This means that any time-consuming task, such as complex calculations or data processing that is executed, would block the main thread and cause the UI to freeze and become unresponsive.

This is where Web Workers come in.

Web Workers were implemented as a way to address this problem by allowing time-consuming tasks to be executed in a separate thread, called a worker thread. This enabled JavaScript code to be executed in the background without blocking the main thread and causing the page to become unresponsive.

Creating a web worker in JavaScript is not much of a complicated task. The following steps provide a starting point for integrating a web worker into your application:

  1. Create a new JavaScript file that contains the code you want to run in the worker thread. This file should not contain any references to the DOM, as it will not have access to it.
  2. In your main JavaScript file, create a new worker object using the Worker constructor. This constructor takes a single argument, which is the URL of the JavaScript file you created in step 1.
    const worker = new Worker('worker.js');
    
  3. Add event listeners to the worker object to handle messages sent between the main thread and the worker thread. The onmessage event handler is used to handle messages sent from the worker thread, while the postMessage method is used to send messages to the worker thread.
    worker.onmessage = function(event) {
      console.log('Worker said: ' + event.data);
    };
    worker.postMessage('Hello, worker!');
    
  4. In your worker JavaScript file, add an event listener to handle messages sent from the main thread using the onmessage property of the self object. You can access the data sent with the message using the event.data property.
    self.onmessage = function(event) {
      console.log('Main thread said: ' + event.data);
      self.postMessage('Hello, main thread!');
    };
    

Now let’s run the web application and test the worker. We should see messages printed to the console indicating that messages were sent and received between the main thread and the worker thread.

One key difference between Web Workers and the main thread is that Web Workers have no access to the DOM or the UI. This means that they cannot directly manipulate the HTML elements on the page or interact with the user.

Web Workers are designed to perform tasks that do not require direct access to the UI, such as data processing, image manipulation, or calculations.

Another important difference is that Web Workers are designed to run in a sandboxed environment, separate from the main thread, which means that they have limited access to system resources and cannot access certain APIs, such as the localStorage or sessionStorage APIs. However, they can communicate with the main thread through a messaging system, allowing data to be exchanged between the two threads.

Importance And Benefits Of Web Workers For Multithreading On The Web

Web Workers provide a way for web developers to achieve multithreading on the web, which is crucial for building high-performance web applications. By enabling time-consuming tasks to be executed in the background, separate from the main thread, Web Workers improve the overall responsiveness of web pages and allow for a more seamless user experience. The following are some of the importance and benefits of Web Workers for multithreading on the Web.

Improved Resource Utilization

By allowing time-consuming tasks to be executed in the background, Web Workers make more efficient use of system resources, enabling faster and more efficient processing of data and improving overall performance. This is especially important for web applications that involve large amounts of data processing or image manipulation, as Web Workers can perform these tasks without impacting the user interface.

Increased Stability And Reliability

By isolating time-consuming tasks in separate worker threads, Web Workers help to prevent crashes and errors that can occur when executing large amounts of code on the main thread. This makes it easier for developers to write stable and reliable web applications, reducing the likelihood of user frustration or loss of data.

Enhanced Security

Web Workers run in a sandboxed environment that is separate from the main thread, which helps to enhance the security of web applications. This isolation prevents malicious code from accessing or modifying data in the main thread or other Web Workers, reducing the risk of data breaches or other security vulnerabilities.

Better Resource Utilization

Web Workers can help to improve resource utilization by freeing up the main thread to handle user input and other tasks while the Web Workers handle time-consuming computations in the background. This can help to improve overall system performance and reduce the likelihood of crashes or errors. Additionally, by leveraging multiple CPU cores, Web Workers can make more efficient use of system resources, enabling faster and more efficient processing of data.

Web Workers also enable better load balancing and scaling of web applications. By allowing tasks to be executed in parallel across multiple worker threads, Web Workers can help distribute the workload evenly across multiple cores or processors, enabling faster and more efficient processing of data. This is particularly important for web applications that experience high traffic or demand, as Web Workers can help to ensure that the application can handle an increased load without impacting performance.

Practical Applications Of Web Workers

Let us explore some of the most common and useful applications of Web Workers. Whether you’re building a complex web application or a simple website, understanding how to leverage Web Workers can help you improve performance and provide a better user experience.

Offloading CPU-Intensive Work

Suppose we have a web application that needs to perform a large, CPU-intensive computation. If we perform this computation in the main thread, the user interface will become unresponsive, and the user experience will suffer. To avoid this, we can use a Web Worker to perform the computation in the background.

// Create a new Web Worker.
const worker = new Worker('worker.js');

// Define a function to handle messages from the worker.
worker.onmessage = function(event) {
  const result = event.data;
  console.log(result);
};

// Send a message to the worker to start the computation.
worker.postMessage({ num: 1000000 });

// In worker.js:

// Define a function to perform the computation.
function compute(num) {
  let sum = 0;
  for (let i = 0; i < num; i++) {
    sum += i;
  }
  return sum;
}

// Define a function to handle messages from the main thread.
onmessage = function(event) {
  const num = event.data.num;
  const result = compute(num);
  postMessage(result);
};

In this example, we create a new Web Worker and define a function to handle messages from the worker. We then send a message to the worker with a parameter (num) that specifies the number of iterations to perform in the computation. The worker receives this message and performs the computation in the background. When the computation is complete, the worker sends a message back to the main thread with the result. The main thread receives this message and logs the result to the console.

This task involves adding up all the numbers from 0 to a given number. While this task is relatively simple and straightforward for small numbers, it can become computationally intensive for very large numbers.

In the example code we used above, we passed the number 1000000 to the compute() function in the Web Worker. This means that the compute function will need to add up all the numbers from 0 to one million. This involves a large number of additional operations and can take a significant amount of time to complete, especially if the code is running on a slower computer or in a browser tab that is already busy with other tasks.

By offloading this task to a Web Worker, the main thread of the application can continue to run smoothly without being blocked by the computationally intensive task. This allows the user interface to remain responsive and ensures that other tasks, such as user input or animations, can be handled without delay.

Handling Network Requests

Let us consider a scenario where a web application needs to initiate a significant number of network requests. Performing these requests within the main thread could cause the user interface to become unresponsive and result in a poor user experience. In order to prevent this issue, we can utilize Web Workers to handle these requests in the background. By doing so, the main thread remains free to execute other tasks while the Web Worker handles the network requests simultaneously, resulting in improved performance and a better user experience.

// Create a new Web Worker.
const worker = new Worker('worker.js');

// Define a function to handle messages from the worker.
worker.onmessage = function(event) {
  const response = event.data;
  console.log(response);
};

// Send a message to the worker to start the requests.
worker.postMessage({ urls: ['https://api.example.com/foo', 'https://api.example.com/bar'] });

// In worker.js:

// Define a function to handle network requests.
function request(url) {
  return fetch(url).then(response => response.json());
}

// Define a function to handle messages from the main thread.
onmessage = async function(event) {
  const urls = event.data.urls;
  const results = await Promise.all(urls.map(request));
  postMessage(results);
};

In this example, we create a new Web Worker and define a function to handle messages from the worker. We then send a message to the worker with an array of URLs to request. The worker receives this message and performs the requests in the background using the fetch API. When all requests are complete, the worker sends a message back to the main thread with the results. The main thread receives this message and logs the results to the console.

Parallel Processing

Suppose we have a web application that needs to perform a large number of independent computations. If we perform these computations in sequence in the main thread, the user interface will become unresponsive, and the user experience will suffer. To avoid this, we can use a Web Worker to perform the computations in parallel.

// Create a new Web Worker.
const worker = new Worker('worker.js');

// Define a function to handle messages from the worker.
worker.onmessage = function(event) {
  const result = event.data;
  console.log(result);
};

// Send a message to the worker to start the computations.
worker.postMessage({ nums: [1000000, 2000000, 3000000] });

// In worker.js:

// Define a function to perform a single computation.
function compute(num) {
  let sum = 0;
  for (let i = 0; i < num; i++) {
    sum += i;
}
  return sum;
}

// Define a function to handle messages from the main thread.
onmessage = function(event) {
  const nums = event.data.nums;
  const results = nums.map(compute);
  postMessage(results);
};

In this example, we create a new Web Worker and define a function to handle messages from the worker. We then send a message to the worker with an array of numbers to compute. The worker receives this message and performs the computations in parallel using the map method. When all computations are complete, the worker sends a message back to the main thread with the results. The main thread receives this message and logs the results to the console.

Limitations And Considerations

Web workers are a powerful tool for improving the performance and responsiveness of web applications, but they also have some limitations and considerations that you should keep in mind when using them. Here are some of the most important ones:

Browser Support

Web workers are supported in all major browsers, including Chrome, Firefox, Safari, and Edge. However, there are still some other browsers that do not support web workers or may have limited support.

For a more extensive look at browser support, see Can I Use.

It is important that you check out the browser support for any feature before using them in production code and test your application thoroughly to ensure compatibility.

Limited Access To The DOM

Web workers run in a separate thread and do not have access to the DOM or other global objects in the main thread. This means you cannot directly manipulate the DOM from a web worker or access global objects like windows or documents.

To work around this limitation, you can use the postMessage method to communicate with the main thread and update the DOM or access global objects indirectly. For example, you can send data to the main thread using postMessage and then update the DOM or global objects in response to the message.

Alternatively, there are some libraries that help solve this issue. For example, the WorkerDOM library enables you to run the DOM in a web worker, allowing for faster page rendering and improved performance.

Communication Overhead

Web workers communicate with the main thread using the postMessage method, and as a result, could introduce communication overhead, which refers to the amount of time and resources required to establish and maintain communication between two or more computing systems, such as between a Web Worker and the main thread in a web application. This could result in a delay in processing messages and potentially slow down the application. To minimize this overhead, you should only send essential data between threads and avoid sending large amounts of data or frequent messages.

Limited Debugging Tools

Debugging Web Workers can be more challenging than debugging code in the main thread, as there are fewer debugging tools available. To make debugging easier, you can use the console API to log messages from the worker thread and use browser developer tools to inspect messages sent between threads.

Code Complexity

Using Web Workers can increase the complexity of your code, as you need to manage communication between threads and ensure that data is passed correctly. This can make it more difficult to write, debug, and maintain your code, so you should carefully consider whether using web workers is necessary for your application.

Strategies For Mitigating Potential Issues With Web Workers

Web Workers are a powerful tool for improving the performance and responsiveness of web applications. However, when using Web Workers, there are several potential issues that can arise. Here are some strategies for mitigating these issues:

Minimize Communication Overhead With Message Batching

Message batching involves grouping multiple messages into a single batch message, which can be more efficient than sending individual messages separately. This approach reduces the number of round-trips between the main thread and Web Workers. It can help to minimize communication overhead and improve the overall performance of your web application.

To implement message batching, you can use a queue to accumulate messages and send them together as a batch when the queue reaches a certain threshold or after a set period of time. Here’s an example of how you can implement message batching in your Web Worker:

// Create a message queue to accumulate messages.
const messageQueue = [];

// Create a function to add messages to the queue.
function addToQueue(message) {
  messageQueue.push(message);

  // Check if the queue has reached the threshold size.
  if (messageQueue.length >= 10) {
    // If so, send the batched messages to the main thread.
    postMessage(messageQueue);

    // Clear the message queue.
    messageQueue.length = 0;
  }
}

// Add a message to the queue.
addToQueue({type: 'log', message: 'Hello, world!'});

// Add another message to the queue.
addToQueue({type: 'error', message: 'An error occurred.'});

In this example, we create a message queue to accumulate messages that need to be sent to the main thread. Whenever a message is added to the queue using the addToQueue function, we check if the queue has reached the threshold size (in this case, ten messages). If so, we send the batched messages to the main thread using the postMessage method. Finally, we clear the message queue to prepare it for the next batch.

By batching messages in this way, we can reduce the overall number of messages sent between the main thread and Web Workers,

Avoid Synchronous Methods

These are JavaScript functions or operations that block the execution of other code until they are complete. Synchronous methods can block the main thread and cause your application to become unresponsive. To avoid this, you should avoid using synchronous methods in your Web Worker code. Instead, use asynchronous methods such as setTimeout() or setInterval() to perform long-running computations.

Here is a little demonstration:

// In the worker
self.addEventListener('message', (event) => {
  if (event.data.action === 'start') {
    // Use a setTimeout to perform some computation asynchronously.
    setTimeout(() => {
      const result = doSomeComputation(event.data.data);

      // Send the result back to the main thread.
      self.postMessage({ action: 'result', data: result });
    }, 0);
  }
});

Be Mindful Of Memory Usage

Web Workers have their own memory space, which can be limited depending on the user’s device and browser settings. To avoid memory issues, you should be mindful of the amount of memory your Web Worker code is using and avoid creating large objects unnecessarily. For example:

// In the worker
self.addEventListener('message', (event) => {
  if (event.data.action === 'start') {
    // Use a for loop to process an array of data.
    const data = event.data.data;
    const result = [];

    for (let i = 0; i < data.length; i++) {
      // Process each item in the array and add the result to the result array.
      const itemResult = processItem(data[i]);
      result.push(itemResult);
    }

    // Send the result back to the main thread.
    self.postMessage({ action: 'result', data: result });
  }
});

In this code, the Web Worker processes an array of data and returns the result to the main thread using the postMessage method. However, the for loop used to process the data may be time-consuming.

The reason for this is that the code is processing an entire array of data at once, meaning that all the data must be loaded into memory at the same time. If the data set is very large, this can cause the Web Worker to consume a significant amount of memory, potentially exceeding the memory limit allocated to the Web Worker by the browser.

To mitigate this issue, you can consider using built-in JavaScript methods like forEach or reduce, which can process data one item at a time and avoid the need to load the entire array into memory at once.

Browser Compatibility

Web Workers are supported in most modern browsers, but some older browsers may not support them. To ensure compatibility with a wide range of browsers, you should test your Web Worker code in different browsers and versions. You can also use feature detection to check if Web Workers are supported before using them in your code, like this:

if (typeof Worker !== 'undefined') {
  // Web Workers are supported.
  const worker = new Worker('worker.js');
} else {
  // Web Workers are not supported.
  console.log('Web Workers are not supported in this browser.');
}

This code checks if Web Workers are supported in the current browser and creates a new Web Worker if they are supported. If Web Workers are not supported, the code logs a message to the console indicating that Web Workers are not supported in the browser.

By following these strategies, you can ensure that your Web Worker code is efficient, responsive, and compatible with a wide range of browsers.

Conclusion

As web applications become increasingly complex and demanding, the importance of efficient multithreading techniques — such as Web Workers — is likely to increase. Web Workers are an essential feature of modern web development that allows developers to offload CPU-intensive tasks to separate threads, improving application performance and responsiveness. However, there are significant limitations and considerations to keep in mind when working with Web Workers, such as the lack of access to the DOM and limitations on the types of data that can be passed between threads.

To mitigate these potential issues, developers can follow strategies as mentioned earlier, such as using asynchronous methods and being mindful of the complexity of the task being offloaded.

Multithreading with Web Workers is likely to remain an important technique for improving web application performance and responsiveness in the future. While there are other techniques for achieving multithreading in JavaScript, such as using WebSockets or SharedArrayBuffer, Web Workers have several advantages that make them a powerful tool for developers.

Adopting more recent technology such as WebAssembly may open up new opportunities for using Web Workers to offload even more complex and computationally-intensive tasks. Overall, Web Workers are likely to continue to evolve and improve in the coming years, helping developers create more efficient and responsive web applications.

Additionally, many libraries and tools exist to help developers work with Web Workers. For example, Comlink and Workerize provide a simplified API for communicating with Web Workers. These libraries abstract away some of the complexity of managing Web Workers, making it easier to leverage their benefits.

Hopefully, this article has given you a good understanding of the potential of web workers for multithreading and how to use them in your own code.

]]>
hello@smashingmagazine.com (Sarah Oke Okolo)
<![CDATA[Building And Dockerizing A Node.js App With Stateless Architecture With Help From Kinsta]]> https://smashingmagazine.com/2023/04/building-dockerizing-nodejs-app-stateless-architecture-kinsta/ https://smashingmagazine.com/2023/04/building-dockerizing-nodejs-app-stateless-architecture-kinsta/ Thu, 20 Apr 2023 12:00:00 GMT This article is a sponsored by Kinsta

In this article, we’ll take a swing at creating a stateless Node.js app and dockerizing it, making our development environment clean and efficient. Along the way, we’ll explore the benefits of hosting containers on platforms like Kinsta that offers a managed hosting environment while supporting Docker containers as well as application and database hosting, enabling users to deploy and scale their applications with more flexibility and ease.

Creating A Node.js App
In case you’re newer to code, Node.js is a platform built on Chrome’s JavaScript engine that allows developers to create server-side applications using JavaScript. It is popular for its lightweight nature, efficient performance, and asynchronous capabilities.

Stateless apps do not store any information about the user’s session, providing a clean and efficient way to manage your applications. Let’s explore how to create a Node.js app in this manner.

Step 1: Initialize The Node.js Project

First, create a new directory and navigate to it:

mkdir smashing-app && cd smashing-app

Next, initialize a new Node.js project:

npm init -y

Step 2: Install Express

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. Install Express with the following command:

npm install express

Step 3: Create Your Stateless App

Create a new file named “app.js” and add the following code:

const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
app.get("/", (req, res) => {
  res.send("Welcome to our smashing stateless Node.js app!");
});
app.listen(port, () => {
  console.log(`Smashing app listening at http://localhost:${port}`);
});

Let’s explore this a bit. Here’s what each line does:

  • const express = require("express");
    This line imports the Express.js framework into the code, making it available to use.
  • const app = express();
    This line creates an instance of the Express.js framework called app. This app instance is where we define our server routes and configurations.
  • const port = process.env.PORT || 3000;
    This line sets the port number for the server. It looks for a port number set in an environment variable called PORT. If that variable is not set, it defaults to port 3000.
  • app.get("/", (req, res) => {}
    This line defines a route for the server when a GET request is made to the root URL (“/”).
  • res.send("Welcome to our smashing stateless Node.js app!");
    This line sends the string “Welcome to our smashing stateless Node.js app!” as a response to the GET request made to the root URL.
  • app.listen(port, () => {})
    This line starts the server and listens on the port number specified earlier.

Now, run the app with:

node app.js

Your Node.js app is now running at http://localhost:3000.

Stateless Architecture

Stateless architecture means that the server doesn’t store any information about the user’s session, resulting in several benefits:

  • Scalability
    Stateless applications can easily scale horizontally by adding more instances without worrying about session data.
  • Simplicity
    Without session data to manage, the application logic becomes simpler and easier to maintain.
  • Fault tolerance
    Stateless applications can recover quickly from failures because there’s no session state to be lost or recovered.

Okay, we’ve got our Node.js server running locally, but how can we package it up so that anyone can run it? Even people without Node.js installed, and have it run on any platform? That’s where Docker comes in.

Dockerizing The App

Docker is a tool that helps developers build, ship, and run applications in a containerized environment. It simplifies the process of deploying applications across different platforms and environments.

Step 1: Install Docker

First, make sure you have Docker installed on your machine. You can download it here.

Step 2: Create A Dockerfile

Create a new file named Dockerfile in your project directory and add the following code:

FROM node:18-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
ENV PORT=3000
CMD [ "node", "app.js" ]

Once again, let’s take a look at what this is doing in a little more detail:

  • FROM node:18-alpine
    This line specifies the base image for this Docker image. In this case, it is the official Node.js Docker image based on the Alpine Linux distribution. This gives Node.js to the Docker container, which is like a “virtual machine” but lighter and more efficient.
  • WORKDIR /usr/src/app
    This line sets the working directory inside the Docker container to /usr/src/app.
  • COPY . .
    This line copies all the files from the local directory to the working directory in the Docker container.
  • RUN npm install
    This line installs the dependencies specified in the package.json file.
  • ENV PORT=3000
    Using this directive, we make the app more configurable by using the PORT environment variable. This approach provides flexibility and allows hosting providers like Kinsta to connect the application to their infrastructure seamlessly.
  • CMD [ "node", "app.js" ]
    This line specifies the command to run when the Docker container starts. In this case, it runs the node command with app.js as the argument, which will start the Node.js application.

So, this Dockerfile builds a Docker image that sets up a working directory, installs dependencies, copies all the files into the container, exposes port 3000, and runs the Node.js application with the node command.

Step 3: Build And Run The Docker Container

Let’s now build this and run it locally to make sure everything works fine.

docker build -t smashing-app

When this succeeds, we will run the container:

docker run -p 3000:3000 smashing-app

Let’s break this down because that -p 3000:3000 thing might look confusing. Here’s what’s happening:

  1. docker run is a command used to run a Docker container.
  2. -p 3000:3000 is an option that maps port 3000 in the Docker container to port 3000 on the host machine. This means that the container’s port 3000 will be accessible from the host machine at port 3000. The first port number is the host machine’s port number (ours), and the second port number is the container’s port number.
  3. We can have port 1234 on our machine mapped to port 3000 on the container, and then localhost:1234 will point to container:3000 and we'll still have access to the app.
  4. smashing-app is the name of the Docker image that the container is based on, the one we just built.

Your Dockerized Node.js app should now be running at http://localhost:3000.

When running the Docker container, we can additionally pass a custom PORT value as an environment variable:

docker run -p 8080:5713 -d -e PORT=5713 smashing-app

This command maps the container's port 5713 to the host's port 8080 and sets the PORT environment variable to 5713 inside the container.

Using the PORT environment variable in the Dockerfile allows for greater flexibility and adaptability when deploying the Node.js app to various hosting providers, including Kinsta.

More Smashing Advantages Of Dockerizing A Node.js App

Dockerizing a Node.js app brings several advantages to developers and the overall application lifecycle. Here are some additional key benefits with code examples:

Simplified Dependency Management

Docker allows you to encapsulate all the dependencies within the container itself, making it easier to manage and share among team members. For example, let's say you have a package.json file with a specific version of a package:

{
  "dependencies": {
    "lodash": "4.17.21"
  }
}

By including this in your Dockerfile, the specific version of lodash is automatically installed and bundled within your container, ensuring consistent behavior across environments.

Easy App Versioning

Docker allows you to tag and version your application images, making it simple to roll back to previous versions or deploy different versions in parallel. For example, if you want to build a new version of your app, you can tag it using the following command:

docker build -t smashing-app:v2 .

You can then run multiple versions of your app simultaneously:

docker run -p 3000:3000 -d smashing-app:v1

docker run -p 3001:3000 -d smashing-app:v2
Environment Variables

Docker makes it easy to manage environment variables, which can be passed to your Node.js app to modify its behavior based on the environment (development, staging, production). For example, in your app.js file:

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'development';
app.get('/', (req, res) => {
  res.send(`Welcome to our smashing stateless Node.js app running in ${env} mode!`);
});
app.listen(port, () => {
  console.log(`Smashing app listening at http://localhost:${port}`);
});

In your Dockerfile, you can set the NODE_ENV variable:

FROM node:18-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
ENV NODE_ENV=production
CMD [ "node", "app.js" ]

Or you can pass it when running the container:

docker run -p 3000:3000 -d -e NODE_ENV=production smashing-app

The TL;DR of this is that through Dockerizing node apps, we can eliminate a whole class of “works on my machine” problems while also boosting the reusability, testability, and portability of our Node.js applications. 🎉

Hosting Containers With Kinsta

Now that we have our stateless Node.js app Dockerized, you might be wondering where to host it. Kinsta is widely known for its application and database hosting. Let’s explore how we’d do this with Kinsta in a step-by-step manner.

  1. Login or sign-up to your Kinsta account.
  2. From there, you should be in your dashboard.
  3. Using the sidebar, navigate to Applications.
  4. From here, you should be able to Add a Service of type application.
  5. Once you add an application, you’ll be invited to connect your GitHub account to Kinsta so that Kinsta can automatically deploy your application when updates are pushed to it.
  6. You can now choose the repo containing the code you’d like to deploy, along with setting some basic details like the application’s name and environment variables.
  7. Next, we specify the build environment of our application. It is here we specify the location of the Dockerfile in our repo that we just created.
  8. Finally, we allocate computer resources for our container, enter our payment information, and we’re ready to go!

Kinsta will now build and deploy our application, and give us a public, secure link from where it is accessible. Our application is now published to the web!

Conclusion

In this tutorial, we’ve built a Node.js app and Dockerized it, making it easy to deploy across various environments. We’ve also explored the benefits of stateless architecture and touched upon some great choices for hosting containers, like Kinsta.

]]>
hello@smashingmagazine.com (Tejas Kumar)
<![CDATA[Color Mechanics In UI Kits]]> https://smashingmagazine.com/2023/04/color-mechanics-ui-kits/ https://smashingmagazine.com/2023/04/color-mechanics-ui-kits/ Wed, 19 Apr 2023 20:00:00 GMT I am currently working on research linked to a project on creating a complete guide to developing a UI kit as a technical system. In the first stage, I collected technical decisions, requirements, and possible solutions by analyzing open-source and proprietary UI kits. My initial plan was to to dive deep into every detail after collecting the main decisions that were made in dozens of such UI kits.

At my main workplace, an open-source UI kit is used under the hood. I soon noticed that it was difficult to understand its API when it came to anything related to colors.

I had many questions:

  • Which tasks does the kit’s API solve?
  • Which concepts does its API implement?
  • How is the API implemented?
  • What should I know before starting to implement such mechanics in a UI kit from scratch?
  • What are the best practices?

I decided to temporarily interrupt my data collection and dive deep into this topic. In this article, I want to share some things that I’ve learned. I suppose that I’m not the only one who has such questions, and this article’s goal is to answer these questions to save you time. It will also help me not to burn out and to continue my research work.

How to deal with colors is one of many technical decisions. It incorporates many subdecisions and relates to other decisions, such as:

  • How to implement theme switching — according to user action or the OS setting?
  • How to provide theme configuration for different system levels?
  • How to automatically make a color palette?
  • How to implement color-contrast checking?
  • How to support different contrast models? (Windows has high-contrast mode, whereas macOS has inverted colors.)

In the article, I’ll cover two parts. First, we’ll look at base operations, which include the definition and use of colors and known issues and practices related to color. Secondly, we’ll look into an approach to solving tasks by analyzing existing solutions and understanding the connections between them.

Some code examples will contain Sass and TypeScript, but these aren’t the focus of this article. You will hopefully come to understand a model that you can implement with the tools of your choice.

Also, I’d like to warn you against trying to create your own UI kit. The subdecisions that I mentioned aren’t done consciously. You will see that even implementing a small part of a kit, such as the definition and use of colors, is not as easy as it seems at first glance. Can you imagine the complexity of developing an entire system?

As reference examples, we will use Material UI and Fluent UI React Northstar.

Why them?

As for Material UI:

  • It contains a lot of best practices (I have compared it with others).
  • It’s one of the most popular UI kits in open-source software (at least according to the GitHub stars).
  • I have a lot of experience in using and customizing it.

As for Fluent UI React Northstar:

  • It contains a lot of best practices (I’ve also compared it with others);
  • It’s used in large-scale enterprise projects.
  • It contains new concepts that simplify the public API and implementation based on previous experience developing UI kits (see the Fluent UI Web readme).

As a bonus, you will understand how to use the APIs of these UI kits.

To achieve the article’s goals, we will follow a few steps:

  1. Consider which tasks are required to be solved.
  2. Define the terms and their meaning. Without a common language, it would be hard for us to understand each other.
    “A project faces serious problems when its language is fractured. Domain experts use their jargon, while technical team members have their own language tuned for discussing the domain in terms of design.

    The terminology of day-to-day discussions is disconnected from the terminology embedded in the code (ultimately the most important product of a software project). And even the same person uses different language in speech and in writing so that the most incisive expressions of the domain often emerge in a transient form that is never captured in the code or even in writing.

    Translation blunts communication and makes knowledge crunching anemic.

    Domain-Driven Design Tackling Complexity in the Heart of Software, Eric Evans, Addison-Wesley, 2004
  3. Consider problems we might encounter and how to solve them.
  4. Illustrate solutions by considering the implementation of reference UI kits.
  5. Follow the example of the best reference.

Let’s dive in!

Colors Mechanics Model

Terminology

Let’s say that our ultimate goal is to provide the ability to switch themes. In this case, the following concepts come into play:

  • Color, hue
    This refers to the type of color (red, blue, and so on). The term we’ll use in this article is “color”.
  • Color shade, color gradient, color variant, color tone
    Color may be determined by hue, brightness, and saturation. The term we’ll use in this article is “color variant”.
“One important detail about Munsell’s color system is that he divided the color space into three new dimensions: The hue determined the type of color (red, blue, and so on), the value determined the brightness of the color (light or dark), and the chroma determined the saturation of the color (the purity of the color). These dimensions are still used to this day in some representations of the RGB color model.”

— “A Short History of Color Theory”, from Programming Design Systems
  • Color palette
    This is a set of variants of color. We’ll refer to it in this article as “color palette”.
  • Design tokens
    These are general component property names from a design point of view. The term we’ll use in this article is “visual properties”. For example:
    • border,
    • text,
    • background.
  • Color scheme, theme, color theme
    A color scheme is created to impose some constraints. The term we’ll use in this article is “color scheme” because “theme” is more general than “color scheme” (encompassing font size and so on). For example, a color scheme might:
    • contain only variants of the color pink,
    • be tailored to light or dark illumination of the space around the device,
    • be tailored to people with vision impairment,
    • be tailored to specific device constraints.

Producing Operations With Color

We’ll consider basic operations such as defining and using color.

Color is defined according to various color model notations (RGB, HSL, etc.).

In the case of development of a digital user interface, a color scheme is created to color UI components. Each UI component might have a different color for its various properties in each scheme. For example, the background color of a call-to-action button might be red or blue depending on the current theme.

So, how can colors be represented?

How to Name Variables?

If you just name variables according to their color, you will get into a situation where a variable named redColor should have a blue color value in another scheme.

Also, the components that show an error state should still be able to use the red color from the redColor variable. So, another layer of abstraction needs to be introduced to solve the problem.

This additional layer organizes colors by their function (for example, error state) or visual property name (for example, background). It acts as a color scheme.

It’s interesting that organization by function was already introduced to CSS properties.

Each value in the layer’s structure would be mapped to the color palette value by color name and color variant.

How To Remember Use Cases?

After adding colors to the layer, you might encounter a minor problem — how to remember their use cases:

I remember the very first time I tried Sass on a project. The first thing I wanted to do was variablize my colors. From my naming-things-in-HTML skillz, I knew to avoid classes like .header-blue-left-bottom because the color and position of that element might change. It’s better for them to reflect what it is than what it looks like.

So, I tried to make my colors semantic, in a sense — what they represent, not what they literally are:

$mainBrandColor: #F060D6;
$secondaryFocus: #4C9FEB;
$fadedHighlight: #F1F3F4;
But I found that I absolutely never remembered them and had to constantly refer to where I defined them in order to use them. Later, in a ‘screw it’ moment, I named colors more like…

$orange: #F060D6;
$red: #BB532E;
$blue: #4C9FEB;

$gray-1: #eee;
$gray-2: #ccc;
$gray-3: #555;
I found that to be much more intuitive, with little, if any, negative side effects. After all, this isn’t crossing the HTML-CSS boundary here; this is all within CSS and developer-only-facing, which puts more of a narrow scope on the problem.”

— Chris Coyier, “What do you name color variables?

In the initial stage of the project, writing comments next to the variables might help. And creating a dictionary might help to communicate with a design team in subsequent stages.

“The use of dictionaries as a means to establish a common understanding of terms has already proved its benefits in various software-related fields. Literature on software project management recommends the usage of a project glossary or dictionary that contains a description of all terms used in a project. This glossary serves as a reference for project participants over the entire project life cycle.”

Concise and Consistent Naming, Florian Deissenboeck, Markus Pizka, 2006, Software Qual J

Now we understand why just using color names wouldn’t work. But it points to the solution for another minor problem: defining names for variants of a particular color.

How To Define Names For Color Variants?

The solution is simple. Just add numbers as suffixes to the names. The advantage of this approach is that adding a new color will be easy, and the suffix will tell you that the color is a variant of another color. But this is still hard to remember.

$gray-1: #eee;
$gray-2: #ccc;
$gray-3: #555;

Another approach is to give a unique name to each color. This approach is the least convenient because names wouldn’t have any useful information, and you would have to remember them. You would need to define the names or use a name generator, which is an unnecessary dependency.

A better solution is suggested by Zain Adeel in his article “My Struggle With Colors”:

Using a scale from 10–100 with a tone at each ten is by far the simplest. A purple-10 will understandably be the lighter tone in comparison to a purple-50. The familiarity of such an approach allows the system to grow predictably.

The approach provides maximum useful information by name. Also, it can cover more cases if a prefix is added. For example, the prefix “A” can denote an accent color. As explained in the Material UI documentation:

A single color within the palette is made up of a hue, such as “red”, and shade, such as “500”. “red 50” is the lightest shade of red (pink!), while “red 900” is the darkest. In addition, most hues come with “accent” shades, prefixed with an A.

A disadvantage is that the cascade will change if you ever have to add an intermediate color with a brightness variant. For example, if you have to add a color between gray-10 and gray-20, then you might replace gray-20 and then have to adjust the following color values (gray-30, gray-40, and so on).

Also, any solution comes with potential maintenance issues. For example, we would have to ensure that all color definitions have all possible variants in order to avoid a scenario where we have gray-20 but not red-20.

One approach to solving problems is Material Design’s color system. One of the values of this guide is that it doesn’t contain details of technical implementation, but rather focuses on concepts containing only important information.

Illustrating Solutions

Let’s look at an implementation from top to bottom.

Fluent UI React Northstar (@fluentui/react-northstar@0.63.1)

Color Scheme

Let’s consider the “Teams” theme.

Fluent UI React Northstar has a two-dimensional color scheme model.

“Brand” is the color scheme. “Light theme,” “HC theme,” and “Dark theme” will also be color schemes in this article.

Grouping Approach

Color scheme object keys are visual properties combined with states.

export const colorScheme: ColorSchemeMapping<ColorScheme, TeamsColorNames> = {
  amethyst: createColorScheme({
    background: colors.amethyst[600],
    backgroundHover: colors.amethyst[700],
    backgroundHover1: colors.amethyst[500],
    backgroundActive: colors.amethyst[700],
  }),
};

Note: Check out the source code.

In the siteVariables key of the theme configuration, the colors palette is located in the colors key, and the color scheme is in the colorScheme key. They are explicitly separated.

Color Palette

A color palette is an object. Interestingly, some color values are defined with transparency, and the palette contains colors named according to their function.

export const colors: ColorPalette<TeamsTransparentColors> = {
  ...contextualAndNaturalColors,
  ...primitiveColors,
  ...transparentColors,
};

Note: Check out the source code.

“Colors in Teams color palette have the following categorization.

Primitive colors

This part of the palette contains colors that, semantically, cannot have any tints. This group is represented by two colors, black and white — as there is nothing blacker than black and nothing whiter than white.

[...]

Natural colors

This part of the palette includes colors from those that are the most commonly used among popular frameworks (blue, green, gray, orange, pink, purple, teal, red, yellow). Each color includes at least ten gradients; this allows us to satisfy the most common needs.

This decision is experienced from Material UI and allows us to define more variants than by using semantical naming (lightest, lighter, etc.). However, there is no requirement for a client to define all the gradient values for each color — it is just enough to define those that are actually used in the app.

[...]

Contextual colors

This part of the palette may include brand color as well as danger, success, info colors, and so on.”

— “Colors”, Fluent UI documentation

The value in the object’s key by color name may be an object containing keys such as a color variant or just a color string literal of a specific color model.

export const naturalColors: TeamsNaturalColors = {
  orange: {
    50: '#F9ECEA', // darkOrange[50]
    100: '#EFDBD3', // app orange14
    200: '#EDC2A7', // old message highlight border
    300: '#E97548', // orange[900]
    400: '#CC4A31', // app orange04 darkOrange[400]
    500: '#BD432C', // app orange03
    600: '#A33D2A', // app orange02
    700: '#833122', // app orange01 darkOrange[900]
    800: '#664134', // app orange14 dark
    900: '#51332C', // app orange16 dark
  },
}

Note: Check out the source code.

export const primitiveColors: PrimitiveColors = {
  black: ‘#000’,
  white: ‘#fff’,
};

Note: Check out the source code.

Material UI (@mui/material@5.10.4)

Color Scheme

Material UI provides only dark and light color schemes as default schemes.

Grouping Approach

The palette key of the theme configuration contains the color scheme used in this article.

Keys linked to the colors of the color scheme have been chosen according to the following groups:

  1. The functional purpose of the color:
    • primary
    • primaryDark
    • text
    • gray
    • error
    • success
    • warning
    • secondary
    • info
    • action
    • divider

    As the value in these object keys, they may be the following keys:
    • light
    • main
    • dark
    • contrastText
  2. Visual property name
    For example, background.
  3. Colors grouped in a category:
    {
      common: {
        black: "#1D1D1D"
        white: "#fff"
      }
    }
    

At the same time, the values in theme.palette contain other stuff:

  • The current color scheme mode:
    {
      mode: 'dark',
    }
  • Utilities such as getContrastText,
  • ...and more.

Color Palette

Each color is an object. Keys are a color variant. The prefix A denotes the accent color.

const blue = {
  50: '#e3f2fd',
  100: '#bbdefb',
  200: '#90caf9',
  300: '#64b5f6',
  400: '#42a5f5',
  500: '#2196f3',
  600: '#1e88e5',
  700: '#1976d2',
  800: '#1565c0',
  900: '#0d47a1',
  A100: '#82b1ff',
  A200: '#448aff',
  A400: '#2979ff',
  A700: '#2962ff',
};

export default blue;

Note: Check out the source code.

Comparison

We will choose the best reference example according to the following factors:

  • an API that corresponds with the given terminology agreed on by client;
  • implementation that corresponds with the given terminology;
  • following best practices for the designated tasks.

Correspondence With Given Terminology

Fluent UI React Northstar

Pros:

  • The color palette and color scheme are explicitly separated.

Cons:

  • The color palette contains not only common color names (red, green, and so on).

Material UI

Pros:

  • The color scheme (the “palette” key in the theme configuration) contains not only colors.
  • The “palette” key name is confusing because if you want to use a color palette, you would import the “colors” object from the @mui/material package.
  • Misunderstanding is compounded by incomplete compliance with the Material UI guide:

Used Practices

From the point of view of this factor, let’s consider only the differences.

Fluent UI React Northstar

Adding a postfix denoting the brightness of color was chosen as the approach to name variables. The color palette contains colors named by their function and common color names (red, green, and so on). The color scheme groups color by visual properties combined with states.

Material UI

Adding a suffix denoting the brightness of the color and a prefix denoting the accent color was decided on as the approach to naming variables. The color palette contains colors named by their common color names (red, green, and so on). The color scheme groups color by visual properties and function.

I would use the Fluent UI React Northstar as the reference for implementation because it accords with the given terminology. If the topics that were mentioned in the introduction as not being considered were to be considered, then the choice might have been different.

Conclusion

Let’s summarize the key points:

  1. If you want to implement something, examine the best references in order to avoid reinventing the wheel, and focus instead on finding solutions to unresolved problems.
  2. During the examination process, you will encounter solved tasks and terms. Make a summary of them.
  3. Choose the best solutions according to your task’s requirements and limitations.
  4. Choose the best reference that corresponds with the solutions that you chose.
  5. Implement by following the best reference.

If you want to dig into color theory, I strongly recommend the book Programming Design Systems, written by Rune Skjoldborg Madsen.

I would like to thank Andrey Antropov, Daniyal Gabitov, and Oleksandr Fediashov for their suggestions for improvement and valuable additions. I would also like to thank the editors of Smashing Magazine for their assistance.

]]>
hello@smashingmagazine.com (Adel Khamatov)
<![CDATA[Smashing Podcast Episode 59 With Chiara Aliotta: What Is Design Storytelling?]]> https://smashingmagazine.com/2023/04/smashing-podcast-episode-59/ https://smashingmagazine.com/2023/04/smashing-podcast-episode-59/ Tue, 18 Apr 2023 12:00:00 GMT In this episode of The Smashing Podcast, we take a look at design storytelling. What is it, and how can it help us shape digital experiences? Vitaly talks to Chiara Aliotta to find out.

Show Notes

Weekly Update

Transcript

Vitaly Friedman: She’s an award-winning graphic designer, art director and brand consultant working on digital products, print, editorial, UX, and branding. She has founded until Sunday a design studio focusing on regional branding and visual communication. Now in her work, she usually wears many different hats, designing for large and small organizations such as Joomla, PAMS Foundation, Smashing Magazine, Action Aid Hellas, and Medicine South Frontiers, co-running an art gallery, managing a personal lifestyle brand, and speaking at creative events.

Vitaly: Now, she also strongly believes in the power of storytelling and incorporates it in every project she works on. When she’s not working, you’ll find her traveling, capturing photographs or taking a dip in the sun deviled Aegean Sea. And of course, she’s a cat person living with her wonderful husband and her wonderful cat Kesa on the heavenly Greek island of Syros in the Aegean Sea. So we know she’s a wonderful designer and illustrator, but did you know that she also absolutely loves typography and children popup books? My smashing friends, please welcome Chiara Aliotta. Hello Chiara. How are you doing today?

Chiara Aliotta: I’m smashing. How are you Vitaly?

Vitaly: Hello, Chiara. Hello. Thank you so much for coming along. We have so many questions. We have so many things to discuss.

Chiara: Yeah.

Vitaly: And it’s okay, it’s unbelievable because every time I see your smile, every time I see you smiling, you always think about something, you always dream about something, you always have a story that you’re sharing. Right? And I really want us to start today by exploring your story first. So before we dive into storytelling, maybe you could tell us a little bit about yourself. How did you even end up in this wonderful world of design in the first place?

Chiara: Okay. So let me tell you a story. So once upon a time, there was a little girl, she was probably five years old and asked her mother, mom, is there a job where you can actually draw something every day and you can get paid for it? And the mother answered, yes, you can be a painter like your grandfather. So that little girl was me, five years old wondering if there was a job where I could actually always draw things that I like and that I see around me. And I end up doing art school. And then from that I move into design because I studied at the Polytechnic of Milan, and this is where my design journey actually started. When I was 18, I left Sicily in Italy to go in Milan, still in Italy, but in the north and discovered the world of design.

Chiara: While in Sicily, no one knew about design, of what was designed. The closest thing to design was architecture, but architects and designers and not really the same thing. So yeah, so it was quite a journey because I had to convince everyone in my family that I was going to make money out of this job. And it was quite a thing. I met the only female girl moving abroad and in Sicily we are always taking care of the girls. So it was quite a fight with the family before I could actually do what I wanted in my life.

Chiara: And the reason that I decided to study design it was because I wanted to design toys and furniture for children. So that was my goal. But I end up in doing a master in communication design, and this is where I discovered the world of branding. And I love it so much that since that I didn’t go back to toys. For me, everything is a playground. So it’s almost the same that branding and brand consulting sees what I’m enjoying right now. I love to do. And with different brand from printing to digital products.

Vitaly: I can see that for me it’s always very frustrating, I would say just to see the journey that people take when they get from one place to another in their life. And then I always feel like it’s always either hyper coincidences or just random people that you meet somewhere that kind of really motivate you. I remember a story when I was growing up, I had an uncle, or maybe it wasn’t even an uncle, I don’t even know because I saw him only once. But I remember him coming to me once and I was sitting, I was very young, very small, I don’t know, maybe six, seven years old. But he drew something, I think crocodile on a napkin at the time. And I was so impressed by that. I kept that napkin for a very long time until I think I probably lost it or so. But it had such a tremendous impact on me. Did you have those kind of things that really drove you to design or did you just want to draw things since you were a child?

Chiara: I think my inspiration was my grandfather who I never met. My mom was talking very high with him. And my grandmothee’s house, which was my family place, was full of paintings from my grandfather. So to think that someone could actually leave just drawing for me was mind blowing because I was like, wow, can you actually do this for living? I was very much discouraged by my family somehow to become a painter, but they never say no to my decision to go to art school. So that was also good. But yeah, I guess my grandfather played a big role into this decision and probably because I never met him, he became a me, like an important figure that I wanted somehow to be close to because everyone had a very strong idea and image of him.

Vitaly: But then off you went all the way to becoming a branding consultant as well at this point. But actually when I think about branding, I think that many of our dear listeners will be in the same spot as well. I often think about branding, is it just, I don’t know, logo and a bit of a tagline maybe. And sometimes I see this in advertising like a melody or this tune, which is two, three seconds long and maybe even if you go to extreme, it’s like a color palette and typography, right. But I can sense from the way you’re smiling is that you see branding as something slightly broader than that. Could you explain that?

Chiara: Yeah. Okay. You touch a very hotspot right now because I probably had a lot of discussion about this with clients. And slowly I’ve been educating them into understanding the brand is not the logo or the type line or the color palette. For me and in general for many in the field, a brand is how you make your customers feel about it when they experience your products or service. So it’s not anymore something physical, it’s something that is emotional. And it’s a very important aspect when we design anything, any touchpoints that could be an application, could be a brochure, anything really, even a stand, even a conference. That’s an experience when thinking about smashing conference, this is an experience more than of course you have your logo, you have your taglines, you have everything, but what you’re providing is an experience. And that is your brand.

Chiara: This is what you bring with you no matter where you are. If you are in San Francisco, New York or in Freiburg, it doesn’t really matter. That’s what it for me is a brand is the consistency of an experience that no matter how you decline it, then it’s always the same for the customer, for the final customer.

Chiara:So there was definitely a time where a logo, color palette or the tagline were enough to make the difference. And this was the even maybe I was not even born when this was still valid because there was an economy based on manufacturing physical products. So that was, I’m going to say that was more like there was less competition first of all, and there were less products on the shelf. So you don’t have to really show up too much. There was not talking about experience. The economy of the experience is something that we talk about today and it’s been around for a while. And this is where the brand start to become a bigger player. So when the client asks me for a logo or the color palette or the tagline, I usually call it the identity. I never call it the brand. The brand is something else and it goes just beyond all this. It’s one part is probably made of the logo, but it is never about the logo, it’s always about how people feel.

Vitaly: But then I’m wondering also as well at this point, so where does it stop, right? Because if you think about the experience that you’re providing, the website is an experience, the customer service is an experience and you will see that sometimes we have this kind of terms also in the industry, customer experience design, service design. Obviously user experience design as well. So where do you set, lee’s say the frame or the limitations of the boundaries of your work? Because if somebode’s coming to you and they want to have you to design the branding, do you also design things like voice and tone of the copy that they’re writing? Do you also design, I don’t know, things like the personality, the illustrations, the characters and whatever they want to have? Or would you say that there are particular limitations that branding typically has after all?

Chiara: Yeah, that’s a good question. It really depends by the brief and the budget of the customers. This is first of all, one important thing. This is first of all, the limit. Then of course as you say everything could be brand. And indeed, it is, you produce under the name of something that could be, I don’t know, I just seen Smashing because I just took as an example. So whatever you build under Smashing brand has to fill up the same experience. So the same experience of a community has to be consistent in everything you do. Now, when it comes to tone of voice, or things that are very specific, even a video editing, how we renowned design the entering tone of the Smashing podcast. So that also it’s part of the branding. So you usually go back to the tone of voice that you set up for the Smashing magazine maybe.

Chiara: And then you go back and say, okay, it has to be fun. Maybe we can have some cats meowing. And then you start thinking how this could come together. That doesn’t mean I’m going to be the person. I usually go into a very high level aspect of the brand. So it could be indeed the tone of voice, it could be the keywords we are going to use. And then based on that there are specific people, video editors, copywriter is going to tick my work and interpret it like it’s a script. Actually, that’s what it is. Usually that’s what a brand manual is. It works like a script so that everybody can follow it. And of course it needs some kind of interpretations too. So my work finish when I decline the brand in all the aspects, thinking of how it can be declined in a very high level.

Chiara: And after that there are specific people joining and coming and working with that script, let’s say, which usually is a brand manual, which is wider. Sometimes if you have applications, it could be more than a brand manual, it can go down to design system as well. That’s part of the branding for me because that’s another way to experience, but a digital product. There are a lot of things. So you define those things up very high level and then you find people working with you in defining the tiny bits of the brand. So it could be then, as you say, they could be the copywriting, the task, the illustrations, and so on.

Vitaly: What I really like about this approach, seeing it in this way is that it provides us with some opportunities to do something really interesting with branding. I mean, I know that you’ve been very vocal and very interested in how to connect storytelling and branding. Maybe before diving into storytelling though, I’m very curious just about your feelings today about brands per se? So if I think about brands, I don’t know, 10, 20, 30 years ago, I have this strong feeling, and please correct me if I’m wrong, have the strong feeling that many brands could be neutral in so many things. They didn’t need to take a stand, they didn’t need to have an opinion. They were for everybody. And this is how I perceive not all brands of course, but some brands. So for example, it would be very uncommon for a brand to have a political opinion about how things should be or express it on, of course not on social media, but in print or in advertising.

Vitaly: It was more about the product and really kind of advertising for marketing and all that for the product. And now I have the strong feeling that it’s impossible. You can’t be a brand and, you can be a brand, but you cannot survive if you don’t have principles that you stand behind. If you are afraid to make somebody or some of your customers unhappy, you really, if you want to speak to anybody at this point, you have to eliminate somebody just because you have to stand for something. So do you see it in a similar way when it comes to branding or would you say that many brands can be perfectly fine being neutral around topics that are happening in society or in the world?

Chiara: So that’s a very good question. Probably it’s about evolution of brand. I think the brand, every brand or any is political somehow, if you want to say it this way. So they need to stand, they need to have a culture, they need to have a belief and values. So all these words are already defining what you are standing for. Maybe in the past it was easier because you were talking to the mother with the children or the father working until late at night. Now we are talking to communities, and this is something that’s changed because of the social media. So what we do is usually all together we always influenced by what other people are doing. We feel more and more that we need to belong to something. And this is something that social media is probably, how going to say, exasperated. But the sense of community is so strong that now when a brand talks to community, it identifies himself with the community values and what they believe.

Chiara: So definitely that means that a lot of people are going to be cut out from that brand culture or values, and it’s fine. Because if you want to please everyone, probably you’re not going to please everyone anyway. So you have to be very, I’m going to say, loyal to yourself. It’s about consistency. It’s about being true to yourself. So the brand needs to stand for something. And I recall when I was at the conference in New York and there was Debbie Millman, she did an amazing talk about how brand actually stand for a cause and how they can become a real propeller for a change. And I really love that talk because she actually was nailing it because she show how everything, every movement now has become a brand and how actually this is the power of branding. And this is an amazing aspect of branding, especially when they stand for causes that are bigger than us. So as a unit, as small people, we can do very little, but as a community we can really make a big change. So that’s my take on this.

Vitaly: Yeah, that makes sense. I still have to bring up one question about branding. I know that we will want to speak about storytelling, but one thing that really surprised me, I think it was actually quite a, I don’t know, viral thing I guess for a while maybe a couple of years ago before pandemic, where all of a sudden many fashion brands decided that it’s a good idea to redesign. And they kind of rebranded and they ended up becoming quite generic. So the logos that they ended up having are very generic. The website’s very generic, even the copywriting of how the emails were sent, very generic. But then on the other hand, what has been happening also is that you look at the music industry, and you look at festivals happening and every single DJ, every single music producer needs to have their own brand. They all like whenever you have this wall of DJs that are playing, they all have their own branding in a way with their own custom design typefaces.

Vitaly: On the other hand, you also have these big institutions like banks, huge banks, they don’t know should we now be more kind of citizen-centric and then more playful or not be more conservative and traditional because we’re managing other people’s finances and all that? So I do want to ask you at this point, where do you see what would be the right way of putting it? Where do you see maybe the storytelling, right? Where do you see it fitting well and where it doesn’t? Do you think that pretty much every organization, small and large, every company, every product can benefit from integrating storytelling as a part of the experience?

Chiara: My answer is yes. And I’m completely biased because.

Vitaly: I think you’re a little bit biased. Yes.

Chiara: I believe in the power of storytelling and that’s my motto that I guess it will always be because I have a proof that this is working. But it really depends what storytelling is because what you call storytelling. Because storytelling could be, I’m telling you a story about something very specific and about our customers doing, I don’t know, I’m just thinking about one of the most famous story that I recall when I was young. It was a very child, it was with Barilla, the pasta brand worldwide. And their story was always around the family as mother, father and children. And this was the story of the family joining together and the pasta was the thing that was keeping them together because there was a time when they were eating, so they were all at school, the children were at school, the mom was probably working somewhere, the father was coming home.

Chiara: And then the moment of reunion was the pasta. So the pasta Barilla became the symbol of family. This has changed of course with time because of family now it’s broader now and we have a lot of gender consideration to do based on that, but has been changing. And this is a story, this is a story translating to another type thing. Then there is a story as an approach, like a methodology, which is what the banks and other institution could actually use. And then we use this a lot with organization where especially the not-for-profit ones, because most of the time when they work they focus on analyzing the wrong side of the story. The most of the time it’s the effects, your actions do that you need to reflect on. And this is where storytelling comes to play because through the approach you start following your customer and understanding the emotional journey.

Chiara: And this is where you start to understand probably the story of a child dying every day is not, it’s not the one you want to promote. It’s the one that you save every day is the one you want to promote because that is going to give you the climax, which is what you want in a story. So we are not going to tell, of course, the story of a child dying somewhere or someone, I don’t know, losing their house because of a earthquake happened. Unfortunately of all this disaster, we just try to tell a different story.

Chiara: And so the storytelling approach is mostly a background methodology that help us define what our message is going to be. So it’s not going to transform into an advertising necessarily, but it’s going to be, I can say the narrative behind everything we are going to do and say. So that’s the difference. It’s what could be a story. So the advertising I told you before, it’s Barilla, it’s a story that you see happen in front of your eyes. And then there is the background storytelling, the approach itself, which helps you to actually identify the right message. So I see storytelling apply to everything because there are many ways to apply it. We need to decide what’s the best case and the best scenario for applying it.

Vitaly: Talking about the best scenario, I think I have just the question that I wanted to ask for a long time about specifically how to apply storytelling. And obviously it would be very interesting to see your design process. And I heard rumors that you have just published an article about that on Smashing Magazine, so thank you so much for that. But also I know that you’ve been working with the crypto platform in trying to embed storytelling in there. And I’m just really have to ask, I’m just really curious, how do you work to integrate storytelling to this kind of environments or banks or public institutions or some very conservative environments?

Vitaly: I can see it being almost straightforward for brands that care about fashion or that care about work-life balance or they care about lifestyle brands, that’s probably relatively straightforward, although please feel free to correct me at this point. But I’m really curious how you would try to bring in some sort of storytelling in this slightly less straightforward, I would say, environments.

Chiara: Okay, let me tell you a little bit because I think there is always a misconception about storytelling. Because lee’s say, first of all, I’ll start my meetings with the client saying once upon a time as I did with you when I was talking about myself. So I usually-

Vitaly: Oh, you do not?

Chiara: No, I don’t. They will probably throw me out of the office. Like what she talking about? No, never. So the storytelling is a more subtle thing. And I never disclose in the way, hey guys, I just storytelling. They would never understand everything. What are you a screenwriter, a novel writer? I’m still a designer. So what I actually do is what I was telling you before is that I use storytelling as an approach. So when I meet them for the first time, I usually ask all the questions that help me to fill up the script, my script.

Chiara: That stays with me, it’s the behind the scene that you have seen that you can read now on the Smashing Magazine article that I wrote about the landing page we designed together for smart interface, the design pattern. So is this athlete that script, but you were never going to see it. What you’re going to see is the final movie. It’s what you’re going to see in the cinema. You’re not going to see the behind the scene. I’m not going to tell you how I’m going to fill all the blank spaces of my script or what scene I cut and what other actually went into the final movie. So what I usually do is I usually follow the storytelling structure, so the beginning, middle, and end to help the user be with me on the creative ride so that they actually know exactly what to expect, when and how so that they can actually provide me the feedback I need when I need them.

Chiara: And this is what a director of movie will do, they will ask the actor to say specific line because this is like now shot, cut, done. This is what I do. I just direct the scene and I provide specific elements that I wished them to answer. So the client answers in specific times so they don’t feel too overwhelmed. And what they see at the end is the final product, so the final movie or the final book. They will never see the correction and all the things that went through it.

Chiara: Unless I write an article as I did. So that’s the storytelling thing. So I usually go through the story brand script that Donald Miller provide in his book, The Story Brand. And then from there I start filling up the single spaces. And so the clients want to hear, of course I’m happy to, but really they want to go straight to the climax of the story. They just want to see what I came up with. So I just go very quickly through the different steps but very quickly and then go into, okay, this is a final product and this is where they actually usually they have this wow moment. I still remember actually wow moment when you saw this Smashing book six. I still remember that.

Vitaly: Oh yes, I remember that vividly because everything is coming together all of a sudden. Because what I think that I have a strong feeling that very often when people like something, it’s not just because it’s aesthetically pleasing or it’s nice typography or anything like that, it’s just something clicks and that something clicks when you actually see or not necessarily see, but you perceive the connections. So for the Smashing book and also for the landing page, the idea of having all the different elements that kind of have their own life at first, but then put together, they bring everything else to life as well.

Vitaly: But they also, the only kind of best way of how to compare it in my head is they’re playing in a orchestra. So it’s not every single element is doing their own thing. And you have this horizontal line that looks like this and you have this little characters there having this and then you have this image corners looking like that. Whenever everything really fits well together, it’s always like they’re playing in an orchestra or some sort of a symphony or anything. And I think that people notice that. They might not necessarily be able to articulate it and point it directly, I know exactly why it’s done this way, but it’s almost like you are fighting a little bit of jams or Easter eggs every now and again here throughout your design for people to discover. It’s like a treasure hunt almost. So this is at least my feeling about it. What do you think?

Chiara: Yeah, I really agree with you. And that effect is like magic for me when it happens. It’s like when you watch a movie and you really like and you can watch it again and every time you find something different in the movie that you didn’t notice the first time. And I really like this kind of feeling. If I can say, evoke this feeling, for me it’s like one tick in the box. Actually it’s one of the highest thing that I can hope for my work when somebody notice things that were there, but I haven’t told them, but they notice it. And yeah, this is amazing. This is magic for me. And that’s why again, I believe in storytelling so much because only with storytelling you can put all these pieces together to work together well and also to create sequels if you want to and expand that story even more. That’s what storytelling can help you do. And yeah, I’m happy that you felt this way because that’s the highest achievement for a designer.

Vitaly: Yeah. Also, just to maybe go a little bit more into the process. So you would literally sit down and take a piece of paper and think about the plot, thinking about the climax, think about the Aristotle’s Arc, maybe, the story arc or the heroes in the story and the rivals and I don’t know, all the different things. And really map them before you start designing. Or does it help you to design the elements that will then go into the composition or would you say that it guides you towards the structure, the layout of the page or both?

Chiara: Depends. Depends how, it depends really the kind of work. When it comes to branding, because it’s a little bit more complicated, I usually go through the values and all the elements of the story. So value, emotions and actions that we want the user to do with the brand. So all these things. And I really need to create a plot for that because there are so many variables happening when it comes to brand. When it comes to landing page, like the one we design together for your course, usually I use the landing page as a shot. And the first thing I do is really divide it, the landing page in three scenes: the opening, middle and closing scene. And then I start to fill up with the elements I already asked you about the story. For example, you remember I asked you, okay, how do you want the people to buy your course and what else are you providing?

Chiara: Is there any gift? These are all things that help me. Then I position them inside the page between the different act and this is how I start to build the story for you. And to ensure that actually we can move from one act to another one, so I put some delight. So for example, you were telling me, oh there will be a gift and for the people, I’ll name it access to the deck. And I was like, okay, we need to put it somewhere on the website. It needs to be just before maybe they sign up. So it’s going to be a delight moment or surprise that going to convince them that this is the right way to go. And I try not to use dark patterns, but of course the idea is always to propel to the final action. I just want people to finally go to the end.

Chiara: So it really depends. But for example, for your landing page, it was difficult to find the central team, the concept, how can we look different? Okay, we’re talking about video course, but yeah, but how can we make a little bit more memorable? So the people saying, oh, this seems different. It seems interesting. How we can keep this curiosity and playing around because the designers are very difficult to please. So you were talking with a very difficult audience. So I am one of them. So I try not to put myself in that shoes, of the shoes of the customer. But I have to feel some empathy about a designer who wants to discover a little bit more about UX design and design patterns.

Chiara: So the playful side of registration was probably the most difficult part because I mean was like, oh my god, we’re going to talk about food now. But yeah, he’s in the kitchen. Oh my god, everything leads over there to food experience. Oh yeah, this is what it’s going to be. It’s going to be a food experience. So that was me talking to myself, putting down the notes and was like, yeah, this is going to be, that’s it, this is all for experience. Now I need to transform the cogs into fishcakes. I don’t know how I’m going to do it, but I’m going to do it. Yeah, that was exactly what happened. So I don’t know if I answer your question, but-

Vitaly: Yeah, of course. Yeah, this is just exciting to get a little, I would say, peak behind the scenes. But I also just wondering at this point, so as you keep evolving and you create all these worlds that you then put and bring into life when it comes to designs and all, does it happen to you sometimes that you create this universe almost that actually incorporates all the different aspects of the brand, aspects of the company and the values that they believe on the culture and all that? But then the project is done, you move on to other projects, right, but they need to maintain or evolve that universe that you have created.

Vitaly: And I’m wondering, does it work? Because again, this involves everything, right? Because again, as I mentioned, when it comes to branding, it’s a voice and tones how you do your marketing, how you design your advertising spots or banners and you send out emails through your email list and all. Do you also do some sort of, I don’t know, do you write actually the script as well or would you advise companies to do that, to make sure that you actually speak in the same voice that independent on what touchpoints the customer is going to be experiencing or going through with the brand or the company?

Chiara: Usually when I, okay, lee’s talk about brand because it’s a little bit more my sphere, but I will say than it probably open up to all the other things I design. So when I approach a brand, usually they have a, what is called a design brief. That is like a blueprint for anyone approaching the design of any part of the design to read what we have decided up from. It contains the vision, the mission. I know, the brand manual could have that too, but this is very specific. It really have, it’s called design brief because you read this piece of paper, which usually is made of a few pages. And you really understand what kind of elements come into play when you design something for this company. And then you have the brand manual, that’s also combined. You get a very full picture of what it is going to be, the brand.

Chiara: Whatever you’re going to design, this has to be, someone has to be aware that are these two documents. And usually I provide both of them. If work really well for startups, especially because with startups I’ve been working for a long time with blockchain, especially the last two years. During the pandemic, blockchain was probably one of the best industry to work with and a lot of startups started and they wanted to have documents so that the product while evolving could actually follow up what we have decided. That’s always an evolving procedure with startups. So you never know how the product will end up to how it’s going to look like.

Chiara: When it comes to simply product. They’re digital like an application. Then is a little bit more difficult. I usually like to provide element bits and bites of the interface. Also extra that may be used in the future just in case just to give an idea of what it can look like. I want to call this design system, they’re not. They’re just the elements of the user interface that I provide extra. But most of the time I just leave, how I going to say, I just leave it to the interpretation of the developer to come with some ideas about that.

Chiara: And I have clients that coming back and say, oh, our developer design this bit, can you look at it? Does it look in brand for you? And sometimes it’s good. They’re being reused some pieces, which is great because what I do is usually design by modules. So they just take pieces together and they form the new component. Sometimes it’s not that good, but then when it’s bigger part of the design, maybe they come back to me and ask me, please Chiara, can we continue our story together? Can you think about something for this specific element of the website or the application?

Chiara: And now we move forward from there. It’s more working, I don’t know, I think about the sequel or I don’t know, stranger things, okay. Or maybe, oh no, maybe I will say some movies, where a different director working together and then at the end you have a nice melting pot, but it’s nice. It doesn’t look like strange. Because all of them, they pick up from where the other has left. So sometimes they commit to review some of these pieces and it’s a nice moment because you refresh a little bit of brand, you refresh a little bit what you said and you hope they will follow up from there with their own stats. Most of the time it’s easy. It’s easy then. But I usually been called back to review big pieces of design just because they didn’t feel it was quite right as they were done.

Vitaly: Yeah, I think it’s also can be almost like a never ending story when it comes to this kind of embedding storytelling involving the brand and its on. And fortunately there is a wonderful chance that our wonderful readers or readers or listeners can get to join one of your upcoming portraits where I think going to look into just that. And it’s called the Power of Storytelling and it’s taking place in March in about a month or so from now. Maybe you could share a bit of a few insights with us about what it will be about and why all the wonderful people who are listening to this now should absolutely go ahead and join you in that adventure.

Chiara: Okay, so first of all, thank you for mentioning and thank you for the opportunity to actually be able to run this workshop with the Smashing community. So it’s a quite interesting workshop because I’ve been running this live here on the island of Syros on a very basic level because the students are very young and they’re very new to storytelling. And when I decided that we can do a high level workshop online and because I imagine to be, it’s going to be a very directed workshop because we are going to start by analyzing the fundamentals of storytelling. So again, it’s not going to be once upon a time. Okay, we can start every day of the five sessions, say once upon a time, but it actually is going to be a real diving deep into the elements and methodologies of storytelling. So how we actually divide and map the user journey.

Chiara: So if you think about user journey map and heroes journey, and emotional journey, forget about it because we are going to write a script for an Oscar word application or product that every user going to love. So in general, this is what I want. I want to teach and want my student participant to learn how to use a storytelling in a way to create products that are memorable. So it’s not going to be the beautiful illustration, but it mostly like how we can make an experience memorable for the user.

Chiara: Then it doesn’t matter how you decline it. It matters that it’s consistent. So it’s a mix of user experience, probably a little bit of understanding of interface design because we are going to do it for a digital product mostly. But then after that, once you apply the and you learn these methodology, then you can apply to everything you want. Whatever it’s your project, you can just take this methodology and apply it to everything else. To your next project that is in pixel or in print or just an experience for a venue. It really doesn’t matter because that’s the beauty of storytelling and of this pluses that you can really apply it almost everywhere.

Vitaly: Well, if this is not exciting, I don’t know what is, right. So I’m very much looking forward to this as well. So on the Power of Storytelling, which is going to be taking place with Chiara in a month. Just to wrap up at this point, maybe I do have to ask one final question I like asking because it gives us a little bit of a hint about what people who are in here on the Smashing podcast are really interested in. Do you have a particular dream project, something that you maybe would love to work one day? Just to give you a few ideas, right. Some of the people we interviewed are going really big. They want to necessarily have the option to design one of the rockets that are going to go to the moon. That could be the ambition. But it could also be just something as simple as a series of children books. That’s perfectly fine as well. Do you have a particular dream projects that you would like to realize one day, Chiara?

Chiara: I’m a dreamer and I honestly, I think I live a life that is already close to what I dream of. But there are always new dreams coming up. So one thing I would like to do is on the field of storytelling, I really would like to create a little empire around this idea, methodology, that I want to share with the people. Because I’ve seen it, the magic of transformation that happens behind storytelling. So I would like to write a nice book or things that are maybe pop up book as well, something different that about storytelling and the approach and the methodologies behind storytelling. That’s one dream I had. And to become a more like a mentor in this field because I think I have a lot of to share. Just sometimes you don’t have the time to do that, to start writing a book or writing on things you’ve been through just for sharing.

Chiara: And so the other people don’t have to experience the same, they can just jump at the end of the book and read how it’s ending. So you who is the killer, this kind of thing. I would like to share more so that no one has to endure what I endure because there is no need because you can live out the experience someone else. So that’s one dream.

Chiara: And the other dream is something that I’m working because it was a dream until two years ago. Because of the pandemic it couldn’t happen before. And I’m putting together a little hub here in Syros of designers that are on the island. Because the pandemic brought so many people working remotely. They don’t want to live anymore in a big city. They want to live in a nice place with a sea two meter away. And so I start to meet a lot of people, interested in design, and there is a design school here.

Chiara: And so I think there are the right basis for creating nice hub for a nice spot on Syros to be like in the map of the destination for designers. So I’m working on it right now with some other professional creatives in the field and not only, but also musicians and food experts. So I have an entourage of people that we’ve been thinking and discussing how this could happen. And I don’t know, I keep you posted because I don’t know what is happening.

Vitaly: Oh yes, please.

Chiara: And maybe, I don’t know, Vitaly, you can do a Smashing edition, summer editions, Smashing conference summer edition on Syros one night because yeah

Vitaly: That sounds very exciting indeed.

Chiara: That would be lovely.

Vitaly: Yeah. Excellent. If you dear listener would like to hear more from Chiara, you can find her on Twitter where she’s @ChiaraAliotta. On Instagram where she is @untilsundayagency and also on her homepage, beautiful homepage, untilsunday.it. Thank you so much for joining us today, Chiara. Do you have any parting words of wisdom for people who might be listening to the show? 10 or 15 years from now, where storytelling is just everywhere. Anything that you’d like to send to the future? A message to the future generations?

Chiara: I just think about, just design always to put the smile in the face of your customers. So if storytelling is one way, please do it. If you know other ways, please share it.

]]>
hello@smashingmagazine.com (Drew McLellan)
<![CDATA[What Is Design Thinking?]]> https://smashingmagazine.com/2023/04/what-is-design-thinking/ https://smashingmagazine.com/2023/04/what-is-design-thinking/ Mon, 17 Apr 2023 15:00:00 GMT In a world of fast-paced action and reactions, quality results are something that we all aim for. But how can you make something better? Whether it is a product, a service, or perhaps a process, we aim to make things better. It leaves us to wonder how we are going to design a world that is long and equitable to attain a degree of excellence.

When we are talking about making “things better,” we cannot deny the role of the Kanban system in implementing TQM (Total Quality Management) for Toyota. If TQM did that for manufacturing, design thinking has the potential to bring human-centric solutions for innovations.

Design thinking takes the human-centric approach in order to understand how to deal with the problem before we jump into all possible solutions. We could see its use in various places. The buzz is everywhere, from the social sector to policy making, health care to business. So what is design thinking?

The Meaning Of Design Thinking
Design thinking fosters tackling complex problems in a creative way that prioritizes human needs with a huge emphasis on finding creative solutions with what is technically feasible.

Though it’d be hard to put the definition of “design thinking” in a few words, I’d rather look at design thinking as a philosophy or a mindset to solve complex problems that are too tough to be solved with the conventional and standard practices of problem-solving. Design thinking takes the route to give solutions that are: feasible, viable, and desirable.

Generally, solutions to problems are sometimes overlooked with the conventional approach to solving them, while some approaches are highly rational and analytical while others are emotional. Design thinking might just be the third way that augments the rational, emotional, and functional needs of human problems. Design thinking is not restricted to only building products; any new initiatives that foster innovations can leverage the design thinking principles of problem-solving.

The Origin

While there are no solid indications of the origin of design thinking, design thinking as a mindset could be traced back to John E. Arnold, a professor of Mechanical engineering who pioneered the study of “Creative Engineering” at Stanford University. He was one of the first few people to write about design thinking and considered the seed for design thinking as a movement. His lectures motivate being more imaginative and innovative. His theory of problem-solving focuses on human needs by relating personal, scientific, and practical aspects of the problem.

He emphasizes the importance of approaching the problem like an artist and having humans as the cornerstone for the solutions you want to build. “Creative problems” do not have one right answer.

“The engineer can take on some aspects of the artist and try to improve or increase the salability of a product or machine by beautifying or bettering its appearance, or by having a keener sensitivity for the market and for the kinds of things people want or don’t want.”

— John E. Arnold
The Design Thinking Process

In an effort to contextualize and apply design thinking, it is often identified with a process that guides the values to hold sway on how you approach the problem. This process may not necessarily be linear or sequential but rather a loop that makes sense for the particular problem or use-case one undertakes.

Empathize

Designing for humans could be tricky. Sometimes the needs or desires are left uncovered and may not be fully reflective of the real problem. While traditional market research processes go by facts, design thinking approaches to address the problem through empathy. Empathy attempts to understand latent needs and translate the current realities of the environment. This helps solution designers understand the people, their behavior, and the context that can explain the problem to build better solutions.

So, the first step to getting inspired by the problem is to understand the people you design for and what motivates them to search for a solution. This is especially very useful for businesses to understand the opportunity space available. Just the way Apple did. While MP3 players were already a thing, iPods changed the way people consumed music. When Sony ruled the consumer electronics market with their Walkman and CDs, Apple revolutionized the world of music with IPods. Apple empathized with people’s problem of carrying around cassette tapes, and iPods changed the game!

In order to identify and understand the pulse of the problem and to contextualize this step, gathering information is key. This is where you talk to people in the problem space to understand what they care about and how they currently deal with the problem. User interviews and their feedback help you get into their shoes.

Define

This is one of the most important steps where the problem gets shaped.

In design thinking, ill-conceived problem statements pave the way to building solutions to “a problem,” not “the problem.”

Let me explain.

For example, you talk to someone about a problem. You record the observation and pitch in a plausible solution to that problem. The user gets excited that your solution might solve that problem. But what really happens here is that you and the person have been discussing just one of the problems among their many other problems. Therefore, their decision to adopt your solution depends on the importance the person gives to the problem that you promise to solve.

Here is where defining the pulse of the problem becomes very crucial. Often, in hindsight, the spotlight falls on the problem you are trying to solve rather than the many other problems the person might actually have.

Hence defining the problem goes a long way to give you leads on how to go about building human-centric solutions.

Ideate

This is the phase where your observations find a home to be synthesized to create an opportunity for change. You brainstorm to define and redefine the potential solution to create competing ideas to solve the problem. This step ideally helps you to get to the core of the problem.

As said earlier, this is not going to be a linear process, and you might often find yourself going back to previous steps as you work together to challenge the idea or perhaps the problem itself. Thereby you cull out good ideas to implement.

Prototype

The next phase is the prototype, where you validate your ideas by creating a mockup of your final solution. Your solution takes a tangible form to show evidence in this implementation phase of the prototype. It also shows you the limits and limitations of your idea that are left unaccounted for during the ideation phase.

One of the classic companies which nailed building a great prototype is Uber. Uber focused on solving the core problem of “finding taxis ” in its initial release. The first beta version of the product was a very minimalist app where all the orders were managed manually, where the CEO contacted drivers to book the ride. And it did not have features to pay. The goal was to test and validate the problem of hailing a cab, which is the core benefit of the app. Eventually, when they understood the target market and pain point, they rolled out to improve other features.

Test

The final prototype is then tested with your target group and is reiterated to accommodate the learning that comes your way. The validation takes the final form here and may again require you to revisit some of the previous steps to implement the plan at scale.

Design Thinking In Action: Case Studies

Design Thinking In Social Sector

Malaria, one of the nerving problems in Africa, was one of the top 5 causes of death for children under the age of five. This is a social problem highly complex in nature, and the design thinking approach to distributing mosquito nets helped to combat the disease effectively. The World Health Organization reported a 50%-60% decline in death in countries like Ethiopia and Rwanda and a 34% decline in Ghana.

It was found that the design of nets was unappealing to some people in Ghana. A group of researchers identified a potential solution to address the problem of getting people to use the net. They came up with a human-centered design of nets that paved the way to provide a long-lasting solution to this social problem.

Airbnb

Design thinking has also played a huge role in transforming an almost failing company- Airbnb. Their business was crippling down, and when they got into the problem, they saw a pattern in their ads with the pictures which weren’t working great. The pictures on display were taken on low-quality phones. When looking at the photos on the site, the people who wanted to rent felt that they did not get to see what they were actually paying for. As soon as the founders realized this, they rented a camera to take good pictures of the customer’s property. Gebbia, one of the founders, went on to explain how the design school experience helped them reinvent themselves to serve customers better.

Netflix

Another household name, Netflix, has come a long way, and design thinking has had a huge part in the decisions that they make. Netflix came up with a DVD rental service delivered straight to the doorstep while other rivals had people drive through the stores to pick movies.

Later when cable started to give on-demand movies, Netflix understood the pain points of the customers and began online streaming services on a monthly basis without having to pay for every single DVD. They built an online directory with a subscription model and delighted customers with the convenience of watching their favorite movies from the comforts of the home.

When picking something to watch took a long time than actually watching, Netflix came up with “previews” that helped people to choose what to watch. As simple as it may sound, the thought behind Netflix’s recommendation system helps to cut down the time people spend deciding what to watch. While change is inevitable, Netflix keeps reinventing itself with a design-thinking approach to uncover innovative solutions focused on the end user in mind.

From renting DVDs to online streaming, Netflix has continuously aimed to understand the end user to design solutions in a human-centric way.

And not just this. The list goes on and on.

Final Thoughts

Design thinking has been evolving itself. People have been contributing to making it more useful to contextualize its use in various fields. Applying the design thinking framework and getting into creating a human-centric solution comes with different shapes, depending on the size and complexity of the problem.

Given its flexibility, design thinking helps you get familiar and comfortable with ambiguity. The approach lets you play around dynamically at various scales, making it a valuable pursuit.

Try it by starting with any problem you want to solve, and let me know how it worked for you in the comments below. I’d love to hear and help if you wish.

Related Resources

]]>
hello@smashingmagazine.com (Krithika Subramanian)
<![CDATA[How To Design An Effective User Onboarding Flow]]> https://smashingmagazine.com/2023/04/design-effective-user-onboarding-flow/ https://smashingmagazine.com/2023/04/design-effective-user-onboarding-flow/ Tue, 11 Apr 2023 18:00:00 GMT This article is a sponsored by Feathery.io

What is it that causes users to give up on an app before ever stepping inside or really giving it a fair chance? It could be the onboarding process.

Sometimes half the battle in getting users to adopt the products you build is to first get them in them so they can see how awesome they are. With a high-quality user onboarding flow, you can easily increase conversions, user satisfaction, and user activation within the product.

In this post, we’re going to look at what it takes to design an effective user onboarding flow that maximizes how many engaged users you get inside your web app. We’ll be using Feathery — a powerful, no-code onboarding form builder — to demonstrate how to do this.

What Can You Accomplish With An Onboarding Process?

The onboarding flow is a multi-step process that helps users get started with a new SaaS product. In most cases, the flow appears right after signup and bridges the user into the app. And for more complex SaaS, onboarding flows can appear as tooltips and guided tours inside the product.

With a particularly effective onboarding flow, you’ll be able to:

  • Increase conversion rates.
  • Reduce user abandonment.
  • Increase user activation within the product.
  • Improve overall user satisfaction.
  • Decrease churn.

Ultimately, your user onboarding process sets the tone for what’s to come.

You can personalize the product based on user responses, demonstrate how easy it is to get started, or reinforce the overall value of adopting the product into their workflow.

How To Design A Great User Onboarding Flow With Feathery

As I break down the steps below, I’ll demonstrate how to use Feathery to create an effective user onboarding flow similar to Duolingo’s popular onboarding flow.

Note: After you sign up for Feathery, you’ll have a short onboarding process of your own to complete. In the end, you can choose to use a template or start with a blank canvas. For the purposes of this walkthrough, I’ll be starting from scratch.

Step 1: Design The Container Style

Although each step in the flow will contain different content, you want the general design and format to remain consistent throughout. Not only should this design improve the usability of the onboarding process, but it should give users an idea of what your app will look like.

To make changes to the appearance of your onboarding screens, click on the container in Step 1. A “Style” panel will open on the right.

From this panel, you can modify the following:

  • Layout,
  • Background color or imagery,
  • Corner radius,
  • Shadows,
  • Hover-triggered transformations,
  • Click-triggered transformations.

Note: If you plan on making extensive customizations to the style of your container, I’d recommend deleting any subsequent steps that were included with your template if you’re using one. It’ll be much easier if you duplicate this first container for subsequent steps and save yourself time replicating the styles. Alternatively, Feathery offers the ability to build and save reusable styles and components using themes.

Step 2: Create The Steps In Your Flow

People can really only hold about five to seven items in their short-term working memory.

If you want to get as many users through the onboarding process as possible, only give them as much information or ask them as few questions as needed.

That means capping your onboarding steps at no more than seven steps. Five would be better, but if they’re super short and not overly complicated requests, you might be able to stretch it a bit.

To build out your steps, first, decide what type of onboarding flow would be the most beneficial for your app. For example:

  • A product setup walkthrough to help users personalize their experience or get started;
  • A series of questions that help identify what type of user they are;
  • A preview of the core features;
  • A video or GIF intro that welcomes the user and shows them how easy the app is to use;
  • Powerful statistics that reinforce the transformative effects of your product.

Then start piecing them together.

To add a new screen to the flow, use the “Flow” tab on the left. Use the “+Step” button at the bottom to add a new step, or you can click the plus sign that appears beneath your existing step button when you hover over it.

In Feathery’s ‘Flow’ control tab, users can add new steps with ease. (Source: Feathery) (Large preview)

You can rename the labels of each step by double-clicking on each block. Alternatively, if you hover over the block, three vertical dots appear to the right, which gives you the ability to duplicate, rename or delete it.

Step 3: Customize The Content

In terms of what makes an onboarding flow effective, you generally want to keep the design simple — lots of white space, concise and easy-to-follow language, and motivational imagery and colors.

Each step will include a combination of imagery and text. You’ll find all of the mix-and-match components you need under the “Elements” tab in the left sidebar.

Let’s go through an example of what you might put on one of these screens from top to bottom.

Step 3a: Add a Progress Indicator

To start, place a “Progress” element at the top of the page. Whenever you have a multi-step process, providing users with visibility into their progress is a must.

You can customize everything about this progress indicator, including:

  • Length,
  • Alignment,
  • Visibility,
  • Color,
  • Font,
  • Text placement,
  • Text styling.

When designing your progress bar, consider its prominence in terms of the rest of the design. You want it to be easy to find, but not so overpowering that it distracts from the actual message on the page.

Step 3b: Customize The Text

Before adding any imagery, lay down your text layers. Ideally, each screen should contain no more than 50 words or so.

Another thing to think about with text is a hierarchy. If all of the text is the same size and styling, it could end up looking like one long block of text (even if it’s only 50 words).

To keep onboarding screens easy to read:

  • Limit the amount of text,
  • Keep it simple and jargon-free,
  • Choose a readable font,
  • Use headings at the top of the page,
  • Add bolding and italics for emphasis,
  • Place single- or multiple-choice options into blocks with visual companions.

In Feathery, use the “Text” field to add individual text layers.

You’ll have total control over how the text looks from the “Style” panel.

Step 3c: Add Imagery

With Feathery, you can add images and videos to your onboarding step designs using the corresponding elements — images you’ll have to upload from an external source, and videos will need to be hosted on YouTube and then embedded with a link.

For more complex configurations (like text and image blocks), use the element that most closely resembles what you need.

For instance, I want to create nine clickable blocks so that users can tell us how they found the app. For this, I’ll use the “Button Group” element:

You can edit the labels, add images, customize the layout and spacing, change the font, apply a border and shadow, and more.

The three side-by-side button blocks have been transformed into a colorful, custom-labeled grid of options. If they’re going to be clickable options like in this example, you’ll be able to program in hover effects to make them respond to your users’ touch.

Step 3d: Add Other Elements

You can add all kinds of interactive and attractive elements to your onboarding flows. For example:

  • Account setup/login forms;
  • File uploaders;
  • Slider selections;
  • Rating requests;
  • Payment forms.

It all depends on your goal for that step and what the easiest way to get that information across or to collect it from your users is.

Step 4: Add Navigation Buttons

Giving your users full control over their onboarding experience is going to be crucial in getting as many of them through the process as possible.

Although it’s common to place a single “Continue” button at the bottom of each onboarding step, it might be a good idea to give them extra navigation options.

For instance, let’s say the step we designed above is the first in a series of six. We can place a “Next” button on the right side of the step. A “Previous” button wouldn’t make sense, but a “Skip” button would be useful. While it’s nice to find out how people discovered our apps, it’s not totally necessary, so giving them the option to skip is good.

Both buttons are placed side-by-side here. However, the “Skip” button has been designed as a plain text link as opposed to “NEXT,” which is more prominent. You can play around with how you present the various button options to your users.

Step 5: Enable Interactivity and Connectivity

Every step you build will have at least one element of interactivity. To configure your clickable elements, use the “Properties” setting on the right toolbar.

Let’s start with the “Button” elements.

You can configure more than just links to the next steps or pages in your app. You also have the ability to:

  • Set multiple actions.
  • Disable the button if the fields aren’t submitted.
  • Create custom validation rules that need to be met.
  • Set conditional logic that determines when the button appears in the flow.
In Feathery, users can program multiple actions for button elements and force certain rules to be met. (Source: Feathery) (Large preview)

When it comes to other clickable elements in Feathery, you’ll have similar options with regard to validation rules and conditional logic. However, the other settings will differ based on what the element is.

For example, the “Button Group” element asks you to set constraints. You can allow for multiple responses. You can also make the response optional, which you’ll need if you include a “Skip” button on that screen. When it comes to form fields, on the other hand, you may need to set limits on what can be entered or uploaded.

Interactivity is an important piece of the user onboarding flow. If there are any issues with getting through the process, you’re going to lose users before they get inside your app. The rest will likely expect the app to be just as confusing or difficult to use, which won’t bode well for user attrition. So spend extra time on this step to make sure you get it right.

Step 6: Create The Flow

Depending on how you added new steps to your user onboarding flow, you might not need to do much in this step. However, it’s still a good idea to check.

To see what your flow looks like, click on the “Flow” tab on the left. Then click on the “Flow Editor” button to open your flow chart.

If you set up the steps initially to connect together, you’ll see them connected here. Additionally, if you programmed buttons to connect to other slides, you’ll see that reflected in the chart.

In addition to visualizing your flow, you can:

  • Create a new step,
  • Add new connections between steps,
  • Set the connecting element between two steps,
  • Add a condition so that different actions take users to different steps.

When you’re done, click the “Designer” button in the top-left to return to the main editor.

Step 7: Add Integrations (Optional)

There are different reasons to integrate other apps with your onboarding flow. For instance, you might want to track user engagement with a tool like Google Analytics. This would be helpful in keeping an eye on how many users are getting through each step. If they’re dropping out around the same point, your data will at least indicate where the greatest friction point is.

There are other tools that Feathery integrates with as well. Go to the “Integrations” tab at the top of your screen to find them.

You’ll be able to add a wide variety of functionality to your onboarding flows with integrations. Analytics is just the start.

For example, you can integrate with the following:

  • Firebase or Stytch to add an authenticated login step;
  • Stripe to collect one-off or recurring payment from new users;
  • Plaid to automatically collect user financial information;
  • Slack to notify your team when a new user has completed the process;
  • HubSpot to add new users to your CRM and automated email marketing campaigns.

A user onboarding form is a great way to get users into your app without the need for a sales rep or customer service associate to contact them. Adding integrations will allow you to streamline the onboarding and engagement process even more.

Step 8: Publish

When you’ve finished designing your user onboarding steps, hit the “Publish” button in the top-right corner. Use the down arrow to open a preview or the live form to see how your new onboarding flow looks and to test it out.

To add the new onboarding process to your app, use the “Publish” dropdown one more time to retrieve the JavaScript or React code.

The code will automatically be copied to your clipboard. Go into your CMS and add it wherever you want the element to appear — like in a pop-up at startup.

Wrapping Up

Is a user onboarding flow necessary? If you want to maximize conversions or collect necessary user information for other purposes, then yes.

Despite the critical role that onboarding plays in product adoption, designing a great onboarding experience for your users doesn’t have to be difficult. Whether you build it from scratch, use another app’s onboarding flow for inspiration, or start with a template, you can have a well-thought-out and beautifully designed user onboarding flow set up in no time at all.

Sign up for Feathery to start creating effective user onboarding flows of your own.

]]>
hello@smashingmagazine.com (Suzanne Scacca)
<![CDATA[How To Protect Your App With A Threat Model Based On JSONDiff]]> https://smashingmagazine.com/2023/04/protect-app-threat-model-jsondiff/ https://smashingmagazine.com/2023/04/protect-app-threat-model-jsondiff/ Wed, 05 Apr 2023 13:00:00 GMT Security changes constantly. There’s a never-ending barrage of new threats and things to worry about, and you can’t keep up with it all. It feels like every new feature creates expanding opportunities for hackers and bad guys.

Threat model documents give you a framework to think about the security of your application and make threats manageable. Building a threat model shows you where to look for threats, what to do about them, and how to prevent them in the future. It provides a tool to stay safe so you can focus on delivering a killer application, knowing that your security is taken care of.

This article will show you how to create a threat model document. We’ll review JSONDiff.com and build a threat model for it, and we’ll show how small architectural changes can have a gigantic impact on the security of your application.

Who Do You Trust?

Every time you use a computer, you trust many people. When you make an application, you’re asking other people to trust you, but you’re also asking them to trust everything you depend on.

Your threat model makes it clear who you’re trusting, what you’re trusting them with, and why you should trust them.

What Is A Threat Model?

A threat model is a document where you write down three things:

  1. The architecture of your application,
  2. The potential threats to your application,
  3. The steps you’re taking to mitigate those threats.

It’s really that simple. You don’t need complex tools or a degree in security engineering. All you need is an understanding of your application and a framework for where to look for threats.

This article will show how to build your own threat model using JSONDiff as a sample. You can also take a look at the complete threat model for JSONDiff to see the finished document.

Threat Models Start With Architecture

All threat models start with a deep understanding of your architecture. You need to understand the full stack of your application and everything it depends on. Documenting your architecture is always a good idea; you can start anytime. You’re architecting from the moment you start picking the tools you’ll use.

Here are some basic questions to answer for your architecture:

  • Where does my application run?
  • Where is my application hosted?
  • What dependencies does my application have?
  • Who has access to my application?
  • Where does my application store data?
  • Where does my application send data?
  • How does my application manage users and credentials?

Give a brief overview of your application and then document how it works. Start by drawing a picture of your application. Keep it simple. Show the major pieces that make your application run and how they interact.

Let’s start by looking at the overall architecture of JSONDiff.

JSONDiff is a simple application that runs in a browser. The source code is stored on GitHub.com, and it’s open source. It can run in two modes:

  1. The public version is at JSONDiff.com.
  2. A private version users can run in a Docker container.

We’ll draw the architecture in relation to what runs in the client and what runs on the server. For this drawing, we won’t worry about where the server is running and will just focus on the public version.

Drawing your architecture can be one of the trickiest steps because you’re starting with a blank page and have to choose a representation that makes sense for your application. Sometimes you’ll want to talk about larger pieces; other times, you’ll want to focus on smaller chunks and user actions. Ask yourself what someone would need to know to understand your security, and write that.

JSONDiff is a single-page web application using jQuery. In this case, it makes sense to focus on the pieces that run on the server, the pieces that run in the browser, and how they work.

The first step to any architecture is a brief description of what the application is. You need to set the stage and let anyone reading the architecture know some basic information:

  • What does the application do?
  • Who’s using it?
  • Why are they using it?

JSONDiff is a browser-based application that compares JSON data. It takes two JSON documents, compares them semantically, and shows the differences. JSONDiff is free for anyone and anywhere. It’s used by developers to find differences in their JSON documents that are difficult to find with a standard text-editor diff tool or in GitHub.

The architecture diagram looks like this:

The architecture is simple: Nginx hosts the site, and most of the code is in the jdd.js file. But it brings up many good questions:

  • How does JSONDiff load JSON data?
  • Does it ever send the data it loads anywhere?
  • Does it store the data?
  • Where do the ads come from?

Write down all of the questions your architecture diagram brings up, and answer them in your threat model. Having those questions written down gives you a place to start understanding the threats.

Let’s focus on the first question and show how to dig into it with a security mindset.

There are two ways to load the JSON data you want to compare. You can load it in the browser by copying and pasting it or by choosing a file. That interaction is very well understood, and there isn’t much of a threat there. You can also load the JSON data by specifying an URL, which opens a big can of worms.

Specifying a URL to load the data is a very useful feature. It makes comparing large documents easier, and you can send someone else a URL with the JSON documents already loaded. It also brings up a lot of issues.

The same-origin policy prevents JavaScript applications running in browsers from loading random URLs. There are very good reasons that this policy exists. JSONDiff is subverting the policy, and that should make your security spidey-sense tingle.

JSONDiff uses a proxy to enable this feature. The proxy.php file is a simple proxy that will load JSON data from anywhere.

Loading random data sounds like a recipe for a cross-site request forgery (CSRF) attack. That’s a risk.

All applications have risks; we manage those risks with mitigations. In this case, the proxy risk has two mitigations:

  1. The proxy can only load data that are already publicly available on the Internet.
  2. The file that’s loaded by the proxy is never executed.

Our threat model will include this risk and show how we mitigated it. In fact, each threat needs to show how much risk there is and what we did to mitigate each risk.

Let’s take a look at where threats appear in your application.

Threats

There are many categories of threats through the development and deployment lifecycles. It’s helpful to split threats into different categories and document those potential threats for our application, while we’re starting to plan, design, implement, deploy, and test that software or service.

For every threat we identify, we need to describe two pieces:

  • The threat
    What is the specific threat we’re worried about here? How could it be exploited in our application? How serious could that exploit be?
  • Mitigation
    How are we going to mitigate that threat?

Code Threats

Many threats start with the code you write. Here are a few categories of coding issues to think about:

Weak Cryptography

“Does your application use SSL or TLS for secure network connections?”

If you are, make sure that you’re using the latest recommended versions.

“Does your application encrypt data or passwords?”

Make sure you’re using the latest hashing algorithms and not the older ones like MD5 or SHA-1.

“Did you implement your own encryption algorithm?”

Don’t. Just don’t. There’s almost never a good reason to implement your own encryption.

SQL Injection

SQL injection attacks happen when a user enters values in an application that are sent directly to a database without being sanitized (like Bobby Tables). This can inject malicious code that alters the original SQL query to retrieve, change, or delete data inside the SQL database.

Avoid injection attacks by not trusting any inputs coming from users. Your threat model should address any place you’re taking user input and saving it anywhere.

JSONDiff never saves any of the JSON data it compares. If we added that feature, we’d be open to many types of injection attacks. It doesn’t matter if we saved the JSON to a SQL database like PostgreSQL, a NoSQL database like MongoDB, or a file system. We’d mitigate that threat by making sure to sanitize our inputs and never trusting data from users.

Cross-Site Scripting (XSS)

Malicious scripts can be injected into web applications, making browsers run those scripts in a trusted context; that allows them to steal user tokens, passwords, cookies, and session data. This injection attack happens when a user saves or references code from somewhere else and gets that code to run in the application security context.

JSONDiff doesn’t let users save anything, but you can build URLs to preload the documents to compare like this:

This is a clear threat to address in the threat model. If someone referenced malicious code in an URL like this and sent it to someone, they could run it without realizing the risk. JSONDiff mitigates this threat by using a custom parser for the inputs and making sure that none of them get executed. We can test that with ‘evil’ JSON and JavaScript files like this:

Consider all of the inputs to your application and how you’re making sure they can’t cause problems.

Cross-Site Request Forgery (CSRF)

CSRF attacks wait for you to log in and then use your credentials to steal data and make changes. Session-based unique CSRF tokens can be used to prevent such an attack. Examine everywhere your application uses sessions. What are you doing to make sure sessions can’t be shared or stolen?

JSONDiff doesn’t have sessions, so there’s nothing to steal. Adding the ability to manage sessions and login would create a large set of new threats. The threat model would need to address protecting the session token, making sure that sessions can’t be reused, and ensuring that sessions can’t be stolen, among other things.

Logging Sensitive Information

Your logs aren’t secure, so don’t put any sensitive information there. Logging passwords or other sensitive customer information is the most common security issue in building an application: developers log some activity or error, and that contains the token or password information or personal information about the user.

What are you doing to make sure that developers don’t log sensitive information? Make sure your code review includes looking at logging output. There are also password scanners you can run over your log files to find likely passwords.

Code Review And Separation Of Duties

Trust, but verify, as some people on your team will be malicious. Everyone on your team makes mistakes — trust your team, but verify.

The best way to verify this is to separate the roles within your team. Allowing one person to change code, test it, and push it to production without any oversight presents a risk. Separation of duties splits the stages of your pipeline to production into multiple stages. There are four clear stages in every application that you should separate as much as possible:

  1. Writing the code,
  2. Reviewing the changes,
  3. Testing the functionality,
  4. Deploying the application.

For small projects, these roles may overlap or be part of an automated process. Even when the pipeline is fully automatic, you can still separate the functions. For example, making sure that the owner of a given area didn’t write all the tests for that area ensures that someone else is verifying the functionality. In well-run projects, these roles can switch so everyone gets a turn to write code as well as review it or write tests as well as do deployments.

JSONDiff is an open-source application that makes review much easier. For closed-source applications, you can use the Pull Request mechanism in Git to ensure all code is reviewed for the issues mentioned above. Spend time with your team and teach them what they should look for during code review.

Static code analysis tools also help detect security threats and other issues. These tools include linters and code checkers like JSHint, along with more comprehensive security scanners. These tools look at your source code and find problems based on the specific programming language you’re using. OWASP maintains a list of static analysis tools.

Many security scanners use common vulnerabilities and exposures (CVE) databases to know what issues to look for. Integrating these tools into your build process ensures that all your changes will be scanned.

The code for JSONDiff was scanned by JSHint, and all issues were fixed, or so I thought. It turned out that I scanned the JavaScript, but I missed the server side. My co-author Terry ran the SonarQube lint scanner and found an error in the PHP proxy:

This small fix is a great example of how a second pair of eyes can help you find problems.

Third-Party Threats

Your application has dependencies and probably a lot of them. They may be from other groups or open-source projects. The list of all these dependencies and the versions they use makes up a Software Bill of Materials (SBOM).

When the teams who maintain the projects you depend on find security issues, they report them in a CVE database. Other security professionals report CVEs as well. Third-party scanners look at those databases and make sure you aren’t using dependencies with known security issues.

Static application security testing (SAST) tools like Snyk can also scan third-party threats and report vulnerabilities in the libraries you’re using. Those vulnerabilities are then scored by severity, so you know how seriously to take each threat.

Tools like NPM have built-in vulnerability checking for dependencies. Integrating vulnerability checks in your build process mitigates that threat.

Data Security Threats

Protecting your application means protecting the application data. Always make sure your data is transmitted and stored with confidentiality, integrity, and availability.

Here are some of the risks to data security:

  • Accidental data loss or destruction,
  • Malicious access to confidential data like financial data,
  • Unauthorized access from various partners or employees,
  • Natural disasters or uncontrollable hazards like earthquakes, floods, fire, or war.

To mitigate those risks, we can implement these actions:

  • Protect the data with strong passwords, and define the policy for password expiration.
  • Categorize the data with different classes and usage, and define the different roles that can access different levels of data.
  • Always do an authorization check to make sure only a permitted user with the corresponding role can access that level of data.
  • Deploy various security tools like firewalls and antivirus software.
  • Encrypt your data at rest (when it’s stored somewhere).
  • Encrypt your data in transit (when it’s moving between two points).

JSONDiff doesn’t store any data. Let’s think about the in-transit threat:

  • The threat
    JSONDiff loads data from any URL to compare. How are we protecting that data?
  • Mitigation
    JSON uses SSL encryption when loading data if it’s available and always uses SSL to encrypt data sent to the browser.

Runtime Threats

After the application is deployed and running, we need to consider the runtime threats.

The best way to find runtime threats is a penetration test from a team of experts. Pen-test teams pretend they’re hackers and attack your application. They attack your external interfaces and look for SQL injection, cross-site scripting, denial of service (DDOS) attacks, privilege escalation attacks, and many more problems.

If you can afford an external pen-test team, then use one, but you can also do this yourself. Pen-test tools like the OWASP ZAP proxy perform dynamic scanning on your application endpoints and report common threats.

Threats To Stability

Availability attacks try to disrupt your application instead of hacking it. High availability and redundant designs mitigate the threat of these attacks.

There are several things we can consider to build up plans for those threats:

  • High-availability infrastructure, including the network and server. If we deploy the application via the cloud, we can consider using multiple regions or zones and set up a load balancer.
  • Redundancy for the system and data. This will improve stability and availability, but the cost will be high. You can balance stability and cost: Only make your most critical components redundant.
  • Monitoring of system and setup alerts if the system might be running at capacity in various components. There could be a malicious activity that will destroy your infrastructure, and monitoring the health of your system availability will be critical.
  • Backup and restore plans. If security threats take the system down, how can we quickly bring it back up? We need to build a plan for backing up and restoring.
  • Handling outages of dependent services. We need to build up some fallback plans, design and implement circuit breakers, and keep dependent services from breaking the entire application.

Building A Data Recovery Plan

What can disrupt your application or system? Think about human error, hardware failure, data center power outages, natural disasters, and cybersecurity attacks.

Business continuity and disaster recovery (BCDR) design will be critical to ensure that your organization, users or customers, and employees can do business with minimal disruption.

For an organization like a company, you’ll need to create a business continuity plan. That means first assessing your people, IT infrastructure, and application. Identify people’s roles and responsibilities for your business continuity plan and recovery solutions.

If you’re deploying your application in a cloud-based environment, you need to deploy it across multiple regions or multiple cloud providers. The critical part is the data storage for the system and application: All data should have point-in-time replication, allowing your application or service to be restored soon from a secondary data center or a different country or continent.

Your BCDR solution should be regularly tested every year (or even more often), and your plan should be frequently reviewed and improved by the people in your organization.

The Worst-Case Scenario

Threat models provide a framework to imagine the worst-case scenario, which helps you think outside the box and come up with novel threats.

So what’s the worst-case scenario for JSONDiff? It probably involves the proxy.php script. We already know to focus on the proxy, and there have been some severe PHP exploits in the past. The proxy.php file is also the only part that runs on the server side. That makes it the weakest link.

If I was able to hack the proxy, I could change the way it works. Maybe I could fool it into returning different content. I can’t run malicious code with that content, but I could trick someone into thinking two JSON documents were the same when they weren’t; I might be able to do something malicious with that.

I could go even further and think about what would happen if someone hacked into the server and changed the contents of the code, but now I’m just back to credential management, which is already covered in the threat model.

This reminds us to keep up to date with PHP versions, so we get the latest security fixes.

Thinking of the worst-case scenario sends you in different directions and improves your threat model.

We’re Just Scratching The Surface

We’re just scratching the surface of all the threats to think about when building a threat model. Mitre has an excellent matrix of threats to think about when building your own threat model. OWASP also maintains a Top 10 list of security risks and a Threat Modeling Cheat Sheet that everyone should be familiar with.

The most important takeaway is that you should think about all the ways people interact with your application and all the ways your application interacts with other systems. Any time you can simplify those interactions, you’re reducing your vulnerability to threats.

For more complex threat models, making a threat diagram is also useful. Tools like draw.io have specific shapes for threat modeling diagrams:

What If I Can’t Mitigate A Threat?

You can’t mitigate every threat. For JSONDiff, a threat I have no control over is Google AdSense, which adds dynamic content to JSONDiff.com. I don’t get to check that content first. I can’t verify every ad that Google might show. I also can’t force Google to go through a security review process for my site. In the end, I just have to trust Google.

In the rare cases when you have a threat you can’t mitigate or minimize, the best you can do is settle for transparency. Be as open and honest about that threat as possible. Document it. Let your users or customers know, so they can make their own choices about whether the risk is worth it.

Build Your Threat Model Early

Threat models help the most when begun early in the process. Start putting your threat model together as soon as you pick technologies. Decisions about how you’ll manage users, where you’ll store data, and where your application runs all have a major impact on the threat model of your application.

Working on the threat model early, when it’s easier to make architectural changes, makes it easier to fend off threats.

Communicating Your Threat Model

The previous section showed you how to start creating your threat model. What should you do with it once you’re done?

There are a few potential audiences for your threat model:

  • Security reviewers
    If you create an application for any security-conscious company, it will want to do a security review. Your threat model will be a requirement for that process. Having a threat model ahead of time will give you a giant head start.
  • Auditors
    Security auditors will always look for a threat model. They want to make sure you’ve thought through the threats to your application.
  • Yourself
    Use your own threat model to manage your threats. Have the team keep it up to date while you’re adding new features. Making sure that team members update the threat model will force them to think of any potential threats they’re adding when they make changes.
  • Everyone
    If your project allows it, then share your threat model with everyone. Show the people who trust your application the potential threats and how you’re handling them. Openness reassures them and helps them appreciate all the work you’ve done to make your application secure.
Keep Improving Your Threat Model

We talked about the most important steps in constructing a threat model, but threats are a constantly moving target. We need to build up a management plan for security incidents, defining how to respond to any threats we learn about from internal or external sources.

Every incident you find should end up in your threat model. Document how you found it, how you fixed it, and what you did to make sure it never happens again. Every application has security issues; what matters is how well you handle them. This is a continuous process of improvement:

  1. Build the architecture to understand what the application is for.
  2. Identify the application threats.
  3. Think about how to mitigate the identified vulnerabilities.
  4. Validate the threat model with other experts in your area.
  5. Review the threat model, and make updates every time you find a new threat.
Threat Models Let Me Sleep At Night

I make threat models for myself. I want to sleep at night instead of staring at the ceiling and wondering what security holes I’ve missed. I want to focus on delighting my users without constantly worrying about security. Threat models give me a framework to do that.

I make threat models for my customers. I want them to know that I take their security seriously, and I’m thinking about keeping them secure. I want to show them what I’m doing and help them understand so they can judge for themselves.

Threat models are flexible and grow or shrink as much as you need. They provide a tool for you to reassure your users about security and allow you to sleep at night. Now you know why you need one for your application, too.

]]>
hello@smashingmagazine.com (Zack Grossbart & Terry Yao)
<![CDATA[Beyond Algorithms: Skills Of Designers That AI Can’t Replicate]]> https://smashingmagazine.com/2023/04/skills-designers-ai-cant-replicate/ https://smashingmagazine.com/2023/04/skills-designers-ai-cant-replicate/ Mon, 03 Apr 2023 10:00:00 GMT At the start of the Coronavirus pandemic, I led the redesign of a tablet app used by sales representatives of the world’s largest food & beverage company. Never having been a sales representative, nor having ever played one on TV, I was curious about their typical workday. Adapting the first rule of design — Know Thy User — our lockdown approach was to conduct video interviews. As soon as company restrictions allowed, I met two sales representatives at a local Walmart.

Masked and socially distant, I walked a mile in their shoes through the dairy, pet food, and freezer aisles. This single visit uncovered many insights that had not come up in the video interviews and online walkthroughs. I shared this with the team, spread across the world, and everyone could empathize with the sales representatives: juggling multiple devices and printouts, struggling to make technology work in extreme conditions like a low-lit walk-in freezer, and trying to work without hindering harried shoppers. The sales reps would repeat these tasks between twenty and thirty times a day, five days a week, which sounds about as fun as it is.

Our team used these insights to experiment with different concepts, refine them based on feedback from sales representatives, and launch a redesigned app that received glowing feedback from the representatives and praise from the company stakeholders.

Curiosity, empathy, and collaboration were some of the designer-like or designerly behaviors we used to transform the sales representatives’ experience. These behaviors are a few of the behaviors and skills that designers use throughout the design process. Design researcher and educator Nigel Cross first used the word designerly to refer to underlying patterns of how designers think and act.

Designers spend years learning technical design skills, and as they use those hard skills to do their jobs, their designs are impactful when they actively use these non-technical designerly skills and behaviors. Designerly skills and behaviors make us creative and innovative and distinguish us from machines and technology like Artificial Intelligence (AI).

Yes, the same AI that you can’t avoid reading or hearing about on social media or in the news. Stories and posts about people being equally worried about layoffs and AI taking over their jobs, and some even suggesting that AI is why those jobs won’t come back. Creators and people traditionally considered creative, like artists, writers, and designers, seem especially concerned about AI making them redundant. Guesstimates of when AI will perform tasks better than humans just add to the frenzy.

The assumption that AI will replace people is based on the premise that both have the same qualities, abilities, and skills. But that’s just not true. Artificial intelligence is simply technology that is taught to mimic human intelligence to perform tasks. It is trained on large amounts of data — by some estimates, the equivalent of a quarter of the Library of Congress, the world’s largest library.

AI is better than humans in certain tasks that involve processing and analyzing large amounts of data quickly, accurately, rationally, and consistently. Artificial Intelligence may create, but it can’t be creative. It cannot match humans in areas that rely on skills and behaviors that are distinctly human, like intuition, emotional intelligence, cultural context, and changing situations.

Humans are conscious beings with a subconscious mind that can influence decisions and change those decisions based on experience, context, environment, wisdom, and understanding. This takes us years, decades, and even a lifetime to learn and apply, and it cannot be programmed in machines, no matter how sentient they may appear to be. Not for the foreseeable future.

Being designerly takes thinking, feeling, and acting like a designer. I’ve been thinking about and observing what it means to be designerly, and by using six such skills and behaviors, I will discuss how humans have an advantage over AI. I used the head, heart, and hands approach for transformative sustainability learning (Orr, Sipos, et al.) to organize these designerly skills related to thinking (head), feeling (heart), and doing (hands), and offer ways to practice them.

Using our head, heart, and hands together to make a transformative difference is what distinguishes us from AI and makes us human, creative, and innovative.

Head

The skills, behaviors, and habits to help you think like a designer and create a designerly mindset include curiosity and observation.

Cultivate Curiosity

Curiosity is the desire to know. It is a pleasure to ask, explore, experiment, discover, learn, and understand. We see this relentless curiosity in small children, who explore everything novel around them. As they grow up, that curiosity starts getting stifled in many, partly because they are taught to look for an answer instead of exploring questions.

This curiosity stifler of focusing on the answer is what AI is programmed to do. AI is also limited by its knowledge and understanding of the world, unable to explore beyond those boundaries. Also, without physical senses, AI cannot experience the world and be curious about things we see, hear, touch, taste, and smell around us.

This gives us a leg up on AI if we can overcome other curiosity-stiflers like self-consciousness, the shame of not knowing, and the fear of ridicule.

Let’s deconstruct curiosity to understand different types of curiosity we can nurture and build in ways AI cannot. In the 1950s, British-Canadian psychologist Daniel Berlyne presented a model distinguishing between two types of curiosity: perceptual, based on stimulation, and epistemic, driven by a genuine desire for knowledge. He also distinguished between two types of behaviors to address that curiosity: diversive exploration, motivated by a need for novel stimulation or a desire to explore, and specific exploration, motivated by curiosity and a search for new information.

This gives us four dimensions of curiosity, which have their time and place, but the quadrant we are discussing lies at the intersection of the desire to explore and the desire for knowledge. Diversive-Epistemic curiosity is where people use the desire to explore and apply it to learning new things. TED Talks are an example of knowledge exploration, where people can learn about just about any topic they care to explore.

You can cultivate curiosity by being intentional in developing the joy of exploration. Set some time aside every day to learn something new, and pick topics that interest you. Start small and gradually increase the time you spend learning something daily as well as for expanding the topics. I would suggest starting with just 10–20 minutes a day. That’s enough time to watch a TED talk, read a book summary, or start learning a new skill. Reading multiple book summaries on a topic is an easy way to identify the next book you should read cover to cover over a few days or weeks.

Curious exploration broadens the mind to new ideas, perspectives, and approaches, lays the foundation for the cross-pollination of ideas, and leads to creative and innovative solutions.

Advantage: People

Notice & Observe

While often used as synonyms, noticing is seeing something for the first time, while observing is paying close attention to something or someone. Being creative begins with noticing what others have overlooked, followed by closer, intentional observation when warranted.

In traditional ethnography, researchers observe people and cultures in an immersive manner. Design ethnography or digital ethnography is not as extreme; researchers and designers only spend days or weeks observing users, instead of years. The operative word is observing — watching and listening. The payoff is that ethnography can inform and improve design decisions. You don’t need to wait for your next project to observe people. Instead, make it an everyday habit, and you will not only hone your powers of observation, but it will also gradually become second nature.

AI cannot do this because it relies on the limited data it is trained with, unlike people who have an unlimited ability to notice and observe new things all the time. Even if it could overcome that hurdle, without emotions and context, AI would not be able to understand the feelings and emotions involved in the people or situation being observed. We can observe a situation and understand the context and meaning behind it as we process what we are noticing and observing.

We can build our power of observation by taking the time to pay attention to people and their behavior. You can do this anytime — while you are in a coffee shop or waiting in the grocery checkout line. Get your nose out of that glowing rectangle, remove your headphones, and look around. While you may end up seeing others captivated by their own glowing rectangles, start observing the details:

  • What type of phones are they using?
  • Are they passively consuming content or actively interacting with a game or person?
  • What emotions do you notice?

When you start paying attention, you will be surprised by things you may have seen but not noticed or observed in the past. And the more you practice, the more natural it will become. Noticing and observing the world around you in new and different ways provides inspiration and helps reveal issues and patterns, leading to better ideas and solutions.

Advantage: People

Heart

The skills, behaviors, and habits to help you feel like a designer and create a designerly attitude include empathy and advocacy.

Be Empathetic

My favorite definition of empathy is by Roman Krznaric in his book, Empathy: Why It Matters, and How to Get It:

Empathy is the art of stepping imaginatively into the shoes of another person, understanding their feelings and perspectives, and using that understating to guide your actions.
— Roman Krznaric

There are three types of empathy, according to psychologists Daniel Goleman and Paul Ekman:

  1. Cognitive,
  2. Emotional,
  3. Compassionate.

The empathy that results in thinking, feeling, and doing are all important and have their place in our lives, but the empathy that results in doing, compassionate empathy, goes beyond understanding others and sharing their feelings by driving us to do what we can to help them. This helps us make a difference in people’s lives. I am talking about genuinely employing empathy, not doing it as lip service or checking a box off in the process.

Successful designers routinely use empathy in human-centered design. They start with an understanding of the people they are designing for by observing them and immersing themselves in their users’ environments. Designers then apply that deep understanding to design products and experiences that work for those users.

While AI can measure people’s emotions from their expressions and is being trained to mimic human emotions, AI machines and tools don’t have consciousness and cannot understand or experience emotions. AI also lacks personal, shared experiences that allow us to show empathy to varying degrees.

Even if you are not empathetic by nature, try building it over the coming days with one or more interactions with others:

  • Suspend judgment.
    It is difficult to be empathetic if you are mentally judging the other person. If you voice that judgment, you will not be able to be empathetic, and the other person may stop sharing with you.
  • Listen attentively with your eyes and ears.
    Engage more than one sense to listen actively so that you can respond deeply. Pay attention to what the other person is saying, not how you need to respond. Be completely present with the other person, putting aside our modern distractions.

Being empathetic takes practice for most of us. Be empathetic.

Advantage: People

Advocate For Others

User advocacy is at the heart of designerly skills and behaviors. The skills and behaviors of curiosity, observance, and empathy create a deep understanding of users and their needs, but that is only the beginning. User advocacy brings all of the above to life and turns that respect for the user into action to address their needs. It also shares that understanding with others involved so they, too, can identify with users.

Being a user advocate means representing the interests of users in an ocean of competing interests. A user advocate represents the user throughout the design process, giving the user a voice, bringing them to life, and making the impersonal user personal.

Without curiosity, observation, and empathy, AI is unable to use those skills and behaviors to be an advocate. AI also lacks the creativity to come up with solutions to address the needs of others. AI can be programmed to follow rules and guidelines to protect people, an increasingly important area of ethical AI. If you’ve been following the news, this has led to mixed results, sometimes going off the deep end in some instances. No points for guessing that AI cannot make ethical judgment calls on its own.

However, people can do that. And we can manifest it in design by doing what’s right for users. I previously wrote about principles for designers; two of them summarized below:

  • Do no harm.
    Your decisions may affect the minds, behavior, and lives of your users and others around them, so be alert and guard against misusing the influence of your designs. Ask yourself: Would you be comfortable with someone else using your design on you, your parents, or your child?
  • Be aware of your responsibility to your intended users, unintended users, and society at large.
    Accept appropriate responsibility for the outcomes of your design. During design, follow up answers to “How might we…?” with “At what cost?”

Remind yourself that you are not the user and use your knowledge of the user to represent the user when they are absent. Advocate for them.

Advantage: People

Hands

The skills, behaviors, and habits to help you act like a designer are brought to life through visual communication and collaboration.

Communicate Visually

Storytelling is an important skill that vividly paints a picture in people’s minds, driving them to action. It converts words to a visual that people will remember, but even then, different people may all visualize the same thing differently. This happens whether you’re listening to your favorite inspirational speaker or reading your favorite fiction author. No matter how painstakingly a speaker or author describes a character or a situation, chances are high that two people sitting right next to each other both have different images in their minds. However, when there is an accompanying image or visual, people are literally on the same page (or slide, graph), which slashes the risk of them imagining different things. That’s the power of thinking and communicating visually.

Not all designers are artistic, but you don’t have to be artistic to be a visual thinker or communicator. Even a rough sketch on a whiteboard or a notepad can often communicate information faster than the written or verbal form. The aim is to make ideas tangible quickly, to get to the right idea faster. User researchers and designers commonly use visualizations to help them make sense of data and come up with new ideas.

Without physical senses, AI cannot think or communicate visually. Without emotions, the ability to understand context, and creativity, AI cannot ‘read the room’ or come up with ideas outside its dataset and communicate outside its current language abilities, making visual communication impossible. However, people can use AI as a tool to communicate visually, especially with tools that convert text prompts to images.

Next time you describe something, instead of writing a page of instructions or talking it out, use a quick sketch. Describing a process? Boxes and arrows are very powerful. Talking about a screen or two? A rough layout, highlighting the important parts, along with an arrow showing how you get from one to another, is more powerful. Or a quick screen recording. Sketching not your thing? Use images. I’ve been known to use LEGO photography in my articles and presentations. You can also mock up something without advanced design tools. For instance, I had a non-designer boss who communicated visually using PowerPoint. And if you are in the mood to explore and experiment, try one of the many AI text-to-image generators.

Show. Don’t only tell.

Advantage: People

Collaborate

We can achieve much more, much faster, working together. It is uncommon for a single person to come up with the best solution by themselves. Gone are the days of the lone designer working on a solution by themselves. No single person or discipline has the answer to all problems, design or otherwise. It usually takes a team from different disciplines and backgrounds to solve big problems.

A multi-disciplinary team working together toward a common goal is an example of collaboration. This brings different perspectives into the creation process, from idea generation to providing feedback and validation during the creation process.

Collaboration relies on understanding and navigating social dynamics. While some people struggle with that, AI fails. Ditto for the ability to negotiate or compromise. Some people struggle with that too, but AI cannot unless specifically programmed to. Collaboration also requires the ability to adapt based on live inputs, feedback, or the situation, which traditional AI has limited capability to do beyond its training phase.

That said, AI can support collaboration if you think about people collaborating with AI tools. We’ve seen how AI tools can generate designs, logos, layouts, code, write content, do homework, and generate legal documents. But there are enough examples of it being plain wrong, which is why we should use them as assistants in our workflow.

AI tools can support the efforts of designers and researchers by reducing manual human effort (e.g., transcribing), making people more efficient and saving time (e.g., text-based video editing), providing machine learning-based insight (e.g., attention prediction), and augmenting human effort (e.g., AI evaluation). Just remember that AI is not perfect, and there are plenty of mistakes and errors, as shown below (I’m not India-based, did not write The UX Book, and never taught at the schools mentioned).

Next time you are working on a project, get others involved. These could be different departments, different specialties, different backgrounds, and, where appropriate, even customers — maybe even AI.

Advantage: People

Conclusion

I’ll use an analogy from the restaurant industry of chefs and cooks to draw parallels between humans and AI. Chefs can cook meals by themselves, but they are more effective when they focus on the strategic work of planning the menu, overseeing the cooks who tactically follow recipes, sometimes improvising, and applying the finishing touches before the meal is served to customers. Robots have replaced parts of what cooks do and technology that may suggest recipes and meals, but it still needs the chef to make the final decisions.

Artificial Intelligence is changing the way we work and live, making us more efficient. As designers, we can use AI to support ideation, analyze data, generate variations, and predict behavior based on patterns. This will free us up to focus on more strategic aspects of design, using the designerly skills above which are impossible to duplicate, and for which people have the advantage over AI. We can use AI to make us more efficient and allow us to do what we do best — understand our users, stakeholders, and real-world constraints and then collaborate with others to design successful solutions. What we do won’t change as much as how we do it, with AI augmenting, instead of replacing us.

Advantage: People

AI cannot be trained to mimic these designerly skills the way we can practice and develop them because it is not conscious, cannot adapt, and does not have the experiences, emotions, or intuition that we have. AI can artificially mimic some but cannot match human abilities in these areas. Skills like curiosity, observation, empathy, advocacy, visual communication, and collaboration are key non-technical skills to help us use the head, heart, and hands together to be more designerly and thrive in a world of AI.

Resources:

Links

Books

]]>
hello@smashingmagazine.com (Lyndon Cerejo)
<![CDATA[Swing Into April (2023 Wallpapers Edition)]]> https://smashingmagazine.com/2023/03/desktop-wallpaper-calendars-april-2023/ https://smashingmagazine.com/2023/03/desktop-wallpaper-calendars-april-2023/ Fri, 31 Mar 2023 08:00:00 GMT New month, new wallpapers! To cater for a fresh dose of colorful inspiration every month, we embarked on our monthly wallpapers journey over 12 years ago. It’s the perfect occasion for creatives to put their design skills to the test, indulge in a little project just for fun, or tell a story that matters to them. Of course, it wasn’t any different this time around.

In this post, you’ll find beautiful, unique, and inspiring wallpapers for April 2023 created with love by artists and designers from across the globe. All of them are available in versions with and without a calendar and can be downloaded for free. At the end of the post, we also compiled a little best-of from past April editions for you. Maybe you’ll rediscover one of your almost-forgotten favorites in there, too? A big thank you to everyone who shared their designs with us! Happy April!

  • You can click on every image to see a larger preview,
  • 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 a wallpaper!
    Did you know that you could get featured in our next wallpapers post, too? We are always looking for creative talent.
The Loneliest House In The World

“March 26 was Solitude Day. To celebrate it, here is the picture about the loneliest house in the world. It is a real house, I found it on Youtube.” — Designed by Vlad Gerasimov from Georgia.

April Showers

“April Showers bring hedgehogs under flowers!” — Designed by Danaé Drews from the United States.

Kitten Season

“Lover of cats and it is indeed the season!” — Designed by Shannon Corr from New York.

Puddle Splash

“I designed this playful and fun wallpaper inspired by nature that is present during the early spring.” — Designed by Marla Gambucci from the United States.

Le Printemps Est Rose

“Spring has arrived in Paris. We go to the Sacré-Cœur and enjoy the sunset or the sunrise. There it seems that time has stopped.” — Designed by Veronica Valenzuela Jimenez from Spain.

Fresh Kicks

“Spring time means the nicer weather is rolling in, so that means the nice shoes roll out as well.” — Designed by Alex Shields from the United States.

I “Love” My Dog

Designed by Ricardo Gimenes from Sweden.

To Be Or Not To Be?

“Capture the essence of Bard’s time with this William Shakespeare calendar for April. With intricate details and period-specific clothing and accessories, this calendar is a stunning work of art that transports you to the world of Elizabethan England.” — Designed by PopArt Studio from Serbia.

Free As A Bird

“In this beautiful weather, these kids are enjoying their moment freely, just like a bird in an endless sky.” — Designed by Kasturi Palmal from India.

First Day Of Spring

“April is my birthday month! Creating this wallpaper was a reminder of the new beginnings spring brings!” — Designed by Marykate Boyle from the United States.

Spring Doodles

Designed by Kristina Zenga from the United States.

An Eerie Village

“I designed the wallpaper to bring an eerie atmosphere, strange occurrences, and mysterious happenings. The houses and buildings may be dilapidated and abandoned, with overgrown vegetation and creaking doors. There might be strange symbols etched on the walls or the ground, and street light may be seen flickering in the darkness. The villagers along with the animals might appear suspicious and reclusive, adding to the overall feeling of unease. In an eerie village, it often feels like something is not quite right, and the sense of foreboding and danger can be palpable. Hope you like this wallpaper! :)” — Designed by Hrishikesh Shome from India.

Goose Picnic

“I love fashion and nature, so I wanted to combine those two ideas into the wallpaper. I wanted something bright and colorful.” — Designed by Jennifer Flynn from the United States, NJ.

Spring Moonlight

“The days are getting warmer, and so are the nights!” — Designed by Gabrielle Ziegler from the United States.

Granthagar

“The history of libraries began with the first efforts to organize collections of documents. Topics of interest include accessibility of the collection, acquisition of materials, arrangement and finding tools, the book trade, the influence of the physical properties of the different writing materials, language distribution, role in education, rates of literacy, budgets, staffing, libraries for targeted audiences, architectural merit, patterns of usage.” — Designed by Bhabna Basak from India.

Ice Scream

Designed by Ricardo Gimenes from Sweden.

Bright Intricacy

Designed by Nick Morrow from Pennsylvania.

Flower Shop

Designed by Allison McDermott from the United States.

The Slimeguy

“April brings with it a fun warmth, it reignites childlike wonder with the world around us. I wanted to capture that in the energy of this happy Slimeguy, as well as with my mostly yellow-toned colors. He leaps forth onto your screen with an abstract warmth and energy one can only find in the springtime.” — Designed by Jad Tindall from United States.

Spring Moon Moth

“Lunar moths, much like spring itself, represent new beginnings and fresh starts. In April, the nights are still crisp and cold, but you can finally start to see the stars.” — Designed by Anna Warkentin from the United States.

Long-Awaited Blooming April

“Long-awaited spring inspired our designers to create a set of wallpapers dedicated to its blooming and greenery. We have more April wallpapers in our selection.” — Designed by MasterBundles from Ukraine.

Oldies But Goodies

From wallpapers celebrating cherry blossom season to love messages to coffee, chocolate, and rainy days, below we compiled some April favorites from 12 years of wallpapers posts. Please note that these designs don’t come with a calendar.

Swing Into Spring

“Our April calendar needs not mark any special occasion — April itself is a reason to celebrate. It was a breeze creating this minimal, pastel-colored calendar design with a custom lettering font and plant pattern, for the ultimate spring feel.” — Designed by PopArt Studio from Serbia.

Dreaming

“The moment when you just walk and your imagination fills up your mind with thoughts.” — Designed by Gal Shir from Israel.

Coffee Morning

Designed by Ricardo Gimenes from Sweden.

Clover Field

Designed by Nathalie Ouederni from France.

Ready For April

“It is very common that it rains in April. This year, I am not sure… But whatever… we are just prepared!” — Designed by Verónica Valenzuela from Spain.

Happy Easter

Designed by Tazi Design from Australia.

Sakura

“Spring is finally here with its sweet Sakura’s flowers, which remind me of my trip to Japan.” Designed by Laurence Vagner from France.

Rainy Day

Designed by Xenia Latii from Berlin, Germany.

The Perpetual Circle

“Inspired by the Black Forest, which is beginning right behind our office windows, so we can watch the perpetual circle of nature, when we take a look outside.” — Designed by Nils Kunath from Germany.

Inspiring Blossom

“‘Sweet spring is your time is my time is our time for springtime is lovetime and viva sweet love’, wrote E. E. Cummings. And we have a question for you. Is there anything more refreshing, reviving, and recharging than nature in blossom? Let it inspire us all to rise up, hold our heads high, and show the world what we are made of.” — Designed by PopArt Studio from Serbia.

An Era Of Metals With Sense Of Touch

“In the future we can expect that machines will have emotions and they will start loving nature and flowers.” — Designed by Themesvillage from London.

A Time For Reflection

“‘We’re all equal before a wave.’ (Laird Hamilton)” — Designed by Shawna Armstrong from the United States.

Spring Fever

“I created that mouse character for a series of illustrations about a poem my mom often told me when I was a child. In that poem the mouse goes on an adventure. Here it is after the adventure, ready for new ones.” — Designed by Anja Sturm from Germany.

Yellow Submarine

“The Beatles — ‘Yellow Submarine’: This song is fun and at the same time there is a lot of interesting text that changes your thinking. Like everything that makes The Beatles.” — Designed by WebToffee from India.

In The River

“Spring is here! Crocodiles search the hot and stay in the river.” — Designed by Veronica Valenzuela from Spain.

Ipoh Hor Fun

“Missing my hometown’s delicious ‘Kai See Hor Fun’ (in Cantonese), that literally translates to ‘Shredded Chicken Flat Rice Noodles’. It is served in a clear chicken and prawn soup with chicken shreds, prawns, spring onions and noodles.” — Designed by Lew Su Ann from Brunei.

Sweet April Showers Do Bring May Flowers

“Discover the seasonal fruits and vegetables in April: artichoke and beans walking in the rain!” — Designed by Vitaminas Design from Spain.

Citrus Passion

Designed by Nathalie Ouederni from France.

Wildest Dreams

“We love the art direction, story and overall cinematography of the ‘Wildest Dreams’ music video by Taylor Swift. It inspired us to create this illustration. Hope it will look good on your desktops.” — Designed by Kasra Design from Malaysia.

Relax!

“…and enjoy your Easter holidays with some good chocolate.” — Designed by Ricardo Gimenes from Sweden.

Springtime Sage

“Spring and fresh herbs always feel like they compliment each other. Keeping it light and fresh with this wallpaper welcomes a new season!” — Designed by Susan Chiang from the United States.

]]>
hello@smashingmagazine.com (Cosima Mielke)
<![CDATA[A Comprehensive Checklist For Running Design Workshops]]> https://smashingmagazine.com/2023/03/organizing-design-workshops-checklist/ https://smashingmagazine.com/2023/03/organizing-design-workshops-checklist/ Thu, 30 Mar 2023 13:00:00 GMT The more workshops you organize, the better you realize how similar they actually are, regardless of the methodology or tool used. I would like to share a comprehensive checklist that will help you prepare for any workshop and take care of all the tiny details (i.e., enablers of the workshop’s success).

Table Of Contents

You can jump directly to the topic you’re interested in or browse through all the steps. Enjoy!

Step 1: Scoping

Problem

The better you understand a problem, the smoother your workshop will be. If you cannot name a problem, the workshop will fall apart.

What problem are you trying to solve?

Don’t skip this step while striving to come up with a robust solution. If you notice a workshop goes sideways at some point, you can always say, “Wait a minute. What problem are we trying to solve?” and refer to the agenda where it’s written.

Remember to formulate the problem negatively (risk of…, lack of…, low…, prefixes ‘un’ and ‘in’). Otherwise, it might not be a real problem but rather an attempt to push your preconceived solution.

Is a workshop the right choice?

Workshops are a tool. They require much preparation but help tackle problems where conventional methods — presentations or discussions — won’t help. Here is what workshops are capable of:

  • Align people: let them exchange opinions and reveal contradictions, not just be informed about something.
  • Reach agreements: resolve conflicts and create a joint action plan, vision, or set of principles.
  • Engage people: excite them about the topic and let them contribute.
  • Have fun: let the team also feel entertained during hard brainwork.

If you want to share fully reliable and accurate information, there is no need to arrange a workshop; a simple meeting will do.

Context

A problem doesn’t exist in a vacuum. There is a chance someone has tried to solve or investigate it before. Turn it to your advantage.

What information is already available?

You don’t want people to write known information again from scratch (it’s just wasting their time) or hear such complaints as:

  • “If only I knew you would need this, I would prepare it properly.”
  • “We already have it, and here is a Confluence link.”

What information can you prepare in advance?

Starting from an empty canvas rarely works in actual business conditions, and here is how you can prepare:

  • Partially pre-fill the workshop canvas with available facts.
  • Create a structure where participants will add their information.
  • Place essential reference information on the side of the canvas.
  • Share pre-reading with participants (documents to review, Loom videos to watch, questionnaires to fill in, and so on).

Expected Output

Planning a workshop is thinking backward. Visualize the ideal result at the beginning, and you won’t be stuck while composing its agenda.

What deliverable will you produce at the end?

Depending on the problem defined in the previous step, you may want to prepare a certain artifact after the workshop, for example:

  • Not clear what to do → an action plan;
  • Efforts without a focus → a list of priorities;
  • Dependencies and many parallel projects → a roadmap;
  • Broken processes → a guideline;
  • Many contradicting opinions → a vision document;
  • Lack of understanding → visualization or storyboard, and so on.

Note: There might be an immediate deliverable right after the workshop and a more elaborate one to be created later.

Who and how will use this deliverable?

Think of it in advance not to produce something people won’t find useful (even if it’s objectively great). A few things to consider:

  • A deliverable for workshop participants or a larger audience;
  • For regular or one-time use;
  • A final artifact or invitation to further discussion and contribution.

Expected Outcome

Apart from creating an immediate artifact, workshops are a great opportunity to make a long-lasting impact on the team.

What long-term effect can this workshop have on your team?

In other words, with what feeling should participants leave the meeting room or Zoom call? For example:

  • Higher transparency around who does what;
  • Better alignment and trust;
  • A new way of doing work and avoiding misunderstandings, and so on.

What other initiatives can build on the achievements of this workshop?

This is an optional point. If you skip it, nothing terrible will happen, but you might overlook an opportunity. Questions to answer here:

  • If this workshop goes as expected, will you want to scale the success to other teams or topics?
  • Can it serve as a role model for others? How can you show the value?
  • What can be the next workshop to build upon the current one?

Step 2: Participants

Expertise, Role, And Experience

Workshops are all about people. Even the best technique won’t help you extract good ideas from the minds of the wrong people.

What expertise do you need to be present in the workshop?

Depending on the subject, you’ll need to involve people with suitable knowledge and skills:

  • Technical (engineering, data science, quality assurance);
  • User experience (design, research, content);
  • Operations, marketing, finances, and so on.

For example, you need to involve software engineers if you’ll talk about the feasibility and business logic, you need to go for customer support and operations specialists, researchers, product managers, and designers if the topic is about user experience, or you need all of them if you are going to identify problems and search for holistic solutions.

Who exactly should participate?

When it comes to choosing particular people, you need to take into account their connection to the subject:

  • Topic promoters
    Who was involved in the workshop topic the most and consistently pushed it?
  • Domain experts
    Who is a go-to person for the topic? Is there anyone with deep knowledge of the subject? Remember: It’s often not the highest-ranking professional.
  • Local context
    If there are multiple representatives of the same role, do you want to involve people from countries where your business is in trouble or, let’s say, gets most of its profits?

Do you need decision-makers or knowledge-keepers? Or both?

There are workshops for gathering and structuring new information and workshops for decision-making with known data.

Depending on participants’ positions and experience, they can be inclined to certain workshop activities. Of course, this is quite simplified, but it narrows down to the following:

  • Hands-on folks are exposed to the topic every day and can share and structure useful information. At the same time, they may lack a bird’s-eye view of the situation.
  • Managers have a mindset of analyzing data and making decisions on the overlap of different factors and limitations. However, they might not be the best source of precise information.

Do you need a co-facilitator, and who can it be?

If your team is large and enthusiastic about workshopping, you might need help with facilitation. Below are several examples of what a co-facilitator can help you with, depending on the workshop format.

Online workshops:

  • Help the participants, who were disconnected, to rejoin the call;
  • Move disordered sticky notes into respective canvas cells;
  • Remove accidentally created elements, fix mistakenly unlocked and moved canvas parts, and so on.

Offline workshops:

  • Put sticky notes that fell on the floor back into place;
  • Quietly instruct participants who came late and missed the beginning;
  • Gently invite not very active participants to the conversation, and so on.

An optimal co-facilitator is a trusted team member who has participated in workshops before, understands workshop basics well, and is proficient with the tool (if you collaborate online).

Team Dynamics

Do not only participants matter but also the way they interact with each other.

How many representatives of one role or function do you need? How will you ensure equality?

When the list of expertise to involve is ready, it’s time to think about the number of people from each side. In a narrowly focused workshop, one expertise can prevail (for example, three-fourths of engineers for a technical feasibility workshop or more than half of product managers for product roadmap alignment).

But if the workshop goal is to co-create a new solution to a large problem, you’ll need an equal representation of product management, design, UX research, software engineering, operations, marketing, customer support, data analysis, and others.

Will you collaborate all together or split into working groups?

Efficient collaboration where everyone contributes equally is possible in groups of 3–5 people. When the team is larger, you’ll need to split it into workgroups. You can organize their work in two ways:

  1. Each group works on a separate aspect of a large problem.
  2. Groups work on the same problem in parallel and then exchange findings and find overlaps.

The number of workgroups also depends on how many representatives of essential roles participate in the workshop. For example, if one of the exercises is sketching potential solutions, it would be helpful to have at least one designer in each workgroup. If the exercise is about mapping pain points on a journey map, having at least one customer support or operations specialist makes sense.

Step 3: Format
When the problem and relevant people are chosen, it’s time to think about how to use everyone’s time in the most productive way possible.

✅ Format: online, offline, or hybrid? Several hours or full-day?

Many factors impact the format choice, for instance:

  • Topic complexity → how much time will you need for it?
  • Team location → can people gather offline without much traveling?
  • Secondary goals → what about an informal part (party) afterward?
  • Team size → how much space do you need?

And here are the main workshop formats:

  • Online works the best when it’s shorter than 3–4 hours; otherwise, people will experience ‘Zoom fatigue’ and be quickly distracted. Complex topics can be split into several sessions instead of working non-stop the whole day.
  • Offline is preferable for all workshop types by default if the team is already collocated, or you can bring them together without too much cost and effort. Such a workshop can be up to several days long and combined with entertainment after work.
  • Hybrid is a rare and fragile format. It works fine when participants are equally distributed and fails when, let’s say, ten people are sitting in the room, and two persons join remotely. In this case, remote team members will eventually drop off the call or make an extra effort to stay as engaged as their colleagues in the room.

✅ A digital tool or paper canvas?

The format influences other workshop parameters, including how people accomplish exercises.

  • Digital tools are a great option for both offline and online workshops. The choice of a particular tool (FigJam, Miro, Mural, Whimsical, and so on) depends on team members’ skills. It’s always better to pick something they’ve already used or just something as simple as possible. It’ll save you quite a few precious workshop minutes.
  • Paper canvases and colored sticky notes are a good match for offline workshops or non-tech-savvy participants. They give a feeling of more valuable contribution and collaboration, but after the workshop, you’ll need to decode and digitize all the handwritten notes.

✅ How to inform people so that they attend and know what to do?

Satisfaction is a matter of expectations. That’s why it’s essential to set the right expectations. If team members lack awareness and alignment, even a perfect workshop is destined to fail before it even starts.

The best approach is to blend in and use channels that people check regularly. If people don’t read emails, don’t spend time on them and better write a Slack message or compose a Google document.

Information to share in advance:

  • Agenda: with all the major stages, coffee breaks, and lunch (no need to describe exercises in detail);
  • Tool-related instructions: if this is a new tool or if not everyone knows how to work with it;
  • Questions or topics: to think about in advance if you expect participants to have certain data at hand or think in a specific direction.

Step 4: Agenda

Workshop Activities

This part will take most of your time to prepare, but is the easiest one if you’ve checked all the boxes above.

What will participants do in the workshop?

Formulate the plan on a high-level first, without diving into individual exercises. Try to fit it into one sentence.

It may sound like this: “Vote for the previously discovered (pre-filled) UX issues, take three top-voted items for brainstorming, generate solution ideas, vote for the strongest ideas, make sketches of the top-voted ideas, vote for the most promising sketches for further prototyping.”

Another example: “Write feedback about team collaboration in a matrix, group positive and negative feedback pieces by topics, rank the issues from minor to major ones, and assign people to solve five major issues.”

Note: Feel free to check a comprehensive anatomy of design workshops where I dwell on typical ‘atomic’ activities all workshops consist of.

✅ What will each exercise be like?

When the general plan is ready, it’s time to think about the way you’ll organize each exercise, for example:

  • How many sticky notes per participant will you give?
  • Do you need to compose input examples so that people submit the information in a proper format?
  • How many votes will you assign to participants? In what order should they vote (if offline)? And so on.

How much time will participants need for each exercise?

Usually, the simplest exercise requires 15–20 minutes, while more sophisticated ones may take 40–50 minutes. And don’t forget to include a few minutes to instruct the participants before each activity and summarize their contributions afterward. Besides, you cannot immediately dive into the workshop since people are a few minutes late and need to switch to a workshopping mood.

However, every team has its own dynamics, that’s why accurate estimations are possible only after you conduct a couple of workshops and witness your teammates’ actual speed and engagement.

Will you need to break the ice at the beginning and keep people energized during the workshop?

Unlike the main workshop activities, these ones play an auxiliary role and help you keep the team spirit high:

  • Ice-breaker or check-in: a fun exercise to fill the time while you are waiting for participants, help people get acquainted with each other, or create a creative mood in the team.
  • Warm-up or energizer: an intermediate short exercise between the sessions of concentrated work. Usually, it’s a physical activity like jumping or stretching.

Structure

When you know what you need from people, you can pack it into a visual structure to help everyone grasp the topic.

Input: where will participants get the information for each exercise?

Every exercise should be based on the previous one. You need to check if there are no logical gaps between the workshop stages.

For example, if you want people to vote for the most critical problems with your digital product, you must get a list of problems first. In this case, ask people to write them down in the previous exercise or add them to the canvas yourself in advance.

Output: how will each exercise feed into the next one?

This is just a double-check that each next exercise will build upon the findings from the previous one. If the information from a previous step doesn’t go anywhere further, the team will be naturally curious about why you even asked them to share this data.

Canvas: what visual structure will help the team to contribute?

Information is clearer and more useful when it’s structured and visualized. Besides, participants can submit better data if you guide them with a relevant canvas. Depending on the workshop goal and expected outcome, you might choose one of the following structures:

  • User journeys, storyboards, and project timelines: for time-based information like stories and processes;
  • Matrices or ratings: for priorities and comparison;
  • Tables, blueprints, and maps: for interconnected data;
  • Mindmaps: for hierarchies, and so on.

Step 5: Risk Management

Prevention is always better than a cure. When you involve many people in any activity, there will always be an element of ‘chaos’. But, like a seasoned standup comedian always finds a way out when they forget a joke or when a microphone stops working, the workshop facilitator should also have a trump up their sleeve just in case.

Workshops have many ‘moving parts’, which means things may not go as expected. So, having Plan B (and C, and D) is indispensable.

⚠️ Some people are skeptical and resist the workshop idea.

How to prevent it:

  • One-on-one interviews with skeptics before the workshop to learn more about their concerns and expectations.
  • A survey about expectations from the workshop and urgent needs.
  • Asking about participants’ expectations at the beginning of the workshop and then comparing them to the actual result at the end.
  • Sharing stories about similar successful workshops conducted with other teams in the company earlier.

When it has happened:

  • Figure out what the actual concern is and adjust if it makes sense.
  • Invite the workshop ‘sponsor’ (usually a domain, product, or discipline manager) to explain to a skeptical participant why this activity is crucial and how the team will benefit from it.
  • Ask people to stick to the agreed agenda since they received it in advance, and thus could’ve shared their concerns before the event instead of disrupting it.

⚠️ You are about to exceed the planned timeline.

How to prevent it:

  • Don’t let people discuss random things; politely interrupt and remind them about the workshop goal.
  • Use a ‘parking lot’ for spin-off topics and questions. Don’t dismiss ideas but keep people focused on the subject.
  • Split a large team into working groups where everyone can contribute more efficiently without long debates.
  • Analyze previous workshops and how long it actually took people to do corresponding activities.

When it has happened:

  • Skip or shorten inessential workshop steps (if you have any).
  • Predict the delay at least half an hour before the planned finish and openly announce it.
  • Properly finish the last exercise, summarize intermediate results, and announce another session for later.

⚠️ The online workshop tool stopped working.

How to prevent it:

  • Use a reliable and robust tool that has good reviews.
  • If participants have non-standard software or hardware setup, share a test canvas in advance so that they can try the tool and tell you if everything works fine.

When it has happened:

  • Wrap up the last step and schedule the workshop continuation.
  • If the remaining exercise is simple, create an empty canvas in another tool and continue there.

⚠️ The key people are absent.

How to prevent it:

  • Talk with all the major stakeholders one-on-one in advance and make sure they understand why their participation is important.
  • Choose the time slot when the key participants can attend.
  • Reach out to people who haven’t confirmed the appointment in their calendars and ask them to respond.

When it has happened:

  • If you receive last-minute appointment rejections, reschedule the workshop as soon as possible.
  • If the key people didn’t show up without any notification, reschedule the workshop or conduct a simplified session to gather preliminary information from the available people.

⚠️ In the middle of a workshop, you suddenly discover the actual hidden problem that changes your initial plan.

How to prevent it:

  • Choose a significant problem that people would have tried to solve anyway — with or without a workshop.
  • Confirm the workshop topic and format with the key stakeholders.
  • Send the workshop goal and agenda via a channel where participants will notice and, if needed, challenge it.
  • Justify the presence of each participant; be able to explain to yourself and others why these people are invited and others aren’t.

When it has happened:

  • Wrap up the workshop and agree to organize another, more relevant team activity soon.
  • Repurpose the existing workshop if you can use the same canvas and all the participants have sufficient expertise to work on the new problem.

⚠️ People get distracted during the workshop.

How to prevent it:

  • Don’t leave the team unattended for too long: even if the exercise needs a lot of time, split it into parts and check the progress, for example, every 20 minutes.
  • Include a reasonable dose of fun and humor in exercises.
  • Create a space for random stuff and jokes so that enthusiastic people can express themselves in a non-intrusive way.
  • Set the right expectations: participants shouldn’t think they’ll be able to multitask during the workshop. If someone has an urgent task, let them leave the room/call and turn back later.

When it has happened:

  • Conduct an energizer/warm-up activity or give people a short break.
  • Gently remind the team that you should achieve a certain result and that you don’t want to finish late or schedule another session, thus using everyone’s time inefficiently.

Summary

Design workshops are no rocket science. In the ideal world, there would probably be no workshops: people would just have common sense by default. Maybe, that’s why small, close-knit teams usually don’t need special workshop preparations because they share the same values and already speak the same language.

However, in most cases, workshops are inevitable. They help build trust if it doesn’t appear between team members naturally and align people of different backgrounds who haven’t collaborated a lot before. That’s why you should plan workshops with people in mind. And if I had to choose one point that contributes to the workshop’s success the most, it’s involving the right people.

Meanwhile, here is a short version of the checklist:

Problem framing

  • Choose the topic and formulate the problem.
  • Check if a workshop will be the right tool to use.
  • Analyze already available information on the subject.
  • Prepare known information for the workshop.
  • Decide what deliverable you’ll produce as a result of the workshop.
  • Think of making the future deliverable relevant and valuable for the team.
  • Envision the long-term effect of this workshop on your team.
  • Think of other initiatives that can build on the achievements of this workshop.

Participant selection

  • Define the expertise you need to be present in the workshop.
  • Think of the potential participants based on their knowledge and experience.
  • Invite decision-makers and knowledge-keepers according to the workshop goal.
  • If you’ll need help, assign a co-facilitator.
  • Ensure equality by inviting a certain number of representatives of each role or function.
  • If your team is large, plan how to create constructive group dynamics.

Workshop format

  • Define the optimal format and timeline based on the problem scale and team availability.
  • Choose a digital workshopping tool if you decide to work paperlessly.
  • Find an optimal way to invite people and set their expectations from the workshop.

Agenda and canvas

  • Formulate the general workshop outline in one or two sentences.
  • Plan the details of each exercise based on the workshop goals.
  • Allocate time for all exercises and auxiliary activities.
  • Prepare ice-breakers and energy boosters, just in case.
  • Make sure each exercise will be based on the results of the previous one.
  • Identify how each exercise will lead to the next one.
  • Choose or compose a canvas — a visual structure to organize information from the team.

Risk management: what can go wrong

  • Some people are skeptical and resist the workshop idea.
  • You are about to exceed the planned timeline.
  • The online workshop tool stopped working.
  • The key people are absent.
  • In the middle of a workshop, you suddenly discover the actual hidden problem that changes your initial plan.
  • People get distracted during the workshop.
]]>
hello@smashingmagazine.com (Slava Shestopalov)
<![CDATA[Fine-Grained Access Handling And Data Management With Row-Level Security]]> https://smashingmagazine.com/2023/03/access-handling-data-management-row-level-security/ https://smashingmagazine.com/2023/03/access-handling-data-management-row-level-security/ Wed, 29 Mar 2023 12:00:00 GMT Many apps have some kind of user-specific information or data that is supposed to be accessed by a certain group of users and not by others. With these sorts of requirements comes a demand for fine-grained access handling. Whether for security or privacy reasons, dealing with sensitive data is an important topic for any app. Big or small, nobody wants to be on the wrong side of a data leakage scandal. So let’s dive in on what it means to handle sensitive or confidential information in our apps.

Take It Seriously

Regardless if you’re requesting access on Twitter, a bank, or your local library, identifying yourself is a crucial first step. Any sort of gateway needs a reliable way to verify if an access request is legitimate.

“Identity theft is not a joke.”
Dwight Schrute

On the web, we encapsulate the process for identifying a user and granting them access as Auth, which stands for two related but distinct actions:

  • Authentication: the act of confirming a user’s identity.
  • Authorization: granting an authenticated user access to a resource.

It is possible to have authentication without authorization, but not the other way around. The strategy to implement authorization at a data management level can be loosely referred to as Row-Level Security (RLS), but RLS is actually a bit more than this. In this article, we will take a step deeper into managing sensitive user data and defining access roles to a user base.

Row-Level Security (RLS)

A ‘row’, in this case, refers to an entry in a database table. For example, in a posts table, a row would be a single article, check this json representation:

{
    "posts": [
        {
            "id": "article_23495044",
            "title": "User Data Management",
            "content": "<huge blob of text>",
            "publishedAt": "2023-03-28",
            "author": "author_2929292"
        },
        // ...
    ]
}

To understand RLS, each object inside posts is a ‘row’.

The above data is enough for creating a filter algorithm to effectively enforce row-level security. Nonetheless, it’s crucial for scalability and data handling that such relationship is defined on your data layer. This way, any service that connects to your database will have all the required information to implement its own access-control logic as required. So for the above example, the schema for the posts table would roughly look like the following:

{
    "posts": {
        "columns": [
            {
                "name": "id",
                "type": "string"
            },
            // ... other primitive types
            // establish relationship with "authors"
            {
                "name": "author",
                "type": "link",
                "link": "authors"
            }
        ]
    }
}

In the above example, we define the type of each value in our posts database and establish a relationship to the authors table. So each post will receive the id of one author. This is a one-to-many relationship: one author can have many posts.

Of course, there are patterns to define many-to-many relationships as well. Take, for example, a team’s backlog. You may want only members of a certain team to have access. In such case, you can create a list of users with access to a specific resource (and thus being very granular about it), or you can define a table for team, and thus connecting a team to multiple tasks, and a team to multiple users: this pattern is called a junction table and is great for defining scoped access within your data layer.

Now we understand what authorization is and looks like in a few cases. This should be enough to design a mental model for defining access to our data. We understand that in order to use the granular access to our data effectively, our app must be aware of which user is using that particular instance of the app (aka who’s behind the mouse).

Authentication

It is time to set up a reliable and cost-effective authentication. Cost-effective because it is counter-productive to re-authenticate the user on every request. And it increases the risk factor of attacks, so let’s keep auth requests to a minimum. The way our app stores the user credentials to re-use in a defined lifecycle is called a session.

There are multiple ways of authenticating users and handling sessions. I invite you to check Eric Burel’s article on “Authentication in Websites: A Banking Analogy”. It’s a great and thorough explanation of how authentication works.

From this moment on, let’s assume we did our due diligence: username and password are securely stored, an authentication provider is able to reliably verify our user’s identity and returns a session, which is an object carrying a userId matching our user’s row in the database.

Connecting The Dots

So now that we have established what it means and the requirements each moving piece brings in order to get it working, our goal is the following:

  1. Authentication
    The provider performs user authentication, the library creates a session, and the app receives that as a payload from the auth request.
  2. Resource request
    Authenticated User performs request with resourceId; the app takes userId from session.
  3. Granting access
    It filters all resources from the table to only the ones owned by userId and returns (if it exists) the one with resourceId.

With the above mental model defined, it is possible to any sort of implementation and properly design your queries. For example, on our first defined schema (posts and authors), we can use filters on our fetching service to only provide access to the results a user should have:

async function getPostsByAuthor(authorId: string) {
    return sdk.db.posts
        .filter({
            author: authorId
        })
        .getPaginated()
}

This contrived snippet is just to exemplify a bare-bones RLS implementation. Maybe as a food-for-thought so you can build upon it.

Conclusion

Hopefully, these concepts have offered extra clarity on defining access management to private and/or sensitive data. It’s important to note that there are security concerns before and around storing such kind of data which were beyond the scope of this article. As a general rule: store as little as you need and provide only the necessary amount of access to data. The least sensible data going over the wire or being stored by your app, the lesser the chance your app is a target or victim of attacks or leaks.

Let me know your questions or feedback in the comment section or on Twitter.

]]>
hello@smashingmagazine.com (Atila Fassina)
<![CDATA[The Best Handoff Is No Handoff]]> https://smashingmagazine.com/2023/03/best-handoff-is-no-handoff/ https://smashingmagazine.com/2023/03/best-handoff-is-no-handoff/ Mon, 27 Mar 2023 14:00:00 GMT Many companies organize their workflows around projects and departments. Especially in large companies, work often travels from one place to another, often getting stuck between emails and Slack messages, and often “refined” on its never-ending journey between design and engineering teams.

This inevitably brings up the question about the design hand-off: that magical moment when designers are done with their work and developer can take over. Most importantly, that’s where designers must stop working, and move on to other work — unless the scope changes or late adjustments creep their way in.

The “No Handoff” Method

Last week, I stumbled upon an interesting article about the no-handoff method, in which Shamsi Brinn shows an alternative to typical design hand-offs. Shandi shows a fluid model where product and engineering teams work on the product iteratively all the time, with functional prototyping being the central method of working together.

With the process, the working prototype is the living spec of the project and a shared language for the team. No more translation is needed because everyone works on the same prototype. The problem space and the solution space are explored by designers and engineers collaboratively, and the entire workflow is organized around the product, rather than company’s internal structure.

The “Hot Potato” Process

This reminded me of the Hot Potato Process by Dan Mall and Brad Frost, where ideas are passed quickly back and forth from designer to developer and back to designer then back to developer for the entirety of a product creation cycle — similar to throwing hot potato back and forth (audio, video).

From my personal experience, I can only testify that the best collaboration doesn’t have any handoffs between teams. There, work flows seamlessly from design to engineering and back — with both teams working simultaneously, and discussing issues as they occur, during the entire product lifecycle.

There are phases of independent work for sure, but there are also plenty of overlaps for collaborative work, which are opportunities to discuss the progress, explore what is and what isn’t viable and hence avoid lurking issues down the line.

Create As Many Overlaps As Possible

Of course, the process works well for small product teams. But what if a part of the product is outsourced to an external agency? Many companies choose the route of extensive documentation — almost to the last pixel, along with a brief explaining the strategy and the thinking behind the design.

This isn’t enough though. Design decisions have to be informed by technical implementations and its limitations. There is no universal language around design patterns and their interaction design either. And not every design detail can be implemented in an accessible and performant way. This is why beautiful mock-ups turn into painfully slow and inaccessible monsters.

We can reduce the risks of hand-offs with dedicated overlaps between designers and engineering teams. With regular check-ins. Weekly reviews. Shared channels for communications. Visibility into the work done. Usability testing of functional prototypes and small but regular design revisions.

Design is a team work. It involves everybody who contributes to the website — from customer service and marketing to developers and designers. Any overlaps you can create will benefit the teams, their productivity, and ultimately your users.

Wrapping Up

So we want to move away from handoffs. But how to convince teams to change their workflow entirely? With a small experiment on a small project. Pick a project where you could test the waters and suggest a collaborative process. Ask what designers could do while developers are busy. Ask what developers could do while designers iterate. And enable both teams to work together, at the same time.

Ultimately, the success depends on one simple thing: just how well the teams work together. And if they can’t collaborate particularly well, chances are high that a design hand-off won’t make it any better, and a major change in the team culture will need to happen first.

You can find more details on design patterns and UX in the video library on Smart Interface Design Patterns 🍣 — with a live UX training that’s coming up in September this year.

]]>
hello@smashingmagazine.com (Vitaly Friedman)
<![CDATA[Overcoming The Challenges Of Content Creation For Informational Websites]]> https://smashingmagazine.com/2023/03/overcoming-challenges-content-creation-informational-websites/ https://smashingmagazine.com/2023/03/overcoming-challenges-content-creation-informational-websites/ Thu, 23 Mar 2023 17:00:00 GMT Web apps and e-commerce sites may get all the love these days, but the majority of the web is still informational, and most websites are still content-led. Whether it’s a marketing website trying to convince you to buy a product or an informational site seeking to educate and answer your questions, the web is still dominated by words. But unfortunately, these sites face two substantial challenges:

  1. According to the Nielsen Norman Group, users only read 20 to 28% of a webpage.
  2. Most people who write content for the web lack the necessary skills, which leads to poor-quality content.

In an ideal world, professionals would write our website copy, but that rarely happens, especially in larger organizations. Instead, we have an eclectic mix of people from all parts of the organization posting content online, which is why content quality is often poor.

Of course, complaining about this fact fixes nothing. So, what can we do to improve the copy on our websites when we potentially have dozens of inexperienced people posting the copy online?

Unsurprisingly, there’s no single magic answer that will fix the quality of our site content. However, there are four techniques we can use that together can get us where we want to be. When implemented correctly, these techniques can have a transformational impact.

Technique #1: Provide Content Creators Training

In my experience, most of the training that content creators receive focuses on how to use the content management system, not how to write good web copy. Even when they do receive training on how to write online, this is often in the form of live training.

Live training has its place, but it comes with its drawbacks. It is hard to arrange and needs to be repeated every time there is a new member of staff. However, the biggest problem with live training is that unless the person goes out of that training session and starts using what they learned immediately and on an ongoing basis, they quickly forget what they have learned and fall back into old patterns of writing.

What content creators really need is training material they can easily reference when they sit down to create content for the website. The material should be broken down into modules that are directly related to things they might want to do, like the following:

  • How to optimize a page for search engines.
  • How to ensure your page is accessible.
  • How to structure your content.
  • How to write clear and engaging titles.
  • How to make content more engaging.

And so on.

Each module should be small, self-contained, and take only a few minutes to digest. Ideally, it should also be supported by video walkthroughs and include specific actions people can take.

There should also be checklists that ensure they have thought of all the things that need doing when writing, all as quickly accessible as possible.

Technique #2: Make Content Creators Accountable

If content creators are not made accountable for the content they create, they will not put the effort in to ensure its quality.

To address this issue, we can assign every page on a website to a specific individual and potentially even add their contact details to the page in case users have questions. Doing this motivates content creators to ensure the page answers as many user questions as possible and is up-to-date.

You may meet resistance to this idea because people change roles, and so responsibilities change. However, that is why pages should have a specific owner. Too often, pages do not get handed over when people move on, and these orphan pages are abandoned, leading to content ROT (redundant, out of date or trivial content).

Ensuring content remains relevant and up-to-date is essential, which leads me to my third technique.

Technique #3: Establish Governance Around Website Content

The only way content will remain up-to-date is if it is reviewed regularly. And to achieve that, we need some governance that motivates content creators to do exactly that with the pages for which they are responsible.

You can create this motivation by establishing a policy stating that if certain conditions are not met, the content will be archived.

What these conditions are is entirely up to you. You could require a page to meet a certain threshold of page views or engagement (encouraging content creators to ensure page titles are relevant and clear.) You could even flag pages that perform poorly in search engine rankings.

However, as an absolute minimum, you should require pages to be reviewed regularly — how regularly will depend on your content and situation.

For instance, I work on many public sector and higher education websites where change is slow. In such cases, an annual review of pages is usually sufficient, except for certain time-sensitive pages.

If the condition is not met (such as the page not being reviewed by a required date), the page could be removed from navigation and search, effectively orphaning it. Whatever you decide, it should also have a banner added to the page saying that the content may not be up-to-date and to contact the page owner for the latest information. This will motivate the content creator to update the page to avoid a lot of emails!

Another condition I often use is poor user feedback on a page, which brings me to my final technique for ensuring quality content.

Technique #4: Provide Content Creators with Good Feedback

One way to gather user feedback for content creators is through surveys. Surveys can be added to the bottom of a page or integrated into the site experience, asking users how they found the content and if there is anything missing that they would like to see.

Another way to gather feedback is through social media listening. Monitoring social media channels can help you understand how users are engaging with your content and what they are saying about it. This can be valuable in identifying areas of your site that may need improvement or in identifying content that resonates with your audience.

In addition, it’s important to regularly review your site’s analytics to see which pages are performing well and which are not. Special attention should be given to dwell time, traffic levels, and search engine rankings.

By analyzing this data, you can better understand which pages may need improvement or which topics are of most interest to your audience.

Whatever the case, all of this feedback needs to be made available to content creators because if the page rates poorly, it will encourage content creators to act.

You can also take this technique even further by celebrating the most successful content creators or the most improved pages by giving out awards and prizes (much like employee of the month).

Bringing It All Together

To bring these techniques together, we can create a content creator’s dashboard that shows each content creator all the pages they are responsible for. This dashboard will display how well pages are performing and highlight pages that are doing well or poorly.

At the top of the dashboard, we can flag pages that need the content creator’s particular attention — pages that are in danger of being archived because they need reviewing or have been rated poorly.

Finally, we can integrate training directly into the dashboard in the form of quick tips (like the Hemingway App example) and more detailed advice on how to address questions content creators may have at that point.

Of course, the approach I have laid out in this post is not a comprehensive solution to poor quality, but it does at least put in place a framework for improvement. One that works well for large sites that have a significant number of content creators who are not web copy specialists.

By using these four techniques together, we can ensure that the copy on our websites is of high quality and that our users find the content they are looking for.

Further Reading on SmashingMag

]]>
hello@smashingmagazine.com (Paul Boag)
<![CDATA[Smashing Podcast Episode 58 With Debbie Levitt: What Is CX Design?]]> https://smashingmagazine.com/2023/03/smashing-podcast-episode-58/ https://smashingmagazine.com/2023/03/smashing-podcast-episode-58/ Tue, 21 Mar 2023 07:00:00 GMT In this episode of the Smashing Podcast, we ask what is Customer Experience design, and how does it differ from User Experience design? Vitaly Friedman talks to expert Debbie Levitt to find out.

Show Notes

Weekly Update

Transcript

Vitaly Friedman: She’s a Customer Experience and User Experience Strategist, Researcher, Designer, and Trainer. She spends most of her time helping companies of all sizes, big and small and large, medium, transform towards a customer-centric approach. Now she’s been teaching how to improve customer satisfaction, predict and mitigate business risk, and increase ROI by investing in, of course, great customer experiences. Now she lives east of Olbia-Sardinia, what an incredible city that is in Italy, out in the countryside.

Vitaly: Also, she has recorded over 175 episodes of her livestream podcast on YouTube and has over 600 hours of videos on the wonderful Delta CX YouTube channel and has just published a wonderful book, Customers Know You Suck: Actionable CX Strategies To Better Understand, Attract and Retain Customers. So we know she’s a great design strategist with a keen eye for customer satisfaction. But did you know that Debbie is often called the Mary Poppins of CX and UX? Why? Well, because she flies in, improves everything she can, sings a few songs every now and again, and flies away to her next adventure. While, in fact, a set of clients started calling her just that.

Vitaly: My Smashing friends. Please welcome Debbie Levitt. Hello, Debbie. How are you today?

Debbie: Hey, thank you so much for having me. And I’m almost Smashing. I’m unfortunately getting over Covid, so some people might hear that in my voice. Luckily it’s been mild, and I have to apologize, I accidentally sent you that I live east of Olbia. East of Olbia would be the Mediterranean Sea. I live west of Olbia. Totally my fault. Oh my gosh. I promise I live on land.

Vitaly: That’s okay. But you do not live in the sea, right? It’s not like fish are your neighbours, or?

Debbie: No, I’ve evolved and I live on land, and so I’m sorry about that. That’s what happens when you are multitasking. So thank you for putting up with me, but...

Vitaly: That’s okay. Well, I didn’t check where it is because... Actually I was in Olbia and-

Debbie: Oh wow.

Vitaly: ... I was waiting for a bus four times in Olbia and it never came.

Debbie: I’m so sorry. Don’t do it. No, you must rent a car if you’re here.

Vitaly: Well, we will speak about that for sure in our future seasons as well.

Debbie: Come on back and stay with us.

Vitaly: Yes, that might be very reasonable. But when I look at all the wonderful things that you’ve been producing and you’re always there and you’re always advocating for the humans, right? It seems like you’re really care about people, don’t you?

Debbie: I do, yes. Thank you for noticing. I certainly do.

Vitaly: Yes, I think you do. But one thing that’s really struck me,.. I spent quite a bit of time in organizations, also large and small, and every now and again, I have to explain what CX means, what is different between UX and CX and so. Because there are many kind of ways of we can do that, and I think you also mentioned in your book as well. Some people see it as something that marketing does. Some people see it like customer support or customer success. Sometimes it’s like this magical overlap between business and customer experience. And what is it, Debbie, tell us what is it in the first place?

Debbie: Well, the way that I see CX is that it is end-to-end customer experience. It’s that everything our company can possibly do or offer touches our customers. And so we have to be considering all of that. They could be products, they could be services, they could be experiences, they could be digital, they could be all of these things. Very often when people think of UX, they’re thinking, well, that’s just screens, that’s just digital design or research for something that’s going to be digital. But when we think about CX, for whatever reason, CX is generally understood to mean that full customer experience. And so to me, I believe that when we’re doing CX and UX right, they’re the same thing because many people who work in UX don’t want to just think about the screens. They do want to think about the full and holistic journey that the customer has. They want to think about where the customer interfaces with the bank branch or the customer support or the hotel desk people. We do want to think about those.

Debbie: I remember when I was a contractor at Macy’s, we were fighting to be involved in the stores and they said, "No, you’re just the people who make the screens" and they wouldn’t let us. And we really wanted there to be that holistic tie between the digital experiences, website, mobile web and app, and the in-store experiences. And so again, I believe that when you’re doing them well, they kind of are the same thing and they can be the same thing. And we still use some different names for them, but I don’t want to fight too much over that today. I’m dying on other hills, as we say.

Vitaly: So what I hear is that basically CXs ideally would be also a wonderful world of beautiful, beautiful UX and the other way around. But I’m wondering actually still at this point, and maybe you can enlighten me at this point, Debbie as well, when I see companies thinking about how they should work, how they should operate, that often feels like it’s still a feature factory... So you just, let’s deliver that feature for that release and let’s deliver that feature for that cycle and then keep going, keep going. And it’s interesting to me because I think that we’ve been doing this now what for 15, 20 years, this UX, CX, whatever, that kind of thing, did we fail in communicating to companies the right way of running business? Or why is it that we are now by 2023 are still in the position where we kind of have to almost fight for the role of CX — or even UX actually at this point — in a company small and large. So why is that?

Debbie: To me it tends to be two things. I think that in many companies, the question is what’s the least we can do that we can pretend is good enough? And I think some of that comes from what I call “fake agile” because if you look at original Agile and the Agile manifesto, it cares about customer satisfaction. It cares about good design. But the idea of agility was ultimately to make engineering teams faster and more efficient. So we got into this way of thinking, how fast can we go? Can we go faster? Can we go faster? Can we release more? And I say, well, congratulations on going faster and releasing more, but if you’re not attracting customers, making them happy, keeping them, let’s not congratulate ourselves on whatever that agility was.

Debbie: Same for Lean. Many people are working from a definition of Lean that runs against Lean. Lean is supposed to be about finding defects and risks and waste early, mitigating them, proving your efficiency, not because the weapon, and you made people try to go faster, but because you were driven more by quality, and you were more likely to put out how great things that you didn’t have to cycle back and fix later. So think part of what we battle in most of our companies is really mediocrity because everybody who we work with knows that they hate every company that chips crap. You hate those apps, you hate those websites, you hate those hotels, you hate those airplanes, you hate those whatevers. You hate it. And then you show up to your job and you go, "That’s probably good enough. Just get it out there." And it’s like people have really lost their sense of what customers define as quality and value. So I think part of it is that mediocrity of ads good enough.

Debbie: Let’s just say we’re fast and keep going. And this is going to be a little bit spicy, but part of it to me is UX leaders. I think in some cases, not everybody, we have some weak UX leaders. We have some people who are over-focused on making the stakeholder happy. They’re over-focused on the visual design. They’re over-focused on, "Look, we can pretend we’re agile and Lean too. We’ll just slice UX down to the least we could do, we’ll research for a day. We’ll run a survey, uh.. we’ll design for two seconds. Yes sir. Yes ma’am." And I think that our UX leaders have done us a disservice and in many ways continue to when they are not fighting for quality, they’re dying on the wrong hills.

Debbie: They’re coming in and they’re saying, "Don’t you understand my job? These are artists, these are not artists." And I say, stop dying on that hill. Talk to people about how great CX and UX work, mitigates risk, saves companies time and money, increases customer satisfaction, is more likely to increase that loyalty. You’re dying on the wrong hills and you’re saying yes to ridiculously short timeframes, UX work being badly done by a circus of everybody just to say, we got more done. And again, it’s all speed over quality. So I think this has not yet sunk in for companies because we’ve been selling the wrong things. We’ve been trying to sell the value of my job instead of selling the value of the outcome. Hey, remember that crappy project we did where we ended up having to go back and figure out what we did wrong and fix it and redo it? And our customer service had to give people some free coupons to apologize and remember the multidimensional disaster that was? Well, that would’ve gone better if we had done this research, this design, this testing.

Debbie: If we had spent three more weeks, three more weeks would’ve saved all of this wild expense and marketing problems and voice of the customer issues and customer support usage. We are not doing a good job showing the math of how much carnage and waste and money we can save if we just fought for, what sometimes is a few weeks, maybe it’s a little bit longer in some cases, but we’re not demanding generative research. We’re claiming we can work from assumptions and guesses. And I say no one wants that, Agile’s against that, Lean’s against that, Scrum is against that, Nielsen Norman group is against that. Nobody wants to see that. And yet I’m fighting some dude on LinkedIn last week who says, "Assumption-based methodologies are valid." And I say, well, there’s a Grand Canyon between valid and a freaking good idea. You can work from guesses and assumptions, but this is where they’re landing us. We all see what this is like. We mostly hate our jobs. We need our leaders to be fighting more and differently.

Vitaly: Well, that’s interesting because I think in many ways I do find myself really in these positions where I still wonder sometimes, why do we even bother this position of I can over here or the side of the I can matters, but I mean the position and we went on the left, we test that with A/B testing testing and then we see if this works better or not. But then I always think this always goes into this notion of speed. I think this is very much the core of it really as well, because it seems like we are rushing all the time. We need to deliver, we want to deliver good quality, but in the end, we just want to deliver — be it features or anything else. And one thing that I find quite weird is that we ended up in this situations where we want MVP to validate a product. So MVP is important. We don’t want to spend too much time building and designing and all, but shouldn’t we be designing, I don’t know, the minimal first-class user experience kind of VP or something? I don’t know. What is your take on MVPs in general? Is it just me seeing it wrongly?

Debbie: No, I’ve been fighting MVP and Lean Startup for some time, and then I’m mostly fought back by a lot of white guys who want to comment on my Medium articles. It’s a very narrow audience there wants to fight me on that. But I think we do have to take a second look at MVPs and some of these, again, Lean Startup or other ideas. A lot of these things came from books from over 10 years ago and there’s nothing wrong with 10 years, but they haven’t been updated. And they come from these books that were really aimed at startups. The Lean Startup was for startups. It wasn’t for Oracle or Fang or whoever they are now. It was for startups. And it said, "Hey, if you want to go really fast" — and we have to remember where we all were in the late 2000s and 2010, one of the biggest problems with startups, and you’ll remember this because there was vaporware, there were people who were promising technologies and features and systems and they were never even built.

Debbie: So the Lean startup made sense as an answer to that, "Hey, stop waiting and waiting and waiting and never putting out your mysterious vaporware. Really something early. Just get it out there, give it a try." And I think that advice can make sense for startups in 2010, but they really don’t make sense for our company and the size of projects we have, the amount of customers we have, the reliance we have on retaining those customers and making them happy. It’s not the same as two bros in Silicon Valley in 2010 who are going to rush some early version out.

Debbie:And the other thing I remind people is that the MVP can be reframed. There’s no reason why a solid realistic UX prototype can’t be your MVP. And in fact, in my book, I think in chapter 21 where we interview Steve Johnson, a product manager, he says, "Eric Rees admitted that he made a mistake." He meant minimum viable prototype. He didn’t mean minimum viable product. He didn’t imagine that this early pseudo beta, almost beta early version was something that you would sell, something that you would expect people to pay for. He really expected that it was almost like an early prototype. But of course we have that in user-centered design and human-centered design. I don’t need engineering to build it for me to see if it’s going in the right direction. I’m a big fan of Axure (hashtag not sponsored), and I want to make sure that I’m making a highly realistic prototype, but not realistic from the perspective of visual design, from the perspective of usability flow —

Vitaly: User experience.

Debbie: Yes, process. Can you type in a field? Yes, you should be able to type in the field. And then I can bring that to usability and other testing and be able to say, aha, we are solving the real problem well or we’re solving the real problem, but we’re not there yet. Or wow, we’re way off. We are really not solving the real problem well or at all. And that’s what we should be doing early on and in cycles. But the problem is that people read Lean Startup and they saw a couple of things that said Agile, and they now think you can’t know if you’re going in the right direction without having engineering spend sprints, weeks, months, building it, testing it, merging it, releasing it, and then sitting around waiting for customer support complaints or an A/B test, which is often quite flawed or some sort of feedback.

Debbie: And then what do we do? We go, it’s probably good enough and we put it in the backlog or the ice box. So we have a lot of problems with our processes, we have problems with our standards. We have much lower standards internally than our customers have for us. So I think that the MVP is our problem, but I think it can be reframed. Ultimately the minimum viable product or prototype is an early UX prototype that can help us test a concept or one of its many endlessly, many executions.

Vitaly: Well, I think also when it comes to customers, standards are different, expectations are much different now as well. So it’s just a very, very different world. And coming back to your book, I rarely read one single chapter in which is so packed that I feel like, wow, there is so much stuff in it. And I usually don’t do that to be honest, I actually printed out chapter 18.

Debbie: Oh, thank you.

Vitaly: Just because I wanted to underline first because the reason I do it is like I read and then I underline and then I was so tired of underlining. I just said, I’m just going to put it next to me. So maybe just to make it a bit more tangible, I would say to all your listeners, so let’s imagine you’re working for a company that is just a regular conservative company, very much legacy ridden, a lot of good old processes in place, not really a culture of sustainability or interest in user-centric or ethical design or anything of that sort maybe.

Vitaly: But there is a strong need and there is a strong will to move there. But of course when it comes to little exercises like that, it’s a big shift. It’s a culture shift. It’s a shift of how people are working, what they believe in, how they embed their values and the way they’re working into the product, how the metrics are going to be working for that, namely specifically, how do we even choose metrics that fit? How do we track them? How often do we track them? What do we track and all that.

Vitaly: Maybe you could just give us a little bit of insight in that kind of scenario if you wanted, let’s say, to support in some way, some sort of a shift like that. I would say what is absolutely required for this to be successful? That would be question maybe number one. Question number two, how to get there? Because you are Mary Poppins, right? So you just come in, you fly in, you solve problems, you fly away. So what would be your magic dust that you would sprinkle all over all departments in the organization?

Debbie: I would say the first way to help yourself get there is to shift to the language that the business cares about. The business doesn’t care about delight, the business doesn’t care about empathy. The business cares about the usual stuff. Find more customers. We hope they’re happy because we want them to stay. That’s it. Attraction or adoption satisfaction and some sort of loyalty or retention. That’s it. Talk about those things. Talk about risk, talk about wasted time and money. Look up Six Sigmas, cost of poor quality. It’s a wonderful model that I go into early in the book. I think in chapter two, it’s a whole list of things that your company is wasting time and money on because you didn’t build something better for the user. So forget about some of the words we tend to use in UX and design because they make sense to each other.

Debbie: Makes sense when you and I talk about it, empathy, delight. But somebody who is just counting beans as they say, or looking at numbers and budgets and bottom lines, they don’t care. They just don’t. They want to know how do we make more people join and stay and we hope they give us some good satisfaction scores in the middle. So we have to start there and we have to make sure that’s our common ground. And that’s where I focus. I focus on how can we find ways to bring more customers in, make them happier so that they’ll stay. Focus there. And then the question is, what can CX or UX work do that augments that, supports that? How do we use early generative research to bring us customer intelligence we don’t have now? Because sure, we have endless analytics, we have surveys, we have, what do you want?

Debbie: We have AB tests, we’ve got lots of things that are mostly quantitative, but we don’t know a lot of the why. We don’t know a lot of the how. We get an NPS score that says negative 30 and we don’t really know why, but everyone will get together in a brainstorming session, guess why, and then guess how to fix it. And they’re surprised when that doesn’t work. So I drive people towards customer intelligence. Now some people think that’s just more market research. Let’s just find people who demographically fit into our sweet spot and throw more darts at them and give them $10 off and advertise more heavily to them. But I say, look, you can do that. That’s the adoption piece. But if you’re not building the better product, service or experience, you won’t have the satisfaction and you won’t have the retention and the loyalty.

Debbie: So all of these things are that longer arc. So I’m making it sound over simple, "Hey, you just have to speak the business’ language." But it’s a huge shift that a lot of people in UX and design are not always doing. They’re still focused on we have to delight the user. Someone asked me, "How do you build a usability test to prove that people are delighted?" And I said, "I don’t think I would do that. I’m not usability testing for delight. I’m usability testing that we’ve solved the correct problem with a good execution of a good concept." So we get hung up on some of these buzzwords. And so I say to people, forget the buzzwords. Take that MBA approach. That’s why I went and got an MBA. I could have gone out and gotten a master’s in UX HCI. Human factors.

Debbie: I went for the MBA because when I come in, I want companies to know that I care about how the business works, I care about how the business runs. I care about the business making money. Yes, I want it to be done ethically. Yes, I want it to be done with customers in mind, with DEI, with accessibility, but I am dedicated to good, solid, long-term, not quick shortcuts, ethical ways to attract those customers, genuinely make them happy, not fool them into some sort of weird high score or pay them for a good rating. And then loyalty because we’ve built something great. The example I use is I am a super wacky wild fan of Monday.com (hashtag not sponsored). I just paid them for another year. They pay me nothing. They have no idea who I am. Can you think of a system that you freaking love that much that you are going to tell people this thing is the bomb?

Debbie: You couldn’t pull me away. When I left my previous project management system for Monday, the CEO contacted me, "You’ve been with us for 10 years. What can I do to keep you?" I said, "Nothing. I wouldn’t stay if it were free, I wouldn’t stay if you paid me." Monday is a better match to my needs and tasks. I will be more productive there. Those are my standards. So we have to be using better research, earlier research, generative qualitative research to know our customers so that we can say we really built that thing. Was it 20 years ago, we talked about the killer app. We don’t seem to care about that anymore. We don’t seem to care about if we’re really building what customers need. We seem to care about checking stakeholders ideas off a list.

Vitaly: That’s right. I think I also read an article about the boring designer or boring products that we actually got. So in the past, as you were saying, we got so excited about building just that cool thing that’s going to take off and take over the world. But now I think that many of us have discovered the sympathy and I guess also interest in just boring product that help us sleep better. I always go in a medium and your collective and so on. And I read all these articles and I would love to see more things about, I don’t know, healthcare or enterprise, B2B, CX, UX, I don’t know, anything like that. Those kind of case studies. They’re not necessarily most exciting applications to some people, but they’re also so important. It’s so interesting to solve.

Vitaly: And maybe one thing I wanted to dive in a little bit deeper with you here as well is, so if you encounter a situation where you are in that legacy environment and corporate environment and enterprise environment and whatnot, the question is for me at least in my work, is to always prove that what I’m doing is moving in the right direction, kind of moving the needle in the right direction. So again, what you’re saying is just music to my ears, speaking business terms to people on who are your managers. I think this is an incredibly important skill for designers to have rather than having the design, I don’t know, design dish, I guess, which many people might not understand.

Vitaly: So I’m wondering though, how do you convert the needs that the company has in terms of business into something that’s necessarily customer-centric? Because at least this was my experience, it cannot not necessarily go hand in hand. Sometimes we end up with some business goals, which are we need to be aggressive on the market, we need to take over, we need to be better than every competitor. We need to be, I don’t know, newsletters all over the place. We need to be as prominent as possible. How do you balance it out with something that’s more, because it’s more like short term, long term? Because usually in my experience, you need a strategy for both.

Debbie: Oh, there are a lot of questions rolled into there. I’m trying to figure out where I start. I think that companies are looking very much at the short term a lot of times. So you have to have a short and a long term strategy. But a lot of people don’t even have a strategy. As you said, they’re just saying, "More newsletters, more content, just more things. And then we’ll throw those darts and see what happens." And I think that companies have to get a little bit more focused. And a lot of that goes back to customer intelligence.

Debbie: If you don’t really understand who Debbie is and why she comes to your site or uses your product or is still at the trial version and hasn’t paid. If you are guessing or making things up about me or trying to assume something about me because I’m a 50-year-old white woman, then you don’t really have good customer intelligence. You are probably going to be guided mostly by guesses, assumptions, and copying your competitors. And you can do that. But let’s not pretend you’re innovative. Do not sing the song of we’re innovative if you’re just going to copy your competitors.

Debbie: But I think that one of the biggest key steps that a lot of companies need to take that they haven’t taken is they need at least a few customer-centric metrics. Very often when we look at a company’s KPIs, not only are they business-centric, but as you said, very often they’re the opposite of what people want to do. When I see a KPI in a company or even a North star metric of how many people did we get to apply to jobs? And I go, well, that’s funny because we know that people want to apply to as few jobs as possible.

Debbie: So you’re going to try to make people apply more in a world where people want to apply less, there is a mismatch here. And what often happens is because we are feature factories and because we tend to be very stakeholder driven, the stakeholder says, "Look, we just want to see these numbers go up. We want to see more people applying to jobs." And I say, what about the long term mark of their success or happiness? "It doesn’t matter. We just want to see more people applying to jobs." And then they’ll do whatever it takes. And we see this reflected in traditional impact maps, which in my chapter 18, I blow impact maps out of the water and I give you a different version of them that’s more customer focused. But you see these impact maps that are like, "Hey, what do you want to make happen? You want to make people click on a button more? Well, cool, as you said, more newsletters, more discounts, more whatever, you more content, more emails." Hands up who wants more emails?

Debbie: So I think we have to start with always looking at both, how does this create something the business wants? And we have the metrics to measure that and how do we make sure this is something that’s going to produce in our customers what they would want for themselves. We want them to be loyal, but we can’t trick people into being loyal. We can’t force them into being loyal, that’s a short-term win. It’s not going to be a long-term win. So we have to start with some of these metrics and being able to have some tough conversations around crappy metrics. How many page views did someone see? I have an example in the book where when I tried to log into an online stock investing account, I saw six pages before I could get into the account.

Debbie: Now we all know that that could be done in one screen. It absolutely can be done in one screen. Hey, what’s your username and password? Hey, we sent you a text to make sure it’s really you. Hey, it’s really you. Thanks for chopping by. You’re in. That could be one screen. This was six separately loading pages. And I swear one page was just a giant screen that said, "We’re going to text you a code." Continue. And that’s how I know someone has a metric of more page views. Congratulations on achieving your more page views metric. That’s a vanity metric. It’s meaningless. It doesn’t improve the customer experience. So we have to start looking at both of these in terms of each other.

Debbie: Which is hard for companies. They’re going to need consultants, they’re going to need specialists. They’re going to need new people because the same old people that are there are probably used to tap dancing along with the way we do things and following and not making waves and not challenging the status quo. You’re going to need a few new leaders or a couple of consultants to come in and shake that up and say, "Look, it’s great that you’ve been successful thus far. You’re doing many right things, but there’s room for improvement. And you have to be open to that change."

Vitaly: Yes, I think one of the funny things is that I often find so much passion, I would say around things like time on site as well, but what does it mean time on site? Does it mean that people like what they see? Does it mean that they don’t find what they need? Does that mean that they’re just totally frustrated and annoyed just try to find it all over the place because search is not working well? What does it even mean? All those things are not really reflecting in any way the customer experience at all. So that’s very much aligns to my experience I guess as well. There is one thing that’s really is probably to me the most problematic, and that’s the shift of culture in a company like that. So the problem is that very often, very different departments have their own set of KPIs and they track trying to improve their own KPIs and very much they’re not really aligned.

Vitaly:So maybe one department just wants to publish more just to be out there. The other department will be looking at traffic and other things and the other, what is our velocity in terms of their deployment or features that we have and things like that. But then we need to really change the culture so that we have this customer centricity as again, our north star. And so that defines what is going to happen in all these different departments, but that requires a lot of movement in organization, which is really slow and a lot of time as well. Now, fortunately, we have wonderful people like you who come in and just hoof and get it all done.

Debbie: Well, not quite. But yes, I try to push as many boats out and as many needles as I can. I usually can’t get all the changes on my list done. Sometimes I’m lucky if I can get half, but I can go into a place and I can affect change. But obviously that company has to want to change, but then you also have to have that change management hat on because that company’s afraid to change. They feel they’ve been really successful thus far doing it this way. Why should we care about that? Why should we prioritize? I remember having a conversation, I think I put it in the book where I said to someone, almost all of our app ratings in the last X months are one in two stars, and I’ve confirmed that the complaints are valid, we really are broken. And I said, what are we doing about that?

Debbie: And the person said, "Well, we have a 4.6 rating out of five overall on the Apple Store. So what’s the problem?" And so again, like you said, if you’re watching the wrong metrics, you can tell yourself any story you want. I can tell myself any... I recently lost 10 pounds. I thought I looked amazing until the pictures came back. And then I said, I’ve got more change to make. So you can see numbers and you can tell yourself any story you want. The better company with that better future is going to tell itself some more honest stories about that, which is, isn’t it great we’ve got a 4.6 rating in the Apple Store that’s probably going to help us get download a little bit more than if our rating was lower? But we probably should prioritize all of these complaints coming in, especially since we found that these aren’t just complainers.

Debbie: These are valid complaints. So what I have found in companies, what tends to block this is usually in some cases, a very toxic leader, a narcissist, a malignant narcissist, a person who the only way to do it is my way. A person who will make up fake facts and fake stories. A person who creates fear in people under them. A person who loves to put people on performance review plans or performance improvement plans when you speak up against the status quo or question something or want to try something different. So first of all, to me, there are a few toxic leaders. And the wacky thing is every company I go into has them and every company knows who they are. And I always say, you know who this is. And they stand out from other people, which means you’ve done a good job hiring.

Debbie: If they fit in and everyone’s like that, then this needs an atomic bomb to fix. But these people are different because they’re that bad. Why aren’t we removing them? Or why aren’t we shifting what they do? Why aren’t we demoting them? Why aren’t we putting them on a performance improvement plan? Why do we allow them to continue to create such negativity and carnage? And in some cases, attrition, people quit. They can’t stand to deal with that person anymore. So we have to do something about those toxic people and we have to work with corporate strategists on how they measure success. How do we measure success internally? If it’s making people click the button that nobody wants to click, that’s just going to come down the line. And especially in companies where CX and UX have no voice, then you just have the engineering team pushing for faster delivery and you have the product team pushing for I am unfortunately an order taking puppet who’s just going to do what the stakeholder says and not really push back and stuff like that.

Debbie: We need people. We claim we have empowered teams, we claim we want empowered teams. We don’t. We’re not even close. And somebody with some watts has to start saying out loud, we’re not empowered. We’re not empowered. We’re not living up to our company values. I saw a company last year who was not living up to their company values, changed their company values, and they changed them to the most watered down, meaningless things I’d ever seen in my life. You can do that. You can make your company values more meaningless if you’re having trouble adhering to them, but that also sends a message. So you’re right, it’s a complicated thing. There’s a lot of gears locked into each other and I can’t say, here’s that one thing that everybody needs to do that’s going to really help. It’s mostly speaking up against the status quo.

Debbie: Does it mean that your job could be on the line or you could receive some badness from saying those things out loud? Sure. At an unhealthy company, there could be that retaliation. There isn’t supposed to be, but there could be. So you take that chance. A lot of people don’t want to take that chance. And that’s why I say bring in the outside consultants. I will come in, I will say everything that needs to be said, and you know in six months I’m gone anyway. I have no horse in the race. I just want to tell the truth. But a lot of people working there can’t tell the truth anymore. And that’s a bigger culture problem, as you said. So I don’t have the one magic bullet. If I had the one magic bullet, my book would be 10 pages long. Three pages of introducing the magic bullet, five pages about the magic bullet and two pages thanking everybody for reading.

Debbie: But my books tend to be on the long side because I am trying to walk people through a lot of different instances and scenarios that they will run into at their jobs as consultants and say, here’s some things you can try to just chip away at that piece. Because if you try to look at the whole mountain of overwhelming BS at our companies, you just give up. You go, how am I ever going to change that monolith? But we have to look at some of the smaller pieces and how we can make small changes there just to start and just to show the company it’s worth it.

Vitaly: Debbie, we could be speaking for hours of course and have so many questions prepared, which I know didn’t get to, but I do have to ask one question that has been bothering me for a very long time, and I still haven’t found the proper answer to that. So can you make this shift? Like transition to customer centricity in an organization without a proper commitment from the top?

Debbie: Oh, definitely not. Because what I found is that everything comes from the top. You can certainly have a bottom up swell of support for this. It can be a bottom up person who goes to their manager and says, "Why aren’t we saying more about this?" And that person goes to their manager and says, "Look, we know this sucks. Why aren’t we saying more about this?" So there can be some bottom up support and action, but the change and everything else comes from the top. That’s it. Now, we may not have to impress the C level executive, they may be too high up. They may not care as much about some of the day-to-day. Sometimes it’s those mid or high level leaders, maybe the directors or heads or whatever it might be in a particular country or business’ hierarchy. Those are the people. The people looking at budgets, the people looking at outcomes, the people checking on the KPIs.

Debbie: It’s not always the C level. It’s probably somebody below them and they just report up. So it’s those people that we have to affect. Could be VPs. Those are the people that we have to go to and say, "Look, we know you want more adoption, satisfaction and retention. How’s that going right now?" "Not so well." "Oh, why not?" "I don’t know." That’s our first problem. Why don’t we know? They usually don’t know why. Or they’ve made something up. People are disloyal, they’re tire kickers, they’re broke, they’re whatever, echo. Cool, bro, you made that up. You don’t really know. That’s probably only true for a certain percentage of your customers. Let’s not work from guesses. Let’s not work from assumptions. Let’s use guesses and assumptions as an opportunity to dive deeply into customer intelligence. You think a survey’s going to answer that? Go ahead. Start with a survey.

Debbie: When the survey comes back, I’m going to ask you again, what do we know and what don’t we know? Is that survey enough to take action and do we know what action to take? If we’re guessing again and going into another brainstorming workshop to guess again, we still don’t know. And so I want to make sure that we are not creating these strategies or making these decisions or pushing these KPIs without better knowing some stuff, knowing some stuff internally about ourselves, knowing some stuff externally about users, customers, partners. Obviously this ends up falling into service design, which to me can also be CX and UX. These all float in the same ocean. But that’s what I tried to tell people is you don’t even know. You don’t even know why sales is losing people. They picked a competitor. That’s not the full answer. That’s the surface level answer.

Debbie: Oh, our NPS is low. Do you know why? We can’t seem to retain people. Sales even offered them 10 bucks. Do you know why? I just keep pushing for why don’t we know why? Shouldn’t we know why? Can you give me four to six weeks to start learning why? And some companies will go, "Oh, it’s only four to six weeks? I thought it was months." It doesn’t have to be months. I can get you some preliminary data from generative observational or interview research in four to six weeks. Can we start there? Yes. Then you make sure you collect their-

Vitaly: That’s probably going to be very difficult to say no to that.

Debbie: Well, look, and especially as a consultant, I then put a number on that, and I don’t overcharge as a consultant, I’m very fairly priced. I hear, I’m under-priced. I say, "Hey, a six-week project, let’s just call it five figures." It’s 60, 80, whatever, thousand dollars. Maybe I have to throw more people on it to make it go faster. It’s a hundred something thousand dollars. Hey, how much money are we losing right now in customer loyalty? How much money are we losing because sales couldn’t get those people to stay? Isn’t $150,000 worth it and six weeks for us to be able to answer all these questions of why and to replace these guesses and assumptions with knowledge? We don’t have to work from guesses and assumptions. We can work from really good knowledge that goes beyond our market research, that goes beyond demographics to look at behaviors and perspectives and tasks. I am task-oriented person 100%.

Vitaly: Well. I think also there are so many different other stories and companies that you also mentioned in your book of course. So this brings me to an important of probably the last question for today. Given the fact that you’ve been working again with small and large companies all over the place, what were some of the most interesting lessons you learned? What would say some patterns which emerge, you would say, if this is that kind of company, I have to do this. Or if that’s kind of company, I’m going to do that. If this, oh, no, I’m running away. This is not, no, no, no, I’m not going through that. So would you say are some of the most important notable lessons that you’ve learned? Just maybe a few personal stories. It’s always interesting to hear.

Debbie: Yes, sure. One of the things that I mentioned in my book and in the workshop version of the book, I talk about making sure... A lot of change management courses say, find your allies. But I say also identify your detractors. There are going to be those toxic leaders who want you to fail. They don’t want that change because even if that change brings something good, people might wonder why they didn’t make that change. It accidentally shines a negative spotlight on them. So you’ve got detractors, you’ve got toxic people who are probably going to work against what you are there to do. It’s important to identify them and to manage them. And I won’t have time to go into how, some of that’s in the book, but you’ve got to manage those detractors. You can’t just focus on who are my allies or who is excited about this or who’s buying in.

Debbie: You have to look at who might sabotage this or me. That’s definitely one of the things that I would warn people about. And another reason why I remind people, this may be an area where you do want to bring in consultants because that person can sabotage the hell out of me and undercut me as much as they want and make themselves look foolish, and then I’m gone. But if you work in a company and you try to do some of this stuff and that person sabotages, you could lose your job. You could be demoted. I’ve seen this. And so that’s a place where you want to put me in front of the target instead of yourself. Save yourself. That’s one thing. Another thing is you have to look for the company’s compelling reason to change. You have to figure out why should they change?

Debbie: Because again, many companies, even those who claim they want to change, they claim they want to be customer-centric, they claim they want more customer journey maps. Even when companies claim this, a lot of times they really don’t want to change. They’ve been profitable. They’ve been making money, they’ve been growing stock prices, doing okay, whatever ways that they measure themselves, they’re usually pretty happy. And so the question is, now, do you want to run away from that and say, these people don’t want to change, I’m not going to bother? Or can you find either that compelling narrative or that reason for them to make some sort of change or find the area in which they are willing to change? And that’s hard. Last year I was working with a 1 billion dollar European company that competes against Indeed there, therefore job posting and applying to jobs.

Debbie: And when you’re a $1 billion company and you’re the market leader of Germany, why change? Is it going so badly? Can we just say, this is going pretty well? And so that’s hard. So I had to find some places and some allies where we could get people to say, you know what? This part of things isn’t going as well as it could. And oh yes, our UX team doesn’t really have a voice, isn’t really treated well, are treated as order takers. What can we do to improve that? How do we elevate our user experience work and workers? So I think it’s a matter of, and I know that we’re supposed to stop saying things like, pick your battles because it’s violence based language. And I’m still bad at that, I apologize. But we really have to take a look at where can I make change?

Debbie: Where will they let me make change? That’s why when I do the Mary Poppins thing, I say, hey, look, I fly in, fix as much as I can, as they’ll let me, and then I fly away. So you have to find the places where that door is open or where you can create that compelling narrative. Has the company lost a lot of money in a certain area lately? Have they burned customer trust and now they’re over-utilizing customer support? And it would be great if people weren’t so unhappy in calling in so much that saves companies money. You have to start looking for all of that. And so one of the exercises in chapter 18, which I’ve been doing on my YouTube show on some Mondays, is the Delta CX version of an impact map. Where we start not with what the company wants to do, we start with the customer’s problem, and then we look at what’s the root causes of that, and then what’s the impact on the business?

Debbie: What’s happening in the business, what money, time, resources, environmental damage, what’s happening because we have this customer problem and these root causes we haven’t addressed. If you can start building something like the Delta CX impact map version, you now have that built in argument. We need to make this better for our customers because here’s all the stuff. Here’s all the waste and risk and lost time and money that our company is dealing with, and that’s what we’re going to save. These are the arguments that we need to start making on all levels. Could a junior make that argument? They could try. Why not? They’ll have access to some of that information, but it’s probably more for our managers and leaders. You got to find that small open door.

Vitaly: Well, if you the listener would like to hear more from Mary Poppins or also called Debbie, you can find her on LinkedIn where she’s, guess what? Debbie Levitt, but also on her website, Delta CX. And of course, get her wonderful book: Customers Know You Suck: Actionable CX Strategies To Better Understand and Track and Retain Customers, well, whenever you get your books. Now, thank you so much for joining us today, Debbie. Should I call you Mary? No, probably not.

Debbie: No, I’m definitely Debbie. Mary Poppins is somebody else. And I also want to mention we’re putting up a website at customercentricity.com, which will have even more information because guess who owns that domain? And you can also grab my book at DeltaCX.media, which is where I’ve got information about our books and workshops, and we’ve got the digital version up for as little as $1. So if anybody is from a country or area or life situation where buying a book right now doesn’t feel affordable, we do have the $1 version to try to make it more available.

Vitaly: That’s wonderful, Debbie, wonderful. Well, as we often do in the end though. Well, imagine somebody listening to this 20 years from now thinking, oh, they had problems in 2023 mean, but by now, like 2043, we have solved CX issues for good. So is there anything you’d like to send out to the future or any parting words of wisdom you’d like the future generations to follow along? Like I don’t know, maybe aliens 200 years from now thinking, how do we improve CX of our ships?

Debbie: Yes, that’s a hard one. I can certainly hope for the future. I can certainly hope that in the future we’ve made more ethical choices, we’ve made more customer-centric choices. We’ve realized that we have no business, no staff, no money if we aren’t making customers happy. I don’t know. I wonder what our problems, I think in, I want to say 2043, but it really feels like it’s going to be 2025 where we’re battling for what should we let a machine learning machine do, and what should we let a person do? I think that’s going to be our first challenge. I can’t even think out to 2043 right now. I have to admit. I really think that the, we’re already seeing the question of what do we really need Debbie Levitt to do, and what can we ask a bot to do? And what I’ve noticed is a bot can rehash stuff that’s out there.

Debbie: For example, if you go to Google right now and you say, how do I be more customer-centric? See a load of great sounding things that aren’t actionable at all, you’ll see, “Care about your customer. Build empathy. Brainstorm and be innovative.” None of those are actionable. You’ve no idea what to do and what not to do. So I think if we can just talk about the nearer future instead of the distant future when it’s the robot uprising, I think that our more immediate challenge in the coming years will be how do we keep critical thinking about what the bots are feeding us or returning to us to make sure that even if we do find a place for what I’m calling bots to assist us in our work or be part of our adventures. How do we make sure we’re still critically thinking about what we’ve put into them and what we’re getting out of them? Because I see a lot of stuff that people are very excited about that just looks like crappy rehashed articles you can find anywhere on Google or Medium and blog posts that just say, “Yeah, have more empathy and make a customer journey map and be more customer-centric.” That doesn’t help you at all. And that may be where our AI is for some time because it’s not yet a thinking robot. It doesn’t have my ability to be strategic. So that’s my wish for the immediate future because I can’t even think about 2043. Hope you don’t mind the answer.

]]>
hello@smashingmagazine.com (Drew McLellan)
<![CDATA[Free Fonts For Interface Designers]]> https://smashingmagazine.com/2023/03/free-fonts-interface-designers/ https://smashingmagazine.com/2023/03/free-fonts-interface-designers/ Mon, 20 Mar 2023 09:00:00 GMT Not every project has the budget to spend a lot of money on fonts. But that doesn’t mean that typography needs to play a secondary role when the budget is tight. The variety and quality of free and open-source fonts out there is impressive and enables everyone to use beautiful, well-crafted typefaces.

In this post, we compiled some free fonts that we came across and that you probably haven’t spotted before. Some of them shine with their flexibility, some put a special focus on readability, and others are a great choice if you want to make a bold statement. As different as the fonts are, they all have one thing in common: You can use them for free in both personal and commercial projects. A huge thank-you to the wonderful type designers and contributors for making their fonts available to all of us! 👏🏼👏🏽👏🏾

Recursive

Built to maximize versatility, control, and performance, Recursive is a five-axis variable font that can go from Sans to Mono. Taking full advantage of variable font technology, it gives you full flexibility.

Recursive allows you to choose from a wide range of predefined styles or dial in exactly what you want for each of its axes: Monospace, Casual, Weight, Slant, and Cursive. Inspiration came from single-stroke casual signpainting to give the font a flexible and warmly energetic look, making it a great fit for data-rich-apps, technical documentation, code editors, and much more. Designed by Stephen Nixon, with contributions from Lisa Huang, Katja Schimmel, Rafał Buchner, and Cris R Hernández.

Yrsa & Rasa

The type families Yrsa and Rasa have a different approach than other type projects. They build upon the existing typefaces Merriweather and Skolar Gujarati to produce two entirely new type families that span different writing systems.

Yrsa supports over 92 languages in Latin script and has a special focus on properly shaping the accents in Central and East European languages. Rasa supports a wide array of basic and compound syllables used in Gujarati. Both type families include five weights and are intended for continuous reading on the web. Perfect for longer articles in online news, magazines, or blogs. Designed by Anna Giedryś and David Březina.

Space Grotesk

Space Grotesk is a proportional sans-serif typeface variant based on Colophon Foundry’s fixed-width Space Mono family. It retains the idiosyncratic details of the monospace while optimizing for improved readability of non-display sizes.

Space Grotesk includes four weights and open-type features like old-style and tabular figures, superscript and subscript numerals, fractions, and stylistic alternates. Latin Vietnamese, Pinyin, and all Western, Central, and South-Eastern European languages are supported. Designed by Květoslav Bartoš for Florian Karsten Typefaces.

Figtree

Figtree combines friendly curved shapes, a simple monolinear construction, a high x-height, and slight taper into a charming geometric typeface that ensures maximum readability.

Figtree comes in seven weights, ranging from Light to Black, and includes typographic finesses such as fractions, monospace numbers, and scientific inferiors. Minimal but not stiff, casual but not silly, the typeface beautifully manages to maintain a crisp, clean feeling. Designed by Erik Kennedy.

Reforma

Reforma is a versatile font family designed for long-form reading. Commissioned to celebrate the centenary of the university reform of the Universidad Nacional de Córdoba, Argentina, the typeface had to convey four premises: plurality, intellectual heritage, versatility, and free availability.

After three years of work, 20 font styles were born that work harmoniously in different contexts. They are grouped into three subfamilies — from a classic serif to a modern sans-serif and an intermediate hybrid style with flare serifs — and are available in three weights plus an ultra-black companion set for headings. Reforma beautifully manages to strike the balance between tradition and novelty while staying super-versatile. Designed by Alejandro Lo Celso, Jorge Ivan Moreno Majul, Francisco Galvez Pizarro, Francis Ramel, and Oscar Yañez.

Hanken Grotesk

If you’re looking for a versatile sans-serif typeface inspired by the classic grotesques, Hanken Grotesk might be right down your alley. It shines with a friendly, distinguishable look and is equally suitable for small text and headings.

Nine weights are available, ranging from Thin to ExtraLight, Light, Regular, Medium, SemiBold, Bold, ExtraBold, and Black. Each weight comes with matching italics. A modern classic designed by Alfredo Marco Pradil.

Grenze

Grenze combines the best of two worlds. As a hybrid between Roman and Blackletter styles, it transports a sense of boldness and texture while at the same time offering the readability of classical typefaces.

The family includes nine weights (Thin, Extra Light, Light, Regular, Medium, Semibold, Bold, Extra Bold, and Black) with matching italics. To respond to different needs, Grenze comes with some useful advanced features such as ligatures, ornaments, extended language support, and various figure sets. Designed by Renata Polastri and the Omnibus team.

Fira Sans

Originally designed as a system font for Mozilla’s FirefoxOS, the humanist sans-serif Fira Sans grew into a versatile open-source typeface that stays readable across screen qualities and sizes.

Fira Sans is available in 18 styles, including nine weights and accompanying italics. The package also includes a mono-spaced variant. Designed by Carrois Apostrophe in cooperation with Erik Spiekermann.

Atkinson Hyperlegible

Certain letters and numbers can be hard to distinguish from one another for low-vision readers. Atkinson Hyperlegible is here to change that. Named after Braille Institute founder J. Robert Atkinson, the typeface focuses on letterform distinction to increase character recognition and improve readability.

Recognizable footprints, differentiated letterforms, unambiguous characters, and exaggerated forms are some of the techniques that optimize readability and give the typeface its distinctive look. Atkinson Hyperlegible includes four fonts, with two weights (Regular, Bold, Italics, Italics Bold). Thanks to accent characters, 27 languages are supported. Designed by Braille Institute of America.

Anek

The multi-script typeface Anek tells a very special story. It covers nine Indian languages plus Latin and was created through a collaboration of twelve type designers working across eight cities in India. The design of each script is deeply rooted in its typographic culture, while the different scripts live together in visual harmony.

All Anek fonts share visual similarities like circles and circular shapes, robust letter structures, and delicate joineries. With 40 styles per set, Anek is one of the few Indian variable display fonts with such a large set of weight and width styles. Designed by Sarang Kulkarni, Girish Dalvi, Noopur Datye, Hanif Kureshi, Maithili Shingre, Yashodeep Gholap, Divya Kowshik, Aadarsh Rajan, and Shuchita Grover.

Source Sans

Designed by Paul D. Hunt, Source Sans is Adobe’s first open-source typeface family. The sans-serif draws inspiration from classic grotesques and is characterized by a visual simplicity that works equally well in long-form texts just like as short labels in user interfaces.

Source Sans comes in six weights (ExtraLight, Light, Regular, SemiBold, Bold, Black) plus matching italics. The fonts offer wide language support for Western and East European languages, Vietnamese, Pinyin romanization of Chinese, and Navajo. A modern classic.

Beattingvile

If you’re looking for a font to give your project a personal, hand-made touch, Beattingvile by Garisman Studio is worth checking out.

The multilingual script font features stylistic alternates, swashes, and ligatures and is perfect for all projects where you want to make a statement that is a bit bolder. Perfect for headings, branding, label design, logo type, quotes, and much more — both on screen and in print.

Disket Mono

Monospace fonts often have a technical feel to them, waking connotations of coding editors or typewriters. Disket Mono is a bit different. The font strikes a perfect balance between the inspiration it draws from geometry, grids, and architecture and using soft corners for a more tactile, personal feel.

Disket Mono comes in two weights (Regular and Bold) and supports twenty languages. A beautiful display font, designed by Mariano Diez.

Srbija Sans

Srbija Sans is a neo-grotesque sans-serif typeface with a geometric look. It gets by without any decorative details, but when you look more closely, you’ll notice how small design decisions improve readability and give the clear shapes a warm and natural touch.

The typeface includes 315 glyphs, supporting Latin and Cyrillic, and featuring accents and ligatures, mathematical symbols, and currencies. Srbija Sans was designed by Vedran Eraković and Studio Metaklinika for the National Tourism Organisation of Serbia.

The League Of Moveable Type

The League of Moveable Type opened its doors back in 2009 when designers were just gaining the ability to put custom fonts on the web. The project’s mission has stayed the same since day one: to raise the design standards of the web.

Micah Rich, maintainer of the foundry, cares deeply about good typography and empowering everyone with great design skills. That’s why the catalogue only features carefully-picked open-source fonts — 17 at the moment. You can use them for free however and wherever you want.

Google Fonts

It’s certainly not an insider’s tip but always a great place to look for free fonts: Google Fonts. The library features more than 1,400 open-source font families for more than 135 languages, plus icons for common actions and items.

By the way, if you want to dive deeper into the principles of typography or delve into all of the artistic and technical aspects of modern typesetting and font technology, the Google Fonts Knowledge library is a treasure chest of typography wisdom.

Wrapping Up

Do you have a favorite free font that isn’t listed in the post? Let us know in the comments below. We’d love to hear about it!

]]>
hello@smashingmagazine.com (Cosima Mielke)
<![CDATA[Internationalization In Next.js 13 With React Server Components]]> https://smashingmagazine.com/2023/03/internationalization-nextjs-13-react-server-components/ https://smashingmagazine.com/2023/03/internationalization-nextjs-13-react-server-components/ Thu, 16 Mar 2023 20:00:00 GMT next-intl to implement all internationalization needs in React Server Components and shares a technique for introducing interactivity with a minimalistic client-side footprint.]]> With the introduction of Next.js 13 and the beta release of the App Router, React Server Components became publicly available. This new paradigm allows components that don’t require React’s interactive features, such as useState and useEffect, to remain server-side only.

One area that benefits from this new capability is internationalization. Traditionally, internationalization requires a tradeoff in performance as loading translations results in larger client-side bundles and using message parsers impacts the client runtime performance of your app.

The promise of React Server Components is that we can have our cake and eat it too. If internationalization is implemented entirely on the server side, we can achieve new levels of performance for our apps, leaving the client side for interactive features. But how can we work with this paradigm when we need interactively-controlled states that should be reflected in internationalized messages?

In this article, we’ll explore a multilingual app that displays street photography images from Unsplash. We’ll use next-intl to implement all our internationalization needs in React Server Components, and we’ll look at a technique for introducing interactivity with a minimalistic client-side footprint.

Fetching Photos From Unsplash

A key benefit of Server Components is the ability to fetch data directly from inside components via async/await. We can use this to fetch the photos from Unsplash in our page component.

But first, we need to create our API client based on the official Unsplash SDK.

import {createApi} from 'unsplash-js';

export default createApi({
  accessKey: process.env.UNSPLASH_ACCESS_KEY
});

Once we have our Unsplash API client, we can use it in our page component.

import {OrderBy} from 'unsplash-js';
import UnsplashApiClient from './UnsplashApiClient';

export default async function Index() {
  const topicSlug = 'street-photography';

  const [topicRequest, photosRequest] = await Promise.all([
    UnsplashApiClient.topics.get({topicIdOrSlug: topicSlug}),
    UnsplashApiClient.topics.getPhotos({
      topicIdOrSlug: topicSlug,
      perPage: 4
    })
  ]);

  return (
    <PhotoViewer
      coverPhoto={topicRequest.response.cover_photo}
      photos={photosRequest.response.results}
    />
  );
}

Note: We use Promise.all to invoke both requests that we need to make in parallel. This way, we avoid a request waterfall.

At this point, our app renders a simple photo grid.

The app currently uses hard-coded English labels, and the dates of the photos are displayed as timestamps, which is not very user-friendly (yet).

Adding Internationalization With next-intl

In addition to English, we’d like our app to be available in Spanish. Support for Server Components is currently in beta for next-intl, so we can use the installation instructions for the latest beta to set up our app for internationalization.

Formatting Dates

Aside from adding a second language, we’ve already found that the app doesn’t adapt well to English users because the dates should be formatted. To achieve a good user experience, we’d like to tell the user the relative time when the photo was uploaded (e.g., “8 days ago”).

Once next-intl is set up, we can fix the formatting by using the format.relativeTime function in the component that renders each photo.

import {useFormatter} from 'next-intl';

export default function PhotoGridItem({photo}) {
  const format = useFormatter();
  const updatedAt = new Date(photo.updated_at);

  return (
    <a href={photo.links.html}>
        {/* ... */}
        <p>{format.relativeTime(updatedAt)}</p>
      </div>
    </a>
  );
}

Now the date when a photo has been updated is easier to read.

Hint: In a traditional React app that renders on both the server and client side, it can be quite a challenge to ensure that the displayed relative date is in sync across the server and client. Since these are different environments and may be in different time zones, you need to configure a mechanism to transfer the server time to the client side. By performing the formatting only on the server side, we don’t have to worry about this problem in the first place.

¡Hola! 👋 Translating Our App To Spanish

Next, we can replace the static labels in the header with localized messages. These labels are passed as props from the PhotoViewer component, so this is our chance to introduce dynamic labels via the useTranslations hook.

import {useTranslations} from 'next-intl';

export default function PhotoViewer(/* ... */) {
  const t = useTranslations('PhotoViewer');

  return (
    <>
      <Header
        title={t('title')}
        description={t('description')}
      />
      {/* ... */}
    </>
  );
}

For each internationalized label we add, we need to make sure that there is an appropriate entry set up for all languages.

// en.json
{
  "PhotoViewer": {
    "title": "Street photography",
    "description": "Street photography captures real-life moments and human interactions in public places. It is a way to tell visual stories and freeze fleeting moments of time, turning the ordinary into the extraordinary."
  }
}
// es.json
{
  "PhotoViewer": {
    "title": "Street photography",
    "description": "La fotografía callejera capta momentos de la vida real y interacciones humanas en lugares públicos. Es una forma de contar historias visuales y congelar momentos fugaces del tiempo, convirtiendo lo ordinario en lo extraordinario."
  }
}

Tip: next-intl provides a TypeScript integration that helps you ensure that you’re only referencing valid message keys.

Once this is done, we can visit the Spanish version of the app at /es.

So far, so good!

Adding Interactivity: Dynamic Ordering Of Photos

By default, the Unsplash API returns the most popular photos. We want the user to be able to change the order to show the most recent photos first.

Here, the question arises whether we should resort to client-side data fetching so that we can implement this feature with useState. However, that would require us to move all of our components to the client side, resulting in an increased bundle size.

Do we have an alternative? Yes. And it’s a capability that has been around on the web for ages: search parameters (sometimes referred to as query parameters). What makes search parameters a great option for our use case is that they can be read on the server side.

So let’s modify our page component to receive searchParams via props.

export default async function Index({searchParams}) {
  const orderBy = searchParams.orderBy || OrderBy.POPULAR;

  const [/* ... */, photosRequest] = await Promise.all([
    /* ... */,
    UnsplashApiClient.topics.getPhotos({orderBy, /* ... */})
  ]);

After this change, the user can navigate to /?orderBy=latest to change the order of the displayed photos.

To make it easy for the user to change the value of the search parameter, we’d like to render an interactive select element from within a component.

We can mark the component with 'use client'; to attach an event handler and process change events from the select element. Nevertheless, we would like to keep the internationalization concerns on the server side to reduce the size of the client bundle.

Let’s have a look at the required markup for our select element.

<select>
  <option value="popular">Popular</option>
  <option value="latest">Latest</option>
</select>

We can split this markup into two parts:

  1. Render the select element with an interactive Client Component.
  2. Render the internationalized option elements with a Server Component and pass them as children to the select element.

Let’s implement the select element for the client side.

'use client';

import {useRouter} from 'next-intl/client';

export default function OrderBySelect({orderBy, children}) {
  const router = useRouter();

  function onChange(event) {
    // The `useRouter` hook from `next-intl` automatically
    // considers a potential locale prefix of the pathname.
    router.replace('/?orderBy=' + event.target.value);
  }

  return (
    <select defaultValue={orderBy} onChange={onChange}>
      {children}
    </select>
  );
}

Now, let’s use our component in PhotoViewer and provide the localized option elements as children.

import {useTranslations} from 'next-intl';
import OrderBySelect from './OrderBySelect';

export default function PhotoViewer({orderBy, /* ... */}) {
  const t = useTranslations('PhotoViewer');

  return (
    <>
      {/* ... */}
      <OrderBySelect orderBy={orderBy}>
        <option value="popular">{t('orderBy.popular')}</option>
        <option value="latest">{t('orderBy.latest')}</option>
      </OrderBySelect>
    </>
  );
}

With this pattern, the markup for the option elements is now generated on the server side and passed to the OrderBySelect, which handles the change event on the client side.

Tip: Since we have to wait for the updated markup to be generated on the server side when the order is changed, we may want to show the user a loading state. React 18 introduced the useTransition hook, which is integrated with Server Components. This allows us to disable the select element while waiting for a response from the server.

import {useRouter} from 'next-intl/client';
import {useTransition} from 'react';

export default function OrderBySelect({orderBy, children}) {
  const [isTransitioning, startTransition] = useTransition();
  const router = useRouter();

  function onChange(event) {
    startTransition(() => {
      router.replace('/?orderBy=' + event.target.value);
    });
  }

  return (
    <select disabled={isTransitioning} /* ... */>
      {children}
    </select>
  );
}
Adding More Interactivity: Page Controls

The same pattern that we’ve explored for changing the order can be applied to page controls by introducing a page search parameter.

Note that languages have different rules for handling decimal and thousand separators. Furthermore, languages have different forms of pluralization: while English only makes a grammatical distinction between one and zero/many elements, for example, Croatian has a separate form for ‘few’ elements.

next-intl uses the ICU syntax which makes it possible to express these language subtleties.

// en.json
{
  "Pagination": {
    "info": "Page {page, number} of {totalPages, number} ({totalElements, plural, =1 {one result} other {# results}} in total)",
    // ...
  }
}

This time we don’t need to mark a component with 'use client';. Instead, we can implement this with regular anchor tags.

import {ArrowLeftIcon, ArrowRightIcon} from '@heroicons/react/24/solid';
import {Link, useTranslations} from 'next-intl';

export default function Pagination({pageInfo, orderBy}) {
  const t = useTranslations('Pagination');
  const totalPages = Math.ceil(pageInfo.totalElements / pageInfo.size);

  function getHref(page) {
    return {
      // Since we're using Link from next-intl, a potential locale
      // prefix of the pathname is automatically considered.
      pathname: '/',
      // Keep a potentially existing orderBy parameter. 
      query: {orderBy, page}
    };
  }

  return (
    <>
      {pageInfo.page > 1 && (
        <Link aria-label={t('prev')} href={getHref(pageInfo.page - 1)}>
          <ArrowLeftIcon />
        </Link>
      )}
      <p>{t('info', {...pageInfo, totalPages})}</p>
      {pageInfo.page < totalPages && (
        <Link aria-label={t('prev')} href={getHref(pageInfo.page + 1)}>
          <ArrowRightIcon />
        </Link>
      )}
    </>
  );
}
Conclusion

Server Components Are A Great Match For Internationalization

Internationalization is an important part of the user experience, whether you support multiple languages or you want to get the subtleties of a single language right. A library like next-intl can help with both cases.

Implementing internationalization in Next.js apps has historically come with a performance tradeoff, but with Server Components, this is no longer the case. However, it might take some time to explore and learn patterns that will help you keep your internationalization concerns on the server side.

In our street photography viewer app, we only needed to move a single component to the client side: OrderBySelect.

Another aspect to note is that you might want to consider implementing loading states since the network latency introduces a delay before your users see the result of their actions.

Search Parameters Are A Great Alternative To useState

Search parameters are a great way to implement interactive features in Next.js apps, as they help to reduce the bundle size of the client side.

Apart from performance, there are other benefits of using search parameters:

  • URLs with search parameters can be shared while preserving the application state.
  • Bookmarks preserve the state as well.
  • You can optionally integrate with the browser history, enabling undoing state changes via the back button.

Note, however, that there are also tradeoffs to consider:

  • Search parameter values are strings, so you may need to serialize and deserialize data types.
  • The URL is part of the user interface, so using many search parameters may affect readability.

You can have a look at the complete code of the example on GitHub.

Many thanks to Delba de Oliveira from Vercel for providing feedback for this article!

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Jan Amann)
<![CDATA[Full Stack GraphQL With Next.js, Neo4j AuraDB And Vercel]]> https://smashingmagazine.com/2023/03/full-stack-graphql-nextjs-neo4j-auradb-vercel/ https://smashingmagazine.com/2023/03/full-stack-graphql-nextjs-neo4j-auradb-vercel/ Thu, 16 Mar 2023 10:00:00 GMT This article is a sponsored by Neo4j

Recently I was chatting with some folks about a book I wrote last year titled Full Stack GraphQL Applications. In the book, we demonstrate how to use GraphQL, React.js, and Neo4j to build and deploy full stack applications. One of the most common questions I get from readers is, “Can we use Next.js with this stack?” Next.js is a powerful React framework that adds many additional features and conventions on top of React, so the answer is “Of course!”

In this article, we will explore how to build a full stack GraphQL application that takes advantage of the API Routes feature of Next.js API to combine our GraphQL server and front-end React applications into a single framework.

We’ll use the Neo4j graph database as our data source. Graph databases like Neo4j use the property graph model to enable developers to model, store, and query data as a graph. Both graph databases and GraphQL use the concept of a ‘graph’ to work with application data, making them perfect to use together. The open source Neo4j GraphQL Library makes it even easier to build GraphQL APIs backed by Neo4j, as I’ll illustrate in this article.

Let’s see how to leverage the power of graph data by working with graphs in a full stack GraphQL application with Next.js, Neo4j, and Vercel!

Neo4j AuraDB Overview: Graph Data In The Cloud

First, we’ll set up our database. The easiest way to get started with Neo4j is by using the free tier of Neo4j AuraDB, Neo4j’s cloud database service. The free tier allows us to spin up a Neo4j cluster for building applications without a credit card. We can also choose from several sample datasets to get started. We’ll choose to load the “Graph-based Recommendations” dataset. This dataset contains information about movies and user ratings to demonstrate approaches for personalized recommendations, a common use case for graph databases.

While our database is being provisioned, we’ll be presented with a randomly generated password and the option to download a .env file that contains the connection credentials for our newly created database. Be sure to download this file, as we’ll use it to set environment variables in our Next.js application.

# Wait 60 seconds before connecting using these details, or login to https://console.neo4j.io to validate the Aura Instance is available
NEO4J_URI=neo4j+s://2826d3f8.databases.neo4j.io
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=vePwrRzzD23JjCug5tLSPF-pBNsmocHQ45hOc11d6ZY
AURA_INSTANCENAME=Instance01

Once our database is ready, click the Open button to start exploring the data in Neo4j Workspace. Neo4j uses the Cypher query language to interact with the database. The ‘Query’ tab allows us to execute Cypher statements and visualize the results as a graph. Cypher allows us to declaratively define graph patterns using ASCII-art notation. Later, we’ll see how we can use Cypher to find movie recommendations, but for now, this example demonstrates how to filter for a movie by title and traverse the graph to find the actors and genres of the movie as well.

Now that we have our database up and running, we can start to think about the API layer. To build our movies search application, we don’t want just to expose our database to the world — we want an API application to act as a type of gatekeeper, handling things like authorization and business logic. Thanks to a feature of Next.js called API routes, we can combine our GraphQL API application and our React front-end application in a single Next.js project.

Getting Started With Next.js

One of the easiest ways to get started with Next.js is with the create-next-app command line tool. This tool will ask us a few questions to help us create a skeleton Next.js project.

npx create-next-app fullstack-graphql-movies

This will generate a Next.js project with the following structure:

├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│   ├── _app.js
│   ├── _document.js
│   ├── api
│   │   └── hello.js
│   └── index.js
├── public
│   ├── favicon.ico
│   ├── next.svg
│   ├── thirteen.svg
│   └── vercel.svg
└── styles
    ├── Home.module.css
    └── globals.css

We will concern ourselves mostly with the files in the pages directory. With the Next.js file-based routing feature, any files we add to the pages directory will be given their own route using the filename. Let’s start our Next.js application by running the following command:

npm run dev

This will launch a local web server and serve our Next.js application at http://localhost:3000 by default. If we go to this address, we’ll see the default Next.js splash screen. The code for this page can be found in pages/index.js.

If we navigate in our web browser to http://localhost:3000/api/hello, we’ll see an example of a Next.js API route.

{
  name: "John Doe"
}

If we examine the code at pages/api/hello.js, we can see the logic powering this API endpoint, defined as a single function:

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction

export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

Similar to its parent pages directory, any file created in the API directory results in a new endpoint matching the name of the file. Unlike pages that define React components, the API directory defines new API routes which can be deployed as serverless functions.

In the next section, we’ll learn how to create a GraphQL server using a Next.js API route and the Neo4j GraphQL Library.

First, let’s bring over the .env file we downloaded from Aura and rename it .env.local in the root directory of our project. Next.js supports setting environment variables using .env files by default, so we’ll be able to use our Neo4j AuraDB credentials in our API route to connect to the database.

Building A Serverless GraphQL Server With Next.js API Routes

Now we’re ready to build our GraphQL API application as a Next.js API route. First, let’s install some dependencies, including the Neo4j GraphQL Library and GraphQL Yoga.

npm install graphql-yoga @neo4j/graphql graphql neo4j-driver

Since GraphQL Yoga supports Next.js API Routes, we’ll use it as our GraphQL ‘server’ framework. We’re going to use the Neo4j GraphQL Library to generate a full GraphQL API, including database queries, using just GraphQL type definitions. Let’s create a new file, graphql.js, in the API directory.

We saw the graph data model containing movies, actors, and genres for our movie’s dataset above, so we’ll write GraphQL-type definitions to match.

 type Movie {
    title: String!
    plot: String
    poster: String
    imdbRating: Float
    actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
    genres: [Genre!]! @relationship(type: "IN_GENRE", direction: OUT)
  }

  type Genre {
    name: String!
    movies: [Movie!]! @relationship(type: "IN_GENRE", direction: IN)
  }

  type Actor {
    name: String
  }

Note the use of the @relationship directive. GraphQL schema directives are GraphQL’s built-in extension mechanism and allow us to add additional information used in the Neo4j GraphQL Library’s schema generation process to configure the API. You can see more examples of directives in the documentation.

Next, we’ll read our Neo4j connection credentials from environment variables defined in the .env.local file and create a Neo4j driver instance to connect to the database.

// Read our Neo4j connection credentials from environment variables (see .env.local)
const { NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD } = process.env;

// Create a Neo4j driver instance to connect to Neo4j AuraDB
const driver = neo4j.driver(
  NEO4J_URI,
  neo4j.auth.basic(NEO4J_USERNAME, NEO4J_PASSWORD)
);

Next, we’re ready to pass our GraphQL type definitions and Neo4j driver instance as we create a new Neo4j GraphQL instance:

// Type definitions and a Neo4j driver instance are all that's required for
// building a GraphQL API with the Neo4j GraphQL Library - no resolvers!
const neoSchema = new Neo4jGraphQL({
  typeDefs,
  driver,
});

Because it involves verifying the schema and some database state, building the Neo4j GraphQL schema is an asynchronous process. I’ve moved the asynchronous bit to a function called initServer, which logs when it’s called. I did this so we can see in the application logs each time our GraphQL server is rebuilt. We’ll want to monitor this and make sure we aren’t rebuilding the GraphQL schema at each request, and this will help us do that.

// Building the Neo4j GraphQL schema is an async process
const initServer = async () => {
  console.log("Building GraphQL server");
  return await neoSchema.getSchema();
};

// Note the use of the top-level await here in the call to initServer()
export default createYoga({
  schema: await initServer(),
  graphqlEndpoint: "/api/graphql",
});

You’ll see that we used awaitwith our top-level module export. This is currently an experimental feature that we’ll need to explicitly enable in next.config.js.

const nextConfig = {
  reactStrictMode: true,
  webpack: (config, options) => {
    config.experiments = {
      topLevelAwait: true,
      layers: true,
    };
    return config;
  },
};

Enabling usage of top-level await will allow us to gracefully handle the asynchronous server setup in our API Route.

Now, if we run npm run dev, open our web browser, and navigate to http://localhost:3000/api/graphql, we’ll see the GraphQL Yoga GraphiQL in-browser IDE and be able to start querying our GraphQL API to fetch movie data from Neo4j. Note that we didn’t need to write any resolver functions or database querying logic to implement our GraphQL API. The Neo4j GraphQL Library generated operations for each type defined in our type definitions, including arguments for filtering and pagination.

Now that we’ve created a Next.js API route for our GraphQL endpoint, let’s see how we can use our GraphQL endpoint in our React application.

Client Side Data Fetching With Apollo Client In Next.js

There are several ways to approach data fetching with Next.js, such as static site generation, server-side rendering, and client-side rendering. We’re going to focus on client-side rendering with GraphQL — executing GraphQL requests from the client web browser to fetch data and update the DOM in our application. For an overview of other approaches to data fetching with Next.js, see this blog post that also shows other ways of using Neo4j with Next.js.

We’ll be using Apollo Client in our React application to execute GraphQL data fetching queries. Apollo Client has a React integration that uses hooks as the primary interface. Hooks are functions that allow us to ‘hook’ into React state and other lifecycle methods and are commonly used with data fetching in React applications. Let’s install Apollo Client and start using it in our React application.

npm install @apollo/client

We’ll need to update pages/_app.js to create our Apollo Client instance and inject it into the React component hierarchy so that we can make use of the useQuery and useMutation hooks that Apollo Client provides for interacting with a GraphQL API from our React application.

In pages/_app.js, we first import the modules we’ll need from Apollo Client.

import {
  ApolloProvider,
  ApolloClient,
  InMemoryCache,
  HttpLink,
} from "@apollo/client";

The ApolloProvider component uses the React Context API to make our Apollo Client instance available throughout our React application. The InMemoryCache and HttpLinkmodules are used to configure the cache and networking layer for connections to our GraphQL API.

Next, we’ll define a function to create a new ApolloClient instance, specifying the endpoint for our GraphQL API served as an API route.

const createApolloClient = () => {
  const link = new HttpLink({
    uri: "/api/graphql",
  });

  return new ApolloClient({
    link,
    cache: new InMemoryCache(),
  });
};

Then we can inject the ApolloProvider component into our React component hierarchy.

export default function App({ Component, pageProps }) {
  return (
    <ApolloProvider client={createApolloClient()}>
      <Component {...pageProps} />
    </ApolloProvider>
  );

Now we’re ready to start fetching data in our application. Let’s replace the Next.js default landing page with a movies search page that will allow us to search for movies by genre and see details about the top-rated movies. Later, we’ll add a movie recommendation feature to show recommended movies based on the top results.

We’ll replace the existing index.js, starting with some imports.

import React, { useState } from "react";
import { gql, useQuery } from "@apollo/client";

useState is a hook function that allows us to work with React state variables. useQuery is a hook function provided by Apollo Client that we’ll use to query data from our GraphQL API. The gql template tag helps with parsing GraphQL operations.

As you can see, hooks are such a fundamental part of React that we use a hook to manage state variables as well. To enable the user to search for movies by genre, we’ll declare a state variable to keep track of the user’s selected genre.

 const [selectedGenre, setSelectedGenre] = useState("Action");

Next, we need to define the GraphQL query used to search for movies by genre. We’ll also return information about the movie, like the poster URL and who acted in it. We’ll use a GraphQL variable in the query to filter for movies matching the selected genre.

const MOVIE_SEARCH_QUERY = gql`
    query MovieSearch($selectedGenre: String!) {
      movies(
        where: {
          genres: { name: $selectedGenre }
          imdbRating_GTE: 0.0
          poster_NOT:""
        }
        options: { limit: 100, sort: { imdbRating: DESC } }
      ) {
        title
        plot
        poster
        imdbRating
        actors {
          name
        }
        genres {
          name
        }
      }
    }
  `;

We’ll use this query with the useQuery hook to fetch data, passing in the value of our selectedGenre state variable. If we have an error or loading state from our GraphQL operation, then we render a placeholder.

 const { loading, error, data } = useQuery(MOVIE_SEARCH_QUERY, {
    variables: { selectedGenre },
  });

  if (error) return <p>Error</p>;
  if (loading) return <p>Loading...</p>;

We’ll use a simple select form input to let the user choose the movie genre. By binding the value of the form to our selectedGenre state variable, we have created what’s called a controlled component — a form that is controlled by React state.

To render the results of the movie search GraphQL query, we’ll map over the movie results and add a row to a table with the details for each movie. We can find the results of our GraphQL operation in the data variable, the shape of which matches the selection set of our GraphQL query.

<h2>Results</h2>
      <table>
        <thead>
          <tr>
            <th>Poster</th>
            <th>Title</th>
            <th>Genre</th>
            <th>Rating</th>
          </tr>
        </thead>
        <tbody>
          {data &&
            data.movies &&
            data.movies.map((m, i) => (
              <tr key={i}>
                <td>
                  <img src={m.poster} style={{ height: "50px" }}></img>
                </td>
                <td>{m.title}</td>
                <td>
                  {m.genres.reduce(
                    (acc, c, i) =>
                      acc + (i === 0 ? " " : ", ") + c.name,
                    ""
                  )}
                </td>
                <td>{m.imdbRating}</td>
              </tr>
            ))}
        </tbody>
      </table>

If we return to our web browser, we can see our application up and running. Try choosing a different genre in the form to see the results of our GraphQL search.

Now that we have our application running locally, let’s see how we can deploy this simple movie search application to the web using Vercel and Neo4j AuraDB.

Deploying to Vercel And Neo4j AuraDB

Next.js is a powerful React framework when used on its own, but when we pair Next.js with Vercel, a platform for deploying web applications, we can leverage some huge developer experience benefits. To deploy our application on Vercel, we’ll first push it to GitHub and connect the GitHub repository to a new project in Vercel. Later, we’ll show an advantage of using this approach when adding new features to our app: ‘preview’ deployments that allow us to test and share our updated application to gather feedback before updating the production deployment.

First, we’ll create a new GitHub repository and push our Next.js application to it. By default, create-next-app generated a git repository for us when we started the project. Let’s commit our changes and push them to our new GitHub repository.

git add -A
git commit -m "add fullstack graphql app"
git remote add origin git@github.com:johnymontana/fullstack-graphql-movies.git
git push -u origin main

Next, we’ll sign in to Vercel and create a new project. If you don’t have a Vercel account, you can create one for free. The free tier of Vercel includes all the features we need to deploy our Next.js application.

Since our .env.local file with our database credentials wasn’t checked for version control to keep our secrets safe, we’ll need to specify our Neo4j AuraDB credentials as environment variables when configuring the project in Vercel. We can use a different database here to have multiple development, staging, and production environments.

Hit the Deploy button, and after a few seconds (and some confetti), our application will be deployed to the web. Vercel will even assign our app a new domain name and SSL certificate. Our React application is deployed to Vercel’s CDN, while our API Routes are deployed as serverless functions.

This is great, but let’s see how we can take advantage of Vercel’s preview deployment feature. We’ll add a new feature to our app and push it to a new branch of our GitHub repository, which will trigger a new preview deployment on Vercel.

Adding A New Feature And Vercel Preview Deployments

Preview deployments allow us to test and share new features to our application without updating our production deployment. To see how this works, let’s add a recommended movie feature to our application. To do this, we’ll add a new field to the Movie type in our GraphQL API called similar that will return a list of similar movies a user might be interested in watching if they liked the original movie. We’ll use the @cypher schema directive to attach custom logic to our GraphQL API using a Cypher statement.

First, we’ll write a Cypher query to find similar movies. We saw earlier that Cypher allows us to declare graph patterns using ASCII-art syntax, so our Cypher query will define a graph pattern to find similar movies by traversing through the actors and genres of the movie.

MATCH (m:Movie {title: "Matrix, The"})
MATCH (m)-[:ACTED_IN|:IN_GENRE]-()-[:ACTED_IN|:IN_GENRE]-(rec:Movie)
WITH rec, COUNT(*) AS score ORDER BY score DESC
RETURN rec LIMIT 3

We could also use things like user ratings to improve our movie recommendations, but this is a good start. In our GraphQL type definitions in api/graphql.js, we’ll add our new similar field and annotate it with our movie recommendation Cypher statement.

 extend type Movie {
    similar(first: Int = 4): [Movie!]! @cypher(statement: """
    MATCH (this)-[:ACTED_IN|:IN_GENRE]-()-[:ACTED_IN|:IN_GENRE]-(rec:Movie)
    WITH rec, COUNT(*) AS score ORDER BY score DESC
    RETURN rec LIMIT $first
    """)
 }
 

We use the this variable in the Cypher statement to refer to the currently resolved movie. Similarly, any GraphQL field arguments we define will be passed to the Cypher statement as Cypher parameters, like the $first parameter that will allow for specifying the maximum number of similar movies to return.

If we include this new similar field in our GraphQL movies search query and in the result table, we’ll see a recommended movie for each movie in our search results.

Let’s create a new git branch and commit our changes to this new branch. This will trigger a preview deployment on Vercel. Our updates will be deployed to a new domain, which we’ll be able to share and test before merging the changes to the main branch and moving the deployment to our main domain.

git checkout -b recommendations
git add -A
git commit -m "add recommendations feature"
git push origin recommendations

One neat feature included in each preview deployment is the ability for our users to add annotations and feedback to our app just by clicking on the screen. This is a great way to gather feedback on a new feature just by sharing the URL to your preview deployment!

In this blog post, we saw how to use Next.js and Neo4j AuraDB to build and deploy a full stack GraphQL web application. We used the Neo4j GraphQL Library in a Next.js API route to quickly create a fully featured GraphQL API backed by a native graph database as a serverless function. We also saw some of the advantages of using Vercel to deploy our full stack application, like the preview deployment functionality.

Where To Go From Here

To learn more about building full stack GraphQL applications, be sure to download my book Full Stack GraphQL Applications. Thanks to Neo4j, you can download the ebook version for free! The book covers more advanced features of the Neo4j GraphQL Library, like adding authorization rules, how to work with mutations, using GraphQL for client state management, and more. You can find the code for this blog post on GitHub.

]]>
hello@smashingmagazine.com (William Lyon)
<![CDATA[What Leonardo Da Vinci Can Teach Us About Web Design]]> https://smashingmagazine.com/2023/03/leonardo-da-vinci-teach-web-design/ https://smashingmagazine.com/2023/03/leonardo-da-vinci-teach-web-design/ Tue, 14 Mar 2023 16:00:00 GMT Exhaustive, sometimes bizarre notes… wireframes… mind-bending blends of art and science. Is it a GitHub repository? No, it’s the life of a Renaissance genius. With the right lessons, we can all write some da Vinci code.

Web development is a pretty big tent. It encompasses color, mathematics, accessibility, typography, photography, copywriting, ethics, and the list goes on and on. The web is a near-infinite world which — for all its relentless innovation and disruption — inherits many of its most beautiful qualities from old ways.

It is in that spirit that we’ll be looking at the Italian polymath Leonardo da Vinci, the latest in a rather eclectic lineup of old maestros I’ve had the pleasure of writing about:

Perhaps more than any other person in history, da Vinci showed the kind of magic that can happen in the overlap between art and science, where much of web development lives. His methods and outlooks are as applicable today as they were in Renaissance Italy.

Document Your Thoughts, Ideas, And Work

Da Vinci was a fastidious writer, producing tens of thousands of pages of notes and sketches during his life. Their content ranged from mundane to genius, and that was part of their value. One day it’s a shopping list, another it’s flying machines. There was no filter, no preciousness, only expression and exploration.

This exhaustive documentation was valuable for a number of reasons. They were of benefit to him as an outlet for his thoughts, ambitions, and experiences and as points of reference for long-term projects. Getting his thoughts down allowed them to be tested and iterated on.

The benefits of such extensive documentation were not limited to da Vinci himself. Writing his ideas down also allowed them to survive him for the benefit of countless millions since. Centuries on his notebooks continue to surprise, delight and educate.

Da Vinci’s zeal for writing and sketching lends itself to web development. First is the powerful — sometimes downright mysterious — creative freedom of jotting down what’s going on inside your head. Sometimes you start writing down idea A and suddenly find yourself at solution X.

Not everything we do has to be perfect. Anyone expecting to arrive directly at the final product is going to be disappointed or have a pretty shoddy final product. Writing and sketching give you the license to be playful, maybe even a little bit audacious. Many timeless ideas are born on notebook paper.

There is a sense sometimes that the code we write is akin to sand sculptures — pretty but temporary. This doesn’t have to be the case. Even if the final form of websites continues to change, the thinking behind that evolution is invaluable. How did we get here, and why?

Documenting your pull requests to survive when you’re dead may be a bit strong, but your successors at old jobs will be grateful for the insight and guidance.

Web devs and designers ought to document their own journey, be it through PR descriptions or an actual notebook of their own:

  • Flesh out ideas,
  • Jot down idle thoughts,
  • Doodle page layouts.

May future generations be delighted and awed by your pull request descriptions. May the feature ideas in your GitHub issues be as aspirational as da Vinci’s flying machines.

The best ideas in the world are of no practical use for as long as they’re stuck in one’s head.

Obsess Over Geometry

As most famously demonstrated by the Vitruvian Man, da Vinci was a lifelong student of geometry, shape, and proportion. He was fascinated by the recurrence of various shapes in nature, as well as by the workings of proportion and perspective. He understood their value to paintings and architecture alike.

Da Vinci took great pains to understand these invisible frameworks and replicate them in his work. Although he is more often remembered for his fine art, everything he did was underpinned by a fascination with science and mathematics.

These are essential tools for any web developer. Pages look similarly off-kilter if they are not assembled around invisible guidelines. Grids are the most common example of this, but areas like typography and responsive design are similarly rooted in questions of size, proportion, ratio, and shape.

Showing a da Vinci-like interest in the rules behind these subjects is the difference between a website being pleasing to the eye and being a complete disaster. If you’re unsure where to start, then it’s safe to say Smashing has you covered:

From nature to painting to architecture to web design, applied geometry can create a sense of the sublime.

Think Right-To-Left

In his notebooks, da Vinci typically wrote right to left in ‘mirror script’. He only wrote the ‘normal’ way when he intended it to be read by other people.

Why did he write that way? He was left-handed and wasn’t classically schooled. It prevented him from smudging the ink. It made his ideas harder to steal. Whatever the combination, it’s clearly what he felt most comfortable with.

Da Vinci’s mirror script shows the value of embracing ways of working that suit you. Da Vinci didn’t have to justify his methods to anyone else. And neither do you.

Trust what feels natural and customize the way you work to fit. Personalize your IDE, choose fonts and colors that you like, and write and draw however comes naturally — be that with a tablet or in a leatherbound journal.

Norms being what they are doesn’t necessarily mean that’s how they should be. You will feel better about yourself, and who knows, maybe making space for your methods will allow unexpected ideas to appear.

Find Good Patrons (Or Failing That, Good Employers)

Da Vinci was picky about the work he did and the patrons he found. He lived in places that gave space to his flamboyance and creativity. Florence valued the arts, so it valued da Vinci as well as peers like Michelangelo.

When he moved to Milan, he delighted the courts with his theatrics, eloquence, and stagecraft. On the other end of the spectrum, da Vinci also spent a couple of years in the service of Cesare Borgia, a man so conniving, violent, and altogether horrible that he was a major inspiration for Machiavelli’s book The Prince. Still, it gave him the opportunity to apply himself in new areas like mapping.

Time inside the belly of the beast can be educational in its own way. However, it’s telling that da Vinci only spent a few years in Borgia’s service before slipping back into the less murderous company.

Although patrons are all well and good, we, in the world of web development, usually have to settle for employers. We owe it to ourselves — if at all possible — to find spaces for our creativity, to find outlets for our passions, or at the very least, not feel like a cog in some colossal evil machine.

Have enough pride in your work to channel it into projects you care about. Even da Vinci needed a good working culture. Find your Florence, and if you can’t, do what you can to make where you are a little more like it.

Iterate, Iterate, Iterate

It may be of some comfort to know that Leonardo da Vinci was, at times, a breathtaking procrastinator. He would take years to complete works, and that’s if he finished them at all.

Da Vinci worked on many of his paintings for years, including the Mona Lisa, which he took with him on his travels until the day he died.

Da Vinci’s creations were the result of countless experiments, tangents, and iterations. The final products are what looms large in the public consciousness today, but each was but the final step of long, often difficult journeys.

One particularly pertinent example of this process in action is Leonardo’s Horse, an equestrian monument da Vinci was commissioned to design and build in 1482 by the Duke of Milan Ludovico il Moro. A decades-long frenzy of research ensued, ranging from horse anatomy to concocting entirely new bronze casting techniques.

The project was not completed in da Vinci’s lifetime, but his work made it possible for the effort to be renewed when his extensive notes resurfaced in the 20th century. In 1999, a cool 517 years after he was commissioned, da Vinci’s horse was finally unveiled in Milan.

For all his brilliance, da Vinci was also an exemplar of the power of slow, steady progress — even procrastination. Yes, sometimes inspiration strikes, but more often, we find it at the end of a long, laborious journey. As Steven Pressfield puts it in The War of Art, “The Muse favors working stiffs.”

In the world of web design, the idea of something being ‘finished’ is pretty quaint. There will always be dependencies to update, tweaks to make, and new devices to accommodate. This is a good thing. It is true to nature. It’s exciting. In how many fields can one rebuild something they’ve made? Architects don’t have that luxury. Even painters can only change so much before they have to start again.

The ethereal nature of the web and its technologies lends itself to a da Vinci-esque approach to iteration. Build it, then build it again better. And again. And again.

Do not get too attached to what it is now. It is valuable, yes, but ultimately a stepping stone to what is to come. It is not about throwing away your work but evolving it.

Seldom is a work truly finished. There are always more perfections to be made.

“Art is never finished, only abandoned.”
— Leonardo da Vinci
Feed Your Inner Polymath

Leonardo da Vinci was too multifaceted to be tied down with one label. He was a writer, painter, sculptor, architect, inventor, scientist, philosopher, and the list goes on and on.

“He who loves practice without theory is like the sailor who boards a ship without a rudder and compass and never knows where he may cast.”
— Leonardo da Vinci

His knowledge of each field improved his proficiency in others. Anatomical studies led to more realistic illustrations. His studies of light helped him to create more lifelike paintings.

This, in part, stemmed from his atypical education. By avoiding the classical syllabus, he was able to explore on his own terms, blurring the lines between different subjects. His understanding of the world was fluid and holistic.

Web developers operate within a similarly vast and beautiful constellation of interconnected disciplines. The really good stuff happens when we tie them together.

“Technology alone is not enough — it’s technology married with liberal arts, married with the humanities, that yields us the results that make our heart sing.”
Steve Jobs

Play with new languages, old languages, frameworks, and libraries. Browse Smashing Magazine categories that you’re a novice in. Go down those rabbit holes. Pull on those threads. As da Vinci said of art, so too is true of the web: it can never be finished, only abandoned.

Further Reading

]]>
hello@smashingmagazine.com (Frederick O’Brien)
<![CDATA[A Pragmatist’s Guide To Lean User Research]]> https://smashingmagazine.com/2023/03/pragmatists-guide-lean-user-research/ https://smashingmagazine.com/2023/03/pragmatists-guide-lean-user-research/ Fri, 10 Mar 2023 08:00:00 GMT We don’t live in an ideal world. Most of us have too much work, too little time, and too small a budget. When it comes to digital projects, it seems like our clients or bosses always prioritize speed over quality.

To make matters worse, we read countless articles telling us how we should do things. These articles emphasize research and testing but do nothing more than leave us disillusioned and add to our imposter syndrome.

In this article, I want to try a different approach. Instead of telling you what the best practice is, I’ll explore some practical approaches to user research that we might be able to fit into our existing projects.

I know what you’re thinking:

“I won’t be allowed to do research. I’ll be told there’s no time.”

So let’s start there.

Lean User Research Saves Time Rather Than Costs It

The notion that all user research must take away from the available time for a project is flawed. Lean user research has the potential to save you time, especially on projects with multiple stakeholders.

Consider how much time is wasted on calls debating the best approach or in Figma endlessly revising the design because the client can’t make up their mind. Then there is the time of the other stakeholders, all of whom have to attend those meetings and provide feedback.

A small amount of user research can solve much of that. It can replace endless opinions, discussions, and revisions with data.

We don’t need to ask for extra time for research. Instead, we can replace some of those meetings with a quick survey or test and cut through all the discussion.

But what about the discovery you are supposed to do upfront? What about the research into your audience before you begin? Isn’t that best practice, and shouldn’t you be doing that?

Well, yes and no.

What About Upfront Research?

Yes, a discovery phase is best practice. It is our chance to challenge our assumptions about the users and their needs. However, we don’t always get to do what we should, and not every discovery phase needs to take a lot of work.

If you’re not careful, discovery phases can be a little wasteful. General research into your audience and needs may not always provide applicable insights. That’s because it’s only once we start work that we learn what questions to ask upfront. Of course, by that point, you have already used time on the discovery phase, and stakeholders may be reluctant to do any more research.

Simply carrying out exercises like customer journey mapping because you’ve read that you should do it upfront is not a good enough reason when time and money are tight.

So, if time is tight, don’t feel like you have to do a full-blown discovery phase just because articles like this tell you to. Instead, start by collating what the organization already knows about the user and their needs. Most organizations know more than you think about their audience. Whether it’s personas produced by marketing, surveys run in the past, or analytics data, it can often just be a matter of gathering together what already exists.

Once you have done that, you will have a clearer picture of what is missing. If there are some significant and obvious gaps in your knowledge, then some upfront research is worthwhile. However, it might be that you have enough to start, leaving more time for user research as issues arise.

Either way,

Your focus should be on answering specific questions, not improving your general understanding of the user.

Focus On Answering Specific Questions

User research can quickly become a time sink if not managed carefully. Adding more and more questions to surveys because “it would be interesting to know” will slow down the surveying process. Equally, you can waste hours simply watching user sessions back. While this context is helpful, it is better to conduct user research only when there is a specific question that needs answering.

For example, if you want to know why people aren’t buying on your website, run a one-question survey that asks why when people go to leave the site. Or, if stakeholders are concerned that users will miss a critical call to action, do a quick 5-second test to reassure them.

Focusing user research on answering these kinds of questions not only ensures a better result but also ensures that user research saves time. Without user research, discussions and debates around these topics can drag out and slow momentum. Additionally, by focusing user research on addressing a single question, it keeps it small and easy to incorporate into an existing project.

Many little bits of user research are easier to insert than a single significant discovery phase.

Of course, this is only true if the types of user research you do are lightweight.

Keep Your User Research Lightweight

When trying to keep our user research lean, tough decisions must be made. One of these is to move away from facilitated research, such as user interviews or usability testing, as they are too time-consuming.

Instead, we should focus on research that can be set up in minutes, provides results quickly, and can be understood at a glance. This leaves us primarily with surveys and unfacilitated testing.

Run Quick And Dirty Surveys

Personally, I love quick surveys to resolve areas of disagreement or uncertainty. If in doubt, I argue, it’s best to ask the user. Just a few examples of surveys I have run recently include:

  • Comparing two labels for a second on a website.
  • Identifying tasks users wanted to complete on a website.
  • Discovering why people weren’t signing up for a free trial.
  • Assessing whether people understood an infographic.

I could go on, but you get the idea. Short, focused surveys can help answer questions quickly.

Surveys are easy to create and depending on how you approach them, you can get results quickly. If time is more of a barrier than money, you can use an app like Pollfish to recruit the exact demographic of people you need for a few dollars per submission. You can usually get results in less than a day with only a few minutes of work to set up the survey.

If money is an obstacle, consider sharing your survey on social media, a mailing list, or your website. You could even share it with random people who aren’t involved in the project if you’re desperate. At least you’d get an outside perspective.

When your questions are about a design approach you’ve produced, you can turn to unfacilitated testing.

Try Some Unfaciliated Tests

Stakeholders often spend days debating and revising design concepts when quick tests could provide the answers they need. Generally, these design discussions revolve around four questions:

  • Did users see it?
  • Did users understand it?
  • Can people use it?
  • Will they like it?

Fortunately, there are quick tests that can help answer each of these questions.

Did Users See It?

If stakeholders are concerned that someone might miss a call to action or critical messaging, you can run a 5-Second Test. This test presents users with a digital product, such as a website or app, for five seconds before asking what they saw. Tools like Usability Hub and Maze provide a URL for the test that you can share with participants, similar to how you would distribute a survey. If users recall seeing the element in question, you know everything is good.

Did Users Understand It?

A slight variation of the test can also be used to answer the second question: did users understand it? Show the user your design for 5 seconds, then ask them to describe what they saw in their own words. If they accurately describe the concept, you can be sure of your approach.

Can People Use It?

When it comes to the “can people use it?” question, you have two options.

If you have a prototype, you can run unfacilitated usability testing with a tool like Maze:

  1. Define the task you need to see people complete;
  2. Provide Maze with the most direct route to complete the task;
  3. Give participants the URL Maze provides.

Maze will give you aggregated data on how long it took people to complete the task and the number of mistakes they made.

If you don’t have a prototype, the alternative is to do a first-click test:

  1. Show users a mockup of your website or app;
  2. Ask where they would click to complete a specific task.

According to a usability study by Bob Bailey and Cari Wolfson, if the first click is correct, users have an 87% chance of completing the action correctly, compared to just 46% if the first click is wrong. So, if people get their first-click correct, you can be reasonably confident they can successfully complete the task.

Usability Hub can help you run your first-click test. They will provide a heat map showing the aggregated results of where everyone clicked, so you don’t need to analyze the results manually. This allows you to get answers almost immediately.

Will People Like It?

The final question is, “Will people like it?” This is not easy to answer, as different stakeholders may have different opinions about what works.

To resolve this, I usually conduct a preference test or, ideally, a semantic differential survey.

First, I agree with stakeholders on the associations we want users to have with the design. These may include words like professional, friendly, inspiring, or serious.

In a semantic differential survey, users can then rate the design against those words. If the design scores well, we can be confident it will generate the desired response.

A Pragmatic Approach

I know this post will make user researchers uncomfortable, and I can fully understand why. The results you get back will be far from perfect and could possibly lead to false conclusions. However, it is better than the alternative. Resolving design decisions through internal discussion is always going to be inferior to getting user feedback.

This kind of lean user research can also be a great starting point for bigger things. If you can add even some user research to the process, stakeholders can start to see its benefits, and it can lead to bigger things.

Some may choose to pick holes in your approach, suggesting that you aren’t testing with the right people or with a big enough audience. They are, of course, correct. However, this provides you with an opportunity to point out you would happily do more research if only the time and budget were made available!

Further Reading On SmashingMag

]]>
hello@smashingmagazine.com (Paul Boag)
<![CDATA[Building Complex Forms In Vue]]> https://smashingmagazine.com/2023/03/building-complex-forms-vue/ https://smashingmagazine.com/2023/03/building-complex-forms-vue/ Thu, 09 Mar 2023 10:00:00 GMT v-for and the v-model? In this article, Olufunke shares some basic Vue core features that are super useful when building out the complex form in your day-to-day Vue usage.]]> More often than not, web engineers always have causes to build out forms, from simple to complex. It is also a familiar pain in the shoe for engineers how fast codebases get incredibly messy and incongruously lengthy when building large and complex forms. Thus begging the question, “How can this be optimized?”.

Consider a business scenario where we need to build a waitlist that captures the name and email. This scenario only requires two/three input fields, as the case may be, and could be added swiftly with little to no hassle. Now, let us consider a different business scenario where users need to fill out a form with ten input fields in 5 sections. Writing 50 input fields isn’t just a tiring job for the Engineer but also a waste of great technical time. More so, it goes against the infamous “Don’t Repeat Yourself” (DRY) principle.

In this article, we will focus on learning to use the Vue components, the v-model directive, and the Vue props to build complex forms in Vue.

The v-model Directive In Vue

Vue has several unique HTML attributes called directives, which are prefixed with the v-. These directives perform different functions, from rendering data in the DOM to manipulating data.

The v-model is one such directive, and it is responsible for two-way data binding between the form input value and the value stored in the data property. The v-model works with any input element, such as the input or the select elements. Under the hood, it combines the inputted input value and the corresponding change event listener like the following:

<!-- Input element -->
<input v-model="inputValue" type="text">

<!-- Select element -->
<select v-model="selectedValue">
  <option value="">Please select the right option</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

The input event is used for the <input type= "text"> element. Likewise, for the <select> … </select>, <input type= "checkbox"> and <input type= "radio">, the v-model will, in turn, match the values to a change event.

Components In Vue

Reusability is one of the core principles of Software Engineering, emphasizing on using existing software features or assets in a software project for reasons ranging from minimizing development time to saving cost.

One of the ways we observe reusability in Vue is through the use of components. Vue components are reusable and modular interfaces with their own logic and custom content. Even though they can be nested within each other just as a regular HTML element, they can also work in isolation.

Vue components can be built in two ways as follows:

  • Without the build step,
  • With the build step.

Without The Build Step

Vue components can be created without using the Vue Command Line Interface (CLI). This component creation method defines a JavaScript object in a Vue instance options property. In the code block below, we inlined a JavaScript string that Vue parses on the fly.

template: `
  <p> Vue component without the build step </p>
  `

With The Build Step

Creating components using the build step involves using Vite — a blazingly fast, lightweight build tool. Using the build step to create a Vue component makes a Single File Component (SFC), as it can cater to the file’s logic, content, and styling.

<template>
  <p> Vue component with the build step </p>
</template>

In the above code, we have the <p> tag within the HTML <template> tag, which gets rendered when we use a build step for the application.

Registering Vue Components

Creating a Vue component is the first step of reusability and modularity in Vue. Next is the registration and actual usage of the created Vue component.

Vue components allow the nesting of components within components and, even more, the nesting of components within a global or parent component.

Let’s consider that we stored the component we created using the build step in a BuildStep.vue file. To make this component available for usage, we will import it into another Vue component or a .vue, such as the root entry file. After importing this component, we can then register the component name in the components option property, thus making the component available as an HTML tag. While this HTML tag will have a custom name, the Vue engine will parse them as valid HTML and render them successfully in the browser.

<!-- App.vue -->
<template>
  <div>
    <BuildStep />
  </div>
</template>

<script>
import BuildStep from './BuildStep.vue'

export default {
  components: {
    BuildStep
  }
}
</script>

From the above, we imported the BuildStep.vue component into the App.vue file, registered it in the components option property, and then declared it within our HTML template as <BuildStep />.

Vue Props

Vue props, otherwise known as properties, are custom-made attributes used on a component for passing data from the parent component to the child component(s). A case where props can come in handy is when we need a component with different content but a constant visual layout, considering a component can have as many props as possible.

The Vue prop has a one-way data flow, i.e., from the parent to the child component. Thus, the parent component owns the data, and the child component cannot modify the data. Instead, the child component can emit events that the parent component can record.

Props Declaration In Vue

Let us consider the code block below:

<template>
  <p> Vue component {{ buildType }} the build step</p>
</template>

<script>
export default {
  props: {
    buildType: {
      type: String
    }
  }
}
</script>

We updated the HTML template with the interpolated buildType, which will get executed and replaced with the value of the props that will be passed down from the parent component.

We also added a props tag in the props option property to listen to the props change and update the template accordingly. Within this props option property, we declared the name of the props, which matches what we have in the <template> tag, and also added the props type.

The props type, which can be Strings, Numbers, Arrays, Boolean, or Objects, acts as a rule or check to determine what our component will receive.

In the example above, we added a type of String; we will get an error if we try to pass in any other kind of value like a Boolean or Object.

Passing Props In Vue

To wrap this up, we will update the parent file, i.e., the App.vue, and pass the props accordingly.

<!-- App.vue -->
<template>
  <div>
    <BuildStep buildType="with"/>
  </div>
</template>

<script>
import BuildStep from './BuildStep.vue'

export default {
  components: {
    BuildStep
  }
}
</script>

Now, when the build step component gets rendered, we will see something like the following:

Vue component with the build step

With props, we needn’t create a new component from scratch to display whether a component has a build step or not. We can again declare the <BuildStep /> component and add the relevant build type.

<!-- App..vue -->
<template>
  <div>
    <BuildStep buildType="without"/>
  </div>
</template>

Likewise, just as for the build step, when the component gets rendered, we will have the following view:

Vue component without the build step
Event Handling In Vue

Vue has many directives, which include the v-on. The v-on is responsible for listening and handling DOM events to act when triggered. The v-on directive can also be written as the @ symbol to reduce verbosity.

<button @click="checkBuildType"> Check build type </button>

The button tag in the above code block has a click event attached to a checkBuildType method. When this button gets clicked, it facilitates executing a function that checks for the build type of the component.

Event Modifiers

The v-on directive has several event modifiers that add unique attributes to the v-on event handler. These event modifiers start with a dot and are found right after the event modifier name.

<form @submit.prevent="submitData">
 ...
<!-- This enables a form to be submitted while preventing the page from being reloaded. -->
</form>

Key Modifiers

Key modifiers help us listen to keyboard events, such as enter, and page-up on the fly. Key modifiers are bound to the v-on directive like v-on:eventname.keymodifiername, where the eventname could be keyup and the modifiername as enter.

<input @keyup.enter="checkInput">

The key modifiers also offer flexibility but allow multiple key name chaining.

<input @keyup.ctrl.enter="checkInput">

Here the key names will listen for both the ctrl and the enter keyboard events before the checkInput method gets called.

The v-for Directive

Just as JavaScript provides for iterating through arrays using loops like the for loop, Vue-js also provides a built-in directive known as the v-for that performs the same function.

We can write the v-for syntax as item in items where items are the array we are iterating over or as items of items to express the similarity with the JavaScript loop syntax.

List Rendering

Let us consider rendering the types of component build steps on a page.

<template>
  <div>
    <ul>
        <li v-for="steps in buildSteps" :key="steps.id"> {{ steps.step }}</li>
      </ul>
  </div>
</template>

<script>
export default {
 data() {
   return {
     buildSteps: [
      {
       id: "step 1",
       step:'With the build step',
      },
      {
        id: "step 2",
       step:'Without the build step'
      }
    ]
   }
 }
}
</script>

In the code block above, the steps array within the data property shows the two types of build steps we have for a component. Within our template, we used the v-for directive to loop through the steps array, the result of which we will render in an unordered list.

We added an optional key argument representing the index of the item we are currently iterating on. But beyond that, the key accepts a unique identifier that enables us to track each item’s node for proper state management.

Using v-for With A Component

Just like using the v-for to render lists, we can also use it to generate components. We can add the v-for directive to the component like the following:

<BuildStep v-for="steps in buildSteps" :key="steps.id"/>

The above code block will not do much for rendering or passing the step to the component. Instead, we will need to pass the value of the step as props to the component.

<BuildStep v-for="steps in buildSteps" :key="steps.id" :buildType="steps.step" />

We do the above to prevent any tight fixation of the v-for to the component.

The most important thing to note in the different usage of the v-for is the automation of a long process. We can move from manually listing out 100 items or components to using the v-for directive and have everything rendered out within the split of a second, as the case may be.

Building A Complex Registration Form In Vue

We will combine everything we have learned about the v-model, Vue components, the Vue props, the v-for directive, and event handling to build a complex form that would help us achieve efficiency, scalability, and time management.

This form will cater to capturing students’ bio-data, which we will develop to facilitate progressive enhancement as business demands increase.

Setting Up The Vue App

We will be scaffolding our Vue application using the build step. To do this, we will need to ensure we have the following installed:

Now we will proceed to create our Vue application by running the command below:

# npm
npm init vue@latest vue-complex-form

where vue-complex-form is the name of the Vue application.

After that, we will run the command below at the root of our Vue project:

npm install

Creating The JSON File To Host The Form Data

We aim to create a form where users can fill in their details. While we can manually add all the input fields, we will use a different approach to simplify our codebase. We will achieve this by creating a JSON file called util/bio-data.json. Within each of the JSON objects, we will have the basic info we want each input field to have.

[
  {
    "id": 1,
    "inputvalue":"  ",
    "formdata": "First Name",
    "type": "text",
    "inputdata": "firstname"
  },
  {
    "id": 2,
    "inputvalue":"  ",
    "formdata": "Last Name",
    "type": "text",
    "inputdata": "lastname"
  },
]

As seen in the code block above, we created an object with some keys already carrying values:

  • id acts as the primary identifier of the individual object;
  • inputvalue will cater to the value passed into the v-model;
  • formdata will handle the input placeholder and the labels name;
  • type denotes the input type, such as email, number, or text;
  • inputdata represents the input id and name.

These keys’ values will be passed in later to our component as props. We can access the complete JSON data here.

Creating The Reusable Component

We will create an input component that will get passed the props from the JSON file we created. This input component will get iterated on using a v-for directive to create numerous instances of the input field at a stretch without having to write it all out manually. To do this, we will create a components/TheInputTemplate.vue file and add the code below:

<template>
  <div>
    <label :for="inputData">{{ formData }}</label>
    <input
      :value= "modelValue"
      :type= "type"
      :id= "inputData"
      :name= "inputData"
      :placeholder= "formData"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  </div>
 </template>

<script>
export default {
  name: 'TheInputTemplate',
  props: {
    modelValue: {
      type: String
    },
    formData: {
      type: String
    },
    type: {
      type: String
    },
    inputData: {
      type: String
    }
  },
  emits: ['update:modelValue']
}
</script>
<style>
label {
  display: inline-block;
  margin-bottom: 0.5rem;
  text-transform: uppercase;
  color: rgb(61, 59, 59);
  font-weight: 700;
  font-size: 0.8rem;
}
input {
  display: block;
  width: 90%;
  padding: 0.5rem;
  margin: 0 auto 1.5rem auto;
}
</style>

In the above code block, we achieved the following:

  • We created a component with an input field.
  • Within the input field, we matched the values that we will pass in from the JSON file to the respective places of interest in the element.
  • We also created props of modelValue, formData, type, and inputData that will be registered on the component when exported. These props will be responsible for taking in data from the parent file and passing it down to the TheInputTemplate.vue component.
  • Bound the modelValue prop to the value of the input value.
  • Added the update:modelValue, which gets emitted when the input event is triggered.

Registering The Input Component

We will navigate to our App.vue file and import the TheInputTemplate.vue component from where we can proceed to use it.

<template>
  <form class="wrapper">
    <TheInputTemplate/>
  </form>
</template>
<script>
import TheInputTemplate from './components/TheInputTemplate.vue'
export default {
  name: 'App',
  components: {
    TheInputTemplate
  }
}
</script>
<style>
html, body{
  background-color: grey;
  height: 100%;
  min-height: 100vh;
}
.wrapper {
  background-color: white;
  width: 50%;
  border-radius: 3px;
  padding: 2rem  1.5rem;
  margin: 2rem auto;
}
</style>

Here we imported the TheInputTemplate.vue component into the App.vue file, registered it in the components option property, and then declared it within our HTML template.

If we run npm run serve, we should have the following view:

At this point, there is not much to see because we are yet to register the props on the component.

Passing Input Data

To get the result we are after, we will need to pass the input data and add the props to the component. To do this, we will update our App.vue file:

<template>
  <div class="wrapper">
    <div v-for="bioinfo in biodata" :key="bioinfo.id">
      <TheInputTemplate v-model="bioinfo.inputvalue":formData= "bioinfo.formdata":type= "bioinfo.type":inputData= "bioinfo.inputdata"/>
    </div>
  </div>
<script>
//add imports here
import biodata from "../util/bio-data.json";
export default {
  name: 'App',
 //component goes here
  data: () => ({
    biodata
  })
}
</script>

From the code block above, we achieved several things:

  • We imported the bio-data JSON file we created into the App.vue file. Then we added the imported variable to the data options of the Vue script.
  • Looped through the JSON data, which we instantiated in the data options using the Vue v-for directive.
  • Within the TheInputTemplate.vue component we created, we passed in the suitable data to fill the props option.

At this point, our interface should look like the following:

To confirm if our application is working as it should, we will open up our Vue DevTools, or install one from https://devtools.vuejs.org if we do not have it in our browser yet.

When we type in a value in any of the input fields, we can see the value show up in the modelValue within the Vue Devtools dashboard.

Conclusion

In this article, we explored some core Vue fundamentals like the v-for, v-model, and so on, which we later sewed together to build a complex form. The main goal of this article is to simplify the process of building complex forms while maintaining readability and reusability and reducing development time.

If, in any case, there will be a need to extend the form, all the developer would have to do is populate the JSON files with the needed information, and voila, the form is ready. Also, new Engineers can avoid swimming in lengthy lines of code to get an idea of what is going on in the codebase.

Note: To explore more about handling events within components to deal with as much complexity as possible, you can check out this article on using components with v-model.

Further Reading on Smashing Magazine

]]>
hello@smashingmagazine.com (Olufunke Moronfolu)
<![CDATA[How To Create Dynamic Donut Charts With TailwindCSS And React]]> https://smashingmagazine.com/2023/03/dynamic-donut-charts-tailwind-css-react/ https://smashingmagazine.com/2023/03/dynamic-donut-charts-tailwind-css-react/ Tue, 07 Mar 2023 15:30:00 GMT conic-gradient(). There are no additional libraries to install or maintain, and there’s no heavy JavaScript that needs to be downloaded by the browser in order for them to work.]]> CSS is amazing — I’m regularly surprised at how far it has come in the years I’ve been using it (~2005 – present). One such surprise came when I noticed this tweet by Shruti Balasa which demonstrated how to create a pie chart using conic-gradient().

It’s fairly straightforward. Here’s a code snippet:

div {
  background: conic-gradient(red 36deg, orange 36deg 170deg, yellow 170deg);
  border-radius: 50%;
}

Using this tiny amount of CSS, you can create gradients that start and stop at specific angles and define a color for each ‘segment’ of the pie chart.

Happy Days!

Brills, I thought I could use this instead of a charting library for a data dashboard project I’m working on for the new CockroachDB Cloud API, but I had a problem. I didn’t know the values for my chart ahead of time, and the values I was receiving from the API weren’t in degrees!

Here’s a preview link and Open-source repo of how I worked around those two problems, and in the rest of this post, I’ll explain how it all works.

Dynamic Data Values

Here’s some sample data from a typical API response which I’ve sorted by value.

const data = [
  {
    name: 'Cluster 1',
    value: 210,
  },
  {
    name: 'Cluster 2',
    value: 30,
  },
  {
    name: 'Cluster 3',
    value: 180,
  },
  {
    name: 'Cluster 4',
    value: 260,
  },
  {
    name: 'Cluster 5',
    value: 60,
  },
].sort((a, b) => a.value - b.value);

You can see that each item in the array has a name and a value.

In order to convert the value from a number into a deg value to use with CSS, there are a few things you need to do:

  • Calculate the total amount of all the values.
  • Use the total amount to calculate the percentage that each value represents.
  • Convert the percentage into degrees.

Note: The code I’ll be referring to in the steps below can be found in the repo here: /components/donut-1.js.

Calculate The Total Amount

Using JavaScript, you can use this little one-liner to sum up each value from the data array, which results in a single total.

const total_value = data.reduce((a, b) => a + b.value, 0);

// => 740

Calculate The Percentage

Now that you have a total_value, you can convert each of the values from the data array to a percentage using a JavaScript function. I’ve called this function covertToPercent.

Note: I’ve used the value of 210 from Cluster 1 in this example.

const convertToPercent = (num) => Math.round((num / total_value) * 100);

// convertToPercent(210) => 28

Convert Percentage to Degrees

Once you have a percentage, you can convert the percentage into degrees using another JavaScript function. I’ve called this function convertToDegrees.

const convertToDegrees = (num) => Math.round((num / 100) * 360);

// convertToDegrees(28) => 101

The Result

As a temporary test, if I were to map over the items in the sorted data array, using the two functions explained above, you’d end up with the following output:

const test_output = data.map((item) => {
  const percentage = convertToPercent(item.value);
  const degrees = convertToDegrees(percentage);

  return `${degrees}deg`;
});

// => ['14deg', '29deg', '86deg', '101deg', '126deg']

The return value of test_output is an array of the value (in degrees) + the string deg.

This solves one of a two-part problem. I’ll now explain the other part of the problem.

To create a Pie chart using conic-gradient(), you need two deg values. The first is the angle from where the gradient should start, and the second is the angle where the gradient should stop. You’ll also need a color for each segment, but I’ll come to that in a moment.

 ['red 🤷 14deg', 'blue 🤷 29deg', 'green 🤷 86deg', 'orange 🤷 101deg', 'pink 🤷 126deg']

Using the values from the test_output, I only have the end value (where the gradient should stop). The start angle for each segment is actually the end angle from the previous item in the array, and the end angle is the cumulative value of all previous end values plus the current end value. And to make matters worse, the start value for the first angle needs to be manually set to 0 🥴.

Here’s a diagram to better explain what that means:

If that sounds confusing, it’s because it is, but if you look at the output of a function that can do all this, it might make more sense.

"#...", 0, 14,
"#...",, 14, 43,
"#...",, 43, 130,
"#...",, 130, 234,
"#...",, 234, 360,
The Function That Can Do All This

And here’s the function that can indeed do all of this. It uses reduce() to iterate over the data array, performs the necessary addition to calculate the angles, and returns a new set of numbers that can be used to create the correct start and end angles for use in a Chart.

const total_value = data.reduce((a, b) => a + b.value, 0);
const convertToPercent = (num) => Math.round((num / total_value) * 100);
const convertToDegrees = (num) => Math.round((num / 100) * 360);

const css_string = data
  .reduce((items, item, index, array) => {
    items.push(item);

    item.count = item.count || 0;
    item.count += array[index - 1]?.count || item.count;
    item.start_value = array[index - 1]?.count ? array[index - 1].count : 0;
    item.end_value = item.count += item.value;
    item.start_percent = convertToPercent(item.start_value);
    item.end_percent = convertToPercent(item.end_value);
    item.start_degrees = convertToDegrees(item.start_percent);
    item.end_degrees = convertToDegrees(item.end_percent);

    return items;
  }, [])
  .map((chart) => {
    const { color, start_degrees, end_degrees } = chart;
    return ${color} ${start&#95;degrees}deg ${end&#95;degrees}deg;
  })
  .join();

I’ve purposefully left this pretty verbose, so it’s easier to add in console.log(). I found this to be quite helpful when I was developing this function.

You might notice the additional map chained to the end of the reduce. By using a map I’m able to modify the returned values and tack on deg, then return them all together as an array of strings.

Using join right at the end converts the array back to a single css_string, which can be used with conic-gradient() 😅.

"#..." 0deg 14deg,
"#..." 14deg 43deg,
"#..." 43deg 130deg,
"#..." 130deg 234deg,
"#..." 234deg 360deg
Using The css_string With An SVG foreignObject

Now, unfortunately, you can’t use conic-gradient() with SVG. But you can wrap an HTML element inside a foreignObject and style the background using a conic-gradient().

<svg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' style={{ borderRadius: '100%' }}>
  <foreignObject x='0' y='0' width='100' height='100'>
    <div
      xmlns='http://www.w3.org/1999/xhtml'
      style={{
        width: '100%',
        height: '100%',
        background: conic-gradient(${css_string}), // <- 🥳
      }}
    />
  </foreignObject>
</svg>

Using the above, you should be looking at a Pie chart. In order to make a Donut chart, I’ll need to explain how to make the hole.

Let’s Talk About the Hole

There’s only really one way you can ‘mask’ off the middle of the Pie chart to reveal the background. This approach involves using a clipPath. This approach looks like the below code snippet. I’ve used this for Donut 1.

Note: The src for Donut 1 can be seen here: components/donut-1.js.

<svg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' style={{ borderRadius: '100%' }}>

  <clipPath id='hole'>
    <path d='M 50 0 a 50 50 0 0 1 0 100 50 50 0 0 1 0 -100 v 18 a 2 2 0 0 0 0 64 2 2 0 0 0 0 -64' />
  </clipPath>

  <foreignObject x='0' y='0' width='100' height='100' clipPath='url(#hole)'>
    <div
      xmlns='http://www.w3.org/1999/xhtml'
      style={{
        width: '100%',
        height: '100%',
        background: conic-gradient(${css_string})
      }}
    />
  </foreignObject>
</svg>

However, there is another way. This approach involves using a <circle /> element and placing it in the center of the pie chart. This will work if the fill of the <circle /> matches the background color of whatever the chart is placed on. In my example, I’ve used a pattern background, and you’ll notice if you look closely at Donut 3 that you can’t see the bubble pattern through the center of the chart.

Note: The src for Donut 3 can be seen here: components/donut-3.js.

<svg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' style={{ borderRadius: '100%' }}>
  <foreignObject x='0' y='0' width='100' height='100'>
    <div
      xmlns='http://www.w3.org/1999/xhtml'
      style={{
        width: '100%',
        height: '100%',
        background: conic-gradient(${css&#95;string})
      }}
    />
  </foreignObject>
  <circle cx='50' cy='50' r='32' fill='white' />
</svg>

IMO the clipPath approach is nicer, but it can be more difficult to amend the path points to get the desired thickness of the hole if you don’t have access to something like Figma or Illustrator.

Finally, Colors!

Colors for charts are something that always cause me problems. Most of the time, the colors I use are defined in CSS, and all this stuff is happening in JavaScript, so how do you use CSS variables in JavaScript?

In my example site, I’m using Tailwind to style ‘all the things’ and by using this trick, I’m able to expose the CSS variables so they can be referred to by their name.

If you want to do the same, you could add a color key to the data array:

data={[
  {
    name: 'Cluster 1',
    value: 210,
    color: 'var(--color-fuchsia-400)',
  },
  {
    name: 'Cluster 2',
    value: 30,
    color: 'var(--color-fuchsia-100)',
  },
  {
    name: 'Cluster 3',
    value: 180,
    color: 'var(--color-fuchsia-300)',
  },
  {
    name: 'Cluster 4',
    value: 260,
    color: 'var(--color-fuchsia-500)',
  },
  {
    name: 'Cluster 5',
    value: 60,
    color: 'var(--color-fuchsia-200)',
  },
].sort((a, b) => a.value - b.value)

And then reference the color key in the array map to return it as part of the css_string. I’ve used this approach in Donut 2.

Note: You can see the src for Donut 2 here: components/donut-2.js.

.map((chart) => {
  const { color, start_degrees, end_degrees } = chart;
  return ` ${color} ${start_degrees}deg ${end_degrees}deg`;
})
.join();

You could even dynamically create the color name using a hard-coded value (color-pink-) + the index from the array. I’ve used this approach in Donut 1.

Note: You can see the src for Donut 1 here: components/donut-1.js.

.map((chart, index) => {
  const { start_degrees, end_degrees } = chart;
  return var(--color-pink-${(index + 1) &#42; 100}) ${start&#95;degrees}deg ${end&#95;degrees}deg;
})
.join();
If You’re Lucky!

However, you might get lucky and be working with an API that actually returns values with an associated color. This is the case with the GitHub GraphQL API. So. I popped together one last example.

You can see this working in your browser by visiting /github, and the src for both the GitHub Donut Chart and Legend can be found here:

Wrapping Up

You might be thinking this is quite complicated, and it’s probably easier to use a Charting Library, and you’re probably right. It probably is. But this way is super lightweight. There are no additional libraries to install or maintain, and there’s no heavy JavaScript that needs to be downloaded by the browser in order for them to work.

I experimented once before with creating Donut Charts using an SVG and the stroke-dashoffset. You can read about that in my article, “Create an SVG Doughnut Chart From Scratch For Your Gatsby Blog.” That approach worked really well, but I think I prefer the approach described in this post. CSS is simply the best!

If you’d like to discuss any of the methods I’ve used here, please come find me on Twitter: @PaulieScanlon.

See you around the internet!

]]>
hello@smashingmagazine.com (Paul Scanlon)
<![CDATA[Why You Should Consider Graphs For Your Next GraphQL Project]]> https://smashingmagazine.com/2023/03/consider-graphs-graphql-project/ https://smashingmagazine.com/2023/03/consider-graphs-graphql-project/ Tue, 07 Mar 2023 12:00:00 GMT This article is a sponsored by Neo4j

The explosion of GraphQL over the past few years has introduced many front-end developers to the concepts of data modeling and storage, turning front-end developers into full-stack developers.

GraphQL provides developers working on a simple contract with a database, guaranteeing consistency and predictability of the data returned while also managing persistence and data fetching. The developer trusts the API to store and retrieve the data most efficiently.

But convenience comes at a cost. One day, your side project hits the front page of Hacker News, and a sudden influx of users grinds your database to a halt. Sometimes, the remedy is as simple as using the right underlying database for the loads.

In this article, I will look at the Graph behind GraphQL and demonstrate why Neo4j is the best fit for your next project.

The Graph In GraphQL

GraphQL itself is a database-agnostic query language. Many database companies and startups now offer libraries that convert a GraphQL query or mutation into a query language that works with the underlying data store, whether that be SQL for relational databases, Cypher for graph databases, or any number of proprietary query languages.

Graphs provide a natural way to represent data, where Nodes (or vertices) that represent entities or things are connected together by Relationships (or edges). Depending on the underlying data storage in your GraphQL library of choice, a certain amount of gymnastics may be involved. Suddenly, unnatural tables with strange names are created, or data is duplicated to improve query response times, introducing technical debt along the way.

This is where Neo4j comes in. Neo4j is a native Graph Database. Graph Databases are in a category all of their own, and for a good reason.

Graph databases treat the connections between data as first-class citizens, storing relationships so that highly connected datasets can be queried in real-time.

An Example: Movie Recommendations

Say we’re sick of scrolling through an endless list of thumbnails on our favorite streaming platform looking for something to watch. We decided to build a new website where users can register, provide movie ratings, and in return, receive movie recommendations based on users who have similar ratings.

In our GraphQL schema, we define types that represent movie information. Users provide movie ratings, each with a score between 1 and 5. Movies can have one or more actors and one or more directors. Movies are also tagged with one or more genres.

Note: Luckily, this Recommendations dataset already exists as a free Neo4j Sandbox. Neo4j Sandbox instances are free of charge, initially run for three days, and can be extended up to 10 days.

type User {
  userId: ID!
  name: string
  email: string
  ratings: [Rating]
}

type Rating {
  user: User!
  movie: Movie!
  rating: Int
  createdAt: Date
}
type Movie {
  movieId: ID!
  title: String
  released: Date
  actors: [Role]
  directors: [Person]
}

type Role {
  person: Person!
  movie: Movie!
  roles: [String]
}
type Person {
  personId: ID!
  name: String!
  born: Date!
  roles: [Role]
  directed: [Movie]
}

Let’s take a look at how this data will be stored in a relational database, a document store, and a graph and see where we might hit a problem when trying to generate recommendations.

In A Relational Database

Relational databases provide a structured method of data storage where data is organized into tables. Tables conform to strict rules known as a database schema, where each row contains a set number of columns, each with a set data type. Where a value may not exist, nullable columns can be used.

The underlying database schema provides a perfect base to map GraphQL Type Definitions. Each field within a type description will map one-to-one with a column. Those Type Definitions can be quickly translated into an SQL query (SQL stands for Structured Query Language) to insert or retrieve data.

A JOIN is constructed at read-time for nested types, joining two tables using foreign keys to find the corresponding records in a database. Here comes the first potential problem.

Let’s look at an Entity Relationship Diagram (ERD) that describes how the data may be stored in a relational database.

The tables highlighted in yellow represent the main entities in the data model: users, people, and movies. The tables highlighted in green represent the JOIN tables required to facilitate the many-to-many relationships between the entities.

There are two potential pitfalls here. First, let’s talk about naming. The example above is fairly straightforward, but say we have a many-to-many relationship in our data model between Products and Orders — an order may contain one or more products, and a product may appear in many orders. What do we call that table? order_products, order_line? This feels unnatural, and instantly you are adding tribal knowledge to the database, making it harder for others to understand.

When you use that table to find an actor for a particular movie, you start to hit the O(n) problem.

JOINs & The O(n) Problem

GraphQL is designed to be a flexible query language that allows you to retrieve an infinite level of nested values. The more nested items retrieved, the more joins are queried. Therefore the longer the query takes. Furthermore, the more data added to the database, the larger the underlying indexes become and the longer the query will take to return a result.

This is known as the Big O notation or O(n) notation — the number of computational resources required to compute the JOINs is relative to the size of the input data. The more data added to the database, the more data needs to be processed, and the slower the database will become.

Many relational databases support subqueries or window functions, but these must still be constructed in memory at query time, which can be an expensive operation.

This problem can be partially resolved by database tuning, partitioning, or denormalizing data to improve response times, at which point you’ll need to become a database expert.

In A Document Store

Document stores, such as MongoDB or CouchDB, differ from Relational databases in that they are designed to store unstructured or semi-structured data. Data is organized into collections, each of which consists of many documents. Each document in a collection represents a single record, which can have its own unique set of key-value pairs. This approach is more flexible than relational databases, but as the data is schema-less, you must be careful to enforce consistency through your application layer.

You would most likely create collections to store users, movies, and people.

Data Duplication for Query Performance

Document Stores can also fall foul of the O(n) problem. NoSQL databases, in general, are all designed to provide various their own solutions to the problems of read and write performance.

A common approach to solve the O(n) problem is to duplicate data across collections to speed up query responses. For example, the movies collection may store directors as an array of string values.

{
  "_id": ObjectId("63da26bc2e002491266b6205"),
  "title": "Toy Story",
  "released": "1996-03-22",
  "directors": ["Tom Lasseter"]
}

This is perfect if you only want to display the data within a UI. But if we need to ask more complex questions, for example, how many movies has Tom Lasseter directed? — things start to get complicated. Do we loop through every movie record and check the directors array for a name? What if two directors share the same name?

If you want to query across collections, you would usually store a reference to the unique ID of the record in the corresponding collection. Take the user example below: the ratings for that user can be stored as an array against the user document, making it easy to access. Each rating contains a reference (in this case, a MongoDB DBRef to reference the ObjectId of the document in the movies collection).

{
 "_id": ObjectId("63da267a89f7381acf7ab183"),
 "email": "john.doe@example.com",
 "name": "John Doe",
 "ratings": [
   {
     "movie": {
       "$ref": "movies",
       "$id": ObjectId("63da2681680f57e194eb3199"),
       "$db": "neoflix"
     },
     "rating": 5
   },
   {
     "movie": {
       "$ref": "movies",
       "$id": ObjectId("63da26b613fe29cf79d92e2f"),
       "$db": "neoflix"
     },
     "rating": 3
   },
 ]
}

Document stores support pipelines or map-reduce functions that allow you to compute the JOIN at read time. But these can become unwieldy quickly and hard to reason about, and take time to compute. These read-time JOINs also fall victim to the O(n) problem. Each reference must be looked up in an index to find the corresponding record, which must also be decoded. The larger the collection, the larger the index and the longer each lookup may take. Multiply that time and complexity by the number of nested items, and all of a sudden, we’ve got a slow and complicated pipeline or map/reduce function.

To avoid this complexity, you could also store some of the required properties for the movie, for example, the movie title, in the rating object.

You may also store the movie title as a key in the rating to balance out the ease of readability and data duplication. But now we also have to make difficult decisions on what data to duplicate to speed up. If the use case changes in any way, a mountain of work is required to fit the new use case. What if we want to query from movie to rating?

You may also want to fan out your writes, duplicating data across collections to speed up the read-time performance, but that also comes with its own maintenance headaches and a whole load of potential for technical debt.

The Case for Graphs

Now, let’s look at this data as a graph. The data structure of Nodes and Relationships fits this problem well. Rather than creating JOIN tables to handle many-to-many relationships or storing duplicated data for reference, the verbs in the use case are stored as relationships:

More Natural Modeling

The data model above is easier to understand and reason about. At a quick glance, you can see that a User may have one or more REVIEWED relationships pointing to a Movie node. Nodes and relationships can both contain properties stored as key-value pairs. We can use this to store the rating and createdAt properties of the review directly on the relationship.

Constant Query Times

Remember how I mentioned earlier that relationships are treated as first-class citizens? When a relationship is created in Neo4j, a pointer is appended to the node at each end of the relationship, ensuring that every node is aware of every relationship going out from or coming into it.

This enables the query engine to quickly lookup relationships without relying on an index. This ensures that query response times remain constant to the amount of the graph touched during the query rather than the data size overall.

Querying a Neo4j graph is also different from relational databases and document stores. Neo4j uses a proprietary language called Cypher. Cypher is similar in structure to SQL, but instead of starting with a SELECT statement and using JOINs to combine data, a Cypher statement begins with a MATCH clause, which defines a pattern of data to return.

Neo4j will then parse the query, examine the database schema and use database statistics to determine the most efficient way to traverse the pattern. Regardless of the way the pattern is written, the query will be executed in the same way.

Let’s look at the SQL and Cypher statements required to retrieve the data side by side. Both queries will find the names of actors from the movie The Matrix.

SQL Cypher
SELECT p.name, p.born, r.roles, m.title
FROM people p
INNER JOIN roles r on p.id = r.person_id
INNER JOIN movies m on r.movie_id = m.id
WHERE m.title = ‘The Matrix’
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE m.title = ‘The Matrix’
RETURN p.name, p.born, r.roles

In a Cypher statement, you use an ASCII-art style syntax to draw the pattern you would like to read from the graph. Nodes are surrounded by parentheses ( ( and ) ), and relationships are drawn using dashes and an arrow to represent the direction. This declarative approach differs from a Pipeline in MongoDB, where you must express exactly how the data should be retrieved.

This is only a trivial example, but the more complex the use case becomes, the more a Cypher statement comes into its own. I have shown Cypher statements to business owners, architects, and even C-level executives, who have all quickly understood what the statement is doing, which cannot be said for an SQL statement and certainly cannot be said for a pipeline.

Suddenly the barrier to data engineering doesn’t seem so high.

Conclusion

My mantra has always been to use the best tool for the job, particularly when it comes to databases. You may feel that my opinion is a little biased, as I am literally paid to have this opinion. But since first installing Neo4j around a decade ago, I’ve started to see the value of connections everywhere.

A simple network of nodes and relationships is surprisingly powerful when storing data. Graph databases allow you to avoid much additional work to model your use case to work with a database and naturally handle performance and scale.

If you would like to learn more about Neo4j, you can check Neo4j GraphAcademy, where we have constructed Beginners courses that will give you the confidence to import and query data in Neo4j, and the Developer courses teach you will show you how to connect to Neo4j using one of the five official drivers: Java, JavaScript, Python, .NET, and Go.

You can create an AuraDB Free instance pre-populated with data, which will hold 200k nodes and 400k relationships, and it’s free for as long as you need.

So, if you are working with a complex, highly connected dataset or would like to futureproof your project against complicated database migrations and refactoring in the future, why not put the Graph into GraphQL?

]]>
hello@smashingmagazine.com (Adam Cowley)
<![CDATA[Inspiring Web Design And UX Showcases]]> https://smashingmagazine.com/2023/03/inspiring-web-design-ux-showcases/ https://smashingmagazine.com/2023/03/inspiring-web-design-ux-showcases/ Mon, 06 Mar 2023 16:00:00 GMT Design inspiration! Where do you find interesting websites? Here’s a list of showcases that we frequently visit for inspiration.

No matter if you’re looking for effective, unpretentious designs, websites that have that extra bit of fun built-in, examples of good e-commerce UX, interaction scenarios, or if you want to leave your own comfort zone and dive deeper into designs that go beyond the Latin writing system, you’ll surely find something in this post to tickle your ideas. Happy browsing!

Table Of Contents

You can jump directly to the topic you’re interested in to find relevant showcases or browse the complete list. Enjoy!

Japanese Design

The web spans the entire globe, however, when we talk about web design, the examples usually revolve around the 26 characters of the Latin alphabet. Other writing systems are often not part of the discussion — with the effect that a lot of brilliant websites stay unnoticed for a lot of us. Time to change that. If you’re up for a journey through Japanese web design, Responsive Web Design JP is for you. The examples in the collection shine with a unique lightness and concentration on the essential, and, even if you don’t master Japanese, you can browse the showcase by technique.

Design Made In Germany

Design Made In Germany compiles the best design work from German agencies and designers. Apart from covering website design, there are also collections featuring stellar pieces of brand design, print design, packaging, logos, posters, movies, typefaces, and illustrations.

Dark Mode Design

Dark Mode Design showcases beautifully designed websites that are either exclusively in dark mode or have the ability to switch. Wonderful examples that dark mode is not an add-on to a “regular” light design but a style with lots of creative possibilities.

Minimal Design

Dominic Whittle and Tom Fitzgerald, curators of Httpster, love good typography and effective, unpretentious design. More than ten years ago, they started emailing links of nice sites to each other but quickly realized that they needed a better system for sharing and tagging the things they get inspired by. That’s when Httpster was born.

Low-Carbon Websites

With big JavaScript libraries, large unoptimized images, and auto-playing videos, many incredible websites are heavier than they could be, creating a large, hidden carbon footprint. And then there are websites that prove that good design can also be achieved while keeping the carbon impact on the planet low. Lowwwcarbon features examples of sustainably built, low-impact websites. And if that’s not enough inspiration yet, Lowww is also dedicated to sustainable web design.

One Page Love

One Page Love showcases websites that get by with just one single page. The beauty of “one-pagers” lies in promoting one thing, straight to the point, without any clutter. Rob Hope founded One Page Love back in 2008 and continues to add one-page websites and resources daily. If you need some landing page inspiration or are looking for templates, this place has got you covered.

Fine Web And Interaction Design

Almost 8,000 sites that run the spectrum from fun and novel to clean and simple are waiting to be discovered on Siteinspire. Curated by Howells—Studio, you can browse them by style, type, or subject, or just see the very best.

Alternative Design

If you’re looking for extraordinary designs that experiment with interactivity and content in new and interesting ways, Hoverstat.es never ceases to inspire. The site describes itself as “the home of alternative design, code and content on the world wide web” and features everything from a portfolio with layered 3D preview to delightful little details like a slick looping scroller or menus that think outside the box.

Whimsical Design

“The web needs to take itself less seriously” is the message of The Whimsical Web. The site showcases websites that have that extra bit of fun that we often miss on the web these days. So if you’re up for some little surprises and weird details, Whimsical Design will leave you with a smile on your face and some new ideas.

Personal Sites

Your personal site needs an update? Personalsit.es has some new ideas in store for you. Built to share and revel in each others’ personal sites, the collection is jam-packed with inspiration — from simple and minimalistic to bold.

Site Of The Day

Every day, Awwwards awards the title “Site of the Day” to an outstanding website, rating its design, usability, creativity, and content and highlighting some of the details that make it outstanding, among them typography and color palette.

Website Roundups

In her Inspirational Website Roundups, Manoela Ilic presents websites with exceptional designs and interactions. Each edition is a surprise bag of the most beautifully designed and thoughtfully crafted websites.

UX In The Wild

Waveguide documents UX examples on different platforms and in different contexts, shining a light on remarkable interaction scenarios. From load-more pagination to QR code login, JJ. Ramirez, curator of Waveguide, explores every example in detail.

UI Patterns

From launch screens to error messages, from settings to radio buttons — no matter what kind of UI pattern you’re looking for, UI Garage features more than 6,700 patterns for web, mobile, and tablet, categorized and handpicked. Another great stop for some UI inspiration is Design Vault. The ever-growing collection features designs and patterns from products like Netflix, Pinterest, Medium, GitHub, and many more.

E-Commerce UX

The Baymard Institute maintains a database of 12,000+ full-page design examples, documenting e-commerce designs from 2012 to today. The examples are organized across 57 page types ranging from homepage and category to accounts and self-service and include desktop, mobile web, and mobile apps. Each example highlights what the page design does well from a UX perspective and what could be improved.

E-Commerce Inspiration

Ecomm.design unites design and tech inspiration in one place. The site showcases more than 3,800 e-commerce websites, along with their tech stack. You can browse the examples by e-commerce platform, category, technologies, and traffic.

Landing Pages

Landbook showcases different types of websites, browsable by color, typography, style, and industry. Among the examples are landing pages, portfolios, blogs, product pages, and more. For more landing page inspiration, also be sure to browse by Landings. The site collects hundreds of landing pages created by leading companies. You can browse them by color, light, and dark mode.

Mobile Inspiration

Mobbin is a library of more than 100,000 fully searchable mobile and web screenshots. The screenshots are organized by app categories, screen patterns, and user flows. Login is required; the free plan includes the latest app designs of the week.

Page Flows

Page Flows was created to help you design better user flows by learning from proven products. The library features more than 3,300 recordings and emails of tried and tested products to give you inspiration for anything from onboarding to upgrading and inviting friends. A membership is required to access all user flows.

User Journeys

UI Sources has got your back when it comes to designing common flows. The site features recordings of end-to-end user journeys to help you gain insights and identify trends. A subscription is required to access some of the features.

SaaS Interfaces

Do you need some inspiration for SaaS interfaces? SaaS App Design Inspiration collects UI and UX design examples from some of the best SaaS products. A subscription is required to access the complete gallery. Lookin’ for more? Saas Landing Page Examples features UI examples created by SaaS companies. Plenty of inspiration for anything from landing pages and pricing to “About Us” pages, features, testimonials, and more.

Weekly Showcase

Do you want to get design inspiration delivered directly to your inbox? The UIJar newsletter brings you design updates, articles, and design resources every week. The accompanying online showcase features handpicked websites, branding, and curated collections, among them brutalist websites, websites with big typography, or websites with lots of whitespace.

Fonts In Use

There are so many fantastic typefaces out there that decisions can be hard. Fonts In Use is here to help. The independent archive indexes typography by typeface, format, industry, and period. Perfect for discovering new fonts and font pairings.

Wrapping Up

Do you have a favorite showcase that you keep visiting for web design inspiration? Or maybe you’ve been curating one yourself? Let us know in the comments below! We’d love to help spread the word.

]]>
hello@smashingmagazine.com (Cosima Mielke)