JS Party – Episode #347

Nine pillars of great Node apps

with Natalia Venditto & Matteo Collina

All Episodes

Recently, four pillars of the JavaScript community (James Snell, Natalia Venditto, Michael Dawson & Matteo Collina) teamed up to create a resource that lays out nine principles for doing Node.js right in enterprise environments. On this episode, Natalia & Matteo join Jerod to discuss all nine.

Featuring

Sponsors

Notion – Notion is a place where any team can write, plan, organize, and rediscover the joy of play. It’s a workspace designed not just for making progress, but getting inspired. Notion is for everyone — whether you’re a Fortune 500 company or freelance designer, starting a new startup or a student juggling classes and clubs.

WorkOSA platform that gives developers a set of building blocks for quickly adding enterprise-ready features to their application. Add Single Sign-On (Okta, Azure, Google, Microsoft OAuth), sync users from any SCIM directory, HRIS integration, audit trails (SIEM), free magic link sign-in. WorkOS is designed for developers and offers a single, elegant interface that abstracts dozens of enterprise integrations. Learn more and get started at WorkOS.com

Jam.devOne click bug reports developers love — Never explain another bug report again. Jam auto-captures all the info engineers need to debug and repro.

Notes & Links

📝 Edit Notes

Chapters

1 00:00 It's party time, y'all 00:39
2 00:39 Sponsor: Notion 01:28
3 02:07 Hello party people 01:36
4 03:43 How it came together 03:09
5 06:52 The nine pillars 01:31
6 08:24 5: Avoid dependency creep 06:15
7 14:38 6: De-risk your dependencies 04:06
8 18:44 Sponsor: WorkOS 02:50
9 21:34 7: Avoid globals 08:34
10 30:09 8: Handle errors, log well 04:37
11 34:46 9: Use API specs, generate clients 05:37
12 40:23 Sponsor: Jam.dev 01:31
13 41:55 1: Do not block the event loop 03:53
14 45:47 2: Monitor Node-specific metrics 04:09
15 49:56 3: Use Node LTS 04:36
16 54:32 4: Automate testing, code review, conformance 02:32
17 57:04 Bonus pillars 03:09
18 1:00:14 Closing time 02:54
19 1:03:08 Next up on the pod (merch!) 01:00

Transcript

📝 Edit Transcript

Changelog

Play the audio to listen along while you enjoy the transcript. 🎧

Hello, party people. I’m Jerod, your internet friend, and I’m joined today by half of the team behind an awesome document called the Nine Node Pillars. Maybe you’ve heard of them… Matteo Collina is here. What’s up, Matteo?

Hi, Jerod. Very happy to be here again. Everything is absolutely fantastic. I just came back from Ireland for the Node.js Collaborator Summit and NodeConf EU. It’s been a blast.

Nice. Always a blast to have you, Matteo. Frequent guest here on JS Party. And a first time guest - Natalia Venditto, who is the lead owner of the JavaScriptDX and DevTools at Azure. Natalia, welcome as well.

Thank you. Thanks for having me here. I’m very excited.

I’m excited about this document, this piece of work you all put together, because I think it’s excellent for giving people foundations on building Node apps in a proper, enterprise-ready way. We’re going to dive into hopefully all nine pillars. I might take them out of order… Because some of them are very generic, and I think apply to many kinds of applications, and then there’s some like Node specific ones. I would love to hit the generic ones first, so we make sure we get to all those, and then loop back around. And you may disagree with me on that, Matteo, but we’ll get into that.

I do agree with you. I actually agree with you.

You do?

Let’s get started.

Let’s get started. So first, let’s hear about quickly how this came together. You have four people writing a document… Whose idea was this? Why did we write it? Etc. How did it go?

The main idea was mine, essentially. We started coalescing a lot of ideas about – I’ve been doing this for a long time, and helping companies, doing consulting. Before Platformatic, my startup, I started to – I did consulting for a long time, and basically I collected a lot of bad, bad experience on what companies do wrong with Node.js. And then I decided “Well, there’s a lot of bad opinions out there… So maybe we should spread good opinions. So what can I do about it?” And I said, “Well, if I just write them, it’s just my opinion. Let’s take a group of people to write them.” And therefore, here we are. At the beginning I think there were less than nine.

We started with a lower number.

Oh, scope creep. A little bit of scope creep.

Then we became nine, and nine was a good number.

That is a good number, especially because of the alliteration. Nine Node Pillars. Natalia, how did you get involved?

Well, I’ve been collaborating with Matteo for a while already, ever since I joined Azure… But I think a little bit earlier also, following him because of his work in the technical steering committee. And I’ve been working with Node.js for a very long time, actually in enterprise for more than a decade, as a webmaster of the time, way before that… That wasn’t with Node.js, but anyway, with JavaScript. And yeah, I’ve also seen everything, all the pitfalls, all the bads, all the goods, actually leading a consultancy at the frontend team, or frontend department, with a consultant back in the day, with leading enterprises doing a lot of stuff that – yeah, basically ruined their applications… And tried to inform people how to not make the same mistakes they did, and we did. Because I’m not going to say I never made any mistakes. I probably made a lot of the mistakes we’re trying to avoid people to make in the future.

Sure. You can’t really know good until you’ve known bad. You’ve made the mistake and you’re like “Oh, that’s not good. Let’s not do that anymore.” So this is very much the hard won learning process. And not all of us have to go through it every single time. Of course, certain things you have to learn on your own… But if you can glean from people who have made the mistakes, how to avoid them in the first place, then you’re ahead. And so I’m glad that you all put your knowledge into this Nine Node Pillars.

Now, I want to take them out of order, but are they ordinal? Is it one through nine and one’s the most important, Matteo? Or can we –

No, I don’t think so. It’s a “Let’s put it that way”, a marketing decision on the orders of them. There might be something that comes before the others, but it’s mostly put on what would resonate more for people at the beginning.

Gotcha. So I’ll read through them real quick. We will then discuss, as we see fit. No way we’re going to be comprehensive and cover all nine in extreme depth. That’s what the document is for. So of course, to our listener, if you’ve learned something from this conversation, go dive deep into that, and pull out some gems. But the Nine Node Pillars… One, “Do not block the event loop.” Two, “Monitor Node-specific metrics and act on them.” Three, “Use Node LTS versions in production.” Four, “Automate testing, code review and conformance as much as possible.” Five, “Avoid dependency creep.” Six, “De-risk your dependencies.” Seven, “Avoid global variables, config or singletons.” Eight, “Handle errors and provide meaningful logs.” And nine, “Use API specifications and automatically generate clients.” There you have these folks, nine pillars of good enterprise-ready Node.js apps.

Now, I think some of these are good for pretty much any application, and I think some of these are Node-specific. Matteo, did you agree with me? I couldn’t hear what you said. Did you disagree with me on that?

No, I absolutely agree.

Oh, okay. Cool.

[00:08:04.08] Some of them are – so there’s a thing to say. Some of them are – like, the principle might be generic, but a lot of the content within the section is Node-specific. So while the principle might be generic, the content in there has Node-specific examples on how to implement that principle in Node.js. So they were worth mentioning anyhow.

So let’s start with the ones that I think are the most generic, and we can dive into all the noding details. And those are the ones like “Avoid dependency creep.” This is number five, for you all. And certainly that to me is like a universal thing for all software development. Avoid dependency creep. Say more, Natalia. Do you agree? Do you disagree? What do you think about this particular pillar of Node.js apps?

People that work with me know I’m a hater sometimes, because I try to avoid dependencies at all costs. And of course, you’re not going to reinvent the wheel and write whatever it’s already written and maintained by other people, and you know that it’s reliable, and you can add to your codebase… But I think that we tend – and I’m going to say “we”, because it’s an ecosystem problem; we tend to add dependencies where we don’t need them. We tend to not consider the cost of maintenance. We tend to not consider the cost of being tied to a piece of code that somebody else is leading, or has control over the roadmap of.

Yeah, and that’s something that we need to keep under control. And that’s what we are trying to – and you’re absolutely right, that’s not only a JavaScript ecosystem problem, it’s a software development or web development in general problem. But yeah, it’s a very, very important thing to keep in mind.

Yeah. And I’ve spoken with hundreds and thousands of devs, and we all kind of agree on this. And yet we all find ourselves still with unwieldy dependencies. So Matteo, maybe the question becomes, like, how? Like, we agree that we should, but how do you actually decide how do you do that?

That is true. There is a very important thing to say… The JavaScript community and Npm have solved a problem that plagued the industry for decades. “How to reuse software at scale?” And this is – but whenever there is a big problem to solve, you need to say “Okay, be careful what you wish for.” And now we have Node modules full of modules that maybe we use, maybe we don’t, maybe we can get without. And there are a few things to say… A lot of the time, some of the modules might not be necessary anymore, because we have been adding APIs to Node.js Core for a long time. And also, the web has been adding APIs itself. And therefore, let me make a very clear example.

Fetch is a fantastic spec, is a fantastic API. Everybody loves Fetch. But whenever I open an enterprise codebase, most of the time I see Axios. I’m pointing at an example – and I love Axios. I like Axios. I’m just saying.

It’s an example. Or - I’ve opened a codebase recently and they still use the Request module. Now, I just want to check how many times the Request module, which has been deprecated ages ago, is still used every single day. Because it’s actually a very good number. The Request module is still downloaded 70 million times per week.

Wow. That’s astounding.

And it’s been deprecated for five years. Five years this thing’s been deprecated, and it’s still being downloaded 17 million times per week. This is the problem, that you need to keep those APIs condensed, and try to reuse them. But being smart in what you [unintelligible 00:12:02.08] what you do today, versus what you do in two years. Things change, and you need to keep your codebase liquid in that sense. You can’t put things in stone. And a lot of teams put things in stone, and say “This is our kit, and we decided it three years ago.” But you don’t need this anymore, “We decided it three years ago, and the staff engineer said so.”

Yeah. And this is why we’re big proponents of the web platform… Because first of all, go and check what’s there. That’s future-proof. And then go and find it somewhere else when that’s not supported natively.

Are there heuristics or best practices that you can give regarding dependency selection, or that choice to go search NPM, versus just coding something? Is there a certain size or a difficulty level of a feature where you say “You know what? Grab a dependency.” Fastify, for instance. Matteo, you’re not going to say “I should go roll all my own routing, and HTTP stuff.” You’re saying “Probably grab Fastify”, most likely.

But you probably should. It’s a lot of fun. [laughter]

I probably would if I had the time… Because I like having fun.

Yeah. So that moment, that threshold, how do I decide “Yeah, I’m going to grab something”, versus “I should just build this”?

