Skip to main content

cargo_coupling/balance/
issue_type.rs

1/// Types of coupling problems
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub enum IssueType {
4    /// Strong coupling spanning a long distance
5    GlobalComplexity,
6    /// Strong coupling to a frequently changing component
7    CascadingChangeRisk,
8    /// Intrusive coupling across boundaries (field/internals access)
9    InappropriateIntimacy,
10    /// A module with too many dependencies
11    HighEfferentCoupling,
12    /// A module that too many others depend on
13    HighAfferentCoupling,
14    /// Weak coupling where stronger might be appropriate
15    UnnecessaryAbstraction,
16    /// Circular dependency detected
17    CircularDependency,
18    /// Strong temporal co-change without an explicit code dependency
19    HiddenCoupling,
20    /// Supporting or generic module changing more often than expected
21    AccidentalVolatility,
22    /// Direct coupling to a third-party crate is spread across many modules
23    ScatteredExternalCoupling,
24
25    // === APOSD-inspired issues (A Philosophy of Software Design) ===
26    /// Module with interface complexity close to implementation complexity
27    ShallowModule,
28    /// Method that only delegates to another method without adding value
29    PassThroughMethod,
30    /// Module requiring too much knowledge to understand/modify
31    HighCognitiveLoad,
32
33    // === Khononov/Rust-specific issues ===
34    /// Module with too many functions, types, or implementations
35    GodModule,
36    /// Public fields exposed to external modules (should use getters/methods)
37    PublicFieldExposure,
38    /// Functions with too many primitive parameters (consider newtype)
39    PrimitiveObsession,
40}
41
42impl std::fmt::Display for IssueType {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        match self {
45            IssueType::GlobalComplexity => write!(f, "Global Complexity"),
46            IssueType::CascadingChangeRisk => write!(f, "Cascading Change Risk"),
47            IssueType::InappropriateIntimacy => write!(f, "Inappropriate Intimacy"),
48            IssueType::HighEfferentCoupling => write!(f, "High Efferent Coupling"),
49            IssueType::HighAfferentCoupling => write!(f, "High Afferent Coupling"),
50            IssueType::UnnecessaryAbstraction => write!(f, "Unnecessary Abstraction"),
51            IssueType::CircularDependency => write!(f, "Circular Dependency"),
52            IssueType::HiddenCoupling => write!(f, "Hidden Coupling"),
53            IssueType::AccidentalVolatility => write!(f, "Accidental Volatility"),
54            IssueType::ScatteredExternalCoupling => write!(f, "Scattered External Coupling"),
55            // APOSD-inspired
56            IssueType::ShallowModule => write!(f, "Shallow Module"),
57            IssueType::PassThroughMethod => write!(f, "Pass-Through Method"),
58            IssueType::HighCognitiveLoad => write!(f, "High Cognitive Load"),
59            // Khononov/Rust-specific
60            IssueType::GodModule => write!(f, "God Module"),
61            IssueType::PublicFieldExposure => write!(f, "Public Field Exposure"),
62            IssueType::PrimitiveObsession => write!(f, "Primitive Obsession"),
63        }
64    }
65}
66
67impl IssueType {
68    /// Whether this finding is a diagnostic observation rather than a structural
69    /// defect. Diagnostics (e.g. raw git churn contradicting a declared subdomain)
70    /// are reported for investigation but do not lower the health grade.
71    pub fn is_diagnostic(&self) -> bool {
72        matches!(self, IssueType::AccidentalVolatility)
73    }
74
75    /// Get a detailed description of what this issue type means
76    pub fn description(&self) -> &'static str {
77        match self {
78            IssueType::GlobalComplexity => {
79                "Strong coupling to distant components increases cognitive load and makes the system harder to understand and modify."
80            }
81            IssueType::CascadingChangeRisk => {
82                "Strongly coupling to volatile components means changes will cascade through the system, requiring updates in many places."
83            }
84            IssueType::InappropriateIntimacy => {
85                "Direct access to internal details (fields, private methods) across module boundaries violates encapsulation."
86            }
87            IssueType::HighEfferentCoupling => {
88                "A module depending on too many others is fragile and hard to test. Changes anywhere affect this module."
89            }
90            IssueType::HighAfferentCoupling => {
91                "A module that many others depend on is hard to change. Any modification risks breaking dependents."
92            }
93            IssueType::UnnecessaryAbstraction => {
94                "Using abstract interfaces for closely-related stable components may add complexity without benefit."
95            }
96            IssueType::CircularDependency => {
97                "Circular dependencies make it impossible to understand, test, or modify components in isolation."
98            }
99            IssueType::HiddenCoupling => {
100                "Files frequently change together without an explicit code dependency. This suggests implicit shared knowledge or a missing abstraction."
101            }
102            IssueType::AccidentalVolatility => {
103                "A supporting or generic subdomain changes frequently despite being expected to be stable. This suggests churn from design or ownership issues rather than essential business volatility."
104            }
105            IssueType::ScatteredExternalCoupling => {
106                "A third-party crate is used directly from many internal modules, spreading upgrade and API-change risk across code you control."
107            }
108            // APOSD-inspired descriptions
109            IssueType::ShallowModule => {
110                "Interface complexity is close to implementation complexity. The module doesn't hide enough complexity behind a simple interface. (APOSD: Deep vs Shallow Modules)"
111            }
112            IssueType::PassThroughMethod => {
113                "Method only delegates to another method without adding significant functionality. Indicates unclear responsibility division. (APOSD: Pass-Through Methods)"
114            }
115            IssueType::HighCognitiveLoad => {
116                "Module requires too much knowledge to understand and modify. Too many public APIs, dependencies, or complex type signatures. (APOSD: Cognitive Load)"
117            }
118            // Khononov/Rust-specific descriptions
119            IssueType::GodModule => {
120                "Module has too many responsibilities - too many functions, types, or implementations. Consider splitting into focused, cohesive modules. (SRP violation)"
121            }
122            IssueType::PublicFieldExposure => {
123                "Struct has public fields accessed from other modules. Consider using getter methods to reduce coupling and allow future implementation changes."
124            }
125            IssueType::PrimitiveObsession => {
126                "Function has many primitive parameters of the same type. Consider using newtype pattern (e.g., `struct UserId(u64)`) for type safety and clarity."
127            }
128        }
129    }
130
131    /// Get a Japanese description of what this issue type means.
132    pub fn description_japanese(&self) -> &'static str {
133        match self {
134            IssueType::GlobalComplexity => {
135                "遠いコンポーネントへの強い結合は認知負荷を高め、理解や変更を難しくします。"
136            }
137            IssueType::CascadingChangeRisk => {
138                "頻繁に変わるコンポーネントへ強く結合すると、変更がシステム全体に波及しやすくなります。"
139            }
140            IssueType::InappropriateIntimacy => {
141                "モジュール境界を越えた内部詳細への直接アクセスはカプセル化を損ないます。"
142            }
143            IssueType::HighEfferentCoupling => {
144                "多くのモジュールに依存するモジュールは壊れやすく、テストも難しくなります。"
145            }
146            IssueType::HighAfferentCoupling => {
147                "多くのモジュールから依存されるモジュールは変更しづらく、依存元を壊すリスクがあります。"
148            }
149            IssueType::UnnecessaryAbstraction => {
150                "近く安定したコンポーネントに抽象インターフェースを使うと、利益より複雑さが増える場合があります。"
151            }
152            IssueType::CircularDependency => {
153                "循環依存はコンポーネントを単独で理解、テスト、変更することを難しくします。"
154            }
155            IssueType::HiddenCoupling => {
156                "明示的なコード依存がないのにファイルが頻繁に一緒に変わっています。暗黙の知識や不足した抽象化を示している可能性があります。"
157            }
158            IssueType::AccidentalVolatility => {
159                "安定しているはずの支援/汎用サブドメインが頻繁に変更されています。設計や所有権の問題によるチャーンの可能性があります。"
160            }
161            IssueType::ScatteredExternalCoupling => {
162                "サードパーティクレートが多くの内部モジュールから直接使われており、更新やAPI変更のリスクが広がっています。"
163            }
164            IssueType::ShallowModule => {
165                "インターフェースの複雑さが実装の複雑さに近く、単純なインターフェースの背後に十分な複雑さを隠せていません。"
166            }
167            IssueType::PassThroughMethod => {
168                "メソッドが価値を追加せず別メソッドへ委譲しており、責務分担が曖昧な可能性があります。"
169            }
170            IssueType::HighCognitiveLoad => {
171                "公開API、依存、複雑な型シグネチャが多く、理解や変更に必要な知識が多すぎます。"
172            }
173            IssueType::GodModule => {
174                "関数、型、実装が多すぎて責務が集中しています。焦点の絞られたモジュールへの分割を検討してください。"
175            }
176            IssueType::PublicFieldExposure => {
177                "構造体の公開フィールドが他モジュールから使われています。getterなどで結合を弱めることを検討してください。"
178            }
179            IssueType::PrimitiveObsession => {
180                "同じプリミティブ型の引数が多すぎます。newtypeパターンで型安全性と明確さを高めることを検討してください。"
181            }
182        }
183    }
184}