Index | Previous: The Human Aspect
Being pragmatic means making decisions that work in the real world, not just in theory. The JavaScript and broader development ecosystem has a tendency toward over-engineering and dependency accumulation that can cripple long-term maintainability.
Every dependency you add is a liability. It's code you don't control, with its own bugs, security vulnerabilities, and breaking changes. Before adding a package, ask yourself:
- Can I write this myself in under 100 lines? - If yes, consider doing so
- How many transitive dependencies does this bring? - Check with
npm lsor similar - Is this package actively maintained? - Check last commit date and open issues
- What's the download size impact? - Use tools like Bundlephobia1
The JavaScript ecosystem is particularly prone to "left-pad"2 situations where trivial functionality is packaged as dependencies. A package to check if a number is odd, a package to pad a string: these create fragility without adding real value. David Haney's analysis3 of the npm ecosystem's issues is worth reading.
Practical guidelines:
- Audit your
node_modulesregularly. Tools like npm-audit4 and Snyk5 can identify vulnerabilities. - Prefer standard library functions over utility packages
- Be sceptical of packages with dozens of dependencies for simple tasks
- Consider vendoring small, stable utilities rather than depending on them
- Use Socket.dev6 to analyse supply chain risk
Adopting a framework is a marriage, not a date. Once your codebase is built around Express7, NestJS8, or any other framework, migrating away is expensive. Consider:
- Keep business logic framework-agnostic - Your domain logic should not import Express types
- Use ports and adapters9 - Abstract your HTTP layer from your business logic (also known as Hexagonal Architecture10)
- Prefer libraries over frameworks - Libraries you call; frameworks call you. See Martin Fowler on Inversion of Control11.
- Evaluate longevity - That hot new framework may be abandoned in two years
The more your code depends on framework-specific patterns, the harder it becomes to:
- Switch frameworks when better options emerge
- Test business logic in isolation
- Reuse logic across different contexts (CLI, serverless, etc.)
Sometimes the pragmatic choice is to not build at all. Before implementing custom authentication, rate limiting, or API gateways, consider whether managed services or existing solutions fit your needs. But weigh this against:
- Vendor lock-in - Can you migrate away if needed? See CNCF's guidance on avoiding lock-in12.
- Cost at scale - Cheap at low volume doesn't mean cheap at high volume
- Complexity - Does the "simple" solution actually simplify things?
- Control - What happens when the service doesn't do exactly what you need?
The Thoughtworks Technology Radar13 is useful for evaluating technology choices and understanding industry trends.
AI tools like Claude14 can significantly accelerate API development when used pragmatically:
- Design review - Have AI review your OpenAPI15 specs for consistency and best practices
- Boilerplate generation - Generate repetitive CRUD handlers, validation schemas, and tests
- Documentation - Generate endpoint descriptions and examples from code
- Refactoring - Identify inconsistencies across endpoints and suggest standardisation
However, maintain human oversight. AI can generate plausible but incorrect code, especially around security, authentication, and edge cases. Use AI to accelerate, not to replace understanding. See OWASP's guidance on AI security risks16.
Written by Philip A Senger | LinkedIn | GitHub
This work is licensed under a Creative Commons Attribution 4.0 International License.
Previous: The Human Aspect | Next: Security and Permissions
Footnotes
-
Bundlephobia. "Find the cost of adding a npm package to your bundle." https://bundlephobia.com/ ↩
-
npm Blog. (2016). "kik, left-pad, and npm." https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm ↩
-
Haney, David. (2016). "NPM & left-pad: Have We Forgotten How To Program?" https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-program/ ↩
-
npm Documentation. "npm-audit." https://docs.npmjs.com/cli/v8/commands/npm-audit ↩
-
Snyk. "Developer Security Platform." https://snyk.io/ ↩
-
Socket. "Secure your JavaScript supply chain." https://socket.dev/ ↩
-
Express.js. "Fast, unopinionated, minimalist web framework for Node.js." https://expressjs.com/ ↩
-
NestJS. "A progressive Node.js framework." https://nestjs.com/ ↩
-
Cockburn, Alistair. "Hexagonal Architecture." https://alistair.cockburn.us/hexagonal-architecture/ ↩
-
Wikipedia. "Hexagonal architecture (software)." https://en.wikipedia.org/wiki/Hexagonal_architecture_(software) ↩
-
Fowler, Martin. "Inversion of Control." https://martinfowler.com/bliki/InversionOfControl.html ↩
-
Cloud Native Computing Foundation. (2018). "6 Considerations for Avoiding Lock-in When Using Cloud Native Services." https://www.cncf.io/blog/2018/03/07/6-considerations-for-avoiding-lock-in-when-using-cloud-native-services/ ↩
-
Thoughtworks. "Technology Radar." https://www.thoughtworks.com/radar ↩
-
Anthropic. "Claude - AI Assistant." https://www.anthropic.com/claude ↩
-
OpenAPI Initiative. "OpenAPI Specification." https://www.openapis.org/ ↩
-
OWASP. "AI Security and Privacy Guide." https://owasp.org/www-project-ai-security-and-privacy-guide/ ↩