TECH PLAY

株式会社ラクス

株式会社ラクス の技術ブログ

935

こんにちは、配配メール開発エンジニアのhiro_jiです。 突然ですが、負荷テストの進め方ってイメージできますか? ある程度経験があれば難なく進めることができると思いますが、そうでない場合はそもそも進め方のイメージが湧きづらいかと思います。 かくいう私も最初は何から手を付ければよいか分からなかった記憶があります。。。 そこで今回は負荷テスト初心者の方向けに、私の所属するチームで実施している手順を紹介します! 負荷テストとは? 負荷テストのフロー 全体像 方針検討 詳細計画 テスト準備 テスト実施 評価 分析・チューニング おわりに 負荷テストとは? 本題に入る前に、負荷テストとは何かについて軽く触れておきます。 負荷テストとは、特定の条件下でシステムやアプリが示す性能を評価、検証するものであり、運用中の障害を未然に防いだり、パフォーマンスの問題や ボトルネック を改善するために非常に重要な役割を持ちます。 負荷テストには、性能要件を満たしているか検証するための「ロードテスト」や、限界値を特定するための「ストレステスト」など、目的や観点に応じて様々な手法があり、計測方法や分析する指標がそれぞれが異なります。 (テスト手法の名称に関してはサービスや会社によってまちまちなようですが、本記事ではそれらの総称を「負荷テスト」として扱います) 本記事ではそれぞれの手法については触れませんが、「スムーズにテストを進める方法」という観点で参考になれば幸いです。 負荷テストのフロー 全体像 負荷テストフロー 私たちのチームではいくつかの工程に分けてテストを進めていて、 工程ごとにレビューを挟むことで余計な手戻り作業を削減しています。 方針検討 このフェーズでは以下のようなことを決めます。 テストを行う背景や目的 性能要件を満たしているかを確認したい?それともシステム限界値まで特定したい? どのような指標で評価するか 応答時間 エラー率 スループット サーバリソースの使用量 評価対象とする機能や処理の範囲 など ここの方針がずれていると、 無駄な作業や大幅なやり直し につながってしまいます。 例えば、限界値を特定したかったのに性能要件の範囲までの負荷しかかけれていなかったり、ある SQL の性能だけを計測したいのに機能全体も性能を計測したり... 効率的に進めるためにも、最低限上記のような内容は早い段階で明確にしておきましょう。 詳細計画 ここでは方針検討で決めた内容を元により詳細な内容を決めます。具体的には 、 使用する環境やサーバ構成 負荷の量 同時ユーザー数 リク エス ト数 レコード数やファイルサイズ エビデンス として残す情報 処理時間だけでよいのか?サーバリソースの状況も取得するのか? 操作手順(負荷をかけるシナリオ) 使用ツール 評価基準 などなど 決めることは多いですが、ここが曖昧だと実は想定する負荷をかけれていなかったなんてことになりかねないので、可能な限り詳細に記載することが大切です。 随分過去の話ですが、DBに用意するレコードに関してレコード数自体は想定通りだけど、その内訳に関して計画担当とデータ準備担当間で認識齟齬が生じていしまい、テストのやりなおしが発生したことがありました。 特にデータ量などを記載する際は、 数値だけでなくその数値とした根拠や内訳も明確に記載 し、チーム内の認識を合わせましょう。 テスト準備 詳細計画で決めた内容に沿って必要な環境、データや スクリプト などを準備します。 テスト用の環境 テストシナリオ DBに登録するレコードやリク エス トなどのデータ 負荷の計測用 スクリプト やツール 詳細計画に沿ってテスト準備をするだけといえばそれまでですが、個人的にはここが一番時間がかかるフェーズだと思います。 対象機能の理解や大量データの作成方法など、ある程度の前提知識やコツが求められることが多いです。詰まったら迷わずチーム内の 有識者 に聞いちゃいましょう。 また、次回以降の テストの効率と再現性向上のため に、データ作成や計測用に作成した スクリプト はどこかに残しておくことをおススメします。 テスト実施 準備ができたらいよいよテスト実施です。 テストの内容にもよりますが、大量データを扱う場合などは色々と注意が必要になります。 私たちのチームではトラブルや手戻りを未然に防ぐために、以下のような内容をチェックリスト化し、テスト実施前に毎回確認しています。 使用する環境が正しいか 共用の環境を利用する場合、事前に利用することを周知できているか リソース監視対象のサーバで、余計な処理が動いていないか 計測データにノイズが入らないか 外部サービスへ大量リク エス トを送るようなことはないか 送る必要がある場合は、許可を得ているか テスト手順が適切か 負荷テストはその性質上、他のテストに比べて様々なリスクがあります。 いきなり本番テストを行うのではなく、 まずはミニマムで実施する ことでテストの妥当性を確認しましょう。 評価 計測した結果が、詳細計画で決めた基準を満たしているかどうかを明確にします。 単純にOK、NGだけ記載するのではなく、その評価に至った根拠や補足情報を記載し、 結果の妥当性を示すこと が大切です。例えばサーバリソース(LAやメモリ)に関して、瞬間的な値のみで判断するのと、連続的な値も含めて判断するのとでは、大きく意味合いが異なると思います。 分析・チューニング 評価、分析の結果、基準を満たさない場合はアプリの改修もしくはインフラ側の拡張を検討する必要があります。 いきなりアプリ改修やインフラ側の拡張に走ってしまうと、全く改善効果が得られず無駄な対応に時間をかけてしまったなんてことになりかねません。 まずは ボトルネック の特定から進めることがチューニングの一番の近道です。 おわりに 本記事では私のチームで実践している負荷テスト手順についてご紹介させていただきまいた。 負荷テストと聞くと身構えてしまう方もいる多いかもしれませんが、 段階的にチーム内で認識を合わせて進める ことができていれば、なんてことないと思います。 今回は進めかたという点に絞ってご紹介しましたが、次回は具体的に使用している負荷計測ツールや分析方法についても紹介できればと思います!
アバター
概要 Prometheus未経験の非インフラエンジニアが、Grafanaでサー バモ ニタリングができるようになるまでの 軌跡を記録します。 とりあえず、モニタリングができることが目標なので運用面の考慮等はしていませんが、参考になれば幸 いです。 概要 きっかけ Prometheusとは Grafanaとは 今回構築する環境の構成 ①prometheus server ②exporter ③Grafana インストール 前提条件 ②exporterのインストール (1)ソースをダウンロード (2)ダウンロードしたソースを解凍する (3)node_exporterを起動する (4)node_exporterの起動確認 ①prometheus serverのインストール (1)ソースをダウンロード (2)ダウンロードしたソースを解凍する (3)Prometheusの設定ファイルを編集する (4)prometheus serverを起動する ③Grafanaのインストール (1)Grafanaのインストール (2)grafana-serverの起動と起動確認をする (3)Grafanaにブラウザでアクセスする (4)Data Sourceの設定 (5)dashboardの設定 やってよかったこと まとめ きっかけ 検証環境のとあるサーバが突然死しました。 なぜ死んだのかは分かりませんでした。 というのも、OSと必要最低限の ミドルウェア をインストールしただけのサーバだったのです。 これは良くないなと思い、サーバをモニタリングしたいなと思いました。 sysstatとか使えば良いのかもしれませんが、せっかくなのでPrometheusを使ってみることにしました。 Prometheusとは システムおよびサービスのモニタリングシステムです。 設定されたターゲットから定期的にデータを収集して 蓄積 可視化(Prometheusでの可視化は、今回は触れません) アラートの通知(今回は触れません) を行うことが可能です。 Grafanaとは Grafanaは、様々なデータソースから取得したデータを可視化するツールです。 Prometheus自体でも可視化は可能ですが、 アドホック な立ち位置で利用されるものだそうです。 可視化には、Grafanaを使うよう公式サイトに記載されています。 今回構築する環境の構成 ①prometheus server いわゆるPrometheusと呼ばれるものです(だと思っています)。 ②exporter 監視エージェントです(だと思っています)。 取得したい情報に応じて、exporterをインストールします。 主なexporterは、 Prometheusのマニュアル に記載されています。 ①prometheus server  は、  ②exporter  に対して定期的に情報を取得しに行き、データを蓄積します。 ③Grafana ③Grafana  は、  ①prometheus server  からデータを取得し、可視化を行います。 インストール 順番は前後しますが、 ②exporter ①prometheus server ③Grafana の順番でインストールします。 前提条件 OS: AlmaLinux 8.8 ②exporterのインストール 今回は、サーバの状況が知りたいので、 node_exporter をインストールします。 (1)ソースをダウンロード Prometheusのダウンロードページ のリンクから  node_exporter-1.7.0. linux - amd64 .tar.gz  をダウンロードしました。 wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz (2)ダウンロードしたソースを解凍する tar xzvf node_exporter-1.7.0.linux-amd64.tar.gz (3)node_exporterを起動する cd node_exporter-1.7.0.linux-amd64 ./node_exporter (4)node_exporterの起動確認 node_exporterが起動していることを確認します。 node_exporterのポート番号 9100 exporterのエンドポイント /metrics コマンド curl -s http://localhost:9100/metrics 実行結果 # HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 3.0043e-05 go_gc_duration_seconds{quantile="0.25"} 4.12e-05 go_gc_duration_seconds{quantile="0.5"} 4.6299e-05 ・ ・ ・ ①prometheus serverのインストール (1)ソースをダウンロード Prometheusのダウンロードページ のリンクから  prometheus-2.45.2. linux - amd64 .tar.gz  をダウンロードしました。 # wget https://github.com/prometheus/prometheus/releases/download/v2.45.2/prometheus-2.45.2.linux-amd64.tar.gz (2)ダウンロードしたソースを解凍する tar xzvf prometheus-2.45.2.linux-amd64.tar.gz (3)Prometheusの設定ファイルを編集する cd prometheus-2.45.2.linux-amd64 vi prometheus.yml prometheus.yml  の末尾に  node_exporter  の情報を追記します。 - job_name : "node_exporter" static_configs : - targets : [ "localhost:9100" ] (4)prometheus serverを起動する ./prometheus --config.file=prometheus.yml ③Grafanaのインストール Grafanaは、 cloud on-premises Enterprise OSS エディションがありますが、今回はon-premisesの OSS をインストールします。 (1)Grafanaのインストール GrafanaのOSSダウンロードページ を開き Red Hat, CentOS, RHEL, and Fedora  のコマンドを実行します。 今回は以下のコマンドを実行しました。 sudo dnf install -y https://dl.grafana.com/oss/release/grafana-10.3.1-1.x86_64.rpm (2)grafana-serverの起動と起動確認をする sudo systemctl start grafana-server sudo systemctl status grafana-server (3)Grafanaにブラウザでアクセスする http://<IPアドレス>:3000  にアクセスします。 Email or username admin Password admin でログインできます。 ※初回ログイン時にパスワードの変更を求められます。  Skipも可能です。 (4)Data Sourceの設定 画面左上のトグルメニューから Home Connections Data sources を選択します。 +Add new data source  をクリックして  Prometheus  を選択します。 Name: 任意の名前 HTTP Prometheus server URL:  http://<IPアドレス>:9090 を入力し、  Save & Test  をクリックします。 (5) dashboard の設定 Grafanaの dashboard の設定ですが、 テンプレート が公開されています。 今回は、 Node Exporter Full を使わせていただきました。 画面右上の +  をクリックして  Import dashboard  を選択します。 先程エクスポートしたテンプレートをアップロードします。 Options Name: 任意の名前 Unique identifier(UID): 任意の値 Prometheus: 先程追加した  data source  を選択 を設定し、 Import  をクリックします。 表示される ダッシュ ボードの一部ですが、テンプレートを取り込むだけで簡単にモニタリングが出来ています。 キャプチャには入っていませんが、 ディスク使用量 ディスクIO ロードアベレージ 等もグラフ化されています。 やってよかったこと サーバのモニタリングができるようになった 結構簡単にできた インストールが簡単 ダッシュ ボードの設定もテンプレートを利用するだけ 拡張性が高いことがわかった exporterを追加することで、別のモニタリングも可能 対象サーバの追加も容易にできそう ディスク枯渇を事前に検知できた 日々ディスク使用量が増加していることが分かった 作業ファイルの削除漏れを見つけ、定期的に削除するようにした 実行するJobの数を調整した メモリ使用量を確認し適切な実行数となるよう調整した まとめ 環境構築からモニタリングを行えるところまでを紹介しました。 今回は、1サーバで1項目だけのモニタリングを紹介しましたが、対象サーバやモニタリング項目の追加も 容易に行えますので、気になる方はぜひ試して頂ければと思います。
アバター
はじめに こんにちは。フロントエンド開発課に所属している新卒1年目のm_you_sanと申します。 今回はissue formsを使って GitHub Issuesのテンプレートを作成する方法について、紹介したいと思います。 はじめに issue formsとは?導入するメリットは? 作り方 まとめ issue formsとは?導入するメリットは? issue formsは、 GitHub 上で提供される GitHub Issuesに入力フォームを追加する機能です。 GitHub Issuesでは、デフォルトで大きめのテキストエリアが1つ提供されていますが、そのまま運用すると以下のような問題が起こります。 具体的に何を書いて良いのかわからない 人によって記載粒度にばらつきがある 欲しい情報が記載されていない場合がある 上記の問題は MarkDown 形式のテンプレートでも、ある程度改善することはできますが、記入者がテンプレートを無視して自由に記載できてしまうなどの欠点があります。 一方でissue formsでテンプレートを作ることで、小項目に分けることができるので、記入者がどこに何を書けば良いのかが明確になります。 また、 MarkDown 形式のテンプレートと異なり、記入者がテンプレートを無視することができないため、記入者による書き方のばらつきが起こりにくくなります。 加えて、条件付きではありますが、issue formsでは必須項目の指定ができるので、欲しい情報を記入者に入力させることが可能です。 作り方 今回は例として、バグ報告用と改善・リファクタ用のテンプレートを作成します。 まずプロジェクト直下に .github/ISSUE_TEMPLATE/ を作成し、その下に yaml ファイルを置きます。 //ディレクトリ構成 . ├── .github │ └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── enhancement_request.yml │ ├── config.yml : 次に bug_report.yml を編集します。 # bug_report.yml name : バグ報告 description : 不具合報告はこちら title : 'Bug: ' body : - type : textarea id : overview attributes : label : 概要 description : | 不具合の概要を記載してください。 見た目に関係する場合は、スクリーンショット等を貼り付けてください。 validations : required : true - type : input id : environment attributes : label : 再現環境 description : | 再現環境を記載してください。 例: Chrome + Windows Edge + Windows Chrome + macOS Safari + macOS validations : required : true - type : textarea id : process attributes : label : 再現手順 description : 不具合を再現させる手順を記載してください。 value : | 1. 2. 3. ... validations : required : true - type : textarea id : supplement attributes : label : 補足 キーの詳細は以下の通りです。 キー 説明 必須 name テンプレートの名前。一意である必要があります。 〇 description テンプレートの説明。名前の下に表示されます。 〇 title タイトルに事前に入力されているテキスト。 × body フォーム全体の内容。 〇 type フォームの要素。 checkboxes、dropdown、input、 markdown 、textareaの中から指定できます。 〇 id フォーム要素の識別子。フォーム定義内では一意である必要があります。 × attributes フォーム要素のプロパティを定義するキーと値のペア。 〇 label フォームのラベル。 〇 description フォームの説明。ラベルの下に表示されます。 × value 事前にフォームに入力されているテキスト。 × validations フォームのバリデーションを定義するキーと値のペア。 × required trueにすると入力必須になります。 public リポジトリ の場合のみ有効になります。 × 同じように enhancement_request.yml も編集します。 # enhancement_request.yml name : 改善・リファクタ description : 改善・リファクタはこちら body : - type : textarea id : background attributes : label : 背景 description : どのような課題を抱えてissueを立てたのか、経緯や前提を記載してください。 validations : required : true - type : textarea id : merit attributes : label : メリット description : 改善することでどのようなメリットがあるのかを記載してください。 validations : required : true - type : textarea id : do attributes : label : やること description : このissueで取り組むことを記載してください。 validations : required : true - type : textarea id : supplement attributes : label : 補足 最後に config.yml を編集します。 この config.yml は、新しくissueを作成する際に表示されるテンプレート選択画面をカスタマイズするためのファイルです。 今回は blank_issues_enabled をfalseにすることで、issue formsで作成したテンプレートのみを選択できるようにしています。 # config.yml blank_issues_enabled : false push後、画面を確認して以下のようになっていれば完成です。 テンプレート選択画面 バグ報告用テンプレート 改善・リファクタ用テンプレート まとめ 今回は、issue formsで GitHub issuesのテンプレートを作成する方法について紹介させていただきました。 私が所属しているチームでは、実際にissue formsを運用しているのですが、デフォルトのテンプレートを使っていたときに比べて、issueの管理がしやすくなったので、気になった方は是非試してみてください。 参考資料 docs.github.com docs.github.com
アバター
ラク スでは多くの SaaS プロダクトを開発・運用しており、オンプレミスまたは クラウド を適切に選択してインフラ基盤を構築しています。 そのインフラを担うのが、 ラク スのインフラ開発部です。 今回はインフラ開発部のマネージャーが厳選した、インフラエンジニアにおすすめの書籍10選をご紹介します。 それぞれの書籍に推薦コメントを記載していますので、是非ご参考になさってください。 選定基準は以下の通りで、今後インフラを深く理解し実力をつけていきたい方にも最適です。是非ご覧ください。 「すぐに役に立つがすぐに廃れる知識ではなく、10年以上使える書籍」 「分かりやすい本ではなく、難解ではあるがきちんと原理・原則を学べる書籍」 目次 目次 Operating Systemを理解しよう 詳解 Linuxカーネル 第3版 DNS & BIND 第5版 トラブルシューティングを理解しよう 詳解 システム・パフォーマンス 第2版 パケットキャプチャ入門 LANアナライザWireshark活用術 第4版 分散システムを理解しよう 分散システム 第二版 Google File System セキュリティを理解しよう AWSではじめるクラウドセキュリティ: クラウドで学ぶセキュリティ設計/実装 体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践 思考力を高めよう 失敗の科学 失敗から学習する組織、学習できない組織 なぜあの人の解決策はいつもうまくいくのか? おわりに Operating Systemを理解しよう 詳解 Linux カーネル 第3版 Daniel P. Bovet (著), Marco Cesati (著), 高橋 浩和 (監修, 読み手), 杉田 由美子 (翻訳), 清水 正明 (翻訳), 高杉 昌督 (翻訳), 平松 雅巳 (翻訳), 安井 隆宏 (翻訳) インフラ技術の基本知識である Linux Kernelの本質を学び取れる一冊。Kernelはどんな機能を持ち、管理、処理しているのか。OSコア機能であるKernelを知ることはインフラエンジニアとしての基本的素養といえます。 DNS & BIND 第5版 Cricket Liu (著), Paul Albitz (著), 小柏 伸夫 (翻訳) DNS に関係する機能全般の詳細解説書です。OS内部でも外部でも名前解決技術は深く広く利用されている。名前解決技術を抑えることはOSのみならずシステム全般の理解を深めることとイコール。 トラブルシューティング を理解しよう 詳解 システム・パフォーマンス 第2版 Brendan Gregg (著), 西脇 靖紘 (監修), 長尾 高弘 (翻訳) インフラだけではなく、SREでも求められるシステムレスポンスについての知識、調査、分析方法を網羅的に記載している良書です。 システムがスローダウンし原因不明の際には必ず目を通したい一冊。 パケットキャプチャ入門 LANアナライザ Wireshark 活用術 第4版 ネットワークパケット解析ツール Wireshark の利用法が記載されています。ネットワークありきのシステム運用においてトラブル解決にパケット取得、分析スキルは必須です。 tcpdump だけではなく wireshark を用いることで迅速かつより明快に分析が可能になります。 分散システムを理解しよう 分散システム 第二版 アンドリュー・S・タネンバウム (著), マールティ ン・ファン・ス ティー ン (著), Andrew S. Tanenbaum (著), Maarten van Steen (著), 水野 忠則 (翻訳), 佐藤 文明 (翻訳), 鈴木 健二 (翻訳), 竹中 友哉 (翻訳), 西山 智 (翻訳), 峰野 博史 (翻訳), 宮西 洋太郎 (翻訳) PublicCloudでは分散システムの利用が容易に可能になっていますが、これをオンプレで実現するためには分散システムの全体像、構成する機能群を学びとる必要があります。 自前のPrivateCloud構築、運用に対応できる知識をこの書籍で身につけることができます。 Google File System Sanjay Ghemawat, Howard Gobioff, and Shun-Tak Leung(著) 分散システムを体現したシステムでもあり、分散システムのコアシステムである Google File Systemの理解を深めることで分散システムを実践的に学び取ることが出来ます。難解に見えますが、 アメリ カの大学にて分散システムを扱う際の教材にもなっています。 https://web.mit.edu/6.033/www/papers/gfs-sosp2003.pdf セキュリティを理解しよう AWS ではじめる クラウド セキュリティ: クラウド で学ぶセキュリティ設計/実装 松本 照吾 (著), 桐谷 彰一 (著), 畠中 亮 (著), 前田 駿介 (著) AWS を題材にセキュリティの基本を学べる書籍で、「 クラウド における特徴ポイント」を学び取ることができます。 AWS はrootアカウントの設定に不備があると、乗っ取りや不正利用の被害にあい、数百万の利用料金を請求されるケースも多発しています。基礎 からし っかり学んでおく必要があります。 体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性 が生まれる原理と対策の実践 徳丸 浩 (著) インフラ基盤だけではなく、アプリケーションの設計、実装不備によっても外部侵入は起こりえます。インフラエンジニアだからアプリ側の知識は不要というわけではなく、少なくとも設計時に指摘ができる程度の知識を身につけておくことは必要です。   思考力を高めよう 失敗の科学 失敗から学習する組織、学習できない組織 マシュー・サイド (著), 有枝 春 (翻訳) エンジニアリングにおいて設計、テスト、運用、あらゆる場面に失敗は紛れ込みます。その失敗にどう対処すべきか、他業種事例からも学び取れる一冊。 なぜ失敗するのか、なぜ失敗から学ぶ必要があるのかを具体例を挙げて記載している良書です。 なぜあの人の解決策はいつもうまくいくのか? 枝廣 淳子 (著), 小田 理一郎 (著) システム思考+問題解決を扱った書籍です。 ロジカルシンキング は一つの事象を一時点でスナップショットし、分析、比較します。しかし、実際のシステムはいくつもの事象の集合体であり、時間軸によっても変化していきます。システム思考を身につけることで一つの事象だけではなく、全体、フローの概念を加えてさらに高い次元で問題解決できる思考力を身につけることができます。 おわりに 今回は、原理原則をしっかり学ぶことができ、10年先にも活かせる知識が身につく書籍を中心に紹介しました。 ラク スでの実務体系や利用技術に沿って「Operating System」、「 トラブルシューティング 」、「分散システム」、「セキュリティ」の知識、そして「思考力」を高めるラインナップとなっていますので、通して読んでいただくことでインフラエンジニアとしての実力をバランスよく高められるのではないかと思います。 是非手にとっていただき、都度立ち返ってみていただければ幸いです。
アバター
はじめに こんにちは、Hiropyです。 今回は、 Java のComparatorについて簡単に解説できればと思います。 はじめに Comparatorとは? compareメソッドの使用方法 使用例 Comparableとの違い 主なメソッド comparing reversed naturalOrder・reverseOrder nullsFirst・nullsLast thenComparing まとめ Comparatorとは? Comparator は、「比較者」という和訳の通り オブジェクト同士の比較 を行うインタフェースで、主にList等の ソート (並べかえ)に使われます。 型パラメータTを持つ 関数型インタフェース で、抽象メソッドの compare (T o1, T o2)を実装することで大小比較ができるようになります。 後述する通り便利なメソッドが複数あり、毎回compareを実装する必要がないこともポイントです。 ※この記事には関数型インタフェースや ラムダ式 が特に説明なく登場します。よくわからない方はまずそちらから調べてみてください。 compareメソッドの使用方法 compare (T o1, T o2)は、 o1が小さい(ソートしたとき先に並ぶ)ときは返り値が負に、o1が大きい(後に並ぶ)ときは正に、等しいときは0 になるように実装します。 例えば、String型を文字数で比較(短いほうを「小さい」と判定)したい場合、実装は以下のようになります。 // s1のほうが短いときはs1.length() < s2.length()なので負の値を返す、s1のほうが長いときはその逆で正を返す Comparator<String> stringComparator = (String s1, String s2) -> s1.length() - s2.length(); より複雑な実装も可能です。 以下のComparator は、heightが小さいほうを「小さい」と判定し、heightが同じ場合は、weightが大きい方を「小さい」と判定する一風変わったものです。 class Person { public int height; public int weight; } Comparator<Person> personComparator = (p1, p2) -> { if (p1.height != p2.height) { return p1.height - p2.height; } return p2.weight - p1.weight; }; 使用例 配列やリストには、Comparatorを用いたソートを行うメソッドが用意されています。 以下に代表的なものを挙げますが、基本的にソート後の並びは 昇順 (小さい順)です。 (無論ソートメソッドの実装次第で並び順が降順やその他の順になっているものも存在し得ます) 以下の例では、先程のstringComparatorを用いてList を文字数の昇順で並べ替えています。 Comparator<String> stringComparator = (String s1, String s2) -> s1.length() - s2.length(); List<String> wordList = new ArrayList<>(Arrays.asList( "Today" , "is" , "a" , "good" , "day" )); System.out.println(wordList); // >[Today, is, a, good, day] // stream().sortedは元のリストを変更せずに新しいストリームを返す List<String> sortedList = wordList.stream().sorted(stringComparator).toList(); System.out.println(sortedList); // >[a, is, day, good, Today] // List.sortは元のリストを変更する wordList.sort(stringComparator); System.out.println(wordList); // >[a, is, day, good, Today] List<String> wordList2 = new ArrayList<>(Arrays.asList( "This" , "is" , "a" , "pen" )); // Collections.sortも元のリストを変更する Collections.sort(wordList2, stringComparator); System.out.println(wordList2); // >[a, is, pen, This] もちろん、1回しか使わないときはいちいちComparator変数を定義しなくてもソートする関数の引数内に記述すればOKです。 List<String> wordList = new ArrayList<>(Arrays.asList( "Today" , "is" , "a" , "good" , "day" )); List<String> sortedList = wordList.stream().sorted((String s1, String s2) -> s1.length() - s2.length()).toList(); // >[a, is, day, good, Today] Comparableとの違い Comparatorと似た名前の比較用インタフェースとして、 Comparable が存在します。 Comparableも型パラメータTを持つ関数型インタフェースで、実装時には compareTo (T o)を実装する必要があります。 このcompareToはクラス内蔵のComparatorのようなもので、 インスタンス の比較がしたいクラスであらかじめ比較方法を実装しておくものです。 Comparableを実装したオブジェクトをソートするときにメソッドを引数なしや引数nullで呼び出すと、メソッドにもよりますがcompareToを使用した昇順ソートがなされることが多いです。 なお、compareToの比較による順序付けのことを 自然順序付け といいます。 class Person implements Comparable<Person>{ public int age; public Person( int age) { this .age = age; } @Override // thisが小さいときは負の数を、thisが大きいときは正の数を、同じときは0を返すよう実装 public int compareTo(Person p) { return this .age - p.age; } } List<Person> people = new ArrayList<>(Arrays.asList( new Person( 10 ), new Person( 30 ), new Person( 20 ))); // stream.sortedでは引数なしで呼び出す List<Person> sortedPeople = people.stream().sorted().toList(); // List.sortでは引数nullで呼び出す people.sort( null ); // いずれも[10, 20, 30] Comparableは クラス内で一度実装すれば毎回ソートの際の比較方法を書かなくていい というメリットがあります。 一方でComparatorはソート時に毎回実装するので、 同じクラスでもその場に合わせた色々な基準でソートできる ソートする場所に比較方法を書くのでパッと見て何でソートするのかわかりやすい といった点がメリットです。 両方使用して、「Comparableを実装しておいて普段は自然順序付け、特別な並べかえ方法を使いたいときはComparator」といった運用方法も可能です。 ちなみに、 JDK に含まれているメジャーなクラスにも、Comparableを実装しているクラスは以下のように複数存在します。 IntegerやDouble, BigDecimal など数値系は、数値の昇順に並ぶ Stringは、辞書順の昇順に並ぶ LocalDateTimeなどの日付時刻系は、日付時刻の昇順に並ぶ 主なメソッド 前述の通りComparatorにはcompare以外にもstatic・defaultメソッドがいくつか用意されています。 これらを使用することで、より短く、見やすいコードで比較・ソートが行えます。 comparing Comparator. comparing (Function keyExtractor)では、引数に「Comparatorを実装したオブジェクトを返すメソッド」を実装したFunctionを入れることで、そのメソッドの返り値を自然順序付けで比較するComparatorが返されます。 オブジェクトの比較は、数値型(Integer, Doubleなど)の変数やlengthなど何らかの 数値 を使って行うことが多いかと思いますが、 この際compareを実装してComparatorを作る場合は同じメソッドの呼び出しを2回書くことになるほか、「どっちからどっちを引くと昇順だっけ?」と迷うことも少なくありません。 comparingを使用するとメソッドを1回書くだけで済むので、コーディングミスを減らすことが可能です。 Comparator<String> stringComparator = Comparator.comparing(s -> s.length()); // Comparator<String> stringComparator = (String s1, String s2) -> s1.length() - s2.length(); と同じ // メソッド参照を使用するとより簡潔に書ける Comparator<String> stringComparator2 =Comparator.comparing(String::length); 数値型に限らず、例えばStringを返すメソッドを入れた場合、辞書順で比較するComparatorになります。 class Person { public String name; public Person(String name) { this .name = name; } public String getName() { return name; } } List<Person> people = new ArrayList<>(Arrays.asList( new Person( "Hinata" ), new Person( "Emily" ), new Person( "Tsubasa" ))); List<Person> sortedList = people.stream().sorted(Comparator.comparing(Person::getName)).toList(); // > [Emily, Hinata, Tsubasa] また、引数を2つ取るcomparing(Function keyExtractor, Comparator keyComparator)もあり、この場合は自然順序付けではなく第2引数のComparatorで比較します。 reversed このメソッドを呼び出したComparatorの 逆順 で判定を行うComparatorを返します。 降順 でソートしたい場合や既存のComparatorの逆順でソートしたい場合、このメソッドを使うと便利です。 List<String> wordList = new ArrayList<>(Arrays.asList( "Today" , "is" , "a" , "good" , "day" )); List<String> sortedList = wordList.stream().sorted(Comparator.comparing(String::length).reversed()).toList(); // >[Today, good, day, is, a] naturalOrder・reverseOrder Comparator. naturalOrder ()は、Comparableを実装したオブジェクトについて、自然順序付けで比較をするComparatorを返します。 Comparator. reverseOrder ()は、Comparableを実装したオブジェクトについて、自然順序付けの 逆順 で比較をするComparatorを返します。 List<Integer> numberList = new ArrayList<>(Arrays.asList( 4 , 2 , 3 , 5 , 1 )); List<Integer> naturalSortedList = numberList.stream().sorted(Comparator.naturalOrder()).toList(); // > [1, 2, 3, 4, 5] // Comparableの項で書いた通り、以下のように書いても同じ結果になる // List<Integer> naturalSortedList = numberList.stream().sorted().toList(); List<Integer> reverseSortedList = numberList.stream().sorted(Comparator.reverseOrder()).toList(); // > [5, 4, 3, 2, 1] nullsFirst・nullsLast Comparator. nullsFirst (Comparator comparator)は、nullをnull以外より小さいとみなし、両方がnull以外なら引数のcomparatorによる比較を行うComparatorを返します。 つまり、ソート時にnullが先頭に来ることになるのです。 Comparatorを実装する際に比較対象にnullが入ってくると NullPointerException が発生する場合がありますが、 List<String> wordList = new ArrayList<>(Arrays.asList( "Today" , "is" , "a" , "good" , "day" , null )); List<String> sortedList = wordList.stream().sorted(Comparator.comparing(String::length)).toList(); // > NullPointerException nullsFirstを使用することで例外発生を防ぐことができます。 List<String> wordList = new ArrayList<>(Arrays.asList( "Today" , "is" , "a" , "good" , "day" , null )); List<String> sortedList = wordList.stream().sorted(Comparator.nullsFirst(Comparator.comparing(String::length))).toList(); // > [null, a, is, day, good, Today] nullsLastはその逆で、nullをnull以外より大きいとみなす、つまりソート時にnullが末尾に来るようなComparatorを返します。 thenComparing 複数条件でソート するときに使用するメソッドです。 Comparatorの後ろにつけて引数で比較条件を指定することで、そのComparatorが0を返したときに追加の条件で比較することができます。 引数にはComparatorの他、comparingと同様FunctionやFunction+Comparatorを入れることが可能です。 以下の例では、Stringのリストを文字数の昇順で、文字数が同じものについてはStringの自然順序付け(辞書順)で並べ替えています。 List<String> wordList = new ArrayList<>(Arrays.asList( "cat" , "dog" , "apple" , "banana" , "elephant" , "ant" , "zebra" )); List<String> sortedList = wordList.stream().sorted(Comparator.comparing(String::length).thenComparing(Comparator.naturalOrder())).toList(); // > [ant, cat, dog, apple, zebra, banana, elephant] まとめ Comparatorは Java でソートを行う際に非常に重要になるインターフェースです。 Webアプリなどではそもそも SQL のORDER BYでソートしているから Java でソートをする場面は必ずしも多くないかとは思います。 とはいえ Java 側での処理の途中でソートを行う処理もあったりするので、使いかたを覚えておいて損はないでしょう。 本記事がComparator、ひいてはソートの理解に少しでも役立てれば幸いです。
アバター
新卒1年目のTKDSです! 今回は、AIコーディング支援サービスである、 Amazon CodeWhispererの導入方法について記事を書きました。 個人での利用は無償ですので、自宅などでは費用をかけずにAIコーディング支援サービスを利用できて便利でした。 Amazon CodeWhispererの情報 導入の手順 1. 最新の AWS Toolkit プラグインをVS Codeにインストール 2. 認証 3. AWS Builder IDの作成 試す まとめ Amazon CodeWhispererの情報 公式サイト https://aws.amazon.com/jp/codewhisperer/ 公式サイトのインストール情報 https://aws.amazon.com/jp/codewhisperer/resources/#Getting_started 導入の手順 今回は VS Code にCodeWhispererを導入する手順をご紹介します。 1. 最新の AWS Toolkit プラグイン を VS Code にインストール VS Code 用の AWS Toolkitのサイト https://aws.amazon.com/jp/codewhisperer/resources/#Getting_started 拡張機能 のストアを開き、インストールを選択します。 2. 認証 インストール完了すると次の画面が表示されるので、CodeWhispererを選択します。 クリックすると以下の内容が展開されます。 「 Sign up or Sign in」を選択します。 ブラウザで認証と AWS Builder IDの作成に移ります。 3. AWS Builder IDの作成 Emailを使ってBuilder IDを作成します。 登録すると、メール認証が行われ、完了すると再度 VS Code の画面に遷移します。 試す 少しだけコード補完を試してみました。 コード補完が実際に働いていることが確認できました。 まとめ 今回はCodeWhispererを導入してみました。 GitHub Copilotと比べるとやや使いにくさを感じましたが、無償と考えると十分なのではないでしょうか。 ぜひ記事をご覧になった方はお試ししてみてください。
アバター
はじめに こんにちは。フロントエンド開発課に所属している新卒1年目のm_you_sanと申します。 今回はTypeScriptのinferについて紹介したいと思います。 はじめに inferとは? 具体的な使用例 関数の戻り値の型を推論する Promiseの内部の型を推論する 配列の中身を推論する 文字列リテラルと組み合わせる まとめ inferとは? inferは 型推論 する際に使われるキーワードで、 ジェネリクス 型と条件型(Conditional Types)と合わせて使われます。 inferを使うことで、関数の戻り値や配列の中身など、 ジェネリクス 型の内容によって変化する型情報をConditional Typesの条件分岐の中で推論することができます。 具体的な使用例 関数の戻り値の型を推論する inferは組み込み型のReturnTypeの内部で実は使われています。 型変数の R が、 型推論 が行われる部分です。 下記のコードでは、 ジェネリクス 型の T が関数である場合、その戻り値の型を R として推論し、その R がReturnTypeの結果として得られます。 関数が ジェネリクス 型である場合、戻り値は文字列や数値などの様々なパターンがありますが、inferを使うことで柔軟に型情報を取得することができます。 type ReturnType < T > = T extends ( ...args: any [] ) => infer R ? R : any ; const helloFn = () => "Hello World" ; const addtion = ( num1: number , num2: number ) => num1 + num2 ; const isEvenNumber = ( num: number ) => num % 2 === 0 ; //string型になる type HelloFnReturnType = ReturnType <typeof helloFn >; //number型になる type AddtionReturnType = ReturnType <typeof addtion >; //boolean型になる type IsEvenNumberReturnType = ReturnType <typeof isEvenNumber >; Promiseの内部の型を推論する inferを使うことで、Promise型が内包している型を推論することができます。 下記のコードでは、 ジェネリクス 型の T がPromise型であった場合、Promiseの型引数の部分を R として推論して、その R がExtractPromiseの結果として得られます。 type ExtractPromise < T > = T extends Promise < infer R > ? R : never ; //string型になる type SampleStringType = ExtractPromise < Promise < string >>; //number型になる type SampleNumberType = ExtractPromise < Promise < number >>; 配列の中身を推論する inferを使うことで、配列の中身を推論することもできます。 下記のコードのFisrtは、 ジェネリクス 型の T が配列の型だった場合、その配列の先頭の要素を R として推論します。 Array1の場合、先頭の要素以外(2と3)は ...any[] となって、1のみが R として推論されるため、結果としてArray1FirstTypeは1となります。 type Fisrt < T extends any [] > = T extends [ infer R , ... any []] ? R : never ; type Array1 = [ 1 , 2 , 3 ] ; type Array2 = [ "1" , 2 , 3 ] ; //1になる type Array1FirstType = Fisrt < Array1 >; //"1"になる type Array2FirstType = Fisrt < Array2 >; 文字列 リテラル と組み合わせる inferは文字列 リテラル と組み合わせることができます。 Replaceは文字列 S に含まれる文字列 T を U に置き換える型です。 具体的な処理の流れとしては、まず初めにstring型の S に T が含まれているかをConditional Typesを用いてチェックしています。 このとき、 T の前後の文字列をそれぞれ A 、 B として推論しています。 最後に T を U に置き換えて、推論された A と B を文字列 リテラル で結合させて、結果として返します。 下記の例では、 A は「NO」、 B は「NO LIFE」になり、 T の「MONEY」が U の「CAT」に置き換わるため、結果として「NO CAT NO LIFE」が得られます。 type Replace < S extends string , T extends string , U extends string > = S extends ` ${ infer A }${ T }${ infer B } ` ? ` ${ A }${ U }${ B } ` : never ; //NO CAT NO LIFEになる type replaced = Replace < " NO MONEY NO LIFE" , "MONEY" , "CAT" >; まとめ 今回はtypescriptのinferについて紹介させていただきました。 個人的には、関数の戻り値やPromiseの型引数など、型情報が不確定なものに対しても、inferを使うことで柔軟に型情報を取得できるところが魅力的に感じました。 inferの使い方について、更に深堀したい方は type-challenges に取り組んでみるのが良いかと思います。
アバター
こんにちは。フロントエンド開発課所属の koki _matsuraです。 今回はPlaywrightの コンポーネント テストについて個人的な意見を書いています。 目次は以下の通りになっています。 はじめに 導入方法 Playwright Component Test Runner のスゴい点 コンポーネントが実際にレンダリングされる 画面のサイズを指定できる タイムゾーンや言語を指定できる コンポーネントの振る舞いを見るテストに対応できる まとめ 参考 はじめに Playwrightは Microsoft が開発・メンテナンスしているCypress、Puppeteerなどと同じE2E自動テスト フレームワーク として有名です。 playwright.dev Chromium 、Edge、 Firefox などの複数のブラウザに対応しており、全てに単一の API で簡単にテストの実装が可能になっています。 目玉機能としては、コード生成が挙げられるのではないでしょうか。 コード生成とはユーザが画面を実際に触り、それがコードとして自動で反映されていく機能で手っ取り早くテストを開始するには最適な機能です。 他にも素晴らしい機能があるのですが、その中でも現在、実験的に試されているComponent Test Runnerがとても興味をそそられました。 そこで導入方法とPlaywright Component Test Runnerの個人的に凄いと思った点を紹介していきます。 導入方法 プロジェクトのトップで下記のコマンドを実行してください。通常のPlaywright導入コマンドにオプションでctをつけたような形になっています。 npm init playwright@latest -- --ct どの フレームワーク に向けて使うのかを聞かれるので、該当するものを選択してください。今回はReact18を選択します。 次はブラウザをインストールするかを聞かれますが、デフォルト(true)にします。 これで導入が完了しました。 プロジェクトの ディレクト リには3つのファイルが追加されていると思います。以下がそれぞれの簡単な役割となっています。 playwright / index.html テストの対象となる コンポーネント を レンダリング するためのhtmlファイル playwright / index. tsx index.htmlに対して、 スタイルシート の反映、テーマの適用などをするためのファイル playwright-ct.config.ts コンポーネント テストの設定を行うファイル テスト対象 ディレクト リを設定したり、 タイムアウト の設定、テストをするブラウザの設定が可能 テストファイルを作成すれば、 npm run test-ct でテストが実行できます。 Playwright Component Test Runner のスゴい点 コンポーネント が実際に レンダリング される 昨今の コンポーネント テストでよく使われているテストランナーはVitest・Jestではないでしょうか。そして、テストランナーとともに使われるJSDomなどはNode.js環境でDOMをエミュレートするためのライブラリであり実際のブラウザに レンダリング されているわけではありません。 ブラウザと完全に同じ レンダリング になるかわからないという問題があります。 しかし、Playwrightは index.html を通して、対象の コンポーネント が実際のブラウザに レンダリング されます。 つまり、ユーザの環境に限りなく近い状態でテストが可能となります。 また、副作用的なメリットとして今まではNode.js上でDOMをエミュレートしていたため、testing-libraryやuser-eventが必要になってましたが、それも要らなくなります。 Playwright Component Test Runnerのみで基本的なテストはできます。 以下は チェックボックス のテストを例に比較したものです。 内容自体は同じですが、簡潔に書けていることがわかります。 // @playwright/experimental-ct-reactを使わない例 import { AddressForm } from "../../Checkout/AddressForm" ; import { render } from "@testing-library/react" ; import { screen } from "@testing-library/dom" ; import { it , expect } from "vitest" ; import userEvent from "@testing-library/user-event" ; import "@testing-library/jest-dom/vitest" ; it ( "チェックボックスをクリックするとcheck状態が切り替わる" , async () => { render (< AddressForm / >); const user = userEvent.setup (); const checkbox = screen.getByRole ( "checkbox" ) as HTMLInputElement ; await user.click ( checkbox ); expect ( checkbox ) .toBeChecked (); } ); // @playwright/experimental-ct-reactを使う例 import { test , expect } from "@playwright/experimental-ct-react" ; import { AddressForm } from "../../Checkout/AddressForm" ; test ( "チェックボックスをクリックするとcheck状態が切り替わる" , async ( { mount , } ) => { const component = await mount (< AddressForm / >); const checkbox = component.getByRole ( "checkbox" ); await checkbox.click (); expect ( checkbox ) .toBeChecked (); } ); 画面のサイズを指定できる コンポーネント には画面のサイズによって見た目が変わるレスポンシブなものもよくあります。 このような コンポーネント をviewportを変えてテストするようなことはあまりないと思います。 そもそも、そのようなテストをVitest・Jestでするにはwindow.innerWidthやwindow.innerHeight、そしてresizeイベントなどで実装することになり非常に困難です。 だからと言って、E2Eテストで行うには適さないため、手動で確かめることが必要とされることが多いのでないでしょうか。 Playwright Component Testはそれを解決します。 方法は以下のようにviewportを設定するだけです。 テストファイルに書けば、個々に設定でき、 playwright-ct.config.ts に書けばテスト全体に設定可能です。 import { test } from '@playwright/experimental-ct-react' ; test.use ( { viewport: { width: 1280 , height: 720 } } ); 例えば、以下のような一定の幅になるとサイドバーが ハンバーガ ーメニューになる コンポーネント があります。 この コンポーネント に対し、次のようなテストで対応します。 test.use ( { viewport: { width: 599 , height: 720 } } ); test ( 'widthが599pxの時にハンバーガーメニューになっていること' , async ( { mount } ) => { const sideMenu = await mount (< SideMenu / >); const hamburgerButton = sideMenu.getByRole ( 'button' ); await expect ( hamburgerButton ) .toBeVisible (); } ) テストを実行するとwidth: 599px、height: 720pxで レンダリング されます。 サイドバーになることを確認する場合もviewportのサイズを変えてテストするだけ大丈夫です。 また、画面サイズではなく、 iOS などの様々なデ バイス を指定したい場合も playwright-ct.config.ts から変更できます。 タイムゾーン や言語を指定できる 時間によって見た目が変わったり、ブラウザの言語設定によってテキストが変わるような コンポーネント があると思います。 以下はブラウザの言語設定によってテキストが変わるサイドバーです。 これをVitest・Jestで見た目部分のテストをするとなると非常に困難で、手動で確認したり、VRT(Visual Regresion Test)で対応することになります。 Playwrightはこれにも対応しており、先ほど同様に タイムゾーン や言語を下記のようにテストファイルに書くことで設定できます。 test.use ( { locale: "en-GB" , timezoneId: "Europe/Paris" , } ); これでブラウザの読み込み時の言語や タイムゾーン が変わるのですが、例えば、多言語対応のためにi18nextなどのライブラリを使っている場合は上手くいきません。Providerがないため、Playwrightのブラウザでは以下のような レンダリング になります。 これへの対応方法は @playwright/experimental-ct-react をインストールした際に自動で作成される playwright/index.tsx にProviderを書きます。 import { beforeMount } from '@playwright/experimental-ct-react/hooks' ; import { I18nextProvider } from 'react-i18next' ; import i18n from '../src/i18n/configs' ; beforeMount (( { App } ) => { return ( < I18nextProvider i18n = { i18n } > < App / > < /I18nextProvider > ); } ); そして、 コンポーネント テストファイル側では特に気にせず、いつも通りのテストを書くだけです。 test.use ( { viewport: { width: 600 , height: 720 } , locale: 'ja' } ); test ( 'lang="ja"の時は日本語で表示されていること' , async ( { mount } ) => { const sideMenu = await mount (< SideMenu / >); const listRoot = sideMenu.locator ( '.MuiList-root' ); const inbox = await listRoot.locator ( 'li' ) .nth ( 0 ) .innerText (); const favorite = await listRoot.locator ( 'li' ) .nth ( 1 ) .innerText (); const trash = await listRoot.locator ( 'li' ) .nth ( 2 ) .innerText (); const sent = await listRoot.locator ( 'li' ) .nth ( 3 ) .innerText (); expect ( inbox ) .toBe ( '受信トレイ' ); expect ( favorite ) .toBe ( 'お気に入り' ); expect ( trash ) .toBe ( 'ゴミ箱' ); expect ( sent ) .toBe ( '送信済み' ); } ); Playwrightのブラウザでも問題なく日本語で レンダリング されていることが確認できます。 コンポーネント の振る舞いを見るテストに対応できる PlaywrightのようなE2Eテスト フレームワーク では当然なのですが、実際のブラウザに レンダリング するという特徴が非常に強力で、例で紹介したようなVitest・Jestでは対応が困難であった 画面サイズや タイムゾーン に依存する コンポーネント のテスト や今までは仕方なく 手動で確認していたテスト 、 E2Eのような 単体テスト コードの改善 などの コンポーネント の振る舞いを見るテストに最適です。 しかし、 コンポーネント 内部のロジック面のテストにおいては今までのようにVitest・Jestで対応するのが良いと思います。 まとめ 今回はPlaywright Component Test Runnerについて個人的に凄いと思った点について軽く紹介させていただきました。 既存のPlaywrightにmount関数を組み合わせたシンプルな形でありながら、今まではPage単位だったテストをComponent単位にすることを可能にしてくれました。 Vitest・Jestと少し比較するような書き方をしてしまいましたが、どちらかのみではなく両方 を上手く使い分けることでより コンポーネント の品質を高く保てるのではないかと考えています。 また、Playwright Component Test Runnerが登場したことにより、本来Vitest・Jestがどのようなテストに取り組むべきなのかがわかってきたような気もします。 まだ実験的機能ですが、正式に公開された際には コンポーネント テストに積極的に取り込んでいきます! 最後まで読んでいただきありがとうございます。 参考 playwright.dev
アバター
皆さん、こんにちは!もしくはこんばんは! 楽楽精算プロダクトマネージャーの @wekkyyyy です。 前回は、本件の 前編 を記載させていただきました。 tech-blog.rakus.co.jp 今回は後編を記載します。 目次は以下となります。 対象読者、筆者がどういう人物か、執筆背景については、前編をご参照くださいm( )m 資料を作るときに考えていること (復習)【いざ開始】1つのアウトプットを3ステップで分けて作業する 【60点版】今一度 本当にこれだけか? なぜそうなる? その次はどうなる?を考える 【90点版】メッセージを意識する 【90点版】届ける相手を自分に憑依させる 編集後記 資料を作るときに考えていること (復習)【いざ開始】1つのアウトプットを3ステップで分けて作業する 以下の4ステップに分けて考えています。 それぞれの段階でレビューにかけます。 ★注意点 レビュー相手としては、上長はもちろんですが「自分にない・足りない視座がある人」に頼むといいと考えています。 レビューの目的は、この内容で「目的とした達成状態にできる・近づくかどうか」を見るためだからです。 自分と同じ観点でレビューを受けてもそれはただの二重チェックであり、レビューの目的にはそぐわないと考えています。 前編 では、30点版までの部分を記載しました。 今回は60点版〜です。 1. 15点版(全体の流れこんな感じ状態) 2. 30点版(一旦作りました状態) 3. 60点版(見直して熟成します状態) 4. 90点版(これで提出します状態) ※100点は、最終合意状態を指すので割愛します。 【60点版】今一度 本当にこれだけか? なぜそうなる? その次はどうなる?を考える 30点版 にて 定性的なデータを可視化した上で、 定量 情報を付与する行為を30点版で一度実行している前提です。 ここを今一度!ロジックに抜け漏れがないか確認・修正・補足をします。 資料は、1日寝かしてもう一度見ると改善点が見つかること※が多いですが、 ここをやるやらないで合意・説明の場でのスムーズさが変わると考えています。  ※ 前田 鎌利さん著 社内プレゼンの資料作成術【完全版】 にも記載があります 可視化(カスタマージャーニー等)したものを見て、つながりに対して、 `本当にこれだけ?`、`なぜそうなのか`、`その次はどうなる?`を再度確認します。 ※すみません。以下は説明のためにシンプルさを求めて書いたので精度は低いです。 【90点版】メッセージを意識する ここは題名の通りシンプルです。 正直個人差はでます。正解はないです。 しかし意識すべき部分はあります。 1. 今一度、【15点版】1に達成状態・2に達成状態・3、4がなくて5に達成状態に立ち戻りましょう。         a. 誰が・どのような状態になっていれば、この仕事は完遂されるのか? 2. どこからどこまでの情報で、誰に何を言いたいのか? 3. 全てのメッセージを集めると、1. の達成状態を得れるのか? こちらを今一度考えることを意識しています。 【90点版】届ける相手を自分に憑依させる いよいよ最後の仕上げです。 ここを意識できてるできてないでは、読み手に与える印象が格段に変わるな。と 実体験から感じています。 偉そうに色々書いていますが、私もうまくできてない時はあります。 (特にはじめましてな人相手だと確率は高い) ですが、ここは諦めることはしないように心がけています。 書き出すと細かいことは、ものすごい量があるのですが、 サマると意識している事項は以下です。 1. 誰がこのOutputを見るのか? 2. その人に伝わる言葉になっているか? 3. その人にどう動いて欲しいのか? a. その人にどの流れで理解をしてほしいか? b. その人にどこに注力して見てほしいか? c. その人の利益になる情報を与えているか? d. その人に次にどういうアクションをしてほしいのか? 編集後記 楽楽精算PdMが資料を作るときに考えていること。 というテーマで書いて見ましたが、これは、、、書くのが難しいですねw Agendaのレベルで何回も書き直しました。 最初は細かすぎてブログとして読むのはしんどいな。。。というレベルから削って削って今の形にしました。 それによる弊害としても、そもそもの私の記載内容としても、 色々と足りない部分があると思います。 そこはすみませんが、 このブログをフックに様々な書籍を読んでみてください。 このブログ内容は、様々な書籍を自身で読んで・実践して・ミックスした上で、ある程度成功できる方程式を、私なりに組み上げた内容です。 ですが、 読者のみなさまを取り巻く状況によっては、過不足あるものだと思います。 ぜひ、学習してみなさんの中での方程式を組めるようにしてください。 ありがとうございました。
アバター
考えること1: JDKのEOL 考えること2: 使用しているMW(ミドルウェア)の対応バージョン 考えること3: JDK本体の更新内容 考えること4: 性能テスト まとめ 皆さんは JDK の更新をしたことがありますでしょうか。 私はこれまでやったことはありませんでした。。 理由は単純で基本的に JDK はLTS(長期サポート)を使用し更新する機会がなかったからです。 しかし今回偶然にも JDK の更新をする機会があったので更新する際にどのようなことを考えながら実施したかを 備忘録がてらご紹介したいと思います。 考えること1: JDK のEOL 現在、主に使用されている JDK は古い順から8, 11, 17, 21だと思われます。 これらはまだEOL(End of Life)を迎えておらずアップデートの対象です。 ここで Red Hat のOpenJDKのサポート期間を見てみましょう。 JDK8 JDK11 JDK17 JDK21 2026年11月 2024年10月 2027年10月 2029年12月 JDK8がそろそろEOLかと思いきやJDK11の方が早くEOLを迎えてしまいます。 これはJDK8を使用したアプリケーションが世の中に多く存在することや、 JDK8からJDK11への更新難易度が高いためと言われています。 では、最新のJDK21に更新すればOKというわけにも行きません。。これについては次で説明します。 考えること2: 使用しているMW( ミドルウェア )の対応バージョン Java は無数の フレームワーク やライブラリに支えられており開発の容易性や効率性に富んでいます。 しかし、その反面 現在はライブラリのメンテナンスが行われていないものも多く存在します。 これらが最新の JDK では動作しない可能性があります。 JDK の更新は行う際にはしっかりと各ライブラリが動作するかを確認する必要があります。 また、更新の際にはMWだけでなく静的解析ツールなども更新すべきです。 JDK の更新によって新しいコードの書き方ができるようになったりするためコード解析が正常に動作しない可能性があります。 考えること3: JDK 本体の更新内容 JDK の更新によって JDK 内部の動作に変更があり、本番コードまで影響がある場合があります。 例を上げるとすればJDK17の更新に含まれるJEP403の「 JDK 内部の強力な カプセル化 」などが挙げられます。 これによって JDK 内部の API へのアクセスが制限されるようになり一部 フレームワーク やライブラリはこの影響を受けると考えられます。 以上のような JDK の更新内容についても確認すべきです。 考えること4: 性能テスト JDK17からデフォルトの GC ( ガベージコレクション )がG1 GC に変更されました。 これを受けて主に GC の種類について検証しました。 JDK17の段階で使用できる GC は以下の通りです。 以下の GC をそれぞれ設定し性能テストを実施しチューニングを見直しました。 GC 一言説明 Serial GC シングルコア環境で主に使用する Parallel GC マルチコア環境ではJDK11までデフォルト G1 GC ヒープサイズの大きいアプリケーションに適している。JDK17からデフォルト Z GC 8MBから16TBまでのヒープサイズをサポートしている Shenandoah GC アプリケーションのスレッドと並列的に動作する GC まとめ 実際に更新に着手した際にはどこから手をつけるべきか悩むことが多いと思います。 アプリケーションの規模にもよりますが、膨大な作業を行う必要があったりもするかと思います。 今回ほぼ手探りで大規模なアプリケーションの JDK 更新を行ってみて以下のような学びがありました。 JDK のEOLを事前に確認する(JDK11のように短くなってしまう例もある) 更新を行った際のドキュメントは残しておく MWやビルドツール、静的解析ツールの更新を怠らない(EOLなMWがあると更新が難しいこともありそう) 性能テストを実行する環境があると便利(色々な種類の GC を試せた) さらっと書きましたが、実際はここに到達するまで1年以上かかってたりするので これから JDK 更新をする誰かの指針になったら幸いです。
アバター
弊社で毎月開催し、 PHP エンジニアの間で好評いただいている PHP TechCafe。 2023年4月のイベントでは「PhpStorm」について語り合いました。 弊社のメンバーが事前にまとめてきた情報にしたがって、他の参加者に意見を頂いて語り合いながら学びました。 今回はその内容についてレポートします。 「PhpStorm」を語る PhpStormとは JetBrains社とは 静的解析ツールとしての一面 最新機能 2022.3 非推奨の動的プロパティ 日時形式のプレビュー リストでの array shape の繰り返しをサポート 2023.1 3v4l.org での PHP スクラッチファイルの実行 インデックス作成中でも使用できるようになった Go to Class(クラスに移動)アクション データフロー解析に対応したデバッガー var_dump() / dd() のターミナル出力にクリック可能なパスとクラス参照を追加 新しいインスペクション ショートカット 主なコマンド 編集系 検索系 ナビゲーション 参考資料 プラグイン Marketplace Top PhpStorm Downloads Pickup 静的解析機能 他のエディタと比べて まとめ 「PhpStorm」を語る RAKUS Developers Blogには他にもPhpStormに関する記事がありますので、あわせてご覧ください。 【PhpStorm入門】基本的な使い方 PhpStormの個人的おすすめプラグイン3選 PhpStormで始めるGit生活 PhpStormとは PhpStorm はJetBrains社製の PHP 開発者に向けて設計された開発に便利な様々なツールが統合された環境、 IDE です。 公式HPにも以下のような記載があり、 PHP 開発者における大きな選択肢の一つとなっています。 PHP 開発者向けに設計された高速でスマートな IDE 以下に機能例を挙げます。 強力なコード補完/静的解析つきのエディタ 様々な リファクタリング 機能 DBクライアントサポート Gitクライアントサポート デバッガとの連携機能 JetBrains社とは JetBrains は プラハ に本社を置くソフトウェア開発企業です。 IntelliJ IDEA を筆頭に様々な言語の IDE ・ソフトウェア開発ツールの開発、販売を行っています。 PHP に注目して見ると IDE の開発だけでなく、 PHP 言語自体の開発にも貢献しており、 Nikita Popov 氏を数年雇用し PHP の開発を進めるなど PHP コミュニティへの貢献も大きいです。 PhpStormチーム 静的解析ツールとしての一面 PhpStormには強力な静的解析機能が存在します。 エディターで開かれたファイル内のコードを分析し、入力時に問題のあるコードをハイライト PHPDocを解析し引数や戻り値の型をチェック Gitコミット実行後にチェック(以前はコミット前) どの規約をチェックするのかなどを細かく設定可能 コミット時のチェックタイミングが前から後に変更されたことについては、 「コミット後だと実質プッシュ前チェック?」 「コミット前の方が個人的には良かったが、コミット内容によっては後チェックの方が良いもある」 「両タイミングでできればなお良かった」 などの意見がありました。 最新機能 ※ここで扱う最新機能は PHP TechCafe開催当時2023年4月のものとなりますのでご了承ください。 気になる最新機能をピックアップしていきます。 2022.3 https://www.jetbrains.com/ja-jp/phpstorm/whatsnew/2022-3/ 非推奨の動的プロパティ PHP8.2から非推奨警告が出るようになったことへの対応。 将来的には禁止される可能性が高いので対応していきたいです。 プロパティを追加するか #[AllowDynamicProperties] を追加するか選択できます。 <?php class EmptyClass {} $ class = new EmptyClass () ; $ class -> dynamicProperty = 'dynamicProperty' ; // ここで警告が出る 日時形式のプレビュー date()等で H``Y などの日時形式文字列を使用する時に自動補完してくれます。 言語や関数によっても形式が異なるのでマニュアルを確認しに行くことが多かったと思います。 リストでの array shape の繰り返しをサポート PHPDocの アノテーション でarray shapeを使用するとループ内で自動補完してくれます。 以前までは プラグイン を入れる必要がありました。 array shapeを書くことが明確なメリットになります。 <?php /** * @return array<string, array{post: Post}> */ function getData () : array { ... } foreach ( getData () as $ i -> $ data ) { $ data [ 'post' ] -> title ; // ここで$dataがpostというkeyがあると補完、そのvalueがPostクラスであると判断しメソッドやプロパティの補完をしてくれる } 2023.1 https://www.jetbrains.com/ja-jp/phpstorm/whatsnew/ 3v4l.org での PHP スクラッチファイルの実行 好きな PHP バージョンでス クラッチ ファイルの実行が可能になりました。 ここでは 3v4l.org について、 「完全に個人が運用しているサイトが連携されるのはすごい」 「アクセスが増えてインフラ費用がかさみそう」 「Jetbrainsはどのくらい資金提供しているのだろう」 などの話題が出ました。 インデックス作成中でも使用できるようになった Go to Class(クラスに移動)アクション ちょっとした待ち時間が減るので嬉しいです。 今後もインデックス作成中にできるアクションを増やしていく予定みたいです。 データフロー解析に対応したデバッガー xdebug ユーザは DFA デバッガ―を使用できるようになりました。 各分岐をステップ実行しなくても、実行されないコード分岐を事前に確認できます。 var_dump() / dd() のターミナル出力にクリック可能なパスとクラス参照を追加 var_dumpの出力結果から直接クラスやパス参照を出来るようになりました。 新しいインスペクション 互換性の無い戻り値の型変更 <?php class C { public function f () : int { return 1 ; } } class C0 { public function f () { // ここで警告が出て戻り値の型intを1クリックで追加出来る } } class C1 { public function f () : void { // ここで警告が出て戻り値の型を1クリックでintに変更出来る } } アサーション の置換 <?php $ this -> assertEquals ( true , $ test ) ; // 1クリックでassertTrueに変更出来る $ this -> assertEquals ( false , $ test ) ; // 1クリックでassertFalseに変更出来る ショートカット Windows / Linux : https://pleiades.io/sites/willbrains.jp/keymap/pdf/shortcut_phpstorm_windows.pdf Mac : https://pleiades.io/sites/willbrains.jp/keymap/pdf/shortcut_phpstorm_mac.pdf 「 Ctrl+E での最近使用したファイル表示をよく使う」 「 Shift+F6 でのプロパティリネームをよく使う」 など参加者の皆さんの良く使うショートカットの話題で盛り上がりました。 プロジェクトの規模や特性、はたまた個人の感性などで特別利用頻度の多いショートカットがあったりして面白いです。 個人的には汎用的なショートカットは全 IDE で統一してくれないかなと思ったりします。 主なコマンド 以下 Windows でのコマンドになっています。 編集系 説明 ショートカット コードの生成(Getter, Setter, コンストラクター など) Alt + Insert コメント化/コメント解除 Ctrl + / 自動インデント Ctrl + Alt + L 選択範囲のコードをフォーマット Ctrl + Alt + L ファイル全体をフォーマット Ctrl + Alt + Shift + L 検索系 説明 ショートカット どこでも検索 Shift2回 ファイル名で検索 Ctrl + Shift + N クラス名で検索 Ctrl + N ファイル内検索・置換 Ctrl + F / Ctrl + R プロジェクト内検索・置換 Ctrl + Shift + F / Ctrl + Shift + R 使用箇所を検索 Alt + F7 / Ctrl + F7 ナビゲーション 説明 ショートカット クラス、変数、メソッドの定義元にジャンプ Ctrl + B / Ctrl + Click 前のカーソル位置に移動 Ctrl + Alt + ⇐ 次のカーソル位置に移動 Ctrl + Alt + ⇒ 行番号を指定して移動 Ctrl + G コードブロックの最初・最後に移動 Ctrl + ] / Ctrl + [ 最近使用したファイルに切替 Ctrl + Tab 最近使用したファイルを表示 Ctrl + E 参考資料 あなたはPhpStormくんのショートカットキーを何個知っている? 【PhpStorm入門】基本的な使い方 プラグイン PhpStormには プラグイン が多くあり、公式や有志の作ったものをダウンロードすることでよりPhpStormを自分好みにより使いやすくカスタマイズできます。 Marketplace プラグイン を探してインストールすることができます。 JetBrainsスタッフのオススメPhpSrotm プラグイン やインストール数ランキングが表示されているので、人気の プラグイン が分かります。 まずWebの方でお目当ての機能を探してみてから、見つかった プラグイン をPhpStormでインストールするのがわかりやすいかもしれません。 https://plugins.jetbrains.com/phpstorm Top PhpStorm Downloads https://plugins.jetbrains.com/search?orderBy=downloads&products=phpstorm .ignore(様々な○○ignoreを管理する)やBashSupportが人気です。 他にもIdeaVimやemacsIdeasなど別エディタの操作感を再現するような プラグイン も存在します。 Markdown のように昔は プラグイン を入れて補完していたけれど現在はPhpStorm標準機能としてサポートしているというようなものも存在します。 Pickup Japanese Language Pack / 日本語言語パック PhpStormを日本語化してくれます。 Laravel Idea 有料の プラグイン です。以前は「Laravel」 プラグイン があったがメンテされておらず非推奨になりました。 Laravelを使っているとこれがないとしんどいという意見も。 有料ということもありcopilotが出てきた今は入れないという選択肢も出てくるかもしれません。 Symfony Support Symfony 用の プラグイン です。 Symfony 用の様々な追加サポートを受けられます。 PHP Annotations PHPDocの補完をサポートしてくれます。 静的解析機能 下記では一例を挙げます。 コードインスペクション コードの作成中に解析を行い、危険な箇所に対して下線で示すか、ハイライトしてくれます。解析方法は PHP ファイルをPhpStormで開くだけです。 文法の誤りをハイライトし、重要度によってハイライト部分の色が変更されるため見やすいです。重要度は個別に設定できます。 他の解析ツールを追加でインストールして使用することも可能です。 コールバックの参照 使用箇所の検索 名前変更リファクタリング 名前空間 Auto-Import(自動インポート) Optimize Imports(import文の最適化) folding for imports(import文の折りたたみ) など 静的解析ツールの導入が簡単 PHP_CodeSniffer PHPStan 他のエディタと比べて PHP の開発体験を高めるための機能が最初から備わっています コード補完 コード整形 コードインスペクション コードジャンプ 強力な検索機能 デバック Git操作 静的解析 テスト実行 DB操作 その他のエディタや IDE でも同等のことは可能ですが... 当然 PHP 専用のものではないため プラグイン を追加する必要があります 「この プラグイン おすすめだよ」であったり「これ入れるべきだよ」という意見を聞かないと勝手に気づくことができないような便利機能も数多くあります PhpStormは PHP の開発初心者でも開発体験を高めるための機能があらかじめ利用可能な状態になっています 開発しているうちに自然と便利な機能に触れることができます 初心者ほどPhpStormを使うことで開発スキルを高められる可能性があります 初心者ほど開発に必要な機能の切り分けができないのでおすすめ いきなり「有料ツールを使うのはちょっと...」と思っている方もフリートライアルがありますので是非試してみてください! 設定の共有 を行えます プロジェクトごとの設定共有 はGitを通じて可能 設定を共有することについては、 「設定ファイル(.idea)を整理して管理するのが厳しすぎる」 「共有したい設定と個人の設定が分離され切っていない」 「中にはDBの接続情報が入っていたりもする」 「検査例外・非検査例外の共有は便利」 など皆さん設定共有は試しているものの現状では中々やりきるのが厳しそうな印象でした。 まとめ PHPer御用達 IDE である PhpStorm について、イベント参加者の生の声を交えてまとめていきました。 毎日使うツールということもありたくさんの意見・コメントが出て盛り上がりました。 こんな設定があったのかこんな機能があったのかと知れるきっかけとなれば幸いです。 次はPhpStorm以外の IDE やエディタを使って PHP を開発している方の意見ももっと聞いてみたいですね。 PhpStorm使ったことない方は是非一度触ってみてください! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。
アバター
はじめに こんにちは、Hiropyです。 昨秋(2023年10月) IPA の データベーススペシャリスト 試験を受け、無事合格しました。 本記事では、私が行った対策法と軽い感想を紹介します。 はじめに データベーススペシャリスト試験とは 受験の動機 受験対策 午前対策 午後対策 問題選択について 結果 終わりに     データベーススペシャリスト 試験とは データベーススペシャリスト 試験は、 情報処理推進機構 (以下、 IPA )が行っている 情報処理技術者試験 の1つです。 名前の通りデータベースに関する専門性を問う試験で、 IPA の試験では 基本情報技術者試験 や 応用情報技術者試験 の上位に位置する、いわゆるレベル4の試験となります。 情報処理技術者試験 試験区分一覧より引用   ベンダー資格ではなく国家試験であることから、特定の製品に依存しない、設計・運用力を問う試験になっています。 問題は午前1,2(選択式)、午後1,2(記述式)の4段階で実施され、4つ全てで合格点を取ることで試験合格となります。午前1に関しては直近2年以内の 応用情報技術者試験 合格など一定の条件を満たすことによりスキップすることが可能です。 受験の動機 入社から3年余、業務でデータベースに接することが多かったのですが、設計や運用に関してはあまり触れてきませんでした。 とはいえ勉強するにも何からやれば…という状態で、国家試験の データベーススペシャリスト は一つのわかりやすい指標として興味を持っていました。 折しも私は2年前(2021年秋)に 応用情報技術者試験 に合格して以来 IPA 試験の合格から遠ざかっており、この秋を逃すと午前1の免除資格がなくなってしまう状態であったため、タイミング的にちょうどいいと思い受験を決めました。 受験対策 勉強期間: 3ヶ月・100時間程度 用いた教材(本のリンクに関しては同種の本の執筆時最新版を掲載しています) 情報処理教科書 https://www.amazon.co.jp/dp/4798179914/ 「専門知識+午後問題」の重点対策 https://www.amazon.co.jp/dp/4865752897/ 過去問道場 https://www.db-siken.com/dbkakomon.php なお、問題の傾向については私が受験した2023年秋時点のものであり、今後変更される場合があることをご了承ください。 午前対策 午前問題は選択式であることもあり、過去問から出る割合が高いです。 そのため、情報処理教科書をざっと読んだあとは「過去問道場をひたすらに解く⇔よくわからない箇所は教科書に立ち戻る」という方法で勉強していきました。 最初は分からなかった問題も繰り返し解くうちに覚えるようになっていき、最終的には正答率が8割を超える状態で試験に挑みました。 もちろん教科書の内容を理解し応用できるようになることも必要ですが、午前問題に関しては「過去問の問題と選択肢を覚えてしまう」という方法がかなり有効であると思います。これは他の IPA 試験でも通用する方法でしょう。 午後対策 午後問題は午後1,2とも長文を読みながら設計や運用に関する問題に記述式(一部選択式)で答えていく形式です。 午後1では数ページ、午後2に至っては10ページ程度にも及ぶ長文や複雑な図の中から答えを見つけていくことから、俗に「国語の試験」とも呼ばれています。 こちらは午前試験と違い過去問がそのまま出ることはありませんが、私は午後問題でも教科書を読むことより過去問を解いて解説を読むことをベースとした勉強方法を続けました。 午後はより深い知識が求められるはずだから教科書を熟読して知識をつけては?と思われるかもしれませんが、 データベーススペシャリスト 試験は求められる知識量はあまり多くなく、むしろ与えられた要件を正確に読み解いて回答を導く力が重要になってきます。 ですので、知識を増やすことよりも問題形式に慣れ、より速く正確に問題文を読み取れるようになることを優先して勉強を進めていきました。 問題選択について 午後問題は問題を選択する形式になっており、午後1は3問中2問、午後2は2問中1問を選択します。 出る分野としては、午後1は概念設計(ER図や関係 スキーマ など)と物理設計(パフォーマンスや同時制御など)、 SQL を主題とした問題が1問ずつ出題されることが多いです。 また午後2に関しては例年概念設計と物理設計が1問ずつ出るようでした。 私は過去問を見ながら「物理設計の分野は要求される知識に知らないものが多い」と感じたので、暗記することの少ない概念設計と既に業務である程度使っている SQL に的を絞って対策することにしました。 結果 合格点を大きく超える点数で無事合格することができました。 特に午後1はかなりの高得点が取れていますが、これは概念設計が2問出たことが大きかったです。 対策する分野を絞ることは問題形式に依存する諸刃の剣ではありますが、今回は吉と出ました。 終わりに 資格としてはデータベースの スペシャ リストとなったわけですが、「専門家になった」という気は全くしていません。 特に実務経験が増えたわけではないですし、知識を要求される分野を避けて対策を行いましたからね。 とはいえデータベースの設計をする際の頭の使い方は多少身についたかと思います。最近業務で設計をすることも徐々に出てきたので、できるだけ速く的確な設計ができるよう今回の受験体験を活かして頑張っていきたいです。 また、参考書は試験以外でも役立つと思うので、今回避けた物理分野の設計はまた見直しておこうと思います。   今回の合格で高度試験の午前1の免除資格が再度2年付与されたので、この期間内にまた何か合格できればいいなと考えています。情報処理安全確保支援士や システムアーキテクト 、2023年春に撃沈した ネットワークスペシャリスト あたりが候補です。今度は知識問題を避けることはできなさそうなので、じっくり取り組んでいこうと思います。
アバター
皆さんこんにちは!開発エンジニアをしているnkumaです! 最近ますます生成AI系の勢いが増しているのを感じる今日この頃です。 今回は、(1年くらい前の経験にはなりますが)ChatGPTを触り始めたくらいに躓いた経験から、 うまくいかないときに試していただきたい工夫をいくつかご紹介したいと思います。 本記事のターゲット お使いのChatGPTが素直じゃない方 なぜかChatGPTに作らせたいものが、どんどん逸れていってしまう方 など ※ChatGPTや シェルスクリプト といった言葉は知っている初心者を対象といたします。 そのため、そういった言葉の定義や解説は当記事では触れないのでご了承ください。 本記事のターゲット はじめに 知りたかったコツ4個 ⓵ 段階的に飲み込ませる ② パーツごとに作成してもらい、組み合わせるのは自分でやる ③ 入力データを用意して、読み込ませる ④ 都度、途中経過のファイルを出力する Before/After のスクリプト例 最後に はじめに 職場で、こんなお話を耳にしました。 昔は「パソコンが使えないおじさん」という揶揄がありましたが、 今は「AIがつかえないおじさん」でしょうね…。 胸に刺さりました。。確かにそうですよね。 ということで、「AIがつかえないおじさん」にならないようガンガン使っていこうと考えています。 ある時、丁度仕事で、とある大量の CSV データの重複を消しつつ、加工するということをする機会がありました。 早速ChatGPTにお願いして、 シェルスクリプト を書いてもらい楽をする、、予定だったのですが、 上手くいかないことこの上なし。 気づけばChatGPTの調教に時間をかけすぎていて、自分で書いた方が早かったじゃないかと感じました。 そういった経験を通して、自分が躓いたこと、気づいたことを、この記事で簡単にまとめようと思います。 技術的な内容は薄いので、どちらかといえば非技術者向けかもしれません。 とはいえ、改めて足元を確認する意義もあるかと思います。是非お気軽にお読みください。 知りたかったコツ4個 なぜか、うまくいかない悪い例: [1] CSV データの中から、列Aが"条件A"を満たす行を取り出して、列BをXXXに変更し、新しい CSV ファイルに保存するプログラムを書いてください。 ⓵ 段階的に飲み込ませる 悪い例:一気に複雑なタスクを要求している 良い例:段階的に飲み込ませている [1] 列Aが"条件A"を満たす行だけを取り出すようにしてください。 [2] 加えて、列BをXXXに変更してください。 [3] それを 新しい CSV ファイルに保存するようにしてください。 悪い例のように一気に複雑で具体的なタスクを指示すると、ChatGPTは思わぬものを出してくることが多いです。 また、なによりエラーが発生した際に原因の特定が難しくなります。 良い例のようにお願いしたいタスクを小さなステップに分け、段階的に依頼するようにしてください。 上記の例はまだシンプルなので悪い例でも意図したものが作成できるかもしれませんが、 実際に使いたいものは自分で考えるのが面倒になるくらいなので、もっと複雑かと思います。 そんな場合こそ、この工夫が役立ちます。 一気に依頼してするよりも、できる限り細かく分解して依頼していった方が、結果的に早く作成できることが多いです。 ② パーツごとに作成してもらい、組み合わせるのは自分でやる 悪い例:一気に全体の作業を依頼している 良い例:作りたいものをパーツごとに分けて作成してもらい、組み合わせるのは自分でやっている [1] CSV データの中から、列Aが"条件A"を満たす行だけ取り出す スクリプト を教えてください。 ---------------------------------------------------------------------------------- [1] CSV データの中から、列BをXXXに変更する スクリプト を教えてください。 ---------------------------------------------------------------------------------- [1] CSV データの中から、出力内容を新しい CSV ファイルに保存する スクリプト を教えてください。 ---------------------------------------------------------------------------------- ※最後に手元で、上記の スクリプト を組み合わせて利用する もっとよい方法は、組み合わせるのは自分でやることです。 1つ1つを頼むときは意図した動きができているのに、結合する際に意図しない スクリプト になってしまうのは 往々にしてあるかと思います。 であれば、パーツはお願いして、合わせるのは自分でやった方が早いというのが自分の結論です。 少し知識がないと難しいかもしれませんが、意図が分からないコードがあれば、「以下を解説して」 + 当該コードでChatGPTに頼むと詳細に解説してくれます。 それを駆使して、意図を理解しつつ、組み合わせてみましょう。 意図を理解すればまた他のものにも活かせますし!   ③ 入力データを用意して、読み込ませる 悪い例:入力データがない 良い例:入力データを用意して、読み込ませている [1] 以下のような CSV データから、国語の点数が"100"となる行を取り出して、名前列をXXXに変更し、新しい CSV ファイルに保存するプログラムを書いてください。 名前,クラス,国語の点数,数学の点数,英語の点数 太郎,A,85,90,78 花子,B,75,82,88 二郎,C,100,78,85 幸子,A,88,85,90 三郎,C,80,92,78 簡易的なもの、一部だけでもよいので、入力するデータを用意できると、ChatGPTが動作を理解しやすく、 より意図したものが作成できるかと思います。 入力データがない場合、思っていた挙動と微妙な部分で異なっていたり、実際に使ったときに、 思わぬバグを生んでしまいがちです。 調整が手間となってしまうので、多少時間がかかっても最初に具体的なデータを用意することをお勧めします。 実際のデータが使えないのであれば、ChatGPTに要件を言って作成を依頼するのが良いです! ④ 都度、途中経過のファイルを出力する 悪い例:完成版のファイルのみしか出力させない 良い例:都度、途中経過のファイルを出力する [1] CSV データの中から、列Aが"条件A"を満たす行だけを取り出したものを、step1. csv として保存してください。 [2] step1. csv から、列BをXXXに変更したものを、`step2_output. csv `として保存してください。 途中経過のファイルを出力することで、どこまで意図したものができているか、どこから狂いだしたのかを、 より具体的に把握することができます。 完成版のファイルのみでは、どこでうまくいかなくなったのか調査するのにとても手間がかかります。 途中経過を確認することで、どのステップで問題が発生しているかを特定しやすくなります。 また、途中経過のファイルは、部分的な修正の際の デバッグ や検証においても役立ちます。 例のようなそこまで複雑でない スクリプト や、細かいステップごとに出す必要はないと思いますが、 中間 セーブポイント を作る意識で出力するとよいかもしれません。 Before/After の スクリプト 例 Before: [1] CSV データの中から、列Aが"条件A"を満たす行を取り出して、列BをXXXに変更し、新しい CSV ファイルに保存するプログラムを書いてください。 After: [1] 以下のような CSV データから、列Aが"条件A"を満たす行だけ取り出したものを、step1. csv として保存してください。 名前,クラス,国語の点数,数学の点数,英語の点数 太郎,A,85,90,78 花子,B,75,82,88 二郎,C,100,78,85 幸子,A,88,85,90 三郎,C,80,92,78 ---------------------------------------------------------------------------------- [1] 以下のような CSV データから、列BをXXXに変更したものを、step2. csv として保存してください。。 ※step1. csv の中身 ---------------------------------------------------------------------------------- ※最後に手元で、上記の スクリプト を組み合わせて利用する 最後に 今回は私の経験上こうした方がうまくいっているといった工夫をお伝えしましたが、 これだけが正しいとは思いません。 日頃、皆さんがどのようなことを工夫・意識して、ChatGPTと絡んでいるのかが気になります。 そのため、方々で発信していただけるのを期待しております! また、書く上で色々検証してて思いましたが、もうエンジニアじゃなくても簡単なプログラムなら組める時代ですね。。 どう書くかはAIにお任せして、何を書くかの方を磨いていく必要があるのかなあとしみじみ。。 どちらにせよAIを活用していきたいので、作らせる技術は磨いていきたいです。 皆さんもどんどん活用していきましょう!この記事が、その一助になれれば幸いです!
アバター
はじめに こんにちは、新卒1年目のTKDSです。 今回はgitについて調べました! gitはよく使われている バージョン管理システム で、記事をご覧の皆さんも使ったことがあるのではないでしょうか? この記事では、diffコマンドのケース別の使い方について実際に試しながらご紹介します。 はじめに git diffとは? 準備 add前の変更の差分 特定のコミットとadd前の変更との変更 特定のブランチと現在のブランチの状態の比較 コミット間の変更 ブランチ間の変更 まとめ git diffとは? gitにおいて、管理しているファイルの変更の差分が見れるのがdiffコマンドです。 gitの日本語リファレンスによると、 ワークツリーとインデックスまたはツリー間の変更、インデックスとツリー間の変更、2つのツリー間の変更、マージによる変更、2つの ブロブ オブジェクト間の変更、またはディスク上の2つのファイル間の変更を表示します。 と記述されています。 今回は一部のケースを紹介します。 準備 では、実際に ディレクト リとファイルを作ってコマンドを試していきましょう。 まず、コマンドを試すための準備をします。 $ mkdir git-diff $ cd git-diff $ git init $ touch a.txt $ git add a.txt $ git commit -m " add a.txt " $ git switch -c diff-1 $ echo " change file. " > a.txt これで準備は完了しました。 次項から、ケースごとにコマンドを紹介します。 add前の変更の差分 図のように単純にファイルを変更した場合は、オプションなしのdiffコマンドで差分が確認できます。 $ git diff 次項のために、変更を反映しておきましょう。 $ git add -A $ git commit -m " 2. change file. " 特定のコミットとadd前の変更との変更 次はコミットとdiffの差分を出します。 まず変更を加えます。 $ echo " 変更と特定のコミットを比較する " >> a.txt 次にコミットのIDを調べます。 $ git log commit 94d83c65c55c14008ec9af90abbf827ab572cf46 ( HEAD - > diff-1 ) Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Thu Aug 24 23:12:39 2023 + 0900 2 . change file. commit c963cd1fa1f8748eff9ce4a78684fb2d6a0b12ed ( main ) Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Thu Aug 24 22:31:48 2023 + 0900 add a.txt それぞれのコミットと差分を比べてみますしょう。 $ git diff 94d83c65c55c14008ec9af90abbf827ab572cf46 diff --git a/a.txt b/a.txt index 9720d84..1e0a356 100644 --- a/a.txt +++ b/a.txt @@ -1 + 1 , 2 @@ change file. +変更と特定のコミットを比較する $ git diff c963cd1fa1f8748eff9ce4a78684fb2d6a0b12ed diff --git a/a.txt b/a.txt index e69de29..1e0a356 100644 --- a/a.txt +++ b/a.txt @@ -0 , 0 + 1 , 2 @@ +change file. +変更と特定のコミットを比較する このように、git diffにコミットIDを追記することで、特定のコミットとの差分を取ることができます。 今回した変更を追加しておきましょう。 $ git add -A $ git commit -m " diff-1: change file. " [ diff -1 17b9f12 ] diff-1: change file. 1 file changed, 1 insertion ( + ) 特定のブランチと現在のブランチの状態の比較 ファイルに変更を加えます。 echo " ファイルに変更を加えます。 " >> a.txt ではmainブランチとの差分をとってみましょう。 mainブランチでのファイルの中身は空です。 git diff の引数にmainブランチを指定します。 $ git diff main diff --git a/a.txt b/a.txt index e69de29..65005f7 100644 --- a/a.txt +++ b/a.txt @@ -0 , 0 + 1 , 3 @@ +change file. +変更と特定のコミットを比較する +ファイルに変更を加えます。 これで、mainブランチとの差分を見ることができました。 また、addした内容を除いて、今いるブランチとの差分がみたい場合は --staged をつけることで、差分が確認できます。 git diff --staged main diff --git a/a.txt b/a.txt index e69de29..1e0a356 100644 --- a/a.txt +++ b/a.txt @@ -0 , 0 + 1 , 2 @@ +change file. +変更と特定のコミットを比較する 今回した変更を追加しておきましょう。 $ git add -A $ git commit -m " diff-1: change file. " コミット間の変更 次はcommitとcommitの差分を比較します。 diff-1ブランチに戻ります。 $ git switch diff-1 ログを見て今までのコミット履歴を確認します。 $ git log commit 03bbf93929733a4c59aba01f019f3518dad5757d ( HEAD - > diff-1 ) Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Fri Aug 25 09:35:23 2023 + 0900 diff-1: change file. commit 17b9f127dad5fd9a69d5a0e33deb30cb0e1da8ba Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Fri Aug 25 09:18:38 2023 + 0900 diff-1: change file. commit 94d83c65c55c14008ec9af90abbf827ab572cf46 Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Thu Aug 24 23:12:39 2023 + 0900 2 . change file. commit c963cd1fa1f8748eff9ce4a78684fb2d6a0b12ed ( main ) Author: shun.takeda < shun.takeda@rakus.co.jp > Date: Thu Aug 24 22:31:48 2023 + 0900 add a.txt 引数にコミットIDを指定して差分を比較してみましょう。 $ git diff 03bbf93929733a4c59aba01f019f3518dad5757d 94d83c65c55c14008ec9af90abbf827ab572cf46 diff --git a/a.txt b/a.txt index 65005f7..9720d84 100644 --- a/a.txt +++ b/a.txt @@ -1 , 3 + 1 @@ change file. -変更と特定のコミットを比較する -ファイルに変更を加えます。 これで、コミット間の差分を確認できました。 ブランチ間の変更 次はブランチ間の差分を比較します。 mainブランチに一度戻り、新たなブランチを作成します。 $ git switch -c diff-2 次に新たなブランチで、変更をadd・commitします。 $ echo " 1. 別のブランチで変更を記述 " >> b.txt $ echo " 2. 別のブランチで変更を記述 " >> b.txt $ git add -A $ git commit -m " diff-2 ファイルを追加 " [ diff -2 3c7bdda ] diff-2 ファイルを追加 1 file changed, 2 insertions ( + ) create mode 100644 b.txt 元のブランチに戻ります。 $ git switch diff-1 引数にブランチ名を指定することで、ブランチ間の差分を確認できます。 今回は、diff-1とdiff-2の差分を確認してみましょう。 git diff diff-1 diff-2 diff --git a/a.txt b/a.txt index 65005f7..e69de29 100644 --- a/a.txt +++ b/a.txt @@ -1 , 3 + 0 , 0 @@ -change file. -変更と特定のコミットを比較する -ファイルに変更を加えます。 diff --git a/b.txt b/b.txt new file mode 100644 index 0000000 ..320e7b2 --- /dev/null +++ b/b.txt @@ -0 , 0 + 1 , 2 @@ + 1 . 別のブランチで変更を記述 + 2 . 別のブランチで変更を記述 これでブランチ間の差分が確認できました。 まとめ 今回の記事では、git diffで色々な差分を確認してみました。普段よく使っているコマンドをよく知る機会になりました。他にもコマンドについても機会があれば調べてみたいと思います。 最後まで読んでいただきありがとうございました。
アバター
はじめに 新卒1年目のTKDSです! 今回は昨年社内LTで発表した内容をもとにWASMについての情報をまとめた記事を書きました。 WASMについていくつかの項目に分けて記述します。 はじめに WebAssembly(WASM)とは WASMの仕組み : 実行環境 WASMの仕組み : なぜJSより速い? ブラウザで試す WASMの事例 Google Meetの背景ぼかし Amazon Prime Video LibreOffice WebVM Postgres-wasm CRDT(yjs,Ywasm) WasmEdge+Neural Network SPIN まとめ WebAssembly(WASM)とは まず、WASMについてまとめました。 WASMの特徴は次の通りです。 ブラウザで動くバイナリコードのフォーマット(ただし、ブラウザ以外でも動く) C/C++ やRustなどの言語を コンパイル するとブラウザ上で実行可能 JavaScript と並行して動作するように設計されているため、 JavaScript と連携可能 JavaScript より動作が速い(場合が多い) WASMの仕組み : 実行環境 WASMの実行環境は、ブラウザとブラウザ外に分けられます。 どちらも コンパイル して生成したWASMのバイナリをWASM runtimeで実行します。 ブラウザではブラウザの JavaScript エンジンが実行し、ブラウザ外では、ブラウザ外でも実行できるように作られたWASM Runtimeを使用します。 WASMの実行環境 WASMの仕組み : なぜJSより速い? 解説ブログ があったので簡単に図を引用しながら説明します。この解説ブログはブラウザでの使用について解説しています。通常、 JavaScript を実行する際、下図(ブログより引用)に示すように ソースコード の解析 コンパイル +最適化 再最適化 実行 ガーベージコレクション の5つのステップを必要とします。 一方で、WebAssemblyの場合、解析・ コンパイル ・実行の3ステップで済みます。そのため、 JavaScript よりも高速であると説明していました。 ブラウザで試す 次にブラウザでWASMを簡単に試す方法を紹介します。 MDNのサイト に載っている方法です。 wasmファイルに以下の内容を記述して、 JavaScript からロードすることでWASMを使用できます。 以下の形式はWAT形式と呼ばれ、WASMを人が読めるようにしたものです。 (module (func $i (import "imports" "imported_func") (param i32)) (func (export "exported_func") i32.const 42 call $i)) サイトに載っている通りに実行すると開発者ツールのコンソールに42が出力されているのが確認できるのでぜひやってみてください。 WASMの事例 次にWASMを使用した事例やライブラリについて情報収集したのでご紹介します。 Google Meetの背景ぼかし Google Meetの背景ぼかしにはWASMが使われているそうです。解説ブログのリンクは こちら です。 WebAssembly を介してブラウザ内で実行MLモデルはCPUで動かしてるようです。 下図は解説ブログから引用したものです。 入力された画像から対象となる人以外と背景を分割するマスクを生成し、それをもとに背景をぼやけされるようです。 MLモデルの実 行基 盤になっている MediaPipe は Google Meetの他にもWasmEdgeのAI inferenceでNNモデルの推論実行環境として挙げられていたり、メルカリのブログでプロダクト開発に使用されている 事例 がありました。 WASMで 機械学習 モデルを使用する際の1つの選択肢になりそうです。 Amazon Prime Video 解説ブログの リンク です。 アプリケーションの一部をWASMに置換したことで、パフォーマンス、安定性、CPU消費量が大幅に向上し、メモリ使用量が削減されたそうです。 LibreOffice オープンソース ソフトのオフィスソフトです。 Linux デスクトップを使ったことがある人は一度は使ったことがあるのではないでしょうか? LibreOffice をWebAssemblyに移植しようと試みられているようです。 wasm版の LibreOffice のデモの リンク です。読み込んでから起動までにしばらくかかります。 起動すると以下のような画面になります。 基本的な操作はできるようですが、動きがもっさりしている、日本語を使用できないなど使いづらさがあります。 しかし、Officeソフトがとくにインストールを必要とせず動くのは素晴らしいと感じました。 build手順 ドキュメント github WebVM ブラウザで実行できる仮想の Linux 環境です。 紹介記事の リンク です。 簡単に内容を要約します。 VM の実行エンジンにはCheerpXというものを使っています。 特徴として以下の点があります。 IndexedDBにファイルの変更などを保存して永続化→変更を自分のブラウザに保持 ファイルシステム に Ext2 を使用 Linux syscallをエミュレート可能 UIはXterm.js 色々なパッケージがインストール済みであり、使用可能 デモページの リンク があり、実行するとWasmファイルをダウンロードしてきて、ブラウザで実行されます。 起動すると以下の画面が表示されます。 コマンドなどの実行も可能です。 Postgres-wasm postgresql のWASM実装です。 デモページの リンク です。 起動すると以下の画面が表示され、 SQL が実行可能です。 テーブルの作成、データの追加・削除・検索などができます。 少し SQL の動作を確認したい時などは便利そうです。 CRDT(yjs,Ywasm) 共同編集機能のためのライブラリである yjs のRust実装のy-crdtのWASM bindingです。 リンクは こちら です。 ブラウザで内容を同期させるなど重そうな処理はまさにWASMの使い所なのではないでしょうか。 WasmEdge+Neural Network Wasm RuntimeのひとつであるWasmEdgeについてです。 WASI-NNを使用することにより、外部ライブラリを用いて、 ニューラルネットワーク による推論をWASMで実行可能なようです。 ドキュメントと ソースコード を少し読んだ感じでは、推論自体は外部のライブラリに任せているようでした。そのため、推論のパフォーマンスは外部ライブラリに依存しそうです。 ドキュメント では、llama2などの実行(ggml)や、その他の外部ライブラリ(Pytorch,OpenVINO,Tensorflow Lite)の使用方法も掲載されていました。 サンプルプロジェクト がたくさんあったので、ぜひお試しください。 ドキュメントのサンプルだと、Pytorchバックエンドの場合、依存するlibtorchがcpu版だったのが疑問点です。 ggmlの項だと自動でCUDAを探すと記述があるので、 Please note, the installer from WasmEdge 0.13.5 will detect CUDA automatically. If CUDA is detected, the installer will always attempt to install a CUDA-enabled version of the plug -in. PytorchでもCUDAによって GPU が使用可能になる方法があるのでしょうか? せっかくなので、 GPU で動かせるとNNの性能を引き出せるのでいずれやり方を調べてみたいです。 SPIN WebAssemblyを使用してマイクロサービスを構築する フレームワーク です。 リンクは こちら です。 Wasm runtimeにはWasmtimeを使用しているようです。 ドキュメントに チュートリアル がいくつかあるため、取り組んでみると使い方がわかると思います。 まとめ 今回は、WASMについての情報をまとめました。 個人的な感想としては、ブラウザ外での利用であるWasmEdge,spinに興味を持ちました。いずれ触ってみてまた記事にしたいです。 読んでいただいた方もぜひWASMを試してみてください。 ここまで読んでいただきありがとうございました。
アバター
皆さん、こんにちは!もしくはこんばんは! 楽楽精算プロダクトマネージャーの @wekkyyyy です。 前回は「楽楽精算のPRD(製品要求仕様書) Agenda」というテーマで記事をかかせていただきました。 tech-blog.rakus.co.jp 今回は趣向を変えて、「資料を作るときに考えていること」 いわゆる ドキュメンテーション スキルについて書いていこうと思います。 目次は以下となります。 対象読者 筆者がどんな人物か なぜこれを書いたのか 注意点 資料を作るときに考えていること 【まずやる】仕事と作業を分けて優先度をつける 【いざ開始】1つのアウトプットを3ステップで分けて作業する 【15点版】1に達成状態・2に達成状態・3、4がなくて5に達成状態 【15点版】Agendaとざっくり内容でストーリーをつくる 【30点版】納得感をどうやって実現させるか考える 続きは後編へ... 対象読者 ドキュメントを作成し、人に説明義務が発生する方 特に以下のドキュメントを作成する方 課題解決において 誰かを説得するための資料 何かを合意するための資料 筆者がどんな人物か 以下の通り PjMをやり始めてから ドキュメンテーション の重要性を知ることになり、 ゴリゴリに鍛えてもらいました。 (当時の同僚・先輩・上司に感謝です) インフラエンジニア(ネットワーク) 6年 このころはゴリゴリのエンジニア PjM/Director 4年 ここから業務の仕組み化に着手しだす 元コンサルの同僚/上司に ドキュメンテーション についてしごかれまくる 毎週役員の時間を15分だけもらい、その時間で説明・質疑応答・合意できなければいけなくなる PdM 4年 ドキュメンテーション 能力がないとまったく成り立たない役割になる (会社によって異なりますが筆者はその環境でした) なぜこれを書いたのか 弊社のshibaが書いた記事  楽楽精算PdMのオンボーディングと実践したこと  にて以下の記載がありました。 「お、これは俺のことだな。んならいっちょ私の知識をちょっと共有したろ。」 という完全に上から目線ムーブを かます ためです。 嘘です。本当に勉強になって成長に寄与できるなら共有しようと思っただけです。 (もう何も言っても無駄な気がしてきました) ブログにしたのは、「楽楽精算のPdMは、こんなこと考えて仕事してます!こんな人がいます!」 ということを未来の同僚に対してもお伝えしたかったからです。 (これはプラスにもマイナスにもなり得るのでビクビクしてます) 注意点 本内容は、万物のドキュメントにあてはまるものではないと考えています。 「今自分が取り掛かっているものにハマるか?」は、ご自身でご確認をお願いいたします m( )m 資料を作るときに考えていること 【まずやる】仕事と作業を分けて優先度をつける 基本的は、「仕事」になるものを優先度をあげて行っています。 時間がかかるものですし、作業は仕事の合間にこなすことができると考えるためです。 ※仕事・作業の中でも優先順位は、プロダクト インパク トだったり、上司からの緊急だったりと様々あると思うので、ご自身で操作してください。 - 仕事:その結果によって誰かに価値を届けるための活動 →めっちゃ頭使う。 - 作業:事前に定められた手続きとゴールに向けて行う活動 →ある程度は、脳死でできる。 【いざ開始】1つのアウトプットを3ステップで分けて作業する 以下の4ステップに分けて考えています。 それぞれの段階でレビューにかけます。 1. 15点版(全体の流れこんな感じ状態) 2. 30点版(一旦作りました状態) 3. 60点版(見直して熟成します状態) 4. 90点版(これで提出します状態) ※100点は、最終合意状態を指すので割愛します。 【15点版】1に達成状態・2に達成状態・3、4がなくて5に達成状態 ここから各点数版での細かい話に移ります。 とにもかくにもまずは、達成状態を決めます。 誰が・どのような状態になっていれば、この仕事は完遂されるのか? 自分の言葉でまとめられない限り、後続は進めなくていいと考えているくらいです。 【15点版】Agendaとざっくり内容でストーリーをつくる 決めた達成状態に対して、以下を検討し全体のストーリーを作成します。 「どんなことを説明・証明する必要があるか?」 「どんな流れで説明するとわかりやすいか?」 ここで完璧なもの作ろうとはしてないです。 なるべく完璧にできるといいですが、ドキュメントを作りながら変えることも多いです。 「ん〜こんなことは説明しないと伝わらないよな〜。」くらいの気持ちで大丈夫と言い聞かせてます。 筆者がよく使うストーリーとしては、以下です。 この流れで上記のことを考えて、書くことを箇条書きにしておきます。 ものによって細かく分けたりしますが、考え方として参考にしてください。 1. 現状把握 a. 現状を解像度高くわかるようにする 2. 創案 a. いわゆる解決案を出す 3. 評価 a. 解決案を評価する 4. 選択 a. 解決案を絞る 【30点版】納得感をどうやって実現させるか考える 上記の 現状把握 ・ 創案 ・ 評価 ・ 選択 に当てはめて記載します。 それぞれのフェーズでの要素を記載していきます。 こちらも筆者のよく考える思考を書いているだけなので、 対応する課題内容、すでに把握している情報、社内状況によって変動しますので一例とさせてください。 現状把握 定性・ 定量 セット で状況を把握する (Factが重要!!) 定量 データ システムログ DB アンケート結果など 定性データ インタビュー結果 VoCなど 定性的なデータを 可視化 した上で、 定量 情報を付与する ユーザーストーリー マッピング ・カスタマージャーニーマップを利用することが多い 誰の目線なのか?を意識する( MECE 意識※) 「なぜ?」「それでどうなる?」を繰り返すことでマップがつながる( MECE 意識※) 数値の変化もあるか意識する(傾向が見えるか) 1.2.の結果から課題点を可視化・ 言語化 する ※ MECE にするためのテクニックは、以下創案部分をご参照ください。  (あくまでテクニックの一部なので、他にも調べてみるとよいと思います。) 創案 現状把握で可視化・ 言語化 した課題に対して取れ得る策を洗い出す What/Howをロジックツリーで洗い出す WhatとHowのロジックツリーを分ける( MECE 意識) まず当たり前の答えを考える 当たり前の対極を考える それとそれ以外を考える ペアになるものを考える 因数分解 した結果を考える 分裂したものが、「AND」なのか「OR」なのか明確にする 評価 漏れのない評価項目をまず作る( MECE 意識) 評価項目にウェイトをつけるルール(条件)を考える(条件設定法とも言う) 必要ない評価項目は後で消すかもしれないので、どれが重要なのか明示できるようにする 評価項目内の優劣の基準を明確にする めざす方向性に対しての基準を取るようにする 筆者がよく使うのは5 or 10段階のポイント制 どの状態がどのポイントなのかを明確にする(絶対重なり合うような状態にしない) 選択 複数案出すようにする この時点では、同じ点数になることも多いと思います。 (その場合評価項目が足りていないのだと思います) ですが、そのまま関係者含め選択し、後学として選択した際の判断基準を確認するようにしましょう。 仮に同じ点数じゃないとしても、XXを重要視するならこれ等 迷う部分はあると思います。 (これも評価項目が足りてないと思われる) ですが、まだ30点版なので、思い切って出しましょう。後で削ればいいと思ってます。 続きは後編へ... 書き出したら長くなってしまいました。。。 続きは次回の後編に記載します。
アバター
はじめに こんにちは。フロントエンド開発課に所属している新卒1年目のm_you_sanと申します。 実務でZodを使う機会が多いので、基本から理解しようと思い、 チュートリアル に取り組んでみました。 今回はZodの基本について、 チュートリアル のコードを交えて解説したいと思います。 はじめに Zodとは Zodのチュートリアルについて プリミティブ型の検証(チュートリアル01) オブジェクトの検証(チュートリアル02) 配列の検証(チュートリアル03) スキーマから型を生成(チュートリアル04) オプショナル(チュートリアル05) デフォルト値を設定する(チュートリアル06) ユニオン型の検証(チュートリアル07) 特定の条件を満たしているか検証する(チュートリアル08) スキーマの拡張(チュートリアル09) バリデーション前後で値を変換する(チュートリアル10) 独自のバリデーションチェックを行う(チュートリアル11、12) 再帰的なスキーマを宣言する(チュートリアル13) ジェネリクス(チュートリアル14) まとめ Zodとは Zodとは、端的に言うとtypescriptファーストの スキーマ 宣言及びバリデーションライブラリです。 Zodはtypescriptの型システムを活用して、フォームの入力値などアプリケーションで扱うデータが、宣言した スキーマ に沿っているかを検証することができます。 また、後で解説しますが、Zodでは スキーマ から型を生成できるという便利な機能があります。 一応、同じバリエーションライブラリの Yup でも、 スキーマ から型生成は行えますが 型推論 が弱いとされています。 一方で、YupはZodと比べて API が豊富という長所があるので、お好みで使い分けると良いと思います。 Zodの チュートリアル について ここから、 チュートリアル のコードを一部抜粋しながら、Zod基本について解説します。 なお、この チュートリアル は問題のコードが与えられて、テストが通るように修正するという形式になっています(全部で14問あります)。 気になる方は、 こちら をcloneして取り組んでみてください。 プリミティブ型の検証( チュートリアル 01) 最も基本的な使い方です。 const numberParser = z. number (); export const toString = ( num: unknown ) => { const parsed = numberParser.parse ( num ); return String ( parsed ); } ; 始めにnumber型が期待される スキーマ を宣言しています。 toString関数では、引数で渡ってきたunknown型のnumをparseの引数に設定しています。 このparseは、引数に渡された値がnumberParserが期待する型、つまりnumber型であった場合は、その値を返し、そうでなかった場合はエラーを返します。 そのため、1つ目のテストではstring型の"123"がtoStringに渡されるので、エラーが返されます。 オブジェクトの検証( チュートリアル 02) オブジェクトの スキーマ を宣言する際は、z.objectを使用し、プロパティにもそれぞれ スキーマ を作成します。 チュートリアル のコードでは、 API のレスポンスが { name: string } になっているかを検証しています。 const PersonResult = z. object ( { name: z. string () } ); export const fetchStarWarsPersonName = async ( id: string ) => { const data = await fetch ( "https://www.totaltypescript.com/swapi/people/" + id + ".json" , ) .then (( res ) => res.json ()); const parsedData = PersonResult.parse ( data ); return parsedData.name ; } ; 配列の検証( チュートリアル 03) 配列の スキーマ を作成するときは、z.arrayを使用します。 チュートリアル のコードでは、 API のレスポンスが { results: { name: string }[] } の形になっているかを検証しています。 const StarWarsPerson = z. object ( { name: z. string (), } ); const StarWarsPeopleResults = z. object ( { results: z.array ( StarWarsPerson ) } ); export const fetchStarWarsPeople = async () => { const data = await fetch ( "https://www.totaltypescript.com/swapi/people.json" , ) .then (( res ) => res.json ()); const parsedData = StarWarsPeopleResults.parse ( data ); return parsedData.results ; } ; スキーマ から型を生成( チュートリアル 04) Zodでは、z.inferの型引数に スキーマ を渡すことで、その スキーマ から型を推論して、型を生成することができます。 チュートリアル のコードでは、StarWarsPeopleResultsから型を生成しているため、dataTypeの型は { results: { name: string }[] } になります。 const StarWarsPerson = z. object ( { name: z. string (), } ); const StarWarsPeopleResults = z. object ( { results: z.array ( StarWarsPerson ), } ); type dataType = z.infer <typeof StarWarsPeopleResults > この型生成は、実務でもよく使っており、フォームの入力値を検証する スキーマ から型生成し、その型を API リク エス トを送る関数の引数の型にするといったような使い方をしています。 //フォームの入力値を検証するスキーマ const PersonSchema = z. object ( { name: z. string (), hometown: z. string (), } ); type PersonSchemType = z.infer <typeof PersonSchema >; const handleSubmit = ( formData: PersonSchemType ) => { //APIリクエストなどの処理 } オプショナル( チュートリアル 05) オプショナルで スキーマ を定義する際は、optionalを使用します。 チュートリアル のコードでは、 { name: string, phoneNumber?: string } を期待する スキーマ を定義しています。 phoneNumberがオプショナルになったことで、validateFormInputにnameのみを渡したとしても、エラーが発生しなくなります。 const Form = z. object ( { name: z. string (), phoneNumber: z. string () .optional (), } ); export const validateFormInput = ( values: unknown ) => { const parsedData = Form.parse ( values ); return parsedData ; } ; デフォルト値を設定する( チュートリアル 06) スキーマ にデフォルト値を設定する場合は、defaultを使用します。 チュートリアル では、keywordsのデフォルト値に空配列を設定しています。 const Form = z. object ( { repoName: z. string (), keywords: z.array ( z. string ()) . default( [] ), } ); ユニオン型の検証( チュートリアル 07) ユニオン型の スキーマ を作成する際は、z. enum もしくはz.unionを使用します。 チュートリアル のコードでは、 privacyLevel: "private" | "public" を期待するユニオン型の スキーマ を定義しています。 テストを実行すると、privacyLevelにprivateとpublic以外の値を渡すとエラーを返すことが分かります。 このユニオン型の スキーマ 定義ですが、実務ではプルダウンメニューの項目を検証する際によく見かけます。 const Form = z. object ( { repoName: z. string (), privacyLevel: z. enum( [ "private" , "public" ] ) //↓の書き方でも可 //privacyLevel: z.union([z.literal("private"), z.literal("public")]) } ); 特定の条件を満たしているか検証する( チュートリアル 08) 最小値、最大値など特定の条件を満たしているかを検証する方法です。 この スキーマ は、nameに最低1文字、phoneNumberに5文字以上20文字以下、emailに「x@x.x」の形式、 website に「fuga:// hoge 」の形式を期待するものです。 テストを確認すると、条件を満たしていないとエラーを返すことが分かります。 const Form = z. object ( { name: z. string () .min ( 1 ), phoneNumber: z. string () .min ( 5 ) .max ( 20 ) .optional (), email: z. string () .email (), website: z. string () .url () .optional (), } ); スキーマ の拡張( チュートリアル 09) 一度定義した スキーマ は、extendやmergeを使用して拡張させることができます。 const ObjectWithId = z. object ( { id: z. string () .uuid (), } ); const User = ObjectWithId.extend ( { name: z. string (), } ); const Post = ObjectWithId.merge ( z. object ( { title: z. string (), body: z. string (), } ), ); バリデーション前後で値を変換する( チュートリアル 10) Zodでは、バリデーション前後で値を変換することができます。 チュートリアル のコードでは、transformを使ってバリデーション後に値を変換しています。 具体的には、parseに渡しているdataがStarWarsPeopleResultsで期待している型( { result: { name: string }[] } )だった場合、 { results: [ { name: "foo hoge", nameAsArray: ["foo", "hoge"] } ] } のような形 で返却するという流れになっています。 const StarWarsPerson = z. object ( { name: z. string (), } ) .transform (( person ) => ( { ...person , nameAsArray: person.name.split ( " " ) } )); const StarWarsPeopleResults = z. object ( { results: z.array ( StarWarsPerson ), } ); export const fetchStarWarsPeople = async () => { const data = await fetch ( "https://www.totaltypescript.com/swapi/people.json" , ) .then (( res ) => res.json ()); const parsedData = StarWarsPeopleResults.parse ( data ); return parsedData.results ; } ; 独自のバリデーションチェックを行う( チュートリアル 11、12) Zodでは、refineを使うことで独自のバリデーションチェックを作成することができます。 refineはparseを実行した際に、条件式がfalseの場合、エラーを返します。 チュートリアル 11のコードでは、passwordとconfirmPasswordが不一致の場合、エラーメッセージを返すという形になっています。 refineは相関チェックを行う際によく使われている印象です。 const Form = z. object ( { password: z. string (), confirmPassword: z. string (), } ) .refine (( { password , confirmPassword } ) => password === confirmPassword , { message: "Passwords don't match" } ); またrefineは、 チュートリアル 12のように、非同期関数を渡すことができます。 doesStarWarsPersonExistは、parseAsyncに渡されたidで API を叩き、dataがあった場合はtrueを返し、なかった場合はfalseを返します。 doesStarWarsPersonExistがfalseの場合、refineはエラーメッセージのNot Foundを返します。 const doesStarWarsPersonExist = async ( id: string ) => { try { const data = await fetch ( "https://www.totaltypescript.com/swapi/people/" + id + ".json" , ) .then (( res ) => res.json ()); return Boolean ( data?.name ); } catch ( e ) { return false ; } } ; const Form = z. object ( { id: z. string () .refine ( doesStarWarsPersonExist , { message: "Not found" } ), } ); export const validateFormInput = async ( values: unknown ) => { const parsedData = await Form.parseAsync ( values ); return parsedData ; } ; 再帰 的な スキーマ を宣言する( チュートリアル 13) 再帰 的な スキーマ を宣言する場合、lazyを使用します。 lazyのみだとMenuItemがany型になるため、少し手間がかかりますが、手動でMenuItemTypeを定義して、その型情報をMenuItemに渡す必要があります。 interface MenuItemType { link: string ; label: string ; children?: MenuItemType [] ; } const MenuItem: z.ZodType < MenuItemType > = z.lazy (() => z. object ( { link: z. string (), label: z. string (), children: z.array ( MenuItem ) . default( [] ), } ) ) ジェネリクス ( チュートリアル 14) スキーマ を ジェネリクス で渡したい場合は、 ジェネリクス の型に extends ZodSchema ( extends ZodTypeAny でも可)で制約を加えます。 チュートリアル のコードでは、 ジェネリクス で渡した スキーマ から、z.inferで型を生成して、戻り値の型にしています。 const genericFetch = < TSchema extends z.ZodSchema >( url: string , schema: TSchema ) : Promise < z.infer < TSchema >> => { return fetch ( url ) .then (( res ) => res.json ()) .then (( result ) => schema.parse ( result )); } ; まとめ チュートリアル のコードを交えて、Zodの基本について紹介させていただきました。 再帰 的な スキーマ 宣言や ジェネリクス など、やや応用的な部分もありましたが、私自身も チュートリアル を通じて、基本的な部分はさらうことができたと思っています。 今回は紹介しませんでしたが、ZodはReact Hook Formと組み合わせることができるので、気になる方はこちらの記事も是非読んでみてください。 tech-blog.rakus.co.jp
アバター
本記事のターゲット 転職活動中のPdMの方 PdMへのキャリ アチェ ンジを検討している方 ラク スへの入社を検討している方 はじめに こんにちは、楽楽精算プロダクトマネージャー(以下PdM)のShibaと申します。 2023年5月に ラク スに入社して、半年以上が経過しました。 PdMという職種は会社毎で役割や責任範囲が異なります。 そのため、転職後の業務は多くの人が気になるポイントかと思います。 ラク スに入社して私がやってきたことと気付きを共有することで、 ラク スへの転職を考えている方の参考になればと思い本記事を書くことにしました。 注意 入社者の志向やスキル/経験に基づいて適切な役割を アサイ ンする仕組みが ラク スにはあると思います。 全員が同じ流れで同じ業務をすることはないという点はご了承ください。 また、時間軸は若干曖昧なところがあります。 本記事のターゲット はじめに 注意 私のバックグランドと転職理由 入社後に感じた自身のスキルとのギャップ 入社後の業務 入社1カ月目 入社2~3か月目 入社4か月目~現在 さいごに 私のバックグランドと転職理由 前職は新卒で入社した会社でBtoB SaaS のワークフロープロダクトに約7年間携わっていました。 エンジニアからキャリアをスタートして、プロジェクトマネージャ/プロダクトマネージャ/カスタマーサポート/プリセールスなど プロダクトの成長に必要なことは何でも経験させてもらいました。非常に成長できたと実感があります。 そんな中、30歳を目前に「もっと プロダクトマネジメント に特化したスキルを伸ばしたい」という思いからPdMへの転職を決意しました。 またなんとなく「若いうちに転職を経験しておきたい」という浅い理由もあったかもしれません。 楽楽精算はARR100億以上、累計導入社数も15,000社を超えています。 国内トップシェアのプロダクトに関わることが出来るというのは私にとって非常に魅力的なポイントでした。 ( ラク スを選んだ理由はあまり深掘りしません) 入社後に感じた自身のスキルとのギャップ 1. 言語化 する力 前職では課題の特定~設計/開発/テスト/リリースまですべてを担当していました。 自分の頭の中ではなぜそれをすべきか、なにをすべきかの情報があり、それをもとにプロダクト開発を行っていました。 しかし ラク スは規模(顧客数、ステークホルダ数、開発 工数 など)が大きいため、役割分担によってプロダクト開発が成り立っています。 我々PdMの役割は課題の「Why」「What」を明確にして、適切な課題に適切なアプローチをすることが出来るようにすることだと考えています。 この「Why」「What」を誰が見ても理解できるような形でアウトプットし、納得してもらうための能力はまだまだ伸ばしていく必要があると感じています。 2.思考の道筋の整理 シニアPdMと一緒に仕事をすると痛感する部分です。 私は物事を整理する時、あらゆる情報を集め、そこから必要な情報の取捨選択、ストーリーの構築を行っていくスタイルだと自認しています。 対照的に、結論に向けてストーリーを構築し、必要最低限の情報を集めるパターンの人がいます。 (このタイプの人も頭の中で情報を整理し取捨選択していると思いますが、頭の中はわからない) この違いで生じる差は、大きくはスピード感です。 情報が MECE に整理され、論理的にもおかしくないストーリーをスピード感をもって組み立てる能力は変化の早い時代において伸ばしていく必要があると考えています。 入社後の業務 入社1カ月目 はじめの1カ月は以下のような業務に必要な情報のインプットを行いました。 事業・組織の方針 プロダクトロードマップやKPIなどプロダクト方針 プロダクト(プロダクトの価値、仕様) 法/制度(主に インボイス 制度、 電子帳簿保存法 ) 経理 ドメイン 知識 組織内の役割分担 各種業務プロセス システム構成や環境情報 競合/市場の情報 私の所属する「製品管理課」ではオンボーディング資料が整理されており、特に重要な情報に関してはそこから参照することが出来るようになっています。 資料からわからないところは、インターネットや書籍、上司との1on1を通して理解度を深めていきました。 特に ドメイン 知識というのはこの資料を読めば理解できるというようなものはなく、実際の業務/作業レベルまで理解する必要があります。 プロダクトを触り業務を体験することである程度は理解することが出来ますが、 機能から逆算した業務フローでは、実務レベルまで解像度を高めるは難しいため、 この段階では「業務のイメージが出来る」「用語が理解できる」など定性的な目標を定めて学習するようにしました。 情報が多すぎるがゆえに、認知負荷がかかり何をどこまで理解するかという点は非常に悩みましたが、 自分のキャパと自分の理想の折り合いをつけることが大事です。 また、参加可能な会議には出席するようにしました。 ステークホルダ/キーマンの把握、どのような意思決定が行われているかは早めにキャッチアップし、 なるべくスムーズに実務を開始できるよう準備しました。   入社2~3か月目 2カ月目からは実際の顧客課題に対して、プロダクト バックログ アイテム(以下PBI)の策定を開始しました。 PBIは事業部との課題/解決策の擦り合わせ・開発チームでの概算 工数 の見積もり・PRD(製品要求仕様)のインプットにも利用される重要な情報です。 楽楽精算のPBIには以下のような情報が含まれます。 財務効果 誰のどんな業務のどんな課題 どうすればその課題を解決できるのか AsIs/ToBeの業務フロー 楽楽精算ではカスタマーサクセス(CS)が収集した顧客の声(VoC)が1か所に集約されており、開発サイドも常に確認ができるようになっています。 PBI作成で注意すべきは、VoCの中には課題だけではなく「〇〇できるようにしてほしい」といった要望も多く存在するという点です。 その要望通りの機能を実現するのではなく、背景にある課題に目を向け最小限のコストでその課題の解決策を考えること必要です。 (言ってしまえば、既存機能の運用回避などが提案できればそれでもよい) 課題/要望や社数、発生頻度が精度の高い状態で集まっていることで、 リリース後の効果の不確実性やユーザ調査の工程を省略しスピード感をもってリリースすることができますので、 この仕組みは非常に強力な仕組みだと思っています。 参考( ラク スエンジニアブログ) 楽楽精算の成長を支えるPBI優先度設定の狙いとポイント PRD一部Contents解禁!楽楽精算のPRD(製品要求仕様書) Agenda 入社4か月目~現在 4カ月目以降からは実案件(リリースが確定している案件)に アサイ ンされ、PRDの策定やエンジニアが作成した機能要求やUX設計のレビューを行っています。 また、現在は製品戦略上重要なプロジェクトの案件の実現に向けて、 課題の深堀・ユーザ調査の設計(インタビュー、アンケート、仮説検証)・ソリューションの検討などをPMMと連携して行っていたり、 モバイルアプリの案件に着手したりと担当させてもらえる業務範囲が広がってきました。 顧客への価値提供はもちろん、社内での期待に応えられるように自分のできることを増やしていこうと思った8カ月間でした。 さいごに 前記したような売上や契約社数が多いプロダクトとなると、完成したプロダクトと思う方もいらっしゃるかもしれません。私はそうでした。 しかし、法改正や IT技術 の発達、競合プロダクトの出現、顧客業務の変化などプロダクトを取り巻く環境は日々変化しています。 それらに対応していくために、楽楽精算ではPdM人材を引き続き募集しております。 是非まずはカジュアル面談からお申込みいただけると幸いです。 ラクス エンジニア採用サイト プロダクトマネージャ
アバター
はじめに CentOS8系がEOL(End Of Life)を迎えた関係で、個人的にAlmalinux系を触る機会が増えていきました。 CentOS8系の代わりと考えるとAlmalinuxも同様にバージョン8系を使うというのが素直なところでしょうか。 しかしながら、EOLもありますし、Almalinuxバージョン9系がリリースされてもいますので、Almalinux9系のサーバを構築してみました。 構築してみて、気づいた点(主に8系との違い)をいくつかご紹介します。 ※調査不足なこともあるかと思います。暖かく見守ってくだされば助かります。 はじめに インストールGUI selinuxの無効化の方法が減った・・・ 仮想環境上(LVM)でスナップショットを使ったリストアをすると起動しない?! ethernetの命名が変わっただけじゃないの?? 意図したファイルのログローテーションがエラ―するよ。。。 最後に インストール GUI CentOS7やCentOS8/Almalinux8系と比べてもあまり差は感じませんでした。 タイムゾーン 設定画面で地域をピンポイントで選択できるようになっていたぐらいかなと思います。 日本列島のいろんなところを選択はできるものの東京の タイムゾーン になります。 selinux の無効化の方法が減った・・・ 最近だと selinux は有効化した状態でfirewalldも活用して、適切にセキュリティ環境を整えましょう という風潮とは思いますが、とりあえず動く環境を構築するのに selinux は邪魔!!なので↓ # vi /etc/selinux/config SELINUX=enforcing を disabledにしてreboot!! あれ?無効化されない?! どうやらAlmalinux9系では、 selinux の無効化方法が減ったようです。 /etc/ selinux /configの SELINUX をdisabledに設定することはできるが有効な手段ではないそうで、 カーネル パラメータを変更する方法しかなさそうでした。 改めて↓ # vi /etc/default/grub (抜粋)  GRUB_CMDLINE_LINUX="crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/almalinux-swap rd.lvm.lv=almalinux /root rd.lvm.lv=almalinux/swap biosdevname=0 net.ifnames=0 selinux=0" # grub2-mkconfig -o /boot/grub2/grub.cfg # reboot 仮想環境上(LVM)でスナップショットを使ったリストアをすると起動しない?! 仮想環境で構築したAlmalinux9系のサーバの各種設定を色々イジって遊んでみよう!! 設定変更前の状態のスナップショットを取得しておいたら、元に戻せるし便利~♪ と思っていて、いざスナップショットを利用してリストアしてみたものの起動しない!!! 原因はLVM LVMがDEVNAMEなどのPVを検索するために /etc/lvm/devices/system.devices が使用されるるため、 クローンした VM /スナップショットでリストアした VM が正常に起動せずエマージェンシーモードで起動してしまいます。 Almalinux8系ではデフォルトで「無効」状態となっていたため今までは特に考慮することなくスナップショットを利用したリストアができていたようです。 是正方法は以下の通り。 # vi /etc/lvm/lvm.conf  └ use_devicesfile = 0 をコメントイン # rm -f /etc/lvm/devices/system.devices (当初は原因がわからず、何回もOSインストールを行っていたのは内緒です) ethernet の 命名 が変わっただけじゃないの?? みなさんは、ネットワークの名前( ethernet )にはenp**とかens**とかをお使いでしょうか。 私はいまだにeth0とかeth1とか使ってます。 ということで、Almalinux9系のサーバでもいつもと同じように ethernet の名前を変えてしまいます。 /etc/default/ grub の GRUB _CMDLINE_ LINUX 項目で biosdevname=0 net.ifnames=0 を付与 ( selinux のところで登場してるので、他のコマンドはここでは割愛) # vi /etc/sysconfig/network-scripts/ <Tab>キー、、、<Tab>キー、、、あれ?? ifcfg-***とかが出てこない・・・ network-scriptsが削除 されたとのことでした。。。 代わりに /etc/NetworkManager/system-connections/eth0.nmconnection を編集するそうです。 # vi /etc/NetworkManager/system-connections/eth0.nmconnection   [connection]   id=eth0   uuid=<UUIDの長い文字列>   type=ethernet   autoconnect-priority=-999   interface-name=eth0   timestamp=      [ethernet]      [ipv4]   address1=999.999.999.999/24,<必要ならデフォルトゲートウェイ>   method=manual      [ipv6]   addr-gen-mode=eui64   method=ignore  ※ipv6は原則ignoreしてます。いつの日にか使います。      [proxy] ざっと上記ような内容です。 nmcliコマンドによる IPアドレス 変更はもちろんCentos7系以降は推奨なので使えます。 nmconnectionを修正したら↓ # nmcli c down eth0 # systemc restart NetworkManager # nmcli c up eth0 ※NetworkManagerサービスを再起動するだけでは反映されません。ethを一度ダウン、アップする必要があります。 意図したファイルのログローテーションがエラ―するよ。。。 今回Almalinux9系を触っていて、一番嵌ったのがこれかもしれません。 いわゆるrsyslog類【messages,maillog,secure,spoolerなど】のログローテーション状況を確認すると # ls -1 /var/log/messages*   /var/log/messages   /var/log/messages-20231226   /var/log/messages-20231227.gz /etc/logrotate.confと/etc/logrotate.d/rsyslogの設定通りにログファイルはローテーションされています。 しかし、/etc/logrotate.d/に個別で設定した、意図した ディレクト リ配下のファイルはなぜかローテーションされませんでした。 こういうときはおおよそ、以下が考えられると思います。 ローテーション対象のログファイルやその ディレクト リの権限がイケてない 対象のファイル 命名規則 の誤り ローテーションするファイルの指定ミス messagesログにもエラーメッセージが出力されていました。 error: failed to rename <対象のログファイル> to <対象のログファイル>: 読み込み専用ファイルシステムです。 エラー内容から権限がイケてなさそうだと判断して、対象のファイルや ディレクト リ、念のためローテーションのオプションを見直してみました。 翌日確認すると、同じエラー!!! ここから数日同じ確認と修正をしては同じエラーに悩まされました。 ちなみに手動実行でのテストでは問題なし。 原因を切り分けていくとlogrotate.serviceファイルがもしや何らかの問題を抱えているのでは?と考え至り、確認してみました。 すると /etc/systemd/system/logrotate.service 上記ファイルの設定の内 ProtectSystem=full という設定によってローテーションできないことが判明しました。 Almalinux9以前のOSでもこの設定はあるのですが、デフォルトでは ProtectSystem=no という設定になっており、ローテーションできていました。 設定を変更すると無事に問題が解決! 今回のケースでは2種類の解決方法がありました。 ProtectSystem=noに設定変更 ReadWritePaths=<ローテーションしたい ディレクト リを指定> セキュリティの観点では2を選択したほうがよさそうです。 最後に LINUX 系OSについて業界がざわざわする事態もありました。 その最中にAlmalinux9系を触ることになって、意味があるのかないのかひやひやしてましたが 落ち着いた?ようで今のところよかったです。 今回ご紹介したAlmalinux9系の情報が、だれかのお役に立てば幸いです。
アバター
SRE課の飯野です。 2023/12/11(月)〜12(火)の2日間、『 CloudNative Days Tokyo 2023 』(以下CNDT)が開催されました。 弊社からはわたしが所属するSRE課の他、インフラ開発部の大阪メンバー(出張での参加!)や楽楽精算の開発メンバーなども含め、15名ほどが現地参加しました。 本ブログでは、CNDT参加後に行った社内でのふりかえりの内容をお届けします。 『 SRE NEXT 2023 』参加時のブログもありますので、よろしければこちらもご覧ください。 tech-blog.rakus.co.jp 目次 CNDTとは? 当日の様子 ふりかえりやってみよう 総括 CNDTとは? 『 CloudNative Days 』というコミュニティが手掛けている 日本最大級の クラウド ネイティブ・テックカンファレンス です。 その名の通り「 クラウド ネイティブ技術」に焦点を当てており、 クラウド ネイティブな アーキテクチャ や開発手法、ツール、運用等に関するトピックが取り上げられ、最新の動向や実際の現場においてどのような取り組みを行っているかといった情報を得ることができます。 今年もオフライン会場は 有明 セントラルタワー ホール&カンファレンスにて行われ、オンライン配信もありのハイブリッド方式で開催されました。 今回のテーマは「+Native ともに飛び出せ!」とのこと。 "CloudNative Days"は、技術を学び、技術と人・人と人の繋がりを深めるテックカンファレンスです。 コロナ禍で生じたコミュニティの分断を乗り越え、一体感を再び取り戻し、仲間や友達と共に成長しましょう。 今回は分断されたコミュニティを再集結するための一歩として、東京で開催します! みなさんの所属組織の垣根を飛び越え、CloudNativeを元に交流する場に飛び込みませんか? "CloudNative"を学び、新たな世界に飛び出しませんか? さあ、ともに飛び出しましょう。 "CloudNative Days"で、新たな繋がりと成長をお楽しみください。 ( 公式サイト より) 申込者数はなんと2,000名を超えていたようです、界隈の盛り上がりを感じますね〜。 当日の様子 タイムテーブル 両日共に午前の部は各20分×6本の Keynote があり、午後は休憩を挟みつつ4トラック同時開催で各40分ずつのセッションが行われました(スポンサーセッション含む)。 その他、現地では技術コミュニティによるLT大会や、美味しいコーヒーを飲みながら交流ができる「ゆるカフェ」スペース、ついつい貯めがちなステッカーを集約できちゃう 御朱印 帳作りなど、様々な企画が行われていました。 スポンサーブースで開催されていたスタンプラリーもとても盛り上がっていました〜(おみやげたくさん!)。 また、1日目のセッション終了後には懇親会も行われました。 ふりかえりやってみよう さて、今回も現地参加の熱が冷めやらぬうちに、インフラ開発部(SRE/大阪)のメンバーで後日さっそくふりかえりを実施してみました。 実施するにあたって、事前に用意したフォーマットは下記です。 # 印象に残ったセッション ## タイトル ## 登壇者情報 ## スライド ## セッション概要 - セッションの内容を簡潔に ## 共有したい点、感想等 - どんな点に共感したか、疑問に思ったこと等 --- # 今後実施/挑戦したいこと - 参加してみてアクションを起こしたくなったものが何かあれば # 全体を通しての感想 - 率直な感想をご自由に それぞれが印象に残ったセッションを選択し、セッション概要と共有したい点/感想等を事前にまとめてもらいました。 以下、実際にまとめてもらったふりかえりの内容を一部ご紹介します。 大阪インフラ/U氏のまとめ noteの Kubernetes 移行、ゼンブ見せます セッション紹介ページ speakerdeck.com セッション概要 2023年9月に本番稼働の全てのアプリケーションを Kubernetes に移行したプロジェクトで行ったことについて 共有したい点、感想等 新規サービス立ち上げでなく、既存環境への移行の場合はサービスの継続性を重要視する為、綿密な計画とステップを踏みながら行っている 移行完了は年単位レベルになる為、自社で行う場合は複数サービスがある為、移行是非の検討は慎重に行いたい 今後実施/挑戦したいこと 開発への環境提供を高速に行うために、まずは自社内の Kubernetes ベストプ ラク ティス環境を策定し、その後にPrehubのようなものを作成し開発者体験向上に貢献していきたい 全体を通しての感想 コロナ明けによりオフライン開催が増え、久々の大型イベントの参加だった為、素直に楽しかった Kubernetes 歴はまだ1年未満だが社内でも詳しい人があまりおらず、自分の中の「?」の回答を得る為に情報収集するのがとても大変だったが、各社ブースや登壇者、 Kubernetes 界隈の方々と直接意見交換することで正解に近い答えが得られたりと有意義な時間が得られた 大阪インフラ/M氏のまとめ 100万コンテナの Kubernetes プラットフォームを5年間スケーラブルに運用するために乗り越えていること セッション紹介ページ speakerdeck.com セッション概要 1600 クラスタ 規模にスケールしたKaaSの高い安全性/信頼性・トイル削減について 効果のあったプ ラク ティス(アラート削減)について 共有したい点、感想等 運用されている クラスタ 数(1600)、コンテナ数(100万超)に圧倒された この規模の基盤を運用するには、トイルの徹底削減も必須になることが分かった 信頼性向上のためのSLIを用いた監視拡充を進めたことにより増加したアラートを削減するプロセスが参考になった アラートを洗い出し、以下4つに分類 Noisy Alerts: すぐ直る一時的なアラート、監視の問題 Easy-Easy Alerts: 原因究明、対応手順が簡単 Easy-Hard Alerts: 原因究明は簡単だが、手順が明確でない Hard-Hard Alerts: 原因究明が難しい、手順もない 今後実施/挑戦したいこと Kubernetes 未導入のサービスでも現状通ずること(トイル・アラート削減など)があったので、まずは改善できるところから実践していきたい 知識不足から難しいと感じる内容もあったので、引き続き情報をインプットしていきたい 全体を通しての感想 クラウド ネイティブな環境の運用のスタンダートが知れて良かった コンテナ/ クラウド 辺りの基礎知識のおさらい~他社の運用事例まで幅広い情報をキャッチアップできた 大阪インフラ/A氏のまとめ これからのPlatform Engineeringを支えるコンテナ×Backstageの真価 セッション紹介ページ speakerdeck.com セッション概要 クラウド ネイティブにおける開発で、認知負荷が高まっている Docker, Kubernetes , Git, Security, TestTools, CI/CDなどの多種多様なツール PlatformEngineeringの力で開発者の道筋を整備・誘導し、開発生産性を向上させる そのために『開発環境・ルール・ノウハウ』を一括で提供する 仕組みとしてGoldenPath:開発のベストプ ラク ティスを動作環境とサンプルアプリと一緒に開発者に提供 ツールとしてBackstage:開発者ポータル、ツール類のカタログのようなイメージ Backstageで開発&運用ノウハウの『集約・展開』を支援、GoldenPathで『習得・体系化』でブラシュアップしていく 共有したい点、感想等 開発者に限らず、インフラ側でもBackstageのようなポータルがあることで、例えばノウハウ共有や新規参入メンバの立ち上がりを高速化するなどの恩恵を受けられそう クラウド ネイティブな開発に限らず、GoldenPathやBackstageのエッセンスを取り入れられる部分がないか調査/改善していきたい 今後実施/挑戦したいこと オブザーバビリティ/Platform Engineering面白い、どんどん学習して改善に繋げていきたい クラウド ネイティブ技術をまずはハンズオンから実践してみる 全体を通しての感想 凄いところに来た感はありつつも、活発な技術カンファレンスで刺激を受けられたため、また参加したい SRE課/U氏のまとめ Kubernetes Persistent Volume 向けゾーン障害への備え セッション紹介ページ speakerdeck.com セッション概要 Kubernetes でPersistent Volumeを利用する上で、ゾーン障害とどのように向き合っていくか 前提知識となる Kubernetes の基礎知識もすこし 共有したい点、感想等 クラスタ ー構成別にどのような形でPVを扱うべきかが簡潔にわかる そもそもPVを必要とするアプリケーションが悪という認識が強まる 今後実施/挑戦したいこと ステートレスなアプリケーション開発を徹底しようと決意した 逆にPVが必要になる ユースケース についてもっと学ぶべきだと思った 全体を通しての感想 昨年参加した時よりも クラウド ネイティブ周りの知識が少しはついた実感があった(成長を感じた) 初心者〜上級者向けのセッションまで幅広くあり、初心者にもぜひ参加を薦めたい 一部登壇者の異次元感でモチベが上がった SRE課/S氏のまとめ クラスタ ーを分割するという運用の現実解 ~Pod を VM のように使い始めたら見えてきた世界~ セッション紹介ページ クラスターを分割するという運用の現実解 from CASAREAL, Inc. www.slideshare.net セッション概要 VM からコンテナ( Kubernetes )に移行して良かったこと 協力会社が VM を使用していたため、開発環境の構築時間を大幅に削減し、人的エラーを解消できた Dockerfileは開発チーム自身でGit管理し自由にカスタマイズが可能に Kubernetes で運用していく中で出てきた課題 しばらくコンテナで運用していると、開発環境の動作が全体的にもっさりしはじめた 1 クラスタ ーで全てを管理していたため、特定の高負荷podが クラスタ ー全体の安定性に影響を与えてしまう Kubernetes のバージョンアップが行いづらい 共有したい点、感想等 運用していく中で、構築時に予想していなかった課題は都度出てくるものだと思うので、載せてからがスタートだと身に染みた 今後の構築において学びが多かった クラウド ネイティブ初心者にぜひ聞いてほしいセッションだと思った 今後実施/挑戦したいこと CNDTで聞けた内容を実務で挑戦、取り入れていきたい アプリケーションを Kubernetes 上に載せてからの実運用 全体を通しての感想 去年参加した時は右も左もわからない状態であったが、今年は聞いたことがないワードが少なく楽しく拝聴できた 去年と比べて少しは成長した 去年より クラウド ネイティブが身近に感じるようになった SRE課/I氏のまとめ 決済システム内製化のその先に 〜 クラウド ネイティブな開発を"スケール"させるために必要だったこと セッション紹介ページ speakerdeck.com セッション概要 5年前に内製化された決済システムが、月日を経て規模が大きくなりどのようにスケールさせたか 一部リソースを クラウド からオンプレ、内製から外注に移行しており、それぞれを進める上で生じた課題解決の知見を紹介 共有したい点、感想等 クラウド ネイティブなシステムを内製から外注に移行するのは相当ハードルが高いことだと思ったが、とても丁寧にイネイブリングしていたのが印象的だった 新しい取り組みを始めるにあたって、まずは動く実物なりサンプルを用意してから ガイドライン に落とし込みレクチャーするという流れは対象が何だとしても重要 プラットフォームが用意されていることで「開発者が安心して開発に注力できる」という点は、気持ちの面で学びになった 今後実施/挑戦したいこと 立場的に、 クラウド ネイティブな環境をどう用意しどのように展開していくかを考えることが多いので、レクチャーマインドを参考にしていきたい 泥臭い活動ですけど価値はありありですよねと常に思う 会社としてこの分野に一丸となって取り組めるように文化醸成頑張る、と共に説得力をつけるためにインプット邁進 全体を通しての感想 CNDTは初参加だったが、普段課内で触れているキーワードが多かったので クラウド ネイティブにしっかり取り組めているなと自信がついた SRE課以外の他チームも現地参加していて、単純に嬉しかった!仲間が増えてる! SRE課/I氏のまとめ GitOpsで実装する Kubernetes セキュリティ -攻撃者が考えるアタックシナリオと OSS を活用した守り方- セッション紹介ページ speakerdeck.com セッション概要 パブリックな リポジトリ にアップされた非公式のコンテナイメージを利用することによる攻撃シナリオの例を解説 攻撃用コンテナイメージへの対策として、OPA( GateKeeper )を利用したAdmission Controllerによるイメージ取得元のバリデーションチェック導入のハンズオンを実施 共有したい点、感想等 イメージ上のOSやライブラリの静的スキャンはtrivyでも実施できるが、今回の攻撃例はコンテナ起動時に バックドア を作ってコンテナ内部に侵入するというものだったのでtrivyでは防げない コンテナ起動後の不審な挙動の検知まで行けなくても、コンテナイメージ取得元のチェックだけで相当多くの攻撃が防げる、かつそこまで導入の難易度は高くなさそうなので、是非導入すべきだと思う チェックロジックはRegoで書かれていたが、簡単なものであればサンプルも多いので導入は難しくなさそうに感じた( GitHubリポジトリ ) 今後実施/挑戦したいこと コンテナイメージ取得元のチェックを実行( GateKeeper 使うのかはさておき) Kubernetes 特有のセキュリティの学習 全体を通しての感想 東京のインフラ開発部内で「 基礎から学ぶコンテナセキュリティ 」の輪読会をやっているが、あくまでコンテナ(docker)に閉じているので、 Kubernetes に適用した際にどのような技術や対策があるのかの知見をインフラ開発部内で高めるべきだと感じた SRE課/I氏のまとめ (※なぜかSRE課はIがつく人が多い) 計測の手間を省きたい!OpenTelemetry に見る”自動計装”のイマ セッション紹介ページ speakerdeck.com セッション概要 オブザーバビリティ、計装、OpenTelemetry(以下OTel)について OTel計装の基礎 OTelの"自動"計装 OTel計装(自動/手動)のデモ 補足情報( Kubernetes Operatorでの自動計装、Goへの自動計装 by eBPF) 共有したい点、感想等 自動計装を使うと、自社へのTraceの導入がスムーズに進むかもしれない アプリケーションの改修が不要というところがポイント ラク スはインフラとアプリケーション開発で組織が分かれているため、インフラ発案でTrace導入を進めるとなると、アプリケーション開発への協力依頼が必要になる 手動計装の場合、机上での説得が必要 自動計装の場合、とりあえず実装してデモを見てもらえるし、TraceのON/OFFも容易であるため本番での導入障壁も低い 逆井さんの「オブザーバビリティは横断的関心事。組織間には必ずオブザーバビリティ"格差"が存在する」という言葉が染みた 今後実施/挑戦したいこと Kubernetes 上のサービスに対し、分散トレーシングを導入する Java 系サービスのアプリケーションに自動計装を注入してデモ→導入 OTelCollectorを導入 Kubernetes 上のMWもTrace/Spanを出すようにインスツルメンテーションする バックエンドはGrafana Tempoで実装 問題なければ本格導入へ 全体を通しての感想 自社にオブザーバビリティを導入するステップが少しイメージできた、面白かった! SRE課/M氏のまとめ〜その1〜 Wasm is becoming the runtime for LLMs セッション紹介ページ ※スライドなし/リンク先に動画あり セッション概要 Wasmを利用して超軽量かつ、高性能なLLMアプリを実現 共有したい点、感想等 Wasm(WASIのがいいのかな)って何が良いの? どうすごいの? という感覚の方に見てもらいたい 私もそうですが、何がすごいのか良く分かっていなかった人にその効果を見て驚いて欲しい Wasmの単語は知っていましたが、実用的な事例で改めて素晴らしさを感じた 個人的にはコンテナランタイムのゲームチェンジャーになる可能性を感じたのでものすごくワクワクするセッションだった 今後実施/挑戦したいこと Wasm周りについて情報が追えておらず、ヤバさを感じてWasmEdgeをインストールして簡単なデモを動かしてみた 今後もドンドン革新的な変化を遂げそうなのでWasmの動向はチェックしていきたい 全体を通しての感想 Wasmという単語しか分かっていなかった自分にその必要性や効果をしっかりと示してくれるセッションだった SRE課/M氏のまとめ〜その2〜 マイクロサービスの信頼性を支えるオブザーバビリティとサービスメッシュ セッション紹介ページ ※スライドなし/リンク先に動画あり セッション概要 マイクロサービスにおいてサービスメッシュを利用することで信頼性を向上させる方法について解説 SLIやSLOといった信頼性に必要な概念から、実際にサービスメッシュを利用してどういったことが出来るのかの紹介 共有したい点、感想等 信頼性やオブザーバビリティといった概念を把握出来る サービスメッシュとは何なのかその概念を把握出来る サービスメッシュを利用した自動計装についてその概要を理解出来る 今後実施/挑戦したいこと サービスメッシュの利用を検討していたところだが、信頼性の点で有効活用することは考えていなかった 本セッションで紹介された機能を利用することで、アプリケーションエンジニアの負担を軽減しながら信頼性の向上を目指すヒントを得られたと思う、今後は実際の導入に向けて検討を進めたい 全体を通しての感想 サービスメッシュのことは知っていたが、詳しい機能については知識が不足していた このセッションを通して有効な利用方法の一端を把握することが出来た 総括 以上、『CNDT』に参加したメンバーのふりかえりの内容をご紹介しました。 単純にインプットが増えただけでなく、参加者同士での情報共有や議論の場が持てたことで、理解をより深めることができたのではないかと思います。 こういった大型イベントは自社や個人の取り組みをふりかえる良い機会にもなりますし、何より参加者が刺激を受けてモチベーションが上がるのが嬉しいですね。 スタッフの皆さま、登壇者の皆さま、企画運営本当にお疲れ様でした。そしてありがとうございました! 次回の開催は北海道か沖縄という噂? SREの課長は必ず現地参加するのでw、現地レポートに期待しましょう!
アバター