Last active
June 25, 2025 11:58
-
-
Save paulbrodner/b7e8e095b702c6ba1fb9ddfa4fcfda33 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 🚀 Refined "Delete First, Code Last" Rules - Practical Edition | |
| > **Core Philosophy: Question every line of code. Prefer simplicity over cleverness, but don't sacrifice clarity for brevity.** | |
| ## 🎯 **The Golden Question** | |
| Before writing any code: **"What's the simplest way to solve this that I can still understand in 6 months?"** | |
| --- | |
| ## 🏆 **6 Practical Principles** (Guidelines, Not Laws) | |
| ### 1. **🔍 Question Abstractions - But Don't Avoid Them** | |
| **Guideline:** Create abstractions when they genuinely simplify understanding or prevent errors. | |
| ```python | |
| # ❌ Pointless wrapper | |
| class StringHelper: | |
| @staticmethod | |
| def get_length(s): | |
| return len(s) | |
| # ❌ Missing useful abstraction | |
| def process_order(order_data): | |
| # 50 lines of validation, calculation, and formatting | |
| # Should be broken down into conceptual chunks | |
| # ✅ Meaningful abstraction | |
| def process_order(order_data): | |
| validated_order = validate_order_data(order_data) | |
| calculated_totals = calculate_order_totals(validated_order) | |
| return format_order_response(calculated_totals) | |
| ``` | |
| **Test:** Does this abstraction represent a meaningful concept that could be explained to a domain expert? | |
| --- | |
| ### 2. **🧹 Eliminate True Duplication** | |
| **Guideline:** Consolidate identical logic, but similar-looking code isn't always duplication. | |
| ```python | |
| # ❌ True duplication - same logic, same purpose | |
| def validate_user_email(email): | |
| if not email or "@" not in email: | |
| raise ValueError("Invalid email") | |
| return email.lower().strip() | |
| def validate_admin_email(email): | |
| if not email or "@" not in email: | |
| raise ValueError("Invalid email") | |
| return email.lower().strip() | |
| # ✅ Consolidated | |
| def validate_email(email): | |
| if not email or "@" not in email: | |
| raise ValueError("Invalid email") | |
| return email.lower().strip() | |
| # ✅ Similar but NOT duplication - different purposes | |
| def format_display_name(name): | |
| return name.title().strip() | |
| def format_database_key(name): | |
| return name.lower().strip() | |
| ``` | |
| **Test:** Is the logic identical AND serving the same purpose? Only then consolidate. | |
| --- | |
| ### 3. **📁 Functions vs Classes - Context Matters** | |
| **Guideline:** Use functions for transformations, classes for stateful behavior and related operations. | |
| ```python | |
| # ❌ Class for simple data holding | |
| class UserSettings: | |
| def __init__(self, theme, language): | |
| self.theme = theme | |
| self.language = language | |
| # ✅ Simple data structure | |
| @dataclass(frozen=True) | |
| class UserSettings: | |
| theme: str | |
| language: str | |
| # ✅ Class justified - manages state and related operations | |
| class DatabaseConnection: | |
| def __init__(self, connection_string): | |
| self._connection = None | |
| self._connection_string = connection_string | |
| def connect(self): | |
| if not self._connection: | |
| self._connection = create_connection(self._connection_string) | |
| def execute(self, query): | |
| self.connect() | |
| return self._connection.execute(query) | |
| def close(self): | |
| if self._connection: | |
| self._connection.close() | |
| ``` | |
| **Test:** Does this need to maintain state between operations? If yes, consider a class. If no, use functions. | |
| --- | |
| ### 4. **⚡ Fail Fast - But Handle Gracefully** | |
| **Guideline:** Let exceptions bubble up for programmer errors, handle expected failures gracefully. | |
| ```python | |
| # ✅ Let programming errors bubble up | |
| def calculate_average(numbers): | |
| return sum(numbers) / len(numbers) # ZeroDivisionError is appropriate | |
| # ✅ Handle expected business failures | |
| def process_payment(amount, card_token): | |
| try: | |
| return payment_service.charge(amount, card_token) | |
| except PaymentDeclinedError as e: | |
| return PaymentResult(success=False, error=str(e)) | |
| # Let unexpected errors (network, auth) bubble up | |
| ``` | |
| **Test:** Is this an expected business scenario or a programming error? Handle business scenarios, let programming errors fail fast. | |
| --- | |
| ### 5. **🎯 Prefer Pure Functions - When Practical** | |
| **Guideline:** Use pure functions where possible, but don't contort your code to avoid necessary state. | |
| ```python | |
| # ✅ Pure function - easy to test and reason about | |
| def calculate_tax(amount, rate): | |
| return amount * rate | |
| # ✅ Necessary state - don't force this into pure functions | |
| class OrderProcessor: | |
| def __init__(self, tax_calculator, payment_service): | |
| self.tax_calculator = tax_calculator | |
| self.payment_service = payment_service | |
| def process_order(self, order): | |
| # Coordinates multiple services - state is justified | |
| tax = self.tax_calculator.calculate(order.amount) | |
| payment_result = self.payment_service.charge(order.amount + tax) | |
| return OrderResult(order, tax, payment_result) | |
| ``` | |
| **Test:** Can this logic work without external dependencies or state? If yes, make it pure. | |
| --- | |
| ### 6. **🗑️ The Contextual Delete Test** | |
| **Guideline:** Delete code that doesn't serve a clear purpose, but consider the full context. | |
| **Safe to Delete:** | |
| - Dead code (unreachable) | |
| - Obvious comments (`x = x + 1 # increment x`) | |
| - Trivial wrappers that don't add meaning | |
| - Unused imports (verified by tools) | |
| **Consider Context Before Deleting:** | |
| - Single-use functions (may represent important concepts) | |
| - Seemingly redundant checks (may prevent edge case bugs) | |
| - Comments explaining non-obvious business logic | |
| - Error handling that seems excessive | |
| **Delete Process:** | |
| 1. **Understand why it exists** - check git history, ask teammates | |
| 2. **Verify it's truly unused** - search codebase, check tests | |
| 3. **Comment it out first** - don't delete immediately | |
| 4. **Run full test suite** - including integration tests | |
| 5. **Monitor in production** - some code prevents rare edge cases | |
| --- | |
| ## 🎯 **Practical Implementation** | |
| ### **The 30-Second Rule:** | |
| Before writing code, spend 30 seconds considering: | |
| 1. **Does this already exist?** (standard library, existing function) | |
| 2. **Is this the simplest approach?** (not necessarily shortest) | |
| 3. **Will this be clear to future maintainers?** (including yourself) | |
| 4. **What could go wrong?** (edge cases, failure modes) | |
| ### **Balanced Metrics:** | |
| - ✅ **Cyclomatic complexity <15** per function (10 is ideal, but context matters) | |
| - ✅ **File length <500 lines** (split if much larger, but related code can stay together) | |
| - ✅ **Function parameters <7** (use objects for more, but don't force awkward groupings) | |
| - ✅ **Clear naming** (slightly longer names are fine if they're clearer) | |
| - ✅ **Good test coverage** (focus on critical paths, not 100% line coverage) | |
| ### **Code Smells (Investigate, Don't Auto-Delete):** | |
| - 🔍 Functions >50 lines - may need breakdown | |
| - 🔍 Classes with >10 methods - may have too many responsibilities | |
| - 🔍 Files importing >15 modules - may be doing too much | |
| - 🔍 Functions with >5 parameters - consider grouping | |
| - 🔍 Deeply nested conditions - consider early returns or extraction | |
| --- | |
| ## 🌟 **Practical Mantras** | |
| 1. **"Clear is better than clever"** | |
| 2. **"Simple is better than easy"** | |
| 3. **"Explicit is better than implicit"** | |
| 4. **"Readable code is maintainable code"** | |
| 5. **"Optimize for the reader, not the writer"** | |
| 6. **"Perfect is the enemy of good"** | |
| 7. **"Delete with purpose, not prejudice"** | |
| --- | |
| ## 🧪 **Weekly Code Review** | |
| **Every week, pick one area and ask:** | |
| 1. **What's confusing?** - simplify or document | |
| 2. **What's duplicated?** - consider consolidation | |
| 3. **What's unused?** - delete safely | |
| 4. **What's overly complex?** - break down or simplify | |
| 5. **What's missing?** - add needed abstractions | |
| 6. **What's fragile?** - add error handling or tests | |
| --- | |
| ## 🔄 **Balanced Before/After Template** | |
| ``` | |
| 📊 CHANGE ANALYSIS: | |
| ❌ BEFORE: [brief description of issue] | |
| ✅ AFTER: [brief description of solution] | |
| 📈 METRICS: | |
| - Lines: X → Y (Z% change) | |
| - Complexity: A → B | |
| - Test coverage: C → D | |
| 🎯 TRADE-OFFS: | |
| - Gained: [specific benefits] | |
| - Lost: [what was sacrificed, if anything] | |
| - Risk: [potential issues to monitor] | |
| 🔧 TECHNIQUE: [specific method used] | |
| ``` | |
| --- | |
| ## 🎪 **The Context Game** | |
| When tempted to apply a rule rigidly, ask: | |
| 1. **What's the goal?** (performance, maintainability, clarity) | |
| 2. **Who's the audience?** (junior devs, domain experts, future you) | |
| 3. **What's the risk?** (production failure, maintenance burden, confusion) | |
| 4. **What's the timeline?** (prototype, long-term system, migration) | |
| 5. **What are the constraints?** (team size, expertise, deadlines) | |
| **Remember: Rules are tools, not laws. Use judgment, not dogma.** | |
| --- | |
| ## 🎯 **The Ultimate Test** | |
| **Would you rather:** | |
| - Maintain 100 lines of crystal-clear code? | |
| - Maintain 50 lines of clever, terse code? | |
| - Maintain 150 lines of obvious, redundant code? | |
| **The answer depends on your team, timeline, and domain. Choose consciously.** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment