Skip to content

bosornd/todo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ToDo Application

A Flutter-based todo application demonstrating three different approaches to developing high-quality software with LLMs.

🎯 Purpose

This project demonstrates that developing high-quality software with LLMs requires collaboration, not just simple requests. It compares three different approaches, showing how iterative refinement with LLMs leads to better maintainability and extensibility.

πŸ”€ Three Development Approaches

1️⃣ Simple Request Approach (using-simple-request branch)

Approach: Directly ask the LLM to build the entire application with a single prompt.

Request:

Create a todo list app using Flutter. It should have features for adding/deleting/checking 
tasks as completed, and the ability to hide completed items from the list. Store data in 
local SQLite, and create a simple list-style UI.

Result:

  • βœ… Quick implementation
  • ❌ Limited design considerations
  • ❌ Tightly coupled code
  • ❌ Difficult to adapt to future changes
  • ❌ No architectural principles

Lesson: Simple requests produce working code, but not maintainable software.


2️⃣ Spec-Kit with Constitution (using-speckit branch)

Approach: Use GitHub Spec-Kit workflow with established design principles (constitution).

Constitution Setup:

Write the core principles for developing a maintainable and scalable application:

* **Maintainable Software Design Principles**: Follow SOLID principles to ensure code 
  is modular, extensible, and easy to test.

* **Interface vs Implementation Separation**: Clearly separate interfaces from 
  implementations to allow flexible substitution and easier updates.

* **Modular Architecture Guidelines**:
  - Apply the Acyclic Dependencies Principle (ADP): Module dependencies must not form cycles.
  - Apply the Stable Dependencies Principle (SDP): Modules should depend on more stable modules.
  - Distinguish between core modules and extension modules.
  - Isolate complex or frequently changing modules.
  - Clearly define module boundaries and strictly manage dependencies.

Result:

  • βœ… Structured development workflow
  • βœ… Constitutional principles guide design
  • βœ… Better separation of concerns
  • ⚠️ Still based on initial requirements only
  • ⚠️ Limited anticipation of future changes

Lesson: Following design principles improves quality, but requirements must also evolve.


3️⃣ Collaborative Refinement Approach (main branch) ⭐

Approach: Collaborate with LLM to review and refine requirements and design decisions before implementation.

Process:

  1. Analyze anticipated changes - Work with LLM to identify future requirements
  2. Refine specifications - Update requirements to support extensibility
  3. Establish architecture - Design with change in mind
  4. Implement iteratively - Build with maintainability as a priority

Key Activities:

  • πŸ” Requirements Analysis: Identify expected changes (UI, database, features, integrations)
  • πŸ“ Specification Refinement: Add extensibility requirements (FR-020 to FR-025)
  • πŸ—οΈ Architectural Guidance: Document evolution areas and design principles
  • βœ… Maintainability Metrics: Define measurable maintainability success criteria

Result:

  • βœ… Requirements anticipate future changes
  • βœ… Architecture supports extensibility
  • βœ… Clear separation of concerns (presentation, logic, data)
  • βœ… Technology-agnostic design
  • βœ… Documented evolution roadmap
  • βœ… Measurable maintainability goals

Lesson: Collaborating with LLMs to refine requirements and design produces high-quality, maintainable software.

πŸ’‘ Key Insight

Don't just ask LLMs to write code. Work WITH LLMs to:

  • Analyze anticipated requirement changes
  • Refine specifications for extensibility
  • Establish architectural principles
  • Design for maintainability

This collaborative approach produces software that's easier to maintain and extend.

Branch Approach Result
using-simple-request Single prompt β†’ Code ❌ Works but not maintainable
using-speckit Spec-Kit + Design principles βœ… Better but reactive to changes
main ⭐ Collaborate to refine requirements βœ… Anticipates changes, highly maintainable

Key Difference: The main branch works WITH the LLM to analyze anticipated changes, refine specifications for extensibility, and design with maintainability as a priorityβ€”not just follow requirements.

πŸ“¦ Built with GitHub Spec-Kit

This project was developed using GitHub Spec-Kit, a systematic workflow system for feature development that ensures:

  • πŸ“ Clear Requirements: Structured specification with user stories and acceptance criteria
  • πŸ—οΈ Planned Architecture: Constitution-compliant design validated before implementation
  • βœ… Task-Driven Development: 45 well-defined tasks from setup to polish
  • 🎯 Quality Assurance: Built-in compliance checks and verification steps

