인스턴스 변수를 가진 모듈은 유해할 수 있습니다
Rails에서 모듈과 인스턴스 변수를 무분별하게 사용할 때 발생하는 문제점과 이를 해결하는 올바른 패턴, RuboCop 규칙 비활성화 방법을 설명합니다.
배경 # Rails는 어디서든 모듈과 인스턴스 변수를 사용하도록 권장하는 경향이 있습니다. 예를 들어, 컨트롤러, 헬퍼, 뷰에서 인스턴스 변수를 사용합니다. 또한 ActiveSupport::Concern 의 사용을 권장하는데, 이는 모든 것을 하나의 거대한 단일 객체에 저장한다는 생각을 더욱 강화하며, 사람들이 그 하나의 거대한 객체 안에서 모든 것에 접근할 수 있게 합니다. 문제점 # 물론 이 방식은 개발할 때 편리합니다. 필요한 모든 것이 손 닿는 곳에 있기 때문입니다. 하지만 해당 객체가 커질수록 같은 이유로 나중에는 통제 불능 상태가 되는 등 여러 단점이 있습니다. 동일한 컨텍스트 안에 너무 많은 것이 들어있어, 각 요소들이 서로 강하게 결합되어 있는지 또는 서로 의존하고 있는지 알기 어렵습니다. 복잡도가 어느 수준을 넘으면 파악이 매우 어려워지고, 코드 추적도 극도로 힘들어집니다. 예를 들어, 하나의 클래스가 3개의 서로 다른 인스턴스 변수를 사용하고, 그 모든 변수가 3개의 서로 다른 모듈에서 초기화되고 조작될 수 있습니다. 이 변수들이 문제를 일으키기 시작할 때 추적하기가 어렵습니다. 어떤 모듈이 변수 중 하나를 갑자기 변경할지 알 수 없습니다. 모든 것이 무엇이든 건드릴 수 있습니다. 유사한 우려 사항 # 다중 상속이 나쁘다고 말하는 사람들이 있습니다. 여러 인스턴스 변수가 여기저기 흩어진 여러 모듈을 혼합하는 것도 같은 문제를 겪습니다. ActiveSupport::Concern 도 마찬가지입니다. 참고: concerns를 전용 클래스 & 컴포지션으로 대체하는 것 고려 비슷한 아이디어도 있습니다: 데코레이터와 인터페이스 분리를 사용하여 과도하게 커지는 모델 문제 해결 included 가 전체 문제를 해결하지는 않는다는 점을 참고하세요. 의존성을 정의하긴 하지만, 각 모듈이 최종 거대 객체의 인스턴스 변수를 통해 암묵적으로 통신하는 것을 여전히 허용하며, 바로 그것이 문제의 핵심입니다. 해결책 # 거대한 객체를 여러 객체로 분리하고, 그 객체들이 API, 즉 공개 메서드를 통해 서로 통신하게 해야 합니다. 간단히 말해, 상속보다는 컴포지션입니다. 이 방식으로 각각의 작은 객체는 자신만의 제한된 상태, 즉 인스턴스 변수를 가지게 됩니다. 하나의 인스턴스 변수가 잘못되면, 그것이 그 작은 객체 하나에서 비롯된 것임을 명확히 알 수 있습니다. 다른 어떤 것도 그것을 건드릴 수 없기 때문입니다. 명확하게 정의된 API를 통해 결합도가 낮아지고 디버그 및 추적이 훨씬 쉬워지며, 다른 객체들이 사용하기 위한 확장성도 훨씬 높아집니다. 암묵적인 의존성이 아닌 명확한 방식으로 통신하기 때문입니다. 허용되는 사용 # 하지만 모듈에서 인스턴스 변수를 사용하는 것이 항상 나쁜 것은 아닙니다. 같은 모듈 안에서만 사용되는 경우, 즉 다른 모듈이나 객체가 그 변수를 건드리지 않는다면 허용되는 사용입니다. 특히 ||= 와 함께 단일 인스턴스 변수를 사용하여 값을 설정하는 경우는 허용합니다. 이는 다음과 같은 모습입니다: module M de