コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Railsのloggerで出力されるかを検証するときは、モックを使って確認するのがよい

小ネタ備忘録です。

環境

rails (5.2.0)

下記のクラスをテストしたい場合

class Example
  def logging
    Rails.logger.info("hoge")
  end
end

下記のように書く

# 実行前にloggerのinfoに設定される引数を見るようにする
expect(Rails.logger).to receive(:info).with("hoge")
# テスト対象を実行
Example.new.logging

参考リンク

『アーキテクチャ ディスカッション Vol.1』に行ってきたよメモ

アーキテクチャ ディスカッション Vol.1に傍聴席サイドで行ってきましたのでそのメモ。

トークの話題別まとめ

ディスカッション形式だったので、話題ごとにまとめてみました。 今回のねらいとしてはクリーンアーキテクチャの導入事例、成功した話、表に出にくい失敗した話などを語りたい、という回でした。

データのモデリングってどうしてる?

話のテーマとしてRDBのテーブル設計とデータのモデリングというのをどうしているかという話があった

アプローチに関しては…

などがあがりました。

また、データを分析するときの考え方として…

  • ドメインモデリングという言葉を使って、DBのモデリングとは異なるということを意識させる
  • 付箋での単語の割り出しや業務の重要なポイントを割り出して分析を行っていく

などのやり方の話もあがりました。

また、これらのベースの力をつけるために図書館アプリを作るという例をあげて「図書館といえば貸し借り」「だが会社としての着目点は『本の資産管理』である」「なのでドメインは『在庫管理』や『資産管理』が着目点になる」という考え方の練習法などが紹介された

クリーンアーキテクチャを採用した例と体験談

nrs(@nrslib)さんによる体験談とそれに対する質問。

クリーンアーキテクチャの右下の図 がデータの流れを表しておりだいたいこの形式に落ち着いた。MVCフレームワークと共存させる場合は非同期処理が不要という観点からPresenterが不要になる。

「Presnterは日付オブジェクトから日付文字列への変換などをする形でテストしやすいものとしにくいものを分けるために必要では?」という話になったらDTO(Data Transfer Object)を用意していたので、今回の事例の場合はその点は不要だった。

関連リンク

クリーンアーキテクチャの教育

手順化すると何も考えずにやってしまう人が多くなってしまうがその点どうしているかという話から布教の話題に。いろいろな体験談があがり…

  • アーキテクチャの冗長性を担保をプログラマーの自主性に任せるのは難しいので、考え方を伝える会を数回に分けて設けて生成ツールを提供したという話
  • 作業としては単純にファイルが増える作業ではあり、伝えてから良い感触が得られるまでのスパンが長いので、民主主義な流れになるとうまくいかないことが多いという体験談
  • 進化的アーキテクチャの文脈で、check style という静的解析ツールを一枚噛ませることで、依存関係的にご法度なものを防いだり、コードレビューでその点を充填的に見るなどの実践的なアプローチ

などなどが上がりました。

関連リンク

Ripository

何をデータとして渡すか

Entityを渡す、という設計で組む話が多く、Entityを渡してRipository内で差分をチェックしてRDBに書き込むという作業をしていたがつらい、などの話が出た。Entity Frameworkにおまかせすることで簡易化するという話もあがった。

更新と参照をどう表現するか

ケースバイケースだったが、以下のような話があがった。

  • 単純にテーブルのデータを取得したい場合はクエリを発行してそのまま渡すという考え方もある
  • 参照するものが異なるケース(ElasticSearchとRDBなど)があるので、レイヤーとして同一のものを挟んで運用する
  • ドメインに入れたくないデータは別途違う橋渡し方法を考える

参考リンク

開発での向き合い方、取り組み方

コミュニケーションと言葉

クリーンアーキテクチャなどを実践していくと、どうしてもドメイン分析が入ってきてコミュニケーションをとっていくことが必要になってくる。

