Smashing Podcast Episode 30 With Chris Murphy: What Is Product Design?

In this episode, we’re talking about Product Design. What does it mean to be a product owner, and how can you learn the skills required? I spoke to expert Chris Murphy to find out.

Show Notes

Weekly Update

Transcript

Drew McLellan: He’s a designer, writer, and speaker based in Belfast UK, he’s a teacher and, like many of us, one who’s still on his own learning journey. As a design strategist, he’s worked with companies large and small, driving innovation by drawing on over 25 years of experience working with clients such as Adobe, Electronic Arts, and the BBC. He now mentors startup founders, with a particular focus on purpose-driven businesses. His work is underpinned by his own startup, The School of Design, a community for creatives who are designing, building, and selling products. So we know he’s an expert in helping others to learn, but did you know he was once taught to play the hurdy-gurdy by Dame Helen Mirren? My smashing friends, please welcome Mr. Chris Murphy. Hi, Chris. How are you?

Chris Murphy: I’m smashing.

Drew: As mentioned in the intro, you first and foremost are an educator, a teacher, and your focus and your energy at the moment is being put into a lot of helping design-focused entrepreneurs to be equipped with the skills that they need to build products. It’s a phrase that we hear a lot, but what’s it actually mean to be design-focused?

Chris: It’s really interesting. I had to do a pitch at the end of the Propel program that I was on from January to June. If I just rewind a little bit and talk about Propel, it’s a startup founder program that I was a mentor on two years ago. Honestly, I was so excited to be a mentor, and the teams were great. Over the summer, last summer, I came back in for what they have, an office hours session, and Ian, who was one of my colleagues on the program, his instinctive ... “Well, why are you here?” I said, “Because I think I’m actually going to go on Propel next year,” and they were like, “What,” because they had lined me up to teach on it. I just said, “Look, there was so much excitement in the program, and I just wanted to be part of it.” Plus, I feel that I’ve been teaching for 20 years, and it’s time for a change.

Chris: I also think that education’s going through this massive re-imagination at the minute, partly because of COVID and just partly because there’s a pushback against very high fees in universities. The other thing is, and I’m going to get back to your question in a second, my daughter, I think she’s 21, and she’s in her third year at Glasgow School of Art, and she’s racking up on an awful lot of debt to study jewelry. I think there must be a better way to teach design in a connected age. But coming back to your question, design-focused companies. At the end of my pitch at the end of Propel, I talked about Apple, and I know Apple’s a bit of a tired example. But it was at the time the world’s first two billion dollar company, and everything they do is design-focused. I mean, the hardware is considered, the software is considered, as we’ve seen recently, the chips are considered, everything is considered in terms of how it goes together.

Chris: One of the debates I’ve been having in my head recently, Drew, is this idea of ... Yesterday, I spoke to somebody about product design, and I have a friend who’s on Propel and he is a product designer, as in he was studying physical product design. I said, “That’s really interesting,” and he said, “I think you’re calling these people the wrong thing.” I said, “But” ... Another person on the course, who is a product designer, but she’s what we would call a product designer, someone who’s making digital stuff, and so in my head, I think, “Well, these ideas of these separate disciplines are kind of ludicrous these days,” because you can’t really have a product, a physical product, let’s take this laptop here, without some software on it. You can’t have the software and the laptop working together without getting that laptop into our hands, so we then have to go to a shop to buy that. That’s an experience, and that’s been designed as well.

Chris: So if we take just this computer that we’re using to record this conversation, design is involved every step of the way. It’s involved in the processes that are used to mill out the aluminum that all the stuff goes into. It’s involved in Big Sur, which is the operating system that’s running on it. It’s involved with going to the Apple Store to replace my computer the other day, and it’s not like the Apple Store anymore, but it’s being designed as an experience that’s designed for COVID. So everything is designed, everything, or I suppose a fairer way to put it is everything can be designed but not everything necessarily is designed. I think that that’s what I’m interested in. Design can touch lots of things.

Drew: So to be design-focused would mean to make sure to design every little bit of the process that you can or to care about designing more of the bits of the process than a company that isn’t as designed-focused?

Chris: Yeah, I love that. I love that idea of designing more of it because if we step back and we look at the entire process ... And I think designers are quite good at this. Designers are quite good at going into a business and maybe we’re asked to solve this problem over here. I don’t know about other people, but the way I tend to do that when I’m doing work as a consultant is I tend to go in and I’ve been asked to look at this problem, problem X, and I’ll spend a couple of days looking at that, and then I’ll come back and say, “Look, I can totally help you with problem X and we’ll get that sorted, but I really think a more pressing issue is this thing over here. Let’s take a look at that.” Because I am so terrible at business, I usually say things like, “I’ll do that for free, and then I’ll help you with this problem over here,” because I’m really interested in all of the parts of the experience.

Chris: A lot of companies just don’t really look at ... They might be design-focused companies, but perhaps they haven’t considered how they, let’s take an example, package up their products and send them out. For me, when I look at that as an experience ... Because one of the things that we’re doing at The School of Design is a thing called designer tools, which is basically these sketchbooks, of which I have thousands, thousands sitting just over here, these bands that go round them which you put your pens in, and a system I use to keep everything organized in my sketchbooks. We’re selling all of that stuff, but I’m not just putting those sketchbooks into a box. I’m putting them in with lots of little things, like badges and stickers and little notes and all of that kind of stuff, because when that arrives at someone’s house, I want them to open that and have an experience. I don’t want them just to open it and have three sketchbooks. I want them to be thinking, “Whoa, that’s a nice experience,” because I think that that will make a deeper connection with that person. I don’t want to use the word customer. I think I prefer to use the word friend who paid me some money for something.

Drew: So you mentioned Apple there, and despite being, as you say, a slightly tired example, I still think they’re an excellent example. I don’t think it matters that people have mentioned them before because they are such a great example. Are there any canonical examples in the more digital space of companies that do this particularly well, this design-focused approach?

Chris: Look, I don’t want to use another hackneyed example, but I think GOV.UK are doing an amazing job. I don’t think they’re a company, but I think what GOV.UK have done through the digital cabinet office or whatever that’s called and thinking about the processes of government and how people access services, what’s interesting to me is that has had an impact on lots of other companies. So if we look at ... The Co-op is a good example of a company company. A friend of mine, Charles Burdett, who made Workshop Tactics ... I don’t know if you know Workshop Tactic. They’re these really, really great cards, Workshop Tactics. I think it’s workshoptactics.com. If you want to run workshops, they’re brilliant for that. But Charles used to work for the Co-op and was a consult ... He’s working as a consultant there just now, I think, and they’re very good at designing all of the different aspects of the business, including, I think, visualizing how we might shop in the future.

Chris: If you want to go into the Co-op, I have a Co-op just down the street, and if I want to go into the Co-op today, what I quite like to do because of COVID is walk around with my phone and scan things as I put them just straight in my bag and then just leave the shop. I don’t particularly want to talk to anybody because usually I’m listening to a podcast. I mean, I do talk to a lot of people in the Co-op, like there’s Anna and there’s a few people in there who are my friends in the sense that it’s my local shop. But there’s always staff I don’t know, and on those days I just want to get in, get out as quick as possible. If we add COVID on top of that as a potential life-threatening issue, I really want to get in there and get out as quickly as possible with a minimum of fuss and with a minimum of connection with other people as well. That current experience is bringing us to a bottleneck, which is a checkpoint, or not a checkpoint, that sounds very Northern Ireland-

Drew: Checkout.

Chris: ... a till, a checkout, thank you, and that’s a bottleneck. Even with the things on the floor that say, “Maintain two meter distance,” et cetera, people never ... They’re so busy that they never really notice those little signs on the ground. That process could be redesigned in a much, much better way. I think there’s scope there and potential to think about how design impacts everything.

Drew: Thinking in terms of individual founder businesses, entrepreneurial businesses, does it follow that if an individual is design-focused themselves that the product that they make will be that way? Is a product really an extension of the person who designed it?

Chris: I think that’s a really good question, Drew, and I think that the answer to it is it depends. I think it depends on that person and it depends on the scale of the company. If you take a look at Hiut Denim, and I use Hiut a lot in my teaching, it’s a really good example of a company that’s doing one thing well, and that’s their sort of strapline jeans. I think if you look at David’s previous ... David and Claire, because they’re a partnership. If you look at David Hieatt and Clare Hieatt’s previous company, which was Howies, that company had grown so big, there were so many people involved. Once scale starts to creep in, it starts to become very difficult to keep an eye on all of the little touchpoints that matter in the customer journey. I think it’s really telling that when they left Howies, because Howies had been bought by ... It’s complicated. Go read it on the Internet. But it was Timberland, and Timberland was bought, and there’s all this story.

Chris: I think it’s really interesting that what they’re focused on now is jeans. That’s it. They’re telling an amazingly good story around jeans. They’re also packaging everything really, really well, and the jeans are like a vehicle for stories, really. Also, the jeans are ... And this is something I think, Drew, is going to become more important as we come out the other end of COVID, which I hope we come out the other end of. Everyone who’s making those jeans is being paid a proper wage. One of the problems I have at the minute when I look at the world is not everybody is being paid a proper wage and I find that a little bit concerning, as someone ... Look, I’m 51, my son is 25, 24, 25, something like that. It’s terrible. I should know all this stuff. He’s a wedding photographer. He has been a wedding photographer for a year and a bit. His business is completely decimated because no one’s really getting married at the minute because it’s just difficult. He has no salary because he didn’t have enough self-employed books to get the support.

Chris: He’s fallen through the cracks, and there’s a lot of other people who’ve fallen through the cracks. I would argue that’s a design problem, that we need to look at that as a design problem. But if I also look at that wider issue of COVID and the government and all of these things without getting too political, I read an article in the Guardian yesterday about Matt Hancock’s neighbor, and anyone who’s listening who’s not from the UK, Matt Hancock is the Health Secretary. His neighbor, who was running a business, was texting him and asking for advice about, “How do I supply products for this COVID thing?” There’s an awful lot of rumblings around the chumocracy, is what the papers call it, friends of friends of government ministers who seem to be getting jobs because they know the right people.

Chris: I get this sense that we’re going to come to the other end of this and see this ... Individuals see that, and they think, “Well, where is this money going, and are people being paid properly? What’s the price of this one pound t-shirt from shop X?” I don’t want to mention any brands. But everything has to be paid for, and everything that’s made, people have to be paid to make it. I think people are increasingly interested in are people being paid fairly.

