My first serious Python project as a Node.js developer was disorienting. The package management, the project structure, the development workflow — everything worked differently. Some of it was better. Some of it was frustrating. All of it was worth understanding.
The Cultural Shock: Package Management
Coming from npm's package.json and node_modules, Python's approach to dependencies took some adjustment.
What struck me immediately was the absence of a central configuration file that handled both dependencies and scripts. Instead, Python projects typically separate these concerns:
requirements.txtfor production dependenciesrequirements-dev.txtfor development toolsMakefileor scripts for automation
This separation offers flexibility but requires a mental shift when you're used to having everything defined in a single manifest file.
The Python Development Trinity: Black, Flake8, and MyPy
If ESLint and Prettier are the guardians of JavaScript code quality, Python has its own set of defenders:
Black: The Uncompromising Formatter
Black is Python's Prettier — it formats your code with minimal configuration options. That turned out to be exactly what I needed.
No more style debates. Black just works.
Flake8: The Linter
Flake8 combines multiple Python linting tools into one package. It identifies potential bugs, enforces style guides, and checks for code complexity.
MyPy: Type Checking Without TypeScript
MyPy is Python's static type checker. Coming from TypeScript, this was the tool I was most relieved to find:
MyPy catches type-related bugs before runtime — familiar territory for TypeScript developers.
The Unsung Hero: Vulture
One tool I didn't initially appreciate was Vulture – a utility that finds unused code. In large JavaScript projects, tree-shaking often handles this automatically, but Python's dynamic nature makes dead code detection valuable:
Vulture has caught abandoned functions I would have maintained indefinitely.
Automation: The Makefile Renaissance
In JavaScript projects, npm scripts handle most automation tasks. Python developers, however, often reach for a much older tool: Make.
A Makefile is a simple, language-agnostic command registry — useful when projects mix Python with other technologies.
Virtual Environments: The Node.js Dev's Confusion
The concept that took longest to appreciate was virtual environments. In Node.js, dependencies are project-scoped by default. Python requires explicit isolation:
It felt like extra overhead until I hit dependency conflicts between projects. Now I see virtual environments as a more transparent version of what npm does behind the scenes.
Bringing It All Together: My Python Development Workflow
After months of exploration, I settled on a workflow that feels natural for a Node.js developer working in Python:
- Set up a virtual environment for each project
- Create separate requirements files for production and development
- Configure Black, Flake8, and MyPy for code quality
- Use a Makefile for common tasks
- Set up pre-commit hooks for automated checks
Final Thoughts
The biggest lesson from crossing ecosystems: work with the language's approach instead of fighting it. Python's philosophy — explicit over implicit, one obvious way to do things — is different from Node.js, but the goal is the same: clean, maintainable code that solves real problems.
I initially tried to make Python feel like Node.js. The setup got better once I stopped.