I tend to not rewrite code. So if I find something that meets my standard, I’ll use it. I use it from Npm. The question is my standard is usually pretty high, and therefore – whenever I use something, my question is “Okay, if I adopt this, will I be able to maintain this thing?” And this is the question that everybody needs to ask when they adopt a piece of software, especially a company. If the thing is small, the answer is always yes. If the thing is big, then you need to ask, “Okay, I cannot maintain this. If I don’t maintain this, then who can? And how can I get them access?” And then it gets to “Who do I need to pay?”, essentially, as a company. And this is important - company versus individual developers is a different mindset. You need to reason about this long-term stability of your project. So if there is a problem and you don’t know how to solve or what to do…

I’ve recently been very, very – I am in a fork frenzy. A lot of the time I like a module, but maybe I don’t necessarily agree on some of the choices of the maintainers, and I just say *bleep* it. Fix it, make it my own, and that’s it.

Fair. Well, that leads us to our next one. We could definitely do a whole episode on this topic… And our next pillar actually is on the same topic, which is de-risk your dependencies. So Matteo, you’re kind of talking about dependency risk… You fork it and maintain it yourself…

Larger the dependency, I think larger the risk. There are some things you can look at with regards to bus factors, for instance, like how likely is this to get abandoned… But de-risking your dependencies, Natalia - this is pillar number six. Speak to that point.

In enterprise specifically, I think that one of the suggestions or things we would like to encourage stakeholders to do is to get more people involved in open source. Because you cannot understand the risks of using code that you are not involved with. So if you’re using XYZ, or you decide you’re going to be using XYZ module, go and investigate about it, get involved; understand the activity in that repo, and understand the security concerns that people may have brought forward for certain choices, design choices, architecture choices… And that’s one way of de-risking. And the other one is making sure that you understand that codebase that you’re integrating. Because you are going to have to debug it, you’re going to have to maybe make the decision of patching something on your end. And if you have to do that, you probably want to contribute back upstream, right? So everybody benefits from whatever you have solved, whatever problems you have solved.

[00:16:22.11] But yes, definitely, getting to know the code that you’re going to use is a – and then keeping an eye, again, on the ecosystem at large, because whatever vulnerability you’re going to have in a dependency, it might be a vector to access other parts of your application.

Let me make a very simple example here. As all of you know, Express has been rebooted; the project had a change in leadership. And one of the things that the new leadership did as soon as it got on the driving seat was to publish a flurry of CVEs. Now, a lot of people have known of those CVEs or those vulnerabilities for a long time… And what was the problem? Well, because the project was not in a good position. So this is one of the important things to look at. Is the project well maintained? [unintelligible 00:17:23.05] Tools can help you a lot tools. I’m talking about tools, but tools is the minimum. You need to go do more than the tools. Tools help, but tools help after the problem happened. Tools are like “Bam!” And this is the famous meme of the duct tape.

Slap it on there.

Slap it on there. But you need to look at the problems beforehand, most of the time.

Yeah, to add to Natalia’s statement around getting to know the code, and to de-risk, get to know the maintainers - get to know the team behind the thing. Hop in their issues and say hi, or just read about the reasons for their motivations, who they are, why they built it… Some people will just put their intentions, “I plan on maintaining this for the next 10 years”, or “This was me scratching my own itch. It’s free for you to use, but I’m done with it.” Those kinds of things are very useful to know in order to de-risk. So get to know the code, but also get to know the team or the individual. You don’t have to have be on a nickname basis with them, like Matteo and I are, for instance, my Fastify maintainer. But I know the team behind Fastify, and that gives me confidence in the project.

Break: [00:18:45.23]

Another good pillar of many applications… Number seven, “Avoid global variables, configs or singletons.” Now, this was yelled at me very loud by my university professors, and I didn’t really know why, but they’re like “Globals are evil. Globals are evil.” And I was like “Okay, I won’t use them.” And here we are, years and years and years later, and y’all are saying, “Don’t use globals, or avoid them.” Why, why, why, why, why? They’re so handy. They’re so useful. They’re so easy. Who wants to take that one?

Go ahead, Matteo, since you’re hitting yourself…

Matteo’s hitting something on his head as I talk.

I am literally like – this is insane. The amount of JavaScript applications on Node.js that are full of globals, the [unintelligible 00:22:25.07] through how the system back and forth, without any possible control of how the project is booted, and setup, and so on and so forth - it’s everywhere. A codebase becomes an absolute mess in no time, because “Oh, I need some data that’s parked somewhere… Oh, I just export it from my module, and then require it somewhere else. Job done.” And then, I don’t know, 10,000 iteration later, the codebase is unmaintainable. And now it’s a problem of Node, and Node that makes all the problems, and therefore you need whatever else to fix it, and move it from JavaScript to TypeScript, or something like that. But the reality is you probably did not apply any structure to your code.

This comes from the history of JavaScript. In the browser, we can use globals. One user, one global. Okay, fine. I can [unintelligible 00:23:32.08] Probably not, okay? And then in order to support this pattern, we had to invent all sorts of things to make it feasible for users to use globals without having actual globals, so they can have a nice DX, and a nice DX is called having globals now, for some frameworks… But the reality is we have a lot of async local storage magic behind it to make it happen. Popular framework [unintelligible 00:24:01.28] if you want the headers of a request, you can just call the headers function exported from a module, and you’ll get the headers. Fantastic, right? To make that happen, there is a lot of state being handled behind the scene, so the right requests get the right headers. And it’s a lot of complexity behind it, a lot of performance that’s being lost by providing this kind of developer experience… Mostly because developers love globals.

[laughs] Yeah, we do. We really do. Well, they’re so convenient.

If you want to avoid this kind of stuff, don’t do it. The other problem is NODE_ENV=production. This is another one of mine… I don’t know, Natalia, do you want to talk to talk a little bit about this disaster? NODE_ENV=production.

