Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

일반적인 Ruby on Rails 문제 및 요약

Ruby on Rails Patterns and Anti-Patterns 시리즈의 마지막 부분에 오신 것을 환영합니다. 이 모든 주제를 작성하고 연구하는 것은 꽤 힘든 일이었습니다. 이 블로그 게시물에서는 몇 년 동안 Ruby on Rails 애플리케이션을 빌드하고 출시할 때 겪었던 가장 일반적인 문제를 살펴보겠습니다.

여기에서 살펴볼 아이디어는 코드의 거의 모든 곳에 적용됩니다. 따라서 그것들을 Model-View-Controller 패턴과 관련된 것이 아니라 일반적인 아이디어로 간주하십시오. Rails MVC와 관련된 패턴 및 안티 패턴에 관심이 있으시면 Model, View, Controller 블로그 게시물을 확인하세요.

이제 일반적인 문제와 요약으로 넘어가 보겠습니다.

이기적인 대상과 데메테르의 법칙

데메테르의 법칙(Law of Demeter)은 한 그룹의 사람들이 데메테르 프로젝트에서 작업할 때 그 이름을 얻은 휴리스틱입니다. 아이디어는 개체가 한 번에 하나의 메서드를 호출하고 여러 메서드 호출을 연결하지 않는 한 문제가 없다는 것입니다. 이것이 실제로 의미하는 바는 다음과 같습니다.

# Bad
song.label.address
 
# Good
song.label_address

이제 song 객체는 더 이상 주소의 출처를 알 필요가 없습니다. 주소는 label의 책임입니다. 물체. 하나의 메서드 호출만 연결하고 개체를 '이기적'으로 만들어 전체 정보를 직접 공유하지 않고 도우미 메서드를 통해 공유하는 것이 좋습니다.

다행히도 Rails에서는 도우미 메서드 자체를 작성할 필요가 없습니다. delegate를 사용할 수 있습니다. 도우미:

def Label < ApplicationModel
  belongs_to :song
 
  delegate :address, to: :song
end

대리인의 문서에서 대리인이 수락하는 옵션을 가지고 놀 수 있습니다. 그러나 아이디어와 실행은 매우 간단합니다. 데메테르의 법칙을 적용하여 구조적 결합을 줄입니다. 강력한 delegate과 함께 , 더 적은 수의 라인과 훌륭한 옵션이 포함되어 있습니다.

Demeter의 법칙과 매우 유사한 또 다른 아이디어는 단일 책임 원칙(또는 줄여서 SRP)입니다. 모듈, 클래스 또는 함수가 시스템의 단일 부분을 담당해야 함을 나타냅니다. 또는 다른 방식으로 제시:

<블록 인용>

같은 이유로 변하는 것들을 모아라. 다른 이유로 변경되는 항목을 분리합니다.

사람들은 종종 SRP에 대해 다른 이해를 가질 수 있지만 아이디어는 단일 요소에 대한 책임을 빌딩 블록으로 유지하는 것입니다. Rails 앱이 확장됨에 따라 SRP를 달성하는 것이 어려울 수 있지만 리팩토링할 때 이를 인지해야 합니다.

기능을 추가하고 LOC를 늘릴 때 사람들이 종종 빠른 솔루션을 찾는 것을 발견했습니다. 그럼 빠른 수정을 진행해 보겠습니다.

나는 한 남자를 알고 있습니다(그 루비 보석이 필요하십니까?)

Rails가 화두였을 때, 새로운 Ruby 보석이 구석구석에 등장하면서 오픈 소스 협업의 붐이 일어났습니다(요즘 모든 새로운 JavaScript 라이브러리가 있지만 훨씬 더 작은 규모임).

👆 모듈 수의 정보.

어쨌든 일반적인 접근 방식은 문제를 해결할 기존 보석을 찾는 것이었습니다.

아무 문제가 없지만 gem을 설치하기로 결정하기 전에 몇 가지 조언을 나누고 싶습니다.

먼저 다음 질문을 스스로에게 하십시오.

  • 보석의 기능 중 어느 부분을 사용할 예정입니까?
  • '단순'하거나 더 최신의 유사한 보석이 있습니까?
  • 필요한 기능을 쉽고 자신 있게 구현할 수 있습니까?

