jherr-dev-workflow
npx skills add https://github.com/adrianbrowning/agent-skills --skill jherr-dev-workflow
Agent 安装分布
Skill 文档
jherr Development Workflow
A systematic approach to building software iteratively, inspired by Jack Harrington (jherr) and the classic software development principle.
Core Philosophy
Development should happen in three distinct phases:
- Make it work – Get a working solution first
- Make it right – Refactor and improve code quality
- Make it fast – Optimize for performance when needed
Each phase has different priorities and success criteria. Moving to the next phase too early causes problems.
Phase 1: Make It Work
Goal: Create a minimal working solution that demonstrates the feature works end-to-end.
Priorities:
- Get something functional as quickly as possible
- Focus on the happy path
- Use straightforward approaches
- Hardcode values if it helps move faster
- Skip error handling that isn’t critical
- Accept code duplication temporarily
With TDD (Test-Driven Development):
- Write tests for the core happy path first
- Get those fundamental tests passing
- Defer edge case tests to Phase 2
- Use Red-Green cycle: failing test â minimal code â passing test
- Tests serve as proof the feature works, not comprehensive coverage yet
Without TDD:
- Build the feature directly
- Manual testing or simple validation is acceptable
- Add automated tests in Phase 2
Success criteria:
- The feature demonstrates the intended behavior
- Core functionality works for the primary use case
- You can show it to someone and they understand what it does
- (TDD) Happy path tests are green
Common mistakes:
- Trying to handle every edge case immediately
- Building abstractions before understanding the problem
- Optimizing before knowing if the approach works
- Adding features beyond the core requirement
- (TDD) Writing exhaustive test suites before understanding the problem
Phase 2: Make It Right
Goal: Refactor the working code into maintainable, well-structured software.
Priorities:
- Remove code duplication (DRY principle)
- Add proper error handling and edge cases
- Extract reusable functions and components
- Improve naming and code clarity
- Add type safety (TypeScript types, Python type hints)
- Write tests for critical paths
- Add documentation where behavior is non-obvious
With TDD:
- Add edge case tests now
- Test error conditions and boundary cases
- Refactor with confidence (tests prevent regressions)
- Use TDD’s refactor step to improve design
- Achieve good test coverage of important behaviors
Without TDD:
- Add automated tests for critical functionality
- Focus on integration and key unit tests
- Tests enable safe refactoring
Success criteria:
- Code is readable and maintainable
- Common errors are handled gracefully
- Components have clear, single responsibilities
- Tests cover the main functionality
- Other developers can understand and modify the code
- (TDD) Comprehensive test suite with edge cases covered
Common mistakes:
- Over-abstracting before patterns emerge
- Premature optimization
- Perfect test coverage on first pass
- Adding speculative features “just in case”
- (TDD) Testing implementation details instead of behavior
Phase 3: Make It Fast
Goal: Optimize performance based on actual measured bottlenecks.
When to enter this phase:
- Performance testing reveals actual issues
- Users report slowness in production
- Profiling identifies clear bottlenecks
- You have specific performance requirements to meet
Priorities:
- Profile first to find actual bottlenecks
- Optimize the slowest parts first (80/20 rule)
- Measure impact of each optimization
- Consider caching strategies
- Evaluate algorithmic improvements
- Look for unnecessary re-renders/re-computations
With TDD:
- Add performance tests to capture benchmarks
- Ensure existing tests still pass after optimization
- Use tests to verify optimizations don’t break behavior
- Consider adding specific performance regression tests
Success criteria:
- Measured performance meets requirements
- Optimizations target actual bottlenecks
- Performance improvements are documented
- Code remains maintainable
- (TDD) All tests still pass, performance tests validate improvements
Common mistakes:
- Optimizing without measuring first
- Making code complex for negligible gains
- Optimizing parts that aren’t bottlenecks
- Sacrificing maintainability unnecessarily
- (TDD) Breaking tests during optimization without realizing behavioral changes
Workflow Guidelines
Starting a new feature
- Clarify the core requirement
- Sketch the simplest working approach
- Build Phase 1: Make it work
- Demo/validate it works
- Proceed to Phase 2
When something breaks
- Fix in the current phase
- Don’t jump back to “make it work” mode unnecessarily
- Maintain the quality level achieved
Knowing when to move forward
- Phase 1 â 2: When core functionality works
- Phase 2 â 3: When you have performance requirements AND measurements showing issues
- Staying in Phase 2: Most code should stay here indefinitely – clean, working code doesn’t need optimization
Red flags
- Writing complex abstractions in Phase 1
- Discussing performance in Phase 1
- Skipping Phase 2 entirely
- Entering Phase 3 without measurements
TDD Integration
This workflow pairs naturally with Test-Driven Development:
How they complement each other:
- TDD answers “how” – Write test first, then implementation
- jherr answers “when” – When to refactor, when to optimize
Phase mapping:
- Phase 1: Red-Green cycle for happy path (minimal tests, minimal code)
- Phase 2: Add edge case tests, refactor with test safety net
- Phase 3: Performance tests validate optimizations don’t break behavior
Best practices:
- In Phase 1, write just enough tests to prove it works
- In Phase 2, expand test coverage to include edge cases
- In Phase 3, ensure tests pass after each optimization
- Tests are documentation of expected behavior across all phases
If using TDD throughout:
- Maintain Red-Green-Refactor cycle in all phases
- Let test failures guide implementation
- Use refactor step as your Phase 2 signal
- Add performance assertions in Phase 3 only
Examples
Example: Building a user search feature
Phase 1 – Make it work:
// Just get it working
function searchUsers(query: string) {
return users.filter(user =>
user.name.toLowerCase().includes(query.toLowerCase())
);
}
Phase 2 – Make it right:
// Add proper handling and structure
function searchUsers(query: string): User[] {
if (!query.trim()) return [];
const normalizedQuery = query.toLowerCase().trim();
return users.filter(user =>
user.name.toLowerCase().includes(normalizedQuery) ||
user.email.toLowerCase().includes(normalizedQuery)
);
}
Phase 3 – Make it fast (only if measurements show it’s slow):
// Optimize with debouncing and indexing
const searchIndex = buildSearchIndex(users);
const debouncedSearch = debounce((query: string) => {
if (!query.trim()) return [];
const normalizedQuery = query.toLowerCase().trim();
return searchIndex.query(normalizedQuery);
}, 300);
Example with TDD: Building a shopping cart
Phase 1 – Make it work (with TDD):
// Test: Happy path only
test('adds item to cart', () => {
const cart = new ShoppingCart();
cart.addItem({ id: 1, name: 'Widget', price: 10 });
expect(cart.total()).toBe(10);
});
// Implementation: Simplest thing that works
class ShoppingCart {
items = [];
addItem(item) {
this.items.push(item);
}
total() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}
Phase 2 – Make it right (with TDD):
// Tests: Add edge cases and error handling
test('handles empty cart', () => {
const cart = new ShoppingCart();
expect(cart.total()).toBe(0);
});
test('prevents adding invalid items', () => {
const cart = new ShoppingCart();
expect(() => cart.addItem(null)).toThrow();
});
test('removes items correctly', () => {
const cart = new ShoppingCart();
cart.addItem({ id: 1, name: 'Widget', price: 10 });
cart.removeItem(1);
expect(cart.total()).toBe(0);
});
// Implementation: Refactored with types and validation
interface CartItem {
id: number;
name: string;
price: number;
}
class ShoppingCart {
private items: CartItem[] = [];
addItem(item: CartItem): void {
if (!item || typeof item.price !== 'number') {
throw new Error('Invalid item');
}
this.items.push(item);
}
removeItem(id: number): void {
this.items = this.items.filter(item => item.id !== id);
}
total(): number {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}
Phase 3 – Make it fast (only if needed):
// Performance test
test('handles large cart efficiently', () => {
const cart = new ShoppingCart();
const start = performance.now();
for (let i = 0; i < 10000; i++) {
cart.addItem({ id: i, name: `Item ${i}`, price: i });
}
const total = cart.total();
const duration = performance.now() - start;
expect(duration).toBeLessThan(100); // Should complete in <100ms
expect(total).toBe(49995000);
});
// Optimized implementation with memoization
class ShoppingCart {
private items: CartItem[] = [];
private cachedTotal: number | null = null;
addItem(item: CartItem): void {
if (!item || typeof item.price !== 'number') {
throw new Error('Invalid item');
}
this.items.push(item);
this.cachedTotal = null; // Invalidate cache
}
total(): number {
if (this.cachedTotal !== null) {
return this.cachedTotal;
}
this.cachedTotal = this.items.reduce((sum, item) => sum + item.price, 0);
return this.cachedTotal;
}
}
Key Principles
- Resist premature optimization – Most code never needs Phase 3
- Iterate quickly – Feedback loops are more valuable than perfect first attempts
- Measure, don’t guess – Performance problems must be measured
- Maintainability matters – Code is read more than written
- Ship working software – A working MVP beats a perfect plan
- TDD enhances the workflow – Tests provide safety nets for refactoring and prove behavior doesn’t change during optimization
- Test behavior, not implementation – Focus on what the code does, not how it does it
When NOT to use this workflow
This workflow may not fit when:
- Building safety-critical systems (correctness first)
- Working with strict performance requirements upfront
- Making small fixes to existing code
- Prototyping/exploring (stay in Phase 1)
- The “right” solution is obvious from the start
Related Skills
/tdd-integration– TDD Red-Green-Refactor cycle that complements this workflow/testing-best-practice– Testing philosophy and patterns for quality tests