Spec-Kit Commands Used:

  • /speckit.constitution - Create project governing principles and development guidelines
  • /speckit.specify - Define what you want to build (requirements and user stories)
  • /speckit.clarify - Clarify underspecified areas (requirements and user stories)
  • /speckit.plan - Create technical implementation plans with your chosen tech stack
  • /speckit.tasks - Generate actionable task lists for implementation
  • /speckit.implement - Execute all tasks to build the feature according to the plan

πŸ”§ Development Process

The following sections document the complete Spec-Kit workflow used in the main branch to build this application.

Step 0: Constitution Establishment with /speckit.constitution

The constitutional principles were created using the Spec-Kit workflow system with the /speckit.constitution command.

Original Input:

Write the core principles for developing a maintainable and scalable application. The summary should include:

* **Maintainable Software Design Principles**: Follow object-oriented design principles such as SOLID to ensure code is modular, extensible, and easy to test.

* **Interface vs Implementation Separation**: For features that may change or expand, clearly separate interfaces from implementations to allow flexible substitution and easier updates.

* **Modular Architecture Guidelines**
  - Apply the Acyclic Dependencies Principle (ADP): Module dependencies must not form cycles.
  - Apply the Stable Dependencies Principle (SDP): Modules should depend on more stable modules.
  - Distinguish between core modules and extension modules. Core modules must not depend on extension modules.
  - Modules that are complex or frequently change should be isolated and not depended on by other modules.
  - Clearly define module boundaries and strictly manage dependencies.

The goal is to design a system that is robust, adaptable to change, and easy to maintain over time.

Generated Output: Based on the user requirements above, a comprehensive project constitution was automatically generated and documented in .specify/memory/constitution.md.

The constitution defines three core principles:

  1. SOLID Principles - Ensuring modular, testable, and extensible code through Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion principles.

  2. Interface/Implementation Separation - Clear contracts for flexible evolution, enabling testing with mocks, implementation swapping, and clear boundaries.

  3. Modular Architecture Guidelines - Enforcing acyclic dependencies (ADP), stable dependencies (SDP), core/extension separation, complex module isolation, and explicit boundaries.

All development in this project must comply with these constitutional principles to ensure long-term maintainability and scalability.

7 Constitutional Gates:

  1. βœ… SOLID Principles compliance
  2. βœ… Interface/Implementation separation
  3. βœ… Acyclic dependencies (no circular references)
  4. βœ… Stable dependencies (depend on stable modules)
  5. βœ… Core/Extension separation (core independent)
  6. βœ… Complex module isolation (minimize dependents)
  7. βœ… Explicit boundaries (documented interfaces)

All subsequent development steps validate against these 7 gates to ensure architectural integrity.

Step 1: Requirements Specification with /speckit.specify

The feature requirements were created using the Spec-Kit workflow system with the /speckit.specify command.

Original Requirements Input:

Create a todo list app using Flutter. It should have features for adding/deleting/checking tasks as completed, and the ability to hide completed items from the list. Store data in local SQLite, and create a simple list-style UI.

What /speckit.specify Generated:

  • πŸ“„ spec.md - Comprehensive feature specification with:

    • 4 user stories (US1-US4) with acceptance criteria
    • Functional requirements (FR-001 to FR-016)
    • Non-functional requirements (performance, security, accessibility)
    • Technical constraints and assumptions
  • βœ… checklists/requirements.md - Requirements verification checklist

The specification process included 5 rounds of clarification via Q&A to ensure all requirements were clear and unambiguous before implementation began.

Step 2: Implementation Planning with /speckit.plan

Generated comprehensive implementation plan and supporting documentation:

All 7 constitutional compliance gates were validated during planning.

Step 3: Task Generation with /speckit.tasks

  • πŸ“ tasks.md - 45 implementation tasks organized by:
    • Phase 1: Setup (3 tasks)
    • Phase 2: Foundation (6 tasks)
    • Phase 3-6: User Stories 1-4 (29 tasks)
    • Phase 7: Polish & Cross-cutting (7 tasks)

Step 4: Implementation with /speckit.implement

