№ 02 · Writings · essay

A Node.js Developer's Journey into Python Territory

Navigating Python's ecosystem as a Node.js developer — package management, virtual environments, and the tools that bridge the gap.

Published
Read
2m
Contents

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.

# requirements.txt - Python's answer to package.json dependencies

flask==3.1.0
requests==2.32.3
SQLAlchemy==2.0.40

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.txt for production dependencies
  • requirements-dev.txt for development tools
  • Makefile or 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.

# Adding to requirements-dev.txt

black==25.1.0

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.

# A typical .flake8 configuration

[flake8]
max-line-length = 88
extend-ignore = E203
exclude = .git,__pycache__,build,dist

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:

def get_user(user_id: int) -> dict:
    """Retrieve user data from the database."""
    return {"id": user_id, "name": "John Doe", "active": True}

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:

# Find unused code

vulture my_project/

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.

# Makefile

.PHONY: format lint test clean

format:
 black src tests

lint:
 flake8 src tests
 mypy src

test:
 pytest tests/

clean:
 rm -rf __pycache__/ .pytest_cache/ .mypy_cache/

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:

# Creating and activating a virtual environment

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

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:

  1. Set up a virtual environment for each project
  2. Create separate requirements files for production and development
  3. Configure Black, Flake8, and MyPy for code quality
  4. Use a Makefile for common tasks
  5. Set up pre-commit hooks for automated checks
# A typical development setup

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
make format  # Run Black
make lint    # Run Flake8 and MyPy

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.