Say more, Natalia.

I think that you were very good at explaining why NODE_ENV shouldn’t be used, and I would like you to elaborate on that. But one thing that I really like that you made a distinction about was the use of globals in the browser, the use of globals in Node.js, in the server. That’s two different stories, and we’ve seen a lot of overengineering on the browser side to manage state, which I don’t want to talk about, because I’m going to – but that’s for another chapter, right Jerod? Another episode.

Yes, exactly.

But it’s very, very important to not pollute – to understand scopes. Before you start writing JavaScript. And I got a lot of also people angry at me for saying that before you learn frameworks, try to learn those mechanics of JavaScript.

Yeah. Well, Matteo said something very interesting, which is I think how we get into this mess… Is that what works in the small does not work in the large. And what he said was “a thousand iterations later”, or something like that, where it’s like, when you started, it made sense in that small little “This is just a single file. I’m just running a little Node server. I’ll have a global for my database. It’ll be fine.” And it is fine at that scale of code.

[00:26:16.09] And then we take that and we just like one by one add to it, add to it, and we kind of grow these organic applications out of a single file… And a thousand iterations later you have a huge mess on your hands, and you did not think about the structure ahead of time when it was small, and it comes back to bite you. And of course, blame the runtime is what Matteo said, but… I mean, it happens a lot. It happens a lot. And so how do we avoid it? Well, you have to kind of know what your app is going to turn into eventually, and maybe add some structure up top, or just avoid them altogether, or set NODE_ENV=production at all times. This is what this document says, Matteo. Why?

Well, the NODE_ENV=production is one of the biggest example of this pattern failing spectacularly. Some time ago, a long time ago, a friend of mine, Tim Caswell, decided to add the NODE_ENV environment variable to a library called Connect. I don’t know if you were doing JavaScript when doing Node with Connect.

I remember Connect, and I know Tim. We’ve had him on the show. But lots of people probably don’t, so feel free to fill in the gaps.

Ah, it’s fine. So Connect was the predecessor of Express, very early days. By the way, Tim Caswell - hi. You did a fantastic job.

He’s awesome.

You did a fantastic job for the community. So I’m sorry to put you on the spot for this thing. But he had this idea of “We need to have this library make some different choices between the development environment and the production environment.” Which makes an absolute – it’s a great idea. We need that. We need that in all our code. Any app these days has a development mode, and a production mode. This is great. The idea is great. Then something horrible happened. A few people thought “Oh, but that’s an environment. So I can add a staging environment, and have the configuration of my database be selected by that same variable.” And that’s the disaster happening, because the ops people think that the environment is a server running somewhere. The JavaScript people think that the environment is my computer. And it’s basically a big language barrier, a big language problem of an overlap of two terms with two completely different meanings.

So to resolve that, you just set to production at all times…

Everywhere. Yes.

…and don’t use it.

Yes. And there is a specific module called, I think, Config, that uses that library. Don’t use that module, please, guys.

You would put yourself into big trouble. There’s a lot of people using it, by the way.

How then do you go about achieving the same goals of like “Well, it’s different in dev than it is out there in the real world”?

Oh, you can use whatever you want, really. You can even use NODE_ENV with that specific meaning. But then you have two meanings. It’s either dev, or production. There is no staging.

Because then your staging makes nothing. Okay? Because a lot of libraries in the ecosystem will react to that specific environment. They will react in that specific environment specifically. And if you don’t set it, you will get very different results. So you need to always set it for your final – when you are deploying on a server, that needs to be always set, even if it’s your staging environment.

Otherwise your staging environment is not equal to your production environment, and then you are in trouble.

I’ve actually fallen into that exact trap, where I had a staging environment, but I had to set the environment to production in staging in order to get it to look like production. I can’t set it to staging, because things don’t work. So I can feel what you’re saying. I’ve felt it, and I agree with it.

[00:29:59.05] Singletons - same story, different thing. So pretty much the same. I think we can skip that one. Let’s move on entirely, lest we don’t get to all nine, and I become a liar. Number eight, “Handle errors and provide meaningful logs.” This just sounds like “Breathe, eat food, put one foot in front of the other…” But sometimes we have to state the obvious, and oftentimes as devs we’re in a hurry. We have things to do, features to ship, and we have a propensity, I’ll admit it, to be a little bit lazy sometimes. And that error is not going to happen very often… What’s the big deal? Natalia, do you want to kick off on this topic? “Handle errors and provide meaningful logs.”

Even if the error happens once, that’s it, right?

[laughs] Just once…

Yeah, just once. I think we are not good sometimes at handling errors all the way from the database, the API, and the application. So we should start there, very low-level, and go up. And of course, you need to create meaningful logs in order to simplify your life at the time of debugging, but also because we’re building applications that are going to interact with users, right? And you also want to pass that to the client and make sure that everyone understands what’s going on at all times. It’s essential. Error handling is, like you said, like breathing for developers. It should come naturally. It should be top of mind, and never a second thought.

It’s certainly part of your application. I’m not too big of a person to admit that I’ve just punted on errors plenty of times throughout my 20-plus years of coding. Most of the time when I don’t do something with the error, it’s because I just don’t know what to do. I’m just like “What am I going to do if this actually is an error?” I don’t know, console.log error, and move on. Matteo, do you have advice on error handling? I guess it’s very contextual, so maybe you can’t give generic advice… But have you ever come across a situation and you’re like “I don’t know if it’s errors here”? What do we do?

