window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster가 이미 존재합니다') } else { w.LeadBooster = { q: [], on: 함수 (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: 함수 (n) { this.q.push({ t: 't', n: n }) }, } } })() 안녕하세요, 저는 포로입니다 - The Codest
The Codest
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 산업 분야
    • 핀테크 및 뱅킹
    • E-commerce
    • 애드테크
    • 헬스 테크
    • 제조
    • 물류
    • 자동차
    • IOT
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
뒤로 화살표 뒤로 가기
2018-01-03
소프트웨어 개발

안녕하세요, 포로입니다.

카타리나 자루가

많은 사람들이 Rails 프레임워크로 시작하여 루비를 배우고 있지만, 안타깝게도 이것은 이 언어를 배우는 최악의 방법입니다. 오해하지 마세요: Rails는 훌륭하며 많은 기술적 세부 사항을 다루지 않고도 웹 애플리케이션을 빠르고 효율적으로 구축할 수 있도록 도와줍니다.

만나서 반갑습니다!

많은 사람들이 Rails 프레임워크로 시작하여 루비를 배우고 있지만, 안타깝게도 이것은 이 언어를 배우는 최악의 방법입니다. 오해하지 마세요: Rails는 훌륭하며 많은 기술적 세부 사항을 다루지 않고도 웹 애플리케이션을 빠르고 효율적으로 구축할 수 있도록 도와줍니다. 일을 간단하게 만들어주는 많은 "Rails 마법"을 제공합니다. 그리고 초보 프로그래머에게는 "살아있다!"라고 말할 수 있고 모든 부분이 서로 맞고 사람들이 앱을 사용하는 것을 볼 수 있을 때가 가장 즐거운 순간이기 때문에 정말 좋습니다. 하지만 좋은 프로그래머와 평균적인 프로그래머를 구별하는 한 가지가 있습니다. 좋은 프로그래머는 자신이 사용하는 도구가 어떻게 작동하는지 이해합니다. 여기서 "도구를 이해한다"는 것은 프레임워크에서 제공하는 모든 메서드와 모듈을 아는 것이 아니라 프레임워크가 어떻게 작동하는지, "Rails 마법"이 어떻게 일어나는지 이해하는 것을 의미합니다. 그래야만 Rails로 객체를 사용하고 프로그래밍하는 데 편안함을 느낄 수 있습니다. 객체 지향 프로그래밍의 기초이자 복잡한 Rails 애플리케이션을 더 쉽게 만드는 비밀 무기는 제목에서 이미 언급된 PORO, 즉 Plain Old Ruby Object입니다.

이 이름 뒤에 숨겨진 비밀은 무엇일까요? 이 위대한 비밀 무기는 무엇일까요? 그것은 아무것도 상속하지 않는 단순한 루비 클래스입니다. 네, 바로 그거죠.

어썸포로 클래스
end

무엇을 도와드릴까요?

사용자 수와 기대치가 증가함에 따라 애플리케이션을 지속적으로 개발하고 새로운 기능을 추가하고 있습니다. 그러다 보면 아무리 용감한 개발자라도 전염병처럼 피하고 싶어하는 극도로 뒤틀린 논리의 어두운 지점을 점점 더 많이 만나게 됩니다. 이러한 장소가 많을수록 애플리케이션을 관리하고 개발하기가 더 어려워집니다. 표준적인 예는 새 사용자를 등록하는 작업으로, 이 이벤트와 관련된 다른 작업 그룹 전체를 트리거합니다:

  • 스팸 데이터베이스에서 IP 주소를 확인합니다,
  • 새 사용자에게 이메일을 보냅니다,
  • 추천 사용자의 계정에 보너스를 추가합니다,
  • 관련 서비스에서 계정을 만들 수 있습니다,
  • 그리고 더 많은...

샘플 코드 사용자 등록을 담당할 수 있습니다:

등록 컨트롤러 클래스 < 애플리케이션 컨트롤러
  def create
    user = User.new(registration_params)
    if user.valid? && ip_valid?(registration_ip)
      user.save!
      user.add_bonuses
      user.synchronize_related_accounts
      user.send_email
    end
  end
end

좋아, 코딩을 했고 모든 것이 작동하지만... 이 모든 코드가 정말 괜찮은 건가요? 더 잘 작성할 수 있을까요? 우선, 프로그래밍의 기본 원칙인 단일 책임 원칙을 위반하고 있으므로 더 잘 작성할 수 있을 것입니다. 하지만 어떻게? 이 부분에서 이미 언급한 PORO가 도움이 될 수 있습니다. 모든 관련 서비스를 알리는 한 가지 일만 담당하는 RegistrationService 클래스를 분리하는 것으로 충분합니다. 서비스별로 우리는 위에서 이미 선택한 개별 작업을 고려할 것입니다. 동일한 컨트롤러에서 등록 서비스 객체를 생성하고 "fire!" 메서드를 호출하기만 하면 됩니다. 코드가 훨씬 명확해지고 컨트롤러가 차지하는 공간이 줄어들었으며 새로 생성된 각 클래스는 이제 하나의 액션만 담당하므로 필요한 경우 쉽게 교체할 수 있습니다.

등록 서비스 클래스
  def fire!(params)
    user = User.new(params)
    if user.valid? && ip_validator.valid?(registration_ip)
      user.save!
      after_registered_events(user)
    end
    user
  end
  private
  def after_registered_events(user)
    BonusesCreator.new.fire!(user)
    AccountsSynchronizer.fire!(user)
    EmailSender.fire!(user)
  end
  def ip_validator
    @ip_validator ||= IpValidator.new
  end
end
등록 컨트롤러 클래스 < 애플리케이션 컨트롤러
  def create
    user = RegistrationService.new.fire!(registration_params)
  end
end

그러나 평범한 루비 객체는 컨트롤러에만 유용하지 않을 수 있습니다. 만들고 있는 애플리케이션이 월별 청구 시스템을 사용한다고 가정해 보세요. 이러한 청구서를 생성하는 정확한 날짜는 중요하지 않으며 특정 월과 연도와 관련이 있다는 것만 알면 됩니다. 물론 매월 1일로 날짜를 설정하고 이 정보를 "Date" 클래스의 객체에 저장할 수 있지만 이는 실제 정보도 아니며 애플리케이션에 필요하지도 않습니다. PORO를 사용하면 필요한 정확한 정보를 저장하는 객체 "MonthOfYear" 클래스를 만들 수 있습니다. 또한 "Comparable" 모듈을 적용하면 Date 클래스를 사용할 때와 마찬가지로 해당 객체를 반복하고 비교할 수 있습니다.

MonthOfYear 클래스
  포함 비교 가능
  ATTR_READER :년, :월
  def initialize(month, year)
    month.between?(1, 12) 아니면 ArgumentError를 발생시킵니다.
    year, @month = year, month
  end
  def (other)
    [year, month]  [other.year, other.month]
  end
end

Rails를 소개합니다.

Rails 세계에서는 각 클래스가 모델, 뷰 또는 컨트롤러라는 사실에 익숙합니다. 또한 디렉토리 구조에서 정확한 위치를 가지고 있으므로 우리의 작은 PORO 군대를 어디에 배치할 수 있을까요? 몇 가지 옵션을 고려해 보세요. 가장 먼저 떠오르는 생각은 생성된 클래스가 모델도 뷰도 컨트롤러도 아닌 경우 모두 "/lib" 디렉터리에 넣어야 한다는 것입니다. 이론적으로는 좋은 생각이지만, 모든 PORO 파일이 한 디렉터리에 있고 애플리케이션의 크기가 크다면 이 디렉터리는 금방 열기가 두려운 어두운 장소가 될 것입니다. 따라서 의심할 여지없이 좋은 생각이 아닙니다.

어썸프로젝트
├──앱
│ ├─컨트롤러
│ ├─모델
│ └─뷰
│
└─lib
  └─서비스
      1TP63톨 포로 여기

일부 클래스의 이름을 액티브 레코드 모델이 아닌 모델로 지정하여 "app/models" 디렉터리에 넣고, 다른 클래스의 처리를 담당하는 클래스의 이름을 서비스로 지정하여 "app/services" 디렉터리에 넣을 수도 있습니다. 이것은 꽤 좋은 해결책이지만 한 가지 단점이 있습니다. 새 PORO를 만들 때마다 모델인지 서비스인지 매번 결정해야 한다는 것입니다. 이렇게 하면 애플리케이션에 어두운 부분이 두 개가 있고 작은 부분만 있는 상황에 도달할 수 있습니다. 세 번째 접근 방식은 네임스페이스 클래스와 모듈을 사용하는 것입니다. 컨트롤러나 모델과 이름이 같은 디렉터리를 만들고 해당 컨트롤러나 모델에서 사용하는 모든 PORO 파일을 그 안에 넣기만 하면 됩니다.

어썸프로젝트
├──앱
│ ├─컨트롤러
│ │ ├─registration_controller
│ │ │ └─registration_service.rb
│ │ └─registration_controller.rb
│ ├─models
│ │ ├─settlement
│ │ │ └─month_of_year.rb
│ │ └─settlement.rb
│ └─views
│
└─lib

이 배열 덕분에 클래스 이름 앞에 네임스페이스를 붙일 필요가 없습니다. 코드가 더 짧아지고 논리적으로 정리된 디렉토리 구조를 갖게 됩니다.

저를 확인해 보세요!

PORO를 사용하면 애플리케이션의 단위 테스트를 더 빠르고 쉽게 작성할 수 있고 나중에 다른 사람이 이해할 가능성이 높아진다는 것은 놀라운 일입니다. 이제 각 클래스가 한 가지 일만 담당하므로 경계 조건을 더 빨리 인식하고 적절한 테스트 시나리오를 쉽게 추가할 수 있습니다.