Drew: One thing you mentioned in there was design touchpoints, which by a design touchpoint, you mean anything where the customer, if we can use that term, comes into contact with your product or business? Is that what a touchpoint is?

Chris: Yeah, I hired a placement student this year, which is really unusual because I’ve been teaching at Belfast School of Art for 20 years and I don’t think a member of staff has ever hired a student who’s going on a placement year. But I kind of knew I was leaving, even though nobody else did, so I hired a placement student to help me. I think the last diagram she drew for me was touchpoints because I constantly have conversations with people who say, “What is that?” They’ve never heard that term before. In a sense, that really is what The School of Design is about. It’s teaching you all the things that nobody taught you in art school, basically. So, yes, it’s about building products, but it’s also about just covering gaps in knowledge.

Chris: But touchpoints are everything. They’re from how you answer the phone, which increasingly is not really something that we do, it’s maybe the tone of voice of your email or the tone of voice of your social media messaging or how you write a blog post. There’s so many different ways you come into contact with people, and all of those ways have to be designed.

Drew: So things like microcopy and all of the communications, the tone of voice, the-

Chris: 100%. One of the things that Jasmine, my placement student, has been working on for me is an illustration system for The School of Design so that when she comes to the end of her placement with me, which, at the minute, is looking like about December sometime, but when I embark on The School of Design properly from the first of January, I have everything so that we have visual aesthetic that is considered. If you think back to some of the articles I’ve written for Smashing Magazine on UX design, I’ve always designed those illustrations for those articles with the smashing red, and I’ve always thought, “Well, these are part of the series for Smashing Magazine.” I’ve done some stuff for Smashing in Adobe, and I think, “Well, we should try to make these illustrations on brand,” for want of a better word, because that’s where they’re going to end up, right?

Chris: What was interesting to me, that if we think back to those articles, Adobe published them on the Adobe blog, and I could instantly tell that they were Smashing because they had that color, and you could see looking down the page, some were by me and some were by other people, but you could see, “Oh, that was from Smashing Magazine.” I was stoked for ... I’m so biased because I think Smashing Magazine is doing an amazing job.

Drew: Thank you very much. Yeah, you often hear people talk about entrepreneurial business saying that, “Oh, it all starts with an idea.” I’m not really sure that’s true, personally. I think, to me, the products that really make it and are successful often start with a problem.

Chris: Yeah, I knew you were going to say that. Yeah.

Drew: Or a constraint or a limitation. It always starts with a struggle, and it probably carries on that way as well. Do you agree with that?

Chris: I do, I do. I think that most products ... I mean, if we think of products, they probably fall into two categories. One is problem-solving, like I have an issue and, oh, look, I have this issue and there doesn’t appear to be anyone solving it in a particularly delightful way. Perhaps someone is solving that problem but maybe not in a delightful way, and so we can bring delight to the party, and we can bring delight to the table. I think we should be thinking about that full-stop for everything. So one category is that I have a problem. But I think another category is just delight. We buy a lot of things for no other reason than they bring joy into our lives. I think everybody has probably got something that they bought that they could get a cheaper version of this thing, but they bought this thing because it brings product.

Chris: I have an example behind me, which is this shoe. I have these shoes in two sizes. Unfortunately for people who are listening to this podcast, you can’t see the shoe. It’s a Camper shoe. All my shoes are Camper shoes. I fell in love with Camper a few years ago. It’s a really good story. Portugal, I think, is the company. I only buy the Pelotas shoes, which have got the balls on the feet and on the soles, and they have a story behind that as well inspired by footballs, I think. This is a Camper Kvadrat. I don’t know how you pronounce Kvadrat. It’s like K-V-A-D-R-A-A-T or something, and it’s a textile company. I bought this in a size 10 because that’s my usual size, and I also have it in a size 11 because it’s such a stiff fabric, it’s really tight. So I had to buy another one, and so these are kind of like an ornament sitting on this bookcase behind me.

Chris: Now, I could buy these Camper shoes, and I think they probably cost me about 90 pounds or something. Now, I don’t need to buy those shoes for 90 pounds. I could probably go and get a decent pair of shoes for 20 pounds. But they just bring a bit of joy into my life. When I put the shoes on, they’re bright blue, and people usually say, “Whoa, where’d you get your shoes?” So they’re a conversation starter. They’re not just a shoe. So that’s another half. I think if we think of those products as being in those two categories, problem-solving and delight-bringing, ideally, we want a mixture of the two, we want problem-solving and delight-bringing. But I’d say probably 70% are problem-solving and about 30% are no other reason than joy.

Drew: You mentioned the story behind a product. How important is it to have a sort of origin story behind your products?

Chris: I think it’s really important. I think that people are hungering for stories now. I think if we think back to the overlong section where I was criticizing the government, which you might want to edit, I think stories are important. I have a whole deck, it’s on Notist as well, which is called Product Storytelling, and it looks at the story behind Hiut Denim, but it also looks at the story behind Field Notes, which are somewhere behind me on that bookcase. Field Notes are a really good example of this. If you go to the Field Notes website, and you click on any of the printed products, they will tell you crazy details like, “Thanks to these three people who invented the staple,” and, “This particular printing press is called a such and such and such and such,” and, “It’s printed with these Pantone Hoya inks,” and, “The paper is this, that, and the next thing.” If you’re spending $9.95 on three tiny notebooks, the story’s kind of important because you could probably just pop down to your local stationer’s and get a much cheaper set of notebooks.

Chris: But you’re not really buying notebooks, you’re buying a story there. I think that Field Notes are a really good example of that because they’ve taken something which could easily be a commodity and it could easily be something that you buy based upon the price and they’ve turned that into something that is a story and that you’re buying not just because it serves a purpose, it’s useful to put in your pocket and take notes. Just, it’s something that brings a smile to your face. On one end of the spectrum, they have the standard brown field notes, which are kind of the commodity end, and even those aren’t really a commodity. Then, on the other end, they have their editions, where they’re trying different print finishes and they maybe are inserting maps.

Chris: There’s a huge amount of Field Notes influencing this, the designer tool sketchbooks that we’re working on for The School of Design because Andy McMillan, who folks may know for Build Conference and XOXO, he is the person who printed all of these sketchbooks. When he moved to Portland, I bought them off him, or I bought some of them because we used to share a building and he was one floor down and my studio was above him. I bought a box off him, and I started to use the sketchbooks, and I always used to put my ... I’d do them in a particular way. I’d put a postcard on the cover so I can tell that’s the current sketchbook, and then I have a table of contents on the inside and so on and so forth.

Chris: When he was selling them, he had a shop called Draft Tools or Draft Supply. It was Draft Supply Co. You can see it on the Wayback Machine. He said sketchbooks shouldn’t be celebrated. They should just be cheap. It’s the ideas that should be celebrated. I agree with him, but I kind of wrote something recently where I said, “But why can’t the sketchbooks be celebrated as well?” When he got them printed ... I wish I could show you, Drew. There’s literally boxes of these everywhere. They’re printed by a company called Oddi, O-D-D-I, and I remember Andy saying to me that he’d had them printed by Oddi, and I was like, “Why did you get them printed by Oddi? They print books, and they’re probably an expensive place to get notebooks made.” But, for me, I looked at the paper and the print and the binding, and it’s just there’s a story there, and Field Notes have done a really good job of telling that story, and they’re very successful as a consequence.

Drew: So is it about creating an emotional connection with the customer on whatever level?

Chris: 100%. And this is one of the things, one of the many things, that I am trying to cover in The School of Design. I’m just writing that down frantically in motion. Because a lot of the purchases that we make today are driven by emotion, not necessarily by rational decisions. When the M1 computer came out, oh, two weeks ago, coming back to my son, the photographer, he is working on a very old computer with the screen hanging off and I happen to have a spare, old-ish MacBook Pro, I said to him, “Okay, you can take this, and it would improve your life considerably.” But at the same time, I was like, “But maybe you should get that M1,” because I had been completely seduced by the visuals and the storytelling and the chip and the memory and all of that kind of stuff. After about 10 minutes of talking to him about this, I was like, “Maybe you should be getting this computer that I have and I should be getting that M1."

Chris: Then, after I rationally thought about it the next day, I thought, “I don’t need an M1 computer. There’s nothing wrong with this one. I bought it last year.” But that’s a really good example of emotion getting the better of you. You think to yourself, “Oh,” and you get carried away. I’m sure we’ve all been in a shop where we’ve bought something and we didn’t really need it, but we bought it on a credit card, and then maybe when the credit card bill comes in, we think, “Why did I buy that X?” That’s a good example of emotion and not rational thinking. I think a lot of this isn’t taught in design school. I’m really struggling with what The School of Design is, but it’s definitely this, right? It’s psychology, it’s touchpoints, it’s customer journeys, it’s emotional responses versus rational responses, it’s mental models. It’s all of the things that nobody really mentioned to you when you were at art school but you really need to know in order to work as a designer now.

Drew: I think having that sort of story behind a product is something that Apple does particularly well. I think they do it so consistently and have been doing it for so long now that perhaps people don’t even notice that it’s happening, but everybody listens to it. They can say, as you were mentioning earlier, “This new product has been milled from a single piece of aluminum,” and they’re telling that story. On a practical level, we don’t care how it’s been manufactured. They can use whatever manufacturing process works best for the end product. But they sell it to you on that, this is the care that’s gone into it, this is the process, we did this research, we found that this was the ... Then you see the unboxings on YouTube and the reviews, and they’re all, “Ah, did you know this was milled from a single piece of aluminum?” Those stories really sink in and give people an attachment to the product more than if it was just a utilitarian tool.

Chris: 100%. Because I’m leaving Belfast School of Art, at the moment, I’m bringing home boxes and boxes of stuff. One of my boxes, I don’t think it’s here, I think it might still be in the university, is called the experience, and it’s a cardboard box full of stuff that’s to do with this whole topic. There’s a lot of stuff from Howies, including a box of Clipper tea that came with a bag I bought. I was like, “Why are you putting that tea in,” and they said, “We always put a box of Clipper tea in with everything you buy.” I was like, “Right, okay,” fascinating for me.

Chris: But one of the other things, which I don’t have anymore, as a lecturer I used to do about 10 or 15 years ago where I had an Apple computer box in one hand and a Dell computer box in the other hand. The Dell box was a brown cardboard box, silkscreen-printed, pretty utilitarian and not very exciting. The Macintosh box was just the opposite. My story with the students was always like, “If you’ve just bought a computer that was 1500 pounds, this unboxing experience over here is telling you every step of the way you’ve made the right choice. The Dell box, on the other hand, wasn’t really doing anything. It was just getting it from A to B without getting scratched.” I think that that’s a real missed opportunity.