その中でユビキタス言語を整理していくと、どうしても英語だと表現しにくいものが出てくる、そこで無理に英語を使わず、部分的に日本語表現するのも1つの方法論としてはありという意見がでた。

学び方

どうやって学ぶべきか、という観点になり…

  • 新人さんには社内用にDDD教育プログラムがある、1ヶ月やってもらうことで、理解しているかは別としてコピペできるレベルには至ることで学ぶトリガーをつくっている
  • RSSリーダーのような鉄板のテーマで実装して、いろいろなアーキテクチャで作ることにより差分などを感じ取りやすくなる

チームとしての進め方

  • 肌感のようなものは埋まるものではないので、ある程度大きな枠組みは整理して提供して、チームメンバーと一緒にやることで相互理解や、チームに合わない部分は軌道修正する
  • 古い手法と新しい手法が混在するコードに関しては、コードレビューや一緒にリファクタすることで軌道修正をかける

あなたが設計に興味を持ったのは、どこから?

設計というジャンルに興味を持ったきっかけを三者三様に話があがり…

  • 長年続くサービスのあるべき姿をどうにかするために設計を学びたい
  • 自らクソコードを生み出したので、その反省をもとにどうすれば良いものになるのかというところから
  • データモデリングの文脈で、時代的背景もあり、オブジェクト指向などの流れから自然と出会い
  • 既存の巨大なコードを相手にするときに、自身の責任範囲ではないことを明確に説明するための材料として
  • 炎上案件を正しくしたいということへのアプローチをするために
  • ひとつのファイルに詰め込まれたコードを分解するため、生き残るために

などなどのバックグラウンドが語られた

クリーンアーキテクチャを適応するところ、できないところ

  • クリーンアーキテクチャは万能ではない
  • 業務的な複雑さと技術的な複雑さがあるが、前者の場合は有効だが、後者の場合はパフォーマンスなどを考える必要があるため必ずしも有効ではない
  • ただ、前提知識として持った状態で取り組むと取り組まないでは大きな差になる。

DRY原則に関して

クリーンアーキテクチャの本に取り上げられていた「本物の重複・偶然の重複」という部分からDRY原則の話になった。

  • DRYを実践することで見えるものがあるので、はじめから怖がってはいけない
  • 技術的な重複はDRYでまとめるべきだが、ビジネスロジックとしての重複は気をつけて考えるべき(特に境界づけられたコンテキストを跨いでいないか、など)

コンウェイの法則への対処

コンウェイの法則を例にあげ、それらへの立ち向かい方の話に。

  • 細かいサービスを複数チームで取り扱うときにはジョブローテーションをすることなどで知識の共有化が有効
  • 1つのモノリシックなサービスに対して複数のチームが関わる場合は、設計方針などをWikiにまとめたり、勉強会形式で知識を共有するなどで対処している

また、組織とソフトウェア開発との関わり方の話になり…

  • 類似サービスをスクラッチで複数立ち上げてしまい、共有化できる部分の余地があったのにできない場合などもあり、そこは組織として働きかけないと難しい
  • コンウェイのアプローチ(ドメイン分析に応じて組織を組成する)というやり方も方法としてはあるが、様々な事業を扱う会社においては現実的に難しい
  • アーキテクチャと組織はセットで考える必要がある

全体の感想

  • クリーンアーキテクチャの文脈から始まり、設計との付き合いかた、組織にどうやってなじませていくかなど、普段の技術トークでは聞きづらい面白い話がたくさん聞けた。特に理解して使っている実践者はマジで少ないので大変学びがあった。
  • 新しく生まれくるコードをどうやって保つかというところには皆さん苦心されているんだなと思いながらも、そこらへんを滞りなく動かす仕組みや組織づくりが肝要なんだなと改めて実感。
  • 浸透させる話題や、コンウェイの法則の話題などは自分も時々考えさせられる場面があるのですごいためになった
  • モデリングなどはユースケース駆動開発実践ガイド に書かれていた話と共通する部分があったで、ココらへんを素地にするといいのかなと思った
  • ゲーム文脈でクリーンアーキテクチャが流行っているっていうのは、もしかしてもんりぃさんとか話かな?と思った
  • 次回はちゃんと書籍を読んでディスカッション枠で参加したい
  • 今回速記された方(下の関連リンク参照)いるので細かいものはちょっとオミットしました。

