Why algorithms (in particular, I/O algorithms) are important

Suppose we have a two-dimensional array, which is a map with given heights at different points. Let's calculate the average elevation. To do this, you can go through either each row:
sum = 0
for i = 0 to m - 1 do
  for j = 0 to m - 1 do
    sum = sum + A[i, j]
avg = sum / m^2
or each column:
sum = 0
for j = 0 to m - 1 do
  for i = 0 to m - 1 do
    sum = sum + A[i, j]
avg = sum / m^2
Then summarize all heights and divide by the number of points on the map. Do you think there is any difference between these methods? It would seem not, but in fact, there is. The first method (traversing all rows) turns out to be more productive than the second method (traversing the columns). The whole thing is related to the organization of the array in memory and access to each cell. I tried to compare on Java. That's what I did.

// Computing the average elevation
class Avg {
  public static void main(String[] argv) {
    int n = 1000; // 1000 * 1000 = 10^6
    int[][] matrix = new int[n][n];

    fillMatrix(matrix, n, 1);

    long start = System.nanoTime();
    int avg = avgRowByRow(matrix);
    System.out.println(String.format(
      "avg (Row By Row) = %s,
      it takes %s nano-seconds",
      avg,
      System.nanoTime() - start
    ));

    start = System.nanoTime();
    avg = avgColumnByColumn(matrix);
    System.out.println(String.format(
      "avg (Column By Column) = %s
      it takes %s nano-seconds",
      avg,
      System.nanoTime() - start
    ));
  }

  private static void fillMatrix(int[][] matrix, int n, int default_value) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        matrix[i][j] = default_value;
      }
    }
  }

  private static int avgRowByRow(int[][] matrix) {
    int sum = 0, m = matrix.length;

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < m; j++) {
        sum = sum + matrix[i][j];
      }
    }

    return sum / m / m; // sum / (m * m)
  }

  private static int avgColumnByColumn(int[][] matrix) {
    int sum = 0, m = matrix.length;

    for (int j = 0; j < m; j++) {
      for (int i = 0; i < m; i++) {
        sum = sum + matrix[i][j];
      }
    }

    return sum / m / m; // sum / (m * m)
  }
}
Then I tried to run it a couple of times and got the following result. The result can be said to be obvious:
avg (Row By Row)       = 1, it takes 3822568 nano-seconds
avg (Column By Column) = 1, it takes 5646746 nano-seconds

avg (Row By Row)       = 1, it takes 3902352 nano-seconds
avg (Column By Column) = 1, it takes 5467638 nano-seconds

avg (Row By Row)       = 1, it takes 3939734 nano-seconds
avg (Column By Column) = 1, it takes 5077092 nano-seconds

avg (Row By Row)       = 1, it takes 3736544 nano-seconds
avg (Column By Column) = 1, it takes 4950847 nano-seconds

avg (Row By Row)       = 1, it takes 3900019 nano-seconds
avg (Column By Column) = 1, it takes 5009578 nano-seconds

avg (Row By Row)       = 1, it takes 3954720 nano-seconds
avg (Column By Column) = 1, it takes 5109380 nano-seconds

avg (Row By Row)       = 1, it takes 3824056 nano-seconds
avg (Column By Column) = 1, it takes 5276105 nano-seconds

API Documentation. Multiple examples in Swagger

When describing the API documentation, sometimes there is a need to add several examples of responses. This is necessary for the possibility of a more complete description of the API documentation, since this API documentation is a kind of contract between the backend and the frontend. If you still use Swagger v.2.0 then you face the limitation - adding multiple examples is not supported. To get around this limitation, you need to go to the OpenAPI v. 3.0.0 specification. Then you will be able to add examples as follows.

- One example:

responses:
  "200":
    description: user creation successful
    content:
      application/json:
        example:
          token: fEt4IouUyRrqlx80treEWwq8
- A few examples:

responses:
  "422":
    description: user creation failed
    content:
      application/json:
        schema:
          properties:
            response:
              $ref: "#/components/schemas/ErrorResponse"
        examples:
          "Missing parameters":
            value:
              error: 'error-1'
              message: 'error-message-1'
          "Validation failed":
            value:
              error: 'error-2'
              message: 'error-message-2'


The differences between Swagger v.2.0 and the OpenAPI v. 3.0.0 specification are generally not so big:

    Swagger v.2.0     |  OpenAPI v.3.0.0
