Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This gem requires a significant refactor #5

Open
ocvit opened this issue Apr 29, 2024 · 0 comments
Open

This gem requires a significant refactor #5

ocvit opened this issue Apr 29, 2024 · 0 comments

Comments

@ocvit
Copy link

ocvit commented Apr 29, 2024

Hi,

Few minutes into a code and this is what strikes me:

  1. File structure.
    • serpapi/serpapi.rb that hosts just a Client class - should be serpapi/client.rb
    • SerpApi::Client::VERSION that is used as a gem version - should be in a separate file serpapi/version.rb using SerpApi::VERSION namespace
    • serpapi/error.rb does not include corresponding Error module, just SerpApiException class - should be enclosed in unified Errors module, e.g.:
      # serpapi/errors.rb
      module SerpApi
        module Errors
          # all your custom errors
        end
      end
    • specs should represent actual file structure, e.g.:
      spec/serpapi/client_spec.rb    // client config specs
      spec/serpapi/client/*_spec.rb  // all the integration tests that are currently just laying around
      spec/serpapi_spec.rb           // should include VERSION check only
      
  2. Don't use open-uri. It creates temporary file for each response, i.e. redundant IO operation that just degrades performance. BTW, why do you have different HTTP clients in different gems? Some uses faraday, some open-uri, some http etc.
  3. This:
    attr_accessor :timeout
    # Default parameters provided in the constructor (hash)
    attr_accessor :params

    def initialize(params = {})
    # set default read timeout
    @timeout = params[:timeout] || params['timeout'] || 120
    @timeout.freeze
    # delete this client only configuration keys
    params.delete('timeout') if params.key? 'timeout'
    params.delete(:timeout) if params.key? :timeout
    # set default params safely in memory
    @params = params.clone || {}
    @params.freeze
    end

    def engine
    @params['engine'] || @params[:engine]
    end

    def api_key
    @params['api_key'] || @params[:api_key]
    end

    Can be simplified to:
    class SerpApi # should be Client
      DEFAULT_TIMEOUT = 120
    
      attr_accessor :timeout
      attr_reader :params, :engine, :api_key
    
      def initialize(params = {})
        @params = params.transform_keys(&:to_sym)
    
        @timeout = @params[:timeout] || DEFAULT_TIMEOUT
        @engine  = @params[:engine]
        @api_key = @params[:api_key]
      end
    end
  4. So which one?
    # HTTP timeout in seconds (default: 120)

    # timeout [Integer] HTTP read max timeout in seconds (default: 60s)
  5. No need in nil as third param, it's optional:
    get("/searches/#{search_id}.#{format}", format, nil)
  6. This:
    query = (@params || {}).merge(params || {})

    Can be simplified to:
    query = @params.merge(params)
    # @params can't be nil because of default value {} in #initialize
    # params can't be nil because of default value {} in #get
  7. This:
    query.delete_if { |_, value| value.nil? }

    Can be simplified to:
    query.compact!
  8. SerpApiException should not be raised for HTTP transport errors, it's misleading just from the naming convention. There should be a separate error class or just a transparent bypass.
    rescue OpenURI::HTTPError => e
    data = JSON.parse(e.io.read)
    raise SerpApiException, "error: #{data['error']} from url: #{url}" if data.key?('error')
    raise SerpApiException, "fail: get url: #{url} response: #{data}"
    rescue => e
    raise SerpApiException, "fail: get url: #{url} caused by: #{e}"
    end
  9. No full branch coverage in simplecov, you just ignore bunch of untested places:
    # do this
    SimpleCov.start do
      enable_coverage :branch
    
      add_filter "/spec/"
    end
  10. describe/it blocks are just bad. describe should refer to namespaced objects, currently they do context role.
  11. No VCRs and dependence on specific API_KEY with high request limit makes testing impossible for other contributors rather than those who work in company.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant