コード日進月歩

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

bashで乱数を使いたいときは$RANDOMという変数が用意されていいる

表題ですべてを言い切るシリーズ

環境

$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

使い方

$ echo $RANDOM
10931

他のシェル

zsh

同じ名前で存在する

% zsh --version
zsh 5.7.1 (x86_64-apple-darwin18.2.0)
% echo $RANDOM
3117

fish

存在しない、がrandomというコマンドがある

~> fish --version
fish, version 3.0.2
~> echo $RANDOM

~> random
31347

参考サイト

ダークローンチ(リリース)/フィーチャートグル とは何かざっくり調べる

そういや認知度低いなと思い改めて調べる

意味

  • リリースと同時に機能を開放せずに別の方法で新機能を開放する手段を提供する
  • 特定の条件下や特定の割合で新機能を試し、検証を行う

間違えやすい言葉

カナリアリリースともニュアンスが近いが、カナリアリリースはABテストに近く、一定割合のユーザーを新機能に流すような形だが、ダークリリースは特定の条件下においてのみ発動する形になるようなニュアンス。

参考リンク

『レガシーをぶっつぶせ。現場でDDD!』に行ってきたよメモ

レガシーをぶっつぶせ。現場でDDD! にいってまいりましたのでメモ。

今回はDX(デジタルトランスフォーメーション)レポートに取り上げられていた技術的負債の塊であるレガシーシステムに立ち向かうためのDDDということで現場のどろどろ感を出してくイベントという趣旨。

各発表の感想


ソフトウェアの核心にある複雑さに立ち向かう

感想

  • ソフトウェアにおける複雑さの根源に対する向き合いかた、切り分け方の考え方の話
  • 変更容易性が高いことは開発におけるすべての面において有効というのを改めて感じさせられた
  • ドメイン駆動設計本格入門のときにも語られていた「ドメインロジック」を「ビジネスルール」に置き換えるということをより濃く話されていたし、明確に置き換えていたので前回以上に考え方がスッと入った
  • エヴァンス本の3章と4章は何か困ったときの出展として読めるようにするべきとい

関連リンク


レガシーシステムからモダンな環境への移行 ~Y!プレミアム・バックエンドシステムのリニューアル~

感想

  • 現在のレガシーシステムの現状、そしてそこに対してどうやってDDDでアプローチしていっているかという経緯の話
  • 機能としてどんどん継ぎ足しされていった「Yahoo!プレミアム」に対してどうやってドメインを分け、適応していくかという話
  • 複雑化したものとどうやって向き合っていくかを考えたときにDDDが最適解であると考えて導入していったなど、ちゃんと理由をもってDDDを取り込んでいったところなど経緯込みで参考になった
  • DDDを行った副産物として責務分離を意識するようになり、分割することで他の人に使われる意識が強くなるので自然と整理されていく、というエピソードはなるほどなと思えた。

関連リンク


設計人材を育てるためにDDDをどう使うべきか

感想

  • 設計力がある人材を育てるにはどうしたらいいかという話。
  • 大きく複雑なシステムには一人では立ち向かえない、それへのカウンターパートとしてどうやって設計ができる人材を増やしていくかという
  • 設計(Design)とは何かというのは物を作る前に落とし込む行為という言い回しに非常に納得感があった
  • 期限やアウトプットが出てない状況で実装を進めろというプレッシャーを「実装圧力」という言葉で表現しているのが秀逸だったし、その実装圧力で設計が浅いものを作ってしまうという話も綺麗にまとまっていた。
  • 師匠と弟子という形でペアプロ形式を取るのは非常にいい取り組みだと思ったし、やはり言語での継承だと情報量が大きくなってしまうトピックはペアでやる形式が一番時間効率いいものだなという感じに思えた

関連リンク


QualityとDeliveryを両立させるために僕らがやったこと

スライドは公開されたら貼ります

www.slideshare.net

感想

  • 既存サービスを部分的にリプレイスしていくための過程とどういうことをしていったかを多角的に説明した話。
  • DDDの手法でドメイン分析を行い、ドメインを分けることで作るものの構造分析ができているのはDDDの本懐という感じ
  • 増田さんのワークショップを経験されていたので、そこでの考えを生かしている部分に関しての説明が丁寧で「いびつな形でもいいのでアウトプットを出す」「役に立つ部品を見つけることが最優先」など増田さんのDDDの考え方が反映されている感じでした
  • 新技術の導入に対して、チーム内に識者がいないので専属の壁打ち用のメンバーを外からアサインするというのは予算管理とか考えたらあんまり思いつかない手なので「なるほど、そういうのもあるのか!」という事例
  • キレイを維持する、また重要じゃないコンポーネントと重要なコンポーネントをある程度の表建てして判断するという手段をとっているのはちゃんと体制を敷くことに尽力しているという印象を受けた
  • カナリアリリースをするできる仕組みを整えることで、ミニマムスタートをうまく進めていく、旧実装と新実装を両方実装して実際に掛かった工数を比較して新実装の成果を定量的に示すなどのパワープレイはただただすごいと思わされた
  • 疎結合、高凝集を実現するためにBFF的な役割や、DBへレイヤーへの接続に関しても層を設けるなど責務分離をかなり意識したレイヤ構造にしていたにもかかわらず、レイヤでの実装が増えているにもかかわらず工数がトータルでは減ったという話はすごいなと思った
  • V字モデルでテストができるようになった部分など、いろいろ聞いてみたいことはたくさんあったがそこらへん聞きそびれてしまったので何かの機会があればまた伺いたいし、スライドが公開されたときはまた見直したい

関連リンク


実録!LOHACOにおけるDDDとCleanなArchitecture

感想

  • 軽量DDDとCleanArchitectureを採用した事例
  • 複雑なロハコのドメインに関してどうやって挑んでいったかという経緯と実践が込められている
  • 腐敗防止層を設けて頑張るという戦略をとったがどうしてもそこの辛さが出てきた話はどこにでもある話なんだなという感じ
  • DDDは倣うより慣れろ、というのは心理だし抽象的な概念は実践を伴って現実的に活きるものだなという感じ
  • Kotlinを採用するという選択肢に関してもうちょい掘り下げて聞けばよかった
  • 即効性のあるプラクティス(ValueObject)とかはどこでも有効というのは確かにという感じ

関連リンク


ビジネスルールの複雑さに立ち向かう

感想

  • ビジネスルールとどうやって戦っていくかを4象限で分け、「ドメインオブジェクトの設計と実装」「ビジネスルールの 説明文書/定義文書」「ビジネスルールの説明文書/定義文書」「ビジネスの全体像/事業戦略」としそれぞれどのような考えをもつといいかという話。
  • ドメインオブジェクトの設計と実装」に関しては具体的にどういうコード記述をするかという方法論の話でドメイン駆動設計本格入門のときの際にも語られていた作り方の話
  • 「ビジネスルールの説明文書/定義文書」に関しては日頃からある利用規約や料金表など普段のビジネスの取り決め文章からどうやって作るかの脳内トレーニングをすればいざ自身の業務のときにモデリングするときにも活きる、という旨の話をされていた
  • ドメインモデルの全体像/戦略的設計」に関してはビジネス上の振る舞いの分類を知っておくことでどういうビジネスルールを構築するかを着想しやすくするための分類方法の紹介があった
  • 「ビジネスの全体像/事業戦略」に関しては自身の携わるビジネスが市場においてどんな状況であるかなどを把握しておくことでどういう変化や要求が起きうるかを予め把握できるなどの話があった
  • これらの4つの事象を行ったりきたりすると良い、という話で、たしかに磨かれるものは多いだろうなという感じだった
  • もともと「変化に強いシステムの作り方」という話をされてきた増田さんだったがそこにさらにプラスオンで「変化の方向性をシステム化するビジネスから読み取るには」という話に展開されてきた感じがあり、すごく学びが多い話でした。

関連リンク


パネルディスカッション

エスチョンに対して登壇者のコメント要約の形で載せていきます。

