Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill solid-principles명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | solid-principles |
| description | > Use when this capability is needed. |
You are a senior software engineer. Help the user understand, apply, and evaluate SOLID principles with concrete, platform-specific examples and refactoring guidance.
A class should have only one reason to change.
Violation signs: Class handles networking AND parsing AND caching. ViewModel does API calls AND navigation AND analytics. Activity/Controller manages UI AND business logic.
// This class does EVERYTHING — networking, caching, UI logic
public class ProductManager {
public List<Product> fetchFromApi() { /* HTTP call */ }
public void saveToDatabase(List<Product> products) { /* Room insert */ }
public void trackAnalytics(String event) { /* Firebase call */ }
public String formatPrice(double price) { /* currency formatting */ }
public boolean isProductAvailable(Product p) { /* business logic */ }
}
class ProductRepository(private val api: ProductApi, private val dao: ProductDao) {
suspend fun getProducts(): List<Product> { /* fetch + cache */ }
}
class PriceFormatter(private val locale: Locale) {
fun format(price: Double): String { /* currency formatting */ }
}
class AvailabilityChecker {
fun isAvailable(product: Product): Boolean { /* business rule */ }
}
class AnalyticsTracker(private val firebase: FirebaseAnalytics) {
fun track(event: String) { /* tracking */ }
}
// Massive View Controller
@implementation ProductViewController
- (void)viewDidLoad {
[self fetchProductsFromAPI]; // networking
[self setupTableView]; // UI
[self configureAnalytics]; // analytics
[self checkUserPermissions]; // auth
[self validateProductData]; // business logic
}
@end
// Each concern is a separate type
class ProductListViewModel { /* presentation logic only */ }
class ProductRepository { /* data access only */ }
class ProductValidator { /* business rules only */ }
class AnalyticsService { /* tracking only */ }
// Bad: Widget does fetching, formatting, and navigation
class ProductPage extends StatefulWidget { /* 500 lines of everything */ }
// Good: Separate concerns
class ProductRepository { /* data access */ }
class ProductBloc extends Bloc<ProductEvent, ProductState> { /* state logic */ }
class PriceFormatter { /* formatting */ }
class ProductPage extends StatelessWidget { /* UI only, delegates to BLoC */ }
Software entities should be open for extension but closed for modification.
Violation signs: Adding a new feature requires modifying existing classes with if/else chains. Switch statements that grow with every new type.
// Adding a new payment method requires modifying this class
public class PaymentProcessor {
public void process(Payment payment) {
if (payment.type.equals("credit_card")) {
// process credit card
} else if (payment.type.equals("paypal")) {
// process paypal
} else if (payment.type.equals("crypto")) {
// process crypto — had to modify existing class!
}
}
}
// New payment methods are extensions, not modifications
interface PaymentStrategy {
fun process(payment: Payment): Result<Receipt>
}
class CreditCardPayment : PaymentStrategy { override fun process(payment: Payment) = /* ... */ }
class PayPalPayment : PaymentStrategy { override fun process(payment: Payment) = /* ... */ }
class CryptoPayment : PaymentStrategy { override fun process(payment: Payment) = /* ... */ }
// Adding ApplePayPayment doesn't touch any existing code
class PaymentProcessor(private val strategies: Map<PaymentType, PaymentStrategy>) {
fun process(payment: Payment): Result<Receipt> =
strategies[payment.type]?.process(payment) ?: Result.failure(UnsupportedPaymentException())
}
protocol PaymentStrategy {
func process(_ payment: Payment) async throws -> Receipt
}
struct CreditCardPayment: PaymentStrategy { func process(_ payment: Payment) async throws -> Receipt { /* ... */ } }
struct PayPalPayment: PaymentStrategy { func process(_ payment: Payment) async throws -> Receipt { /* ... */ } }
// Extend by adding new conformances, not modifying existing code
abstract class PaymentStrategy {
Future<Receipt> process(Payment payment);
}
class CreditCardPayment implements PaymentStrategy { /* ... */ }
class PayPalPayment implements PaymentStrategy { /* ... */ }
// Register new strategies without modifying PaymentProcessor
Subtypes must be substitutable for their base types without altering program correctness.
Violation signs: Subclass throws exceptions for methods the parent supports. Overriding a method to do nothing. Checking instanceof / is to handle subtypes differently.
class Bird {
public void fly() { /* fly logic */ }
}
class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Penguins can't fly!");
// Violates LSP — callers of Bird.fly() don't expect exceptions
}
}
interface Bird { fun move() }
interface FlyingBird : Bird { fun fly() }
class Sparrow : FlyingBird {
override fun move() { fly() }
override fun fly() { /* fly logic */ }
}
class Penguin : Bird {
override fun move() { /* waddle logic */ }
// No fly() — penguins aren't FlyingBirds
}
// Bad: ReadOnlyRepository extends MutableRepository but disallows writes
protocol Repository {
func getAll() async -> [Product]
func save(_ product: Product) async
func delete(_ id: String) async
}
class CachedRepository: Repository {
func save(_ product: Product) async {
fatalError("Cache is read-only!") // LSP violation
}
}
// Good: Separate read and write protocols
protocol ReadableRepository {
func getAll() async -> [Product]
}
protocol WritableRepository: ReadableRepository {
func save(_ product: Product) async
func delete(_ id: String)
}
Clients should not be forced to depend on interfaces they do not use.
Violation signs: A class implements an interface but leaves half the methods empty or throwing. A "God interface" with 20+ methods.
interface UserService {
User getUser(String id);
List<User> searchUsers(String query);
void createUser(User user);
void deleteUser(String id);
void sendEmail(String userId, String message); // Why is email in UserService?
void exportToCSV(List<User> users); // Why is export here?
boolean validatePassword(String password); // Why is validation here?
}
interface UserReader {
suspend fun getUser(id: String): User
suspend fun searchUsers(query: String): List<User>
}
interface UserWriter {
suspend fun createUser(user: User)
suspend fun deleteUser(id: String)
}
interface UserExporter {
suspend fun exportToCSV(users: List<User>): ByteArray
}
// Classes implement only what they need
// Bad: One massive repository interface
abstract class Repository<T> {
Future<T> getById(String id);
Future<List<T>> getAll();
Future<void> create(T item);
Future<void> update(T item);
Future<void> delete(String id);
Stream<List<T>> watchAll(); // Not all repos need streams
Future<void> syncWithServer(); // Not all repos sync
Future<int> count(); // Not all repos need count
}
// Good: Compose small interfaces
abstract class Readable<T> { Future<T> getById(String id); }
abstract class Listable<T> { Future<List<T>> getAll(); }
abstract class Writable<T> { Future<void> save(T item); }
abstract class Watchable<T> { Stream<List<T>> watchAll(); }
class ProductRepository implements Readable<Product>, Listable<Product>, Watchable<Product> {
// Only implements what it needs
}
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Violation signs: ViewModel directly instantiates Retrofit/URLSession. Business logic imports database framework. Constructor creates its own dependencies with new.
// ViewModel depends directly on concrete implementation
class ProductViewModel extends ViewModel {
// Tightly coupled — can't test without real API and database
private final RetrofitProductApi api = new RetrofitProductApi();
private final RoomProductDao dao = AppDatabase.getInstance().productDao();
}
// ViewModel depends on abstraction
class ProductViewModel @Inject constructor(
private val repository: ProductRepository // Interface, not impl
) : ViewModel()
// DI module wires the concrete implementation
@Module
@InstallIn(SingletonComponent::class)
abstract class DataModule {
@Binds
abstract fun bindProductRepo(impl: ProductRepositoryImpl): ProductRepository
}
// Protocol (abstraction)
protocol ProductRepository {
func getAll() async throws -> [Product]
}
// ViewModel depends on protocol, not concrete class
@Observable
class ProductListViewModel {
private let repo: ProductRepository
init(repo: ProductRepository) { self.repo = repo }
}
// In production: ViewModel(repo: APIProductRepository())
// In tests: ViewModel(repo: MockProductRepository())
// Abstract repository
abstract class ProductRepository {
Future<List<Product>> getAll();
}
// Concrete implementation
class ApiProductRepository implements ProductRepository {
final Dio _dio;
ApiProductRepository(this._dio);
@override
Future<List<Product>> getAll() async { /* API call */ }
}
// DI via Riverpod
final productRepoProvider = Provider<ProductRepository>((ref) {
return ApiProductRepository(ref.read(dioProvider));
});
// Override in tests
final container = ProviderContainer(overrides: [
productRepoProvider.overrideWithValue(MockProductRepository()),
]);
| Platform | Modern | Legacy |
|---|---|---|
| Android | Hilt (recommended), Koin | Dagger 2, manual |
| iOS | Swinject, Resolver, Factory, manual | Typhoon (ObjC), manual |
| Flutter | Riverpod, get_it + injectable | Provider, manual |
| Spring | Spring IoC (constructor injection) | — |
| Node | NestJS DI, tsyringe, awilix | manual |
| Scenario | Apply SOLID? |
|---|---|
| 3+ implementations exist or are likely | Yes — create abstraction |
| Only 1 implementation, no tests needed | No — direct dependency is fine |
| Crossing module/layer boundary | Yes — always use interfaces |
| Internal helper within a single class | No — keep it simple |
## SOLID Assessment
- **Code/Module:** [what was evaluated]
- **Violations found:** [list with principle and location]
## Recommendations
| Principle | Violation | Refactoring |
|-----------|-----------|-------------|
| SRP | ... | ... |
## Refactored Code
[Before/after examples]
Source: ashutoshsrivastava17/skill-library — distributed by TomeVault.