The biggest problem is knowing that somebody will catch your errors. Especially with long promise chains and long async await, you need to know there is somebody at the end catching your things.

Holding the bag.

Pretty much. The other point is implementing a graceful shutdown pattern. It’s very important for your application, most of the time, unless you specifically don’t want to do that. But I will not get into that case. So when an error happens, and is not caught, it will crash your system. It will crash your Node server. Now, what you want to do - you want to try to land as gracefully as possible, which means typically stop accepting new connections, stop accepting new requests, process what you have in flight, and then –

And then exit.

[laughs]

Otherwise, if you have 10 connections running at the same time and you cut them, they will not get anything in their hands. So that’s typically the problem. A lot of people solve this problem by saying “Oh, I’m just running Node.js in my Lambda, and I fixed it.” Well, they pay for it, but yes. That’s a fix. But otherwise, you probably want Close with Grace.

Do you see that often, this lack of graceful exit out there, and –

All the time.

Really?

Or implemented incorrectly, which means all the time.

Okay. Is it hard? It seems like ChatGPT can do that for you.

ChatGPT cannot do that for you.

No, it’s not good enough.

Okay, what’s good enough?

There is a module linked. So read the document. I wrote a module, but there are a few that are identical. If you use the module, then you’re good. But there is a few edge cases that you need to keep into your head when doing these things, and played well with, I don’t know, with Kubernetes and a lot of the other ecosystems like that.

[00:34:09.14] Alright. So the moral of the story here is npm install Close with Grace. Is that the module you’re talking about? Close with Grace?

Yeah. That’s the one that I wrote. Yeah.

There you go. One more dependency ain’t going to hurt you. Go ahead.

This is a good one. This is one that we allow.

Okay. You also have a subsection here about what to log. Do you want to get into that? Because sometimes you’re logging too much, sometimes you’re logging not enough, there’s log levels… It gets very detailed, but I’m not sure if we want to open that can of worms here on the show. What do you think? Read the document…

Read the document.

[laughs] Read the document. Let’s move on… Pillar number nine, “Use API specifications and automatically generate clients.” This is a very opinionated one, because you know, automatically-generated clients can be not so awesome at times. But what if you don’t like the API spec? What API spec should I use? Why can’t I just hand roll a thing? It’s all JSON anyways… Who wants to pick this one up? Because I think I agree with you, but I can see myself skipping this one in my own applications.

Do you work alone all the time? Because I don’t –

Yes. I skip a lot of ceremony, because I do. So yeah, I’m not your target audience, because this is for enterprise apps… So fair.

Yeah. You need contracts. How else are you going to agree on what the shape looks like of your API? There is none.

That’s true. So don’t listen to anything I say. I’m coming from the indie side. Go ahead, tell us - you need contracts, you need to have an agreement on what it’s going to say… And I’m assuming – and you don’t want to have to just invent that every time.

Right. And you want to be consistent across your many APIs. You want to use the same patterns, you want to use the same exceptions, you want to make sure that anybody that comes to work with you will understand right away how to create that connection server-client, or server-server, or whatever.

So how do I pick a spec? There’s OpenAPI, there’s GraphQL…

For me it’s OpenAPI, but I think this is something we don’t necessarily agree with, Matteo…

We might be in agreement, but yeah.

Let’s hear it.

Yeah, I’m a RESTful person.

Natalia says OpenAPI.

I say OpenAPI.

Oh, look at that!

What do you say, Jerod?

I want to say GraphQL. No, just kidding. I just wanted to have some disagreement on the show.

Oh, I like GraphQL. I like both, to be honest. It really depends on the application. If you can’t really – just use something.

Just use something, and then auto-generate the client. So what do we use on that side? I think there’s probably proprietary solutions, there’s probably lots of ways you can get that done.

I have a maybe biased opinion, but we are working on an open source generator, emitter, API shapes thing at Microsoft. It’s called TypeSpec. It’s a tool to define API specs, and generating code.

Is it out there?

Yeah. TypeSpec.io. Actually, I’m going to be speaking about it at an upcoming conference, TypeScript Paris. So yeah, we’re just rolling it out.

Cool. I’ll scoop that one up for the show notes as well. TypeSpec.io. Matteo, do you sign off on this? Do you use something else?

To be honest, it’s on my to-do list to play with that. I am more of an OpenAPI fan generically, mostly because it comes [unintelligible 00:37:40.02] JSON schema, and it’s all integrated well and nice… I also really like GraphQL too, depending on what we need to do as part of an application, and what the use case is. So there are certain things that are better spec’d as GraphQL. If you don’t know how the data will be queried, probably GraphQL is the right choice…

[00:38:04.05] If you have a variety of different clients, and teams are disconnected with each other. Otherwise OpenAPI is actually pretty good. So it depends on the company, on the use case, it depends on the business… There’s no one-size-fits-all in that discussion. Just use something.

At some point I was chatting, and every single time, because of the process that they had and the boilerplate that they needed to do, they needed to add one more API call from the consumer front, from a company I was consulting with. It took them four hours.

Like, it’s literally money burned. You’re literally burning money. And it’s like, this is something that a computer should do. Maybe even ChatGPT is a good generator. I have no clue. Going to the point of, if I need to unroll it, I’d probably try to ChatGPT it, because it seems a lot of work to – a lot of busy work. I’m not delivering anything of value at that point.