----------------------|-------------------
    info              |    info
----------------------|-------------------
   host               |
   basePath           |    servers
   schemes            |
----------------------|-------------------
   security           |    security
----------------------|-------------------
   paths              |   paths
----------------------|-------------------
   externalDocs       |   externalDocs
----------------------|-------------------
   tags               |   tags
----------------------|-------------------
                      |
  securityDefinitions |
                      |  components:
----------------------|    parameters
   produces           |    responses
----------------------|    examples
   consumes           |    requestBodies
----------------------|    headers
   definitions        |    links
   parameters         |    callbacks
   responses          |    securitySchemes
                      |

So the transition itself should not be difficult.

Rspec. When hashes are used inside arrays

I'm always amazed at the flexibility of unit testing when working with Ruby projects. Below are examples of such flexibility in which you can check the contents of hashes nested in an array.

context 'when hashes in array' do
  let(:hash_set) do
    [
      { attr1: 1, attr2: 2 },
      { attr1: 3, attr2: 4 }
    ]
  end

  let(:attribute_keys) { %i[attr1 attr2] }

  it 'contains a set of attribute keys' do
    expect(hash_set).to all(include(*attribute_keys))
  end
end

context 'when hashes in nested array' do
  let(:hash_set) do
    [
      { attr1: 1, attr2: [{ attr3: 3, attr4: 4 }] },
      { attr1: 5, attr2: [{ attr3: 6, attr4: 7 }] }
    ]
  end

  let(:first_attribute_keys) { %i[attr1 attr2] }
  let(:second_attribute_keys) { %i[attr3 attr4] }

  it 'contains a set of first attribute keys' do
    expect(hash_set).to all(include(*first_attribute_keys))
  end

  it 'contains a set of second attribute keys' do
    expect(hash_set).to all(
      include(attr2: all(include(*second_attribute_keys)))
    )
  end
end

# Some class for testing
class Tester
  def exec(options)
    # some work
  end
end

context 'when hashes are passed as parameters' do
  subject(:tester) { Tester.new }

  let(:options) do
    {
      attr1: 1,
      attr2: { attr4: 2 },
      attr3: [
        { attr5: 3 },
        { attr6: 4 }
      ]
    }
  end

  it 'contains a set of attribute keys with values' do
    expect(tester).to receive(:exec).with(
      hash_including(
        attr1: 1,
        attr2: hash_including(attr4: 2),
        attr3: [hash_including(attr5: 3), hash_including(attr6: 4)]
      )
    )

    tester.exec(options)
  end

  it 'contains a set of attribute keys' do
    expect(tester).to receive(:exec).with(
      hash_including(
        :attr1,
        attr2: hash_including(:attr4),
        attr3: array_including(hash_including(:attr5), hash_including(:attr6))
      )
    )

    tester.exec(options)
  end
end

Ruby. Messages from RuboCop about using predefined variables

Ruby has a lot of predefined variables. The one of them is $/. It is used as a universal substitution of newline symbol:

> numbers = ['one', 'two', 'three']
=> ["one", "two", "three"]

> numbers.join($/)
=> "one\ntwo\nthree"

> puts numbers.join($/)
one
two
three
=> nil
RuboCop is a Ruby code style checker (linter) and formatter based on the community-driven Ruby Style Guide. If you use it in your project, then it is possible that you will face with the next problem when using $/:
Prefer `$INPUT_RECORD_SEPARATOR` or `$RS` from the stdlib 'English' module
(don't forget to require it) over `$/`.(convention:Style/SpecialGlobalVars)
To fix it you can do like this:

# readable global var aliases
require 'English'

...
def log_error(error)
  backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
  backtrace_cleaner.add_filter { |line| line.gsub(Rails.root.to_s, '') }
  backtrace_cleaner.add_silencer { |line| line =~ /puma|rubygems/ }

  Rails.logger.error(
    [
      "#{error.class}: #{error.message}",
      *backtrace_cleaner.clean(error.backtrace)
    ].join($RS)
  )
end
...

As you can see I have used the $RS. Instead, you can use $INPUT_RECORD_SEPARATOR.

Mathematical equivalence of bit shifts

a << b <=> a * (2 ^ b)
a >> b <=> a / (2 ^ b)