From Python to Rust - Building a Production Web Application

Learning Modern Web Development Through Dancexam

By Corrado R. Mazzarelli

This article explores my journey learning production-grade web development while creating Dancexam, a tool for dance communities to administer and grade progression tests. The application is live at dancexam.corradomazzarelli.com, with a demo at dancexam-demo.corradomazzarelli.com. The source code is available on GitHub.

Dancexam Logo

The Learning Challenge

After building the Dance DJ Assistant in Python/Flask, I wanted to push myself further by learning Rust and modern web development practices. Dancexam became my vehicle for this learning journey, presenting several challenges:

  1. Learning Rust’s unique concepts (ownership, borrowing, lifetimes)
  2. Understanding modern web architecture
  3. Implementing proper DevOps practices
  4. Managing a production application

The Technology Stack Journey

Why Rust?

Coming from Python, choosing Rust was intimidating but offered several benefits:

  1. Type Safety: Catch errors at compile time rather than runtime
  2. Performance: Near-C speed without manual memory management
  3. Modern Tooling: Cargo’s package management and build system
  4. Growing Web Ecosystem: Emerging frameworks like Axum
  5. Learning Opportunity: Deep understanding of systems programming

Learning Rust for Web Development

The Initial Struggle

The first weeks were challenging:

// Early attempts at handling web requests
async fn handle_submit(
    State(state): State<Arc<AppState>>,
    Form(form): Form<TestSubmission>,
) -> Result<impl IntoResponse, Error> {
    // Fought with ownership, borrowing, and async concepts here
}

Key learning moments:

  • Understanding ownership vs. borrowing
  • Managing shared state with Arc
  • Handling async operations properly
  • Implementing proper error handling

Choosing the Stack

After research and experimentation, I settled on:

  1. Axum: Lightweight, performant web framework
  2. HTMX: Modern frontend interactivity without JavaScript
  3. Askama: Type-safe templating
  4. PostgreSQL: Robust data persistence
  5. SQLx: Type-safe SQL queries

Learning each technology taught valuable lessons:

Axum

  • Route handling and middleware
  • State management
  • Error handling patterns
  • Request validation

HTMX

  • Progressive enhancement
  • Server-side rendering
  • Dynamic UI updates
  • Reducing JavaScript complexity

Askama

  • Type-safe template rendering
  • Rust macro system
  • Build-time template validation

DevOps Learning

The project pushed me to learn modern DevOps practices:

Docker & Containerization

# Learned multi-stage builds for efficiency
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bullseye-slim
COPY --from=builder /app/target/release/dancexam /usr/local/bin/
CMD ["dancexam"]

CI/CD Pipeline

  • GitHub Actions for automated testing
  • Automatic deployment on merge
  • Environment management
  • Secret handling

Database Management

  • Migration management
  • Backup strategies
  • Connection pooling
  • Query optimization

Key Technical Challenges

Type-Safe Database Queries

Learning to use SQLx’s compile-time checked queries was a game-changer:

// Compile-time SQL verification
let test_result = sqlx::query!(
    "SELECT * FROM test_results WHERE id = $1",
    id
)
.fetch_one(&pool)
.await?;

Async Programming

Understanding Rust’s async/await required learning:

  • Future traits
  • Async runtime (Tokio)
  • Proper error propagation
  • Resource management

Configuration Management

Implementing flexible test definitions through YAML:

tests:
  -
    metadata:
      test_name: "Standard Leader Test"
      config_settings:
        live_grading: true
        show_point_values: true
      minimum_percent: 0.60
      max_score: 98

    tables:
      - sections:
        - name: "Pattern Scoring"
          scoring_categories:
            - name: "Footwork"
              values: ["Perfect", "Variation?", "Right Concept", "Nope"]
            - name: "Timing"
              values: ["On", "Off"]
          competencies:
            - name: "Starter Step"
              scores: 
                - [3, 2, 1, 0]
                - [1, 0]
              failing_score_labels: 
                - scoring_category_name: "Footwork"
                  values: ["Nope"]

Lessons Learned

  1. Type Systems Matter: Rust’s type system caught countless errors before production
  2. Testing is Crucial: Automated testing saves time and reduces stress
  3. Documentation is Key: Clear documentation helps both users and future maintainers
  4. Start Simple: Building features incrementally keeps the project manageable
  5. Community Matters: The Rust community was invaluable for learning

Mistakes Made

  1. Over-engineering: Initially tried to make everything perfect
  2. Insufficient Planning: Should have spent more time on architecture
  3. Delayed Testing: Should have implemented testing earlier
  4. Complex Deployments: Initially made deployment too complicated

Conclusion

Building Dancexam was a transformative learning experience. It pushed me far beyond my comfort zone with Python/Flask development into the world of systems programming and production web applications. The journey from concept to production taught valuable lessons about software architecture, testing, deployment, and maintenance.

Most importantly, it showed that diving into challenging technologies like Rust, while initially daunting, can lead to more robust and maintainable applications. The project continues to serve the dance community while providing ongoing learning opportunities in web development and systems programming.

For developers considering a similar journey, I recommend:

  1. Choose technologies that push your boundaries
  2. Build something useful for a real community
  3. Focus on fundamentals before optimization
  4. Embrace testing and automation early
  5. Document your learning process

The application continues to evolve, serving as both a practical tool for dance communities and a platform for exploring new technologies and techniques.

Share: Twitter Facebook LinkedIn