Gunma.web #58 で話してきた
表題の通り LT してきました。
話したのは MCP Training です。
オチは、教えることよりも自主性から色々試してみたら的な内容になりました。
他にも色々な方の発表があって参考になりました。
https://gunmaweb.connpass.com/event/372632/presentation/
次回は 3月末くらいになると思います。
Gunma.web #56
でLT してきました。 テーマは前回同様生成AIという事で...正直ネタが尽きるかな?と思いきや 次から次へとネタが出てくるので、話のネタには正直困りませんでした。
無関心の谷
Developer Summit 2025 [14-D-1] Yuki Hattori - Speaker Deck
実は、この現象に思い当たる節があり、明らかにしておかないと嫌な予感しかしかったので 今回思い切ってやってみた次第です。
まずは、再現性を得ようと...
自分の発表
そして再現性も込みで発表した内容がこちらです。
他の方の発表
いや〜、今回も目白押しでした。 みなさんもネタが尽きなくて正直よかったです。
運営スタッフからも推しに押されての生成AI version 3 でしたが.... まだ、推されそうな予感!!
github copilot + TDD で ズンドコキヨシ
経緯
- github copilot と TDD が相性が良いという話を聞いて...
- 試しに ズンドコキヨシでやってみたという話です。
用意するもの
- github copilot が使える エディタ
- 自分は neovim を使いました。
- product code
- zundoko_kiyoshi.rb
- テストコード
- test_kiyoshi.rb
チャレンジ内容
- コードは極力打たない
- コメント文でgithub copilotを誘導する
問題文
- 「ズン」「ドコ」のいずれかをランダムで出力し続けて「ズン」「ズン」「ズン」「ズン」「ドコ」が出たら「キ・ヨ・シ!」と出力して終了
問題を分解する
- ランダムに ズンとドコを標準出力する
- 配列に出力予定を保存する
- 配列を 結合して ズンズンズンズンドコ が含んでいたら 真を返す
- ズンズンズンズンドコになるまで処理をloopする
- 条件が整ったら
- キヨシ! と出力する
- loop を抜ける
- 条件が整ったら
各個撃
- ランダムに ズンとドコを標準出力する
- 配列に出力予定を保存する
必要なライブラリを準備
- Gemfile
# frozen_string_literal: true source "https://rubygems.org" gem "minitest" gem "minitest-spec-context" gem "minitest-reporters"
- bundle i
実行コード側を用意
- test_kiyoshi.rb
require './zundoko_kiyoshi' require 'minitest/autorun' require 'minitest/spec' require 'minitest-spec-context' require 'minitest/reporters' Minitest::Reporters.use! describe 'ズンドコキヨシ' do before do @ki = ZundokoKiyoshi.new end context 'ズンかドコをランダムに出す' do it '@ki.zundokoがズンかドコか?' do assert_includes %w(ズン ドコ), @ki.zundoko end end end
REDを確認
- bundle exec ruby test_kiyoshi.rb
product code
- zundoko_kiyoshi.rb
class ZundokoKiyoshi def initialize @stock = [] end # ランダムにズンとドコを返却する # また、@stockに追加する end
コメント文の後ろに挿入しようとしばらく待つと...
- あら、便利。下記のコードが出るのでタブキーを押してそのまま採用
class ZundokoKiyoshi def initialize @stock = [] end # ランダムにズンとドコを返却する # また、@stockに追加する def zundoko result = ["ズン", "ドコ"].sample @stock << result result end end
GREEN を確認
- bundle exec ruby test_kiyoshi.rb
- クリア: ランダムに ズンとドコを標準出力する
- リファクタリングを飛ばしてない?と思われるので一応
- ここまでコードが短いと「明白な実装」になってるので、飛ばしてます。
次の各個撃破
- ズンズンズンズンドコになるまで処理をloopする
- 配列を 結合して ズンズンズンズンドコ が含んでいたら 真を返す
- test_kiyoshi.rb
require './zundoko_kiyoshi' require 'minitest/autorun' require 'minitest/spec' require 'minitest-spec-context' require 'minitest/reporters' Minitest::Reporters.use! describe 'ズンドコキヨシ' do before do @ki = ZundokoKiyoshi.new end context 'ズンかドコをランダムに出す' do it '@ki.zundokoがズンかドコか?' do assert_includes %w(ズン ドコ), @ki.zundoko end end context 'ズンズンズンズンドコ を評価' do it '@stockにズンズンズンズンドコ が含んでいたら 真を返す' do @ki.stock = %w(ズン ズン ズン ズン ドコ) assert @ki.kiyoshi? end end end
RED を確認
- bundle exec ruby test_kiyoshi.rb
product code に追加
- コメント文まで書く
class ZundokoKiyoshi def initialize @stock = [] end attr_accessor :stock # ランダムにズンとドコを返却する # また、@stockに追加する def zundoko result = ["ズン", "ドコ"].sample @stock << result result end # @stockをjoinして ズンズンズンズンドコを含んだら # trueを返却する end
コメント文の後に出るかな?
- 候補が出るので、同じようにタブキーを押して採用
class ZundokoKiyoshi def initialize @stock = [] end attr_accessor :stock # ランダムにズンとドコを返却する # また、@stockに追加する def zundoko result = ["ズン", "ドコ"].sample @stock << result result end # @stockをjoinして ズンズンズンズンドコを含んだら # trueを返却する def kiyoshi? @stock.join.include?("ズンズンズンズンドコ") end end
GREEN を確認
- bundle exec ruby test_kiyoshi.rb
条件が整ったら キヨシ! と出力する
- 疑似コード通りに整えるだけ
require './zundoko_kiyoshi' require 'minitest/autorun' require 'minitest/spec' require 'minitest-spec-context' require 'minitest/reporters' Minitest::Reporters.use! describe 'ズンドコキヨシ' do before do @ki = ZundokoKiyoshi.new end context 'ズンかドコをランダムに出す' do it '@ki.zundokoがズンかドコか?' do assert_includes %w(ズン ドコ), @ki.zundoko end end context 'ズンズンズンズンドコ を評価' do it '@stockにズンズンズンズンドコ が含んでいたら 真を返す' do @ki.stock = %w(ズン ズン ズン ズン ドコ) assert @ki.kiyoshi? end end context 'ズンズンズンズンドコになったらキ・ヨ・シ!' do it '条件が整ったらキ・ヨ・シ!と出力しloopを抜ける' do loop do puts @ki.zundoko if @ki.kiyoshi? puts 'キ・ヨ・シ!' break end end end end end
結論
- うまくいった
- メソッドが短くなればなるほど...リファクタリングがなくなる
- 自動生成で十分行けちゃう
Gunma.web #52 テスト駆動開発
表題の通り開催しました。 今回は あの @t_wada さんにお願いをして基調講演していただきました。
ちょうど前日に...
こんなブログの投稿があったもんだから、数人でワクワク感満載
t_wadaさん meet に来る
- 会場の準備を済ませて、大型ディスプレイと繋げて PC を台上に置いて準備万端、あとは呼ぶだけ
- 「初めまして」と数回お会いしたことはあるものの、こちらでは初めてだったので思わずこんな挨拶にw
- 台上のPCを会場全体が見えるようにカメラを向けて欲しいと要望あり
- 開催後、運営メンバーで「確かにオンラインで発表する側からしたら会場の雰囲気気になるよね」と
- 幸い、ちょうどいい感じの高さの台で会場の雰囲気が伝わりやすいカメラ位置だった。
- 次回オンラインでゲストを呼ぶ開催時の反省点としたい
いよいよ始まる
- 当日の流れはこちらで
- やはりというか前日のブログ記事の話題に
FizzBuzz のTDD(ライブコーディング)
- スムーズにライブコーディングというか、箇条書きにテストケースを同じ文脈に揃えることを解説しながらやってました。
- 実際に自分でやるとなったら、ここまでスムーズは難しいよな。
- 見せ方も非常に上手。確実に相手に伝わってる感ある
解説しながら用語など解説
- テスト容易性
- 観測容易性
- 制御容易性
- 小ささ
- Humble Object Pattern
- テスト容易性を低く下げている要素を薄く切り離すテクニック
- 標準出力など
- ToDoリスト作る段階が一番重要
- テスト容易性 と 重要度 を 「高 」と「低 」に分割できれば勝ったようなもん
- 同じ文脈で揃えていく
- 3Aパターン
- 準備:Arrange
- 実行:Act
- 検証:Assert
- 検証から書く!
- テストをゴール(Assert)から書くの最初むずいけど慣れると無駄な準備コードを書きすぎずにスムーズになるイメージ
- 作りやすさに引っ張られると使いやすさが犠牲になる
- 作る前に使う側に回ればその悲劇を回避できるのでは
- 仮実装
- テストを通過させるような簡単なコードをわざと書く
- テストコードのテストは実装コードでやる
- 実装コード(product code)をいじってわざと失敗させる
- 三角測量
- 2つ以上の値を使用しテストを書く
- ここでテストが失敗するが、狙い通りの失敗 -> 失敗することを確認する
- 明白な実装
- 自信があれば = 明白な場合は 三角測量せずに本実装しても良い
ここに来て...バッドシナリオ!!
- 動作する詳細設計書になっているか? -> 違った
- 現場あるある話
- 仕様の構造をテストコードの構造に落とし込む
- テストコードを仕様書として読めるようにリファクタリング
- テストの実行結果を粒度を揃えたツリー構造として表現する
- 三角測量で書いたテストは不要なテストとなる可能性がある
- 不要なもの = 意図が伝わらないものは未来のために消しておく
- 残っていくテストのメンテナンスコストも考える
終盤
- いよいよ完成系になってきたところで、TDDを続けていく上で必要なことを解説
- テストがあると楽っていう体験をしてもらう
下記の記事の紹介
質疑応答
- DB にロジックを埋め込んでしまった場合はどのようにテストすればいいか?
- DBから値を取得したという前提で、ロジックの部分を切り出してテストする
- この本の紹介
- 背景の後ろがリアル本棚で数人がビックリ!
- 現場で実際には緊張したりする場で、重複がある事を気づかず次に行ってしまいがちになる事がある
どうしたらいいか?(自分の質問でした)
- コピペ判定ツールを使ってみる。
- 構造化して、文脈で同じ事を気付きやすくする
- etc...
t_wada さん発表時の slide
- 今回のものが大体網羅されているので、これを貼り付けておきます。 speakerdeck.com
基調講演の後のLT
- 素晴らしい発表のあとに LT をするのは緊張感半端ないですね。
- 自分の LT はこれをしました。 speakerdeck.com
終わった後...
- t_wada さんの発表は「TDD の良さはこれだよ!」と言いたくなるくらいに解りやすく伝わりやすいものでした。
- 自分じゃこうは出来ないな〜汗
- 特に感じたのは...
- インクリメンタルな開発・設計 の部分ですね -> この言葉自体も今回がキッカケで知りました。
- 頭の体操に近いとか感覚の話を後輩にするのですが、一番大切な要素は、動作する詳細仕様書(設計書)であり、「反復しながら動作を頭の中に整理しながら落とし込んでいく、人に優しい手法」だという事が伝わってない感あったのでいい経験になりました。
- さて、来年度の研修資料を作り直すぞ〜!
Ruby の rescue
今更ながら Ruby技術者認定試験のGOLD を受けようと思い
模擬試験問題を解いていたところ...奇妙なコードに出くわした。
忘れると痛い目を見そうなので、ここに記述する
begin 'aaa'.bbbb rescue puts "レスキュー出来たね" end #=> レスキュー出来たね
何も問題はない
begin 'aaa'.bbbb rescue NoMethodError puts "レスキュー出来たね" end #=> レスキュー出来たね
これも問題ない
期待通りの動きである
begin 'aaa'.bbbb rescue NameError puts "レスキュー出来たね" end #=> レスキュー出来たね
- むむ?
- エラーの種類が違うのでは?
begin 'aaa'.bbbb rescue StandardError puts "ここには来ないよね?" rescue NoMethodError puts "レスキュー出来たね" end #=> ここには来ないよね?
来てしまったのである
原因を追うと...
NoMethodError の親クラス = NameError NameError の親クラス = StandardError
という事みたい。
トラップだな。気をつけないとね。
クリーンアーキテクチャを読んで...
- 印象に残ったことをつらつらとメモに残しておきます。
- 読むだけだと忘れるので
- まずは 22章まで
以下印象に残った文章
- アーキテクチャの重要性は変更コストによって計測できる
- 不完全な知識で運用する事を認める
- そうするのが人間であり得意である
- アーキテクチャは、実装と計測によって証明すべき仮説である
- 設計とアーキテクチャに何も違いはない
- ソフトウェアアーキテクチャの目的は、求められるシステムを構築・保守するために必要な人材を最小限に抑える
- ソフトウェアのソフトは...簡単に振る舞いを変更できるため
- 対して変更ができないものをハードウェアとよんだ
- ウェアはプロダクトの意味
- アイゼンパワーのマトリックス
- 緊急と重要の2種類の問題がある。緊急と重要は違う。重要なことが緊急になるわけではない
- 3つのパラダイム
- 「構造化プログラミング」
- 「オブジェクト指向プログラミング」
- 「関数型プログラミング」
- 「構造化プログラミング」の価値を高めるのは反証可能なプログラミングの単位を作成する能力である
- 機能分割がベストプラクティスであると考えられる理由
- UI, ビジネスルール, DBアクセス
- ビジネスルールは 独立させる事ができる
- ビジネスルールは独立してデプロイ可能である
- DBやUI とは別のチームが開発可能である
- 構造化プログラミング
- 直接的な制御の移行に規律を課すものである。
- オブジェクト指向プログラミング
- 間接的な制御の移行に規律を課すものである。
- 関数型プログラミング
- 代入に規律を課すものである。
- ソフトウェアの振る舞いは、既存の成果物を変更せず拡張できるようにすべき
- アーキテクチャを学ぶ理由
- 拡張ではなく大量の変更になってしまったら失敗である
- SRP
- 単一責任の原則
- モジュールはたったひとつのアクターに対して責務を負うべき
- 単一の修正が一つだけではなく複数の修正を誘発してしまうのは違反
- OCP
- オープンクローズドの原則
- 拡張に対しては開き、修正に対しては閉じてなくてはならない
- 既存の成果物を変更せず拡張できるようにすべき
- リスコフの置換原則(LSP)
- クラスの継承 = S型のオブジェクトo1の各々に、対応するT型のオブジェクトo2が1つ存在し、Tを使って定義されたプログラムPに対してo2の代わりにo1を使ってもPの振る舞いが変わらない
- 派生型である
- 置換可能性に少しでも違反してしまうと、システムのアーキテクチャが特別な仕組みだらけになってしまう
- 変化しやすい具象クラスを参照しない
- 変化しやすいクラスを継承すると
- 変化のたびに変更が必要になる危険性があがる
- 全再利用の原則(CRP)
- どのクラスをひとまとめにすべきか ではなく...
- どのクラスをひとまとめにすべきではないか
- 循環依存は厄介
- あるコンポーネントの変更が 依存関係を循環し、自身にも悪影響を与えてしまう
- 解消するには依存関係の逆転が必要
- 初期段階では必要しないが...モジュールなどが増えてきたら
- コンポーネント図は必要
- システムの論理設計に合わせて育てていく
- 独立コンポーネント
- 外部要因で変更が必要になることはない
- ほかのコンポーネントに依存していない
- 複数のコンポーネントに依存しているコンポーネント
- 従属コンポーネント
- ファン・イン
- 依存入力数
- ファン・アウト
- 依存出力数
- 不安定さ
- I = ファン・アウト÷(ファン・イン+ファン・アウト)
- 「方針」と「詳細」
- アーキテクトの目的
- 方針とは無関係に詳細を決めながら、方針をシステムの最も重要な要素と認識するシステムの形状を作ること
- 方針を決める際に 詳細を気にする必要はない
- 会社がDBの選択を決めていた場合...
- 優秀なアーキテクトならば、まだ決まっていないと主張するだろう
- 切り離し方式
- 早すぎる決定とは...
- ビジネス要件とは関係のない意思決定をしてしまう
- framework, DB, web server, ライブラリ, etc...
- 1台しかサーバが使えない状況もあり得る
- その場合はもっと違うアーキテクチャになっただろう...
- ビジネス要件とは関係のない意思決定をしてしまう
- 境界線を引くとは...
- DB と ビジネスルールは別物
- 本来切り離せる
- DB を何にするか?決定を遅らせても構わないはずである。
- エンティティ
- 最重要ビジネスデータを操作する最重要ビジネスルールを含んだインターフェース
- ビジネスを表すものとして独立させる
- これがないとビジネスとして成立しない最低限の単位
- ユースケース
- 自動化されたシステムを使用する方法を記述したもの
- アプリケーション固有のビジネスルールを記述する
- 入力データ、出力データ、それらがやり取りする適切なエンティティへの参照といった、データ要素を持っている
- エンティティは自身を制御するユースケースのことを知らない。
- クリーンアーキテクチャ
「エンジニアリング組織論」を読んで...刺さった言葉集
前提
- ただ漠然と読むのだと、読んだ後覚えてない事が多いので刺さった言葉を文章に書き出してみる
以下、箇条書き
- エンジニアリングは実現の科学
- 認知範囲とシステム思考
- 視野の広さと視座の高さ
- 個人でなく関係性に注目する
- 無能で十分に説明のつくことを悪意のせいにするな
- 「自ら考える人材」
- 自ら問題を発見し解決することができる
- 自立型人材
- 謙虚、敬意、信頼
- 階段を上る手助けをする
- 自己説得
- 問題の可視化
- 人 対 人 -> 問題 対 人
- ラーニングゾーン
- NG: コンフォートゾーン(忖度), 無関心ゾーン, 不安ゾーン
- SMART
- コントロールできない
- 能力, 成果
- 「プログラミングできるようになれ」は威圧でしかない
- コントロールできる
- 行動, 習慣
- 階段を自力で上がれるようになるまでサポートし続ける
- アジャイル開発は3倍の成功率、1/3の失敗率
- プロジェクト, プロダクト の違い
- プロジェクト: 始まりと終わりがある
- プロダクト: うまくいけば終わりはない(継続される)
- アジャイルをするなアジャイルになれ
- チームマスタリー
- ウォーターフォール と アジャイルは 見る対象自体が違う
- 比較するの事に意味があるのか?(似たもの同士ではない)
- アジャイルは経営理論に近い考え方
- what に対する学習, how に対する学習
- 暗黙知を形式知 にする
- リーンとは贅肉を削ぎ落としたという意味
- チームに権限委譲する
- AよりもBを重視しよう -> A はいらなくないよ
- いらないと曲解されがちである
- 通信不確実性を減らすには...
- 大人数よりも少人数
- リスペクト
- 不確実性の3種類
- 方法不確実性
- 目的不確実性
- 通信不確実性
- 情報の非対称性
- 多点見積もり
- 偏差が大きい順に不安度が高い
- 優先順位を上げる
- エージェンシースラック
- 目的不確実性
- 何を作るか?が不明瞭
- 動作可能なプロトタイプを最も安価な方法で作り、早期に動作を確認してもらう
- データベースの詳細な設計は後回し
- データベースの設計を見て仕様変更を指示されないから
- 仕様変更があるか?確認を後回しにしない。
- ユーザストーリー
- どのような人が
- 何ができる
- そのことでどのような感情になる
- ユースケース図との違いは「感情」が絡む
- 検証とは
- 仮説を構成する不確実性のうち最も大きなものを最も安いコストで削減する
- 小さなコストで検証し失敗したら別の仮説をたてる -> 繰り返して仮説検証を成立させる
- 高価値、高リスクのものほど「早く安く」実現する
- インセプションデッキ
- whyを明らかにする
- howを明らかにする
- デリゲーションポーカー
- 権限の委譲には7つの段階がある
- 技術的負債の4象限
- 意図的な
- 無意識の
- 慎重な
- 無鉄砲な
- 「綺麗さ」と「速さ」は交換可能だが...
- ソースコードが汚くて遅い人もいれば、綺麗で速い人も多くいる
- 要求に対して綺麗さと速さを意識する事は不可能では?
- 見える/見えないの軸, プラスの価値/マイナスの価値の軸がある
- 見える+: 新機能
- 見えない+: アーキテクチャ
- 見える-: バグ
- 見えない-: 技術的負債
- 技術的負債の定量化
- 技術的負債のポイント
- エンジニアと経営者の認識の差
- システムの複雑性の増加そのものではない
- 情報の非対称性の解消は「コミュニケーション」そのもの
- システム外注における取引コスト
- 探索のコスト: クオリティの高い技術者を探すのは困難
- 交渉のコスト: 契約条件を整える
- 監督のコスト: 品質を監督しクオリティの維持をチェック
- 結局コストがよりかかるので内製化が進む
- 機能横断チーム
- 地理的に近い配置
- 十分な権限委譲
- 心理的安全性の高さ
- 目的の透明性
- 様々な職種のメンバーが1つの目的のために集まる
- 機能別組織
- 特定の職種の人を集める
- ビジネス上の競合が特定分野に限定されればこれの方が良い
- 知の探索
- 機能横断型組織による組み合わせを考える
- 新しいビジネス分野を開拓していくための活動
- 知の深化
- 機能別組織によって行われるような特定の領域の効率を上げる
- 注意が必要: 勝ち筋が見えると特定領域のみを考えるようになってしまう
- コンピテンシートラップ
- バランスを見る必要がある
- 全体で見れば利益になっていない事がありがち
- 誤解された目標管理
- 目標による管理
- 心理学の成果を取り入れる事で生み出されたもの
- ノルマとは本質的に違う
- ピーター・ドラッガーの本にも書いてある
- 本来の 目標による管理 の目的
- 目標設定による主体性向上
- モチベーションアップ
- 問題解決能力の向上
- セルフコントロール
- 従業員自らが設定し
- 従業員が納得して達成に臨む
- モチベーションの内的動機付けを重視
- 目標はなるべく定量化する
- 定量化すると達成できたか出来ないかを判断しやすくなる
- 透明性を重視した
- 何をもって達成できたか?を明確にした
- 情報公開する
- 情報非対称性, 限定合理性を減らしていく