전체 gem 기능을 사용할 계획이 없다면 구현을 할 가치가 있는지 평가하십시오. 또는 gem의 구현이 너무 복잡하고 더 간단하게 할 수 있다고 생각되면 맞춤형 솔루션을 선택하세요.

내가 고려하는 또 다른 요소는 gem의 저장소가 얼마나 활성화되어 있는지입니다. 활성 유지 관리자가 있습니까? 마지막으로 출시된 것이 언제였습니까?

또한 gem의 종속성에 주의해야 합니다. 특정 버전의 종속성에 얽매이지 않으려면 항상 Gemfile.spec을 확인하세요. 파일. 보석 버전을 지정하는 RubyGems 방법을 참조하십시오.

우리가 gem에 대해 이야기하는 동안 내가 만난 관련 아이디어가 있습니다. 바로 Rails/Ruby 세계에 적용되는 'Not Invented Here'(또는 NIH) 현상입니다. 다음 섹션에서 어떤 내용인지 살펴보겠습니다.

여기서 발명되지 않았습니다(결국 그 루비 보석이 필요할까요?)

내 경력에서 두 번 발생했을 때 나는 사람들(저를 포함하여)이 '여기에 발명되지 않음' 증후군에 빠지는 것을 경험할 기회가 있었습니다. 아이디어는 '바퀴의 재발명'과 비슷합니다. 때때로 팀과 조직은 제어할 수 없는 라이브러리(보석)를 신뢰하지 않습니다. 신뢰 부족은 이미 존재하는 보석을 재발명하는 계기가 될 수 있습니다.

때로는 NIH를 경험하는 것이 좋은 일이 될 수 있습니다. 사내 솔루션을 만드는 것은 특히 다른 솔루션보다 개선할 경우 훌륭할 수 있습니다. 솔루션을 오픈소스화하기로 결정했다면 훨씬 더 나을 수 있습니다(Ruby on Rails 또는 React 살펴보기). 그러나 그것을 위해 바퀴를 재발명하고 싶다면 그렇게 하지 마십시오. 휠 자체는 이미 꽤 훌륭합니다.

이 주제는 매우 까다롭습니다. 그런 상황에 처한 경우 다음 질문을 스스로에게 해보십시오.

  • 기존 솔루션보다 더 나은 솔루션을 만들 수 있다고 확신합니까?
  • 기존 오픈 소스 솔루션이 우리가 필요로 하는 것과 다른 경우 오픈 소스에 기여하고 개선할 수 있나요?
  • 게다가 우리가 오픈 소스 솔루션의 유지자가 되어 많은 개발자의 삶을 개선할 수 있을까요?

그러나 때로는 자신만의 방식으로 라이브러리를 직접 만들어야 합니다. 조직에서 오픈 소스 라이브러리 라이선스를 원하지 않을 수 있으므로 직접 라이브러리를 구축해야 합니다. 하지만 무엇을 하든지 바퀴를 재발명하는 것은 피하라고 말하고 싶습니다.

인명 구조원(초과 구조 예외)

사람들은 원래 의도했던 것보다 더 많은 예외를 구하는 경향이 있습니다.

이 주제는 이전 주제보다 코드와 조금 더 관련이 있습니다. 누군가에게는 상식일 수도 있지만 때때로 코드에서 볼 수 있습니다. 예:

begin
  song.upload_lyrics
rescue
  puts 'Lyrics upload failed'
end

구하려는 예외를 지정하지 않으면 계획하지 않은 일부 예외가 포착됩니다.

이 경우 문제는 song 개체가 nil입니다. . 해당 예외가 오류 추적기에 보고되면 업로드 프로세스에 문제가 있다고 생각할 수 있지만 실제로는 완전히 다른 문제를 겪고 있을 수 있습니다.

따라서 안전을 위해 예외를 구할 때 발생할 수 있는 모든 예외 목록을 확인하십시오. 어떤 이유로 모든 예외를 얻을 수 없다면 과잉 구조보다 덜 구조하는 것이 좋습니다. 당신이 알고 있는 예외를 구하고 나중에 다른 단계를 처리하십시오.

