Skip to content

Why MOFA Architecture?

Our Architectural Philosophy

MOFA architecture is designed to be our shared foundation—making everyone’s life easier, not adding friction.

Our team faced several challenges when building Flutter applications:

  • Inconsistent Patterns: Each developer followed their own approach, leading to unpredictable code structure
  • Repetitive Work: Constantly reinventing solutions for common problems like state management, data fetching, and caching
  • Difficult Code Reviews: Similar features resulted in vastly different implementations, making PRs hard to review
  • Onboarding Friction: New team members struggled to understand different patterns across projects
  • Maintenance Burden: Long-term projects became increasingly difficult to maintain and extend

We realized we needed a systematic approach when:

  1. Feature Development Slowed: Simple features took longer because developers had to make architectural decisions from scratch
  2. Bug Introduction Increased: Lack of testing standards led to regressions when adding new features
  3. Knowledge Silos Formed: Each project had its own “expert” who understood its unique patterns
  4. Cross-Project Movement Became Difficult: Developers couldn’t easily switch between projects

Problem: Each project had different folder structures, naming conventions, and architectural patterns.

Solution: Standardized four-layer architecture with clear responsibilities and boundaries.

Result: Developers can move between projects confidently, knowing exactly where to find and place code.

Problem: Teams constantly reimplemented GraphQL clients, state management, caching, and error handling.

Solution: Reusable patterns and generic packages that solve common problems once.

Result: Focus shifts from infrastructure to business logic and user features.

Problem: Similar features resulted in completely different implementations, making code reviews inconsistent.

Solution: Standardized patterns for services, notifiers, repositories, and UI components.

Result: Code reviews focus on business logic rather than architectural decisions.

Problem: Without clear boundaries, business logic leaked into UI components and data access mixed with presentation.

Solution: Strict layer boundaries with defined responsibilities and data flow.

Result: Clean separation of concerns that’s easy to test and maintain.

Problem: Tightly coupled code made testing difficult and deployment risky.

Solution: Modular architecture with comprehensive testing strategy focused on critical areas.

Result: Rapid iteration with confidence in code quality.

Problem: Projects became increasingly difficult to maintain as they grew in complexity.

Solution: Clear architectural boundaries, comprehensive documentation, and evolution-friendly patterns.

Result: Projects remain maintainable and extensible over years of development.

Why Four Layers?

We experimented with different approaches:

  • No Architecture: Fast initially, but became unmaintainable
  • Three Layers: Lacked clear separation between business logic and data access
  • Five+ Layers: Over-engineered for Flutter applications, added unnecessary complexity

Four layers provide the sweet spot: Clear separation without over-engineering.

The Problem: Ferry’s documentation examples create circular dependencies with Riverpod:

  • client → cache handlers → requests → client dependency cycle
  • Ferry assumes global definitions, but real-world needs dynamic state
  • Cannot use Riverpod providers with Ferry’s trivial examples

Our Solution: Strategy pattern with DatasourceModule that:

  • Eliminates circular dependencies
  • Enables context-aware cache operations
  • Supports dynamic state in GraphQL operations
  • Maintains type safety and code generation benefits

Caching Service Instead of Local Storage Datasource

Section titled “Caching Service Instead of Local Storage Datasource”

The Problem: Traditional approaches mix data access concerns:

  • Local storage logic scattered across repositories
  • Difficult to implement different caching strategies
  • Testing becomes complex with mixed responsibilities

Our Solution: Dedicated caching service with three types:

  • Secure Cache: For sensitive data (tokens, credentials)
  • Simple Cache: For basic data (preferences, settings)
  • Complex Cache: For advanced scenarios (offline sync, TTL)

The Problem: Generic “core” packages become dumping grounds:

  • Mixed concerns in a single package
  • Tight coupling between unrelated utilities
  • Difficult to test and maintain

Our Solution: App-specific core folder containing only:

  • Features that other features depend on (Auth)
  • Shared infrastructure (Router, Service Locators)
  • Configuration (Flavors, App Settings)
  • Increased Confidence: Developers feel confident making changes across projects
  • Better Collaboration: Shared vocabulary and patterns improve team communication
  • Reduced Stress: Clear guidelines eliminate decision paralysis
  • Higher Quality: Consistent patterns lead to more robust applications

MOFA architecture isn’t static—it evolves based on:

  • Team Experience: Lessons learned from real projects
  • Technology Changes: Updates to Flutter, Dart, and ecosystem packages
  • Project Requirements: New challenges that require architectural adaptations
  • Community Feedback: Insights from other teams and open source contributions

We regularly review and update our architecture through:

  • Weekly Architecture Reviews: Discuss patterns and improvements
  • Monthly Deep Dives: Analyze specific architectural decisions
  • Quarterly Planning: Major architectural changes and technology evaluation
  • Project Retrospectives: Learn from successes and challenges

MOFA architecture works best for:

  • Team Development: Multiple developers working on the same codebase
  • Complex Applications: Apps with significant business logic and data management
  • Long-term Projects: Applications that will be maintained and extended over time
  • Multiple Projects: Teams building several related applications

MOFA architecture might be overkill for:

  • Prototypes: Quick experiments or proof-of-concepts
  • Short-term Projects: Applications with limited lifespan

If MOFA architecture sounds right for your team:

  1. Start with Tutorials: Learn the fundamentals through hands-on examples
  2. Read the Explanations: Understand the reasoning behind each decision
  3. Use How-to Guides: Implement specific patterns in your projects
  4. Reference Documentation: Look up details as you build

Remember: Architecture should serve your team, not the other way around. Adapt these patterns to fit your specific needs and context.

Living Documentation

This architecture evolves with our team’s experience. Found something that doesn’t work? Have a better approach? Let’s discuss it! Every improvement makes our shared foundation stronger.