Squashed 'docs/standards/playbook/' changes from c3f8137..25d895d

25d895d 🐛 fix(gitea_workflow): clean up temp repos after job steps
2bc3b11 🐛 fix(gitea_workflow): clean up temporary repo dirs in workflows
98c3f30 📝 docs(agent_rules): allow plan execution on current branch
16c7230 📝 docs(prompts): define custom verify layering
8efc4dd 🐛 fix(skills): quote commit-message description
bc8498f 🐛 fix(ci): install tomli for gitea tests
55cda3b 🐛 fix(tests): report missing toml parser clearly
c0729c7 🐛 fix(playbook): import Optional for cli compatibility
63e24bf 📦 deps(skills): sync thirdparty skills
d2f9356 🐛 fix(ci): isolate gitea workflow repos
588b81d 🐛 fix(ci): inline gitea workflow bootstrap
e0b1c3a ♻️ refactor(skills): standardize first-party skill contracts
2c5050d ♻️ refactor(skills): rename repo skills source dir
f049dfb 📦 deps(skills): drop duplicate first-party superpowers skills
234b335  feat(workflow): add superpowers planning and execution state tracking
c1702a6 📝 docs(markdown): format tracked markdown and drop stale templates
2325409 📝 docs(markdown): clarify optional markdownlint usage
214c44e 🔧 chore(markdown): add markdownlint baseline and lint fixes
a22b324 📝 docs(templates): add execution and memory-bank prompt templates
223a797 📝 docs(templates): update README for Claude Code and current features
4ac8672 📝 docs: simplify README + platform-agnostic tools + auto-create local rules
2431c9d 📝 docs: add claude_md config and use cross-platform paths
d64b248 📝 docs: fix README.md inaccuracies and add Claude Code info
c8d6bf2 🐛 fix(playbook): use relative paths in CLAUDE.md when not at project root
6518f0f  feat(playbook): auto-create CLAUDE.md with path discovery
6ec9a45  feat(skills): add skill_link symlink support + platform-agnostic prompt
9f8b6b5 📝 docs: update README and config example for Claude Code support
79cff6c 📝 docs(skills): add Claude Code platform support
452c6f5  feat(playbook): auto-inject AGENTS.md into CLAUDE.md
e1dbf3c 🐛 fix(skills): remove dual-path from commit-message skill
f3a7259 🔧 chore(ci): use prepare_repo.sh in both workflows
da08212 🔧 chore(ci): extract prepare_repo.sh and clean up workflows
7ade85e 🗑️ remove(tsl): drop syntax_book/, data/ source and build script
f94dba0 ♻️ refactor(skills): update playbook.py and tests for thirdparty/ layout
b3df412 ♻️ refactor(skills): separate thirdparty skills into thirdparty/ subdirectory
64950e7 📦 deps(skills): sync thirdparty skills
a2e3cb0  feat(playbook): add no_backup deploy controls
8609d59 🐛 fix(docs): repair reference catalog source links
956da11 🐛 fix(playbook): publish hidden ci test fixes
3f67754 📦 deps(skills): sync thirdparty skills
08ca87b 📦 deps(skills): add karpathy thirdparty sync
96b705b 📝 docs(tsl): rebuild canonical syntax and routing manual
3ed5052 📦 deps(skills): sync thirdparty skills
60108dd 📦 deps(skills): sync thirdparty skills
da85d4e 🐛 fix(thirdparty): prune nested project snapshots
a2a697e 📦 deps(skills): sync thirdparty skills
9df610a 🐛 fix(thirdparty): exclude duplicated superpowers skills
33dd5bb 🐛 fix(thirdparty): preserve optional manifest fields
91b0ea7 🐛 fix(thirdparty): preserve manifest during snapshot update
2e26f98 🔧 chore(thirdparty): generalize skills sync pipeline
5b9c1e3 📦 deps(skills): sync superpowers
2f2d34a 📝 docs(readme): normalize subtree command spacing
62db7db 🐛 fix(ci): serialize superpowers update and sync
3463223 🐛 fix(ci): use literal superpowers sync paths
48f6de8 📦 deps(skills): sync superpowers
4b23529 🔧 chore(ci): merge superpowers update and sync workflow
a56d75b 📦 deps(skills): sync superpowers
84bcefa 🔧 chore(ci): use ci[bot] commit author name
00a07e5 📦 deps(skills): sync superpowers
7b84daf 🐛 fix(templates): enforce main loop progress tracking
51373d7 🔧 chore(ci): automate superpowers sync workflow
eaaa39c 🐛 fix(ci): prevent stale superpowers sync from restoring skills block
79755c6 📦 deps(skills): sync superpowers
836d878 📦 deps(skills): sync superpowers
8216c9f 📦 deps(skills): sync superpowers
9439505 🐛 fix(playbook): address reported repo issues

git-subtree-dir: docs/standards/playbook
git-subtree-split: 25d895d8b3f56624ccfe99ad7289e9eb49e0f316
This commit is contained in:
csh
2026-05-24 13:04:14 +08:00
parent 35e6a301aa
commit 3d83740f88
292 changed files with 30774 additions and 218828 deletions
+51
View File
@@ -0,0 +1,51 @@
No,Category,Guideline,Description,Do,Don't,Code Good,Code Bad,Severity,Docs URL
1,Views,Use struct for views,SwiftUI views are value types,struct MyView: View,class MyView: View,struct ContentView: View { var body: some View },class ContentView: View,High,https://developer.apple.com/documentation/swiftui/view
2,Views,Keep views small and focused,Single responsibility for each view,Extract subviews for complex layouts,Large monolithic views,Extract HeaderView FooterView,500+ line View struct,Medium,
3,Views,Use body computed property,body returns the view hierarchy,var body: some View { },func body() -> some View,"var body: some View { Text(""Hello"") }",func body() -> Text,High,
4,Views,Prefer composition over inheritance,Compose views using ViewBuilder,Combine smaller views,Inheritance hierarchies,VStack { Header() Content() },class SpecialView extends BaseView,Medium,
5,State,Use @State for local state,Simple value types owned by view,@State for view-local primitives,@State for shared data,@State private var count = 0,@State var sharedData: Model,High,https://developer.apple.com/documentation/swiftui/state
6,State,Use @Binding for two-way data,Pass mutable state to child views,@Binding for child input,@State in child for parent data,@Binding var isOn: Bool,$isOn to pass binding,Medium,https://developer.apple.com/documentation/swiftui/binding
7,State,Use @StateObject for reference types,ObservableObject owned by view,@StateObject for view-created objects,@ObservedObject for owned objects,@StateObject private var vm = ViewModel(),@ObservedObject var vm = ViewModel(),High,https://developer.apple.com/documentation/swiftui/stateobject
8,State,Use @ObservedObject for injected objects,Reference types passed from parent,@ObservedObject for injected dependencies,@StateObject for injected objects,@ObservedObject var vm: ViewModel,@StateObject var vm: ViewModel (injected),High,https://developer.apple.com/documentation/swiftui/observedobject
9,State,Use @EnvironmentObject for shared state,App-wide state injection,@EnvironmentObject for global state,Prop drilling through views,@EnvironmentObject var settings: Settings,Pass settings through 5 views,Medium,https://developer.apple.com/documentation/swiftui/environmentobject
10,State,Use @Published in ObservableObject,Automatically publish property changes,@Published for observed properties,Manual objectWillChange calls,@Published var items: [Item] = [],var items: [Item] { didSet { objectWillChange.send() } },Medium,
11,Observable,Use @Observable macro (iOS 17+),Modern observation without Combine,@Observable class for view models,ObservableObject for new projects,@Observable class ViewModel { },class ViewModel: ObservableObject,Medium,https://developer.apple.com/documentation/observation
12,Observable,Use @Bindable for @Observable,Create bindings from @Observable,@Bindable var vm for bindings,@Binding with @Observable,@Bindable var viewModel,$viewModel.name with @Observable,Medium,
13,Layout,Use VStack HStack ZStack,Standard stack-based layouts,Stacks for linear arrangements,GeometryReader for simple layouts,VStack { Text() Image() },GeometryReader for vertical list,Medium,https://developer.apple.com/documentation/swiftui/vstack
14,Layout,Use LazyVStack LazyHStack for lists,Lazy loading for performance,Lazy stacks for long lists,Regular stacks for 100+ items,LazyVStack { ForEach(items) },VStack { ForEach(largeArray) },High,https://developer.apple.com/documentation/swiftui/lazyvstack
15,Layout,Use GeometryReader sparingly,Only when needed for sizing,GeometryReader for responsive layouts,GeometryReader everywhere,GeometryReader for aspect ratio,GeometryReader wrapping everything,Medium,
16,Layout,Use spacing and padding consistently,Consistent spacing throughout app,Design system spacing values,Magic numbers for spacing,.padding(16) or .padding(),".padding(13), .padding(17)",Low,
17,Layout,Use frame modifiers correctly,Set explicit sizes when needed,.frame(maxWidth: .infinity),Fixed sizes for responsive content,.frame(maxWidth: .infinity),.frame(width: 375),Medium,
18,Modifiers,Order modifiers correctly,Modifier order affects rendering,Background before padding for full coverage,Wrong modifier order,.padding().background(Color.red),.background(Color.red).padding(),High,
19,Modifiers,Create custom ViewModifiers,Reusable modifier combinations,ViewModifier for repeated styling,Duplicate modifier chains,struct CardStyle: ViewModifier,.shadow().cornerRadius() everywhere,Medium,https://developer.apple.com/documentation/swiftui/viewmodifier
20,Modifiers,Use conditional modifiers carefully,Avoid changing view identity,if-else with same view type,Conditional that changes view identity,Text(title).foregroundColor(isActive ? .blue : .gray),if isActive { Text().bold() } else { Text() },Medium,
21,Navigation,Use NavigationStack (iOS 16+),Modern navigation with type-safe paths,NavigationStack with navigationDestination,NavigationView for new projects,NavigationStack { },NavigationView { } (deprecated),Medium,https://developer.apple.com/documentation/swiftui/navigationstack
22,Navigation,Use navigationDestination,Type-safe navigation destinations,.navigationDestination(for:),NavigationLink(destination:),.navigationDestination(for: Item.self),NavigationLink(destination: DetailView()),Medium,
23,Navigation,Use @Environment for dismiss,Programmatic navigation dismissal,@Environment(\.dismiss) var dismiss,presentationMode (deprecated),@Environment(\.dismiss) var dismiss,@Environment(\.presentationMode),Low,
24,Lists,Use List for scrollable content,Built-in scrolling and styling,List for standard scrollable content,ScrollView + VStack for simple lists,List { ForEach(items) { } },ScrollView { VStack { ForEach } },Low,https://developer.apple.com/documentation/swiftui/list
25,Lists,Provide stable identifiers,Use Identifiable or explicit id,Identifiable protocol or id parameter,Index as identifier,ForEach(items) where Item: Identifiable,"ForEach(items.indices, id: \.self)",High,
26,Lists,Use onDelete and onMove,Standard list editing,onDelete for swipe to delete,Custom delete implementation,.onDelete(perform: delete),.onTapGesture for delete,Low,
27,Forms,Use Form for settings,Grouped input controls,Form for settings screens,Manual grouping for forms,Form { Section { Toggle() } },VStack { Toggle() },Low,https://developer.apple.com/documentation/swiftui/form
28,Forms,Use @FocusState for keyboard,Manage keyboard focus,@FocusState for text field focus,Manual first responder handling,@FocusState private var isFocused: Bool,UIKit first responder,Medium,https://developer.apple.com/documentation/swiftui/focusstate
29,Forms,Validate input properly,Show validation feedback,Real-time validation feedback,Submit without validation,TextField with validation state,TextField without error handling,Medium,
30,Async,Use .task for async work,Automatic cancellation on view disappear,.task for view lifecycle async,onAppear with Task,.task { await loadData() },onAppear { Task { await loadData() } },Medium,https://developer.apple.com/documentation/swiftui/view/task(priority:_:)
31,Async,Handle loading states,Show progress during async operations,ProgressView during loading,Empty view during load,if isLoading { ProgressView() },No loading indicator,Medium,
32,Async,Use @MainActor for UI updates,Ensure UI updates on main thread,@MainActor on view models,Manual DispatchQueue.main,@MainActor class ViewModel,DispatchQueue.main.async,Medium,
33,Animation,Use withAnimation,Animate state changes,withAnimation for state transitions,No animation for state changes,withAnimation { isExpanded.toggle() },isExpanded.toggle(),Low,https://developer.apple.com/documentation/swiftui/withanimation(_:_:)
34,Animation,Use .animation modifier,Apply animations to views,.animation(.spring()) on view,Manual animation timing,.animation(.easeInOut),CABasicAnimation equivalent,Low,
35,Animation,Respect reduced motion,Check accessibility settings,Check accessibilityReduceMotion,Ignore motion preferences,@Environment(\.accessibilityReduceMotion),Always animate regardless,High,
36,Preview,Use #Preview macro (Xcode 15+),Modern preview syntax,#Preview for view previews,PreviewProvider protocol,#Preview { ContentView() },struct ContentView_Previews: PreviewProvider,Low,
37,Preview,Create multiple previews,Test different states and devices,Multiple previews for states,Single preview only,"#Preview(""Light"") { } #Preview(""Dark"") { }",Single preview configuration,Low,
38,Preview,Use preview data,Dedicated preview mock data,Static preview data,Production data in previews,Item.preview for preview,Fetch real data in preview,Low,
39,Performance,Avoid expensive body computations,Body should be fast to compute,Precompute in view model,Heavy computation in body,vm.computedValue in body,Complex calculation in body,High,
40,Performance,Use Equatable views,Skip unnecessary view updates,Equatable for complex views,Default equality for all views,struct MyView: View Equatable,No Equatable conformance,Medium,
41,Performance,Profile with Instruments,Measure before optimizing,Use SwiftUI Instruments,Guess at performance issues,Profile with Instruments,Optimize without measuring,Medium,
42,Accessibility,Add accessibility labels,Describe UI elements,.accessibilityLabel for context,Missing labels,".accessibilityLabel(""Close button"")",Button without label,High,https://developer.apple.com/documentation/swiftui/view/accessibilitylabel(_:)-1d7jv
43,Accessibility,Support Dynamic Type,Respect text size preferences,Scalable fonts and layouts,Fixed font sizes,.font(.body) with Dynamic Type,.font(.system(size: 16)),High,
44,Accessibility,Use semantic views,Proper accessibility traits,Correct accessibilityTraits,Wrong semantic meaning,Button for actions Image for display,Image that acts like button,Medium,
45,Testing,Use ViewInspector for testing,Third-party view testing,ViewInspector for unit tests,UI tests only,ViewInspector assertions,Only XCUITest,Medium,
46,Testing,Test view models,Unit test business logic,XCTest for view model,Skip view model testing,Test ViewModel methods,No unit tests,Medium,
47,Testing,Use preview as visual test,Previews catch visual regressions,Multiple preview configurations,No visual verification,Preview different states,Single preview only,Low,
48,Architecture,Use MVVM pattern,Separate view and logic,ViewModel for business logic,Logic in View,ObservableObject ViewModel,@State for complex logic,Medium,
49,Architecture,Keep views dumb,Views display view model state,View reads from ViewModel,Business logic in View,view.items from vm.items,Complex filtering in View,Medium,
50,Architecture,Use dependency injection,Inject dependencies for testing,Initialize with dependencies,Hard-coded dependencies,init(service: ServiceProtocol),let service = RealService(),Medium,
1 No Category Guideline Description Do Don't Code Good Code Bad Severity Docs URL
2 1 Views Use struct for views SwiftUI views are value types struct MyView: View class MyView: View struct ContentView: View { var body: some View } class ContentView: View High https://developer.apple.com/documentation/swiftui/view
3 2 Views Keep views small and focused Single responsibility for each view Extract subviews for complex layouts Large monolithic views Extract HeaderView FooterView 500+ line View struct Medium
4 3 Views Use body computed property body returns the view hierarchy var body: some View { } func body() -> some View var body: some View { Text("Hello") } func body() -> Text High
5 4 Views Prefer composition over inheritance Compose views using ViewBuilder Combine smaller views Inheritance hierarchies VStack { Header() Content() } class SpecialView extends BaseView Medium
6 5 State Use @State for local state Simple value types owned by view @State for view-local primitives @State for shared data @State private var count = 0 @State var sharedData: Model High https://developer.apple.com/documentation/swiftui/state
7 6 State Use @Binding for two-way data Pass mutable state to child views @Binding for child input @State in child for parent data @Binding var isOn: Bool $isOn to pass binding Medium https://developer.apple.com/documentation/swiftui/binding
8 7 State Use @StateObject for reference types ObservableObject owned by view @StateObject for view-created objects @ObservedObject for owned objects @StateObject private var vm = ViewModel() @ObservedObject var vm = ViewModel() High https://developer.apple.com/documentation/swiftui/stateobject
9 8 State Use @ObservedObject for injected objects Reference types passed from parent @ObservedObject for injected dependencies @StateObject for injected objects @ObservedObject var vm: ViewModel @StateObject var vm: ViewModel (injected) High https://developer.apple.com/documentation/swiftui/observedobject
10 9 State Use @EnvironmentObject for shared state App-wide state injection @EnvironmentObject for global state Prop drilling through views @EnvironmentObject var settings: Settings Pass settings through 5 views Medium https://developer.apple.com/documentation/swiftui/environmentobject
11 10 State Use @Published in ObservableObject Automatically publish property changes @Published for observed properties Manual objectWillChange calls @Published var items: [Item] = [] var items: [Item] { didSet { objectWillChange.send() } } Medium
12 11 Observable Use @Observable macro (iOS 17+) Modern observation without Combine @Observable class for view models ObservableObject for new projects @Observable class ViewModel { } class ViewModel: ObservableObject Medium https://developer.apple.com/documentation/observation
13 12 Observable Use @Bindable for @Observable Create bindings from @Observable @Bindable var vm for bindings @Binding with @Observable @Bindable var viewModel $viewModel.name with @Observable Medium
14 13 Layout Use VStack HStack ZStack Standard stack-based layouts Stacks for linear arrangements GeometryReader for simple layouts VStack { Text() Image() } GeometryReader for vertical list Medium https://developer.apple.com/documentation/swiftui/vstack
15 14 Layout Use LazyVStack LazyHStack for lists Lazy loading for performance Lazy stacks for long lists Regular stacks for 100+ items LazyVStack { ForEach(items) } VStack { ForEach(largeArray) } High https://developer.apple.com/documentation/swiftui/lazyvstack
16 15 Layout Use GeometryReader sparingly Only when needed for sizing GeometryReader for responsive layouts GeometryReader everywhere GeometryReader for aspect ratio GeometryReader wrapping everything Medium
17 16 Layout Use spacing and padding consistently Consistent spacing throughout app Design system spacing values Magic numbers for spacing .padding(16) or .padding() .padding(13), .padding(17) Low
18 17 Layout Use frame modifiers correctly Set explicit sizes when needed .frame(maxWidth: .infinity) Fixed sizes for responsive content .frame(maxWidth: .infinity) .frame(width: 375) Medium
19 18 Modifiers Order modifiers correctly Modifier order affects rendering Background before padding for full coverage Wrong modifier order .padding().background(Color.red) .background(Color.red).padding() High
20 19 Modifiers Create custom ViewModifiers Reusable modifier combinations ViewModifier for repeated styling Duplicate modifier chains struct CardStyle: ViewModifier .shadow().cornerRadius() everywhere Medium https://developer.apple.com/documentation/swiftui/viewmodifier
21 20 Modifiers Use conditional modifiers carefully Avoid changing view identity if-else with same view type Conditional that changes view identity Text(title).foregroundColor(isActive ? .blue : .gray) if isActive { Text().bold() } else { Text() } Medium
22 21 Navigation Use NavigationStack (iOS 16+) Modern navigation with type-safe paths NavigationStack with navigationDestination NavigationView for new projects NavigationStack { } NavigationView { } (deprecated) Medium https://developer.apple.com/documentation/swiftui/navigationstack
23 22 Navigation Use navigationDestination Type-safe navigation destinations .navigationDestination(for:) NavigationLink(destination:) .navigationDestination(for: Item.self) NavigationLink(destination: DetailView()) Medium
24 23 Navigation Use @Environment for dismiss Programmatic navigation dismissal @Environment(\.dismiss) var dismiss presentationMode (deprecated) @Environment(\.dismiss) var dismiss @Environment(\.presentationMode) Low
25 24 Lists Use List for scrollable content Built-in scrolling and styling List for standard scrollable content ScrollView + VStack for simple lists List { ForEach(items) { } } ScrollView { VStack { ForEach } } Low https://developer.apple.com/documentation/swiftui/list
26 25 Lists Provide stable identifiers Use Identifiable or explicit id Identifiable protocol or id parameter Index as identifier ForEach(items) where Item: Identifiable ForEach(items.indices, id: \.self) High
27 26 Lists Use onDelete and onMove Standard list editing onDelete for swipe to delete Custom delete implementation .onDelete(perform: delete) .onTapGesture for delete Low
28 27 Forms Use Form for settings Grouped input controls Form for settings screens Manual grouping for forms Form { Section { Toggle() } } VStack { Toggle() } Low https://developer.apple.com/documentation/swiftui/form
29 28 Forms Use @FocusState for keyboard Manage keyboard focus @FocusState for text field focus Manual first responder handling @FocusState private var isFocused: Bool UIKit first responder Medium https://developer.apple.com/documentation/swiftui/focusstate
30 29 Forms Validate input properly Show validation feedback Real-time validation feedback Submit without validation TextField with validation state TextField without error handling Medium
31 30 Async Use .task for async work Automatic cancellation on view disappear .task for view lifecycle async onAppear with Task .task { await loadData() } onAppear { Task { await loadData() } } Medium https://developer.apple.com/documentation/swiftui/view/task(priority:_:)
32 31 Async Handle loading states Show progress during async operations ProgressView during loading Empty view during load if isLoading { ProgressView() } No loading indicator Medium
33 32 Async Use @MainActor for UI updates Ensure UI updates on main thread @MainActor on view models Manual DispatchQueue.main @MainActor class ViewModel DispatchQueue.main.async Medium
34 33 Animation Use withAnimation Animate state changes withAnimation for state transitions No animation for state changes withAnimation { isExpanded.toggle() } isExpanded.toggle() Low https://developer.apple.com/documentation/swiftui/withanimation(_:_:)
35 34 Animation Use .animation modifier Apply animations to views .animation(.spring()) on view Manual animation timing .animation(.easeInOut) CABasicAnimation equivalent Low
36 35 Animation Respect reduced motion Check accessibility settings Check accessibilityReduceMotion Ignore motion preferences @Environment(\.accessibilityReduceMotion) Always animate regardless High
37 36 Preview Use #Preview macro (Xcode 15+) Modern preview syntax #Preview for view previews PreviewProvider protocol #Preview { ContentView() } struct ContentView_Previews: PreviewProvider Low
38 37 Preview Create multiple previews Test different states and devices Multiple previews for states Single preview only #Preview("Light") { } #Preview("Dark") { } Single preview configuration Low
39 38 Preview Use preview data Dedicated preview mock data Static preview data Production data in previews Item.preview for preview Fetch real data in preview Low
40 39 Performance Avoid expensive body computations Body should be fast to compute Precompute in view model Heavy computation in body vm.computedValue in body Complex calculation in body High
41 40 Performance Use Equatable views Skip unnecessary view updates Equatable for complex views Default equality for all views struct MyView: View Equatable No Equatable conformance Medium
42 41 Performance Profile with Instruments Measure before optimizing Use SwiftUI Instruments Guess at performance issues Profile with Instruments Optimize without measuring Medium
43 42 Accessibility Add accessibility labels Describe UI elements .accessibilityLabel for context Missing labels .accessibilityLabel("Close button") Button without label High https://developer.apple.com/documentation/swiftui/view/accessibilitylabel(_:)-1d7jv
44 43 Accessibility Support Dynamic Type Respect text size preferences Scalable fonts and layouts Fixed font sizes .font(.body) with Dynamic Type .font(.system(size: 16)) High
45 44 Accessibility Use semantic views Proper accessibility traits Correct accessibilityTraits Wrong semantic meaning Button for actions Image for display Image that acts like button Medium
46 45 Testing Use ViewInspector for testing Third-party view testing ViewInspector for unit tests UI tests only ViewInspector assertions Only XCUITest Medium
47 46 Testing Test view models Unit test business logic XCTest for view model Skip view model testing Test ViewModel methods No unit tests Medium
48 47 Testing Use preview as visual test Previews catch visual regressions Multiple preview configurations No visual verification Preview different states Single preview only Low
49 48 Architecture Use MVVM pattern Separate view and logic ViewModel for business logic Logic in View ObservableObject ViewModel @State for complex logic Medium
50 49 Architecture Keep views dumb Views display view model state View reads from ViewModel Business logic in View view.items from vm.items Complex filtering in View Medium
51 50 Architecture Use dependency injection Inject dependencies for testing Initialize with dependencies Hard-coded dependencies init(service: ServiceProtocol) let service = RealService() Medium