行動すれば次の現実

テック中心の個人ブログ

RubyとJavascriptにおける連想配列の順序保証の違い

RubyとJavascriptでは連想配列(Rubyの場合はHash、Javascriptの場合はオブジェクトリテラル)の順序保証が異なります。

最近はバックエンドでRuby、フロントエンドはJavascriptの構成にして開発するケースが増えています。

RubyでAPIの結果を連想配列で返し、Javascript側で連想配列をeachして順番に処理を行う場合は、そのギャップに注意が必要です。

Rubyの場合はHashの順序が保証される

Ruby(v1.9以降)の場合、Hashの順序が保証されます。

hash = { '1':'one', '2':'two', '4':'four', '3':'three' }
p hash
=>  {:"1"=>"one", :"2"=>"two", :"4"=>"four", :"3"=>"three"}

hash.each do |k, v|
  p v
end

=> "one"
=> "two"
=> "four"
=> "three"

Javascriptの場合はオブジェクトリテラルの順序が保証されない

Javascriptの場合、オブジェクトリテラルの順序が保証されません。

const hash = { 1:'one', 2:'two', 4:'four', 3:'three' }
console.log(hash)
=> {1: 'one', 2: 'two', 3: 'three', 4: 'four'}

Object.values(hash).forEach((value) => {
  console.log(value)
});
=> "one"
=> "two"
=> "three"
=> "four"

そのため、Javascriptで順序を保ちたい場合は、順序を管理するための配列を別途用意する必要があります。

const hash = {
  entities:  { 1:'one', 2:'two', 4:'four', 3:'three’ },
  orders: [1 ,2 ,4 ,3]
}

hash.orders.forEach((k) => {
  const value = hash.entities[k];
  console.log(value)
});
=> "one"
=> "two"
=> "four"
=> "three"

静的クラスっぽくRubyのモジュールを使いたい

Rubyのモジュール(module)といえばミックスインというイメージが強い。

ミックスインは便利だが、わざわざミックスインで組み込まずに、ユーティリティクラスのようにそのままメソッドを呼び出したいケースがある。 (Javaでいう静的クラスを定義して静的メソッドを呼び出すイメージ)

モジュールでもそのようなことが実現できる

module HashModule
  extend ActiveSupport::Concern

  def self.to_hash(list)
    hash = { entities: {}, orders: [] }
    orders = []
    list.each do |data|
      orders << data.id
      hash[:entities][data.id] = data
    end
    hash[:orders] = orders
    hash.to_h
  end
end

products = Product.all
HashModule.to_hash(products)

まとめて定義したいときは class << self を使うほうがタイプ数が減っておすすめ。

module HashModule
  extend ActiveSupport::Concern

  class << self
    def to_hash(list)
      hash = { entities: {}, orders: [] }
      orders = []
      list.each do |data|
        orders << data.id
        hash[:entities][data.id] = data
      end
      hash[:orders] = orders
      hash.to_h
    end
  end
end

products = Product.all
HashModule.to_hash(products)

Github Projectsを利用したタスク管理と運用ルール

アプリ開発する上で、様々なプロジェクトのタスク管理ツールを使ってきましたが、最終的にGithub projectsに落ち着きました。

弊社プロジェクトで実際に運用しているルールは以下の通りです。 小規模なプロジェクトであれば、問題なく回るのではないかと考えています。

  • リポジトリごとにProjectを一つ作成する
  • Columnは以下の通りとする
    • Inbox: いつかやるけど今じゃない
    • ToDo: やる必要があるもの
    • in Progress: 今やってるもの
    • Check: 作業が終わってるけど本番確認がまだ
    • Done: リリースしたもの(closeしたら自動的にDoneに移動する)
    • Pending: 何らかの理由で作業が止まっているもの
  • 開発手法はGithub Flowを用いる
  • ブランチ名は「issue番号-概要」
    • 1234-fix-conditions
  • PRのdescriptionに issueのリンクを貼る
    • issueとPRが関連付けされる
  • issue:PRは1:N
    • 一つのissueにつき、複数のPRを作成しても良い
    • 全てのPRがマージされたらissueをCheckに移動させる
  • 大規模な機能開発の場合は中間ブランチを作成する
    • Epicのような運用
    • 例) master -> calc_orders/master -> cals_orders/1234-fix-conditions