설명 MonthOfYear do
  subject { MonthOfYear.new(11, 2015) }
  it { be_kind_of 비교 가능해야 함 }
  설명 "새 인스턴스 생성" do
    "올바른 연도와 월로 초기화" do
      expect { described_class.new(10, 2015) }.to_not raise_error
    end
    "주어진 월이 잘못되었을 때 오류를 발생시킵니다" do
      expect { described_class.new(0, 2015) }.to raise_error(ArgumentError)
      expect { described_class.new(13, 2015) }.to raise_error(ArgumentError)
    end
  end
end

다시 만날 수 있기를 바랍니다!

앞서 제시한 예시를 통해 PORO를 사용하면 애플리케이션의 가독성이 향상되고 모듈화되어 결과적으로 관리와 확장이 쉬워진다는 것을 분명히 알 수 있습니다. 단일 책임 원칙을 수용하면 필요한 경우 특정 클래스를 다른 요소에 간섭하지 않고도 쉽게 교환할 수 있습니다. 또한 테스트도 더 간단하고 빠르게 진행할 수 있습니다. 또한 이렇게 하면 Rails 모델과 컨트롤러를 짧게 유지하는 것이 훨씬 쉬워지며, 개발 과정에서 불필요하게 커지는 경향이 있다는 것을 우리 모두 알고 있습니다.

관련 문서

소프트웨어 개발

미래 지향적인 웹 앱 구축: The Codest의 전문가 팀이 제공하는 인사이트

The Codest가 최첨단 기술로 확장 가능한 대화형 웹 애플리케이션을 제작하고 모든 플랫폼에서 원활한 사용자 경험을 제공하는 데 탁월한 성능을 발휘하는 방법을 알아보세요. Adobe의 전문성이 어떻게 디지털 혁신과 비즈니스를 촉진하는지 알아보세요...

최신
소프트웨어 개발

라트비아에 본사를 둔 10대 소프트웨어 개발 기업

최신 기사에서 라트비아 최고의 소프트웨어 개발 기업과 그들의 혁신적인 솔루션에 대해 알아보세요. 이러한 기술 리더들이 어떻게 귀사의 비즈니스를 향상시키는 데 도움을 줄 수 있는지 알아보세요.

thecodest
엔터프라이즈 및 스케일업 솔루션

Java 소프트웨어 개발 필수 사항: 성공적인 아웃소싱을 위한 가이드

The Codest로 효율성을 높이고 전문 지식을 활용하며 프로젝트 성공을 이끌 수 있는 성공적인 outsourcing Java 소프트웨어 개발에 대한 이 필수 가이드를 살펴보세요.

thecodest
소프트웨어 개발

폴란드 아웃소싱을 위한 최고의 가이드

폴란드에서 outsourcing가 급증한 것은 경제, 교육, 기술 발전으로 인한 IT 성장과 비즈니스 친화적인 환경이 조성된 덕분입니다.

더코데스트
엔터프라이즈 및 스케일업 솔루션

IT 감사 도구 및 기술에 대한 완벽한 가이드

IT 감사는 안전하고 효율적이며 규정을 준수하는 시스템을 보장합니다. 전체 기사를 읽고 그 중요성에 대해 자세히 알아보세요.

The Codest
야쿱 야쿠보비치 CTO & 공동 설립자

지식창고를 구독하고 IT 분야의 전문 지식을 최신 상태로 유지하세요.

    회사 소개

    The Codest - 폴란드에 기술 허브를 둔 국제 소프트웨어 개발 회사입니다.

    영국 - 본사

    • 사무실 303B, 182-184 하이 스트리트 노스 E6 2JA
      영국 런던

    폴란드 - 현지 기술 허브

    • 파브리츠나 오피스 파크, 알레야
      포코주 18, 31-564 크라쿠프
    • 뇌 대사관, 콘스트럭터스카
      11, 02-673 바르샤바, 폴란드

      The Codest

    • 홈
    • 회사 소개
    • 서비스
    • Case Studies
    • 방법 알아보기
    • 채용 정보
    • 사전

      서비스

    • IT 자문
    • 소프트웨어 개발
    • 백엔드 개발
    • 프론트엔드 개발
    • Staff Augmentation
    • 백엔드 개발자
    • 클라우드 엔지니어
    • 데이터 엔지니어
    • 기타
    • QA 엔지니어

      리소스

    • 외부 소프트웨어 개발 파트너와의 협력에 대한 사실과 오해
    • 미국에서 유럽으로: 미국 스타트업이 유럽으로 이전을 결정하는 이유
    • 테크 오프쇼어 개발 허브 비교: 테크 오프쇼어 유럽(폴란드), 아세안(필리핀), 유라시아(터키)
    • CTO와 CIO의 주요 과제는 무엇인가요?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • 웹사이트 이용 약관

    저작권 © 2025 by The Codest. 모든 권리 보유.

    ko_KRKorean
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese es_ESSpanish nl_NLDutch etEstonian elGreek ko_KRKorean