Chris: Packaging is something that’s often overlooked, and, actually, if you go and look at ... There’s some great books on Japanese packaging that we could all learn from in a Western culture. There’s a really good book called How to Wrap Five Eggs, and there’s another book called How to Wrap Five More Eggs. They’re both about the Japanese obsession with wrapping. They take an object, and they wrap that in tissue, which is considered, and they then put that in a bag, which is considered. They then maybe wrap that up and tape it together, which is considered, and then they put it in something else. Every step of the way is like a layering process that makes you just feel amazing, and all you’re unwrapping is an egg. It’s incredible.

Drew: Does communicating all these sorts of details and thinking about all these little touchpoints ... Obviously, it works for big businesses, mega-corps like Apple who’ve got lots of money to spend at it. Can it work for very small companies, too? You mentioned Hiut Denim. They’re just a small company, aren’t they?

Chris: I love the way you said mega-corp because it feels like it’s out of a film from the future, and they probably colonize planets as well. Yes, I think it works almost better for smaller businesses. I would argue that if you’re a smaller business, you have a real advantage. Let’s say I’m a mega-corp and I’m sending out my stuff. It’s very difficult for me as the CEO of mega-corp to hand-write a note for every single customer because the business is just too big. Then if I write a note and then try and sign it, well, maybe we could scale it a bit, right? But then what happens is you write a note and then you actually print the signature. It’s no longer actually signed. Then people like me who are cynical go like this and they hold it up to the light and they go, “Oh, that’s not signed.” That’s actually now having the opposite effect, in that it’s looking like it’s personal but it’s definitely not personal. Most businesses don’t think about any of this kind of stuff, but I can’t be alone in feeling that way.

Chris: But, on the other hand, if I’m a small business and I open my package, who’s a good example of this? Counter-Print Books. Don’t go to the website, it’s counter-print.co.uk, I think. Just don’t go to that website. You’re going to spend a fortune on books. But Richard Baird who publishes Logo Archive, which is a fantastic little zine, every issue of Logo Archive that I have had from Counter-Print Books has a little message from ... I think her name is Celine, and it always says, “Enjoy your zine, Christopher,” and she says thank you. I’m just like, “Wow, I’m so stoked.” I took a photo of that recently, which I’ll tweet when this comes out. I’ve got all the thank you notes.

Chris: I was teaching a group of crafts people about two or three months ago, and one of the other crafts people on the call, because I was teaching and they were all muted, I could see that she was wetting herself laughing. I was like, “Why are you ... Have I done something?” I’m thinking, “Is there something behind me?” I said to her, “Angela, why are you laughing?” She said, “I’ve also got all these notes as well.” I was just like, “Oh my goodness.” I thought maybe I was the only person who kept these. But I said to her, “It would feel like sacrilege if someone’s written you this little note to just crumple it up and throw it in the bin,” because it feels like that connection has been made with you across time and space. You can do that as a small business. You have advantages as a small business that big businesses don’t.

Drew: It’s almost like giving it a sense of provenance, isn’t it, like if you went to a local restaurant that has its own kitchen garden and grows its veg and sources its meat from local farms? It’s giving that feel of connection.

Chris: I wish I could show you. I’m opening up noti.st.mrmurphy and I’m going to go and find Paint a Product Picture. And Notist is so nice, so slide nine from Paint a Product Picture, which I’ll give to you and you can maybe put in the show notes, is a screenshot of the Apple Dictionary of the word provenance, “The place of origin or earliest known history of something, the beginning of something’s existence, something’s origin.” In my notes beside the slides in the slide view, the tall slide view, which is fantastic, “In an era of cheaply manufactured goods, customers are eager to know the provenance of your product.” That’s a good example of the differentiation you can have as a small business versus a large business.

Chris: The bigger a business gets, the more people there are in the business, the more there are people in middle layers of management who come along and say, “That thing that we’ve had made by this seamstress in Cardigan Bay, I think” ... If we come back to Hiut Denim, they call those people grandmasters. To you and me, they’re ... I don’t think you’d call them tailors because tailor to me evokes a Savile Row kind of image, like a suit that’s tailored to you. What they probably are are seamstresses or people with a sewing machine, and Hiut Denim call them grandmasters. But the bigger the company gets, the more this middle layer of management starts to say things like, “Look, we’re paying all these people in Wales 10 pound an hour basically to stitch up these jeans. What if we got those made in Bangladesh or somewhere cheaper, where the cost is less expensive and the cost of living is less expensive and there perhaps are less factory condition checks, et cetera? We could save a ton of money, and we could make more profit."

Chris: That’s the slippery slope, and when that happens, the provenance suddenly disappears. People care about that kind of thing now. I think coming out the other end of COVID, I think people will remember ... There were certain companies when COVID started, I remember in the UK, that were ... If you were an essential business selling food, you could stay open, but if you weren’t an essential business, you had to close. There were certain companies like Sports Direct who were saying, “We are an essential business.” There was a backlash in the public saying, “In what way?” It was kind of like, “Because people need to do sports while this is all happening.” I think that those kinds of things, people have long memories.

Drew: As a product owner, how important is it to rigidly stick to that vision that you had when you started things up? I think of companies like Basecamp, which was formerly 37signals, and founder Jason Fried there as always marching to the beat of his own drum in terms of what the product should and shouldn’t be. That’s quite often in the face of customers who are saying, “We will pay extra if we can have these features,” and the answer has always been, “No, that’s not what we’re about.” Is that a key to success, or is that just one path that someone might choose?

Chris: It’s a bit of both, I think. All my answers are always it depends. I think here’s a good example which is closer to home. Over the years, I’ve asked you to make changes to Notist where I’ve said, “I’m an educator. I don’t particularly want to make up fake conferences so I can share my slides.” But your product is really designed for speakers at conferences. I’ve almost come to a form of ... I’ve asked you to make changes to your product many times as a customer, and you’ve decided not to do that, and that’s entirely your right to say that because it’s your product. I think that there’s a place for having a vision and not immediately bowing to the needs of one customer.

Chris: It’s like yesterday, I was thinking about The School of Design and where we’re going. I wasn’t sure if the word designers was an important part of it for the customers, or was creatives a better word? I was having this debate with my other brain in my head, and I was like, “Actually, I think it’s designers.” But the reason I had used the word creatives was because one of the people who’s taking a course with me at the minute is not a designer. He’s a developer, and he said, “I think if you used the word creatives, I would feel part of it. But if you use the word designers, I wouldn’t feel part of it.” So I was almost going to change the whole pitch for the business because of the sake of one person, which, when I thought about it rationally a couple of days later, I thought, “That’s insane,” right? It’s called The School of Design. It’s all about design. You can be a non-designer and you can come into The School of Design, that’s totally cool, but I’m not going to change the language for that one person.

Chris: I think that comes back to what I was saying about Notist earlier. You have a vision, your product is working really well for that vision, and you’re sticking to it. I think that that’s a good thing. The flip side of that, if we think about 37signals, Jason Fried, et cetera, they are very strong-minded. They know what they want to do, and they also know what they don’t want to do. One of the problems with getting stuck in that way of thinking is that you can miss innovations. You can be so focused on this is what the thing is that customers really need something and just don’t do it, I think, because you feel so dogmatic. When we launched Get Invited, our ticketing platform, which is struggling because ticketing in the middle of COVID is a problem, our vision at the beginning was let’s not be Eventbrite. Let’s not put so much stuff on the page. Let’s just keep it simple.

Chris: When I briefed Kyle and David, my two co-founders, who were students when we built the business, it’s incredible, I said to them, “Look, above all, we must never lose sight of the fact that these pages for the events need to look beautiful. So we have stop people, normal customers, from messing up the pages by doing design.” And you know what? Actually, we were wrong. Overwhelmingly, people came to me and said, “Is there any way I can change the color scheme here because it just doesn’t fit my brand?” At the beginning, I was kind of really ... “Nope, forget it.” People were saying, “Could we put our logo on it,” and I was saying, “Absolutely not because it’s going to ruin the design.” Once we had hundreds of people coming and saying that they wanted to change the color or they wanted to add their logo or could they add more than 140 words to a description, we had to listen to the overwhelming evidence that perhaps we were being a bit too narrow-minded and we needed to flex a bit. So it’s that balance between sticking to your vision and not getting stuck in a cul-de-sac.

Drew: And how do you weigh into that the fact there might be competitive products or services in the marketplace that might do things that you don’t do or have features that you don’t have? There’s obviously a temptation there to start matching all the competitors feature for feature.

Chris: I think matching competitors feature for feature is a slippery slope because as soon as you do one, then you suddenly start feeling you have to do another. Before you know it, you’ve lost track of your original vision. If we come back to the Notist example, the thing I was describing to you was probably a different product. It’s probably the guts of Notist but batched as a tool for speakers who are not events, they just make a lot of decks, they make a lot of slide decks, and that’s a different product. So there’s opportunity there in the sense that you could use the same code base to make something different with a different brand and a different audience and a different target, et cetera. But perhaps if you did this thing and this thing and this thing, then suddenly your thing’s lost its identity.

Chris: Coming back to Get Invited, the example, we were very careful to ... If 100 people ask for X and we sit back and look at it rationally and think, “Okay, maybe we should buckle here and we should give them this thing because it’s affecting people’s willingness to take up the product,” so that was something. But it’s the slippery slope. I think you want to be you. You don’t want to be a smorgasbord of your competitors.

Drew: I suppose there’s a balance there between building a very narrow band, focused solutions for a specific need, versus building something that could fit a number of uses, I guess, to use a metaphor, a bit like a garlic crusher and a chef’s knife. The garlic crusher gets the job done with zero effort, but it only does that one thing, and the chef’s knife can also mince garlic, but it can do a thousand other things at once, but it requires a bit of skill to learn and to use. So, in terms of products, is there a way to balance that up? Do you go down a very focused, easy path and then duplicate it if you want to grow?

Chris: I think for me, at the beginning of the product journey, it’s really important to have focus. It’s really important to think, “Okay, well, who are my customers? What are they going to spend, and how am I going to look after them to the best of my abilities?” I think you could sell something that appeals to everybody and as such appeals to nobody. For me, at the beginning of the journey, it’s really important to focus down and think, “These are the core people.” It feels bizarre to me, but we’re nearly in December. I’ve been working on The School of Design in a kind of beta form for 11 months. I still don’t really know what it is. When I started the journey in January, my audience was definitely students. It was like, “This is cheaper to learn UX and UI using what was then called Design Track. It’s an alternative to university education, and it’s students.” The more I’ve been working on it, the more I think it’s not students, it’s actually professionals who are in the middle of their career and there’s just a lot of things about design they need to know. But I haven’t said, “Okay, I’m now going to include those people.” What I’ve actually said is, “This is the wrong audience and this is the right audience, and these people, I am not going to waste any time over."

Chris: I think that, at the beginning of your journey, if you try to be a knife ... This is going to be so cool with this metaphor here because people are not going to understand us if they come right into this bit of the podcast. At the beginning of your journey, if you try to be a knife, you’re being all things to all people, and I think it’s better to be a garlic crusher at the start and then over time add more things, as you scale slowly. So, for me, what’s really important, what are we trying to do and can we get a group of people to be really happy with what we’re doing and also pay us some money in the process because, otherwise, this is just a hobby. Once we’ve got those people happy, can we start to expand a little bit but not just in a massive way where then we’ll lose focus and we’ll become a knife? But at some point in the future, it might be worth considering becoming a knife because a garlic crusher at that point is perhaps too limiting.

Drew: You mentioned finding the right audience. It’s obviously important to find a market and work out what that market should be and tailor the product to fit that market. Is that something that the program at The School of Design addresses? Is that something that it equips people with?

Chris: 100%. I think that one of the things that we’re looking at is definitely audience. Who’s the audience for this thing? One of the modules that I was ... I mean, I don’t even know if we have modules, actually, if I’m honest. But, certainly, one of the things that I will be teaching is a thing I call venture testing. I talked about this in a workshop I was doing on Wednesday for startups in the Northwest, up in Derry, Londonderry, Derry. Covering all the bases here, Derry for one audience and Londonderry for a different audience, that’s a big city in the Northwest. I was talking about this process called venture testing. For me, it’s like build a smoke test page, use Facebook and Instagram to drive traffic to that smoke test page, and if there is interest and there are sign-ups, great, keep working on it. If there is no interest and there are no sign-ups, then either you’re driving the wrong traffic to the page, in which case, modify and change, but if no one is signing up for anything, then it’s time to close and move onto the next thing.

Chris: So I talked about a workshop that I’d launched with a friend of mine on the Propel program, and we had one sign-up. I kicked off the talk on Wednesday with, “This was a success.” Most people are looking at you thinking, “But you only had one sign-up.” Then I’m showing the structure of the course that I was going to have to write and saying, “One person is not worth writing all of this content and making all of these screencasts, so this has saved me a massive amount of time.” It’s really important not to get deluded with your own ... “I really believe this product’s going to be amazing,” and you don’t really check with anybody else, and you’re like, “This is going to be” ... That’s how the Segway kind of happened. The Segway kind of didn’t really turn into what the Segway guy thought it was going to be. It’s now a tours around Berlin type product. It’s not the future transportation.

Drew: On a practical level, what sort of format does The School of Design take? Do you know yet? Is that still up in the air?

Chris: Yeah. I literally have absolutely no idea. What I’m doing ... Well, two or three people I have to say are massive. First of all, the team on Propel have been amazing. Secondly, Ben. There’s a particular guy, Ben Allensi, on Propel who’s been really great. He’s young, he’s early 20s, and he has a startup. He really inspires me because he’s young and he’s got a lot of commitment and passion. Another guy, Mehall, as well, he’s 19, and he, with a friend, has made over 40 grand. He’s a first-year student at Ulster University, I’m amazed, and he’s making a product that connects to satellites for farmers. It’s incredible. Another friend, Al Parra, who’s been helping me with my website, which has been the slowest website build known to man or woman or any other gender. It’s been very, very slow, and that’s because I haven’t really been sure what I’m doing.

Chris: I think the biggest clue I got was signing up for Anne-Laure Le Cunff’s Ness Labs. Ness Labs is amazing. About two weeks ago, I got an email from Anne-Laure, who’s a friend of mine, saying, “Welcome to ... The course starts on Monday.” My immediate reaction was, “Have I signed up for a course that I can’t remember?” It wasn’t. It was more a case of if you’re a member of Ness Labs, you get access to these course. That, for me, was a real turning point because at that point, Drew, I realized that up until now I was selling workshops and with the workshop, you got access to a community. I then realized that what Anne-Laure was doing was selling a community that gave you access to workshops. That’s the same thing, but different. I think that that’s the biggest clue I have in terms of where I’m going.

Chris: It’s a community. It’s not a community you can join right now because I’m still working on it, and there is a very small community of around 30, 40 people who are on our Slack who are all helping each other, and they’re super, super early beta people. So it’s a community, and then my feeling is that if you’re in the community, you just get access to learning. The best way to explain it, if I pull up my Notion ... I have a library in Notion, which is free, and it’s library.theschoolofdesign.com, and it’s essentially everything I’ve learned and everything I’ve taught. But there is a book called Hello: A Practical Guide to Building an Email Newsletter That Works, and it’s part of the series of books that I envisage that I’ll be working on over the next year or so. There’s three ways to read the book, and I think this explains The School of Design.

Chris: Way number one is read it from first page to the last page in that order, right, just pick it up and read it. Way number two is just dip into it, okay, just read bits. Way number three is don’t read it. I realize that that sounds a little bit like, “What?” So I’ve written here, when I say don’t read it, I don’t mean ignore it. A lot of people just don’t have time to read at the minute. They’re too busy rushing around. So I’m going to be taking the books and the learning materials and saying, “Join me on Thursday evening at 7:00, and we will run through the contents of that book.” Then, if you want to go and read certain aspects and go into more depth, you just go and get that book, and it’s free, and it’s in the library, and you have access to it.

Chris: So what I see The School of Design being is a community of designers who know they need to know more, that they haven’t learned everything there is to know, and I think that I’m going to probably get into trouble by saying this, but I think that membership price is probably quite low. I think it’s something like 60 pounds a year or something. All my friends have told me that’s far too low. But I think that the community, it should be open to as many people as possible, and, to me, that’s more important than making money. Somehow or another, Drew, I have to earn enough money to pay my bills in order to just help as many people as I can. That is essentially my vision.

Chris: Essentially, my vision is that The School of Design is like a master’s course but it doesn’t cost what a master’s course would cost. Because if you went to do a master’s course in London or something, it would be 10,000 pounds. I think that in The School of Design, there probably are some courses that are more premium that you can do, but the majority of stuff is just being part of a community. I don’t know about you, but I think communities are going to be big as we move forward. I think that places like Smashing’s community and The School of Design community and Anne-Laure’s Ness Labs, people are hungry for that, especially in this world where we’re not really connected to people. So that, for me, is really exciting.

Drew: It is very exciting. You don’t refer to students as students, do you, in The School of Design? You have another term that you use.

Chris: Yeah, I was calling them founders because that was informed by the Propel program. Founders was the word I was using a while back. I’m not 100% sure if it’s still the right word because I’m not necessarily sure that everybody in The School of Design is a founder. I think that some of them want to build their own businesses, but some of them just want to do a better job of building businesses for other people. I’m torn at the minute, Drew. Last week, I was like, “It’s for people who want to build their own products,” and, yeah, it’s definitely for those people, but they might be a subset. That’s because I was having a conversation with somebody recently who works at Booking.com. I’m helping this particular person with some mentoring, and he doesn’t want to leave Booking.com. He’s very happy, but he knows that there are certain things that he wants to learn to enhance his current understanding, and he’s been out of art school for probably about eight or nine years. He just is at that point where he feels like there’s a few more things he’d like to learn but maybe doesn’t have 10 grand to go and do a master’s.

Drew: I guess it comes back, like you were saying, about Hiut calling their workers grandmasters, it highlights the importance of the choice of language in our products.

Chris: 100%. And I probably would still lean towards founders than students because, to me, students has so many connotations. Students, to me, is the wrong word. I know that. Also, I’ve written two books on language, The Craft of Words with Nicklas, my partner at the time. So we’ve got The Craft of Words, Part One, which is on macrocopy, and The Craft of Words, Part Two, which is on microcopy. We should put a link in in the show notes. But language is so important. How you choose to describe things affects how people perceive things. Language is another part of The School of Design.

Chris: One of the things that I’m doing at the minute is looking at the library, which has some rather ambiguous section titles, like Life First, Work Second, and I’m like, “God, that’s awful. Why don’t I just call it Process or something?” But there are sections in the library like Marketing, Branding. Pricing is another one. There are sections in the library that will still be there. Productivity is another one that I’m adding, in terms of how can you be mindful but be productive as well, and Mental Health or Mindfulness is another one because, to me, living a life intentionally and not just autopiloting through your life is important, and living a life with purpose is important as well. But maybe I’ve just got old and I started to realize these things.

Drew: Is the program focused on founders who are making digital products or the founder who’s ... Would they feel just as at home if they were making shoes?

Chris: Yeah, I think for me it’s products. I would remove digital because I was talking to Cara, my wife, about this yesterday. She’s a silversmith. For me, that distinction isn’t really there. So if we think back to when we were talking about Apple earlier in the conversation, there’s the service design aspect, there’s the physical product design aspect, there’s the software aspect, all of these things we need to know. I don’t think that one designer can do all of those things, but, for me, one of the things we used to start the master’s off with was this idea of a t-shaped person. Tim Brown from IDEO talks about this. You’re really good at a thing, but you understand the other things as well. So I think that the kinds of people who are joining The School of Design are t-shaped people. They’re really good at something, but they understand how to work with other people who are good at their thing, too.

Chris: We have a section of the library which I’m working on, I’m going to be launching next year, which is called Beacons, which are examples of companies that we can learn from. In my Notist decks, it’s noti.st, N-O-T-I, dot, S-T, slash, mrmurphy, there are a number of the beacons are in there. Hiut Denim is one. Field Notes is another. Ustwo Games is ... I’ve been talking to Mills at Ustwo Games, who’s super, super interesting, Mills, amazing. There’s a ... Blok Knives is another one, Benjamin Edmunds. What’s interesting to me is quite a lot of them are not digital products. They’re physical products. We can learn by just looking at all of the landscape of stuff, that consumers give you money in return for you to give them, as we’ve said earlier, solutions to their problems and joy. How do we as designers build those kinds of things? I think we’re good at doing solutions to your problems, sometimes we’re missing joy, and sometimes maybe we could a bit more work into just joy and no solutions to problems.

Chris: But we can learn as designers of products digitally from physical products as well. For me, if you look back to the Bauhaus at the turn of, well, not really at the turn of, but the beginnings of the 20th century, you have a lot of people, Walter Pierce, Johannes Itten, Walter Kandinsky, who are ... They don’t have ... They’re not like, “Oh, I” ... Mies van der Rohe is doing chairs, but he’s also designing buildings, and he’s also designing textiles. At no point, did anyone say, “Oh, no, mate, you can’t do that because you’re a chair guy.” If you look at Charles and Ray Eames, which is more than Charles Eames, it’s Ray Eames as well, and Ray always gets way overlooked, which I think is wrong, the Eames partnership were making films, they were designing chairs, they were ... These people, to me, are like mega-mega-beacons. So we can learn from Dieter Rams. We can learn from Charles and Ray Eames. We can learn from the Bauhaus. We can learn from the Ulm School. If I suppose the only way I can describe The School of Design is that it’s like a master’s education minus the master’s price tag, it’s basically all the stuff I used to teach on my master’s at Belfast School of Art but for a fraction of the price.

Drew: So you’re launching at the beginning of January?

Chris: First of January, yeah.

Drew: What does that launch look like?

Chris: On the first of December, I’m just going to start my blog properly at theschoolofdesign.com. And I’ve got a mailing list, which I’m going to start properly sending emails out and things like that. It’s been busy for me because I’ve been teaching for the last semester. But from the first of January, probably inviting more people into the Slack and then finding our way forwards, lots more customer conversations. What’s really important to me, Drew, is not opening the doors to all and sundry with something I haven’t thought through. I would’ve thought by now that I would’ve got it finished because I’ve spent the last year thinking about this, but it’s been through so many iterations that I’m still learning. What I would say is you can access the library right now, it’s at library.theschoolofdesign.com, and there’s a lot of stuff in there.

Chris: That, for me, is not going anywhere anytime soon. But I see some of those sections being turned into mini-lectures or workshops. It’s just like, “Do you feel like you need a shot of creative injection energy in your arm? Show up on Thursday evening at 6:00, and we’ll do a session on something this week, marketing or product storytelling or mental models.” I’m sure most designers, they don’t need to turn up to all of them to get their money’s worth. They just need to show up to a handful. The other thing I think we’ll probably be doing on the first of January is sharing the first season of speakers. We have this idea of seasons, like a Netflix type thing. So Mills from Ustwo has said he’ll do a talk for us. We’ve a few other interesting people who we’ve lined up.

Chris: That first season is called ... Oh my word, what is it called? I can’t remember. It’s something about the fact that the world has changed. It’s to do with what is tomorrow with COVID. Basically, we just get people to come and they ... They had a thing on Propel called Founder Firesides, which was amazing. I loved it because you would show up and someone would be beaming in from somewhere in the world and Chris, who is the person who ran Propel, would just ask them a bunch of questions and then we as people on the course could ask some questions, too. I don’t know if anyone in Smashing community knows Farnam Street. Farnam Street do something similar. They have monthly AMAs, and they get really interesting people. They ask the community if there’s anything you want to ask this person, what would you ask them? I just see there as being an opportunity to build a community of people who want to learn together.

Drew: It all sounds really exciting, and I look forward to following it as it all happens and seeing what comes of it. It sounds like a great opportunity for those who wish to continue their design education or maybe start their design education.

Chris: Well, start as well. Start as well. There’s an awful lot of people that I’ve been teaching on Propel over the last couple of years who maybe when they started did not really know much about design. By the time I’d finished with them, you’re running a few sessions, they were picking up pens, they were sketching interfaces, they were a bit more design-aware. I think we all need to be design-aware as we move forward. We’ve talked about a lot of it just now, which is great. Awesome.

Drew: I’ve been learning all about product design. What have you been learning about lately, Chris?

Chris: What I’ve been learning about is Facebook advertising. Facebook gets a really bad rap, but I have this idea in the venture testing module, which is what I call traffic beating. It’s terrible. I’m going to pull it up here because I can read it off here. So you’ve built your smoke test page, okay? You’ve got your product described. What I’ve written here in beating traffic, “If you’re unfamiliar with the world of grouse shooting, the idea of beating might be new to you. Here’s a description from the National Organization of Beaters. A beater flushes birds, pheasants or grouse, from cover, driving them in the direction of the guns. In this peculiarly British metaphor, the birds are your customers, and the guns are your smoke test page.” I’m really interested in how do we get people to see the page that we’ve built to describe the product, how do we find the right people, and how do we get them pushed over to here?

Chris: Facebook is one way, but Reddit ads and Google ads ... I think that designers moving forward need to have some of the skills that startup founders have, which is startup founders are trying to achieve a lot on usually not very much money, certainly, the model of startup thinking we have on this side of the Atlantic. In the San Francisco, Silicon Valley kind of world, it’s like, “Don’t worry about customers. Here’s 100 billion dollars, and good luck.” That’s a completely crazy way of running a startup if you’re in the UK. If you’re in the UK or somewhere that’s not Silicon Valley, it’s like you build things, you try them. If people are interested, you do more of it. If they’re not, you move onto the next thing. So that’s what I’ve been learning about. It’s like how do I get more people to see the things that I’m testing?

Drew: If you, dear listener, would like to hear more from Chris, you can follow him on Twitter, where he’s @fehler, that’s F-E-H-L-E-R, and you can find The School of Design online at theschoolofdesign.com. Thanks for joining us today, Chris. Did you have any parting words?

Chris: Yeah, my parting words would be just start. If you have an idea, just start, right? Don’t build it in your head and make it really, really complicated. Until this year, I used to do that. I used to think, “Oh” ... if you look at my Tiny Books, which was my previous thing, tinybooks.com, it was so big in my head. There was going to be a book about this, a book about something else, a book about this, and then there was going to be a smaller book about this and even smaller book called a Comet about something else. I had this huge solar system in my head, and the one thing I did this year was embrace an everything is a prototype mentality. Everything I am doing is a prototype. So if something works, great. What did I learn from it? If something doesn’t work, great. I still learned something from it.

Chris: My advice, my parting words, would be if you have an amazing idea, just start because I’ve met so many people in the last 30-something years who have an amazing idea and when I say, “Can I see the homepage or do you have anything done,” it’s still in their sketchbook. I’d rather see it out there on the web or somewhere. So start, one word, simple.

Creating Tiny Desktop Apps With Tauri And Vue.js

Creating Tiny Desktop Apps With Tauri And Vue.js

Creating Tiny Desktop Apps With Tauri And Vue.js

Kelvin Omereshone

Technology makes our lives better, not just users, but also creators (developers and designers). In this article, I’ll introduce you to Tauri. This article will be useful to you if:

  • you have been building applications on the web with HTML, CSS, and JavaScript, and you want to use the same technologies to create apps targeted at Windows, macOS, or Linux platforms;
  • you are already building cross-platform desktop apps with technologies like Electron, and you want to check out alternatives;
  • you want to build apps with web technologies for Linux distributions, such as PureOS;
  • you are a Rust enthusiast, and you’d like to apply it to build native cross-platform applications.

We will look at how to build a native cross-platform application from an existing web project. Let’s get to it!

Note: This article assumes you are comfortable with HTML, CSS, JavaScript, and Vue.js.

What Is Tauri?

The official website sums up Tauri well:

  • Tauri is a polyglot toolchain for building more secure native apps with both tiny and fast binaries. By “polyglot”, I mean that Tauri uses multiple programming languages. At the moment, Rust, JavaScript, and TypeScript are used. But there are plans to let you use Go, C++, Python, and more.
  • It lets you use any HTML and JavaScript-based front-end framework, such as Vue.js, React, or Angular, to build a native desktop app, and it can be integrated into any pipeline.
  • It helps you build and bundle binaries for major desktop platforms (mobile and WebAssembly coming soon).

So, basically, Tauri allows you to use web technologies to create tiny and secure native desktop apps.

On its GitHub page, Tauri is described as a framework-agnostic toolchain for building highly secure native apps that have tiny binaries (i.e. file size) and that are very fast (i.e. minimal RAM usage).

Why Not Electron?

A popular tool for using web technologies to build desktop applications is Electron.

However, Electron apps have a rather large bundle size, and they tend to take up a lot of memory when running. Here is how Tauri compares to Electron:

  • Bundle
    The size of a Tauri app can be less than 600 KB.
  • Memory
    The footprint of a Tauri app is less than half the size of an Electron app.
  • Licence
    Relicensing is possible with Tauri, but not with Electron. Electron ships with Chromium right out of the box. However, Chromium includes a digital rights-management system named Widevine. The inclusion of Widevine in Chromium makes apps created with Electron frowned upon by users of platforms such as PureOS for the sole reason that it is not free/libre open-source software (FLOSS). Platforms like PureOS are verified by the Free Software Foundation (FSF). This means that they can only publish free and open-source software in their app stores.

In a nutshell, if your app is built with Electron, it will never be shipped officially in the PureOS store. This should be a concern for developers targeting such distributions.

More Features Of Tauri

  • Security is really important to the Tauri team. Apps created with Tauri are meant to be secure from the get-go.
  • Tauri is compatible with any front-end framework, so you don’t have to change your stack.
  • It has many design patterns to help you choose important features with simple configurations.

Pros Of Tauri

  • Tauri enables you to take the code base you’ve built for the web and turn it into a native desktop app, without changing a thing.
  • Although you could use Rust in a Tauri-based project, it is completely optional. If you did, you wouldn’t need to change anything in your original code base targeted for the web.

Real-World Tauri

If you have been part of the Vue.js community for a while, then you’ll have heard of Guillaume Chau, a member of the core team of Vue.js. He is responsible for the Vue.js command-line interface (CLI), as well as other awesome Vue.js libraries. He recently created guijs, which stands for “graphical user interface for JavaScript projects”. It is a Tauri-powered native desktop app to visually manage your JavaScript projects.

Guijs is an example of what is possible with Tauri, and the fact that a core member of the Vue.js team works on the app tells us that Tauri plays nicely with Vue.js (amongst other front-end frameworks). Check out the guijs repository on GitHub if you are interested. And, yes, it is open-source.

How Tauri Works

At a high level, Tauri uses Node.js to scaffold an HTML, CSS, and JavaScript rendering window as a user interface (UI), managed and bootstrapped by Rust. The product is a monolithic binary that can be distributed as common file types for Linux (deb/appimage), macOS (app/dmg), and Windows (exe/msi).

How Tauri Apps Are Made

A Tauri app is created via the following steps:

  1. First, make an interface in your GUI framework, and prepare the HTML, CSS, and JavaScript for consumption.
  2. The Tauri Node.js CLI takes it and rigs the Rust runner according to your configuration.
  3. In development mode, it creates a WebView window, with debugging and Hot Module Reloading.
  4. In build mode, it rigs the bundler and creates a final application according to your settings.

