Claude-skill-registry-data Maintaining Consistent Abstractions
Class interfaces present one cohesive abstraction - don't mix domain logic with serialization, persistence, or unrelated concerns
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/maintaining-consistent-abstractions" ~/.claude/skills/majiayu000-claude-skill-registry-data-maintaining-consistent-abstractions && rm -rf "$T"
data/maintaining-consistent-abstractions/SKILL.mdMaintaining Consistent Abstractions
Overview
A class interface should present ONE cohesive abstraction. All methods should work toward a consistent purpose at a consistent level.
Core principle: Each class implements one Abstract Data Type (ADT). If you can't identify what ADT the class implements, it has poor abstraction.
Goal: Anyone using the class should see a clear, consistent set of related operations, not a miscellaneous grab-bag.
When to Use
Apply when designing any class:
- New class design
- Reviewing existing classes
- Refactoring
- API design
Warning signs of poor abstraction:
- Class groups unrelated functions
- Methods at different abstraction levels (high-level + low-level mixed)
- Domain object with serialization methods (to_json, to_xml)
- Business logic mixed with persistence (SQL in domain class)
- Temporal cohesion (things done at same time, not related by purpose)
- Can't clearly state what abstraction the class represents
- Class description has "and" connecting unrelated purposes
Abstraction Anti-Patterns from Baseline Testing
Anti-Pattern 1: Domain + Serialization Mixed
Baseline violation:
class Employee: def calculate_annual_salary(self): # ✅ Domain operation return self.salary * 12 def update_department(self, dept): # ✅ Domain operation self.department = dept def to_json(self): # ❌ Serialization detail return json.dumps({...}) def get_details(self): # ✅ Domain operation return {...}
Problem: Employee is a domain concept. JSON is a serialization format. Mixing these means:
- Employee must know about JSON, XML, Protobuf, etc.
- Changes to serialization format change Employee class
- Can't serialize same employee different ways
✅ Separate concerns:
class Employee: """Domain: Employee business logic only.""" def __init__(self, name, employee_id, department, salary): self.name = name self.employee_id = employee_id self.department = department self.salary = salary def calculate_annual_salary(self): # Domain return self.salary * 12 def update_department(self, dept): # Domain self.department = dept # Separate serializer class EmployeeSerializer: """Concern: Serialization formats.""" @staticmethod def to_json(employee: Employee) -> str: return json.dumps({ 'name': employee.name, 'id': employee.employee_id, ... }) @staticmethod def to_xml(employee: Employee) -> str: # Can add XML without touching Employee pass
Now: Employee knows nothing about formats. Add CSV/XML/Protobuf without changing Employee.
Anti-Pattern 2: Miscellaneous Grab-Bag (Temporal Cohesion)
Baseline violation:
class Program: """Initialize application components.""" def _init_database(self): # Database concern pass def _setup_web_server(self): # Web concern pass def _start_background_jobs(self): # Jobs concern pass def _init_command_stack(self): # Command concern pass def _init_report_formatter(self): # Reports concern pass
Problem: These are unrelated functions grouped because they happen at startup (temporal cohesion). The class has no consistent abstraction - it's a miscellaneous collection.
Code Complete specifically calls this out as poor abstraction.
✅ Each subsystem initializes itself:
class DatabaseSystem: """Abstraction: Database operations.""" def initialize(self): # Database-specific initialization pass class WebServer: """Abstraction: Web serving.""" def start(self): # Web server initialization pass class BackgroundJobManager: """Abstraction: Job processing.""" def start(self): # Job system initialization pass # Coordinator stays high-level class Application: def __init__(self): self.database = DatabaseSystem() self.web_server = WebServer() self.jobs = BackgroundJobManager() def start(self): # High-level orchestration self.database.initialize() self.web_server.start() self.jobs.start()
Now: Each class has consistent abstraction. Program no longer a grab-bag.
Anti-Pattern 3: Business Logic + Persistence Mixed
Baseline violation:
class DataProcessor: """Mixes data access with statistics.""" def process_dataset(self, dataset_id): # Loads from PostgreSQL (persistence concern) values = self._load_dataset(dataset_id) # Calculates statistics (business logic concern) mean = statistics.mean(values) # Two concerns in one class
Problem: Class does two things - data access AND statistics. If you switch from PostgreSQL to MongoDB, you must modify this class. If you change statistical algorithm, you modify same class.
✅ Separate concerns:
class DatasetRepository: """Abstraction: Dataset storage/retrieval.""" def get_dataset_values(self, dataset_id: str) -> list[float]: # PostgreSQL details hidden here # Can switch to MongoDB without affecting calculator pass class StatisticsCalculator: """Abstraction: Statistical computations.""" def calculate_metrics(self, values: list[float]) -> dict: # Pure calculation, no database knowledge mean = statistics.mean(values) median = statistics.median(values) # Returns statistics only pass class DataProcessor: """Abstraction: Orchestration.""" def __init__(self, repository, calculator): self._repository = repository self._calculator = calculator def process_dataset(self, dataset_id: str) -> dict: # High-level only - delegates to focused abstractions values = self._repository.get_dataset_values(dataset_id) return self._calculator.calculate_metrics(values)
Now: Each class has single, consistent abstraction. Database changes don't affect calculator. Algorithm changes don't affect repository.
The Abstraction Levels Test
For any class, ask:
-
What abstraction does this class represent?
- Can state it in one sentence?
- All methods work toward that one purpose?
-
Are all methods at same abstraction level?
- All high-level (orchestration)?
- All low-level (implementation)?
- Or mixed (violation)?
-
Do methods belong together?
- Related by purpose (functional cohesion)?
- Or just coincidentally grouped (temporal/coincidental)?
If answers reveal inconsistency → poor abstraction.
Types of Cohesion (Worst to Best)
Coincidental (Worst)
Unrelated things in one class:
class Utilities: def validate_email(self): # Validation def format_currency(self): # Formatting def connect_database(self): # Database
No relationship. Avoid this.
Temporal (Weak)
Things done at same time:
class Startup: def init_database(self): # Done at startup def init_webserver(self): # Done at startup def init_logging(self): # Done at startup
Related by WHEN not WHAT. Weak abstraction.
Functional (Best)
One clear purpose:
class EmployeeCalculations: def calculate_annual_salary(self, employee): def calculate_tax_withholding(self, employee): def calculate_benefits_cost(self, employee):
All methods work toward one purpose. Best abstraction.
Always aim for functional cohesion.
Quick Reference
| Violation | Example | Fix |
|---|---|---|
| Domain + Format mixed | | Separate Serializer class |
| Business + Persistence mixed | with SQL | Separate Repository from logic |
| High + Low level mixed | Orchestration with SQL queries | Extract low-level to private/separate |
| Grab-bag class | , , | Split by actual purpose |
| Temporal cohesion | Startup class with unrelated inits | Each subsystem owns initialization |
Consistent Abstraction Examples
Good: Employee (Domain Only)
class Employee: """Abstraction: Employee domain model.""" # All methods are employee operations def calculate_annual_salary(self): def update_department(self, dept): def get_compensation_summary(self): def is_eligible_for_bonus(self):
Consistent: All domain operations about employees.
Bad: Employee with Mixed Concerns
class Employee: """Mixed abstraction - unclear purpose.""" def calculate_annual_salary(self): # Domain def to_json(self): # Serialization def save_to_database(self): # Persistence def send_welcome_email(self): # Notification
Inconsistent: Domain + serialization + persistence + notifications.
When to Split a Class
Split when:
- Class has multiple reasons to change (SRP violation)
- Methods at different abstraction levels
- Can't state class purpose in one sentence
- Methods group into distinct clusters
- Some methods don't use instance data
Example split:
# Before: One class, mixed abstractions class UserService: def create_user(self, email, name): # Validation if not self._is_valid_email(email): raise ValueError() # Create domain object user = User(email, name) # Persist to database self._db.execute("INSERT INTO users ...") # Send welcome email self._smtp.send(email, "Welcome!") return user # After: Focused classes class UserValidator: """Abstraction: Validation.""" def validate_registration(self, email, name): pass class UserRepository: """Abstraction: Persistence.""" def save_user(self, user): pass class UserNotifier: """Abstraction: Notifications.""" def send_welcome_email(self, user): pass class UserService: """Abstraction: Orchestration.""" def create_user(self, email, name): self._validator.validate_registration(email, name) user = User(email, name) self._repository.save_user(user) self._notifier.send_welcome_email(user) return user
Red Flags - Poor Abstraction
Class level:
- Can't explain what abstraction class represents
- Methods don't seem related
- Some methods at high level, some at low level
- Class name is vague (
,Manager
,Handler
,Processor
)Utility - Class description lists multiple unrelated purposes
Method level:
- Domain method mixed with serialization (
)to_json - Business logic mixed with SQL queries
- High-level orchestration with low-level details inline
- Method doesn't fit with others in class
All of these mean: Improve abstraction consistency.
Common Rationalizations
From baseline testing:
| Excuse | Reality |
|---|---|
| "Keeps everything in one place" | One place ≠ good organization. Split by purpose, not location. |
| "It's just a coordinator" | Coordinators coordinate related things. Unrelated = grab-bag. |
| "Easier than multiple classes" | Easier to write ≠ easier to maintain. Abstraction quality matters. |
| "Production-ready code" | Working ≠ well-abstracted. Can be both. |
| "All used during startup" | Temporal relationship is weak. Use functional relationships. |
| "Serialization is part of the object" | No - serialization is a separate concern. External responsibility. |
Verification Checklist
For each class, verify:
- Can state what abstraction this class represents in one sentence
- All methods work toward that one abstraction
- All methods at consistent abstraction level
- No serialization mixed with domain (no to_json, to_xml in domain classes)
- No persistence mixed with business logic (no SQL in calculation classes)
- No grab-bag/utility classes with unrelated functions
- Functional cohesion (related by purpose) not temporal (related by timing)
- Class name reflects clear purpose, not vague role
If any "no" → split class or clarify abstraction.
Real-World Impact
From Code Complete:
- Abstract Data Types (ADTs) are foundation of classes
- Each class should implement one and only one ADT
- Poor abstraction = miscellaneous collection with no clear purpose
- Study found 30%+ comprehension improvement with good abstractions
From baseline testing:
- Agents mixed domain with serialization (Employee.to_json)
- Created grab-bag classes (Program with unrelated inits)
- Mixed business logic with persistence (DataProcessor, OrderProcessor)
- Good instinct: extracted to methods
- Bad pattern: didn't separate into classes
With this skill: Separate concerns, maintain abstraction consistency, functional cohesion.
Integration with Other Skills
For single responsibility: See skills/coding/keeping-routines-focused - same principle applies to classes (one clear purpose)
For encapsulation: See skills/encapsulating-complexity - hiding implementation details supports abstraction consistency
For complexity: See skills/reducing-complexity - consistent abstractions reduce mental load