All 45 tasks completed following the constitutional principles:

  • βœ… Task Completion: 45/45 (100%)
  • βœ… User Stories: 4/4 delivered
  • βœ… Code Quality: Flutter analyze with 0 issues
  • βœ… Constitutional Compliance: All 7 gates verified
  • πŸ“„ Documentation:

πŸ“Š Collaborative Refinement Process

This section demonstrates how the main branch approach works by showing the actual conversation between developer and LLM.

Step 1: Analyze Expected Requirement Changes

Developer Request:

I'd like to develop software that is easier to maintain. First, list the expected changes. 
For example, the card format for task displays could change, or the database that stores tasks could change.
List the expected requirement changes.

LLM Analysis:

The LLM analyzed the project and identified 7 major categories of expected changes:

1. UI/Presentation Layer Changes

  • Task card visual design evolution (colors, layouts, view modes)
  • Navigation enhancements (tabs, search, settings)
  • Theming and dark mode support

2. Data Storage Changes

  • Database migration (SQLite β†’ Hive/Firebase/cloud)
  • Data model expansion (priority, due dates, tags, attachments, subtasks)

3. Business Logic Changes

  • Operations beyond CRUD (edit, reorder, archive, bulk actions, undo/redo)
  • Advanced filtering and sorting
  • Notification system

4. Integration & Platform Changes

  • Third-party integrations (calendar, email, voice, AI)
  • Platform expansion (web, desktop, tablet)

5. Non-functional Requirements

  • Performance scaling, security, accessibility

6. State Management Evolution

  • Architecture patterns (MVC, MVVM, Clean Architecture)

7. User Experience Enhancements

  • Onboarding, personalization, customization

Key Recommendation:

The most critical areas to make flexible are the data layer (storage mechanism) and UI components (task card presentation), as these are almost certain to change.


Step 2: Refine Specification Based on Analysis

Developer Request:

/speckit.specify refine the specifications so that the software can easily reflect anticipated requirements changes. Key requirement changes include visual design changes of task items, database migration, data model expansion, operations beyond CRUD, filtering and sorting, notifications, third-party integration, etc.

LLM Refinement:

The LLM refined the specification by adding:

New Extensibility Requirements (FR-020 to FR-025)

Requirement Purpose Benefits
FR-020 Separate data management from presentation logic Visual design changes without touching business logic
FR-021 Abstract storage operations behind interfaces Database migration without rewriting business logic
FR-022 Design extensible data structures Add attributes (priority, tags) with minimal changes
FR-023 Implement composable operations Add new operations (edit, undo) independently
FR-024 Separate filter/sort logic from data retrieval Advanced queries without changing storage layer
FR-025 Define clear integration boundaries Easy addition of notifications and third-party services

Architectural Considerations Section

Added comprehensive guidance on 8 expected evolution areas:

  1. Visual Presentation Layer
  2. Data Storage Evolution
  3. Data Model Extensions
  4. Operations Beyond Basic CRUD
  5. Advanced Filtering and Sorting
  6. Notification and Reminder System
  7. Third-party Integrations
  8. Cross-platform and Multi-device Support

Each area includes:

  • Specific anticipated changes
  • Design principles to handle them
  • Clear separation between requirements and implementation guidance

7 Design Principles

  1. Separation of Concerns: Distinct layers (presentation, business logic, data access)
  2. Dependency Inversion: Business logic depends on abstractions
  3. Interface-based Design: Contracts for data access, operations, integrations
  4. Modular Components: Reusable, composable UI units
  5. Extensible Data Model: Accommodate new fields without breaking changes
  6. Testability: Test business logic independently of UI and storage
  7. Configuration over Code: Use configuration for themes, preferences, feature flags

Maintainability Success Criteria (SC-M01 to SC-M05)

Added measurable goals for maintainability:

  • SC-M01: Visual changes without modifying task management logic
  • SC-M02: Storage changes without rewriting business logic
  • SC-M03: New attributes with minimal code changes
  • SC-M04: New operations without modifying existing CRUD
  • SC-M05: Automated testing of business logic independent of UI/storage

Updated Files


Step 3: Refine Architectural Decisions

3.1 Adatper for Database (SQLite)

Developer Request:

