Skip to content

Development: Glossary

Marian Kostyk edited this page Nov 8, 2022 · 49 revisions

❗❗❗DISCLAMER❗❗❗

This glossary makes sense only in the context of this library. Do not use it as an authoritative source for term definitions outside of convenient_service. Thanks.

Concern

TODO

Dynamic dependencies

Dynamic dependencies are dependencies that can be loaded on demand by the end-user when a plugin that depends on them is required.

The lib is completely functional without them.

Own method, own const

Own method or const means a method or const that is defined directly in the caller class. For example:

##
# @example Open an interactive Ruby console with already loaded `convenient_service`:
#   cd convenient_service
#   task playground
#
module A
  FOO = :foo

  module B
    BAR = :bar
  end
end

ConvenientService::Utils::Module.get_own_const(A::B, :FOO)
# nil, since FOO is defined in A, not in B

ConvenientService::Utils::Module.get_own_const(A::B, :BAR)
# :bar (value of A::B::BAR), since BAR is defined directly in B

Method step

TODO

Middleware

TODO

Plugin

A plugin is a combination of concerns and middlewares in order to extend/modify/restrict the functionality of services and/or their parts.

Actually, a plugin can be constructed only from a sole concern, or just from one middleware.

The only requirement - it must strictly follow the Separation of Concerns principle.

Here is some example plugins:

  • assigns_attributes_in_constructor.
  • caches_return_value.
  • has_result_steps.
  • raises_on_double_result.
  • wraps_result_in_db_transaction.

As their names state, each of them has a Single Responsibility that is easy to understand with minimal context.

Plugins are grouped by the broadness of their applicability.

  • Common - can be applied to any type of entity, e.g: Service, Result, Step, Internals, etc.
  • Service - plugins that make sense only in the service scope.
  • Result - same as previous, but for results.
  • Internals - effect of Service, Result, Step plugins may be visible to the end-users, while Internals plugins outcome is always hidden.

Plugins may depend on other plugins.

Static dependencies

Static dependencies are dependencies that are always loaded whenever require "convenient_service" is called.

The lib is NOT functional without them.

Sequence diagram

A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.

Sources:

Examples:

Service

TODO

Step

TODO

Support

Support class, module, or concern is a behavior that is very similar to util by its nature, it also does one logical thing and should be easily extractable between projects, but it can NOT be expressed as a pure function.

Check convenient_service/lib/convenient_service/support for examples.

Utils

An util is a pure function that does exactly one thing.

In a general case, it should be easy to extract and reuse utils in the different projects (so they should be context-independent as well).

For example, it is a relatively common task to look for the last item in an array that matches a condition, but Ruby's Array and Enumerable have no built-in methods for that.

Such a case is a great candidate for util:

module ConvenientService
  module Utils
    module Array
      class FindLast < Support::Command
        attr_reader :array, :block

        def initialize(array, &block)
          @array = array
          @block = block
        end

        def call
          array.reverse.find(&block)
        end
      end
    end
  end
end

module ConvenientService
  module Utils
    module Array
      class << self
        def find_last(...)
          FindLast.call(...)
        end
      end
    end
  end
end

array = [1, 2, 3, 4, 5]

array.find { |item| item % 2 == 0 }
# => 2

ConvenientService::Utils::Array.find_last(array) { |item| item % 2 == 0 }
# => 4