全般的な参考リンク

歩くシステム仕様書になってる人に読んで欲しいスライド『バス因子が自分で バス因子を脱するための方法』

温故知新的に振り返る、スライド回顧録のコーナーです。

speakerdeck.com

自走できるかつ頑張る人ほどバス因子になりやすいんですけど、人が少ない間はそれが常だし仕方がないんだけど、人が増えてきたときにそこで積み重ねてきたものを丁寧に分配していったかって話です。

もちろんこのスライドを発表された方自身もすごいのだけれども、それと双璧を成す部分として、できあがった環境がとても良い環境だなって感じていて、バス因子を解いてくれるために協力的な仲間や、バス因子を組織の問題としてどうにかしようという風土があるということ。

だいたいこういうバス因子になるひとってその環境下におけるスタープレーヤー的な部分があるので、バス因子を取り除けど取り除けど新しいものを割り振られがちなんだけど、きっとそれよりも解く速度のほうが早かったんだろうなという感じが(スライドからだと)感じられた。

私の今いる環境は、バス因子をなくして行けるほどここに余裕がないけれども、バス因子をなくしていけるような努力や、姿勢みたいなものはこのスライドからエッセンスとして活かして行きたいなーと思った。

ちなみの同じ人が書かれた、普通のRubylistとしての生活発表(傍からみるとすごくできる人感あるけど)もすごくよかったので併せて読むとよりエモい。

関連リンク

式年遷宮とディスポーザブル長屋

体調悪めなので雑記 + 用語備忘録的な話です。

個人的に昔からインフラ構築とは遠い場所で仕事することが多くて、抱くイメージとして

  • プロの長年の経験と勘により編み出される設計
  • 失敗や空気感から編み出されるミドルウェアのセットアップ法
  • 数多の死線をかいくぐったからこそわかる予防線の張り方

みたいのが5、6年前に抱いていたインフラ屋さんのイメージでした。

しかしながら近年のクラウド化やInfrastructure as Codeの世界観が浸透してきたのと、より自分がインフラ寄りの仕事をせねならぬことになり、現状確認をしたら、だいぶイメージと違っていました。

その中でも一番感銘を覚えた言葉が「式年遷宮」でした。

例えば、1つのシステムを ロードバランサ、スイッチ、サーバ、ミドルウェア、ログ集約サーバなど 完全に冗長化しておき、1週間毎に冗長化されたシステム、A、Bをそれぞれ入れ替える。
- 式年遷宮Infrastracture · さよならインターネット より

秘伝のタレ化しそうなインフラもコードにより安易に複製可能になったのでそれを交互に入れ替えて検証するなんてこともできる、そんな時代になったんだなと思いました。

あとそれに加えて、なにかで耳にした「ディスポーザブル長屋」って概念も素敵だなって思いました。

そういえば、帰り際に興味深い体験がありました。 新幹線までの時間、鴨川で遊んでいると、川沿いにある長屋が目に飛び込んできて 長屋、火事になると隣家が燃えて大変になる。そこで編み出されたのが 長屋を壊しやすくして、火事になればすぐに取り壊して建て替えるシステムだったな。 はて、これはもしやImmutable Infrastructureではないのか。 不要になったものを取り壊し、新しくつくりなおす。 まさにImmutable Infrastructureでした。 我々日本人は、ちょんまげの頃に既に Immutable Infrastructureの概念を取り入れていたのです。

-Monitoring Casual Talk in Kyoto 行ってきた #monitoringcasual · さよならインターネット より