I'd like to review and improve the design. First, regarding the implementation of TaskRepository and sqlflite. Since data other than tasks may be added in the future, would it be a good idea to separate the tables from the database? I'd suggest using an abstract interface for the database, implementing it using the adapter pattern, and then implementing TaskRepository through this abstract interface. Please review and improve the Local Storage Implementation section of research.md. Compare it to the previous design.

LLM Refinement:

πŸ“ Updated Documents

  1. research.md - Section 2 (Local Storage Implementation)

    Added:

    • Database interface specification (7 methods: initialize, query, insert, update, delete, transaction, close)
    • SqliteAdapter implementation (wraps sqflite with Adapter Pattern)
    • Updated TaskRepositoryImpl (now depends on Database, not sqflite)
    • Architecture comparison table (Previous vs Improved)
    • Migration scenarios (adding entities, switching storage)
    • Testing benefits (MockDatabase, InMemoryAdapter)
    • Design Comparison Summary table with constitutional impact

    Key Stats:

    Aspect Previous Improved
    Abstraction Layers 1 (TaskRepository) 2 (Database + Repository)
    Multi-Entity Support Each needs sqflite All share Database
    Migration Effort O(N repositories) O(1 adapter)
    Testing Requires sqflite Mock Database
  2. internal-interfaces.md

    Added:

    • Database Interface contract (complete API specification)
    • DatabaseTransaction interface for atomic operations
    • Updated layer architecture diagram with Database abstraction
    • Updated TaskRepository documentation (now depends on Database)
    • Architecture Comparison section (Previous vs Improved)
    • Migration Scenario examples (sqflite β†’ Hive)
    • Constitutional Gate Impact analysis

    Constitutional Improvements:

    • Before: βœ… Interface Separation, βœ… DIP
    • After: βœ…βœ… Two-level Interface Separation, βœ…βœ… Stronger DIP, βœ… Adapter Pattern, βœ… Complete Isolation
  3. design-improvements.md (NEW)

    Comprehensive analysis document covering:

    • Problem identification (your insight)
    • Solution architecture (two-layer abstraction)
    • Component specifications (Database, SqliteAdapter, Repositories)
    • Benefits analysis (5 major improvements)
    • Constitutional compliance comparison
    • Dependency hierarchy (stability analysis)
    • Implementation roadmap
    • Lessons learned (collaborative design value)

3.2 Extensible Task Definition

Developer Request:

The next is a design review of TaskFilter. It seems likely that TaskFilter will be extended with various attributes or combinations of attributes in the future. How should we design it to minimize the impact of future expansion?

Current Design (Simple Enum)

enum TaskFilter {
  all,            // Show all tasks
  hideCompleted,  // Show only incomplete
}

LLM Refinement:

πŸ“ Updated Documents

  1. taskfilter-design-review.md (NEW)

    Comprehensive 350-line analysis covering:

    • Problem identification (exponential enum growth)
    • Specification Pattern detailed design
    • 8 concrete specification examples (current + future)
    • Composite specifications (And, Or, Not)
    • TaskFilters factory for user-friendly API
    • Benefits analysis (6 major improvements)
    • Migration strategy (3 phases)
    • Performance analysis
    • Constitutional compliance
    • Implementation priority
  2. internal-interfaces.md (UPDATED)

    • Replaced TaskFilter enum with TaskSpecification interface
    • Added specification composition methods (and, or, not)
    • Documented concrete specifications (All, Incomplete, Completed)
    • Added TaskFilters factory
    • Updated FilterService to accept TaskSpecification
    • Updated TaskProvider to use TaskSpecification
    • Added legacy enum for backward compatibility
  3. data-model.md (UPDATED)

    • Replaced TaskFilter enum with TaskSpecification pattern
    • Added specification serialization for UserPreferences
    • Documented current and future specifications
    • Added usage examples (simple, complex, very complex filters)
    • Updated UserPreferences to store TaskSpecification

Specification Pattern (Domain-Driven Design):

  • Encapsulates business rules as reusable, composable objects
  • Each specification defines one filtering criterion
  • Specifications can be combined with AND, OR, NOT operators
  • Type-safe, extensible, testable
