Ruby 코드의 가독성을 높이기 위해 (인터페이스 편)

가독성


https://ja.wikipedia.org/wiki/가독성
사람들은 프로그램의 원본 코드를 읽을 때 그 목적과 처리 절차를 이해하기 쉽다

당연하게 해야 할 일.


Formitter/Litter 사용

  • 루비면 루비
  • 자바스크립트/타입 스크립트의 경우 ESLit & Proettier
  • 등은 고정된 Formoter/Linter입니다.
    기본적으로 사용하지 않을 이유가 없으니 사용하세요.

    다른 사람이 생각해줬으면 하는 거.


    명확한 인터페이스


    예를 들어 다음과 같은 "WebAPI에서 인증 토큰을 받기"클래스를 고려할 것입니다.
    class AuthTokenRepository
      def create(params)
        Faraday.new.post('/api/v1/auth_token', params.to_json)
      end
    end
    

    매개변수의 정의를 자세히 설명해 주세요.


    "Params에서 지정한 내용은 이 URL의 API Reference를 보십시오."댓글을 남겨주시면 좋을 것 같아요.
    위의 메소드 정의에서는 "어떤 매개변수를 통과시킬지"를 전혀 알 수 없습니다.
    리뷰가 있더라도 API 정의를 확인하는 데 시간이 걸립니다.
    나는'학급/방법 정의만 읽으면 사용할 수 있다'는 것이 이상적인 상태라고 생각한다.
    중복된 경우에도 매개변수를 세부적으로 정의합니다.
    class AuthTokenRepository
      def create(user_id:, password:)
        Faraday.new.post('/api/v1/auth_token', { user_id: user_id, password: password }.to_json)
      end
    end
    

    params가 끼면 어떡해요.


        Faraday.new.post('/api/v1/auth_token', { user: { id: user_id, password: password } }.to_json)
    
    →매개 변수로 표현할 필요가 없고 코드를 통해 필요한 요소를 읽어서 표현하면 된다.
  • 스케치
    class AuthTokenRepository
      def create(user_id:, user_password:)
        Faraday.new.post('/api/v1/auth_token', { user: { id: user_id, password: user_password } }.to_json)
      end
    end
    
  • 검증으로 표시
    class AuthTokenRepository
      class ValidationError < ::StandardError; end
    
      def create(params)
        raise ValidationError unless valid_params_for_create?(params)
    
        Faraday.new.post('/api/v1/auth_token', params.to_json)
      end
    
      private
    
      def valid_params_for_create?(params)
        !(params.dig(:user, :id).nil? || params.dig(:user, :password).nil?)
      end
    end
    
  • 메모지
    루비 3.0 이후라면 제작.rbs 파일 정의 유형도 괜찮다.
    내가 일하는 PJ가 좀 모자란 것 같아.

    정상계의 반환값을 포장하다


    그리고 문제.
  • 반환값은 Faraday::Response의 실례이다
  • Faraday gem의 API를 모르면 사용할 수 없음
  • API 응답 구조를 모를 경우 대상 데이터를 가져올 수 없음
  • 네가 개인적으로 개발한 서비스라면 마음대로 해도 된다
    팀 개발 서비스에 있어 새로 참여한 구성원들이 코드를 이해하는 데 장애가 된다.
    봉인을 통해 상기 지식AuthTokenRepository을class에 숨깁니다.
    https://ja.wikipedia.org/wiki/봉인
    class AuthToken
      def initialize(token:, expired_at:)
        ...
      end
    end
    
    class AuthTokenRepository
      def create(user_id:, password:)
        response = Faraday.new.post('/api/v1/auth_token', { user_id: user_id, password: password }.to_json)
        AuthToken.new(token: response.body['token'], expired_at: response.body['expired_at'])
      end
    end
    

    정상적인 시스템 / 비정상적인 시스템의 오류를 압축합니다.


    까먹었어.
  • 가raise의 오류는 Faraday::Error의 하위 클래스
  • 입니다.
    이것에 대해서도 캡슐화하세요.
    class AuthTokenRepository
      class Error < ::StandardError; end
      class FailedToCreateError < Error; end
      class UnexpectedError < Error; end
    
      def create(user_id:, password:)
        response = Faraday.new.post('/api/v1/auth_token', { user_id: user_id, password: password }.to_json)
        AuthToken.new(response.body)
      rescue Faraday::ClientError => e
        raise FailedToCreateError, e.message
      rescue => e
        raise UnexpectedError, e.message
      end
    end
    

    부가: 캡슐화된 기쁜 부작용


    포장을 통해 읽을 수 있을 뿐만 아니라
  • WebAPI의 인터페이스 변경
  • 외부 서비스가 아닌 DB로부터 사용자 정보를 받아 인증
  • 등의 변경은 "수정의 영향 범위를 AuthTokenRepository로 제한할 수 있음",
    변경에 대한 내성이 높아진 것이다.
    # WebAPI のレスポンスフォーマットが変わった
    class AuthTokenRepository
      def create(user_id:, password:)
        response = Faraday.new.post('/api/v1/auth_token', { user_id: user_id, password: password }.to_json)
        AuthToken.new(
          token: response.body['authToken']['token'],
          expired_at: response.body['authToken']['expired_at']
        )
      rescue => e
        # 省略
      end
    end
    
    # DB を使いたい
    class AuthTokenRepository
      def create(user_id:, password:)
        hashed_password = hash(password)
        user = User.find_by!(user_id: user_id, password: hashed_password)
        token, expired_at = create_token_for_user(user)
    
        AuthToken.new(token: token, expired_at: expired_at)
      rescue ActiveRecode::RecordNotFound => e
        raise FailedToCreateError, e.message
      rescue => e
        raise UnexpectedError, e.message
      end
    end
    

    좋은 웹페이지 즐겨찾기