Yeah, I don’t want to hijack the conversation of the pillars, but we also wrote them because, working in enterprise, you understand how this is something that stakeholders, like economic buyers, the ones approving the time of developers need to understand. Because sometimes developers go and say “I need XYZ time, because I need to write the specification, because I need to write error handling”, and so on. And they’re like “No, no, no, no. You just need to get the feature done and roll it out.” And no, because that’s going to cost you more money. You’re going to be – you have the idea that you’re going to be faster in the market, but then you’re going to have to solve a lot of problems that you didn’t want to deal with at the design specification and architecture decisions phase… Which is a big, big error.

Yeah. It goes back to a saying I’ve been repeating for years now, which is “Slow down to go faster.” And it’s difficult to get that across, but it’s 100% the way to do software, is “Slow down to go faster.”

Well, let’s go faster. Now, we’ve reached the end. There’s one more generic one, but I’m going to save it for the very last, because we don’t want our listeners to fall asleep on us talking about testing, and stuff.

Break: [00:40:24.00]

Let’s go back now to what I’ll call the Node-specific ones, although maybe not necessarily Node-specific, but more Node-specific. Back at the top, number one, “Do not block the event loop.” Of course, other things have event loops, but Node certainly does as well… Yeah, this seems like a good one to put in number one. So who wants to kick off on this topic?

Well, do not block the event loop. It’s one of my favorite; it can be a catchphrase, okay?

Most people do not realize how the event loop works, and that’s the reason why it’s number one, to be honest. When your code is executing, you’re not doing any IO. That’s the key part of the event loop, and people don’t understand that. And they don’t think that that is a problem. So they don’t think that, I don’t know, if something takes 50 milliseconds of CPU time to get done, they think, “Oh, it’s pretty fast. It loads super-fast on my machine. How come it’s super-slow in production?” Because 50 milliseconds is a small number, right? You can perceive it locally. However, on a server, 50 milliseconds means that you can do 20 requests per second on a single machine. Now, is 20 requests on a single machine fast or slow?

And that’s the point. But if I try locally, “Oh, it’s 50 milliseconds. It’s super-fast.” I was in a few of those debates. And then that’s a major problem. How you can solve it, do it - there’s a lot of tricks and they’re listed there. But the generic part is be aware that that’s a problem. And if you think that most of the time the solution to your performance issue is the most obvious one, you have architected your application wrong, and you need to rethink your system so that it does not block the event loop.

Natalia, anything to add?

Yeah, I agree with Matteo, and I think that there are several people trying to educate the community on how the event loop works, because it’s so essential to write everything in JavaScript, understanding how - and in Node.js, of course - the stack works, and how things move forward, or get stuck, and why, and how to make sure you’re not causing those blocks. But yeah, essentially also my favorite one…

Is there low-hanging fruit in terms of the how? I know the doc has the details, but is there like a common thing that people are always doing? Or is it just not understanding the event loop itself is the common thing?

Not understanding how it works is a common thing.

Alright. Well, get out there, folks, and understand the event loop, and you will save yourself a lot of pain.

This might also be that because you understand your event loop, you might make different choices in the libraries that you’re going to use. Because most of the time the problem is in your choices. You make choices, you thought something that was very good according to some parameter, then you learn something else, and then you say “Ouch, maybe I made a mistake.” Okay. Well, at least you know now.

And you can fix it.

That goes to one of your bullet points there in terms of things you can do is monitor event loop utilization, and you point out a few tools you can use in order to understand. If you have no event loop problems currently and you pull in a dependency and now you have event loop problems, that’s a pretty clear reaction to that. And if you’re monitoring that, then at least you can see when that thing explodes and/or slows down.

Yeah, Matteo, I think you had suggested some tools?

We are moving essentially to pillar number two, which is a good segue. “Monitor Node-specific metrics and act on them.” The biggest number – like, very often I’m still called to “Can you do a consulting for me? My node.js process keeps crashing” or “I’m having poor performance”, or whatever. Well, what are you using to monitor and evaluate the performance of your system? “Well, I’m using generic metrics provided by Kubernetes.” Well, you’re trying to make choices of your road with a blindfold. So what do you expect? You crash. You try to drive with a blindfold. You’re looking at the wrong things. You’re literally not watching what you need to be watching.

[00:46:24.13] And that’s essentially what this principle is about. Specifically, with the event loop. If you have a Node.js application in production, you need to know the health of your event loop, and act on it. If you don’t act on it, you’re screwed. You have no traffic, and you have no users. And if you have no traffic and no users…

Nothing happens.

[laughs] I feel that I built a few websites like that. No traffic and no users… Yeah, I’ve done that before.

No resources used.

Yeah. Everything’s humming along nicely. The load average is really low. What are the key metrics to watch then? What do you care about in a Node app? What are the key metrics?

Well, I said the event loop utilization is this new method that we added recently. Most people don’t know about it. Read, study, guys. It’s basically a percentage of the event loop that is processing events. It gives us a very immediate number. Then we want memory. But not RSS. [unintelligible 00:47:20.10] Don’t use that. That’s a horrible metric. You need to keep an eye on that, but to be honest, that’s not the important one. The important one is heap use versus heap total. Because Node.js will use all the memory that you give to it. If you take Node, you say “Okay, Node, use one gig.” “Yes.

PacMan.” Yeah, Natalia. It eats all of it. But then it manages it – we’ve seen all of it with Chrome. When you open a lot of Chrome tabs, each one of them consume gigabytes and gigabytes of memory, guys.

Right.

It’s horrible. Anyway, track how much of that memory is actively used. Track that.

Gotcha. So when your Node server starts, it is going to allocate for itself a certain amount of memory, and it may be over-allocated by a lot. It could say “I’m using one gigabyte of RAM.” No, it’s not like that. It’s more like you have one gig, you know… Typically, it happens in this way. You have a chunk of your application, you can name it – a part of the application that allocates a lot of memory. That memory does not get cleaned up very quickly. And then basically the garbage collector of V8 thinks “Well, cleaning this thing up is going to take a lot of time, so I’m going to park it there, and maybe later on, I will have time to clean it up.” And then, “No, but there is memory available on the system. It’s free. I can just get it.” So I’m getting more memory. It’s very lazy.

PacMan.

And then it eats all. Yeah, PacMan.

Right.

It looks like a kid, to some extent, it looks like a teenager that prefers to do something else than cleaning up your [unintelligible 00:49:10.19] room.

Right. Get some new clothes out, versus cleaning the ones that are laying on the ground.

“It’s exhausting to be cleaning up, so I’m going to just use whatever is out there, free for me.”

There you go. So the key there is heap used versus heap total. You’re going to get less information out of the resident set size… Which is unfortunately also RSS, but not really simple syndication. Of course, in context it’s not confusing, but for us just talking about it, perhaps it is. And of course, like you said, the event loop utilization, that’s probably the big one… And then of course, CPU usage; overall processor being used, right? Typical stuff there.

Alright, let’s move on to pillar number three. “Use Node LTS, long-term support, versions in production.” This one seems to me as the most enterprisy of them all. But Natalia has got the face palm going, so I’m thinking people should just do this and –

[00:50:15.02] Yeah, I have seen so many instances of - you know, you’re analyzing an app that is not working, and then you go and check what version of Node they’re using it. Of course, 15, 17, 19… But why?

“But why…?” Well, I can answer that. Because that new one had something fancy in it that I wanted to use, right?

Right. But not in production, right? Until it’s released in LTS.

So what does LTS give us over non-LTS, for those who don’t know how Node gets released?

Well, first of all, they recycle their long-term support… Which is 18 months right now, Matteo?

The current version is six months. Then it’s supported for another two and a half years after that.

Oh, two and a half years. Okay. Yes.

So three total years?

Yeah, three total years. Yeah. But it only gets 12 months out of that as active LTS, which means it gets back parts of new features, and things. It’s great.

And non-LTS gets something - I think you wrote seven months?

Six months. Seven months. Seven months. One month is - I will call it six months, but yeah, seven months.

Why is it a month? That’s so arbitrary.

Because it’s six months plus one month of grace time in which we also fix security vulnerabilities.

For the slow folks.

Yes, for the slow folks. But to be honest, I would just cut it. I would actually remove that. If I had an axe, I would axe it.

Yes. If you were the Node release –

I’m not. I don’t do Node releases.

…BDFL, or something. You would just axe that. But you are not.

Alright, so LTS, longer support… You get benefits like reduced risk of breaking changes, enhanced security, improved stability… And Natalia just says, “Why not? Why not just use that one and get all the goodness in production, versus the six or seven-month one?” Six months with Matteo in charge.

And there’s also people that use LTS, but they use it for 10 years, right? And so they are on version 10 now… Don’t do that.

Don’t do that.

Keep your versions up to date.

There you go. Now, how is Node with backwards compat? Like, as I get newer versions, am I breaking major changes all the time? Is it a huge pain in the butt to upgrade? What’s your guys’ experience there?

I maintain the thing, so I can’t, to be honest… We try not to break anyone most of the time.

You’re too close to it to answer that.

I am too close to it to answer that question. So I hope not, but if we do, we are sorry.

You need to consider there’s going to be a point when you cannot offer backwards compatibility, because otherwise you would never introduce any innovation, any changes in the specification. Like, how do you do that? There is no way, right? You have to. It’s one thing or the other.

You want to innovate. You want to change. You want to –

That’s the problem.

…get that TypeScript support in there, you know?

Yeah, but that’s not breaking.

It’s not breaking because you don’t use it. Because you use a flag not to use this, right?

That’s right. It’s opt-in, so it’s not breaking.

I’ve been a laggard on the TypeScript team group, so…

That felt like a personal dig against you, Matteo.

Oh, yeah. She absolutely knows how to dig it.

I am JavaScript all the way, so…

She’s poking the finger at me on the TypeScript stuff… She’s Microsoft, so come on… What can you expect?

No, no, but I am JavaScript. I own a JavaScript site.

[00:54:02.19] Oh, you are? Alright. Well, we have three JavaScript users here. I’m also not on team TypeScript, but mostly because my co-host, who’s not here, Nick Nisi, is the biggest TypeScript fanboy you could possibly imagine. And so we can’t have that much agreement on the pod, so I just refuse to use it for that principled stance, pretty much only. And the fact that I don’t like ceremony. And like I said earlier, I’m kind of an indie dev, so I don’t need all of the hunky-dory team-oriented things, you know? Which leads us to our last pillar, which is also generic, but I left it for last, because it’s like eating your broccoli. Although, general tip on broccoli, if you don’t like it, actually eat it first, because when it’s cold, it’s even worse. When it’s warm, at least… So here we are. “Automate testing, code review, and conformance.” Oh, that’s three pieces of broccoli. Why? Why do I have to do it? Can’t we just skip that one, Matteo? Test in production.

[laughs] That’s right. That’s right.

If you care about your job, don’t do that. That’s a good genetic principle of life.

Yeah, I agree. If you care about your body, you eat the broccoli, right? So I hear. It’s good for you. Natalia, what’s your take on –

You don’t have to love it, but you have to do it.

You don’t have to love it, but you have to eat it.