classDiagram
   class TaskSpecification {
      <<interface>>
      +isSatisfiedBy(Task task) bool
   }

   class AndSpecification {
      -TaskSpecification left
      -TaskSpecification right
      +isSatisfiedBy(Task task) bool
   }

   class CompletedTaskSpecification {
      +isSatisfiedBy(Task task) bool
   }

   class HighPrioritySpecification {
      +isSatisfiedBy(Task task) bool
   }

   class OverdueSpecification {
      +isSatisfiedBy(Task task) bool
   }

   TaskSpecification <|.. AndSpecification
   TaskSpecification <|.. CompletedTaskSpecification
   TaskSpecification <|.. HighPrioritySpecification
   TaskSpecification <|.. OverdueSpecification
Loading

Developer Request:

While a new design that applies the Specification Pattern offers extensibility, it requires adding TaskSpecifications for additional attributes in the future. On the other hand, if the attributes defining a task are defined as metadata and the filter is configured based on this, then even if the task definition is added or modified in the future, only the metadata needs to be updated. Please review the design regarding this.

LLM Refinement:

πŸ“ Updated Documents

  1. metadata-driven-filtering.md (NEW - 900+ lines)

    Comprehensive design document covering:

    • Problem analysis (exponential enum growth)
    • Metadata architecture (AttributeMetadata, TaskSchema)
    • Filter expressions (declarative, composable)
    • Generic filter engine (metadata-aware)
    • 8 complete code examples with future attributes
    • Benefits analysis (6 major advantages)
    • Performance analysis
    • Migration strategy
    • Constitutional compliance
  2. filter-architecture-comparison.md (NEW - 550+ lines)

    Three-way comparison document:

    • Quick comparison table (15 criteria)
    • 5 detailed scenarios with code examples
    • Constitutional compliance analysis
    • Performance benchmarks
    • Recommendation matrix
    • Implementation timeline
    • Final verdict with rationale
  3. taskfilter-design-review.md (EXISTING)

    Specification Pattern analysis (still valuable for reference)

Metadata-Driven Design

  • Filter Expressions (Declarative, Serializable)

    {
    "operator": "and",
    "children": [
       {"attribute": "completed", "operation": "equals", "value": false},
       {
          "operator": "or",
          "children": [
          {"attribute": "priority", "operation": "equals", "value": "high"},
          {"attribute": "dueDate", "operation": "isPast", "value": null}
          ]
       }
    ]
    }
  • Advantages

    • βœ…βœ… 10x faster to add attributes (data vs code)
    • βœ…βœ… Non-programmers can extend
    • βœ…βœ… Runtime config (server-driven, feature flags)
    • βœ…βœ… UI auto-generation (zero manual UI)
    • βœ…βœ… Filters as data (serialize, store, share)
    • βœ…βœ… Superior OCP compliance
  • Disadvantages

  • ⚠️ Slight performance overhead (map lookup vs direct access)
    • Impact: ~2-3ms vs ~1ms (negligible for <10K tasks)
  • ⚠️ Runtime validation vs compile-time type safety
    • Mitigation: Validate expressions when created
  • ⚠️ Initial complexity (~10 classes for infrastructure)
    • ROI: Pays off after 2nd attribute addition

Verdict: Trade-offs are highly acceptable βœ…

Hybrid Desgin

Use metadata-driven for 95%, specifications for 5%

// 95% of filters: Metadata-driven
final standardFilter = ExpressionFilter(
  FilterExpression(attribute: 'priority', operation: equals, value: 'high')
);

// 5% of filters: Complex business logic via specifications
class HasMostSubtasksCompleteSpec extends TaskSpecification {
  @override
  bool isSatisfiedBy(Task task) {
    // Complex logic not expressible in metadata
    if (task.subtasks == null || task.subtasks.length < 3) return false;
    final ratio = task.subtaskCompletedCount / task.subtasks.length;
    return ratio > 0.75;
  }
}

// Combine both
final hybrid = HybridFilter([standardFilter, specFilter], LogicOperator.and);

Developer Request:

I also think a hybrid design is a good idea. It would be nice to be able to define task metadata as JSON and use the attributes defined therein as filters. When defining filters for attributes, the operators should be set to "eq", "ne", "gt", "gte", "lt", and "lte". For example, if the due date is yesterday, the filter could be configured with "lt" if the "due_date" attribute is less than today. AndFilter and OrFilter are designed to check the and and or of a given filter array. Please reflect the design details in research.md.
In the current design, the Task class already defines priority, dueDate and tags. These properties should be extendable with the Task definition metadata. It would be ideal to allow Task properties to be extended with a Map, as follows:

class Task {
   final String id;
   final String description;
   final bool completed;
   final DateTime createdAt;
   final DateTime updatedAt;

   Map<String, dynamic> attributes;
}

Ultimately, the goal is to design software that is as unaffected as possible by changes to the Task definition metadata. Please design modules that display tasks on cards, as well as filters, or modules that create tasks so that they are not affected by changes in metadata.
I think the research.md file contains too many specific implementation details. This part can be completed during the actual implementation, so please keep the research.md file concise by only including the details that explain the design results.

Requests like these revise the design results. Please refer to research.md.

The Bottom Line

High-quality software development with LLMs is not about asking better questions β€” it's about collaborating iteratively to refine requirements, anticipate changes, and design for maintainability.

πŸš€ How to Apply This Approach

The Iterative Design Discovery Process

The key to developing high-quality, maintainable software with LLMs is continuous collaborative refinementβ€”not one-time prompting. Think of the LLM as your design partner who helps you explore better solutions through dialogue.

For Your Next Project

1. Establish Foundation (/speckit.constitution)

Start with principles and initial requirements:

  • Define design principles and architectural guidelines
  • Document initial functional requirements and user stories
  • Create baseline specification

πŸ”‘ Key Point: This is just your starting point, not the final design.


2. 🌟 Iterate with LLM to Discover Better Designs

This is where the magic happens. Engage in multiple rounds of design exploration with your LLM:

Round 1: Anticipate Changes (/speckit.specify β†’ /speckit.clarify)
πŸ’¬ You: "What requirements are likely to change over time?"
πŸ€– LLM: [Analyzes 7 categories of expected changes]

πŸ’¬ You: "Let's refine the specification to handle these changes gracefully"
πŸ€– LLM: [Adds extensibility requirements FR-020 to FR-025]
Round 2: Challenge Initial Designs (/speckit.plan)
πŸ’¬ You: "I'm concerned about tight coupling to SQLite. 
        How can we make storage swappable?"
πŸ€– LLM: [Proposes Database abstraction with Adapter Pattern]

πŸ’¬ You: "Show me how this compares to the previous design"
πŸ€– LLM: [Creates detailed comparison with constitutional analysis]
Round 3: Explore Extensibility Patterns
πŸ’¬ You: "TaskFilter will grow with many combinations. 
        How do we avoid exponential complexity?"
πŸ€– LLM: [Presents Specification Pattern approach]

πŸ’¬ You: "What if we define filters through metadata instead of code?"
πŸ€– LLM: [Proposes metadata-driven filtering architecture]

πŸ’¬ You: "Compare both approaches for our use case"
πŸ€– LLM: [Provides 3-way analysis: Enum vs Specification vs Metadata]
Round 4: Find the Sweet Spot
πŸ’¬ You: "Can we combine the best of both worlds?"
πŸ€– LLM: [Designs hybrid approach: metadata for 95%, specifications for 5%]

πŸ’¬ You: "How do we make the Task model itself extensible?"
πŸ€– LLM: [Evolves design to support dynamic attributes via Map]

🎯 Pattern: Each round reveals deeper insights. The LLM presents options, you provide context and constraints, together you converge on better designs.


3. 🌟 Ask "What If" Questions Repeatedly

Don't accept the first solution. Challenge and explore:

Design Challenge Questions:

  • "What if we need to migrate from SQLite to Firebase next year?"
  • "What if non-programmers need to define new filters?"
  • "What if the Task model needs 10 more attributes?"
  • "What if we need to support multiple UI themes?"
  • "How would this design handle [specific edge case]?"
  • "Show me the impact on existing code if we add [feature X]"
  • "What are the trade-offs between approach A and approach B?"

Comparison Questions:

  • "Compare this design to the previous version"
  • "What constitutional principles does each approach satisfy?"
  • "Which design requires less code change when [scenario] happens?"
  • "What's the migration path from current to proposed design?"

Refinement Questions:

  • "Can we simplify this without losing flexibility?"
  • "How do we keep this extensible but not over-engineered?"
  • "What's the 80/20 solution here?"

4. 🌟 Request Design Comparisons and Trade-off Analysis

Always ask for explicit comparisons:

πŸ’¬ "Create a comparison table showing:
   - Previous design vs improved design
   - What changes easily in each approach
   - Constitutional compliance for each
   - Code change impact for future scenarios
   - Performance trade-offs"

