A Flutter-based todo application demonstrating three different approaches to developing high-quality software with LLMs.
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.
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:
- Analyze anticipated changes - Work with LLM to identify future requirements
- Refine specifications - Update requirements to support extensibility
- Establish architecture - Design with change in mind
- 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.
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.
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
The following sections document the complete Spec-Kit workflow used in the main branch to build this application.
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:
-
SOLID Principles - Ensuring modular, testable, and extensible code through Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion principles.
-
Interface/Implementation Separation - Clear contracts for flexible evolution, enabling testing with mocks, implementation swapping, and clear boundaries.
-
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:
- β SOLID Principles compliance
- β Interface/Implementation separation
- β Acyclic dependencies (no circular references)
- β Stable dependencies (depend on stable modules)
- β Core/Extension separation (core independent)
- β Complex module isolation (minimize dependents)
- β Explicit boundaries (documented interfaces)
All subsequent development steps validate against these 7 gates to ensure architectural integrity.
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.
Generated comprehensive implementation plan and supporting documentation:
- π
plan.md- Complete implementation strategy - π¬
research.md- Technology choices (Flutter, SQLite, Provider) - π
data-model.md- Database schema design - π
quickstart.md- Development setup guide - π
contracts/internal-interfaces.md- API contracts
All 7 constitutional compliance gates were validated during planning.
- π
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)
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:
This section demonstrates how the main branch approach works by showing the actual conversation between developer and LLM.
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:
- Task card visual design evolution (colors, layouts, view modes)
- Navigation enhancements (tabs, search, settings)
- Theming and dark mode support
- Database migration (SQLite β Hive/Firebase/cloud)
- Data model expansion (priority, due dates, tags, attachments, subtasks)
- Operations beyond CRUD (edit, reorder, archive, bulk actions, undo/redo)
- Advanced filtering and sorting
- Notification system
- Third-party integrations (calendar, email, voice, AI)
- Platform expansion (web, desktop, tablet)
- Performance scaling, security, accessibility
- Architecture patterns (MVC, MVVM, Clean Architecture)
- 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.
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:
| 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 |
Added comprehensive guidance on 8 expected evolution areas:
- Visual Presentation Layer
- Data Storage Evolution
- Data Model Extensions
- Operations Beyond Basic CRUD
- Advanced Filtering and Sorting
- Notification and Reminder System
- Third-party Integrations
- Cross-platform and Multi-device Support
Each area includes:
- Specific anticipated changes
- Design principles to handle them
- Clear separation between requirements and implementation guidance
- Separation of Concerns: Distinct layers (presentation, business logic, data access)
- Dependency Inversion: Business logic depends on abstractions
- Interface-based Design: Contracts for data access, operations, integrations
- Modular Components: Reusable, composable UI units
- Extensible Data Model: Accommodate new fields without breaking changes
- Testability: Test business logic independently of UI and storage
- Configuration over Code: Use configuration for themes, preferences, feature flags
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
- π
specs/main/spec.md- Enhanced with extensibility focus - β
specs/main/checklists/requirements.md- Updated validation checklist
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:
-
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 -
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
-
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?enum TaskFilter {
all, // Show all tasks
hideCompleted, // Show only incomplete
}LLM Refinement:
-
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
-
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
-
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
- 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
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:
-
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
-
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
-
taskfilter-design-review.md (EXISTING)
Specification Pattern analysis (still valuable for reference)
-
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 β
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.
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.
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.
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.
This is where the magic happens. Engage in multiple rounds of design exploration with your LLM:
π¬ 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]
π¬ 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]
π¬ 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]
π¬ 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.
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?"
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.
Capture design evolution in separate documents:
research.md- Technology choices and architecture decisionsdesign-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.
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
π¬ "Build me a todo app with SQLite"
π€ [Generates tightly-coupled code]
β
Done! (but not maintainable)
π¬ "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.
- π Iterate Multiple Rounds: First answer is rarely the best answer
- π€ Challenge Assumptions: Question design choices, ask for alternatives
- π Request Comparisons: Always see trade-offs side-by-side
- π― Think Future Scenarios: Design for what might change, not just what exists
- π Capture Design Rationale: Document why you chose this approach over alternatives
- βοΈ Balance: Don't over-engineer, but don't under-design either
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.
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]?"
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.
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. π―