Yeah. I don’t love it. I am the person that always finds somebody else to write the tests. Because I don’t love the broccoli… But you have to do it, and that’s it. There is no way around it.

What’s the conformance part of this? Code review, I understand. Testing, I understand. Conformance…?

Oh, you need to have standards. You need to have –

You’re talking about linting, and stuff like this?

Well, yes, but also, you have to have conventions. So yeah, you need to have conventions, you need to have standards. I mean, internal standards to your company, that you agree to, that put everyone on the same page on how we’re going to do this, how we’re going to write this, how we’re going to understand each other when we’re writing code, and reviewing it.

Gotcha.

How can you review something if you don’t know what’s right and what’s wrong?

And this is the world of tooling, right? Tools help a lot with this. Otherwise, it would be like a bunch of nitpicky code reviews of saying “Hey, we don’t put our semicolons there”, or whatever. So like linters, style guides, Prettier etc. Also probably some bigger architectural documents where you decide “Here’s how we’re going to – we’re not going to use singletons. We’re going to read the Nine Node Pillars”, stuff like that.

Yeah, “We’re not going to block the event loop.”

“We’re not going to block the event loop.” You have some sort of chant that the whole team does at their stand up, right? “We will not block the event loop”, like Bart Simpson writing it a hundred times on the chalkboard.

Alright, so that brings us to the end of the nine pillars. I thought we did a pretty good job of covering all those. Of course, the details are what matter, and they are in the docs. We didn’t want to just read the doc to you all, we wanted to talk about it… What about pillars that didn’t quite make it? I’m sure – this is a collaborative process. I know you went from four or five up to nine, but certainly there was like a 10th and 11th and a 12th there, like “We’re not putting that in there, but that’s still good advice.” Have you got anything left on the editing room floor that is still worth bringing up?

Very opinionated ones. I think “Use TypeScript” could be a pillar, in a sense. But do you want to? Do you want to make people angry? Even yourself? No. We said “Use LTS”, but we didn’t say “Please don’t use very old versions of Node.js”, which should be a pillar. But that’s common sense, right? We hope.

Right.

[00:58:03.19] On TypeScript, I want to be provocative… I really like – I came to enjoy the experience of writing TypeScript when working with a team and building an application. I absolutely think that the authorship story, from a maintainer perspective, or somebody that’s maintaining a lot of modules on Npm - it’s so much better with JavaScript and writing the types manually, that it’s just like “Okay, I’m probably not doing that.” Like, the authorship story - it’s so hard. It makes maintaining this thing so much harder.

I can maintain a lot of the modules I maintain because I just pull JavaScript that’s super-easy to maintain; not a lot of tool chain. But yeah, that’s probably my – if I wanted to put it as an advice… So TypeScript requires a lot of tooling around it to make it usable. And that’s – it gives you a lot of benefits. So that’s true. But if a maintainer with very little time, optimizing for time consumed, is very often…

Have you looked into JSR? The Deno folks’ new registry. They’re trying to make it super-easy to publish TypeScript packages without –

It’s a great step into the right direction, I think. That means less TypeScript options, and less variability in the tooling, and so on and so forth. It’s a great step. We have a few Node messes to deal with at the moment, unfortunately.

I have a controversial opinion. I mean, it’s great for library authors, for dependency authors… But in your application you still need to transpile, right? So you still need the tooling, if you’re an application author.

Absolutely. Right. Yeah, I think the sales pitch currently is on package authors, is two package authors more than your regular app dev, who still, like you said, yes, has the build tools anyways. Very cool. We’ve come to the end. Anything left unsaid? Anything you guys want to shout out or link to in the show notes, how to connect to you? Of course, Platformatic is where you’ll find the blog posts… You’ll also find it in our show notes… But anything else?

I want to thank also the other two authors of this.

Oh, yes.

Michael Dawson and James Snell. Everybody reviewed this, wrote part of it… It’s been a good collaborative effort. Yeah, that’s probably my take. I want to make a key part, something very important that was not said - there’s been a clear movement there on supporting the maintainers financially. This is very important. There’s been very recently something called the Open Source Pledge. I want to recommend major companies to contribute either developer time, or money, to the maintainers of the commons. It doesn’t mean joining the pledge, but you need essentially – everything uses a lot of open source. And if you have a critical piece of open source that you rely on, sending some money to the maintainers usually helps them a lot. Or even just give them a job and an opportunity to do that work as part of your team.

Now, that last part is more important, because a lot of big companies do not consider public open source as part of their promo packs, which is a huge, huge problem for a lot of people that want to do this kind of good open source work. “Look, I’m doing all this work, but this is not getting me any benefits at my job. So why the heck am I doing it?” And at some point you get burned out and it goes all bad. So that’s probably my last take…

Gotcha.

So please consider, sponsor, help, see how you can make the life of your maintainers easier, and not try to be vampires and sucking the blood out of them and burn them out.

Well said. Natalia, any final words from you?

Yeah, no. I’ll second that pledge from Matteo. And also, get involved. Get involved in open source. As a developer, it’s very, very rewarding.

Well said. Well, on behalf of Matteo Collina and Natalia Venditto, thank you for listening to this episode of JSParty. All the links to all the things are in your show notes. Shout-out also to the other collabs on the doc. I think it’s an excellent resource for the entire community. Thank you all for writing that.

I’m Jerod, this is JSParty, and we’ll talk to you all on the next one.

Bye-bye…!

Changelog

Our transcripts are open source on GitHub. Improvements are welcome. 💚

Player art
  0:00 / 0:00