To turn these prose-based habits into a Domain Specific Language (DSL), we need to shift from "advice" to "constraints and declarations."
I will call this language HabitLang. It is a declarative language used to define a team's "Development Philosophy" or "Quality Manifesto." Instead of writing a README, a team writes a .habit file that acts as a living specification for their workflow.
Below is the specification and the implementation of the rules in HabitLang.
1. The HabitLang Specification
Core Primitives:
policy: A high-level directive that must be followed.threshold: A quantitative limit that triggers an action.priority: A ranking of importance (Immediate, Future, Ignorable).constraint: A hard rule that defines "Working" or "Done."workflow: A sequence of required steps.
2. The Rules translated into HabitLang
Here is how the 10 rules would be written in the DSL:
// Rule 1: Commit Granularity
policy CommitSize {
limit: "compilable_unit",
goal: "effortless_revert",
warning: "if you feel you are taking this too far, you are doing it right"
}
// Rule 2: Refactoring Cadence
policy RefactorCycle {
commit_ratio: 0.5, // 50% of commits should be refactors
max_duration: 10m, // Continuous refactoring units
strategy: "make_easy_then_do_easy",
avoid: "big_refactor"
}
// Rule 3: Deployment & Value
policy Deployment {
liability: "undeployed_code",
measure_of_progress: "working_software",
definition_of_working: "deployed_and_contributing",
cost_tolerance: "high", // Hosting costs < knowledge of progression
}
// Rule 4: Testing Scope
policy TestScope {
trust: "framework_internals",
avoid: "testing_the_framework",
correlation: {
component_size: "small" -> test_burden: "low",
component_size: "large" -> test_burden: "high"
}
}
// Rule 5: Module Organization
policy ModulePlacement {
preference: "independent_construct",
forbidden: "jamming_into_existing_module",
lifecycle: "create_now -> home_later"
}
// Rule 6: API Design
workflow ApiDevelopment {
sequence: [TestFirst, Implement, Verify],
dogma_level: "low",
goal: "customer_perspective"
}
// Rule 7: Abstraction Trigger (The Rule of Three)
policy Abstraction {
copy_paste_limit: 2,
trigger: "third_occurrence",
action: "consolidate_abstraction",
preference: "wonky_parameterization" over "diverging_implementations"
}
// Rule 8: Design Evolution
policy DesignMindset {
state: "stale_by_default",
acceptance: "change_is_core",
metric_of_skill: "ease_of_changing_software"
}
// Rule 9: Technical Debt Classification
policy TechDebt {
categories: {
type_1: { label: "blocking_now", priority: "critical" },
type_2: { label: "blocking_later", priority: "high" },
type_3: { label: "might_block_later", priority: "ignore" }
},
focus: [type_1, type_2]
}
// Rule 10: Testability as a Signal
policy Testability {
signal: "difficult_to_test" -> "design_flaw",
remedy: ["extract_function", "create_test_utility"],
assertion: "tests_go_unwritten_due_to_friction_not_will"
}
3. How this DSL would be used (The "Runtime")
Since a DSL is useless without a way to apply it, here are three ways HabitLang could be "executed":
A. The Linter (Static Analysis)
A CLI tool scans your Git history and project structure:
- Check Rule 1 & 2:
habit-checkanalyzes the last 100 commits. Ifrefactor_ratiois < 0.5, it warns: "Your project is drifting away from Rule 2: Increase refactoring frequency." - Check Rule 7: A static analyzer detects three nearly identical functions and flags: "Abstraction Trigger: Third occurrence detected. Consolidate now."
B. The PR Template (Human Process)
The DSL generates a dynamic Pull Request checklist based on the .habit file:
- Is this commit "small enough to be blissfully revertible"? (Rule 1)
- If this is a new API, were tests written first? (Rule 6)
- Does this add to "Type 1" or "Type 2" tech debt? (Rule 9)
C. The Onboarding Tool (Cultural Alignment)
When a new developer joins, they run habit-init, which transforms the .habit file into an interactive guide, explaining the "Why" behind these constraints, ensuring the team's "Good Habits" are codified and not just implied.