This skill provides guidance on applying SOLID, DRY, KISS, YAGNI, and TDD principles to the ai-cli-syncer Rust project.
This skill provides procedural guidance for applying core software engineering principles to the ai-cli-syncer Rust project. Apply SOLID design patterns, Test-Driven Development (TDD), and simplicity principles (DRY, KISS, YAGNI) to maintain high code quality and maintainability.
This skill should be invoked when:
Apply these five design principles to Rust code:
Single Responsibility (SRP) - Each module/struct has one clear purpose
ConfigManager into ConfigReader and ConfigValidatorOpen/Closed (OCP) - Design for extension through traits, not modification
SyncStrategy trait, then implement FileSyncStrategy, McpSyncStrategyLiskov Substitution (LSP) - Trait implementations must be substitutable
ConfigLoader implementations must handle missing files consistentlyInterface Segregation (ISP) - Create focused traits, not monolithic ones
FileHandler into FileReader, FileWriter, FileValidatorDependency Inversion (DIP) - Depend on trait abstractions, inject implementations
SyncEngine depends on trait ConfigLoader, not JsonConfigLoaderFollow the Red-Green-Refactor cycle for all feature development:
Red - Write a failing test for the desired functionality
Green - Implement minimum code to make the test pass
Refactor - Improve code while keeping tests green
Test Structure:
mod tests within each moduletests/ directory at project roottest_config_loader_returns_error_for_missing_fileBenefits: Catches bugs early, provides living documentation, makes refactoring safer, builds confidence when making changes
DRY (Don't Repeat Yourself) - Extract repeated patterns into reusable functions or modules
KISS (Keep It Simple) - Favor simple solutions over complex ones
YAGNI (You Aren't Gonna Need It) - Implement only what's needed now
Before coding, clarify:
Apply SOLID principles to planning:
Follow TDD:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_feature_behavior() {
// Arrange: Set up test data
let input = "test data";
// Act: Call the function (this doesn't exist yet!)
let result = my_function(input);
// Assert: Verify expected behavior
assert_eq!(result, expected_value);
}
}
Run cargo test - it should fail with "function not found".
Write the simplest code to pass the test:
pub fn my_function(input: &str) -> ReturnType {
// Minimum implementation to pass test
expected_value
}
Run cargo test - it should now pass.
Now improve the code while keeping tests green:
anyhow::ContextRun cargo test after each change to ensure behavior preserved.
Before committing, check:
/// comments?When reviewing code, verify:
anyhow::Context/// doc commentsBefore:
struct ConfigManager {
// Too many responsibilities!
}
impl ConfigManager {
fn read_file() -> Result<String> { ... }
fn parse_json() -> Result<Config> { ... }
fn validate() -> Result<()> { ... }
fn sync_to_agents() -> Result<()> { ... }
}
After (Apply SRP):
struct ConfigReader;
impl ConfigReader {
fn read(&self, path: &Path) -> Result<String> { ... }
}
struct ConfigParser;
impl ConfigParser {
fn parse(&self, content: &str) -> Result<Config> { ... }
}
struct ConfigValidator;
impl ConfigValidator {
fn validate(&self, config: &Config) -> Result<()> { ... }
}
struct ConfigSyncer;
impl ConfigSyncer {
fn sync(&self, config: &Config) -> Result<()> { ... }
}
Before:
struct SyncEngine {
loader: JsonConfigLoader, // Concrete type!
}
After (Apply DIP):
trait ConfigLoader {
fn load(&self, path: &Path) -> Result<Config>;
}
struct SyncEngine<L: ConfigLoader> {
loader: L, // Depends on abstraction
}
Before:
fn sync_cursor() -> Result<()> {
let path = home_dir().join(".cursor/config");
let content = fs::read_to_string(&path)?;
// ... sync logic
}
fn sync_windsurf() -> Result<()> {
let path = home_dir().join(".windsurf/config");
let content = fs::read_to_string(&path)?;
// ... same sync logic
}
After (Apply DRY):
fn sync_agent(agent_name: &str) -> Result<()> {
let path = home_dir().join(format!(".{}/config", agent_name));
let content = fs::read_to_string(&path)?;
// ... reusable sync logic
}
Remember: Good code is simple, clear, and purposeful.