Setting Up Your Environment

Now that you know what Tauri is and how it works, let me walk you through setting up your machine for development with Tauri.

Note: The setup here is for Linux machines, but guides for macOS and for Windows are also available.

Linux Setup

The polyglot nature of Tauri means that it requires a number of tool dependencies. Let’s kick it off by installing some of the dependencies. Run the following:

$ sudo apt update && sudo apt install libwebkit2gtk-4.0-dev build-essential curl libssl-dev appmenu-gtk3-module

Once the above is successful, proceed to install Node.js (if you don’t already have it), because Tauri requires its runtime. You can do so by running this:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash

This will install nvm (Node.js version manager), which allows you to easily manage the Node.js runtime and easily switch between versions of Node.js. After it is installed, run this to see a list of Node.js versions:

nvm ls-remote

At the time of writing, the most recent version is 14.1.0. Install it like so:

nvm install v14.1.0

Once Node.js is fully set up, you would need to install the Rust compiler and the Rust package manager: Cargo. The command below would install both:

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After running this command, make sure that Cargo and Rust are in your $PATH by running the following:

rust --version

If everything has gone well, this should return a version number.

According to the Tauri documentation, make sure you are on the latest version by running the following command:

$ rustup update stable

Voilà! You are one step closer to getting your machine 100% ready for Tauri. All that’s left now is to install the tauri-bundler crate. It’s best to quit your CLI, and run the command below in a new CLI window:

$ cargo install tauri-bundler --force

Eureka! If everything went all right, your machine is now ready for Tauri. Next up, we will get started integrating Tauri with Vue.js. Let’s get to it!

Yarn

The Tauri team recommends installing the Yarn package manager. So let’s install it this way:

npm install -g yarn

Then run the following:

yarn --version

If everything worked, a version number should have been returned.

Integrating Tauri With Vue.js

Now that we have Tauri installed, let’s bundle an existing web project. You can find the live demo of the project on Netlify. Go ahead and fork the repository, which will serve as a shell. After forking it, make sure to clone the fork by running this:

git clone https://github.com/[yourUserName]/nota-web

After cloning the project, run the following to install the dependencies:

yarn

Then, run this:

yarn serve

Your application should be running on localhost:8080. Kill the running server, and let’s install the Vue.js CLI plugin for Tauri.

vue-cli-plugin-tauri

The Tauri team created a Vue.js CLI plugin that quickly rigs and turns your Vue.js single-page application (SPA) into a tiny cross-platform desktop app that is both fast and secure. Let’s install that plugin:

vue add tauri

After the plugin is installed, which might take a while, it will ask you for a window title. Just type in nota and press “Enter”.

Let’s examine the changes introduced by the Tauri plugin.

package.json

The Tauri plugin added two scripts in the scripts section of our package.json file. They are:

"tauri:build": "vue-cli-service tauri:build",
"tauri:serve": "vue-cli-service tauri:serve"

The tauri:serve script should be used during development. So let’s run it:

yarn tauri:serve

The above would download the Rust crates needed to start our app. After that, it will launch our app in development mode, where it will create a WebView window, with debugging and Hot Module Reloading!

src-tauri

You will also notice that the plugin added a src-tauri directory to the root of your app directory. Inside this directory are files and folders used by Tauri to configure your desktop app. Let’s check out the contents:

icons/
src/
    build.rs
    cmd.rs
    main.rs
Cargo.lock
Cargo.toml
rustfmt.toml
tauri.conf.json
tauri.js

The only change we would need to make is in src-tauri/Cargo.toml. Cargo.toml is like the package.json file for Rust. Find the line below in Cargo.toml:

name = "app"

Change it to this:

name = "nota"

That’s all we need to change for this example!

Bundling

To bundle nota for your current platform, simply run this:

yarn tauri:build

Note: As with the development window, the first time you run this, it will take some time to collect the Rust crates and build everything. On subsequent runs, it will only need to rebuild the Tauri crates themselves.

When the above is completed, you should have a binary of nota for your current OS. For me, I have a .deb binary created in the src-tauri/target/release/bundle/deb/ directory.*

Going Cross-Platform

You probably noticed that the yarn tauri:build command just generated a binary for your operating system. So, let’s generate the binaries for other operating systems. To achieve this, we will set up a workflow on GitHub. We are using GitHub here to serve as a distribution medium for our cross-platform app. So, your users could just download the binaries in the “Release” tab of the project. The workflow we would implement would automatically build our binaries for us via the power of GitHub actions. Let’s get to it.

Creating The Tauri Workflow

Thanks to Jacob Bolda, we have a workflow to automatically create and release cross-platform apps with Tauri on GitHub. Apart from building the binary for the various platforms (Linux, Mac, and Windows), the action would also upload the binary for you as a release on GitHub. It also uses the Create a Release action made by Jacob to achieve this.

To use this workflow, create a .github directory in the root of nota-web. In this directory, create another directory named workflows. We would then create a workflow file in .github/workflows/, and name it release-tauri-app.yml.

In release-tauri-app.yml, we would add a workflow that builds the binaries for Linux, macOS, and Windows. This workflow would also upload the binaries as a draft release on GitHub. The workflow would be triggered whenever we push to the master.

Open release-tauri-app.yml, and add the snippet below:

name: release-tauri-app

on:
  push:
    branches:
      - master
    paths:
      - '**/package.json'

jobs:
  check-build:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      — uses: actions/checkout@v2
      — name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: 12
      — name: install rust stable
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
      — name: install webkit2gtk
        run: |
          sudo apt-get update
          sudo apt-get install -y webkit2gtk-4.0
      — run: yarn
      — name: build nota for tauri app
        run: yarn build
      — run: cargo install tauri-bundler --force
      — name: build tauri app
        run: yarn tauri:build

  create-release:
    needs: check-build
    runs-on: ubuntu-latest
    outputs:
      RELEASE_UPLOAD_URL: ${{ steps.create_tauri_release.outputs.upload_url }}

    steps:
      — uses: actions/checkout@v2
      — name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: 12
      — name: get version
        run: echo ::set-env name=PACKAGE_VERSION::$(node -p "require('./package.json').version")
      — name: create release
        id: create_tauri_release
        uses: jbolda/create-release@v1.1.0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ matrix.package.name }}-v${{ env.PACKAGE_VERSION }}
          release_name: 'Release nota app v${{ env.PACKAGE_VERSION }}'
          body: 'See the assets to download this version and install.'
          draft: true
          prerelease: false

  create-and-upload-assets:
    needs: create-release
    runs-on: ${{ matrix.platform }}
    timeout-minutes: 30

    strategy:
      fail-fast: false
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]
        include:
          — platform: ubuntu-latest
            buildFolder: bundle/deb
            ext: \_0.1.0_amd64.deb
            compressed: ''
          — platform: macos-latest
            buildFolder: bundle/osx
            ext: .app
            compressed: .tgz
          — platform: windows-latest
            buildFolder: ''
            ext: .x64.msi
            compressed: ''

    steps:
      — uses: actions/checkout@v2
      — name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: 12
      — name: install rust stable
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
      — name: install webkit2gtk (ubuntu only)
        if: matrix.platform == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install -y webkit2gtk-4.0
      — run: yarn
      — name: build nota for tauri app
        run: yarn build
      — run: cargo install tauri-bundler --force
      — name: build tauri app
        run: yarn tauri:build
      — name: compress (macos only)
        if: matrix.platform == 'macos-latest'
        working-directory: ${{ format('./src-tauri/target/release/{0}', matrix.buildFolder ) }}
        run: tar -czf ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }} ${{ format('nota{0}', matrix.ext ) }}
      — name: upload release asset
        id: upload-release-asset
        uses: actions/upload-release-asset@v1.0.2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ needs.create-release.outputs.RELEASE_UPLOAD_URL }}
          asset_path: ${{ format('./src-tauri/target/release/{0}/nota{1}{2}', matrix.buildFolder, matrix.ext, matrix.compressed ) }}
          asset_name: ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }}
          asset_content_type: application/zip
      — name: build tauri app in debug mode
        run: yarn tauri:build --debug
      — name: compress (macos only)
        if: matrix.platform == 'macos-latest'
        working-directory: ${{ format('./src-tauri/target/debug/{0}', matrix.buildFolder ) }}
        run: tar -czf ${{ format('nota{0}{1}', matrix.ext, matrix.compressed ) }} ${{ format('nota{0}', matrix.ext ) }}
      — name: upload release asset with debug mode on
        id: upload-release-asset-debug-mode
        uses: actions/upload-release-asset@v1.0.2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ needs.create-release.outputs.RELEASE_UPLOAD_URL }}
          asset_path: ${{ format('./src-tauri/target/debug/{0}/nota{1}{2}', matrix.buildFolder, matrix.ext, matrix.compressed ) }}
          asset_name: ${{ format('nota-debug{0}{1}', matrix.ext, matrix.compressed ) }}
          asset_content_type: application/zip

To test the workflow, commit and push your changes to your fork’s master branch. After successfully pushing to GitHub, you can then click on the “Actions” tab in GitHub, then click on the “Check build” link to see the progress of the workflow.

Upon successful execution of the action, you can see the draft release in “Releases” on the repository page on GitHub. You can then go on to publish your release!

Conclusion

This article has introduced a polyglot toolchain for building secure, cross-platform, and tiny native applications. We’ve seen what Tauri is and how to incorporate it with Vue.js. Lastly, we bundled our first Tauri app by running yarn tauri:build, and we also used a GitHub action to create binaries for Linux, macOS, and Windows.

Let me know what you think of Tauri — I’d be excited to see what you build with it. You can join the Discord server if you have any questions.

The repository for this article is on GitHub. Also, see the binaries generated by the GitHub workflow.

Smashing Editorial (ra, il, al)

Mirage JS Deep Dive: Understanding Timing, Response And Passthrough (Part 3)

Mirage JS Deep Dive: Understanding Timing, Response And Passthrough (Part 3)

Mirage JS Deep Dive: Understanding Timing, Response And Passthrough (Part 3)

Kelvin Omereshone

Mirage JS was built to give frontend developers the ability to simulate actual backend API calls. So far, we have seen how we can create records with Mirage, intercept API requests via route handlers and, last but not least, how the shape of the data returned to us from Mirage is affected.

In this part of the series, we will see Mirage mechanism for simulating other aspects of an actual backend server like slow network, HTTP status code response, and also making requests to an actual backend even though Mirage is intercepting your frontend requests.

Let’s begin by simulating slow network requests.

Timing

When developing your frontend application that relies on a backend API, it’s useful to see how your application behaves under slow networks (think about testing loading messages and loaders). This test is important because requests to backend API are asynchronous in nature. What this means is that we can’t make assumptions about when we will get the response so we need to write our code as if it might come immediately, or there might be a delay.

A common reason for a delay in response is a slow Internet connection. It is then really important to know how your app would behave in such circumstances. Mirage caters to this need by making available a timing option which is a property passed to a route handler that tells the handler to wait for a particular duration specified by the timing option (in milliseconds) before returning a response whenever the route it is handling is called.

Note: By default, Mirage is setting a 400ms delay for the server during development and 0 during testing so your tests can run faster (no one really enjoys slow tests).

We now know in theory how to customize Mirage’s server response time. Let’s see a couple of ways to tweak that response time via the timing option.

timing On routes()

As earlier stated, Mirage sets a default delay for the server response time to be 400ms during development and 0 for tests. You could override this default on the routes method on the Server instance.

In the example below, I am setting the timing option to 1000ms in the routes method to artificially set the response delay for all routes:

import { Server } from 'miragejs'

new Server({
    routes() {
        this.routes = 1000
    }
})

The above tells Mirage to wait for 1000 milliseconds before returning a response. So if your front-end make a request to a route handler like the one below:

this.get('/users', (schema) => {
    return schema.users.all();
});

Mirage will take 1000 milliseconds to respond.

Tip: Instead of directly using the schema object, you could use ES 6 object restructuring to make your route handler cleaner and shorter like below:

this.get('/users', ({ users }) => {
    return users.all()
}

timing For Individual Routes

Although the this.timing property is useful, in some scenarios you wouldn’t want to delay all your routes. Because of this scenario, Mirage gives you the ability to set the timing option in a config options object you could pass at the end of a route handler. Taking our above code snippets, let’s pass the 1000ms response delay to the route itself as opposed to globally setting it:

this.get('/users', ({ users }) => {
  return users.all();
 }, { timing: 1000 });

The result is the same as globally assigning the timing. But now you have the ability to specify different timing delays for individual routes. You could also set a global timing with this.timing and then override it in a route handler. Like so:

this.timing = 1000

this.get('users', ( { users } ) => {
    return users.all()
})

this.get('/users/:id', ({ users }, request) => {
    let { id } = request.params;
     return users.find(id);
 }, { timing: 500 });

So now when we make a request to /users/1, it will return the below user JSON in half of the time (500ms) it would take for every other route.

{
  "user": {
    "name": "Kelvin Omereshone",
    "age": 23,
    "id": "1"
  }
}

Passthrough

Route handlers are the Mirage mechanism for intercepting requests your frontend application makes. By default, Mirage will throw an error similar to the one below when your app makes a request to an endpoint that you haven’t defined a Route handler for in your server instance.

Error: Mirage: Your app tried to GET '/unknown', but there was no route defined to handle this request. Define a route for this endpoint in your routes() config. Did you forget to define a namespace?

You can, however, tell Mirage that if it sees a request to a route that you didn’t define a route handler for, it should allow that request to go through. This is useful if you have an actual backend and you want to use Mirage to test out endpoints that haven’t been implemented yet in your backend. To do this, you would need to make a call to the passthrough method inside the routes methods in your Mirage server instance.

Let’s see it in code:

import { Server } from 'miragejs'

new Server({
    routes() {
        // you can define your route handlers above the passthrough call
        this.passthrough()
    }
})

Note: It is recommended keeping the call to passthrough at the bottom in order to give your route handlers precedence.

Now when Mirage sees requests to a route that you didn’t define in Mirage, it would let them “passthrough”. I really find this useful because it makes Mirage play nicely with an actual backend. So a scenario would be, you are ahead of your backend team and you want to make a request to an endpoint that you don’t have in your production backend, you could just mock out that endpoint in mirage and because of the passthrough option, you wouldn’t need to worry about other parts of your app making requests failing.

Using passthrough To Whitelist Route

passthrough takes in options to allow you to have more control over routes you want to whitelist. So as opposed to calling passthrough without any option and allowing routes not present in mirage to passthrough, you can pass in one or more strings of the routes you want to whitelist to passthrough. So if we want to whitelist /reviews and /pets we can do that using passthrough like so:

this.passthrough('/reviews', '/pets)

You can also do multiple calls to passthrough:

this.passthrough('/reviews')
this.passthrough('/pets')

Note: I find passing multiple route strings to passthrough cleaner as opposed to making multiple calls. But you are free to use whatever feels natural to you.

Using passthrough On A Set Of HTTP Verbs

The above passthrough we defined will allow all HTTP verbs (GET, POST, PATCH, DELETE) to passthrough. If your use case requires you to allow a subset of the HTTP verbs to passthrough, Mirage provides an options array on the passthrough method wherein you pass the verbs you want Mirage to whitelist on a particular route. Let’s see it in code:

// this allows post requests to the /reviews route to passthrough
this.passthrough('/reviews', ['post']);

You could also pass multiple strings of routes as well as the HTTP verbs array like so:

// this allows post and patch requests to /reviews and /pets routes to passthrough

this.passthrough('/pets', 'reviews', ['post', 'patch'])

Response

Now you see the level of customization Mirage gives you with both the timing option and passthrough method, it feels only natural for you to know how to customize the HTTP status code Mirage sends for the requests you make. By default, Mirage would return a status of 200 which says everything went fine. (Check out this article for a refresher on HTTP status code.) Mirage, however, provides the Response class which you can use to customize the HTTP status code as well as other HTTP headers to be sent back to your frontend application.

The Response class gives you more control over your route handler. You can pass in the following to the Response class constructor:

  • The HTTP status code,
  • HTTP Headers,
  • Data (a JSON payload to be returned to the frontend).

To see how the Response class works, we would start on an easy note by rewriting our previous route handler using the Response class. So we would take the below route handler:

this.get('users', ( { users } ) => {
return users.all()
})

and then reimplement using the Response class. To do this we first need to import the Response class from Mirage:

import { Response } from 'miragejs'

We would then rewrite our route handler using the Response class:

this.get('/users', ({ users }) => {
    return new Response(200, {}, users.all());
});

Note: We are passing an empty {} to the header argument because we are do not want to set any header values for this response.

I believe we can infer that Mirage under the hood uses the Response class when we previously returned users.all() because both implementations would act the same way and return the same JSON payload.

I will admit the above use of Response is a little bit verbose because we are not doing anything special yet. However, the Response class holds a world of possibility to allows you to simulate different server states and set headers.

Setting Server States

With the Response class, you can now simulate different server states via the status code which is the first argument the Response constructor takes. You can now pass in 400 to simulate a bad request, 201 to simulate the created state when you create a new resource in Mirage, and so on. With that in mind, let’s customize /users/:id route handler and pass in 404 to simulate that a user with the particular ID was not found.

this.get('/users/:id', (schema, request) => {
   let { id } = request.params;
   return new Response(404, {}, { error: 'User with id ${id} not found'});
});

Mirage would then return a 404 status code with the error message similar to the below JSON payload:

{
  "error": "User with id 5 not found"
}

Setting Headers

With the Response class, you can set response headers by passing an object as the second argument to the Response constructor. With this flexibility, you can simulate setting any headers you want. Still using our /users/:id route, we can set headers like so:

this.get('/users/:id', (schema, request) => {
     let { id } = request.params;
     return new Response(404, {"Content-Type" : "application/json", author: 'Kelvin Omereshone' }, { error: `User with id ${id} not found`});
});

Now when you check Mirage logs in your browser console, you would see the headers we set.

Wrapping Up

In this part of the Mirage JS Deep Dive series, I have expounded three mechanisms that Mirage exposes to its users in order to simulate a real server. I look forward to seeing you use Mirage better with the help of this article.

Stay tuned for the next and final part of the series coming up next week!

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

Understanding Machines: An Open Standard For JavaScript Functions

Understanding Machines: An Open Standard For JavaScript Functions

Understanding Machines: An Open Standard For JavaScript Functions

Kelvin Omereshone

As developers, we always seek ways to do our job better, whether by following patterns, using well-written libraries and frameworks, or what have you. In this article, I’ll share with you a JavaScript specification for easily consumable functions. This article is intended for JavaScript developers, and you’ll learn how to write JavaScript functions with a universal API that makes it easy for those functions to be consumed. This would be particularly helpful for authoring npm packages (as we will see by the end of this article).

There is no special prerequisite for this article. If you can write a JavaScript function, then you’ll be able to follow along. With all that said, let’s dive in.

What Are Machines?

Machines are self-documenting and predictable JavaScript functions that follow the machine specification, written by Mike McNeil. A machine is characterized by the following:

  • It must have one clear purpose, whether it’s to send an email, issue a JSON Web Token, make a fetch request, etc.
  • It must follow the specification, which makes machines predictable for consumption via npm installations.

As an example, here is a collection of machines that provides simple and consistent APIs for working with Cloudinary. This collection exposes functions (machines) for uploading images, deleting images, and more. That’s all that machines are really: They just expose a simple and consistent API for working with JavaScript and Node.js functions.

Features of Machines

  • Machines are self-documenting. This means you can just look at a machine and knows what it’s doing and what it will run (the parameters). This feature really sold me on them. All machines are self-documenting, making them predictable.
  • Machines are quick to implement, as we will see. Using the machinepack tool for the command-line interface (CLI), we can quickly scaffold a machine and publish it to npm.
  • Machines are easy to debug. This is also because every machine has a standardized API. We can easily debug machines because they are predictable.

Are There Machines Out There?

You might be thinking, “If machines are so good, then why haven’t I heard about them until now?” In fact, they are already widely used. If you’ve used the Node.js MVC framework Sails.js, then you have either written a machine or interfaced with a couple. The author of Sails.js is also the author of the machine specification.

In addition to the Sails.js framework, you could browse available machines on npm by searching for machinepack, or head over to http://node-machine.org/machinepacks, which is machinepack’s registry daemon; it syncs with npm and updates every 10 minutes.

Machines are universal. As a package consumer, you will know what to expect. So, no more trying to guess the API of a particular package you’ve installed. If it’s a machine, then you can expect it to follow the same easy-to-use interface.

Now that we have a handle on what machines are, let’s look into the specification by analyzing a sample machine.

The Machine Specification

    module.exports = {
  friendlyName: 'Do something',
  description: 'Do something with the provided inputs that results in one of the exit scenarios.',
  extendedDescription: 'This optional extended description can be used to communicate caveats, technical notes, or any other sort of additional information which might be helpful for users of this machine.',
  moreInfoUrl: 'https://stripe.com/docs/api#list_cards',
  sideEffects: 'cacheable',
  sync: true,

  inputs: {
    brand: {
      friendlyName: 'Some input',
      description: 'The brand of gummy worms.',
      extendedDescription: 'The provided value will be matched against all known gummy worm brands. The match is case-insensitive, and tolerant of typos within Levenstein edit distance <= 2 (if ambiguous, prefers whichever brand comes first alphabetically).',
      moreInfoUrl: 'http://gummy-worms.org/common-brands?countries=all',
      required: true,
      example: 'haribo',
      whereToGet: {
        url: 'http://gummy-worms.org/how-to-check-your-brand',
        description: 'Look at the giant branding on the front of the package. Copy and paste with your brain.',
        extendedDescription: 'If you don\'t have a package of gummy worms handy, this probably isn\'t the machine for you. Check out the `order()` machine in this pack.'
      }
    }
  },

  exits: {
    success: {
      outputFriendlyName: 'Protein (g)',
      outputDescription: 'The grams of gelatin-based protein in a 1kg serving.',
    },
    unrecognizedFlavors: {
      description: 'Could not recognize one or more of the provided `flavorStrings`.',
      extendedDescription: 'Some **markdown**.',
      moreInfoUrl: 'http://gummyworms.com/flavors',
    }
  },

  fn: function(inputs, exits) {
    // ...
    // your code here
    var result = 'foo';
    // ...
    // ...and when you're done:
    return exits.success(result);
  };
}

The snippet above is taken from the interactive example on the official website. Let’s dissect this machine.

From looking at the snippet above, we can see that a machine is an exported object containing certain standardized properties and a single function. Let’s first see what those properties are and why they are that way.

  • friendlyName
    This is a display name for the machine, and it follows these rules:
    • is sentence-case (like a normal sentence),
    • must not have ending punctuation,
    • must be fewer than 50 characters.
  • description
    This should be a clear one-sentence description in the imperative mood (i.e. the authoritative voice) of what the machine does. An example would be “Issue a JSON Web Token”, rather than “Issues a JSON Web Token”. Its only constraint is:
    • It should be fewer than 80 characters.
  • extendedDescription (optional)
    This property provides optional supplemental information, extending what was already said in the description property. In this field, you may use punctuation and complete sentences.
    • It should be fewer than 2000 characters.
  • moreInfoUrl (optional)
    This field contains a URL in which additional information about the inner workings or functionality of the machine can be found. This is particularly helpful for machines that communicate with third-party APIs such as GitHub and Auth0.
  • sideEffects (optional)
    This is an optional field that you can either omit or set as cacheable or idempotent. If set to cacheable, then .cache() can be used with this machine. Note that only machines that do not have sideEffects should be set to cacheable.
  • sync (optional)
    Machines are asynchronous by default. Setting the sync option to true turns off async for that machine, and you can then use it as a regular function (without async/await, or then()).

inputs

This is the specification or declaration of the values that the machine function expects. Let’s look at the different fields of a machine’s input.

  • brand
    Using the machine snippet above as our guide, the brand field is called the input key. It is normally camel-cased, and it must be an alphanumeric string starting with a lowercase letter.
    • No special characters are allowed in an input key identifier or field.
  • friendlyName
    This is a human-readable display name for the input. It should:
    • be sentence-case,
    • have no ending punctuation,
    • be fewer than 50 characters.
  • description
    This is a short description describing the input’s use.
  • extendedDescription
    Just like the extendedDescription field on the machine itself, this field provides supplemental information about this particular input.
  • moreInfoUrl
    This is an optional URL that provides more information about the input, if needed.
  • required
    By default, every input is optional. What that means is that if, by runtime, no value is provided for an input, then the fn would be undefined. If your inputs are not optional, then it’s best to set this field as true because this would make the machine throw an error.
  • example
    This field is used to determined the expected data type of the input.
  • whereToGet
    This is an optional documentation object that provides additional information on how to locate adequate values for this input. This is particularly useful for things like API keys, tokens, and so on.
  • whereToGet.description
    This is a clear one-sentence description, also in the imperative mood, that describes how to find the right value for this input.
  • extendedDescription
    This provides additional information on where to get a suitable input value for this machine.

exits

This is the specification for all possible exit callbacks that this machine’s fn implementation can trigger. This implies that each exit represents one possible outcome of the machine’s execution.

  • success
    This is the standardized exit key in the machine specification that signifies that everything went well and the machine worked without any errors. Let’s look at the properties it could expose:
    • outputFriendlyName
      This is simply a display name for the exit output.
    • outputDescription
      This short noun phrase describes the output of an exit.

Other exits signify that something went wrong and that the machine encountered an error. The naming convention for such exits should follow the naming convention for the input’s key. Let’s see the fields under such exits:

  • description
    This is a short description describing when the exit would be called.
  • extendedDescription
    This provides additional information about when this exit would be called. It’s optional. You may use full Markdown syntax in this field, and as usual, it should be fewer than 2000 characters.

You Made It!

That was a lot to take in. But don’t worry: When you start authoring machines, these conventions will stick, especially after your first machine, which we will write together shortly. But first…

Machinepacks

When authoring machines, machinepacks are what you publish on npm. They are simply sets of related utilities for performing common, repetitive development tasks with Node.js. So let’s say you have a machinepack that works with arrays; it would be a bundle of machines that works on arrays, like concat(), map(), etc. See the Arrays machinepack in the registry to get a full view.

Machinepacks Naming Convention

All machinepacks must follow the standard of having “machinepack-” as a prefix, followed by the name of the machine. For example, machinepack-array, machinepack-sessionauth.

Our First Machinepack

To better understand machines, we will write and publish a machinepack that is a wrapper for the file-contributors npm package.

Getting Started

We require the following to craft our machinepack:

  1. Machinepack CLI tool
    You can get it by running:
    npm install -g machinepack
    
  2. Yeoman scaffolding tool
    Install it globally by running:
     npm install -g yo
    
  3. Machinepack Yeomen generator
    Install it like so:
    npm install -g generator-machinepack
    

Note: I am assuming that Node.js and npm are already installed on your machine.

Generating Your First Machinepack

Using the CLI tools that we installed above, let’s generate a new machinepack using the machinepack generator. Do this by first going into the directory that you want the generator to generate the files in, and then run the following:

yo machinepack

The command above will start an interactive process of generating a barebones machinepack for you. It will ask you a couple of questions; be sure to say yes to it creating an example machine.

Note: I noticed that the Yeoman generator has some issues when using Node.js 12 or 13. So, I recommend using nvm, and install Node.js 10.x, which is the environment that worked for me.

If everything has gone as planned, then we would have generated the base layer of our machinepack. Let’s take a peek:

DELETE_THIS_FILE.md
machines/
package.json
package.lock.json
README.md
index.js
node_modules/

The above are the files generated for you. Let’s play with our example machine, found inside the machines directory. Because we have the machinepack CLI tool installed, we could run the following:

machinepack ls

This would list the available machines in our machines directory. Currently, there is one, the say-hello machine. Let’s find out what say-hello does by running this:

machinepack exec say-hello

This will prompt you for a name to enter, and it will print the output of the say-hello machine.

As you’ll notice, the CLI tool is leveraging the standardization of machines to get the machine’s description and functionality. Pretty neat!

Let’s Make A Machine

Let’s add our own machine, which will wrap the file-contributors and node-fetch packages (we will also need to install those with npm). So, run this:

npm install file-contributors node-fetch --save

Then, add a new machine by running:

machinepack add

You will be prompted to fill in the friendly name, the description (optional), and the extended description (also optional) for the machine. After that, you will have successfully generated your machine.

Now, let’s flesh out the functionality of this machine. Open the new machine that you generated in your editor. Then, require the file-contributors package, like so:

const fetch = require('node-fetch');
const getFileContributors = require('file-contributors').default;

global.fetch = fetch; // workaround since file-contributors uses windows.fetch() internally

Note: We are using node-fetch package and the global.fetch = fetch workaround because the file-contributors package uses windows.fetch() internally, which is not available in Node.js.

The file-contributors’ getFileContributors requires three parameters to work: owner (the owner of the repository), repo (the repository), and path (the path to the file). So, if you’ve been following along, then you’ll know that these would go in our inputs key. Let’s add these now:

...
 inputs: {
    owner: {
      friendlyName: 'Owner',
      description: 'The owner of the repository',
      required: true,
      example: 'DominusKelvin'
    },
    repo: {
      friendlyName: 'Repository',
      description: 'The Github repository',
      required: true,
      example: 'machinepack-filecontributors'
    },
    path: {
      friendlyName: 'Path',
      description: 'The relative path to the file',
      required: true,
      example: 'README.md'
    }
  },
...

Now, let’s add the exits. Originally, the CLI added a success exit for us. We would modify this and then add another exit in case things don’t go as planned.

exits: {

    success: {
      outputFriendlyName: 'File Contributors',
      outputDescription: 'An array of the contributors on a particular file',
      variableName: 'fileContributors',
      description: 'Done.',
    },

    error: {
      description: 'An error occurred trying to get file contributors'
    }

  },

Finally let’s craft the meat of the machine, which is the fn:

 fn: function(inputs, exits) {
    const contributors = getFileContributors(inputs.owner, inputs.repo, inputs.path)
    .then(contributors => {
      return exits.success(contributors)
    }).catch((error) => {
      return exits.error(error)
    })
  },

And voilà! We have crafted our first machine. Let’s try it out using the CLI by running the following:

machinepack exec get-file-contributors

A prompt would appear asking for owner, repo, and path, successively. If everything has gone as planned, then our machine will exit with success, and we will see an array of the contributors for the repository file we’ve specified.

Usage In Code

I know we won’t be using the CLI for consuming the machinepack in our code base. So, below is a snippet of how we’d consume machines from a machinepack:

    var FileContributors = require('machinepack-filecontributors');

// Fetch metadata about a repository on GitHub.
FileContributors.getFileContributors({
  owner: 'DominusKelvin',
  repo: 'vue-cli-plugin-chakra-ui',
   path: 'README.md' 
}).exec({
  // An unexpected error occurred.
  error: function (){
  },
  // OK.
  success: function (contributors){
    console.log('Got:\n', contributors);
  },
});

Conclusion

Congratulations! You’ve just become familiar with the machine specification, created your own machine, and seen how to consume machines. I’ll be glad to see the machines you create.

Resources

Check out the repository for this article. The npm package we created is also available on npm.

Smashing Editorial (ra, il, al)