EPISODE 1935 [INTRODUCTION] [0:00:00] ANNOUNCER: Modern web development requires an ever-growing collection of tools, including formatters, linters, bundlers, and plugins. Each tool typically has its own configurations, dependencies, and performance cost. As applications grow more complex, the overhead of maintaining this tool chain becomes a real burden. Biome is an open-source tool chain for web projects that brings formatting and linting together in a single, fast, opinionated tool. It's built in Rust and is designed to be a drop-in replacement for Prettier and ESLint with sensible defaults, minimal configuration, and consistent behavior across the CLI and editor environments. Biome also introduces a module graph that enables cross-file analysis and type-aware lint rules that don't require the TypeScript compiler. Emanuele Stoppa, known as Ema, is a Senior Systems Engineer at Cloudflare, a lead at Astro, and the creator and lead maintainer of Biome. In this episode, Ema joins Josh Goldberg to discuss the history of Biome, how linters and formatters work under the hood, what makes Biome's architecture fundamentally different from the tools it replaces, and what's coming next for the project and its community. This episode is hosted by Josh Goldberg, an independent full-time open-source developer. Josh works on projects in the TypeScript ecosystem, most notably TypeScript ESLint, a powerful static analysis tool set for JavaScript and TypeScript. He is also the author of the O'Reilly Learning TypeScript book, a Microsoft MVP for developer technologies, and a co-founder of SquiggleConf, a conference for excellent web developer tooling. Find Josh on Bluesky, Fosstodon, and.com as Joshua K. Goldberg. [INTERVIEW] [0:02:04] JG: With me today is Emanuele Stoppa, open source maintainer at Cloudflare, creator of Biome, and lead at Astro. Ema, welcome to Software Engineering Daily. [0:02:12] ES: Thank you for having me, Josh. How's it going? [0:02:15] JG: Things are good. I'm excited to talk to you. You've done quite a few interesting things in tech recently. You've been on Astro. You joined Cloudflare. You're the creator, lead maintainer of Biome. Before we get into all that, how did you get into coding? [0:02:27] ES: Well, as maybe the majority of the developers out there were like, "I want to develop video games." That's essentially why I got into coding. Things didn't plan as I thought they were. I went to university, where they was supposed to teach game design. But in the year where I was supposed to join that class, there was no professor. So I had to choose another class. And eventually, I haven't done anything around video games. So I ended up doing PHP, Postgres, and all the stuff that webdev was at that time, and that's how I started. Then it was PHP developer, jQuery, and so on, until React and all the cool kids that we have now. [0:03:16] JG: Do you have any emotions that come to mind when you think about developing front-end full-stack apps, and PHP, and jQuery? [0:03:23] ES: Yes, because I see a lot of partners that I used to use back in the day coming up, like SSR, before it wasn't a thing, like React developers. And it was all about SPAs everywhere. Everyone was developing single-page applications. And that SSR came back, because that's how you used to do things in PHP. I mean, there's nothing new here. We are just doing things as they were, just using JavaScript instead of, I don't know, PHP, C#, or Java. At that time, that's what we had. It's kind of weird because we are not inventing anything. We are not reinventing the wheel. There's nothing exciting. It's just the same patterns using different tools, different libraries. I like the tools that we have now simplify the process. Back in the day, when I wanted to do SPAs or islands, for example, it was a mess. Now we know how to do these kind of things. The libraries allow us to do that. I was like, "Ah, thank God. Now we can do things very quickly." [0:04:35] JG: It's lovely that we've learned how to do the same proper techniques, but with a lot cleaner syntax now. Which brings us to kind of a transition for you. You started off as a sort of standard developer working on apps, PHP, jQuery, and so on. But at some point, you transitioned to dev tooling. And one of the earliest projects that you were associated with in that space that got a lot of interesting news was Rome. Can you tell us about how that came to be and what that is? [0:04:59] ES: Yeah. Rome, Rome tools, was a project that was supposed to be like all-in-one tool for all your web projects. So, having formatting, linting, and bundling, testing, everything in one single application, or binary, or whatever. And I really liked it, the mission behind it. In the past, I always struggled to maintain a lot of these depth libraries, such as formatters, linters, bundlers, plugins. And Rome was like a breath of fresh air. And I was looking for an open source project to contribute to. Yeah, I mean, let's do it. That's how I joined the mission. Rome at that time was in Typescript. And eventually, Rome got some funding. They opened the company, and they joined as an employee of the tool. That's essentially how I got there. But my passion to open source came before, also wrong. I was involved into Webpack before that. I was part of the CLI team. Why? Because I fought with Webpack a lot of times in my working experience in all the companies where I worked. And I became a kind of an expert. I was also on Stack Overflow answering questions and things like that. I wanted to increase my knowledge around Webpack, and that's how you do it. You just go into open source, and you learn stuff from the actual creators. [0:06:36] JG: How did you make that jump from learning about Webpack to contributing back to it or to helping others? It seems like kind of a scary cliff for a lot of people, a gap in difficulty levels. [0:06:48] ES: Yeah, it is. It is scary. But at the end, you just have to do it. It's like a leap of faith. And you come to understand that you can't know everything. You have to make the peace with it and just say, "I don't know this. I don't know that. But I have experience with this thing." Maybe that's your solution. Maybe this is your other solution. Once you understand that you can't know anything, and you have to accept that others might have the answer just gets easy. Eventually, you just do your stuff that you want to do, and you try to learn what you want. [0:07:30] JG: And for you, that's been simplifying those complex tech stacks you've mentioned into something a little easier to wrangle. [0:07:36] ES: Yes. Yes. Exactly. Before tooling, I was in front end. And it's a completely different world. Tooling requires a lot of different knowledge from front end, but there are some similarities. There are some lessons that you can take from front end. And there's accessibility error handlings. And fighting with browsers, fighting with things that don't work in a lot of context. You take them into your tooling. For example, error handling it's the same. You have your user that does a mistake, you have to handle it. You have your back end that does something funky; you have to handle it. Same for tooling. You always have your user that inputs something via CLI, for example, and you have to essentially provide some decent feedback. It's a different context. but at the end, it's a product. You have your users, and you have to provide something good that they like. It's not that scary. Yeah. I mean, in programming, you always have the same problems, more or less. Different context. But at the end, it's just about data. You get some data, you have to pass them and then do something with it. And if doesn't work, you just send a good feedback. If it does, you send the feedback that the user wanted. [0:09:03] JG: Functional programmers may be pleased to hear that, that everything ends up turning into a function that returns one of two types. [0:09:10] ES: Exactly. [0:09:11] JG: Let's talk about that doing something with it. Because you've worked on several projects now that do something with code that builds it. At the very barest, before we go into the details, what is a builder, or what is a bundler? [0:09:24] ES: Oh. Well, bundler, what it is? Well, as you said, a bundle is a linker. It's like taking different files and just create something that is linked all together. In modern programming, now in the web ecosystem, we have a bundler that has to take a lot of JavaScript files scattered in your application and dependencies, and eventually creating something that it's pleasable to use in the browser for you as a developer, but especially for users, your end users. You have to ship something that doesn't break. You have to ship something that doesn't takes a lot to download, for example. You can't ship all file, all dependencies. Otherwise, it's like megs of megs mess of JavaScript that your user needs to download. I mean, it has to deal also with lot of different things like HTML, CSS, SaaS, less TypeScript, CoffeScript, WASM now, and a lot of stuff. A bundler nowadays is actually, from my point of view, one of the most difficult and rewarding software that you can create or contribute to, because there's a lot of care. And I think it's like you learn a lot if anyone wants to work on it, because there's a lot of - also, source maps as well. [0:10:56] JG: Yeah, there's a lot going on there. Let's say that I have just the most barest of applications that uses imports and exports. I got an HTML page, a JavaScript file that imports from a couple node modules, maybe another JavaScript file that imports that one and calls it. And I want to turn that into some .com website, and I'm going to use a tool to do that. First of all, do I need to use a tool? In what situations can I, if any, get away without that? [0:11:20] ES: Well, you could use a tool, but also you can't. It depends on your taste. Back in the day with PHP and these kind of things, you didn't need to. You just have your PHP file. It means your JavaScript and everything. You had everything out of the box. Nothing's got more complex. Our users need more. The browser has more capabilities. We are recording our session on a browser, something that we couldn't do 10 years or 15 years ago. Capabilities increased. We have more tools at our disposal. Even the applications got complex based on what we want to ship. Eventually, you want to use a tool. It simplifies a lot of boilerplate, setting up the page, or dims, or even JavaScript, doing interactions and things like that. You could do it yourself, but there's a lot of going on nowadays. You don't want to do it. And you want to focus on your app. You don't want to focus on the boilerplate. Yes, nowadays, you should use a tool that simplifies all the basics, and so you can focus on creating whatever you want on the browser. Or even Electron, where you have your native app. See, the capabilities are increased. We have endless possibilities. [0:12:50] JG: All right, you've convinced me for my HTML and a couple of JavaScript files page. I know it will get more complicated, so I will use a builder or bundler. How does that actually work? How do we go from that source code split across different JavaScript files to something that gets run by users with all those optimizations you talked about? [0:13:09] ES: That's a really interesting question. I don't have a clear answer. But as a developer of some tools that does the kind of things such as Astro, how does it work? You have a concept of pages, which are essentially your entry points where your user lands. Okay? And from there, you essentially start building your tree of dependencies, which are styles, CSS files component components, JavaScript files, anything that your page requires. And that's how your bundler works. You have your entry points, where your user needs to interact. Call them pages. In most of the cases are synonymous entry points or pages. And there, your bundler creates a tree of dependencies of assets essentially. What it needs to ship in order to render and make the page functional? Of course, there are a lot of challenges understanding the CSS files. Nowadays, things got more complex because styles in some applications are shipped together with some components. They are like atomic. Take, for instance, Vue, Svelte, and Astro. They have the council of components, single-file components. And each file component can contain a piece of JavaScript, can contain a piece of HTML, and a piece of styling. When you have multiple components that are inside the tree, you also need to understand the order of how this style needs to be bundled together in order to actually not mangled the end result. You could have your button that is imported in the middle of the tree or in the end of the tree. And then you have to decide, "Okay, now what's the order?" And that's what the bundler does. It's responsible to tackle these kind of problems for you, so you don't need to fight them. And of course, bugs can be there, but that's what the bundler does for you. And same for JavaScript. You have a lot of scripts important in your tree. You have to make sure that they are imported and executed in order. Eventually, your button reacts to a form submit, or it reacts to an error in your form without breaking other scripts. So that's, I think, the bundler works. [0:15:50] JG: It's interesting the way that you describe the assets because very little, if anything, in your explanation, is specific to JavaScript files. Let's say that we have a new kind of asset. Let's say I want to import some .webp image and then use it as a source string in my file. In this system, does that mean that I could have sort of arbitrary extensible plugins for different sorts of assets? [0:16:12] ES: Yeah. Technically, yes. If the bundler allows you to do so. But essentially, yeah, a bundler needs to work like in a very abstract way. But then he has to has specialized section where he needs to understand what is actually processing. CSS files, images which have different extensions, different kind of encoding, and things like that. We have WASM, which also requires its own instantiation and other things. We have fonts, for example. That's another asset that needs to be treated in a certain way. Yeah, I mean, nowadays, we are creating bundlers that has to be designed in a generic way and extensible, so users can extend the bundler for their needs. Because not everyone needs to deal with web images, or AVIF, or a videos, for example. There's also this kind of asset. In the wild, now we're creating - since Webpack era or Rollup, we are creating bundlers that are generic, and users can extend it. We are settling on a plug-in system where users can essentially do whatever they want with the bundler. [0:17:34] JG: That users can do whatever they want yields a lot of power for users. But a lot of long-lasting web developers may remember that power comes with a cost. Let's talk about two of those costs here. Performance and configurability, or ease of use. There are horror stories out there of multi-thousand-line Webpack configs that are slow. What would your response to that be? [0:17:58] ES: Let's call it belief or opinions on plugins have shifted a lot recently, especially now that I'm dealing with Biome, which is built with a native language. And Astro, which is completely different. Uses plugins. As you said, there's a cost. And I feel like people shouldn't pay that cost. You have a lot of extensibility. But yes, as [inaudible 0:18:28], that's nice. You do your project weekend, you can create your plug-in. And you have a sense of power. You're doing something great because you you're creating stuff. But then there's the other side of the coin, which is you are at work, you are responsible for maintaining the product of your employer. And that's the cost you pay. You have a lot of plugins, you have a lot of extension, integrations that you have to deal with, and they have a cost on your application. Sure, then the bundler somehow has to be responsible of it and reduce the performance and make it faster. But a certain point, I think it's not responsibility of the bundler of the tool, the plug-in system anymore. It's responsibility of the maintainers of the plug-in. Eventually, who pays the cost? The users. I'm coming to a realization that we need the plug-in systems just for certain things. Other things shouldn't be extended too much, but shouldn't be baked into the tool. It can do it correctly. It can monitor the performance. But we can give to our users all these integrations and plugins. And eventually, the performance of the tool degrades. And you ended up with webpack that takes like 30 minutes to bundle your application. I don't know. And we keep trying to solve this problem. We have Rollup. But now we have Rolldown that wants to fix it by using a different language and maybe a different architecture. But I think it's not going to solve everything, because application are going to be more powerful, demanding, and bigger, because that's how the technology works. We're going to see maybe in 3, 4 years, 5 years, we're going to see again the same problems, and we're going to try to solve them the same way. I come to realization now, maybe we have to do something different. That's why configurations should be static. It shouldn't be dynamic. They should be predictable. In fact, I know ESLint paid this cost, and that's when V9 shifted their configuration to be flat. It's easily debuggable. Eventually, they couldn't understand which plugin was making a mess, because it was all a recursion. It was difficult to debug. And so they came to realization, we have to do something. They broke the ecosystem. But I think it was something that had to be done. Because as a open-source maintainer, I understand where they were coming from and why they did it. Of course, a lot of users were not happy. I mean, they made a mistake. They had to fix it. Some users were not happy. But in the long run, I think it's going to pay off. [0:21:45] JG: How do you know, or how are you able to tell where that balance needs to be drawn between powerful users and comprehensive built-ins? [0:21:55] ES: I don't have an answer for that, to be honest. It's very difficult to draw a line there. I think it's also a matter of try and error. Okay, it can be a lot of - very extensible. To be honest, I don't know. I really don't know. A plug-in system allows you to do everything. But if you give it too much, you end up breaking stuff. You end up that you can do a lot of optimizations that you could do if your plug-in system was more tight or has less feature. To give you an example, ESLint has a great plug-in system. And we have plugins everywhere. But it comes at the cost where they can't innovate now. The force of ESLint comes from its plug-in system. But now they can't innovate, they can't try new things. Because otherwise, all these plugins, they could break they could degrade without knowing. That's kind of the line. You should try to give enough power to please your developers and users, but not as much so that you can't innovate. You are a programmer. As a programmer, you also want to look for new things, try new things, because that's I think one of our passions. And if you can't try new things, what's the point? At the end, it's just doing maintenance. I don't know. It gets boring. Maybe that's why you ended up with creating new projects and try new things. [0:23:32] JG: Yeah, there's a natural cycle where, once a project gets successful, that bogs it down. I want to talk a little bit about one of the major new things that a lot of projects, including Rome, and Biome, and Astro, which is native speed code. You led the conversion from Rome in TypeScript to Rome in Rust. First of all, why Rust? For those who haven't heard this hullabaloo. Why are so many projects switching to specifically Rust, or at least native in general? [0:23:59] ES: Why Rust? I think there are two main reasons, or maybe three. Let's list them, then we count them. First one, it's a really strict language. When you have a dependency, there's a less risk to break it. It's so tight, the system, that even when you have a major, you have a less breaking changes. Or if you have them, you catch them straight away at compile time. It gives you the safety of having a lot of dependencies, but at least they break less often as it could happen in TypeScript or JavaScript. You have less maintenance burden in your tooling. Second was essentially speed. Rome, when it was in TypeScript, was actually great. But it suffered from a lot of memory consumption. At that time, Rome was able to bundle itself. As a binary, it could bundle itself. And while it was doing that, it was consuming a lot of memory. 8 gigs of memory. It wasn't sustainable. It felt like it reached the limit of Node.js. That's when we decide, "Okay, maybe we have to go somewhere else." You can try to do a lot of optimizations. But if you can't leverage the actual memory - yes, JavaScript has some tooling for garbage collection, but it's very, very limited. Rust, as a native language, allows you to manage your memory way more than JavaScript. And third point is how easy is to integrate with WASM. Rust has a native bindings using the WASM bindgen crate. It's very easy to have your Rust code and porting into WASM. So then it can be shipped into browsers, other languages that are able to interpretate WASM, and they execute it. That's really great for a playground and things like that. I think that's one of the reasons. Because, sure, the language is very typed. But even TypeScript is typed in a different way. It wasn't the problem. And Rust has gained a lot of traction recently for their memory safety. You don't need to deal directly with memory like C, or C++, or other similar languages because Rust does it for you using their borrow checker. So it takes a while to get used to. But it's the language that does it for you. You don't need to take care about that part, so you can focus on your application. [0:26:51] JG: It sounds great. Let's jump forward in time a little bit. Rome was around the 2021-2022 era. How did we get from Rome to Biome? And what is the difference between those two projects? [0:27:01] ES: Yeah. For a year and a half, we were good at Rome. We were doing great. But eventually, the company behind it went under, so they couldn't get any more money. Eventually, they had to close. The thing is, I liked the project. I joined the open source project before getting hired. And they wanted to continue it. Even after I left the company and I joined another company, I continue to contribute to Rome. Other people joined. I wasn't the only one anymore. Eventually, we had a team of volunteers, and we shipped. We continue shipping. Eventually, I really wanted to change the phase of the project, but it it always requires a lot of work, like logo, names, website domains. You don't want to do that. It's a it's really annoying. But eventually, we had to do it because the NPM tokens expired. So we couldn't actually ship and publish new versions on NPM anymore. We were actually forced to do the move. And why Biome? James, which was the CTO at Rome at that time, had this idea in case we wanted to change Rome, to call it the second Rome. Second Rome, Biome, that was the idea. I asked him, "Can I use it? Are you okay with that?" "Yeah. Sure, go ahead." Yeah. And eventually, Rome fell in December. And in August of the next year, we announced Biome as the new Rome. I would say the mission changed slightly because we are not focusing on the bundler, for example. Because we have less resources. We don't have people dedicated to the project. We are now focusing on format Relinter because that's what we had. Instead of going horizontally, we went vertically. We ship more features into the linter and the formatter. More languages. But still, more lint rules, formatting capabilities. But we are not focusing at the moment on the bundler, or the testing suite, stuff like that. And I think we're happy with that. We are doing still great things. [0:29:25] JG: Yeah, let's talk about those great things. Most users I've talked to are not extremely familiar with formatting and linting as concerns. They know that they clean up the code base. Maybe they know that linting does more logic. Formatting more - well, formatting whitespace. What does Biome do for users around formatting and linters? [0:29:44] ES: First of all, it wants to ship a different developer experience compared to the tools that we have. Better messages, something that you can actually action. You have your error. And Biome tells you, "Okay, that's how you should do it, or you shouldn't do it." Some user, yes, they dismiss the linters as nice to have. What we're trying to do is also to teach people how to do stuff. We ship this lint rule that targets the .reduce function of JavaScript, and says, "Do not use the spread operator when you return the accumulator." And the lint rule tells you don't do it because it's a performance problem. And I've seen people that didn't know that. And once they know the rule, they learned something. That's one of the missions. You have a linter that teaches you something. Because, as I told you before, not everyone knows everything. If we get the chance to teach you something, I think we did good. We're spreading the knowledge. That's why our lint rules have to have a really high standard. They have to tell you why it's an error. Because if you're not able to tell why an error exists, then it's not an error. It's a moot point. And then formatting, it wants to just provide a faster experience compared to the tools that we had at that time. I know that users in the past were kind of unsatisfied with Prettier performance, which was, at that time, the only widespread formatter in the JavaScript world and the web world. With Biome, we provide a very similar formatting, but at least it's faster, especially in CIs and things like that. But we also want to provide an experience that is tied also to other tools. Biome knows your git in files, for example. So you just hook into them. And it doesn't format the files that I ignored in git. You can also integrate with your edit or config, for example. You have your edit and config. So you don't need to maintain the biome config. You just use what you already have. It's not just about linting and formatting, but we also embrace the other tools, so that biome gets to know what you're using, and you learn from them. We're doing the same with Svelte, Vue, Astro, CSS modules. Tailwind, too. See? Webdev is quite vast. We don't want to limit ourself to just one tool. But we think we should actually embrace a lot of them, so get to know them, and you learn something that you might not know. [0:32:37] JG: You've touched on one of the really lovely parts of using Biome, which, as you said, it's all in there. You can run the format, the linter just from one command. How much simpler is it in your experience to configure Biome compared to how things were configured, say, 5 years ago? [0:32:52] ES: I think it's actually really good and fast because you don't lose a lot of time. I still remember when I used to set up ESLint and Prettier years ago. And it got easier. But the fact that you have to install three or four packages. And then you have to configure ESLint to use Prettier's config or plugin. I don't remember. It was a nightmare. I mean, sure, it takes 10 minutes. But why you have to do that? I mean, you shouldn't spend so much time on these tools. And that's why Biome is there. You have one config with sensible defaults, which means that you just install the dependency, and that's it. You don't need to do anything else. You just use it. If you don't like the defaults, okay, you can run Biome in it and change the defaults, and that's it. Also, you don't need to format the code that is fixed by your linter because it's all in there. Biome does it for you. And it works out of the box in your editor. What you get in the CLI, you get it as well in your editor. You don't need to do anything, anything at all. Instead, you can install the extension, of course. But other than that, you don't need to install true extensions like Prettier or ESLint. You don't need to modify any configuration. It's all in there. Works out of the box most of the times, of course. You see, users spend less time in tooling, setting up their tooling, so they can do programming as they want. Because that's what we like to do. We don't like to set up tooling. [0:34:37] JG: Absolutely. Diving into the tooling a bit. Formatting has not changed significantly over the last few years, other than what the defaults may be or configuration. The architecture has been pretty stable. Linting, on the other hand, Biome does linting things quite a bit differently than, say, ESLint that came before. What's different about a Biome lint rule versus, say, a predecessor ESLint rule? [0:34:59] ES: Okay. One thing that we recently shipped in Biome, type-aware rules and project rules. We know that we have TypeScript ESLint. Thank you, Josh, for what you shipped to us. The existence of the ESLint that leverage TypeScript. They provide useful rules such as no floating promises or no-misused promises. But I know that these kind of plugins need to do something that ESLint can't provide, such as scanning the whole project, or the whole dependencies. Because these kind of rules need to understand not just the file that you have open on your editor. But they have to resolve types, dependencies. They have to do a lot of work in order to work. And that's something that ESLint doesn't provide out of the box, but Biome does. Biome, in this case, is able to scan your old project before starting the actual linting. It's able to collect a bunch of information so that we can provide powerful intros, such as no import cycles. It's able to fly over all the import tree of your project. And understand if you're actually importing the same, you're doing a cycle. It's able to scan your dependencies. It understands if you're using a dependency that is not installed on your package.json. One thing that, for example, I recently merged is a lint role that is able to understand if you're using a CSS class that is not defined anywhere. Biome is able to scan the whole project, CS files, JavaScript files, Vue files, all the files. It collects all the information, and then it does the lint rule that inspects, I don't know, your component, your div, or whatever, your element. It reads the classes that you used, and it checks if they're actually defined somewhere in your project. And if they're not, this says, "Oops, you're using a CSS class that it's not defined anywhere." And it's also able to show you the actual tree of components that they were analyzed. And that's something that is provided by the Biome module graph, which is language-agnostic in a sense. It's able to collect multiple languages, or files, or assets in the same time, like HTML, CSS, JavaScript, and so on. And I'm really proud of what they've done because it's something that the tools that we have today they're not able to do that. I mean, that I'm aware, of course. That's what Biome is able to provide that the current tools might lack or they don't provide out of the box. [0:38:11] JG: You've mentioned two big features now. There's typed lint rules out of the box. And then there's the Biome module graph. Talking about typed lint rules a little bit. How does that type information work in Biome? [0:38:22] ES: Yeah. In Biome, we've tried to do things differently because that's essentially our way of doing things. Providing something different from what you have. You can try it. Biome does something called type inference. It actually tries to collect and infer, as it says, the types of your code, of the JavaScript type files. The project and the efforts were led by another core contributor. And Vercel actually employed the contributor to actually ship the feature. It was a great community effort. And it required a lot of resources and time. But now we are able to ship lint rules that don't require the actual TypeScript compiler. You don't need TypeScript to understand if you're using incorrectly a promise. Or there's a dangling promise that you haven't awaited. How does it work? Well, essentially, the engine relies heavily on the model graph in order to essentially collect and read all the files that the project uses, as well as the dependencies. It's not just the project. But also, all the libraries involved in the application. And then there's a lot of work where it tries to flatten, for example, expressions, functions. I don't know all the details because the efforts were led by another co-member. But I managed to actually fix a couple of bugs there. Because the engine requires a lot of tools. Not just the model graph, but also the semantic model. Just the other day, I fixed a bug where Biome couldn't infer the type of dependency. There was import function from Lodash, for example. And it couldn't understand if it was a promise or not. And I fixed it the other day by integrating the semantic model into the inference system. Or I was able to ship the other rule called noUnecessaryConditions, which tells you, "Oh, you don't need to do this kind of check, because it's always true." You have a variable that is always true. It tries to infer when, for example, it changes value and things like that. And at the end, when there's the if or whatever, it tells you, "Oh, there's no need to do any check because this variable never changes. It's always true." I hope it answered your question. [0:41:07] JG: Very much so. You've mentioned another type of graph now, semantic graph. What's the difference between a semantic graph and a module graph? [0:41:13] ES: It's not called semantic graph, but it's called semantic model. The module graph is just essentially a data structure that just checks, "Okay. This module, this file is imported by this other file, and so on." It's very generic. It tells you what imports, what exports. And there it is. Nothing else. Semantic model is actually more specialized. It's not aware of other files. It's just aware of one file. And it's very specialized to the kind of file. In JavaScript, it specializes into understanding the various scopes inside a file. You have your GlobalScope, you have scopes inside the functions. Then you have your arrow function that don't have scopes. You have your classes. They have a different scope. That's what this semantic model does. For example, it checks as well if a binding is exported or not. It does very specialized things. For CSS, for example, it focuses on calculating the specificity of your classes. As you can see, it's very tied to the implied semantics of the language that you're rendering. Surely, we're going to have, for example, a semantic model for GraphQL. I don't know the language. Other maintainers have more expertise than me, but I know they're going to use it. They're going to create it so they can provide specialized rules. The model graph is just a big pile of data of all your files that you have. It's basically a tree, and branches, and leaves. And you have your edges. How they are connected to each other? It's mostly like a spider web. And you have to navigate it to understand to collect the information that you need. [0:43:17] JG: One of the difficulties with building lint rules, specifically in native speed code, is that many of the end users aren't native speed developers. What are you in Biome doing to solve that developer interoperability difficulty? [0:43:31] ES: Well, I mean, as we mentioned, Biome as a plug-in system to try to bridge the gap is a plug-in system based on this DSL called GritQL. It was chosen some time ago as a winner after a lot of discussion. We are aware that we can do everything. And there are some requirements that are project-specific. Things that belong to your arc, or to your employer, to your code base. That's where we think a plug-in is actually very useful. Because, also, your sensitivity data, things like that. You have this powerful DSL that Biome is able to interpret, and it has its own runtime. With these plugins, users are able to inspect the code. And just to let you know. Until now, these plugins were not able to provide code fixes. Until now, that's the rule. That's the diagnostic, there's the error, and that's it. We have now a PR that is able to actually provide a code fix. Probably in the next minor, a user will be able to create a lint rule that is able to autofix possible issues in their codebase. This actually kills my point where the plugins are bad. But I think in this case are actually valid. Because a tool cannot know everything. And it shouldn't. I shouldn't know about the quirks of your codebase because they're sensitive data. And that's where a plug-in makes sense. You leverage the tool, Biome, ESLint, Oxc, whatever. And you apply to your code base specifically to your needs because they belong to your project. [0:45:30] JG: It sounds like you could use code fixes from lint rules as a sort of code mod tool. [0:45:36] ES: Yes. Yes. Exactly. [0:45:39] JG: Love to hear that. That's really cool, though. There's already a Biome search command. And just looking through the biomejs.dev/reference/graql page, it's looks like you can do some pretty powerful matches with not that much syntax with GraQL. Have you seen a lot of developers pick this up and use it? [0:45:56] ES: I'm not into a lot of this part of the tooling. I know that there are users that have a 70 or more Biome plugins written in GraQl. I think like there are users that actually leveraging the plug-in system a lot. But yeah, GraQL was born as a code mod. That's why it's so powerful. And that's why it has a lot of weird syntax. Because one of the initial objectives was to create code mods. And essentially, that's what Biome could potentially do in the future. You could create your code mod to - I don't know. You have your React from 18, 19. There's a lot of changes. You have your code mod. Or even internally. You are changing stuff. There's a lot of refactor. Create your plug-in that does the code mod, run Biome, and there it is. [0:46:55] JG: Beautiful. Let's talk about the feature a little bit. What are some of the big, flashy upcoming features around Biome that you're excited about? [0:47:02] ES: Oh, that's nice, okay. There's a lot of going on, a lot of ideas. One is this lint rule that I talked about that is able to catch a news classes. It's still early stages because there's a lot of components. And the ecosystem is big quirks. The second thing that we're working on is the watcher. You can run Biome lint --watch. And then you can start typing. And Biome, at every change, it links the new file that you just change and it checks if there are some violations or not. And I think it also will work for the formatter. I mean, it's still in the early stages. And the reason why we're able to do that is because Biome is already a watcher under the hood. We are just exposing the watcher using the CLI. One other thing that we're doing, this is just third-party contributions. I'm not doing that much. Plugins that will be able to emit code fixes. And they will be able also to set the severity. Until now, user, they couldn't do much. Now we are making plugins more powerful and customizable to our users. We are working towards markdown support. Internally, we reached 100% coverage against common mark. This is also done by another third-party contributor. That's amazing. I'm just essentially reviewing PRs and contributing with them. There's an effort at the moment doing a refactor of the parser while keeping the conformance to CommonMark to 100%. And we are setting up the formatter at the moment. If everything goes well, it's going to be part of the next minor. Yeah. I mean, we're doing lot of lint rules for Vue. And also, Svelte, probably we're going to start creating some lint rules now that we have a very good handle on the Svelte syntax. Now we can start shipping some lint rules for them. For Astro, I still need to investigate. I know there's an ESLint plugin for Astro, but I'm not familiar with the rules. But probably there's a room for implementing something there as well. [0:49:25] JG: It would be nice if the leader of the Astro project and the leader of the Biome project knew many of the same people together. [0:49:32] ES: Ah, yes. Which is me. [0:49:37] JG: Well, great. One of the interesting notes you brought up was editor support. Can you tell our users what is LSP and what does that mean in this context? [0:49:47] ES: Sure. LSP stands for language server protocol. As the acronym says, it's a protocol to essentially create an editor server that works in all editor clients. Nowadays, the vast majority of editor clients support this protocol. So, VS Code, Zed, WebStorm, and all the IntelliJ. Sorry. JetBrains, IDEs, Vim, Elix. All of them now support LSP. And this is actually quite powerful because we just need to develop the server in one place. And the DX is the same in essentially all the editors. One of the Biome's mission is to focus LSP as well. To provide an all-in-one experience, which means that we implement the business logic in one place. And then you get the same look and feel on the CLI, the LSP in the playground. Any client. Because Biome is essentially a server, you have multiple clients. And that's what we do for our diagnostic. What you see in the CLI is the same thing that you see in your editor. Something that we could potentially do in Biome that other tools can't do is to leverage the model graph to implement things like the go-to. You have your function, you want to know where it's defined. You do common click. And it takes you to the definition. That's something that Biome potentially could do. There's endless possibilities with Biome because everything is central. We own the stock. We own the information. But still it requires essentially the time. I'm setting up essentially the whole infrastructure. I have a lot of ideas. I just need the time to implement them. Now with these AI agents, I get to do things quickly because they just write the code and they review it. Yeah, hope it answered your question. [0:51:58] JG: That does. Before we start to wrap up, are there any other big-ticket features or fixes from Biome that you're excited about in the coming years? [0:52:05] ES: No. I really want to do a shout-out to the actual community. Because a lot of fixes, a lot of new features have been developed by other people that aren't the core team. Biome is essentially a community effort. We are just essentially the orchestrators and the manager. But we are seeing a lot of people sending fixes, sending features. As I said, the markdown parser has been done by another person. The formatter as well. We are actually also working on CSS support, SaaS support. Yeah. I mean, I want to do a shout-out to all the contributors. Because a lot of things that you're using and other people are using have been shipped and created by the community, essentially. [0:52:56] JG: Let's talk about the community then. Biome's been around for a few years now. It's outlasted Rome. It's clearly sustained itself. How have you been able to build a community where so many open source projects aren't? [0:53:08] ES: Well, I feel Biome as a concept attracted a lot of people, as I was. That's just one of the reasons. The second, I don't know. I have some experience in open source. I'm involved in other communities. I learn from the other communities, and I apply it to the Biome's community. I try to be friendly every time. It's not easy. That's actually very difficult as a maintainer to keep your cool. And I know that sometimes I wasn't able to. And, also like you have to be active. We have our Discord chat. And if you're able to answer questions as quickly as possible, people eventually acknowledge that, and they like it. Because sometimes you are in a project. You file an issue, or you ask a question, and then basically you don't get an answer for weeks. I think that's where I try to focus on quick feedback if I'm able to. And I think like this is paying off, because users are seeing that activity. They see that their problems are solved, their questions are answered. Or maybe we don't have the answer, but at least there's some discussion. Something moves every single time. [0:54:31] JG: There's something to be said about positivity. You join the Biome discord, and there are all these fun channels, there are lots of emojis, exciting announcements. It feels like a very big project and a fun place to be. [0:54:41] ES: Yeah, we try. We try to be active, to be positive. Yeah, as you said, to communicate. That's also something that, since day one, I wanted to do. If there's something about Biome, anything related, just share it. Or even if it's not about Biome, share it. You have a link that you like, just drop it, and people like it because it's something nice to read. That's essentially the mentality. You are there. You want to share something, do it. You are more than welcome to do so. [0:55:14] JG: Lovely. Let's say that I'm a listener with a large codebase, complex formatting, linting, and so on. How would I get started trying to switch things over or to evaluate to Biome? [0:55:26] ES: Biome has a couple of commands that allows you to read the config from ESLint and Prettier and create a Biome config that matches as much as they can what you had before. Of course, we don't have all the ESLint rules, but at least something. Second, you can actually do a first pass of your linter by suppressing all the violations. Because you might have a lot of violations in your whole code, in the big code base. You do biomelint--suppress--suppressreason, and say migration or whatever, and you're good to go. Maybe you can also turn off the formatter if you want. But we match 97% of Prettier's formatting, so you should be good to go. But at least the linting is there. It doesn't scream at you. And you can keep your code base there. And then you can progressively address lint rules as you go. That's essentially what you could do for your migration. If you have a lot of formatting problems, one technique that I usually suggest is to have a PR. Make sure the CI is green, merge it, and then goes with another PR that ignores the comment of formatting. Your history is not mangled by the formatting. We do the same also in the Biome repository. When you have these trivial changes that don't bring anything to the table, you ignore that commit, that hash, so that your history is the blame. When you do a blame of the file, it doesn't show any meaningless information. [0:57:13] JG: That's a great tip. You're talking about git revision ignoring? [0:57:16] ES: Yes, exactly. There's a git file where you essentially can list all the commits that you want to ignore. And those commits won't appear in the history of your git blame. [0:57:29] JG: Great. Let's say that I have a new project, and I want to get started fresh with Biome. How is that different? [0:57:33] ES: You start Biome, and you're good to go. You could run Biome in it, which bootstrap a Biome config for you, which essentially mirrors our defaults. It might be lengthy, but at least you can see what are our defaults. You don't need to go to the website. And you can understand what's the default, and then you can change it, like tabs versus spaces, lint rules, and so on. Other than that, we ship also a really nice tool called Biome Explain from the CLI, where you can just type Biome Explain noDebugger, and it shows you the docs right in the CLI. If you don't have any connection, the name of the internet connection, and you don't want to go to the website, you just type that command, and you can see what the lint rule does for you. [0:58:32] JG: Speaking of which, that website is biomejs.dev. Yes? [0:58:36] ES: Yes. [0:58:37] JG: Great. Are there any other resources or links you'd want to send people to if they wanted to learn more about Biome? [0:58:42] ES: I think the website is quite self-explanatory. Also, the main GitHub repo. It's also a nice resource. Yeah, we try to be central. We try to have everything in one place. And the website is where everything goes. And our Discord, biomejs.dev/chat, and you should be good to go. [0:59:03] JG: Excellent. I like to end interviews with one non-work question. You mentioned at the very beginning that you were interested in video games. What games are you playing these days? [0:59:12] ES: So, at the moment I'm playing Assassin's Creed: Shadows. I'm not a big fan of the whole saga, but I like the last video games there because they're really focus on role-playing. So you have your character. You choose your skill that you want to develop, your weapons, skills, and things like that. It's also in Japan, which I really like. It's a really nice mix of things. I really like role-playing, so GDR and things like that. RPG essentially. I'm not into sports or shooting. I really like RPGs. Yeah. [0:59:49] JG: Fun. Are there any lessons you've learned in programming that apply to the stories of these video games or vice versa? [0:59:57] ES: If you want to learn how to do video game, you have to do it yourself. Just do it yourself, like a lot of people do. Indie video games. That's how I think you should start. I mean, I tried the university, it didn't pan out. So, do it yourself if you have the passion and the time. I don't have the time anymore. That's the only problem. But if you have the time and the passion, do it yourself. I mean, with the tools that we have nowadays, I think it's quite easy to pick up. [1:00:30] JG: All you need is time, interest, and energy. [1:00:32] ES: Yes. [1:00:34] JG: Well, great. Ema, this has been wonderful. Thank you for walking us through your history, and Biome, and all the fun things around analyzing and linting that come with it. If people wanted to learn more about you specifically, where would you direct them to go on the internet? [1:00:45] ES: They can go to my Bluesky account, ematipico.xyz, and the GitHub account. Yeah. I mean, that's essentially where you can find me and where I'm active. I'm not a real social person. I like to lurk. And I engage less. [1:01:06] JG: Excellent. Well, thank you for all the info. For Software Engineering Daily, this has been Ema and Josh Goldberg. Cheers, everyone. [1:01:13] ES: Thanks. [END]