너무 많이 요구함(너무 많은 SQL 쿼리)

이 섹션에서는 또 다른 웹 개발인 관계 데이터베이스 문제를 살펴보겠습니다.

한 번의 요청으로 너무 많은 SQL 쿼리로 웹 서버를 폭파합니다. 그 문제는 어떻게 발생합니까? 하나의 요청으로 여러 테이블에서 여러 레코드를 가져오려고 하면 이런 일이 발생할 수 있습니다. 그러나 가장 자주 발생하는 것은 악명 높은 N+1 쿼리 문제입니다.

다음 모델을 상상해 보십시오.

class Song < ApplicationRecord
  belongs_to :artist
end
 
class Artist < ApplicationRecord
  has_many :songs
end

한 장르의 노래 몇 곡과 해당 아티스트를 표시하려는 경우:

songs = Song.where(genre: genre).limit(10)
 
songs.each do |song|
  puts "#{song.title} by #{song.artist.name}"
end

이 코드 조각은 10개의 노래를 얻기 위해 하나의 SQL 쿼리를 트리거합니다. 그 후, 각 노래의 아티스트를 가져오기 위해 하나의 추가 SQL 쿼리가 수행됩니다. 총 11개의 쿼리입니다.

더 많은 노래를 로드하는 시나리오를 상상해 보세요. 모든 아티스트를 가져오려고 데이터베이스에 더 많은 로드를 가할 것입니다.

또는 includes를 사용합니다. 레일스에서:

songs = Song.includes(:artists).where(genre: genre).limit(10)
 
songs.each do |song|
  puts "#{song.title} by #{song.artist.name}"
end

includes 후 , 표시하기로 결정한 노래의 수에 관계없이 이제 두 개의 SQL 쿼리만 받습니다. 얼마나 깔끔한지.

너무 많은 SQL 쿼리를 진단할 수 있는 한 가지 방법은 개발 중입니다. 동일한 테이블에서 데이터를 가져오는 유사한 SQL 쿼리 그룹이 보이면 이상한 일이 벌어지고 있는 것입니다. 그렇기 때문에 개발 환경에 대해 SQL 로깅을 켜도록 강력히 권장합니다. 또한 Rails는 코드에서 쿼리가 호출된 위치를 보여주는 자세한 쿼리 로그를 지원합니다.

로그를 보는 것이 자신의 일이 아니거나 더 심각한 것을 원한다면 AppSignal의 성능 측정 및 N+1 쿼리 감지를 사용해 보십시오. 여기에서 문제가 N+1 쿼리에서 비롯되었는지 여부에 대한 훌륭한 지표를 얻을 수 있습니다. 아래와 같이 표시됩니다.

요약

이 블로그 게시물 시리즈를 읽어주셔서 감사합니다. 일반적인 문제에 대한 이 마지막 블로그 게시물 이전에 Rails의 패턴과 안티 패턴을 소개하는 것부터 Rails MVC 패턴 내부에 있는 내용을 탐구하는 것에 이르기까지 흥미로운 이 작업에 참여해 주셔서 기쁩니다.

나는 당신이 많은 것을 배웠거나 적어도 당신이 이미 알고 있는 것을 수정하고 확립하기를 바랍니다. 다 외우느라 스트레스 받지 마세요. 어떤 분야에서든 문제가 발생하면 언제든지 시리즈를 상담할 수 있습니다.

이 세계(특히 소프트웨어 엔지니어링)가 이상적이지 않기 때문에 패턴과 안티 패턴을 모두 접하게 될 것입니다. 그것도 걱정하지 않으셔도 됩니다.

패턴과 안티패턴을 마스터하면 훌륭한 소프트웨어 엔지니어가 됩니다. 하지만 완벽한 솔루션은 없기 때문에 이러한 패턴과 틀을 깨야 할 때를 아는 것이 당신을 훨씬 더 낫게 만듭니다.

가입하고 읽어주셔서 다시 한 번 감사드립니다. 다음 편에서 뵙겠습니다. 건배!

추신 Ruby Magic 게시물이 언론에 공개되는 즉시 읽고 싶다면 Ruby Magic 뉴스레터를 구독하고 게시물을 놓치지 마세요!