Skip to content

Contribution: Style Guide

Marian Kostyk edited this page Jan 21, 2023 · 11 revisions

Do NOT pollute interfaces of user-facing classes by extra methods

For example, it is sound pretty reasonable to extract @__config__ ||= Entities::Config.new(klass: self) into def config method.

Prefer to do so almost all the time.

But when a class/module is user-visible, create additional methods only when you expect the end user to utilize them.

module ConvenientService
  module Core
    module ClassMethods
      def concerns(...)
        (@__config__ ||= Entities::Config.new(klass: self)).concerns(...)
      end

      def middlewares(...)
        (@__config__ ||= Entities::Config.new(klass: self)).middlewares(...)
      end
      
      # ...
    end
  end
end

See Wrap user-visible internal instance variables.

Document method signatures

Use YARD tags. For example:

##
# @param method_name [Symbol, String]
# @param include_private [Boolean]
# @return [Boolean]
#
def respond_to_missing?(method_name, include_private = false)
  return true if singleton_class.method_defined?(method_name)

  # ... 
end
##
# @param args [Array]
# @param kwargs [Hash]
# @param block [Proc]
# @return [Object] Can be any type.
#
def next(*args, **kwargs, &block)
  @stack.call(@env.merge(args: args, kwargs: kwargs, block: block))
end
##
# @return [Array]
# @raise [ConvenientService::Utils::Array::Errors::NonIntegerIndex]
#
def call
  ensure_valid_overrides!

  # ...
end

Wrap user-visible internal instance variables, methods, and arguments with double underscores

That is needed to avoid possible naming overlaps.

For example, @config was renamed to @__config__ since it is end-user-facing.

Add logs to the most vital (but not trivial to reverse engineer) parts of the library

Config commitment is a good example:

ConvenientService.logger.debug { "[Core] Committed config for `#{self.class}` | Triggered by `method_missing` | Method: `##{method}`" }
ConvenientService.logger.debug { "[Core] Committed config for `#{self}` | Triggered by `method_missing` | Method: `.#{method}`" }
ConvenientService.logger.debug { "[Core] Committed config for `#{self}` | Triggered by `.commit_config!`"