Skip to main content
01

A Node.js Developer's Journey into Python Territory

·3 min read
PythonNode.jsJavaScriptDevOpsCross-Platform

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.

python
# 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.

bash
# 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.

bash
# 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:

python
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:

bash
# 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
# 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:

bash
# 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
bash
# 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.