Terraformなんかがあるとココらへん容易に可能で、「やべぇこの構成おかしいからぶっ壊して作りなおそう」ってのが結構簡単に差し替えられるんですよね。昔は構築するのが大変だったものがサクッと作れるからできるワザ。

現実世界の感覚を、システムにコンバートすると良い発見があるという一例がここには詰まっているなと思いました。

※インフラ避難訓練の話も学びが多かったのでまた別の機会に書く。

関連リンク

Rubyの関数の引数では可変長引数と可変長キーワード引数で便利な使い方ができる

両方使うことで、面白い使い方ができるんだなというメモ

環境

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]

実例

前提のおさらい

*引数名 で引数を好きな個数指定でき、配列に格納できる

def optional_args(*args)
  p args
end

上のメソッドを実行すると以下のような結果になる。(出力結果はコメント表記)

optional_args("30")
# ["30"]

optional_args("20","30")
# ["20", "30"]

optional_args("20","30",:hoge)
# ["20", "30", :hoge]

**引数名 で引数がキーワード引数の形式で選択された場合、キーワード名をシンボルとしたハッシュで格納される

def keyword_args(**keywords)
  p keywords
end

上のメソッドを実行すると以下のような結果になる。(出力結果はコメント表記)

keyword_args(first_sym:1)
# {:first_sym=>1}

keyword_args(second_sym:"2", first_sym:1)
# {:second_sym=>"2", :first_sym=>1}

keyword_args(second_sym: :second, first_sym:1)
# {:second_sym=>:second, :first_sym=>1}

本題

下記のように指定すると、どっちでも対応のような記述ができる

def double_args(*args,**keywords)
  p args
  p keywords
end
# キーワード引数でかけば、**keywordsの方に値が入る
double_args(one_sym:1)
# []
# {:one_sym=>1}

# 普通の引数でかけば、**argssの方に値が入る
double_args("30")
# ["30"]
# {}

もちろん順番通り入れれば両方の値がはいる

# 普通の引数、キーワード引数というdefの設定通り入れればちゃんと入る
double_args("30",first_sym:1)
# ["30"]
# {:first_sym=>1}

# 逆にすると当たり前だけど引数の順が違うのでエラー
double_args(first_sym:1,"30")
# syntax error, unexpected ')', expecting =>
# double_args(first_sym:1,"30")

参考リンク

rspecのsubjectは同一ブロック内で2回指定しても再実行されるわけではない

2回実行した時…みたいので subjectを2回実行すればいいやん! みたいに思うがそうは問屋が…的な。原理までは調べてないが挙動としてはこうなんだよメモ

環境

$ bundle exec rspec --version
RSpec 3.7
  - rspec-core 3.7.1
  - rspec-expectations 3.7.0
  - rspec-mocks 3.7.0
  - rspec-rails 3.7.2
  - rspec-support 3.7.1

結果

下記のようなクラスで

class Calculate
  def initialize
    @value = 0
  end

  def add_and_print
    @value += 1
  end
end

下記のようなrspecを用意した場合

describe ".add_and_print" do
  let(:obj) { Calculate.new }
  subject { obj.add_and_print }
  context "2回実行した場合" do
    it "1回目は1,2回目は2" do
      expect(subject).to eq(1)
      expect(subject).to eq(2)
    end
  end
end

下記のように失敗する。

Failures:

  1) .add_and_print 2回実行した場合 1回目は1,2回目は2
     Failure/Error: expect(subject).to eq(2)
     
       expected: 2
            got: 1
     
       (compared using ==)

なので意図通りにやりたいときは直実行するのみ

describe ".add_and_print" do
  let(:obj) { Calculate.new }
  context "2回実行した場合" do
    it "1回目は1,2回目は2" do
      expect(obj.add_and_print).to eq(1)
      expect(obj.add_and_print).to eq(2)
    end
  end
end