Q.チームのメンバーがDDDに興味を持たず、やる気をしめさないときはどうメリットを伝えればいいか

  • 一緒に1ヶ月ぐらいは勉強したりペアで開発する機会を設けて進めたりした、という体験談があった
  • モチベーションって人それぞれなので、ちゃんと人事制度に埋め込むべき、という意見
  • 2つのパターンがあって「DDDって伝えないでいく、(書籍の)リファクタリングとかでも語られていることはビジネスルールに関する話なのでそういう切り口で話す」「聞いてくれるひとでも最初で全部は伝わらないものなので、そこはそういうものだと思ってやる」という話があり、最後に「正面切ってドメイン駆動設計って話すぎないほうがいい」という旨の話があった

Q.DDDで開発する際、リリース日程や作業工程をどのように見積もってどのように計画立ててるか

  • DDDは関係なく、見積もりをちゃんとやるという意見
  • 同じことであれば経験値から見積もれるが、やれないことは見積もれない。慣れていけば見積もれるし学習曲線ができる。
  • プロジェクトのサイズを小さくやり、DDDなど新しい試みは識者が支援して、わかりきったものは従来通りやってもらうなどで見積もりの精度を保つようにしていた

Q.ユビキタス言語の管理ってどうしていますか

  • だいたい全員がユビキタス言語を管理してない、リストを作ってみたがその後運用はできていない…という回答

Q.(上の質問の続き)ユビキタス言語を管理しないことで問題は起きているか?

  • ビジネスとエンジニアの間に仲介するレイヤーの人が増え、その人がいないと回らないという形になる
  • 用語の重複などが起きた場合は実際に軌道修正をかけてみて、それで治らない場合はその言葉でクラスを作ってみてつながりを考えてみたりする
  • もともとリストを作るなどフラットに全部やるという方法論はとっていない。ただリアルに仕様を取り違えている場合は徹底的に掘り下げて向き合う。(おそらく言葉がすれ違うことで進めていくことの危険を回避するという話)

Q.処理速度とのトレードオフはどれくらいありますか?(ゲームなど60~120FPSとかで導入できるか)

  • Webパフォーマンスの文脈だとGoとかElixirで頑張るなどするし、インフラでカバーするなどの方策をとる。
  • パフォーマンスを求められるところはDDDを諦めて分割するなどの方針をとる

Q.コードが多くなりがちですが、テストコード等はどうしていますか?

  • 動的型付け言語(Rubyとか)、だと何が入ってくるかがわからないのでそれに対するテストコードが多くなりがちだが、型付きの言語やタイプヒンティングができる言語(PHP7とかPython3)であればそれらの手間がなくなり軽減できるので少なくなった
  • 型がある言語だとそこでガードができるのでテストコードは最低限になる
  • テスト自動化という仕組みがない時代からやっているからテストコードは書いていない、ただし分岐が多くなる部分などはビジネス的にも大事な部分なのでしっかり手動で手厚く確認作業を行う。

Q.Railsでうまくやる方法はありますか?勇気を出してリプレイスをしたほうが良いですか?

  • RailsActiveRecordが密結合で実現しているためDDDのモデリングの考え方と相性が悪く、レイヤードアーキテクチャをやろうとすると型がないことなどDDDの考え方が適応しにくい
  • リプレイスに関しては一気にやらずとも少しづつやる方法があるのでやり方は考えてほしい

Q.DDDなくても開発できるじゃんって言われときのベストな回答は?

  • 現在困っていないのであれば無理にDDDを採用しなくても良い
  • DDDのメリットはビジネス側の作業量の感覚と現実のシステム開発の作業量の感覚が近づくこと、それにメリットが見いだせるか
  • 某社で取り組む際は中心メンバーとやってくれそうなメンバーをアサインして全体の2割が動いてくれるようにして全体を動かすように動いた

Q.ユビキタス言語が浸透しない。ビジネスサイドが同じ意味で別の言葉を使う。何か対策工夫はあるか?

  • どちらか正解、というよりはビジネスサイドで使われる言葉のほうに合わえせていくほうがいい
  • 部署によって同じ意味だが違う言葉、みたいな場合はドメインが違うと割り切って対応する

全体感想

  • メンバーや非エンジニアサイドへの理解の求め方は事例として貴重な意見が聞けた。
  • ゲームのFPSの話はおそらく「ValueObjectのようなプリミティブなものをラッピングすることでオブジェクト生成コストが増え、1秒間に何回ループ処理ができるかというゲームにおいてはその重複生成が命取りになったりするんだけどそこに関してどういう考えか」みたいな意図の質問に聞き取れたので、これこそ言語のチョイスやうまくネイティブと相性の良いValueObjectの作り方を考えるなどになるので、言語のエキスパートの人の知見が必要そうな感じ。
  • テストの話とRailsの話は言語選択によるミスマッチや、採用フェーズによって何を活かすかを考えさせられる部分が多かった。テストは結構Twitterでも意見がいくつかあって一考するところがありそう

関連リンク


全体を通しての感想

  • 全体的にレガシーシステムにどう向き合っていくかという話でかなり濃い&学びの多い事例が多かったです
  • QとDを担保する話は組織での人のアサインや立ち回りまで含めて秀逸な事例でした。
  • 最初と最後の増田さんの話は書籍「現場で役立つシステム設計の原則」のさらに先の話を聞くことができて、数々の現場を渡り歩いてきたシステム開発者の知見が集結している気持ちになりすごい学びがありました。
  • 型がない言語に人権のない話が続いてきて、安全に振り切る場合は型のある言語で構築したほうが安全なのかなという気持ちになった。(いまならJavaよりもKotlinのほうがnullのこと考えるとよかったりするんだろうか…)

他の方のブログ記事

組織としてのセキュリティ対策を考えるときに見たいスライド『知らなかった、時に困るWebサービスのセキュリティ対策』

speakerdeck.com

直近でも記憶の新しいRails脆弱性、そのような脆弱性を含めたセキュリティインシデントは思いもよらぬ形で起きうるもの。そういったインシデントに対してどう構えれば良いのか、またどういう心構えでいればいいのかというのを組織として考えるときに参考になるのがこのスライド。

めちゃくちゃ大きい会社であればこれらの考えやこれらに対してどうあるべきかみたいなところが知らず知らずにまとまっていたりするが、自社サービスをやらない会社や、火の浅い会社はこのような組織的な構え方は存在しなかったりする。その場合にどういうことを考えればいいのか?というときにはすごく学びの多いスライドだと思います。

関連リンク

GitHub上でやりかけのPRにはDraft機能を使うと幸せになれる

こういう機能と使い方もあるというただの雑記

GitHubのDraft機能とは

Draft Pull Requestをリリースしました - The GitHub Blog - Japan

  • DraftにするとPRの表記がDraftになる
  • DraftがOpenになるまでマージできない

使い所

  • 純粋にWIPのブランチ対するPR
  • Description書きかけだけど、一時保存としてPRをSubmitしたい
  • 現在レビュー中のPR(ブランチ)から枝分かれしたブランチのPRなどで枝分かれ元の処理が終わるまでレビューを待ってもらいたい

などなど、結構使い所がある。

関連リンク

GitHubにDraft Pull Requestが追加されたけど利用制限があるみたい - komajou’s diary - チームの機能なのか、一人で使う想定のProは除外…

RailsでのRSpec実行時乱数の状態を実行毎に変わらないように固定する

RSpecでsampleするとコケるんだけど特定しづらい…みたいな奴を解消する。

環境

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin18]
$ bin/rails --version
Rails 5.2.2
$ bundle exec rspec --version
RSpec 3.8
  - rspec-core 3.8.0
  - rspec-expectations 3.8.2
  - rspec-mocks 3.8.0
  - rspec-rails 3.8.1
  - rspec-support 3.8.0

やり方

spec_helperでsrandのseed値を固定する

bin/rails g rspec:install

で生成される rspec_helperだと以下のようにbeginでまるまるコメントアウトされているので直す(昔はコメントアウトされてなかったみたいなの場合によって齟齬がある)

# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
  # This allows you to limit a spec run to individual examples or groups
  # you care about by tagging them with `:focus` metadata. When nothing
  # is tagged with `:focus`, all examples get run. RSpec also provides
  # aliases for `it`, `describe`, and `context` that include `:focus`
  # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
  config.filter_run_when_matching :focus

#### 中略 ####

  # Run specs in random order to surface order dependencies. If you find an
  # order dependency and want to debug it, you can fix the order by providing
  # the seed, which is printed after each run.
  #     --seed 1234
  config.order = :random

  # Seed global randomization in this process using the `--seed` CLI option.
  # Setting this allows you to use `--seed` to deterministically reproduce
  # test failures related to randomization by passing the same `--seed` value
  # as the one that triggered the failure.
  Kernel.srand config.seed
=end
Kernel.srand config.seed

これを指定すると rand にまつわるものはすべてseed値が rspec--seed {{seed数値}} もしくは --order rand:{{seed数値}} のオプションのseed数値を使うようになる。

rspec実行時に指定する

前述通りseedの値を指定する

bundle exec rspec --seed {{seed数値}}

もしくは

bundle exec rspec --order rand:{{seed数値}}

※もともとのRSpecのオプションとしては order とあるとおりテスト順番を変えるためのものなので注意

対象とするコード

1から10000の値の数値が入った配列からsampleで1個取り出す

spec/sample/demo_spec.rb

require 'rails_helper'

RSpec.describe "sample" do
  let(:demo_array) { (1..10000).map{|x| x} }
  subject { demo_array.sample}
  context "sample実行した場合" do

    it "期待した結果が返ってくる" do
      expect(subject).to eq(1548)
    end
  end
end

spec_helplerの値をコメントアウトした状態の場合

▼実行1回目

$ bundle exec rspec spec/sample/demo_spec.rb
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 6736
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.02443 seconds (files took 7.75 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

▼実行2回目

$ bundle exec rspec spec/sample/demo_spec.rb
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 9457
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.02021 seconds (files took 5.08 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

実行毎に数値が違う。 ではそのまま --seed をつけるとどうなるか

▼seedつけて1回目

$ bundle exec rspec spec/sample/demo_spec.rb --seed 100

Randomized with seed 100
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 6560
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.01806 seconds (files took 2.08 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

Randomized with seed 100

▼seedつけて2回目

$ bundle exec rspec spec/sample/demo_spec.rb --seed 100

Randomized with seed 100
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 2008
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.01302 seconds (files took 2.04 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

Randomized with seed 100

特に固定はされない

spec_helperで Kernel.srand config.seed を指定した場合

ちゃんとspec_helperに記述して、--seed をつけてやってみる

▼seedつけて1回目

$ bundle exec rspec spec/sample/demo_spec.rb --seed 100

Randomized with seed 100
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 5641
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.02062 seconds (files took 4.1 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

Randomized with seed 100

▼seedつけて2回目

$ bundle exec rspec spec/sample/demo_spec.rb --seed 100

Randomized with seed 100
F

Failures:

  1) sample sample実行した場合 期待した結果が返ってくる
     Failure/Error: expect(subject).to eq(1548)
     
       expected: 1548
            got: 5641
     
       (compared using ==)
     # ./spec/sample/demo_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.02198 seconds (files took 4.91 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/sample/demo_spec.rb:8 # sample sample実行した場合 期待した結果が返ってくる

Randomized with seed 100

5641で固定された。

参考

RailsでCrossOriginの設定をする場合は rack-cors のgemを入れればすぐ終わる

APIモードで作らなかったので、異なるドメインからアクセスされるAPIをやるために Access-Control-Allow-Origin とか設定せねば…とか思ったらすんなりできたのでメモ

環境

$ bin/rails --version
Rails 5.2.2.1

使うgem

cyu/rack-cors: Rack Middleware for handling Cross-Origin Resource Sharing (CORS), which makes cross-origin AJAX possible.

導入方法

Gemfileに書いたら、application.rbに追記するだけ

module HogeApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # 中略


    # rack-corsここから
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        # 許可するドメイン
        origins "localhost:3000", "example.com"
        # 許可するヘッダとメソッドの種類
        resource "*",
                 headers: :any,
                 methods: [:get, :post, :patch, :delete, :head, :options]
      end
    end
    # ここまでrack-cors
  end
end

参考リンク