Jerod and Divya welcome npm CTO Ahmad Nassri to discuss modular architecture. What it is, why it matters, and how you can achieve it. Ahmad has been thinking deeply about this topic lately and we have a very fruitful discussion that should have takeaways for developers of all experience levels.
Ahmad Nassri: [15:56] I think this is a nuanced approach, but thereās a number of different ways people interpret modularity and modular software in general⦠Especially in the JavaScript world, when you use the word āmoduleā or āmodularā, people will either think of a package, or a package resolution methodology, as in with ESM, or otherwise. What Iām talking about when I talk about modularity - Iām talking to the age-old philosophy that started with the Unix philosophy all the way back in 1978, or something like that, where it talks about how you write code and how you write software, and some principles around that.
If I recall correctly, the 4-5 principles there was that in order to make modular software, number one is you make each program do one thing really well; everything has one job, and one job only. I think number two was there was like an output/input exchange, so every output of every program should become the input to another. If youāre ever used Unix or Linux and you pipe operations between command lines, youāre very familiar with those kind of approaches. Again, this is from 1978, so the very early days of computing.
But the things that I find most valuable, especially in the context of software as a social practice, that we all do - the tools and the way you build your tools and products and all these principles should be tailored to make sure that you [unintelligible 00:17:17.25] the programming task to other maintainers⦠And the idea that everything should be easily maintained and repurposed by developers other than the people who created it. So we would not be successful in the software industry if the person who wrote the code the first time is the only person whoās gonna be able to maintain it forever.
Thatās why we have documentations, and we have practices, we have guidelines of how to actually make software repurposable and shareable by others, and thatās why we have patterns like forking, and cloning, and sharing code⦠Because the whole point of all of this is that at the end of the day software is about people, and you wanna make it so that some of these practices around modularity - you wanna make it so that itās easy for others to come and repurpose or refactor or use your software without having to go through tomes of manuals and understanding all your individual authorās purpose and knowledge.
I think one other one that we all suffer from every day is ā you know, one of the principles of the Unix philosophy was everything should be designed in a way that you can just throw it away and rebuild it⦠And as you know, in a monolithic world view, thatās not such an easy thing to do. But as you focus on building smaller and smaller units of code, and build them in a modular fashion, that is everything does one thing very well, every part of the program becomes an input to another, everything can be rebuilt and thrown away, and most importantly, itās built in a way that others can just come in, understand it, do any changes or fixes and move away without having to spend years and sync up with [unintelligible 00:18:48.13] and everything.
To me, those are the key philosophy areas where the ā again, the Unix philosophy did this very well back in 1978. But in todayās world we havenāt really matured that enough. We talk a lot about - especially in the JavaScript world - packages and sharing, and libraries and code, but we still have these big monolithic libraries, we still have these big, complex frameworks. And although weāve done very well on things like sharing and making code repurposable by others other than the original maintainers, I think weāre still lacking some maturity around āHow does our software become portable? How do our libraries become interchangeable?ā So for me, when I talk about modularity, I talk about these kinds of topics in the general sense. And then I start talking a little bit about how to become more specific in nature about solving these problems. And just for context, people seem to like modular code; thereās no debate about that. I donāt think anybody goes into their day-to-day job and talk about building the next monolith.
I think thereās a valid debate in terms of monolithic approach to deployment and infrastructure and maintenance, but thatās separate than writing code and thatās separate than how you design your systems.
[20:09] From a numbers perspective - and this is something everybody sees every day when they go to npmjs.com, we are now at 1.159.000 packages, and these are just the open source ones. And Iām always curious by that number. Iāve always been curious about it from before I even joined npm, why are there so many packages; why does the JavaScript community create such a prolific amount of code and software to share? The answers that I came up with just based on my own personal observations is that we in the JavaScript community have had a good run of satisfying some of those human requirements, making things so easy to throw away and repurpose, making things so easy for a newcomer to jump in and get on board, making things simple and clean, and building one thing that does one thing very well, and not be concerned with big, complex challenges across different domains. Thatās why we have so many packages, thatās why we have such a big JavaScript community. Thatās what made my career, and thatās what made a lot of other peopleās career, and itsā wonderful.
I think the challenge though - and coming back to our enterprise examples over here⦠The challenge is weāve solved that in the open source world, but we havenāt solved it in a way that informs a method of building software. All of this so far has been about libraries and code packages, and patterns around that. But I havenāt seen it being adopted very widely in the way we build software at companies or at work.
So the approaches of modularization, and whether you wanna go down the path of packaging, or microservices, or any of those topics, or even the serverless world today, thereās a real pattern here to adopt, and I think - again, taking the JavaScript example, weāre in a world where JavaScript runs everywhere. Myles Borins from Google has a talk yesterday at Node+JS Interactive where he was talking about universal JavaScript. Universal JavaScript is just a new term that weāre talking about where the whole premise is you write once and run anywhere.
Weāre in a world now where JavaScript is running in the browser, in your server in Node.js, you can write JavaScript on edge workers, on companies like Cloudflare, you can put them in your databases, even in productivity software like Google Spreadsheets - you can run some app scripts in there, you can do that I think in Excel nowadays⦠If youāve gone to NodeConf EU this year, they gave out smart watches that were just running JavaScript⦠So thatās great, JavaScript is successful. But what about the portability of those software code and libraries that are being created? What about the developer experience associated with them? Wouldnāt it be great ā and I think thatās the promise of JavaScript, that you can write the same software that can run in your browser, and on your smartwatch, and in your Excel spreadsheet. But the reality is thereās a lot of work involved in getting that to happen, and weāre kind of offloading a lot of that work to the developer whoās responsible for doing this. But we havenāt come up with the patterns yet of how to approach those things. I think this is where to me the Unix philosophy from so many years ago kind of touches on the key ingredients required to get there. I donāt necessarily have answers in this space, but I love asking the questions, so we can have a dialog and a debate in these conversations.
The one pattern I have noticed in terms of modernizing the way we adopt these Unix philosophies just so happens to be around package management. Itās not because I work at npm and thatās my day-to-day responsibility, but itās true. Youāve seen the success of things like React, where people are now building design systems and iterating on them at such a large scale, and involving not just developers, but now designers, and UX designers in this kind of workflow. Thatās becoming more and more attainable, and nowadays you have tools that are meant for designers that are generating the code, and generating it in a way thatās a package that is shared and distributed in a community within your company or your clientsā environments right off the bat.
[23:57] You donāt even need to write the code anymore, you can just have a designer drag and drop some things. I think the company is called Framer. I know other folks in the industry are looking at this as well; I think InVision and others are playing an interesting part in all of this⦠But this idea of modularization is beyond just the software and the code. It extends to UX designers, it extends to product design, it extends to every aspects of technology. I think, again, we in the JavaScript community have kind of solved or addressed that problem in a very efficient way with package management and packages in general. It would be great to start seeing that pattern being adopted more widely and more ā I donāt wanna call it standard, but perhaps best practices around these ideas and patterns in the day-to-day work of people.
I know Iāve done this before, again, when I mentioned the enterprise space - when we have teams as large as 450 people, itās not gonna be about just publishing a new version and expecting it to work. Thereās a lot of workflow involved, thereās a lot of operations involved, thereās a lot of maintenance and upkeep and analytics involved. A design system with one component that has a button in it might have 15 different versions, but the adoption of it is all over the map, and we end up spending a lot of our time as community moderators and architects of the design systems, and the companies just arenāt chasing that down and trying to get the adoption going.
The way the software is built is really relying on those patterns, or at least it should become more and more embedded in the way that software is being designed, whether itās a monolithic design or a microservices design.
The other interesting area of this - Iām using design patterns as an example because itās an easy one to point at - but now weāre in the world of serverless; now weāre in the world of literally function-as-a-service. While you can deploy a big monolithic application as a serverless application and do that, you probably shouldnāt⦠But now, more and more, we as software developers, especially in a server-side context, are thinking of smaller units of code that have to be built and orchestrated and talk to each other through an events system to create the result and the output of our product. So again, those modular best practices keep coming back time and time again in all the areas of the software industry and all the different things that weāre doing.
I have a lot of questions that I get through the npm community, oddly enough, from people who are using npm in embedded systems, and theyāre asking about best practices of āWell, how do we do package management and download big React libraries, or Lodash libraries and run them on these systems? ā¦because thereās not enough memory, thereās not enough processing power.ā And the answer is perhaps those libraries and those tools were not built to support those embedded system challenges, but the modularization approach allows you to have a more nuanced approach of like āI want this part of this library, I want this part of this framework, and I can just then put them together, create a modular pattern where every piece is responsible for its own logic, and the output of one can help the input of the other, and create kind of a workflow chain of how my system is gonna be designed and work. And hey, if something doesnāt work, maybe I can just throw it away, bring another library in or another part of that module in, and it will still function the same way. I donāt have to refactor my entire codebase. Thatās the future I wanna see.