
2025.02.12
職員一人あたり52時間の残業削減に成功 kintone導入がもたらした富士吉田市の自治体DX“変革”ハウツー
リンクをコピー
記事をブックマーク
koic氏:コンテクストとして、なぜ必要かというところをまず書きます。CHANGELOGを辿るまで、まず何をすればいいかわからないと、もうけっこう致命的なんですけど。
実装ポイントとしても次のような話をします。どんなキーワード引数を使えばよいかというところ、それからメリットとして、ユーザーのアップグレードでの痛みは減らせますよといったような話。
そして実例ですよね。「Beforeがいきなりエラーになる。AfterはもうこのAPIは非推奨なので、新しいキーワード、これに置き換えるとよい」と。自分で言うのもなにですが、「非推奨警告かくあるべきみたい」という感じで、キチンとやったんですよ。
コードのdiffとしては、基本的な部分は、こうした旧APIをデフォルト引数で取っています。そのデフォルト引数のところに、何か値が変わって入ってたら、そこで警告を出すみたいな。なので、キーワード引数も、キチンと受け入れるというところですね。
これはRuby 2.5で、ERBのインターフェースが実はちょっと変わっているので、そのへんのところをヒントにした実装なんですが、そうした実装をちょっと入れています。legacy_sourceとして元の引数でも受け入れるようにして、legacy_sourceが渡された場合は警告を表示して、その値を優先して使うというの入れています。それを125API分やるんですよ。
(会場笑)
どういう意味かというと、メソッド名があるじゃないですか。引数名があるじゃないですか。引数の数もあって、デフォルト値もあって、警告文も1個1個違うのを125個ですよ。
たぶん人間には難しいので、セルフレビューする気も起きません。こういうときに僕は、RuboCopという使い慣れたツールを使います。
何をしたかというと、この非推奨警告のパッチを送るにあたって、まずキーワード引数に変わる前のFakerのコミットハッシュを手に入れて、そのFakerの手元のリポジトリをそのバージョンにrevertして、それを今度はFaker 2に移行用のツールに自分のCopを作って、そこにauto-correctするCopを作って、それを適用して送ったんです。
こうした流れのなかで、auto-correctするCopについて話そうと思います。Copのおさらいを少しすると、RuboCopって、期待していないスタイルのコードを期待しているコードに自動修正する機能が入っています。そうしたCopは、RuboCopが提供しているAPIなどを使えばオリジナルで作れます。
このコードを発掘したんですけど、みなさんお忘れかもしれませんが、Rubyって、オブジェクト指向“スクリプト”言語Rubyです。Webを書くためだけに使われる言語ではないんですよ。
何を言い訳したいかというと、ローカルリポジトリで書きなぐったものを今年の夏ぐらいに発掘したんですが、だいぶスクリプト感いっぱいですね。なんか書きなぐってRubyキメてとりあえずみたいなの。
とりあえず全部出します。量もあったので、どんなことをしたかというところを、ちょっと雰囲気でお伝えしますね。
僕が最初にやるときって、だいたい最初に期待を書くんですよ。「これが悪いコードというか期待していないコードで、これが期待しているコードです」という差分。今回だとこれが差分です。このようになればいい。このあとにテストコードも書いて実装に入っていくんですが、今回は割愛しています。
バッドケースを捉える実装例として、今回はメソッドの定義部分、引数の並びの定義のところをやりたかったので、on_defでメソッド定義のdefでひっかけて、そのノードに対する処理を書きました。
RuboCopは、これ親クラスにした中でついてくるadd_offenceにまで呼び出しがあると警告が出るんです。ここまでいったら警告が出るので、警告しない、ガード条件みたいなものを入れているんですね。ここって。
node、まあdefで渡された引数argumentsが全部〇〇unlessなんですが、ここに出てくるkwarg_typeやkwoptarg_typeが、ここにあるdef do_something……です。このruby-parseというコマンドは、parser gemをインストールすると一緒にインストールされます。
RuboCopはparser gemに依存します。そのparser gemはRubyのコードをS式で返すgemなんですが、ここでどういうノードがこのdef do_something(foo:, bar: 1)とすれば返ってくるかというと、こういうS式なんですね。
ここで、「foo:の値なし」と「bar:の値あり」だと、返ってくる値が違うんです。これ最初、僕は片方しか書いていなくて、バグっていました。こういったところは、条件に応じていればキチンとパスすると部分なんですけどね。
実装においては、このようにして警告する対象を見つけるのですが、対象を見つけたら、それを自動修正するためのAPIが別にあります。RuboCopにはautocorrectというメソッドがあって、それをoverrideするとコールバックされるつくりになっています。いればキチンとパスすると部分なんですけどね。
ここでnodeから引っ張ってきているキーワード、すなわち、あるnodeを引っ張ってきて、それの引数が1というところですね。第1引数、第2引数、第3引数と。このへんは、警告の文字列を組み立てるのに使ったりしています。
今度は、長いので何ページかにわたるんですが、下位互換のための変数をこの「legacy_もともとのオリジナルの引数名」で足して組み合わせます。
これはどのクラスのAPIを使ったら警告を出すという処理で、そのクラスの定義を追うのに、Rubyって何重にもネストをかけていますよね。RuboCopでは、僕は再帰処理をよく使うのですが、これも再帰処理を使っていいます。親をたどってクラスノードになるまでひたすらたどるという処理です。たどったらそれを返してclass_nameとして取っています。
これは自動修正コードの部分。ヒアドキュメントですね。ヒアドキュメントの中で置換する文字列を組み立てているわけです。
最後にこのautocorrectメソッドの中。lambdaで書けるんですが、このlambdaでcorrectorというブロック変数をとったオブジェクトに対して、insert_beforeと呼び出しています。何をしているかというと、”#{legacy_argument} = NOT_GIVEN, “が、このパッチの下に書いてある引数を追加した自動修正コードなんです。
こちらが警告条件のところ、conditionのところを足すという、autocorrectが適用されているところなんですよ。
というところで、このかたちで一応ではあるんですがPull Requestを出して、Mergeいただいた。「おマージいただいた」んですよ。
でもそれで作っておしまいではないじゃないですか、ソフトウェアって。ユーザーの反応があるわけで、「推奨警告の量が半端なくて大変だったよ」というふうにまとめて言われて、「せやなぁ」っていう。
(会場笑)
フィードバックに対してのKPT(振り返り)として、よかったこと・考えたこと・これから考えることということを、ちょっと僕なりに考えたんです。
よかったこととしては、推奨警告。僕の作ったコードが活用されたって、すごくいいことですよね。書いて終わりじゃないですから。ただよくないのは、やはり125以上の破壊的変更を直撃するとつらそうで、僕がやったわけではないんですが、やはりつらそうだなというところ。
(会場笑)
そこを緩和するのに自動修正可能なツールを提供すれば、アップグレードをより楽にできるかなと。ユーザー側のコードを自動修正できるとよいのではと思って作ったのがrubocop-fakerだったんです。
一芸は開発を加速する。これはRuboCopの開発などで身につけた能力ですが、いろいろほかの知識ともひもづいていて、以前RSpec 2からRSpec 3に移行するときには、Transpecというものがあって、それに似た何かが作れると便利なのかなとか考えました。
あとは、先ほど話した、Fakerに非推奨警告を入れるPull Requestを作る過程で、ついでにこのgemを作ってたいような気がしています。似たようなものなので、うろ覚えなんですが。
やっているのは、こういうgemです。Before・After上のほうにあると、Faker::Avatar.imageで、普通の positional argumentを適用するとキーワード引数に変わるというもの。
こういうのを作ったんですが、実装としては似たようなものなので、ちょっと1回割愛というかたちにしたいのです。けれどもここで、ちょっと1つポイントがあります。このgemは、僕が作ったんですが、たぶん作っただけだとなんとなく使われないなと思いました。パッチ会でもお世話になっている松田さんの、僕の中の名言なんですけど、「gemは作っただけで勝手に広まるわけではなくて、使われるためのひと工夫が必要」という言葉。これがパッと頭をよぎって、じゃあこれどうするかなと。
少し似たもので、「64パーセント」という数字があります。だいぶ昔の数字ではあるんですが。これはライブラリではなくて、アプリケーションですね。アプリケーションでは、作っても使われない機能が64パーセントあると。gemも似たようなものではないかと。作ったけれども使われないって、けっこうなんかアレなので、こうした課題を自分なりに、作ったあとももっていいます。
ならば、この課題に対して最強の宣伝方法は、upstreamに取り込んでもらうことです。これがFakerの#1724です。
これが何かというと、警告としてauto-correctできるよというものを出す、警告というか説明を出すというものです。でもそれってそもそも僕がオリジナルで考えたものというよりは、factory_botという、gemのアップグレードの際にauto-correctを使うことでRuboCopの移行をスムーズにするものがあり、それにちょっとインスパイアされて作ったものです。
そこで、こうしたかたちで解決策として、そのgemを使うとよいよというところで・・・。Before/Afterですね。
Beforeだと、positional argumentをkeyword argumentに変えましょうという警告だけだったのを、さらにその警告をコピペできるように書いてあります。このRuboCopの、--require rubocop-faker only……そのFaker gemが唯一持ってるAPIです。auto-correctすると移行ができるよというやつです。ユーザーとしてもメリットがあります。
心配だった点が、やはりありました。僕が個人で作ったFakerのorganizationではないものへ依存していいのかというところです。そのあたりは、キチンと説明すればMergeしてもらえて。「おマージ」いただきました。
ただこれも、その後がまだあります。Fakerの課題#1692です。「引数1個の場合、kwargsはやりすぎじゃね?」って。まぁ「せやなぁ」という感じなんですが、困ったことに、いやこれにいいねとかいいねとか……「いいね」じゃないんですよ!これ、変えちゃいけないんですよ!
(会場笑)
僕は、Fakerの例えば「2.いくつ」で、またそれをやるんだったら非推奨警告を出して、消すんだったらまたそうやるとか警告を立てないとかいうふうに一応出して…。ここで今止まっているので、続きはGitHubでという感じなのですが、なにかこのあたりに興味ある方、いらっしゃればまた何かコメントいただいて、そのあたりディスカッションできればと思います。
そもそもキーワードかポジショナルか、どちらがよいかというところも、どこまで議論されたかよくわかりません。そうしたところの参加もできると思います。
まとめます。破壊的変更というのは、やはり、最初から弱点のない設計にするのは難しいです。悪くしようなんて誰も思っていなくて、よくするために破壊的変更するときがあります。
僕らアプリケーション側としては、やはりいきなり大きく壊れると、いろいろなものに影響し、問題の仕分けがよくわからなくなります。ですから小さくリプレースをするという意味でも、gemのアップデートをこまめにやっていくと、変更範囲も少なく、原因の特定までも早いです。これをわりとやっていくといいのではないかと思います。
そして、そのへんのライブラリ、Railsもライブラリですから、それも含めてバージョンアップするのが非常に重要です。自分や周りは、例えばRails 4のプロジェクトをやりたいとかRails 6のプロジェクトをやりたいとか、プロジェクトの性質にもよると思うのですが、Railsだけで判断すると「どっちですか?」という話があると思うんです。
僕は、この場にいる人の中で古いほうのバージョンを選ぶ人はいないと思って勝手に話していますが、新しいバージョンを使うというのはすごいです。なんて言うんですか、未来にキチンと残して価値になるものなので、そうしたバージョン越えというのは、やっていけるといいと思います。
ふだんから、そのアプリケーションをバージョンアップするというところもそうですし、今話したようにオープンソースというかたちのところに何か関わることによって、もしかすると不必要だったかもしれない破壊的変更を止められるかもしれません。例えば正規表現のmatchのnil渡しのところだとか・・・。そういった破壊的変更でのダメージの緩和、例えば非推奨警告をキチンと入れておきましょう。事前になにかコメントをつけるとか、独自でなにかやるとか。
手元の非推奨警告を見るところは、手始めにやれると思います。そうしたところからやっていきましょう。とくに今回Ruby 2.7で警告が入るRuby 3のキーワード引数の分離などは、かなり大きな変更だと思います。ちょっと先の長い話ですが、2020年末ですから1年後です。みんなでうまくRuby 3へのアップグレード自慢などをしていけるといいと思っています。
最後になりますが、そのコミュニティというところで、今回Rubyコミュニティである「平成Ruby会議」だったわけですが、コミュニティへの参加の仕方も、いろいろ多様にあると思います。
今回はその中の1つにしか過ぎないかもしれませんが、それはとても大きなものです。例えばコードを書いて何かをやるとかコードの世界でディスカッションするといった参加方法です。来年もRubyKaigi 2020があるので、そこでそういったコード、そして自分たちが自慢できるような何かを一緒に話せればよいと思います。
ご清聴ありがとうございました。また来年のRubyKaigiでお会いしましょう。
(会場拍手)
2025.02.13
“最近の新人は報連相をしない”という、管理職の他責思考 部下に対する「NG指示」から見る、認識のズレを防ぐコツ
2025.02.06
すかいらーく創業者が、社長を辞めて75歳で再起業したわけ “あえて長居させるコーヒー店”の経営に込めるこだわり
2025.02.13
AIを使いこなせない人が直面する本当の課題 元マッキンゼー・赤羽雄二氏が“英語の情報”を追い続ける理由
2025.02.12
マネージャーは「プレイング3割」が適切 チームの業績を上げるためのマネジメントと業務の比率
2025.02.12
何度言っても変わらない人への指示のポイント 相手が主体的に動き出す“お願い”の仕方
2025.02.13
「みんなで決めたから」を言い訳にして仲良しクラブで終わる組織 インパクトも多様性も両立させるソース原理
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
2025.02.10
32歳で「すかいらーく」を創業、75歳で「高倉町珈琲」で再起業 「失敗したからすかいらーくができた」横川竟氏流の経営哲学
2025.02.14
報連相ができない部下に対するコミュニケーションの取り方 「部下が悪い」で終わらせない、管理職のスキル向上のポイント
2025.02.10
A4用紙を持ち歩いて殴り書きでアウトプット コクヨのワークスタイルコンサルタントが語る、2種類のメモ術
着想から2か月でローンチ!爆速で新規事業を立ち上げる方法
2025.01.21 - 2025.01.21
新人の報連相スキルはマネージメントで引きあげろ!~管理職の「他責思考」を排除~
2025.01.29 - 2025.01.29
【手放すTALK LIVE#45】人と組織のポテンシャルが継承されるソース原理 ~人と組織のポテンシャルが花開く「ソース原理」とは~
2024.12.09 - 2024.12.09
『これで採用はうまくいく』著者が語る、今こそ採用担当に届けたい「口説く」力のすべて
2024.11.29 - 2024.11.29
【著者来館】『成果を上げるプレイングマネジャーは「これ」をやらない』出版記念イベント!
2025.01.10 - 2025.01.10