Why This Matters: Side-by-side analysis reveals which design truly handles change better.


5. Document the Design Journey

Capture design evolution in separate documents:

  • research.md - Technology choices and architecture decisions
  • design-improvements.md - Before/after comparisons with rationale
  • [pattern]-design-review.md - Deep dives on specific patterns
  • [feature]-comparison.md - Multi-approach trade-off analysis

πŸ”‘ Key Point: These documents aren't just documentationβ€”they're the artifacts of collaborative thinking that justify your architectural decisions.


6. Validate and Implement (/speckit.tasks β†’ /speckit.implement)

Once designs stabilize through iteration:

  • Generate implementation plan based on refined specifications
  • Create task list that respects architectural decisions
  • Implement with design principles baked in
  • Verify constitutional compliance continuously

🎭 The Collaboration Mindset

❌ Don't Do This:

πŸ’¬ "Build me a todo app with SQLite"
πŸ€– [Generates tightly-coupled code]
βœ… Done! (but not maintainable)

βœ… Do This Instead:

πŸ’¬ "Build me a todo app"
πŸ€– [Generates initial design]

πŸ’¬ "What will likely change?"
πŸ€– [Identifies 7 change categories]

πŸ’¬ "How do we design for these changes?"
πŸ€– [Proposes extensibility requirements]

πŸ’¬ "I'm concerned about SQLite coupling"
πŸ€– [Suggests abstraction layer]

πŸ’¬ "Show me the trade-offs"
πŸ€– [Provides detailed comparison]

πŸ’¬ "What about filter extensibility?"
πŸ€– [Explores 3 different patterns]

πŸ’¬ "Let's combine approaches"
πŸ€– [Designs hybrid solution]

βœ… Result: Maintainable, extensible architecture

The difference: 5-10 rounds of design dialogue produces software that handles change gracefully.


πŸ’‘ Key Success Factors

  1. πŸ”„ Iterate Multiple Rounds: First answer is rarely the best answer
  2. πŸ€” Challenge Assumptions: Question design choices, ask for alternatives
  3. πŸ“Š Request Comparisons: Always see trade-offs side-by-side
  4. 🎯 Think Future Scenarios: Design for what might change, not just what exists
  5. πŸ“ Capture Design Rationale: Document why you chose this approach over alternatives
  6. βš–οΈ Balance: Don't over-engineer, but don't under-design either

πŸŽ“ What You'll Learn

Through this iterative process, you'll discover:

  • Patterns you didn't know existed (Specification Pattern, Adapter Pattern)
  • Trade-offs you hadn't considered (metadata vs code, runtime vs compile-time)
  • Architectural principles in action (DIP, OCP, Interface Segregation)
  • How to balance flexibility with simplicity

The LLM becomes your design thinking partner, not just your code generator.


Key Questions to Ask Your LLM

Discovery Phase:

  • "What requirements are most likely to change in this application?"
  • "What are the top 5 areas where flexibility will pay off?"
  • "Which parts of this design are most tightly coupled?"

Design Exploration:

  • "How can we design [component X] to support [future change Y]?"
  • "What patterns help with extensibility without over-engineering?"
  • "Show me 2-3 different approaches to solve [design challenge]"

Validation Phase:

  • "Compare design A vs design B for handling [these scenarios]"
  • "What's the migration path from current to proposed design?"
  • "How does this design comply with [constitutional principle]?"
  • "What are we trading off by choosing this approach?"

Refinement Phase:

  • "Can we simplify this while keeping the key benefits?"
  • "What's the minimal change to achieve [desired flexibility]?"
  • "How do we balance [competing concerns X and Y]?"

πŸ† The Bottom Line

High-quality software emerges from collaborative design exploration, not perfect first prompts.

Treat your LLM as a design partner. Iterate together to discover better architectures. Challenge, compare, refineβ€”repeatedly. The goal isn't to ask the perfect question, but to engage in the design thinking process together.

The conversation IS the design process.

πŸ“ License

This project is a demonstration of software development methodologies with LLMs. Feel free to use it as a reference for your own projects.


Remember: The best code is code that's easy to change. Collaborate with LLMs to design for change, not just for today's requirements. 🎯

About

todo app with Copilot

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors