TECH PLAY

株式会社ラクス

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

927

こんにちは。楽楽勤怠バックエンドチームの mako _makokです。 皆様はSlack アプリを開発されるときはどうやって開発されていますか? Hubotでしょうか?それともHttp Clientから直で叩いていますか? 今回はSlack API を簡単に使え、爆速でSlack アプリを開発するための フレームワーク Bolt のご紹介をさせていただきます。 Boltとは JavaScript Java Python スラッシュコマンドについて スラッシュコマンドの概要 スラッシュコマンドを登録する Boltを使う Slack API を叩いてみる スラッシュコマンドを作る レシーバーの作成 スラッシュコマンドのアクションを作成する 余談: Block Kit まとめ おまけ 参考 Boltとは Slack API チーム謹製のSlack API Client + スラッシュコマンド用のレシーバを兼ね備えた、Slack アプリ開発 用の フレームワーク です。 現時点では JavaScript (TypeScript), Java , Python の SDK が配布されています。 オープンソース で開発されていおり、 リポジトリ はそれぞれ以下です。 JavaScript 主にTypeScriptで開発されています。 型フレンドリーにSlack API を使用することができます。 github.com Java kotlin用のextensionやSpring BootやKtorなど Java , KotlinのWeb Frameworkへのextensionやサンプルなども豊富にあります。 github.com Python type hintフレンドリーな開発ができます。 一部独自のアプローチでSlack アプリが抱える問題を解決したりしています。 github.com どの言語でも細かな差はありますが、基本的なインターフェースは同じなので自身の好きな言語を選択してください。 今回は bolt-js を使用して解説していこうと思います。 スラッシュコマンドについて Boltの説明に入る前に、スラッシュコマンドについて説明します。 スラッシュコマンドは、Slack上で /foo のようにし、それをトリガーとして様々なアクションを行うことができます。 もし既にSlackをインストールしてあるのであれば、 / と入力してみてください。 デフォルトで登録されているいくつかのスラッシュコマンドが一覧表示されます。 続けて /remind と入力してみると、リマインダー登録用のモーダルが表示されると思います。 スラッシュコマンドの概要 スラッシュコマンドを簡略化すると、以下のように動いています。 スラッシュコマンドを入力すると、指定したエンドポイントにSlackからHttp Requestが送られてきます。 スラッシュコマンドを登録する スラッシュコマンドは https://api.slack.com/apps/{app_id}/slash-commands にアクセスし、 Create New Command を押すと以下の画面が出てきます。 Commandに登録したいスラッシュコマンド、Request URLにSlackからのリク エス トを受け取るエンドポイントを設定します。 Boltを使う Slack API を使うために、Boltの初期化をしていきます。 今回は bolt-js を利用するので、npmでインストールします。 プロジェクトを作成し、 npm install @slack/bolt とするだけでインストールが完了します。 TypeScriptはお好みで入れてください。 最初にAppを インスタンス 化します。 import { App } from '@slack/bolt' const app = new App ( { token: process .env.SLACK_BOT_TOKEN , signingSecret: process .env.SLACK_SIGNING_SECRET , } ) (async () => { // Start your app await app.start ( process .env.PORT || 3000 ); console .log ( '⚡️ Bolt app is running!' ); } )(); tokenとsingleSecretは以下から取得することができます。 singleSecret https://api.slack.com/apps/{app_id} token https://api.slack.com/apps/{app_id} Slack API を叩いてみる Boltの初期化は完了したので、実際にSlack API を叩いていきます。 以下は chat.postMessage を叩いて、チームメンバーが参加したらメッセージを送信するサンプルです。 app.event ( 'team_join' , async ( { event , client } ) => { try { await client.chat.postMessage ( { channel: 'foo' , text: `いらっしゃい、<@ ${ event.user.id } >! 🎉` , } ) } catch ( error ) { console .error ( error ) } } ) 第一引数にイベント名、第二引数にリスナーを設定します。 リスナーのclientは認証済みのものが渡されるので、すぐにSlack API を叩くことができます。 また、リスナーを介さずSlack API を叩くことも可能です。 App自体が WebClient を持っているので、tokenを都度渡して実行します。 await app.client.chat.postMessage ( { token: process .env.SLACK_BOT_TOKEN , channel: 'foo' , text: `いらっしゃい、<@ ${ event.user.id } >! 🎉` , } ) さらに、BoltにはSlack API を更に簡単に扱うためのユーティリティが用意されています。 例えば、更に簡単に chat.postMessage を実行できる say() 関数などがあります。 以下は「おはよう」というメッセージに反応して、「今日もいい天気!」と返す スクリプト です。 app.message ( 'おはよう' , async ( { message , say } ) => { await say ( `今日もいい天気!` ); } ); say() 関数はチャンネルが特定できるイベントであれば、使用することができます。 スラッシュコマンドを作る Boltでは簡単にスラッシュコマンドを作ることができます。 レシーバーの作成 Slackからのリク エス トを受け取ってレスポンスを返すレシーバー、以下のように設定します。 import { App , ExpressReceiver } from '@slack/bolt' export const expressReceiver = new ExpressReceiver ( { signingSecret: process .env.SLACK_SIGNING_SECRET , endpoints: '/events' } ) export const app = new App ( { receiver: expressReceiver , token: process .env.SLACK_BOT_TOKEN } ) ExpressReceiver を App に渡すだけで、簡単にレシーバーの設定をすることができます。 エンドポイントは /events と記載してありますが、実際のルーティングは /slack/events となるので注意してください。 このエンドポイントを「スラッシュコマンドについて」で紹介した、Request URLに設定して準備完了です。 スラッシュコマンドのアクションを作成する スラッシュコマンドを入力されたときのアクションを書いていきます。 今回は /register-word というスラッシュコマンドが入力されると、モーダルが開き、情報を入力してsubmitすると入力された内容が送信され、それを受けとるサンプルです。 const close: PlainTextElement = { type : 'plain_text' , text: 'キャンセル' } const submit: PlainTextElement = { type : 'plain_text' , text: '登録' } function buildBlocks () : KnownBlock [] { const keywordInput: InputBlock = { type : 'input' , block_id: 'keyword' , label: { type : 'plain_text' , text: '検索ワード' , } , element: { type : 'plain_text_input' , action_id: 'keyword_input' , } , } // ... return [ keywordInput ] } const VIEW_ID = 'dialog_1' export const register = ( app: App ) => { app.command ( '/register-word' , async ( { ack , body , context , command } ) => { await ack () try { await app.client.views.open ( { token: context.botToken , trigger_id: body.trigger_id , view: { type : 'modal' , callback_id: VIEW_ID , title: { type : 'plain_text' , text: '検索ワードの登録' , } , blocks: buildBlocks (), private_metadata: command.channel_id , close , submit } , } ) } catch ( err ) { console .error ( err ) } } ) app.view ( VIEW_ID , async ( { ack , view , context , body } ) => { await ack () const values = view.state.values const keyword = values.keyword.keyword_input.value // ... } ) } まず app.command でスラッシュコマンドを待機します。 app.command ( '/register-word' , async ( { ack , body , context , command } ) => { } 最初に ack() 関数を実行します。 この関数はSlackに対して即座にレスポンスを返すことができます。 スラッシュコマンドは3秒以内にレスポンスを返さないといけないというルールがあるので、まずはレスポンスを返します。 後続の処理は非同期で実行されます。 await ack () スラッシュコマンドを受け取ったら views.open を叩きます。 この API では Block Kit で作成されたViewを表示することができます。 submitに登録されているオブジェクトがクリックされると実際にsubmitされます。 submitされたフォームのデータは app.view で受け取ることができます。 app.view ( VIEW_ID , async ( { ack , view , context , body } ) => { await ack () const values = view.state.values const keyword = values.keyword.keyword_input.value // ... } ) views.open で設定された callback_id を検知して発火します。 フォームの中身は view.state.values の中にあります。 values以下のオブジェクト構造は views.open で使用しているBlock Kit内で決めることができます。 const keywordInput: InputBlock = { type : 'input' , block_id: 'keyword' , label: { type : 'plain_text' , text: '検索ワード' , } , element: { type : 'plain_text_input' , // action_idがvalues以下のプロパティとなる action_id: 'keyword_input' , } , } 余談: Block Kit Block Kitを利用することで、複雑なUIを表現する事ができます。 Block Kitについては公式のドキュメントがわかりやすいです。 api.slack.com また、 Block Kit Builder というツールもあり、プレビューしながらUIを構築することが可能です。 まとめ 今回はBoltについて紹介させていただきました。 今回紹介しきれなかった機能もたくさんあるので、みなさんもぜひ触ってみてSlackアプリを作ってみてください。 改めて、Boltのメリットをまとめます。 Slack API チームがメンテナンスしているので、信頼性が高い 型安全にSlack API を扱うことができる Slack API を簡単に使うための便利なユーティリティ スラッシュコマンド用のレシーバーを簡単に生成できる おまけ Bolt + Firestore + Cloud Functions 成果物として、スラッシュコマンドからワード登録モーダルを開き、毎朝バッチで勉強会情報を通知してくれるサンプルを作ってみました。 よろしければ参考にしてみてください。 github.com 参考 Bolt入門ガイド( https://slack.dev/bolt-js/ja-jp/tutorial/getting-started ) Slack API ( https://api.slack.com/apis ) Bolt for JavaScript を使った Slack アプリ開発 で知っておくと捗る 7 つのこと( https://qiita.com/seratch/items/dcedc7476eac5f681d30 ) ※冒頭画像のSlackロゴは、 公式サイト で配布されているものを使用しております。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
Rust入門 こんにちは高照です。 今回はここ数年で急成長を遂げたRustという プログラミング言語 を勉強しましたので記事にしました。 本記事では Rustについての解説 と プログラミングのはじめ方 、 基本的なプログラムの記法 をまとめます。 Rust入門 Rustとは Rustの魅力 環境構築 プロジェクトの作成とHello, World! コーディング 最後に Rustとは Rustは Mozilla 社が支援する オープンソース の プログラミング言語 です。 また、2016〜2019年で Stack Overflow Developer Survey で「最も愛されている プログラミング言語 」で一位を獲得し続けていた言語で初めにも記述したように急成長を遂げました。しかしながら、学習難易度が高い言語とも言われていて今後の学習のしやすさが課題となってきます。 Rustの魅力 Rustの魅力的なポイントとして以下の6つを上げることができます。 実行速度の速さ モダンな文法 OSからWebアプリケーションまでカバー ツール群の充実性 強力な安全性 エディションによって互換性を担保 これらの魅力を少し解説していこうと思います。 1. 実行速度の速さ Rustはプログラムの実行速度を重視した言語で、 競技プログラミング でも使用されている C言語 にも匹敵する実行速度を出すことができます。 この理由として以下のような要因が考えられます。 機械語 に コンパイル される ガベージコレクション を持たない ゼロコスト抽象化の追求 機械語 に コンパイル される Java や Python などは、独自の 仮想マシン 上でコードを実行することで様々なプラットフォームでもコードを実行することができるようになるという利点があります。一方、実行には 仮想マシン を介す必要があるため速度においては不利と言えます。 Rustは 仮想マシン を使用せず直接 機械語 に コンパイル できるためこれらの問題での速度低下は起きません。 ガベージコレクション を持たない 自動で使用したメモリを開放する機能である ガベージコレクション を持ちません。 そして、 C言語 や C++ では手動でメモリ管理をする必要もありません。 Rustは 所有権 ・ 借用 ・ ライフタイム というこれまでにない仕組みでメモリを管理されます。 そのため ガベージコレクション や手動のメモリ解放に頼らないため速度と安全性を兼ね備えています。 ゼロコスト抽象化の追求 Java のabstractのような共通部分を抜き出す固有の処理は、抽象化する処理をRustではコストを払うことなく使用することができます。この抽象化は大規模なプロジェクトを作成するにあたり多様されるため、ゼロコストで抽象化をすることができるというのは処理速度面で大きなアドバンテージだと言えます。 2. モダンな文法 Rustは多くの プログラミング言語 を参考にし、設計されました。 Rustはデフォルトで変数割当は不変となっています。つまり、変数を作成した後に、値を再代入しようとすると コンパイル エラーとなります。例は以下の通りです。 fn main ( ) { // 変数aを宣言し1で初期化する let a = 1 ; // aに2を再代入しようとするとコンパイルエラー a = 2 ; } また、letの後ろにmutをつけることで再代入可能な変数を扱うことができます。 fn main ( ) { // 変数aを宣言し1で初期化する let mut a = 1 ; // aに2を再代入する a = 2 ; } 変数をデフォルトで不変にするメリットは、長いスコープ内で代入を繰り返してしまい、値がどう変化してしまうか把握できなくなってしまうことを防ぐことができます。 また予期しない変数への再代入などにより、バグが発生しづらいコーディングをすることができます。 これ以外にもモダンな文法が含まれていますが、現段階で説明してしまうと非常に難しくなってしまうため割愛いたします。 3. OSからWebアプリケーションまでカバー Rustは システムプロ グラムだけでなく、Webアプリケーションのバックエンド開発を行うことも可能です。 activex -webという フレームワーク が存在し、Node.jsなどの フレームワーク と遜色ない開発が可能です。 4. ツール群の充実性 RustにはCargoというパッケージマネージャ・ビルドツールが存在します。 Cargoはライブラリのインストールやプログラムのビルドを全て行うことができます。 今回、使用するのは以下の3つのコマンドです。 cargo new → プロジェクト作成 cargo check → コンパイル が通るかのチェック cargo run → コンパイル ・実行 また、プログラミングする際に使用するエディタも充実しています。 IntelliJ やCLion、 Visual Studio Code 、 Vim 、 Emacs など多くのエディタで プラグイン が作成されています。 今回、私は Visual Studio Code を使用しコーディングしていきます。 5. 強力な安全性 Rustは メモリ安全ではない操作 や スレッド安全ではない操作 を未然に防ぐように設計されています。 メモリ安全ではない操作 メモリを手動で管理する C言語 や C++ などでは「メモリの開放を忘れてしまう」ことや、「開放したはずのメモリをもう一度開放しようとしてしまう」などの状況を メモリ安全ではない と言います。 「 ガベージコレクション を持たない」の項目でも説明したとおり、Rustでは手動管理ではなく 所有権 ・ 借用 ・ ライフタイム でメモリ管理されることでメモリの安全を保証しています。 スレッド安全ではない操作 2つの並行するスレッドがあると仮定し、それぞれa = 1,b = 2の処理を非同期に行うとします。 a = 1の処理が終わった際にbの値はどうなっているのでしょうか。 答えは 分かりません 。 なぜかというと、a = 1の処理が終了した際に b = 2の処理がまだ終了していない場合も考えられるからです。この状態を スレッド安全ではない と言います。 Rustはこの状態をプログラム上で考慮されているかを厳しくチェックし、スレッド安全であることを保証します。 6. エディションによって互換性を担保 Rustには2015エディションと2018エディションが存在し、相互の互換性が効かない文法が存在します。 しかし、ライブラリ単位ごとならば異なるエディションであっても問題なく使用することができます。 環境構築 では、実際に環境構築しプログラムを作成していきましょう。 今回は Windows 環境にRustをビルドできる環境を作成していきます。 まずは、以下のリンクからRustをダウンロードしインストールします。 www.rust-lang.org OSが32Bitか64Bitを確認しダウンロードしてください。 RustDLページ ダウンロードした rustup-init.exe を起動しインストールを開始します。 起動すると コマンドプロンプト が立ち上がり処理を続けるかを聞かれるため y と入力しEnterを押下します。 RustInstall確認 その後、インストール方法を聞かれますので、デフォルトの 1 と入力しEnterを押下します。 RustInstall項目 以下のように出力されれば、Rustのインストールは完了です。 RustInstall完了 続いてVisual C++ ビルドツールのインストールを行います。 以下より、 Build Tools for Visual Studio 2019 をダウンロードし実行してください。 visualstudio.microsoft.com インストールする項目で C++ Build Tools をチェックし、右下のインストールボタンを押下します。 VS Build Tools 2019 Install お疲れさまでした。 以上でRustの開発環境が整いました。 次節からプロジェクトを作成し、コードを書いてみましょう。 プロジェクトの作成とHello, World! まずはプロジェクトを作成します。 わかり易い場所に作業用のフォルダを作成してください。 その後、 コマンドプロンプト にて以下の例の様に、 cdコマンド を使用し作成したフォルダへ移動してください。 例 ) cd Desktop¥Rust¥Project 移動後、先程説明にも出てきたcargoを以下のように使用します。 cargo new test_rust コマンドを実行後、フォルダ内にtest_rustフォルダが作成されます。 ではそのまま実行してみましょう。 cd test_rust cargo run 実際に実行すると、以下のような結果となり Hello, World! と表示されます。 Rust実行 Rustではプロジェクトを作成した段階で Hello,World! をすることができます。 ではコードの中身を見ていきましょう。 メインコードは test_rust¥src¥main.rs に記述されています。 中身は以下のようになっています。 fn main () { println! ( "Hello, world!" ); } main関数が記述され、関数内で println! メソッドが呼ばれ、その中身が表示されていることが分かります。 ではもう少し本格的にプログラムを作成して見ましょう。 コーディング まずは簡単なRustのプログラムから作成しながら見ていきましょう。 以下プログラムではvalという変数を宣言し、数字の 1234 を格納及び、表示しています。 Rustは 型推論 により自動で変数の型を決めてくれます。 今回は自動で32bitのint型で宣言されますが、明示的に変数の後ろに :i32 と記述することも可能です。 println!内の "{}" にはそれ以降の引数の値が置き換えられ表示されます。 fn main () { let val = 1234 ; println! ( "{}" , val); } fn main () { // 明示的に型の指定もできる let val: i32 = 1234 ; println! ( "{}" , val); } また変数のデータ型以下のようになっています。 型 説明 i8 8bit 符号あり 整数 i16 16bit 符号あり 整数 i32 32bit 符号あり 整数 i64 64bit 符号あり 整数 u8 8bit 符号なし 整数 u16 16bit 符号なし 整数 u32 32bit 符号なし 整数 u64 64bit 符号なし 整数 f32 32bit 浮動少数点数 f64 64bit 浮動少数点数 bool 論理値 char 文字型 当たり前ではありますが、他の言語でもあるものは全て揃っています。 また、他にも文字列型や配列、タプルなども存在します。 では最後にfor文とif文の使用方法を見てみましょう。 以下プログラムは、1~9で偶数の値を表示するプログラムです。 for文:1~9の値を順にxに代入しループします。 if文:xを2で割ったあまりが0かどうかを判定することで偶数であるかを判定し画面表示しています。 fn main () { for x in 1 .. 10 { if x % 2 == 0 { print! ( "{} " , x); } } println! (); } 最後に 一般でも言われている通り、Rustは学習するには難しい言語だと感じましたが、それ以上に魅力もあることを知っていただけましたでしょうか。 また、私の印象としては、処理が高速な C言語 や C++ 寄りでプログラムのモダンな記法は Python やSwiftに似ていると思いました。また、Rustを学ぶ上で C言語 のポインタという概念を学習しておくと、理解しやすいのかなと感じました。ポインタは C言語 の関門とも言われているため、Rustは難しい言語と言われているのでは無いかと思います。(ポインタを理解すると、Rustは割りかしすんなりと理解できるかもしれません。) 今回はあまり突っ込んだプログラムの解説はできませんでしたが、また機会があれば続きを書きたいと思います。 ※冒頭画像のRustロゴは、 公式サイト で配布されているものを使用しております。  また、このロゴはRust財団によって CC-BY の下で配布されています。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは、インフラエンジニアのfro-rivです。 日々業務でたくさんのサーバに SSH 接続をしているわけですが、 ユーザ指定、公開鍵認証、ポート指定、ポート フォワ ーディングなどを管理できる ~/. ssh /config ファイルについて深掘りしてみました。 日頃から多くのサーバに接続をしており、 様々なオプションを付ける+覚える必要があって億劫な思いをしている人には役に立つのではないかと思いますので、 ぜひ目を通してみてください。 ~/.ssh/configってなに? configファイルを書くことで何が楽になるのか configファイルを作ってみよう 準備 パラメータ一覧 パターン別サンプルファイル パターン1:SSH接続するサーバ全体に対してホスト鍵認証でエラーが出ないようにする パターン2:接続先のユーザ名・ポートが違う場合 パターン3:ポートフォワーディングする 最後に 参考文献 ~/. ssh /configってなに? ~/. ssh /config ファイルとは、 SSH クライアント用の設定ファイルです。 このファイルに ホスト名(または IPアドレス ) 、 ユーザ名 、 SSH 接続時のオプション などを記入でき、 configファイルに記載しておくことで SSH 接続を行う際は上記の情報を省略することができます。 configファイルは各ユーザのホーム ディレクト リ配下の .ssh ディレクト リで管理します。 configファイルを書くことで何が楽になるのか 例えば、下の図のような感じで クライアントのrootユーザ から リモートサーバのtestuserに1022番ポートへ公開鍵認証 で SSH 接続する場合 本来は、 ## l→ユーザ名 p→ポート番号 i→クライアントの秘密鍵 ssh ${ホスト名 or IP} -l testuser -p 1022 -i ~/.ssh/id_rsa とコマンド入力しなければなりません。この1台だけならいいですが、これを何台分も覚えるのは... 上の設定を ~/. ssh /config に設定を記述すると、この記述のみで SSH 接続できます↓↓↓ ## "server"の部分は分かりやすい名前に変更可能 ssh server ちなみに、 ~/. ssh /config の記述はこんな感じ ## Host で指定した server という文字でSSH接続できる Host server Hostname ${接続先サーバのホスト名 or IP} User testuser Port 1022 IdentityFile ~/.ssh/id_rsa configファイルを作ってみよう 準備 下をコピペしてください。 ファイルの作成としてはこれで完了です。 次の章でパラメータについて紹介します。 # ユーザのホームディレクトリへ移動 cd ~ # ~/.sshディレクトリを作成(公開鍵認証をしている場合はすでに存在するはず) # ~/.sshディレクトリの権限は700にしておいてください mkdir -p -m 700 .ssh # configファイルを作成(権限はデフォルト644の状態でOK) touch config パラメータ一覧 以下に、よく使用するパラメータを表にまとめました。 下に行くにつれて使用頻度は低くなります。 パラメータ 説明 Host ホスト名 (接続時に使用する名前) Hostname ホスト名 or IPアドレス User ユーザ名 Port ポート (デフォルト: 22) IdentityFile クライアントの 秘密鍵 (デフォルト: ~/. ssh /id_ rsa ) StrictHostKeyChecking サーバのホスト認証鍵を. ssh /known_hostsに追加するか yes, no, ask (デフォルト: ask) no にしておけばfinger printが変わっても SSH 接続をはじかれない UserKnownHostsFile known_hostsファイル (デフォルト: ~/. ssh /known_hosts) ProxyCommand ポート フォワ ードする場合などに使用 使用例: ssh -W %h:%p ${踏み台ホスト名} ※%hは接続ホスト名, %pはポート ConnectionAttempts 接続試行回数 (デフォルト: 1) TCPKeepAlive サーバとの接続を保持 (デフォルト: yes) ServerAliveInterval 何秒間サーバの応答がなければ接続を閉じるか LogLevel ログの出力レベル (以下、右がより詳細) QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 もっと詳しい設定まで確認したい場合は、日本語版のmanをご覧ください。 ssh_config(5) manページ パターン別サンプルファイル 3パターンの ~/. ssh /config サンプルファイルを用意しましたので、参考にしてみてください。 パターン1: SSH 接続するサーバ全体に対してホスト鍵認証でエラーが出ないようにする 過去に存在していた SSH 接続経験のある IPアドレス やホスト名でサーバを構築しなおした場合、 以下のようなエラーが表示されることがあります。 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the ECDSA key sent by the remote host is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. Please contact your system administrator. Add correct host key in /root/.ssh/known_hosts to get rid of this message. Offending ECDSA key in /root/.ssh/known_hosts:XX ECDSA host key for [XXX.XXX.XXX.XXX]:1022 has changed and you have requested strict checking. Host key verification failed. これを回避するために、以下の設定を ~/. ssh /config に追記します。 Hostを "*( アスタリスク )" とすることで全ての SSH 接続に適用されます。 ### UserKnownHostsFile→何らかの拍子にフィンガープリントが変わっても接続がはじかれないようにする ### StrictHostKeyChecking→初回のログイン時も接続の可否を聞かれないようにする Host * StrictHostKeyChecking no UserKnownHostsFile=/dev/null 上記の設定を行うことで、 SSH 接続がホスト鍵認証の段階ではじかれることはなくなります。 新しいサーバに SSH 接続する機会が多い場合、おすすめの設定です。 ※但し、この設定は社内や家庭内などのLAN環境で使用することをお勧めします。  本来、なりすましを防ぐためのチェックのため、インターネットからアクセス可能なサーバには設定しない方がセキュリティ的に安全です。 パターン2:接続先のユーザ名・ポートが違う場合 最初の方の説明でも記載しましたが、以下のような場合です。 root@client.local から testuser@server.local:1022 に接続する場合(公開鍵認証設定済み) ## server という文字でSSH接続する想定 ## IdentityFileはデフォルトで`~/.ssh/id_rsa`なので省略可 Host server Hostname server.local User testuser Port 1022 IdentityFile ~/.ssh/id_rsa この設定をすることで # ssh server とコマンド入力するだけで testuer@server.local:1022 に接続できてしまいます。 パターン3:ポート フォワ ーディングする 先ほどのパターン2で紹介した server.local を中継させて、下の図の様に root@server2.local:22 に SSH 接続をしたいと思います。 ( testuser@server.local の公開鍵は root@server2.local:~/.ssh/authorized_keys に登録済み) ## server.localには server という文字でSSH接続する ## IdentityFileはデフォルトで`~/.ssh/id_rsa`なので省略可 Host server Hostname server.local User testuser Port 1022 IdentityFile ~/.ssh/id_rsa ## server2.localには server2 という文字でSSH接続する ## ProxyCommandオプションにて中継サーバを指定 Host server2 Hostname server2.local User root Port 22 ProxyCommand ssh -W %h:%p server IdentityFile ~/.ssh/id_rsa この設定を追記することで # ssh server2 とコマンド入力するだけで root@server2.local:22 に接続できます。 本来は、 # ssh -o ProxyCommand='ssh -W %h:%p testuser@server.local -p 1022' root@server2.local または # ssh root@172.20.100.137 -L 1022:testuser@172.20.100.128:22 といったように、長々とコマンドを打たなければなりませんが、そんな手間を ~/. ssh /config は解決してくれます。 更に、 scp コマンドでファイル転送をしないといけない場合も大活躍で、 root@client.local と root@server2.local 間でファイル転送を行う場合も scp server2:/tmp/test.file ./ scp ./test.file server2:/tmp/ と表記するだけでOKです。 最後に ~/.ssh/config ファイルを使用して、 SSH 接続を楽にするということでパラメータやパターン別の サンプルファイルを紹介させていただきました。 特に、サーバで SSHD の待ち受けポートを22番以外に設定しているサーバや、 ポート フォワ ーディングが必要なサーバの場合はconfigファイルが役に立つのではないかと思います。 また、 SSH 接続は勿論ですが、個人的にはポート フォワ ーディングしているサーバからSCPでファイル転送を行う際に 一番力を発揮してるなと感じました。 今回はconfigファイルでよく使用する頻度の高いパラメータを中心に紹介しましたが、 気になる方は下の参考文献で紹介しているmanページも確認してみてください。 というわけで、~/. ssh /configファイルで SSH 接続を楽にする方法の紹介でした。 参考文献 ~/. ssh /configについて - Qiita: https://qiita.com/passol78/items/2ad123e39efeb1a5286b . ssh /configファイルで SSH 接続を管理する https://qiita.com/0084ken/items/2e4e9ae44ec5e01328f1 ssh を config ファイルで管理して快適にする - WhiteNote https://s10i.me/whitenote/post/42 ssh _config(5) manページ https://nxmnpg.lemoda.net/ja/5/ssh_config ssh (1) - Linux man page https://linux.die.net/man/1/ssh エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは。技術広報の syoneshin です。 今回は当社イベントの中でも人気の高い 『エンジニアの勉強法ハックLT』 でLT発表された資料を、まとめてご紹介します。 ※各イベント詳細は以下 エンジニアの勉強法ハックLT- vol.1 エンジニアの勉強法ハックLT- vol.2 エンジニアの勉強法ハックLT- vol.3 エンジニアの勉強法ハックLT- vol.4 【目次】 日常生活の中にこそエンジニアの勉強はある! 知識を使って知識を増やす投資的勉強法 オンラインでもモブプログラミングを勉強法に取り入れてみる 自分の学習を Output して学習効率を高速にあげる 技術書へのアクセスを劇的に向上させた話 ゲームで学ぶマネジメント 私にとっての学び 面倒臭がりでもキャッチアップしたい- RE:Bot から始めるものぐさ生活 - 3日坊主でも勉強したい 自己学習を支える Inoreader + Notion 1日18時間 勉強する技術 やる気が出ない、そんなとき テスト、テスト、テスト! 振り返りを取り入れ、改善を楽しもう ドラゴン桜から学んだ勉強法 どっちがいいの?本で学ぶ vs Webで学ぶ KPTの空回りを防ぐ! エンジニアリングチーム 立ち上げの取り組み 勉強苦手人間の勉強法 自身の役割/フェーズによって、 効果的な学習法は変わるという話 YouTubeにハマっている若者の勉強法 詰まったときのPEIAサイクル 試行錯誤の勉強法 「〇〇完全に理解したったww」から始めるエンジニア生活 いちばん苦痛だったプログラミング研修を新人研修いちばんの思い出にした話 スキルが浅い中転職活動中にしてきたこと 日常生活の中にこそエンジニアの勉強はある! 発表者: 白栁隆司@エンジニアカウンセラー さん speakerdeck.com 知識を使って知識を増やす投資的勉強法 発表者: UT@TechnicalDonor さん qiita.com オンラインでもモブプログラミングを勉強法に取り入れてみる 発表者: YAMAKAWA, Hiroto さん speakerdeck.com 自分の学習を Output して学習効率を高速にあげる 発表者: @nappa_bebeji さん speakerdeck.com 技術書へのアクセスを劇的に向上させた話 発表者: 写真屋? LTの売人 さん speakerdeck.com ゲームで学ぶマネジメント 発表者: 白栁隆司@エンジニアカウンセラー さん speakerdeck.com 私にとっての学び 発表者: ariaki さん docs.google.com 面倒臭がりでもキャッチアップしたい- RE: Bot から始めるものぐさ生活 - 発表者: MINORU さん 面倒臭がりでもキャッチアップしたい- RE:Bot から始めるものぐさ生活 - from MinoruIto3 www.slideshare.net 3日坊主でも勉強したい 発表者: 脱脂綿/だっしー さん speakerdeck.com 自己学習を支える Inoreader + Notion 発表者: Logy(ロージー) さん speakerdeck.com 1日18時間 勉強する技術 発表者: @chooyan_i18n さん docs.google.com やる気が出ない、そんなとき 発表者: @TSawarabi さん https://speakerdeck.com/sawarabi/studyhacklt-yaruqi-gachu-nai-sonnatoki speakerdeck.com テスト、テスト、テスト! 発表者: @tomokon_0314 さん docs.google.com 振り返りを取り入れ、改善を楽しもう 発表者: @omokawa_yasu さん speakerdeck.com ドラゴン桜 から学んだ勉強法 発表者: @buntafujikawa さん speakerdeck.com どっちがいいの?本で学ぶ vs Webで学ぶ 発表者: 白栁隆司@エンジニアカウンセラー さん speakerdeck.com KPT の空回りを防ぐ! エンジニアリングチーム 立ち上げの取り組み 発表者: @shu038fw さん speakerdeck.com 勉強苦手人間の勉強法 発表者: @nana_csx さん speakerdeck.com 自身の役割/フェーズによって、 効果的な学習法は変わるという話 発表者: @ryu_f_web さん speakerdeck.com YouTube にハマっている若者の勉強法 発表者: @_4geru さん speakerdeck.com 詰まったときのPEIAサイクル 発表者: @d_murakami_0816 さん speakerdeck.com   以降はスピンオフ企画 『 駆け出しエンジニアの勉強法LT会 』 での LT発表資料になります。 試行錯誤の勉強法 発表者: @M_Yamashii さん speakerdeck.com 「〇〇完全に理解したったww」から始めるエンジニア生活 発表者: @ryusa_eng さん speakerdeck.com いちばん苦痛だったプログラミング研修を新人研修いちばんの思い出にした話 発表者: Masuda.S さん speakerdeck.com スキルが浅い中転職活動中にしてきたこと 発表者: @Y0u281 さん speakerdeck.com 以上いかがだったでしょうか? 本記事でご紹介の「エンジニアの勉強法」が皆さまの情報探索の一助となれば幸いです。 よろしければ、当社エンジニアがおすすめする勉強法もご覧ください。 tech-blog.rakus.co.jp また、ゲームや YouTube を利用した勉強ができる環境も整いつつあります。 詳しく知りたい方は以下の記事も ご覧ください。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp 今後も 『エンジニアの勉強法ハックLT』 を定期開催しますので、勉強法を学びたい方・共有したい方は以下Connpassページから ラク ス主催イベントをチェックいただき、ぜひご参加下さい! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 初めまして、tomo37kunです。 業務に携わる中でCI/CDの存在を意識することが多くなったので、CI/CDについて正しい知識と理解を得られるように学習を行いました。また、近年、自動化の重要性の高まりや アジャイル 開発の浸透進化といった背景から、実際にCI/CDに対する需要は急速に高まっています。 本記事のCI/CDの学習内容のアウトプットにより、CI/CDについて全く知識がない人でも体系的に理解できる足掛かりになれば幸いです。 はじめに CI/CDとは CI CD つまりCI/CDとは CI/CDのタイプ オンプレミス型 クラウド型 CI/CDが注目されるようになった理由 自動化テストの重要性の高まり アジャイル開発の浸透と進化 自動化できるタスク テスト実行の自動化 リリースの自動化 その他の作業の自動化 CI CD デプロイの自動化によるメリット リスクマネージメント フィードバックを素早く得る まとめ 参考資料 CI/CDとは まずはそれぞれの単語の意味からです。 CI CIとは「Continuous Integration」の略で、「 継続的インテグレーション 」と訳されています。 「インテグレーション」には「統合」の意味があります。 ソフトウェア開発の場合、「統合」の対象は一連の作業(各種作業やテストなど)です。 これでソフトウェアの動作を「継続的」に確認でき、より正確により迅速に開発を進めることが可能になります。 CD CD とは「Continuous Delivery」の略で、「継続的デリバリー」と訳されています。 一般的に「デリバリー」とは何かを届けることですが、この場合は「配信」や「公開」の意味で使われています。 「配信」するものは、開発テスト中のソフトウェア自体です。 なお「Delivery」と同じ頭文字で「Deployment」という用語も、「Continuous Deployment」(継続的デプロイメント)として使われています。 一般的に「デプロイメント」とは「配置」することですが、この場合は何らかのサービスを利用者が使える状態にすることです。 つまりCI/CDとは CI/CDは1つの技術を表すものではありません。 作業から 継続的インテグレーション (CI)および継続的デリバリー・デプロイ(CD)までを、自動化しておくことで、より効率良く迅速で、継続的に実施できるソフトウェア開発の手法のことです。 CI/CDを取り入れることで、バグを素早く発見することができたり、変更を自動でリリースすることができるようになります。 CI/CDのタイプ CI/CDには大きく分けてオンプレミス型と クラウド 型があります。 オンプレミス型としてはJenkins、 クラウド 型としては Travis CIやCircleCIなどが有名です。 オンプレミス型は一般的に拡張性が高い一方、自分たちで構築・運用する管理コストが発生します。 クラウド 型は拡張性が低いですが、サーバーなどを自前で用意する必要がなく、すぐに使い始めることができるのが大きな魅力です。 オンプレミス型 Jenkins Concoures CI Drone( クラウド 型もあり) クラウド 型 Travis CI Circle CI Wercker Codeship AWS CodeBuild GCP Cloud Build クラウド 型のCI/CDサービスである「Circle CI」の無料枠には以下の特性があるため個人開発や試し使いには十分と言えるので興味を持たれた方は試してみるとよいでしょう。 1コンテナのみ(したがって、同時実行ジョブは1つのみ) 1か月あたり1000分のビルド時間まで リポジトリ 数の制限なし ユーザ数の制限なし CI/CDが注目されるようになった理由 CI/CDが注目されるようになった理由としては2つのことが挙げられます。 自動化テストの重要性の高まり アジャイル 開発の浸透と進化 自動化テストの重要性の高まり あらゆる作業がコンピュータに置き換わっている現在、ソフトウェアを使用していない企業や組織はほとんどいないと言っても過言ではないと思われます。 このソフトウェアの普及に伴って、求められる品質も必然的に高くなり、これまで手動で行われていたテストも自動化されるのは当然の流れといえます。 CI/CDを使うと、コードの変更が発生するたびに自動でテストが行われるので、テストの実行忘れや、環境依存のテストを失くすことによる品質向上が狙えます。 ここまでの説明だけだと、CI/CDサービスやCI/CDのツールが自動でテストを作成してくれるように思えるかもしれませんが、そういうわけではありません。 あくまで、実行するテストは自分たちで定義する必要があり、CI/CDは定義したテストを任意のタイミングで実行してくれるだけのものになります。 アジャイル 開発の浸透と進化 アジャイル 開発の浸透と進化もCI/CDの普及を推し進めました。 アジャイル 開発とは小さな変更を積み上げるように加えていくことで、プロダクトを少しずつ開発していく手法のことです。 この手法が実際の開発現場で有効なことが分かり、現在は多くのチームが アジャイル 開発をするようになっています。 アジャイル 開発で最も重要とされていることはスピードです。 より小さな粒度の変更をいかに早くテスト/リリースしてフィードバックを得るかが アジャイル 開発の成功の鍵となりますが、CI/CDを使うことがこれらの実現にマッチしているため、CI/CDの普及につながりました。 そして、近年 アジャイル 開発そのものも進化しています。 Dockerや Kubernetes のコンテナ技術と AWS や GCP などの クラウド 技術が進歩したおかげで、本番環境にコードをデプロイすることは驚くほど簡単になりました。 テストをパスした変更を常にリリースして、バグがあれば ロールバック を行う。 このような作業はもちろん手動でもできますが、CI/CDで自動化することでより効率的にできるようになります。 まとめると、CI/CDを使うとテスト自動化することで品質を高めるだけではなく、その後のリリース作業も自動化することで、より アジャイル な開発ができるようになるということです。 自動化できるタスク CI/CDの本質は自動化にあります。 今まで手動で行っていた作業を自動化することにより開発者は別のタスクに時間を割くことができるようになります。 ここではCI/CDによって自動化できる以下のものについて紹介します。  1. テスト実行の自動化  2. リリースの自動化  3. その他の作業の自動化 テスト実行の自動化 最近のCI/CDサービスやツールは GitHub などの VCS ( バージョン管理システム )サービスと連携しています。 そのため、開発者が変更を加えるたびに、CI/CDが自動でテストを実行してくれます。 また連携するCI/CD上ですべてのテストをパスしないと変更をメインのブランチにマージできないような機能もあります。 これを活用すればテストが失敗したとき、その変更点を作成した開発者に修正を強制できるので、プログラムにおいて、直したはずのバグが復活していたり、前はなかったはずのバグがあったり、実装したはずの機能がなくなっている状態が生まれることを防ぎやすくなります。 リリースの自動化 一般的にリリース作業は運用チームや開発者が手動で行うものだと思われます。 しかし、このリリースを自動化することにより、 工数 の削減だけでなく、ヒューマンエラーを失くすことも可能です。 リリースの自動化にはいくつかのステージがあり、実際のデプロイは手動で行うケースもあれば、CI/CDで一気にデプロイまでするケースもあります。 どちらのケースがいいかは組織やプロダクトの性質ごとに異なるため、一概には言えません。 しかし、デプロイの自動化を行うことで次のようメリットを受けられます。 バグの迅速な修正 リスクマネー ジメント(詳しくは後述) 変更に対するフィードバックを素早く得る(詳しくは後述) 継続的インティグレーションにより、ある変更がテストに通らなかった場合、その変更に問題があったことが瞬時に分かるようになります。 言い返せば、テストをすべてパスした変更はリリースしても安全だということが分かります。 この時注意したいのは、すべてのシナリオに対してテストがあるわけではないですし、仕様バグなどはCI/CDを使っても取り除くことはできません。 その他の作業の自動化 コードの コンパイル 、静的解析、依存関係のアップデートはもちろん、CI/CDを使うことで、さまざまなことを自動化できます。 最近のCI/CDサービスやツールはとても柔軟に作られているので、ほとんどの作業をCI/CD上で自動化できます。 ※ハードウェアに依存する作業などはCI/CDサービスによってはできない場合もあります。  そのため、自動化したいタスクを思いついたときは、まずCI/CDを使えないか検討してみるとよいと思われます。 CI/CDが走るタイミングは以下の通りです。 CI pull-request作成した時 pull-request作成以降にpushした時 定期実行時(cron) CD mergeした時 ブランチによってデプロイ先を変えられる(masterブランチへmergeされたら本番環境、developブランチへmergeされたら検証環境など) 定期実行時(cron) デプロイの自動化によるメリット リスクマネー ジメント 変更Aと変更Bを個別にリリースする場合とAとBの変更をまとめた変更Cをリリースする場合を考えます。 リリースによって問題が発覚した場合、AとBは別に作業を行っているため、「変更Aに問題はなく変更Bに問題があったので、Bのみ対応を行った」というようにそれぞれ個別に対応することが可能です。 一方、変更CはAとBのどちらに問題が潜んでいるかの切り分けが複雑になってしまう可能性ある他、変更範囲が大きいため ロールバック が容易にできない場合があります。 このように リスクマネー ジメントの観点ではAとBを別々にリリースするべきであることが賢明といえます。 CI/CDによる継続的デプロイはこの リスクマネー ジメントを可能とします。 継続的デプロイができるということは、変更の ロールバック も簡単にできるということであり、問題があった変更点を取り消して再度デプロイをすれば、 ロールバック したことになるからです。 上述の リスクマネー ジメントの考えに乗っ取ると重要なのは ロールバック できる単位を小さくすることであると言えます。 継続的デプロイを用いることでこの ロールバック できる単位を刻むことができるのです。 また、 ロールバック による保険があるため、開発者はより挑戦的にコードを書くことができ、開発者の仕事は劇的にやりやすくなることが見込めます。 デプロイの自動化によって変更の粒度を小さくしてバグのリスクを下げることができれば、バグを恐れる必要はありません。 フィードバックを素早く得る ユーザが本当に求めるプロダクトを効率的に開発するには  1. 実用最低限の機能を作る  2. リリースする  3. フィードバックを得る 上記のループを素早く繰り返すことが大切です。 ユーザにとって価値があるかどうかわからない時でも本番環境でテストすることにより、フィードバックを素早く得られます。 「本番環境でテスト」という言葉に身のすくむ思いを抱かれるかもしれませんが、検証段階で必要かどうかを議論するよりも、本番環境で1度リリースし、フィードバックを集めてしまったほうが効率的な場合もあります。 そして、万が一不要な変更だったとしても継続的デプロイにより簡単に ロールバック ができるのです。 そのため、継続デプロイを使うことで本番環境からより早くフィードバックを得ることができるようになるのです。 まとめ CI/CDを使うことでさまざまな作業を自動化できるだけではなく、デプロイと ロールバック を自動化することでより効率的なプロダクト開発ができるようになります。 また、人力で行うテストとは異なり、人間に起因するミスが起きず、品質が担保されるというメリットもあります。 品質を落とさずに、高速な開発、リリースというサイクルを回すためには必須と言えます。 記事の途中でも触れましたが クラウド 型のCI/CDサービスである「Circle CI」では無料枠があり、個人レベルの使用であれば十分に利用できるので、興味を持たれた方はお試しください。 参考資料 【図解】CI/CD とは?非エンジニアの方向けにわかりやすく解説します | カゴヤのサーバー研究室 CI/CDのエキスパートが解説:CI/CDとは何か? なぜ今、必要とされるのか? (1/3):CodeZine(コードジン) いまさらだけどCircleCIに入門したので分かりやすくまとめてみた - Qiita CI/CDとは | ニフクラ エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 1. position: static の要素ではz-indexは効かない 2. 基本的にはHTMLの記述順に重なる 3. z-indexを指定した場合は数値の大きいものが上に重なる 4. 親子関係がある要素ではz-indexの数値に関係なく親の上に子が重なる 5. 親階層のz-indexの比較が優先して評価される おわりに はじめに こんにちは、フロントエンドチームの北嶋です。 今回は CSS 初学者がつまずきがちな、 z-index について書きたいと思います。 タイトルの「z-index:0とz-index:100ならどちらが上にくる?」の問いですが え、普通にz-index:100じゃないの?と思った方は残念ながら不正解です。 正解は「場合による」なんですよね。 CSS をしっかり勉強したことがある方なら簡単に分かるとは思いますが どのような場合にz-index:0が勝つのか どのような場合にz-index:100が勝つのか を正しく理解するために、z-index関連のルールを整理していきたいと思います。 1. position: static の要素ではz-indexは効かない 前提として position: static が指定されている要素では、z-indexは無効です。 position: static はデフォルトの値なので、z-indexを有効化するためには、 CSS で要素に position: static 以外を指定してあげる必要があります。 ※2以降で説明する要素には、すべて position: static 以外が指定されていることとします。 2. 基本的にはHTMLの記述順に重なる z-indexに数値の指定がなかった場合は、書いた順に要素は重なって行きます。 z-indexの数値が同じだった場合も、同様の挙動を示します。 See the Pen z-index_sample by hk-rks ( @hk-rks ) on CodePen . 3. z-indexを指定した場合は数値の大きいものが上に重なる こちらは直感的な動きですね。 z-index:100の方がz-index:0よりも数値が大きいので、z-index:100が上に重なってきます。 See the Pen z-index_sample_2 by hk-rks ( @hk-rks ) on CodePen . 4. 親子関係がある要素ではz-indexの数値に関係なく親の上に子が重なる 下のコードでは、z-index:100の親要素と、そこに属するz-index:50とz-index:10の子要素が二つあります。 まず、z-index:100の親要素が数値が一番大きいにも関わらず最も下に配置されていることが分かると思うのですが、これは要素同士に親子関係が形成されているからです。 用語としてはスタックコンテキストというのですが「親をベースとして階層が形成され、その上に子要素集合の階層が形成される」というイメージで理解してもらえればOKです。 子要素同士では同じ階層なので、z-index50がz-index:10よりも大きいので上に重なるという通常のz-indexの動作を示していますね。 See the Pen z-index_sample_1 by hk-rks ( @hk-rks ) on CodePen . 5. 親階層のz-indexの比較が優先して評価される 下のコードでは以下の要素があります。 z-index:100の親要素と、そこに属するz-index:10の子要素 z-index:0の親要素と、そこに属するz-index:20の子要素 注目すべきは、子要素同士ではz-index:10とz-index:20の二つの要素がありますが、z-index:10の方が上に来ている点です。 こちらもスタックコンテキストの考え方を適用すれば理解しやすいのです。 まず親要素同士ではz-index:100とz-index:0の二つの要素があって、z-index:100が上に来ていますね。 この親階層をベースとして、子要素が上に乗っているので z-index:100の上に乗っているz-index:10 z-index:0の上に乗っているz-index:20 では前者の方が上に重なるということになります。 つまり、親階層でのz-indexで負けていたら子要素の方でいくらz-indexを大きくしても上に重なることはできないということですね。 See the Pen WNRmQyr by hk-rks ( @hk-rks ) on CodePen . おわりに ここまで理解できれば、タイトルの問いの答えが「場合による」ことが分かってきたのではないでしょうか? 記事を書いていて、僕自身が初学者の頃にひらすらz-indexを大きくしていた時期が懐かしく思い出しました笑 更に理解を深めたい方は「スタックコンテキスト」で調べると詳しい情報がたくさん出てきますので、ぜひ参考にしてみて下さい。 それでは、ここまで読んでいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 技術広報のyayawowoです。 いつも ラク スのエンジニアブログのご購読、そしてエンジニアイベントへのご参加、ありがとうございます。 ラク スでは、現場最前線のエンジニア達から普段の活動や開発・運用で得た知見などの技術情報をお届けするイベント・・・ 『Meetup』 を年に数回開催しております。 そして、2021年度1発目となる今回のMeetupも大盛況に終わりましたので、その中身についてまとめさせていただきました! はじめに イベントテーマ概要 発表の紹介 Mail Dealerにおけるインフラ基盤の歴史と生産性向上について スモークE2Eテストで20年モノのシステムからバグを燻し出す方法 返したいけど返せない、大きな技術的負債を返すために おわりに イベントテーマ概要 今回は、世の中の多くのエンジニア組織が抱える 『技術的負債』 と、チームの力を最大化するための 『生産性向上』 をテーマとしております。 弊社エンジニアから、以下サービスに関わるこれまでの取り組みと今後の展望について、ご紹介させていただきました! メールディーラー 楽楽販売 発表の紹介 それではここから各発表内容と資料を共有させていただきます! Mail Dealerにおけるインフラ基盤の歴史と生産性向上について 初めに、Mail Dealerのインフラ担当である中井の発表です。 ラク スに入社した当時、Mail Dealerのサーバ台数は現在の半数程度の規模ながら、すべて物理サーバで運用していました。 サービス立ち上げ当初からの機器も手付かずな状態で、様々な問題が顕在化しており、抜本的な改善が急務でした。 それから9年が経過し、現在はオンプレ環境での『オール仮想化』を実現することで、クリアとなった問題もたくさんありますが、新たな課題も生まれています。 今回の発表では、Mail Dealerのインフラ基盤の歴史を振り返りながら、その変化の過程でどのようなポイントに着目して改善を行い、生産性向上に結び付けてきたかを、事例を踏まえてご紹介しました。 MD Infra history from motoharunakai www.slideshare.net スモークE2Eテストで20年モノのシステムからバグを燻し出す方法 次は、Mail Dealerの開発担当である桑原からのご紹介です。 Mail Dealerは約20年続く大きなシステムであり、画面数も機能数も多いため、思いもよらない箇所でバグが発生する恐れがあります。 そのため、品質には特に気を配る必要があります。 しかし品質は上げたい一方でどの組織でもあるように、新規開発に追われ、人と時間が足りない状況が常態化していました。 そんなMail Dealerでは高コストな自動テストではなく、「スモークE2E」という簡易的なE2Eテストを増産する取り組みを始めました。 限られたリソースの中でメンバーを巻き込みながら品質を担保する取り組みについてご紹介しました。 speakerdeck.com 返したいけど返せない、大きな技術的負債を返すために 最後は、リリース13年目となる息の長いサービスである楽楽販売を担当している水間の発表です。 サービスが続くのは嬉しいことですが、いわゆる技術的負債はどうしても蓄積して続けてしまいます。 楽楽販売でも長い間、返したいけど返せない負債がありましたが、その中の一部をついに返済する機会がありました。 一般的に、負債の蓄積は避けがたいものであり、 リファクタリング 等の機会も限られているかと思います。 その中でどう返済チャンスを作っていくべきか、今回の体験を振り返りさせていただきました。 speakerdeck.com おわりに 大規模な SaaS サービス開発と20年以上向き合っている ラク スだからこその発表はどうだったでしょうか。 ラク スの取り組みが、皆さまにとって新しい気づきや成長につながる機会となっていますと幸いです! 今後も ラク スMeetupでは日々のエンジニアの取り組みを発信してまいりますので、次回もぜひご参加いただけますと幸いです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは、matsutairaです。僕は普段 Atom という テキストエディタ を使用しており、実用的な プラグイン から面白い プラグイン など必要な プラグイン を入れて作業しています。個人的には、実用的な プラグイン より面白い プラグイン を使うのが好きですが、見つけるのも大変なので自分で プラグイン の作成ができないかと思い作成方法を調べてみました。今回は調べた内容を元に プラグイン の作成を行いたいと思います。 目次 はじめに Atomとは プラグインとは プラグイン作成 パッケージ生成 パッケージ構造 機能作成 おわりに Atom とは そもそも Atom とは、 GitHub が開発した オープンソース の テキストエディタ です。 メリット UIが直観的で使いやすい 無料公開の プラグイン が多数存在し、作業効率アップや息抜きになる プラグイン 同様多数のテーマがあり、カスタマイズ性が高い ショートカットが使いやすい デメリット 起動に多少時間がかかる 動作が重い場合がある とはいえ オープンソース であること、かつデメリットを補えるだけのメリットがあるため、使う価値のある テキストエディタ だと思います。使ったことが無い方はこの機会に是非使ってみてください。 atom.io プラグイン 作成 本題の プラグイン の作成に入ります。今回作成する プラグイン は「入力を検知し何かをする」をコンセプトに作成したいと思います。 パッケージ生成 Atom にはデフォルトでパッケージジェネレータというものが存在しており、 プラグイン の作成に必要なパッケージの雛形を自動で生成してくれます。 メニューバーの[パッケージ]から[パッケージ ジェネレータ]を選択します。まずは雛形を生成してみましょう。 ※コマンドパレット( Ctrl+Shift+P )から「Package Generator: Generate Package」でも生成できます。 保存する場所と名前を入力し[Enter]を押します。 今回は「erai- bot 」という名前で作成します。 生成が完了すると新規でウィンドウが立ち上がります。 たったこれだけで プラグイン の作成に必要な雛形を簡単に作ることができ、デフォルトでこの機能が入っているのはかなりありがたいです。 パッケージ構造 次はパッケージの構造を見てみましょう。 erai-bot ├ keymaps │ └ erai-bot.json ├ lib │ ├ erai-bot-view.js │ └ erai-bot.js ├ menus │ └ erai-bot.json ├ spec │ ├ erai-bot-spec.js │ └ erai-bot-view-spec.js ├ styles │ └ erai-bot.less ├ .gitignore ├ CHANGELOG.md ├ LICENSE.md ├ package.json └ README.md keymaps: キーバインド の定義 lib:機能の定義 menus:メニュー表示の定義 spec:テスト用フォルダ styles: css やlessによるスタイルの定義 package. json :packageの定義を記述 というような構造になっています。今回はkeymaps、libの2つのみを編集していきます。 ※自分で作成する プラグイン は、 C:/Users/~/github/erai-bot 配下に置かれ、同時に C:/Users/~/.atom/packages 配下(インストールした プラグイン が格納される場所)にショートカットが作成されます。 機能作成 それでは実際に機能を作成していきます。 まずは使える AtomAPI を確認しましょう。 数ある API の中から今回は TextEditor という API と NotificationManager を利用します。 NotificationManager:画面右上にメッセージを表示 TextEditor:文字入力検知や文字の自動入力、削除、セーブの検知が可能 この2つの API を基本に作成します。 まずは、生成したままの プラグイン を起動してみます。デフォルトでは Ctrl+Alt+O がショートカットになります。 このままでは、 プラグイン を起動/停止したときに毎回表示されてしまいますし、ON/OFF状態がわかりずらいので右上にメッセージを表示してみます。 以下のように erai-bot.js を編集します。 toggle() { atom.notifications.addInfo( 'ON/OFF' ); // ↓使用しないのでコメントアウトor削除 // console.log('EraiBot was toggled!'); // return ( // this.modalPanel.isVisible() ? // this.modalPanel.hide() : // this.modalPanel.show() // ); } atom .notifications.addInfoを使うことで画面右上にメッセージを表示できます。 nofiticationsの種類は、 * Success * Info * Worning * Error * FatalError の5種類あり、それぞれ種類によって色やアイコンが変わります。optionでアイコンを設定することも可能です。 編集した箇所の反映は Ctrl+S だけではできないので、保存とウィンドウをリロード Ctrl+Shift+F5 をします。 もう一度 プラグイン を起動させてみます。 画面右上にメッセージが表示されるようになりました。しかしこのままだと プラグイン の起動/停止をするごとにメッセージが表示されるので、まだ起動状態かがわかりません。さらに記述していきます。 toggle() { this .active = ! this .active; if ( this .active) { return this .disable(); } else { return this .enable(); } // atom.notifications.addInfo('ON/OFF'); } , enable() { atom.notifications.addInfo( 'えらい!bot起動' ); } , disable() { atom.notifications.addInfo( 'えらい!bot停止' ); } 新たにenable関数とdisable関数を追加しました。これにより プラグイン が起動している状態からは停止→disable関数呼び出し、 プラグイン が停止している状態からは起動→enable関数呼び出しに遷移することが可能となりました。 次は文字を入力するだけで褒められるようにします。 まず、activate関数部分を編集します。ここには プラグイン の読み込み時にロードされる内容を記述します。 activate(state) { this .eraiBotView = new EraiBotView(state.eraiBotViewState); this .modalPanel = atom.workspace.addModalPanel( { item: this .eraiBotView.getElement(), visible: false } ); // 入力検知用 this .editor = atom.workspace.getActiveTextEditor(); this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable this .subscriptions = new CompositeDisposable(); // Register command that toggles this view this .subscriptions.add(atom.commands.add( 'atom-workspace' , { 'erai-bot:toggle' : () => this .toggle() } )); } , 次は、enable関数とdisable関数を編集します。 enable() { // 起動時に有効化 this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); atom.notifications.addInfo( 'えらい!bot起動' ); } , disable() { // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } , 次は、onChange関数を作成します。 onChange(input) { atom.notifications.addInfo( '入力できてえらい!' ); } 入力するたびに「入力できてえらい!」と褒められるようになりました。 プラグイン の起動中はエディタ上に変化がある度にメッセージが表示されるので、EnterやSpaceの入力でも褒められます。 また、 onChange(input) { if (input.newText === " \n " ) { atom.notifications.addInfo( 'Enter押せてえらい!' ); } } のようにすることで、Enterの入力のみを検知することも可能です。 ただし、エディタ上へ入力したもののみ検知できるので、CtrlやShitfは検知できないので注意が必要です。 最後に保存するたびに褒められるようにします。 まず、activate関数部分を編集します。 activate(state) { this .eraiBotView = new EraiBotView(state.eraiBotViewState); this .modalPanel = atom.workspace.addModalPanel( { item: this .eraiBotView.getElement(), visible: false } ); // 入力検知用 this .editor = atom.workspace.getActiveTextEditor(); this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); // 保存検知用 this .editorSaveSubscription = this .editor.getBuffer().onDidSave( this .onSave.bind( this )); // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable this .subscriptions = new CompositeDisposable(); // Register command that toggles this view this .subscriptions.add(atom.commands.add( 'atom-workspace' , { 'erai-bot:toggle' : () => this .toggle() } )); } , 次は、enable関数とdisable関数を編集します。 enable() { // 起動時に有効化 this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); this .editorSaveSubscription = this .editor.getBuffer().onDidSave( this .onSave.bind( this )); atom.notifications.addInfo( 'えらい!bot起動' ); } , disable() { // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); this .editorSaveSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } , 最後にonSave関数を作成します。 onSave() { atom.notifications.addSuccess( '保存できてえらい!' ); } プラグイン の起動中は保存をするたびに「保存できてえらい!」と褒められるようになりました。 最後にショートカットキーを変えます。変更は keymaps にある erai-bot.json を編集します。 { " atom-workspace ": { " ctrl-alt-q ": " erai-bot:toggle " } } これで Ctrl+Alt+Q で プラグイン の起動/停止ができるようになりました。 一通りの動作はこれで完了ですが、若干物足りないのでさらに機能を追加しましょう。 一定時間入力がない場合にメッセージを表示する設定を入れます。 var timeoutId; // 中略 onChange(input) { // タイマー停止 clearTimeout(timeoutId); atom.notifications.addInfo( '入力できてえらい!' ); this .startTimer(); } , // 中略 disable() { // タイマー停止 clearTimeout(timeoutId); // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); this .editorSaveSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } , // 中略 startTimer() { // 60秒後にメッセージを表示 timeoutId = setTimeout(() => { atom.notifications.addError( '休憩できてえらい!' ); } , 60000); } 某太陽神の名言を表示しつつ、 プラグイン の起動状態を強制的に維持する設定を入れます。 var count = 0; // 中略 disable() { if (count < 1) { // アクティブ状態に強制移行 this .active = ! this .active; count = count + 1; atom.notifications.addError( '諦めんなよ!' ); atom.notifications.addError( '諦めんなよ、お前!!' ); atom.notifications.addError( 'どうしてそこでやめるんだ、そこで!!' ); atom.notifications.addError( 'もう少し頑張ってみろよ!' ); atom.notifications.addError( 'ダメダメダメ!諦めたら!' ); atom.notifications.addError( '周りのこと思えよ、応援してる人たちのこと思ってみろって!' ); atom.notifications.addError( 'あともうちょっとのところなんだから!' ); atom.notifications.addError( '俺だってこのマイナス10度のところ、しじみがトゥルルって頑張ってんだよ!' ); atom.notifications.addError( 'ずっとやってみろ!必ず目標を達成できる!' ); atom.notifications.addError( 'だからこそNever Give Up!!' ); } else { // タイマー停止 clearTimeout(timeoutId); count = 0; // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); this .editorSaveSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } } , 何秒後にメッセージを表示するかとオン状態の維持回数をユーザが設定できるようにします。 config: { "TimeSetting" : { "type" : "integer" , "default" : 60, "description" : "最終入力時間から何秒経過後にコメントを表示するか" } , "CountSetting" : { "type" : "integer" , "default" : 1, "description" : "強制的に機能ON状態を継続する回数" } } , // 中略 disable() { if (count < (atom.config.get(`erai-bot.CountSetting`))) { // アクティブ状態に強制移行 this .active = ! this .active; count = count + 1; atom.notifications.addError( '諦めんなよ!' ); atom.notifications.addError( '諦めんなよ、お前!!' ); atom.notifications.addError( 'どうしてそこでやめるんだ、そこで!!' ); atom.notifications.addError( 'もう少し頑張ってみろよ!' ); atom.notifications.addError( 'ダメダメダメ!諦めたら!' ); atom.notifications.addError( '周りのこと思えよ、応援してる人たちのこと思ってみろって!' ); atom.notifications.addError( 'あともうちょっとのところなんだから!' ); atom.notifications.addError( '俺だってこのマイナス10度のところ、しじみがトゥルルって頑張ってんだよ!' ); atom.notifications.addError( 'ずっとやってみろ!必ず目標を達成できる!' ); atom.notifications.addError( 'だからこそNever Give Up!!' ); } else { // タイマー停止 clearTimeout(timeoutId); count = 0; // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); this .editorSaveSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } } , // 中略 startTimer() { // ユーザ設定から秒数を取得 var time = atom.config.get(`erai-bot.TimeSetting`); timeoutId = setTimeout(() => { atom.notifications.addWarning( '休憩できてえらい!' ); } , time * 1000); } 以上で プラグイン は完成です。 プラグイン のコードは以下に記載しますので、気になった方はこちらを参考に プラグイン の作成に役立ててみてください。 'use babel' ; import EraiBotView from './erai-bot-view' ; import { CompositeDisposable } from 'atom' ; // グローバル変数 var timeoutId; var count = 0; export default { // ユーザ設定用 config: { "TimeSetting" : { "type" : "integer" , "default" : 60, "description" : "最終入力時間から何秒経過後にコメントを表示するか" } , "CountSetting" : { "type" : "integer" , "default" : 1, "description" : "強制的に機能ON状態を継続する回数" } } , eraiBotView: null , modalPanel: null , subscriptions: null , activate(state) { this .eraiBotView = new EraiBotView(state.eraiBotViewState); this .modalPanel = atom.workspace.addModalPanel( { item: this .eraiBotView.getElement(), visible: false } ); // 入力検知用 this .editor = atom.workspace.getActiveTextEditor(); this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); // 保存検知用 this .editorSaveSubscription = this .editor.getBuffer().onDidSave( this .onSave.bind( this )); // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable this .subscriptions = new CompositeDisposable(); // Register command that toggles this view this .subscriptions.add(atom.commands.add( 'atom-workspace' , { 'erai-bot:toggle' : () => this .toggle() } )); } , deactivate() { this .modalPanel.destroy(); this .subscriptions.dispose(); this .eraiBotView.destroy(); } , serialize() { return { eraiBotViewState: this .eraiBotView.serialize() } ; } , toggle() { this .active = ! this .active; if ( this .active) { return this .disable(); } else { return this .enable(); } } , enable() { // 起動時に有効化 this .editorChangeSubscription = this .editor.getBuffer().onDidChange( this .onChange.bind( this )); this .editorSaveSubscription = this .editor.getBuffer().onDidSave( this .onSave.bind( this )); atom.notifications.addInfo( 'えらい!bot起動' ); } , disable() { if (count < (atom.config.get(`erai-bot.CountSetting`))) { // アクティブ状態に強制移行 this .active = ! this .active; count = count + 1; atom.notifications.addError( '諦めんなよ!' ); atom.notifications.addError( '諦めんなよ、お前!!' ); atom.notifications.addError( 'どうしてそこでやめるんだ、そこで!!' ); atom.notifications.addError( 'もう少し頑張ってみろよ!' ); atom.notifications.addError( 'ダメダメダメ!諦めたら!' ); atom.notifications.addError( '周りのこと思えよ、応援してる人たちのこと思ってみろって!' ); atom.notifications.addError( 'あともうちょっとのところなんだから!' ); atom.notifications.addError( '俺だってこのマイナス10度のところ、しじみがトゥルルって頑張ってんだよ!' ); atom.notifications.addError( 'ずっとやってみろ!必ず目標を達成できる!' ); atom.notifications.addError( 'だからこそNever Give Up!!' ); } else { // タイマー停止 clearTimeout(timeoutId); count = 0; // disposeで入力検知を停止 this .editorChangeSubscription.dispose(); this .editorSaveSubscription.dispose(); atom.notifications.addInfo( 'えらい!bot停止' ); } } , onChange(input) { // タイマー停止 clearTimeout(timeoutId); atom.notifications.addInfo( '入力できてえらい!' ); // タイマー開始 this .startTimer(); } , onSave() { atom.notifications.addSuccess( '保存できてえらい!' ); } , startTimer() { // ユーザ設定から秒数を取得 var time = atom.config.get(`erai-bot.TimeSetting`); // タイマーのIDを取得しつつタイマー開始 timeoutId = setTimeout(() => { atom.notifications.addWarning( '休憩できてえらい!' ); } , time * 1000); } } ; おわりに プラグイン の作成はそこまで難しいことはなく、 JavaScript の知識さえあれば簡単に作成できました。僕自身 JavaScript の知識はほぼ皆無なので、この程度の プラグイン しか作成できませんでしたが、少しの知識でも プラグイン を作成することができました。個人的には、アニメーションや音等が出るような面白い プラグイン を作成したかったですが、できることはできたかなと思います。 プラグイン の作成自体、試行錯誤を重ねながらだったため、新鮮で勉強にもなりました。より勉強を重ねて自分の納得する プラグイン を作成できればと思います。 皆さんも Atom で自分だけのオリジナル プラグイン を作成してみてはいかがでしょうか。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 技術広報のyayawowoです。 皆さんは、業務中に Excel (エクセル)を利用される機会が多いのではないでしょうか。 Excel (エクセル)には便利な関数がとても多くあります。 今回は、 Excel 初心者向けにビジネスシーンで多く利用されている Excel (エクセル)の中でも、 IF関数 に特化し、使い方をまとめました。 基本的な使い方となりますので、 Excel (エクセル)初心者の方だけでなく、復習をしたい方のご参考になれば幸いです。 はじめに Excel(エクセル)のIF関数とは Excel(エクセル)のIF関数 - 使い方(入門編)- 例題 実践 IF関数と論理式 Excel(エクセル)のIF関数 - 使い方(応用編)- IF関数と複数条件 例題 実践 Excel(エクセル)のIF関数とAND関数・OR関数 IF関数とAND関数 例題 実践 IF関数とOR関数 例題 実践 IF関数と空白(空欄) 例題 実践 IF関数とVLOOKUP関数 例題 実践 まとめ Excel (エクセル)のIF関数とは まず初めに、 Excel (エクセル)のIF関数とはどのようなことができるでしょうか。 簡単にいいますと… IF関数とは 「設定した条件によって、指定された値を返す関数」 のこと Excel (エクセル)のIF関数について、数式を利用した簡単な解説は以下のようになります。 = IF( ① ●●が▲▲だったら【条件】 , ② 設定した値を表示【条件一致】, ③ 設定した値を表示【条件不一致】 ) ①:条件を指定する ②:条件に一致する場合、表示したい値を指定 ③:条件に一致しない場合、表示したい値を指定 では、イメージがついたところでIF関数の使い方に入っていきます。 まずは、入門編からです。 Excel (エクセル)のIF関数 - 使い方(入門編)- 入場料の計算を例題にしていきたいと思います。 例題 入場料が以下条件の動物園があります。 20歳未満の入場料:1,000円 20歳以上の入場料:2,000円 ある旅行会社では、動物園の入場料をまとめるために名簿を作成しました。 各々の入場料がいくらになるか Excel (エクセル)の IF関数 を活用して算出してみましょう! 赤枠箇所の条件を、 以下の通りにすれば良いことがわかります。 = IF( ① 年齢が20歳以上だったら【条件】 , ② 2,000円を表示【条件一致】, ③ 1,000円を表示【条件不一致】 ) この式を使って、 Excel (エクセル)のIF関数の使い方を解説します。 実践 1. 設定した条件に合わせて、 Excel (エクセル)で表を作成します。 2.、 Excel (エクセル)で 作成した表のセルに式を入力します。 D6 に =IF( と入力 Excel (エクセル)が自動で候補の関数を =IF(論理式,[真の場合],[偽の場合]) に式を入力 論理式・・・【条件】 年齢が20歳以上だったら: C6>=20 年齢: C6 20歳以上: >=20 真の場合・・・【条件一致】 2,000円を表示: $C$3 2,000円を手入力しても良いが、汎用的に利用したいため C3 を指定する オートフィルでコピーをした際、セルがずれないように絶対参照 $ で固定する 偽の場合・・【条件不一致】 1,000円を表示: $C$2 1,000円を手入力しても良いが、汎用的に利用したいため C2 を指定する オートフィルでコピーをした際、セルがずれないように絶対参照 $ で固定する ◆式: =IF(C6>=20,$C$3,$C$2) が完成◆ 3. オートフィル 1 で式をコピーします。 D6 に入力した式を D7 、 D8 にもコピーしたいですよね。 そのようなときにオートフィルを利用します。 D6 セルの右下にカーソルをあてる 十字(+)のようなマークがでましたら、クリックしたまま下に引っ張る D7 、 D8 に式がコピーされ、条件通りの値が表示される 20歳以上である ラク ス花子さんと花見 ラク 子さんの入場料が「2,000円」であることがわかります。 Excel (エクセル)のIF関数は覚えてしまえばとても便利な機能です。 様々な場面で活用できるよう、この機会にしっかりと覚えてしまうことをお勧めします。 IF関数と論理式 Excel (エクセル)のIF関数で入力する論理式ですが、 「どのような式にすればいいの?」 「この条件の時、記号は何を使えば・・・」 と、迷われる方もいるかと思います。 以下の通り、少し簡単にまとめましたので、ご参考いただけますと幸いです。 条件 式 C6>20 C6データ(年齢)が20歳より大きい C6>=20 C6データ(年齢)が20歳以上 C6<20 C6データ(年齢)が20歳より小さい(未満) C6<=20 C6データ(年齢)が20歳以下 C6=20 C6データ(年齢)が20歳と等しい(同じ) C6<>20 C6データが20歳と等しくない(異なる) Excel (エクセル)のIF関数 - 使い方(応用編)- Excel (エクセル)のIF関数は、複数の条件を組み合わせて利用することも可能です。 ここからは応用的な使い方について解説をしていきたいと思います。 IF関数と複数条件 応用編では、入門編で扱った例題を再度利用します。 例題 以下の通り入場料の条件を変更しました。 入門編では、「20歳以上」という1つの条件で事足りましたが、そこに以下のような「20歳以上40歳未満」と「40歳以上」の条件が加わった場合はどのようにIF関数の式を作成すれば良いでしょうか。 20歳以上の入場料:1,000円 20歳以上40歳未満の入場料:2,000円 40歳以上の入場料:1,500円 では、複数条件を使った Excel (エクセル)のIF関数について説明していきます。 実践 1. Excel (エクセル)で作成した表のセルに式を入力します。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 20歳未満だったら: C7<20 真の場合・・・【条件一致】 1,000円を表示: $C$ 偽の場合・・【条件不一致】 次の条件:IF関数を追加・・・ (IF(論理式,[真の場合],[偽の場合])) 論理式・・・【条件】 40歳以上だったら: C7>=40 真の場合・・・【条件一致】 1,500円を表示: $C$4 偽の場合・・【条件不一致】 2,000円を表示: $C$3 ◆式: =IF(C7<20,$C$2,IF(C7>=40,$C$4,$C$3)) が完成◆ 2. オートフィルで式をコピーします。 D7 の式をオートフィルを利用して D8~D10 にコピーします。 D7 セルの右下にカーソルをあてる 十字(+)のようなマークがでましたら、クリックしたまま下に引っ張る D8 、 D9 、 D10 に式がコピーされ、条件通りの値が表示される 45歳である楽楽次郎さんの入場料が1,500円であることがわかります。 また、25歳の ラク ス花子さんと20歳の花見 ラク 子さんの入場料は2,000円と正しく算出できています。 このように、条件が複数となった場合でも、 Excel (エクセル)のIF関数を利用して簡単に計算することができますね! Excel (エクセル)のIF関数とAND関数・OR関数 Excel (エクセル)のIF関数ではさらに、より複雑な処理ができます。 次はIF関数と「AND関数(かつ)」と「OR関数(または)」の使い方について説明します。 IF関数とAND関数 例題 以下条件の試験を例題にAND関数の使い方を説明します。 80歳以上:合格 80歳未満:不合格 実践 1. Excel (エクセル)で作成した表のセルに式を入力します。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 午前試験が80点以上かつ、午後試験が80点以上だったら: (C6>=80,D6>=80) 真の場合・・・【条件一致】 合格を表示: $C$2 偽の場合・・【条件不一致】 不合格を表示: $C$3 ◆式: `IF(AND(C6>=80,D6>=80),$C$2,$C$3) が完成◆ 2. オートフィルで式をコピーします。 E6 の式をオートフィルを利用して E7~E9 にコピーします。 E6 セルの右下にカーソルをあてる 十字(+)のようなマークがでましたら、クリックしたまま下に引っ張る E7 、 E8 、 E9 に式がコピーされ、条件通りの値が表示される 今回用意した例題は、「午前試験が80点以上かつ(AND)、午後試験が80点以上」の人だけが合格となります。 表から読み解く通り、合格者は ラク ス太郎さんだけであることがわかります。 合否判定も正しくされていますね。 IF関数とOR関数 例題 次は、以下条件の試験を例題に、OR関数の使い方を説明します。 80歳以上:合格 80歳未満:不合格 実践 1. Excel (エクセル)で作成した表のセルに式を入力します。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 午前試験が80点以上または、午後試験が80点以上だったら: OR(C6>=80,D6,>=80) 真の場合・・・【条件一致】 合格を表示: $C$2 偽の場合・・【条件不一致】 そうでなければ、不合格を表示: $C$3 ◆式: =IF(OR(C6>=80,D6>=80),$C$2,$C$3) が完成◆ 2. オートフィルで式をコピーします。 E6 の式をオートフィルを利用して E7~E9 にコピーします。 E6 セルの右下にカーソルをあてる 十字(+)のようなマークがでましたら、クリックしたまま下に引っ張る E7 、 E8 、 E9 に式がコピーされ、条件通りの値が表示される OR関数の例題は、「午前試験が80点以上または、午後試験が80点以上」の人だけが合格となります。 午前・午後試験の両方とも80点以上がないのは楽楽次郎さんだけですので、IF関数の式が間違っていないことが確認できました。 IF関数と空白(空欄) 例題 例題としてあげていた合否判定ですが、もし合格の人だけを知りたい試験があったとします。 受験者が少ない試験でしたら、今まで通り合格・不合格の表示をしても良いと思うのですが、人数が多い場合はどうでしょうか。 以下のように表示してしまうと少し見にくくなりますよね。 Excel (エクセル)のIF関数では、空白(空欄)を指定することもできますので、次はその説明をしたいと思います。 実践 1. Excel (エクセル)で作成した表のセルに式を入力します。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 点数が80点以上だったら: C6>=80 真の場合・・・【条件一致】 合格を表示: $C$2 偽の場合・・【条件不一致】 空白(空欄)を表示: "" ◆式: =IF(C6>=80,$C$2,"") が完成◆ 2. オートフィルで式をコピーします。 D6 の式をオートフィルを利用して D7~D16 にコピーします。 D6 セルの右下にカーソルをあてる 十字(+)のようなマークがでましたら、クリックしたまま下に引っ張る D7~D16 に式がコピーされ、条件通りの値が表示される どうでしょうか。 合格の人だけをすぐに見つけられる表になりました。 このように、IF関数で空白(空欄)を表示する式を作ることができます。 ちなみにですが、以下の通り論理式に空白(空欄)を指定することもできます。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 点数が空白(空欄)だったら: C6="" 真の場合・・・【条件一致】 不合格を表示: $C$3* 偽の場合・・【条件不一致】 合格を表示: $C$2 ◆式: =IF(C6="",$C$3,$C$2)</span></b> が完成◆ IF関数とVLOOKUP関数 最後は Excel (エクセル)のIF関数とVLOOKUP関数を組み合わせた応用的な使い方を説明します。 まず、VLOOKUP関数を初めて聞く方もいるかと思いますので、簡単にまとめると以下になります。 今回は Excel (エクセル)のIF関数についての説明を中心にしていますので、VLOOKUP関数の使い方は別でご確認いただけますと幸いです。 = VLOOKUP( ① 検索したい値を設定【検索値】 , ② 検索する範囲を設定【範囲】, ③ 設定した範囲の列番号を設定【列番号】, ④ 検索する際の型を設定【検索の型】 ) では、早速例題にうつります。 例題 以下条件に応じて、 E6 セルに入力した人の合否判定を行う表を作成する。 80歳以上:合格 80歳未満:不合格 実践 1. まずVLOOKUP関数で名前に紐づいた点数を検索します。 「=VLOOKUP( 検索値,範囲,列番号,[検索の型] )」の通り、式を埋めていく 検索値 検索したい名前( ラク ス太郎)を指定: E6 範囲 点数表の範囲から検索する: B6:C9 列番号 検索値があれば、指定した範囲の左から2列目の点数を返す: 2 検索の型 ただし、検索値は完全一致で返す: FALSE ◆式: =VLOOKUP(E6,B6:C9,2,FALSE) が完成◆ 以下の通り、名前に紐づいた点数を返すことができましたので、この結果に応じて合否判定もしていきたいと思います。 2. Excel (エクセル)のIF関数を利用して合否判定を行います。 =IF(論理式,[真の場合],[偽の場合]) の通り、式を埋めていく 論理式・・・【条件】 もし検索した点数が80点以上だったら: VLOOKUP(E6,B6:C9,2,FALSE)>=80 真の場合・・・【条件一致】 合格を表示: $C$2 偽の場合・・【条件不一致】 不合格を表示: $C$3 ◆式: =IF(VLOOKUP(E6,B6:C9,2,FALSE)>=80,$C$2,C3) が完成◆ まとめ 今回は Excel (エクセル)のIF関数の入門的な内容から、少し応用的なものまでご紹介しました。 Excel (エクセル)は私だけでなく、皆さんが業務を行う上でも利用機会が多いツールでもあるかと思います。 最近は、 Google の スプレッドシート を利用する方も多いと思いますので次はその内容についてまとめております。 ブログ Google スプレッドシート 使い方 【まとめ】 最後にはなりますが、本内容が1つでも皆様のお役に立てていれば幸いです! Excel (エクセル)のIF関数については以上となりますが、最後に宣伝をさせてください! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com 長々と失礼しました。 今後とも、 ラク スを宜しくお願い致します。 表中のある項目(セル)に特定の値を入力して選択状態にし、そのままマウスなどのドラッグ操作で縦あるいは横に選択領域を広げていくと、新たに選択された項目に次々に連続した値が入力されていく。 ↩
アバター
はじめに こんにちは、楽楽精算の開発に携わっているHiroto-Kitamuraです。 皆さまは、開発にどのような環境( IDE 、エディタ)を使用しているでしょうか? Eclipse に VSCode 、 Emacs に Vim など…個々の使い方によって選択肢は多いですよね。 本記事では、私が職場や家でインストールして使用している IDE の IntelliJ を紹介します。 IntelliJ は機能をフルに使おうとすると有料ですが、私はそれに見合う価値があると考えています。 インストールから日本語化などの簡単な使い方まで解説しているので、気になった方はぜひ最後までお読みください。 はじめに IntelliJとは? 有料版と無料版について インストール手順 Toolboxのインストール IDEのインストール 初期設定 日本語化・プラグイン導入の使い方 ライセンス購入 IntelliJの使い方 プロジェクト作成・プログラム実行 便利なショートカット Git連携の使い方 リポジトリ作成 commit, pushなどの使い方 switch, mergeなどの使い方 Git Bash埋め込み データベース連携の使い方 データベース接続 データベース操作 まとめ IntelliJ とは? IntelliJ (正確には IntelliJ IDEA)は チェコ の JetBrains 社が開発している 統合開発環境 ( IDE )の一つで、 主に JVM 言語( Java , Kotlin, Scala など)及びHTML/ CSS や JavaScript 等フロントエンドで使われる言語、 SQL をサポートしています。 JetBrains社は IntelliJ 以外にも Python や C言語 など使い方の異なる各言語に対応した IDE をそれぞれリリースしており、 これらの IDE と豊富な プラグイン をインストールしてフルに使用することであらゆる言語での開発ができるようになっています。 IDE 名 主なサポート言語 AppCode Objective-C , Swift CLion C, C++ DataGrip SQL 専用 GoLand Go IntelliJ IDEA Java , Kotlin, Scala , Groovy PhpStorm PHP PyCharm Python Rider C# , .NET Framework RubyMine Ruby WebStorm web専用(HTML, JavaScript など) 有料版と無料版について IntelliJ には有料版のUltimateと無料版のCommunity Editionが存在し、使い方によってどちらかをインストールします。 無料版は他の多くの環境と同じく料金がかかりませんが、フロントエンドや SQL 、Webフレームワークのサポートがないため、本格的な開発には向きません。 有料版は個人利用で1年17,200円(初年度・記事作成現在)と決して安くない価格ですので、導入を迷っている方はまず、無料版をインストールして試してみるのも良いでしょう。 また、有料版にも1ヶ月の試用期間がありますので、そちらを試すのも一つの手です。 ちなみに、 IntelliJ Ultimateを含めたJetBrains製 IDE が全部入りになっているAll Products Packというものも存在します。 個別に買い揃えるよりかなり安くなっているので、色々な言語を使いたい方はこちらを購入するのが良いでしょう。 インストール手順 Toolboxのインストール IntelliJ のインストールには、公式サイトから直接 IntelliJ の インストーラ をダウンロードする方法と、JetBrainsの各 IDE をまとめて管理できる Toolbox App からインストールする方法があります。 どちらがよいかは各々のPCの使い方等によって変わってくると思いますが、本記事では IDE のバージョンの管理が簡単で複数の IDE の管理にも便利なToolboxからのインストール方法を解説します。 まず、 こちら からToolboxの公式ページにアクセスし、OSに合わせた拡張子を選択してダウンロードをクリックしてください。 次に、ダウンロードした インストーラ を開き、指示に従ってインストールを行いましょう。 インストールが完了したら、タスクバー右側の通知領域にToolboxアイコンが表示されているかと思います( Windows の場合)。 これをクリックすることで、Toolboxを起動することができます。 表示されていない場合はスタートメニューなどから検索して起動すればOKです。 IDE のインストール Toolboxのインストールが終わったら、前項の方法で起動しましょう。 Toolsタブに表示されている IntelliJ IDEA UltimateかCommunity Editionのどちらかを選択し、インストールをクリックしてください。 私は既に IntelliJ をインストールしているので画像では表示が異なっていますが、本来は他の IDE と同様の表示になります。 インストールが完了したら、Toolsタブ上部・Installed項に表示された IntelliJ をクリックし、起動することができます。 初期設定 IntelliJ のインストール後初回起動時には、初期設定を行う必要があります。 ※私は既に IntelliJ でこの初期設定を完了してしまっているので、以降の一部画像は別のJetBrains製 IDE であるPyCharm, RubyMineをインストールした時のものになります。 やることは IntelliJ とほぼ変わりません。 起動するとまず設定ファイルをインポートするか聞かれるので、他の人や前のPCから設定ファイルを持って来ている人はそのファイルを選択しましょう。 ない人はDo not import settingsを選べばOKです。 次にライセンスの設定です(有料版のみ)。 30日間の無料試用期間があり、Evaluate for free→Evaluateを押すと試用することができます。 後述するライセンス購入を行っている方は、Activate→JB AccountでJetBrainsアカウントのログイン情報を入力するか、Activation codeからライセンスコードを入力してください。 最後にWelcome画面が開きますので、カラーテーマやフォントサイズ、 プラグイン 等の設定を行って最初のプロジェクトを作成すれば初期設定完了となります(これらは後からでも設定できます)。 IntelliJ の画面表示をできるだけ日本語にしたいという方は、ここで次項の日本語化 プラグイン をインストールするのがよいでしょう。 日本語化・ プラグイン 導入の使い方 インストール直後の IntelliJ は表記がすべて英語になっています。 私はこのまま使っているのですが、日本語化したい方も多いのではないでしょうか。 本項では IntelliJ の日本語化の方法とその他 プラグイン のインストール方法を説明します。 先程のWelcome画面でPluginsタブを開き、検索窓にjapaneseと打ち込みましょう。 すると「Japanese Language Pack / 日本語言語パック」という プラグイン が出てくるので、インストールボタンを押します。 他に使い方に合わせて入れたい プラグイン があれば同様にインストールすればOKです。 インストール完了後画面の指示に従ってRestart IDE から IntelliJ を再起動すると、表記がある程度日本語になりました。 完成されたプロジェクトではないので、英語のまま残っているところも多々あります。 プラグイン は IntelliJ のインストール直後だけでなくプロジェクトを作った後でも設定画面で入れることができますし、一度入れた後無効化することもできます。 この場合は画面上部の ツールバー 、File>Settings>Pluginsから設定を行いましょう。 まずは英語で試してみて、読みづらいので日本語にして、でもやっぱり英語に戻して…という使い方も可能です。 この記事では以降日本語化していない環境を前提に説明を進めていきますが、使い方は変わらないので、日本語化をした方は適宜翻訳しながら読み進めてください。 ライセンス購入 有料版の使用には、ライセンス購入が必要となります。 日本の代理店から購入する方法もありますが、ここではJetBrainsから直接購入する方法を紹介します。 まずは、 JetBrains公式サイト から右上のストアをクリックしてください。 IntelliJ のみ使用する場合は IntelliJ IDEA Ultimate、他の全 IDE も使いたい場合はAll Products Packの購入ボタンをクリックし、先に進みましょう。 あとは画面の指示に従って情報を入力し、クレジットカードや デビットカード で支払いを行えば、購入完了です。 この過程でJetBrainsアカウントを作成することになると思います。 Toolboxを開いて右上の歯車アイコンから設定画面に進み、アカウント情報を入力してログインしておくことでライセンスを有効化することができます。 先述した IDE のインストール後初期設定でも有効化できますが、こちらで設定しておくと IntelliJ 以外の IDE をインストールする際にも毎回いちいちアカウント情報を入力する必要がありません。 All Products Packを購入した方にはこちらの設定方法がおすすめです。 IntelliJ の使い方 ここからは、プログラム作成からGitやデータベースの連携まで、 IntelliJ の基本的な使い方・便利機能について説明します。 プロジェクト作成・プログラム実行 IntelliJ のインストールが終わったら、実際にプロジェクトを作ってコードを書いてみましょう。 インストール直後の場合はWelcome画面のProjects>New Project、 既に何らかのプロジェクトを開いている場合は上部 ツールバー のFile>New>Projectから新規プロジェクト作成画面に入ってください。 作るプロジェクトの種類を画面左から選択できますが、今回は基本的な Java プロジェクトを作ることにします。 開発を行うには、 SDK ( JDK 、 Java 開発に必要なツールキット)を選択する必要があります。 既に使いたいバージョンの JDK がPCにある人は表示された候補の中から選ぶか、Add JDK から JDK のフォルダを選択してください。 JDK がない、そもそも JDK って何という方はDownload JDK から使いたい Java バージョンを選んでインストールしましょう。 バージョンがわからなければ11あたりでいいと思います。 次にテンプレートを選ぶ画面に移ります。 チェックを入れると初期パッケージとMainクラスとmainメソッドが作られるので、入れておきましょう。 最後にプロジェクト名(と初期パッケージ)を決めてFinishを押せば、プロジェクトが作成されます。 プロジェクトの画面は下画像のようになっていて、左側にファイル管理、右側にコード、下に実行結果他もろもろが表示されています。 記事内で字が見えづらくならないようにウインドウを縮小しています。普段のコード画面はもっと広いです コードを書いていると自動補完が働きます。 デフォルト設定では特別なショートカットを押さなくとも、入力すると勝手に補完が出てきます。 使い方によると思いますがとても便利です。 大文字小文字の区別をなくすには、File>SettingsのEditor>General>Code CompletionからMatch caseのチェックを外してください。 コードの実行は画面右上などに表示されている右三角ボタンで実行できます。 表示がない場合はmain関数の上で右クリックしてRun Mainを実行すればOKです。 新しくパッケージやクラスなどを作る際は左側のフォルダを右クリック>New(または選んだ状態でalt+insert)で作成しましょう。 このあたりの使い方は Eclipse 等の IDE とほぼ変わらないと思いますが、 IntelliJ ではデフォルトでコードを自動保存してくれる点が大きく異なります。 便利なショートカット IntelliJ には、便利なショートカットが多数存在します。 全ショートカットの一覧は他サイトに譲りますが、ここでは私が普段重宝しているものを紹介しようと思います。 ショートカット 操作 Ctrl+Space 自動補完 Ctrl+Alt+L コードの自動整形 Shift+F6 名称変更 Ctrl+クリック 変数やクラスの宣言場所・使用場所にジャンプ Ctrl+D 行の複製 Ctrl+Y 行の削除(最初に使用した際 Redo と選択) F2 エラーや警告の場所にジャンブ Alt+Enter エラーや警告の修正候補を表示 Shift2回押し クラス・変数・テーブル・設定項目など何でも検索 Ctrl+Shift+F 全ファイル内から grep 検索 Alt+Insert ファイル作成・コンスト ラク タ/getter/setter/toString等の追加 Ctrl+/ 選択行の コメントアウト ※ショートカットはすべて Windows 版です Eclipse などの今使っている環境と、コマンドや使い方が全然違うと思う方もいらっしゃると思います。 こちらに慣れるのもいいですし、File>Settings>Keymapからお使いの環境風に一括で変えたり、1つずつショートカットを自分流にアレンジする使い方もできますよ。 Git連携の使い方 IntelliJ では作ったプロジェクトをGitと連携させると、 GUI でcommitやpush、switchなどを行ったり、ブランチのコミットグラフを図で確認することができるようになります。本項では、このGit連携の基本的な使い方を紹介します。 これらはコマンドで行うことももちろんできますが、ブランチが多くてごちゃごちゃしている場合や、コマンドを叩くより GUI 上で操作したい方におすすめです。 リポジトリ 作成 新しくプロジェクトを作った場合は、画面上部の ツールバー から VCS >Enable Version Control Integrationをクリックしてください。 使う バージョン管理システム の選択肢が出てくるのでGitを選んでOKを押すと、ローカル リポジトリ が作成されます。 既に GitHub などにあるプロジェクトをcloneする場合は、上部 ツールバー でFile>New>Project from Version ControlよりURLの入力や GitHub アカウントへのログインをすることでcloneできます。 commit, pushなどの使い方 ローカル リポジトリ を作ったら、実際にcommitなどの操作を行ってみましょう。 Gitの操作は主に画面右上と画面下部のGitタブ>Logタブ(画像で赤枠で囲まれた部分)で行います。 commitやpushpull、 ロールバック は画面右上のボタンで行います。 commitはチェックボタンです。 差分を見比べながらcommitするファイルを選択する、コミット前に自動整形をする、といった使い方ができるので大変便利です。 ちなみに、差分があるファイルはcommit画面を開かなくてもファイルウインドウやエディタ画面で青く表示されています。 pushは右上向き矢印ボタンで行えますが、 GitHub などのリモー トリポジ トリが必要なので、cloneやgit remoteなどで設定していない場合はpush>Define remoteからリモー トリポジ トリを設定しましょう。 pullは左下向き矢印(Update Project), 未コミット部分の ロールバック はU字矢印ボタンで行うことができます。 switch, mergeなどの使い方 ブランチ関連の操作は画面下部Gitタブで行います。 現在のブランチ名は常に画面右下に表示されています(前項の図参照)。 既存のブランチへのswitchはブランチを右クリック>Checkoutで、新ブランチの作成は派生元のブランチを右クリック>New Branch from Selectedから行いましょう。 簡単な操作は右下のブランチ名クリックから行うこともできます。 mergeはマージ先のブランチにcheckoutした後、マージ元のブランチ右クリック>Merge into Currentから行えます。 ここで紹介した使い方以外にも、様々なGit操作が可能です。 Git Bash 埋め込み 前章ではGitの GUI 操作の使い方について説明しましたが、コマンドで操作を行うGit Bash を IntelliJ に埋め込むことも可能です。 これを使えば、Gitコマンドを使うのにいちいち IntelliJ からウインドウを切り替える必要がありません。 本項で紹介する方法は Windows 用のものとなりますが、他のOSでも似たような使い方でgitが使える端末が埋め込めると思います。 ※Git Bash がPCに入っていない場合は、 IntelliJ への埋め込みの前にGit Bash をインストールしておいてください。 こちら からインストールできます。 まず、上部 ツールバー のFile>Settingsから設定メニューを開き、Tools>Terminalを開きましょう。 そしてShell Pathの欄にGit Bash のインストール ディレクト リのbin\ bash .exeのパスを入力すると(C:\Program Files\Gitあたりにあると思います) 、 IntelliJ 画面下部のTerminalタブでGit Bash を開くことができます。 この状態でGit Bash は使えるのですが、このままだとgit logなどで表示される日本語が正常に表示されず、Gitの使い方によってはとても不便です。 これを解消するためには、Git Bash の設定を変更する必要があります。 まずGit Bash を IntelliJ とは別ウインドウで開き、次の2つのコマンドを実行してください。 $ cd $ vi .bashrc vim が開くので、iボタンで挿入モードに移行した後 export LANG='ja_JP. UTF-8 ' と書き込み、 Escキーで ノーマルモード に移行して:wqと入力して保存します。 その後コマンドで $ source .bashrc を実行した後、 IntelliJ のターミナルを開き直す(Localの横の×ボタンで閉じた後再びTerminalタブを開く)と日本語が表示されているはずです。 データベース連携の使い方 IntelliJ Ultimateをはじめとする有料版JetBrains IDE では、Gitと同じようにデータベースも GUI から操作したり、コンソールを IDE 内で使用することができます。 Webアプリなどデータベースを活用するアプリケーションを開発する際、テーブルの作成やデータの挿入などが IDE 内で簡単に行えるため便利です。 本項では、このデータベース連携の使い方を紹介します。 ※Git Bash と同じくこちらも予め DBMS をインストールする必要があるので、PCに入っていない方はこの項を読む前に何らかの DBMS のインストールをしておいてください。 DBMS のインストール方法や使い方は割愛しますが、例えば PostgreSQL であれば こちら からインストールできます。 データベース接続 まず、画面右端に表示されているDatabaseをクリックしてください。 ない場合は画面端のどこかにあると思います(無料版にはありません)。 データベースのツールウインドウが開くので、+ボタン>Data Sourceから、お使いの DBMS を選択しましょう。 あとは画面の指示に従って JDBC ドライバのインストールや認証情報の入力を行えば、データベースに接続できます。 認証方法など詳しい使い方は DBMS によって異なるので、本記事では紹介しません。各 DBMS の仕様に従ってください。 データベース操作 データベースに接続すると、 SQL を打ち込めるコンソールが開きます。 使い方は概ね他のエディタや コマンドライン と同じですが、書いてある文の中で一部のみ実行といったこともできるので、長い SQL を一度にコピーしてきて少しずつ実行ということも可能です。 コードのエディタと同じくこちらでも強力な補完が自動で働くため、手動で SQL を入力する使い方の場合は非常に便利です。 私が普段使っている PostgreSQL の場合、接続するデータベースや スキーマ をコンソール右上から設定できるので、接続するデータベース クラスタ が同じならいちいちコンソールを開き直したりSET search_pathを入力する必要もありません。 なお、コンソールを閉じてしまった場合には、データベースツールウインドウ上部の SQL ボタンを押すと再度開くことができます。 IntelliJ では、簡単な使い方で GUI でデータベースを操作することも可能です。 データベースツールウインドウにはデータベースが ディレクト リ構造で表示されているので、 右クリックからテーブル作成・削除、 DDL 変更(Modify Table)などを簡単に行うことができます。 また、テーブルをダブルクリックするとそのテーブルに入っているデータが表示されますが、 これはただSELECT文の結果が見られるだけではありません。 画面上部の+-ボタンで行の追加・削除(INSERT・DELETE)ができる他、フィールド(マス)をダブルクリックすれば内容の変更(UPDATE)も可能です。 実際のデータベースへの反映はDB↑ボタンを押してから行われるので、間違って行を消してもボタンを押さなければ問題ありません。 複雑な操作には向きませんが、簡易的なデータの挿入・修正が直感的に行えるのは便利ですね。 まとめ 本記事では IntelliJ のインストール方法・基本的な使い方・便利な機能について紹介してきました。 ここで紹介したのは IntelliJ の機能のごく一部であり、まだまだ色々な使い方が存在します。 私も使い始めて1年も経っていないので、多くの機能を知らないまま使ってきていると思います。 ただ、「こういう機能あったら便利だな」と思って検索すると大体何かしらあるので、 開発時、環境に起因するストレスを感じることはほとんどありません。 個々人の使い方によって合う環境は変わってくると思いますが、 多少お金をかけてでも快適に開発が行いたいという方は、 一度 IntelliJ やJetBrains製 IDE をインストールして試用してみるのも良いのではないでしょうか。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに PHPのソースコードについて 標準関数のソースコードを読むコツ PHP本体のソースコードを読んでみる まとめ はじめに こんにちは。開発エンジニアのシカタです。 今回は PHP の標準関数の読み方について紹介します。 こんな経験をしたことはありませんか? PHP のバージョンアップで挙動が変わった 関数が想定外の値を返してきた 想定外の挙動をしている… リファレンスに書かれていないけど、この引数って使える…? こういうときに、 PHP 本体のコードがどう実装されているのか読むことができればスッキリしそうですよね。 今回、 PHP 本体の ソースコード を読む方法について、具体例を交えて紹介します。 PHP の ソースコード について PHP の ソースコード 自体は C言語 で実装されています。 C言語 と聞くだけでハードルが高く感じるかもしれませんが、標準関数のコードを読んでみる程度であれば意外と雰囲気で読めます。 C言語 の基本的な文法が分かる、雰囲気で上から下へ ソースコード が読むことができれば十分です。 標準関数の ソースコード を読むコツ キーワードは「 PHP _FUNCTION(関数名)」 雰囲気で理解する ある程度納得したらやめておく、適度に追いかける PHP 本体のコア部分は追わない 以上を抑えておけば雰囲気で読むことができます。 PHP 本体の ソースコード を読んでみる 今回はsleep関数のコードを例に追ってみます。 sleep ( int $seconds ) : int https://www.php.net/manual/ja/function.sleep.php この関数の引数が0だったとき、どんな挙動になるのか気にしながら見ていきたいと思います。 まずは ソースコード を入手 php -srcを下記から入手します https://github.com/php/php-src git環境があるならclone、 ソースコード を読みたいだけなのでzipで入手しても良いと思います。 入手した ソースコード を開く 規模のある ソースコード なので、 ソースコード 全体を検索しやすいエディタ、 IDE がオススメです。 今回は VSCode を使います。 「File > Open Folder」で php -srcを開きます。 関数の定義を探す PHP の標準関数は「 PHP _FUNCTION(function_name)」で定義されています。 PHP では、独自の関数(マクロ)を作成することができますが、 こちらでも関数は「 PHP _FUNCTION(function_name)」で定義するものだと説明されています。 関数の定義方法を詳しく知りたい場合には参考になります。 http://php.adamharvey.name/manual/ja/internals2.funcs.php 今回はsleep関数を追ってみるので、 php -srcの中で「 PHP _FUNCTION(sleep)」で検索をしてみます。 下記のようにすぐ見つかります。 関数の中身を読んで見る 上から見ていきます。 まず、「ZEND_XXXX」が出てきますが、ここは PHP のコアなところです。 PHP の 構文解析 や実行エンジンを担っているコアなところは「Zend Engine」と言われています。 PHP の ソースコード 内で出てくる「zend」はコアなところに繋がると思って良いと思います。 そのため、雰囲気で読むだけあればここを追う必要はありません。 ちなみに、ここは「PARSE」や「PARAMETERS、PARAM」と名前が付いたものが呼ばれているぐらいなので 引数を解析しているぐらいの理解で大丈夫だと思います。 その次は、引数が負の値だった場合は、エラー処理をしています。 最後に、「 php _sleep」というマクロが呼ばれてます。 ここを追っていきます。 関数定義を追っていく 「 php _sleep」の定義を探してみます。 2つのマクロ定義が見つかりますが、よくよく見ると windows とそれ以外みたいな分岐があります。 実行環境が windows と Unix 系で違うんだ…ぐらいの理解で大丈夫です。 windows の場合は、さらに「SleepEx」が呼ばれているので、さらに深追いしましょう。 もう一方は、「sleep」なので、ここで C言語 のsleepを叩いているようです。 さらに深追い①( windows の場合の挙動を追う) ここまでと同様に「SleepEx」の定義を探してみます。 しかし、先ほどのマクロ定義のところでしか引っかかりません。 PHP 内の定義されていない場合は、ライブラリまたは C言語 で定義されたものである可能性が高いです。 あとは適当にググってみます。 すると、SleepExはWin32APIで定義されている関数みたいです。 https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepex windows の場合の挙動なので納得できます。 0秒の場合の挙動についても書かれています。 追うのはここまでにしておきます。 さらに深追い( windows 以外の場合の挙動を追う) C言語 の「sleep」まではたどり着けましたが、そこから先は明記されていませんでした。 https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxbd00/rtsle.htm ここから先は C言語 の仕様に依存する部分なので、今日はこのくらいにしておきましょう。 0秒を渡したときは、最終的に C言語 のsleepがいい感じに0秒スリープしてくれる、はずです。 まとめ PHP のコアコードの読み方を解説してみました。 身近な関数の実装であれば、意外と雰囲気だけで読むことはできます。 今回紹介した手順を参考にしていただければ、他の関数でも試してもらえますので、 一度、普段使っている PHP の標準関数の ソースコード を読んでみてはいかがでしょうか。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 背景 Laravelのセッション管理について セッションドライバについて セッションの操作 セッションの共有を検討してみた LaravelでDBを使ってセッション管理する セッション共有の検討 Laravelのカスタムセッションドライバ まとめ はじめに こんにちは、開発エンジニアのシカタです。 今回は、開発を担当するプロダクトで アーキテクチャ を刷新することになり、Laravelの検討したときのお話です。 アーキテクチャ の刷新だけにたくさんの課題がありましたが、その中でも今回はセッションのことについて書きます。 Laravelをやってみようとか、既存プロダクトにLaravelを載せてみたいなーと思ってる人の心に刺されば幸いです。 背景 既存の運用中プロダクトの一部サブシステムを、新 アーキテクチャ で構築し直すプロジェクトがスタートしました。 一気にリリースすると影響が大きすぎるので、一部の機能から徐々にリリースしていく方針です。 現在ノン フレームワーク のため、せっかく新しくするなら フレームワーク を採用したい… ということで、Laravelを検討してみることになりました。 既存プロダクトのノン フレームワーク な世界と、Laravelで新しく作る世界を共存させることを検討する必要があり、 フレームワーク の機能を活用することを目指していますが、たくさんの課題が出てきました。 アーキテクチャ どうしよう… Laravelを活かすにはどういう アーキテクチャ で共存させるのが良いのか… 既存プロダクトとLaravelでどうやってセッション共有しよう… 認証周りとかどうするのが良いんだろう…etc 今回は課題の中からセッションについて取り上げます。 Laravelのセッション管理について まず、Laravelの基本的なセッション管理についてです。 セッションドライバについて Laravelでは、file、 cookie , DBなどでセッション情報を管理することができます。 config/session.php にセッションに関する設定は記載されています。 config/session.php return [ /* |-------------------------------------------------------------------------- | Default Session Driver |-------------------------------------------------------------------------- | | This option controls the default session "driver" that will be used on | requests. By default, we will use the lightweight native driver but | you may specify any of the other wonderful drivers provided here. | | Supported: "file", "cookie", "database", "apc", | "memcached", "redis", "dynamodb", "array" | */ 'driver' = > env('SESSION_DRIVER', 'file'), : : ] セッションの操作 Laravelでセッションの操作を行うには、 Requestインスタンス 、 sessionヘルパ 、 Sessionファサード を使う方法があります。 基本操作に大きな違いはありません。 <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Session; class HogeFunction extends Controller { /** * @param Request $request * @return Response */ public function hogee ( Request $ request ) {   /* セッションから1つデータを取得する */ // Requestインスタンス $ value = $ request -> session () -> get ( 'key' ) ; // Sessionヘルパ $ value = session ( 'key' ) ; // Sessionファサード $ value = Session :: get ( 'key' ) ;   /* セッションの値をすべて取得する */ // Requestインスタンス $ values = $ request -> session () -> all () ; // Sessionヘルパ $ values = session () -> all () ; // Sessionファサード $ values = Session :: all () ;   /* セッションに値を保存する */ // Requestインスタンス $ request -> session () -> put ( 'key' , 'value' ) ; // Sessionヘルパ session ([ 'key' => value ]) ; // Sessionファサード Session :: put ( 'key' , 'value' ) ; /* セッションに値を削除する */ // Requestインスタンス $ request -> session () -> forget ( 'key' ) ; // Sessionヘルパ session () -> forget ( 'key' ) ; // Sessionファサード Session :: forget ( 'key' ) ; /* セッション中に値が存在することの確認(existsはnullでもTrueを返す) */ // Requestインスタンス $ request -> session () -> has ( 'key' ) ; $ request -> session () -> exists ( 'key' ) ; // Sessionヘルパ session () -> has ( 'key' ) ; session () -> exists ( 'key' ) ; // Sessionファサード Session :: has ( 'key' ) ; Session :: exists ( 'key' ) ; } } セッションの共有を検討してみた 既存プロダクトとLaravelでセッションを共有させる方法を検討してみました。 既存プロダクトがDBでセッション管理されているため、今回はLaravelでもDBを用いたセッション管理を前提に考えています。 また、既存プロダクトではセッション周りは純粋な PHP で実装していますが、Laravelのセッション周りは独自実装になっています。 どこかで session_start(); しておけばいい感じになるだろう、というわけにはいきません。 この違いも少し厄介なポイントです。 LaravelでDBを使ってセッション管理する LaravelでDBを使いセッション管理する場合は、以下のようなテーブルを作成する必要があります。 Schema::create('sessions', function ($table) { $table- > string('id')- > unique(); $table- > foreignId('user_id')- > nullable(); $table- > string('ip_address', 45)- > nullable(); $table- > text('user_agent')- > nullable(); $table- > text('payload'); $table- > integer('last_activity'); }); 以下のように設定しておくと、セッション管理に使用するテーブルと認識されます。 config/session.php return [ /* |-------------------------------------------------------------------------- | Default Session Driver |-------------------------------------------------------------------------- | | This option controls the default session "driver" that will be used on | requests. By default, we will use the lightweight native driver but | you may specify any of the other wonderful drivers provided here. | | Supported: "file", "cookie", "database", "apc", | "memcached", "redis", "dynamodb", "array" | */ 'driver' = > env('SESSION_DRIVER', 'database'), : : /* |-------------------------------------------------------------------------- | Session Database Table |-------------------------------------------------------------------------- | | When using the "database" session driver, you may specify the table we | should use to manage the sessions. Of course, a sensible default is | provided for you; however, you are free to change this as needed. | */ 'table' = > 'sessions', : : ] セッション共有の検討 既存プロダクトで使用しているテーブルを使用するか、Laravelに合わせたテーブルを使用するのか…他にもいくつか選択肢がありました。 少なくとも、Laravelのセッション機能を活用しようと思うと、 LaravelでDBを使ってセッション管理する際にテーブル定義の通り作成が必要となるようです。 Laravelのセッションが確立するまでの独自実装を追ってみると、以下にたどり付きました。 Illuminate/Session/DatabaseSessionHandler.php ここを見る限りは指定されているテーブル定義前提で動くような実装になっています。 セッション管理のテーブルやセッション周りの実装が似ていれば移行前提で検討できるかもしれませんが、そうでなければ難しいです…。 よって、LaravelデフォルトのDBのセッションドライバのままでは、既存プロダクトとのセッション共存は困難であることがわかりました。 しかし、Laravelにはカスタムセッションドライバという仕組みがあり独自のセッションドライバを実装できます。 Laravelのカスタムセッションドライバ 以下のように、 SessionHandlerInterface を実装することで独自のセッションドライバの作成が可能です。 <?php namespace App\Extensions; class CustomSessionHandler implements \SessionHandlerInterface { // open: ファイルベースでなければ空でOK public function open ( $ savePath , $ sessionName ) {} // openと同様 public function close () {} // セッションの読み込み処理($sessionIdに紐づくセッションデータの取得) public function read ( $ sessionId ) {} // セッションの書き込み処理($sessionIdに紐づく$dataの書き込み) public function write ( $ sessionId , $ data ) {} // セッションの読み込み処理($sessionIdに紐づくセッションデータの削除) public function destroy ( $ sessionId ) {} // セッションの読み込み処理($lifetimeを超えたセッションデータの削除) public function gc ( $ lifetime ) {} } 次に、作成したカスタムセッションドライバの登録方法についてです。 Session ファサード の extend メソッドで登録することができます。 ServiveProvider の boot メソッドで上記メソッドを呼ぶことでカスタムセッションドライバの登録ができます。 既存の AppServiceProvider またはセッション用に作成した ServiceProvider から呼び出します。 下記は ServiceProvider から呼び出す例です。 <?php namespace App\Providers; use App\Extensions\CustomSessionHandler; use Illuminate\Support\Facades\Session; use Illuminate\Support\ServiceProvider; class SessionServiceProvider extends ServiceProvider { /** * 全アプリケーションサービスの登録 * * @return void */ public function register () { // } /** * 全アプリケーションサービスの初期起動 * * @return CustomSessionHandler */ public function boot () { Session :: extend ( 'custom' , function ( $ app ) { // Return implementation of SessionHandlerInterface... return new CustomSessionHandler; }) ; } } 最後に、作成したカスタムセッションドライバを config/session.php で設定すると、使用できるようになります。 config/session.php return [ /* |-------------------------------------------------------------------------- | Default Session Driver |-------------------------------------------------------------------------- | | This option controls the default session "driver" that will be used on | requests. By default, we will use the lightweight native driver but | you may specify any of the other wonderful drivers provided here. | | Supported: "file", "cookie", "database", "apc", | "memcached", "redis", "dynamodb", "array" | */ 'driver' = > env('SESSION_DRIVER', 'custom'), : まとめ Laravelのセッションについてまとめてみました。 既存のプロダクトとLaravelでセッションをさせる方法は現在検討中なので、 また次の機会に実際に実装したカスタムセッションドライバなどは紹介できればと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは。エンジニアのrs_shoです。 投稿は4回目になります。今回は 排他制御 についてお話ししようと思います。 はじめに 排他制御の種類 楽観ロック(楽観的排他制御) 悲観ロック(悲観的排他制御) それぞれの特徴 Javaにおける排他制御 Semaphore CountDownLatch synchronizedメソッド データベースのLOCK おわりに 参考資料 はじめに そもそも 排他制御 とは何か、ご存じでしょうか。 排他制御 とは、簡単に言うと、処理Aをしている間、他の処理は処理Aが終わるまで待つ、という制御のことです。 身近な例えで言うと、共有フォルダにある Excel などを誰かが開いて編集している間、 他の人は閲覧のみ可能で編集は不可の状態(設定によってはできますが…)のことです。 排他制御 の種類 排他制御 はただ処理待ちをするだけではなく、大きく分けて2つ種類があります。(厳密にはもっと細かく分かれていると思います) 楽観ロック(楽観的 排他制御 ) と 悲観ロック(悲観的 排他制御 ) です。 楽観ロック(楽観的 排他制御 ) 楽観ロックは同時更新は起こらないであろう、という前提の 排他制御 のことです。 更新対象のデータをロック(編集不可)することはせず、 更新時に「手元のデータの編集開始時点の状態」と、「更新対象データの状態」が同じかを確認して更新を行います。 誰でも編集・更新していいけど、更新時に他の人が上書きしていたら更新できないよ!っていう制御です。 個人的には「楽観的(前向きな考え)という割には、更新時にデータが吹っ飛ぶ可能性があって怖いな」と思いますね。 悲観ロック(悲観的 排他制御 ) 悲観ロックは同時更新が起こる可能性がある、という前提の 排他制御 のことです。 更新対象のデータをロックして、自分の編集・更新が終わるまで、他の人が編集できない状態にしてしまいます。 編集中は見たり、コピーを作ることはできても、原本に手を加えることはできないよ!っていう制御です。 こちらの方が自分が開いている間は誰も更新できないので、なんとなく安心感がありますね。 それぞれの特徴 先程説明した楽観ロック・悲観ロックについて、特徴や違いを挙げていこうと思います。 前提 楽観ロック:同時更新は起きないであろう 悲観ロック:同時更新が起きるかもしれない 整合性チェック 楽観ロック:データ編集終了(更新)時 悲観ロック:データ編集開始時 どの処理に向いているか 楽観ロック 同時更新がめったに起きない処理(単体で行う処理) 不整合が起きてもやり直せる処理 短時間で終わる処理 悲観ロック 同時更新が頻繁に起こる可能性がある処理(分担する処理) 不整合が起きてほしくない処理 長時間続く処理 Java における 排他制御 僕は業務中にある種別の中のカテゴリ内で番号が重複しないように実装しようと思い、 排他制御 について調べました。 (例えば、動物という種別の、哺乳類カテゴリの1:象, 2:イルカ …といった感じで、IDが重複しないように実装したかった) 上記はシーケンスを使えばいい、と思うかもしれませんが、カテゴリ毎にIDを1からスタートする場合、 カテゴリを追加する度にシーケンス生成が必要になるので、あまり現実的ではありません。 ですが、DB内で保持しているIDの最大値を取得するだけでは、採番処理が同時に行われた際に最大値が重複し、結果採番されたIDが重複してしまいます。 僕の個人的な解釈になりますが、調べた中で 排他制御 に使用できそうな方法を軽くご紹介しようと思います。 (いずれどこかでより詳しく深堀りしてみたいと思います。) Semaphore アクセス数を制限して、設定した値を超える数の処理が発生した場合、処理待ちをさせる 通常の 排他制御 はSemaphoreのロックが1つ(1つ以上は実行させない)の状態と同じ ロックを解放する方法が特殊で、実装を誤ると正常に機能しない(処理実行可能数を増やし続けてしまい、意図した 排他制御 ができない) CountDownLatch 複数の処理をブロック丸ごとロックする時に有効 引数にロック数を指定して、処理毎にロック数を減算、0になったらロックを解除する 複数メソッドにまたがってロックしたいときなどに有効だが、ロック数が0になったらロックが解放されるので、引数で渡す値には注意が必要 synchronizedメソッド メソッドの修飾子や 入れ子 で使用することで、同時実行をブロックできる 修飾子に追加する or 処理ブロックを 入れ子 にしてくくるだけで実装できる ただし、複数の継承先から参照されるクラスの場合は、 インスタンス 毎に処理が同時実行されてしまう可能性がある データベースのLOCK LOCK文を実行してテーブルのロックを取得、そのテーブルにアクセスしている処理があれば、解放されるまで待つ データ自体にロックがかかるので、整合性を保ちやすい ただ、 RDBMS の種類によっては、SELECTなどでもロックを取得してしまい、 デッドロック が発生したり、勝手に トランザクション をコミットされたりしてしまうため、注意が必要 おわりに 以上、 排他制御 についてざっと説明させていただきました。扱いが難しいですが、使いこなせればデータの整合性を保証できます。 この記事を通して 排他制御 について知っていただく、調べてみるきっかけになれば幸いです。 紹介した方法についても、いずれ深堀りしていこうと思います。 参考資料 排他制御(楽観ロック・悲観ロック)の基礎 【Java】マルチスレッド処理 - 排他制御 Javaの排他制御(ロック)に関係するクラスまとめ PostgreSQLは、SELECTもロックを獲得する エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 株式会社 ラク ス チャットディーラー開発課のエンジニアRakusMoritaです。 2021年3月26日(金)~3月28日(日)開催のPHPerKaigi2021に、 ラク スエンジニア7名が参加してきました。 phperkaigi.jp PHPer(ペチパー)によるPHPerのためのこの大規模イベントは、今年はオンラインでの開催でした。 オンラインでありながらも、豪華な登壇者、絶えず流れるコメント、主催者の勉強になるコントなどなど・・・ お祭り騒ぎのような雰囲気伝わってきて、ワイワイと非常に楽しい勉強会でした。 ラク スは当イベントのスポンサーとして参加 させていただいている他、社内から2名が登壇しました。 この記事では、PHPerKaigi2021に参加した社内のエンジニアが、参加したセッションの内容をまとめましたので、ご紹介したいと思います。 各セッションのスライドも用意しておりますので、PHPerな人、これからPHPerになる人は新たな発見があること間違いなしです。 ~目次~ はじめに 3/27(土) 実践ATDD 〜TDDから更に歩みを進めたソフトウェア開発へ〜 負荷試験の観点から見るGraphQLにおけるPHPのコードチューニング 目的に沿ったDocumentation as Codeをいかにして実現していくか PHPでCSVを安心して扱うために PHPで学ぶ、セッションの基本と応用 PHP8になった今の時代に、PHPの「エラー」「例外」そして「Error」をおさらいしておこう Laravel のメール認証の内部実装を掘り下げる PHPWebアプリケーションパフォーマンスチューニング PHP でもアーキテクチャテストしたい! 3/28(日) そのコード、フレームワークの外でも動きますか? 無駄な物をなるべく作らないリプレイス戦略 なるせ先生のPHP学~PHP8新機能スペシャル~ 今こそ理解するDI(Dependency Injection) プログラマ三大美徳を実現するデプロイフローを目指して PHPのDI、attributesとこれから DNSを制する者はインターネットを制す!DNSの世界/市川@cakephper 新社会人のコード品質カイゼン記録 あとがき 3/27(土) 実践ATDD 〜TDDから更に歩みを進めたソフトウェア開発へ〜 report by id:radiocat speakerdeck.com ATDDとはAcceptance test-driven developmentの略で、日本語にすると受け入れ テスト駆動開発 です。 アジャイル 開発では開発要件をユーザーストーリーとして表現し、それが実現できていることを開発の完了条件として受け入れテストを実施する手法がありますが、 それを駆動型で開発に取り入れるやり方がATDDです。登壇者の現場で考えられている、中心となる2本柱が次の内容です。 四象 限におけるQ2を強化する 四象 限とは技術面とビジネス面の2軸と、開発チーム支援と製品批評の2軸を組み合わせたもので、Q2はその中でビジネス面と開発チーム支援の領域です。顧客視点の高レベルテストで自動化と手動テストを組み合わせるところがポイントです。 テストピラミッドを登る テストピラミッドとは ユニットテスト を土台として、サービステスト、UIテストと上位に階層化したテストレイヤーに分類してテストを概念化したもので、上位のUIテストのほうが重厚化してしまう アンチパターン に陥らないように必要に応じてテストピラミッドを登っていくことがポイントです。 知識的情報だけでもボリュームたっぷりでしたが、さらに PHP で作られた Webサービス を題材とした ケーススタディ では、自動受け入れテストツールを使った実践例も紹介されています。ATDDの自動化領域と手動テストとの共存のさせ方、 ユニットテスト などのTDDの手法との組み合わせ方などについても語られており、実践に向けた応用方法の示唆に富む内容でした。知識のインプットだけでなく実践に向けたインプットにも役立つボリュームたっぷりなセッションだったので、今後も資料を読み返して現場で実践活用したい内容です。 負荷試験 の観点から見るGraphQLにおける PHP のコードチューニング report by id:Y-Kanoh speakerdeck.com API で利用するクエリ言語である GraphQL は、REST と違い、複数のクエリを1度のリク エス トで行うことができます。 そのため、複数のクエリ発行のために何度もレスポンスを待つ必要がなく、 レイテンシは REST と比べて速くなる特性があります。 しかしこの仕組み上、秒間のリク エス ト数低下や、短時間に処理が集中してしまいCPU負荷が高くなること、 重いクエリが含まれると全体のレスポンスに影響を与えることなど、デメリットも存在します。 利用時には、取得するデータを絞る仕組みや、複雑すぎるクエリを制限する仕組み、 PHP の場合は処理向上のためのOPCache導入などを行なって、コードチューニングを行う必要があります。その詳しい勘所について説明されていました。 REST との比較を行いながらわかりやすく説明していただけたので、両者のメリットデメリットなども理解できました。 実際使ってみての勘所を説明いただけていたので、GraphQL の導入を考えるかたはぜひ確認していただければと思います。 目的に沿ったDocumentation as Codeをいかにして実現していくか report by id:Y-Kanoh speakerdeck.com 開発者がチームに join し、開発を始められる状態になるまでのオーバヘッドを削減する方法が、システムの理解を助けるドキュメントです。 しかし、更新漏れによる誤った理解を防ぐために、ドキュメントはメンテナンスを継続的に行わなければなりません。一方、開発と切り離された運用でのメンテナンスは、システムとの乖離を修正するまでの時間も長くなってしまい、 継続的なメンテナンスも難しくなってしまいます。 そこで、この発表では、システムとドキュメントをそれぞれ情報の集合と考え、 各情報同士が紐づいていない状態が増えることを「システムとドキュメントの乖離が大きくなった」と位置付けることで、 この問題の解決策を探っています。 その方法として、PHPDocなどのように、”システムとドキュメントの間に構造化データを用意し、 その構造化データをもとにドキュメントを作成する方法”や、OpenAPIのように “構造化データを先に用意し、 そこからシステムとドキュメントを作成する” 方法などが紹介されていました。 また、具体的に対策を行うためのツールも紹介されており、 どのような仕組みで対策を行うことができるのか想像しやすい内容でした。 ドキュメントのメンテナンス問題は私自身も思い当たることが多く、 発表内容の前半は胸が痛い内容でした。エンジニアらしく問題の本質を分析し、 仕組みでそれをカバーすることを考えさせられる内容でした。 PHP で CSV を安心して扱うために report by id:tsudachantan speakerdeck.com 他サービスとのデータ連携やバルクデータ入出力などで使い勝手が良く、根強く利用されている CSV ファイル。 PHP での CSV 処理は癖が強く、一見安全に対応できたように見えて運用面で深刻な問題を抱えることがあります。 現状とその解決方法について丁寧にお話いただきました。 fw3/streams OSに依存しない安定した入出力と、発生していた問題の根本解決としてライブラリfw3/streamsを紹介されていました。 以下が特徴です。 OSと PHP バージョンの組み合わせに影響されず動作する 安全かつ確実に入出力が可能である mb_convert_encordingを使った文字セットの変更ができる 妥当な文字セット自動検出が行える OSに影響されない改行コード出力を行える 変換できない文字があった場合の代替手段を設定できる ライブラリの説明に沿って様々な環境やパターンを網羅して CSV の扱い方について発表されており、大変勉強になりました。 PHP で学ぶ、セッションの基本と応用 report by id:soachr speakerdeck.com 以下の章立てで発表されていました。 生い立ち 技術的な仕組み 最低限の周辺知識 PHP 以前に、そもそもHTTPでセッションが使われるようになった背景から、現在どのようにセッションが使われているのかまでを紹介された上で、じゃあ実際に PHP はどのようにセッションを実現しているのか、という内容まで紹介されていました。 今までふわっとしていた PHP のセッションについて理解できました。 ログイン機構があるシステムに関わっている方はとりあえずこの発表を聞けば問題ないと思うくらい、わかりやすい&すっと理解できる内容でした。 新卒時代のときにこの発表に出会っていればもっとスムーズに理解できたのでは...とこの発表で初めてセッションについて学んだ方が羨ましいと思うくらいです。新卒の育成担当をしている身としては、ぜひ学習カリキュラムに入れさせていただきたいと強く感じました。 PHP8になった今の時代に、 PHP の「エラー」「例外」そして「Error」をおさらいしておこう report by id:tsudachantan speakerdeck.com PHP には「エラー」を知らせる仕組みがたくさん用意されていますが、それぞれの違いが答えられるでしょうか。 PHP のエラーの扱いはバージョンごとに進化しており、それが混乱する原因にもなりえます。 とにかく不用意に\Throwable、\Errorをキャッチすることは危ない!というメインの主張を。 では、そもそもエラーとは?という説明からお話しされており、納得しながら整理できました。 まだまだ PHP 歴が浅い自分や、わかっているけど人に説明するのは難しいといった方にも役に立つ内容だと思います。 「Throwable/Error/Exception」についての棲み分けについての認識がクリアになり、効果的な例外の使い方について考える機会になりました。 Discordのチャンネルでも様々な意見が交換されており、チーム開発での意識のすり合わせの大切さを感じました。 Laravel のメール認証の内部実装を掘り下げる report by id:Y-Kanoh speakerdeck.com PHP の フレームワーク であるLaravelは、さまざまなロジックが既に用意されており、 メール認証の仕組みも、少しの実装を行うことで、簡単に利用することができます。 しかし、既存のロジックは手軽さのために、拡張性が犠牲になっている部分があり、 独自の仕組みを組み込みたい場合は、内部ロジックを理解した上での改修が必要です。 メール認証の場合、この拡張性を損なっている原因は、App User モデルの責務が多すぎることです。 App User の持っている責務を明確化して、それぞれの依存関係を理解した上で、 分離独立させることにより、拡張性の高いロジックに作り替える方法を紹介いただいていました。 近年、機能が多くなりすぎて批判されることもある Laravel ですが、内部の依存関係を理解し、 責務に沿って作り替えれば上手く付き合っていけることを学べた発表でした。 PHPWebアプリケーションパフォーマンスチューニング report by id:soachr speakerdeck.com パフォーマンスチューニングについて、体系的にかつ具体的に説明されていました。 パフォーマンスチューニングの大原則の考え方である「推測するな、計測せよ」を軸として、どのように再現・計測・原因仮説、からの対策を取るのかを、Webアプリケーションを実現する ミドルウェア ごとに紹介されていました。 自身もパフォーマンス・チューニングを業務で行っていたのですが、まだ知らない視点や、計測時のコマンド、対策を知れてとても勉強になりました。 パフォーマンス・チューニングをやったことがない人で「なにから初めて何をすればいいのかわからない」方にもおすすめです。 PHP でも アーキテクチャ テストしたい! report by id:radiocat speakerdeck.com 弊社のリードエンジニア川並が アーキテクチャ テスト について発表しました。 コードレビューが機能している状況においても、 アーキテクチャ 観点でしっかりレビューするのは難しく、開発初期にしっかり検討していた設計方針がいつのまにか泥団子状態ということも起こりえます。 アーキテクチャ を維持するために、クラスの依存関係や実装ルールをコード化して自動テストするのが アーキテクチャ テストです。 発表では PHP の フレームワーク である deptrac と phpat を使った アーキテクチャ テストの実例がデモを交えて紹介されました。 デモで使われたサンプルコードが以下で公開されています。 github.com アーキテクチャ は一度決めたら終わりではなく、 アーキテクチャ テストが アーキテクチャ を育て、進化させていく!という、希望に満ちたまとめで勇気をもらえるお話でした。 3/28(日) そのコード、 フレームワーク の外でも動きますか? report by id:Y-Kanoh speakerdeck.com アプリケーションの長期運用には、ビジネスサイド要因による仕様変更の他にも、 フレームワーク のバージョンアップ/メンテナンスの終了や、 時代の変化によって利用していた フレームワーク が陳腐化してしまうなど、リプレースを求められることがあります。 そのような時に、 フレームワーク にガッツリ依存したコードになっていると、 大半のコードを書き直す必要が出てきてしまいます。 この発表では、リプレースやリニューアル時に飛型しないために、 チームで作成するコードを フレームワーク から分離し、 環境の変化に強いコードを作成する例を紹介していただけました。 発表中には、実際にLaravelで実装されたコードを、 Symfony に移植するサンプルコードを説明していただき、 具体的にどのような効果が得られるかを体験できました。 また、最後におっしゃっていた、違う フレームワーク や、違う仕組み、違う言語など、 「バリエーション」に強いコードにすることで、結果的に保守性を向上させるという考えが、 とても共感できました。 資料の中に ソースコード のリンクもあるので興味のある方は覗いてみてください。 無駄な物をなるべく作らないリプレイス戦略 report by id:MasaKu speakerdeck.com レガシーソースのリライトについてのお話でした。 リプレイス戦略は以下の段階で難易度が上がっていきます。 リファクタリング リプレイス リライト リライトとは、既存機能を完全に一から書き直すという作業であり、この作業を実施するには、そもそも なぜリライトが必要なのか という課題を明確にして、どのように書き直すかの方針を新たに決定する必要があります。 リライトを始めるには基本的なこととして、現状の仕様を完全に理解する必要があります。 そのための方法は コードリーディング リファクタリング 設計の振り返り 実際にサービスを使ってみる などの方法を行います。 また、実際のユーザと直接対話することも重要です。 サービスが提供している価値はどこにあるのかを再認識するためにも、ユーザストーリーを立てて、本当にリライトが完了するかを見ていく必要があります。 ご発表の中で リファクタリングを限界までしても現状の問題が解決しないと思ったらリプレイス という判断基準をご紹介いただき、とても理解しやすいご説明でした。 なるせ先生の PHP 学~PHP8新機能 スペシャ ル~ report by id:Y-Kanoh PHP8の新機能であるmatch式、NullSafe 演算子 、Attributeを、某テレビ番組風に紹介していただけました。 match式 フォールスルー(brakeがないと次の処理を実行してしまう)がなくて事故が起きにくい マッチする条件がないとエラーになるから安全 再帰 処理で使いやすい コードの見通しが良くなる NullSafe 演算子 オブジェクトがNullの場合、指定されたメソッドが実行されない 似たようなものでNull合体 演算子 や、 エルビス 演算子 がある エルビス 演算子 の” エルビス ”は、エルヴィス プレスリー の髪型が語源 Attribute 言語としてサポートされるようになった アノテーション 今の形になるまで様々な議論があった アトリビュート を読み取って トランザクション を張るなどの応用がありえる また、新機能を単に紹介するだけでなく、その機能の便利なところや、 ちょっとした裏話も共有していただけて、ドキュメントを読むだけでは得られない内容でした。 個人的には、エルヴィス プレスリー が初耳でした。 今こそ理解するDI( Dependency Injection) report by id:MasaKu speakerdeck.com DIについて詳しく再認識させていただけたご発表でした。 というのも、個人的にDIについていろいろと調べていたことがあったのですが、結局これがDIなのかな? といったぼんやりとした理解だったので、今回のご発表を聞き、少し理解が進んだように感じました。 DIとは保守性の高いコードを書くことを目的とした設計原則とパターンのセットであり、 疎結合 を実現することを目的とした デザインパターン です。 概念としては、制御の逆転を行い、必要になった時だけ呼び出す、という流れで外部からオブジェクトを使用するようにします。 例えば、メールを送信するメソッドを例にすると、外部から該当のメール送信メソッドを呼び出す際、メソッド内でメール送信オブジェクトを生成してしまうと、そのメソッドはメソッド内で生成したオブジェクトを自由に付け替えることができなくなくなります。 検証のタイミングでは、検証用のメールサーバを利用して、本番では AWS のメールサーバを利用する、など使い分けをしたい場合、そのメソッド内でオブジェクトを生成してしまうと、コードを修正しなければオブジェクトの付け替えができません。 こういった密結合の状態を回避するのがDIです。 なお、DIの説明がある際にDIコンテナの話も良く出てくるが( フレームワーク の標準機能として搭載されている場合が多い)、DIを実現するためにDIコンテナが必要なわけでなく、DIを実現しやすくするための工夫として存在しているものなので、DIコンテナは必須ではないようです。 また、類似の デザインパターン として、サービスロケーターの話もよく登場するが、目的はDIと同じだが実現する手段がが異なる デザインパターン とのことです。 プログラマ 三大美徳を実現するデプロイフローを目指して rebort by id:Jazuma プログラマ三大美徳を実現するデプロイフローを目指して from 智也 鈴木 www.slideshare.net 株式会社 M & A Cloud 所属 @yamotuki さんによるセッションです。 「 ベンチャー におけるプロダクトやチームの成長とデプロイフロー自動化」というサブテーマのもと話が進みました。 (デプロイフローにおける) プログラマ の三大美徳 怠惰 :同じ作業の繰り返しは面倒くさい →自動化したい 傲慢 :デプロイ手順をミスってエラーになるのはダサい →自動化したい 短期 :デプロイ作業に2時間もかけたくない →2秒で終われ! デプロイフロー自動化の歴史 サービス開発当初はデプロイフローが自動化されていませんでした。 開発者の人数が少ないのでやっている時間がない 売上が立っていないので運用フロー効率化よりも機能追加優先 自動化のノウハウがない 自動化文化がない ユーザーアクセスが少なく、障害発生リスクがない しかし、サービスが軌道に乗ってくると自動化をする理由が出てきました。 売上が立った 開発者が増えて手動作業だとミスが起こる可能性が大きくなった デプロイフローそのものが複雑になり手動作業がつらくなる 運用に時間を取られて機能追加もおろそかに なによりめんどくさことはしたくない! このような経緯でデプロイフロー自動化が段階的に進みました。 セッションの中で 「プロダクトとチームの成長は自動化と密接に関係している」 と述べられていたのが印象的でした。 エンジニアはつい自動化それ自体が目的になりがちですが、チームやプロダクトがどのようなフェーズにあり、どんな問題を解決するために自動化をするのかということが重要だと思いました。 PHP のDI、attributesとこれから rebort by id:rakusMorita speakerdeck.com DI( Dependency Injection・依存性の注入)とは、簡単に言うと Dependency :使われるオブジェクトを Injection:使う側のオブジェクトに渡す ということです。DIについては詳しく説明しませんが、 具象クラス(具体的な実装をしているクラス)との処理の結合を避けて、抽象クラスと処理を結合させることで、変更に強くすることが基本的な考え方です。 注入とは、 インスタンス を抽象クラスから作成して動かすというものです。まだ具体的な実装ができていなくてもダミーの インスタンス を作りやすい(モックの作成がしやすい)ので、その結果、実装もそうですが、 単体テスト なども非常にやりやすくもなります。 DIの歴史とポイント DIは Java から始まった PHP5でクラスの機能が強化され、DIっぽいことができるようになった。 近年 PHP でもDIが標準的な思想として認知されつつある(型指定が当たり前に/interfaceが使いやすくなった/autoloadでrequire不要に等々) 今までの型指定のない PHP 的な書き方もできますし、いい意味で Java っぽさも取り入れた実装もできるようになってきて、 PHP は良いとこ取りな言語に進化してきましたね。 APC やOPchaceなどによるコードキャッシュにより、実行速度も向上し、ますますDIがやりやすくなりました。 今時な フレームワーク (Laravel、 Symfony 、 CakePHP あたり)はDIコンテナを持っている(あるいは持とうとしている)ということは、特に意識しなくてもDIを使えるようになってきたと言えるでしょう。 PHP の動向 PSR-11という インターフェイス が普及 異なる フレームワーク やライブラリのを使っていても同じように呼び出せるDI用の インターフェイス が使えるようになりました。 PHP -DIというDI用のライブラリの存在 PSR-11互換。 フレームワーク と組み合わせて使えるので便利です。 @Inject( アノテーション )記法が廃止になって#[Inject]( アトリビュート )になった アノテーション は結局のところPHPDocだったので、文字列の解析になるので重かったのが、 アトリビュート だと言語としてサポートされていて、動作が格段に速くなりました。 Autowireという機能 明示的にInjectの必要がなくなり、設定ファイル書かなくても作れるようになりました。 DIがシームレスに使える=意識せずともDIのメリットを享受できるように開発できる ということですね。素晴らしい。 DIコンテナは今後も自然に広く使われていくことになるでしょう。 DNS を制する者はインターネットを制す! DNS の世界/市川@cakephper report by id:MasaKu ドメイン 名ハイジャックの恐ろしさについて改めて身に染みたご発表でした。 悪意あるユーザが名前解決先のIPを書き換えてしまうため、ユーザ側としては悪意あるWebページに遷移してしまっていることを認識できません( HTTPS にも対応させることができる)。 また、この問題に気づきにくくする厄介な方法として、常に悪意あるWebページに遷移させるのではなく、10人に1人だけ悪意あるページに遷移させるなどするとより気づきにくくなります。 過去の事象として、名前解決先のIPを返す レジストラ の 脆弱性 を突かれて情報改ざんされ、MXレコードが書き換えられたせいでメールも乗っ取られた、という事件も発生したようです。 この問題は レジストラ 側の問題になるため、対策のしようがないため、 改ざんを検知したらいち早く対応するなどの運用が必要 となります。 また、 DNS の歴史についてもご説明がありました。詳しい仕様についてはこの場では割愛しますが、面白かったエピソードとして、お子さんの YouTube 閲覧時間制限のために、 DNS パケットの解析を行い、アクセス制限を追加したというお話がありました。 DNS のクエリはどのIPの利用者が何時にどのアドレスの名前解決をしたか、という情報が暗号化されずに送信されるため、プライバシー上の問題もあるようです。(お子さんのプライバシーにかかわるため、上記対策は中断したとのこと) ODoHという仕組みを利用して DNS のメッセージを暗号化する ことも現在提案されているようです。 新社会人のコード品質 カイゼン 記録 rebort by id:rakusMorita speakerdeck.com ラク スのエンジニアの発表でした。 指摘が多く、コード品質が良いとは言えない状態から、どのように品質をアップさせてきたのかの発表でした。 チェックリストも、コミット前のコードの見直しも色々やってみたところ・・・ 目立った効果がありませんでした。しかし・・・! ペアプロ / モブプロ これで、大きく品質が向上したようです。 先輩エンジニアの視点や考え方がリアルタイムでわかるので、「どういうところに気を付ければいいのか」などがわかるようになったとのことです。 「 ペアプロ をしてもらえる環境が素晴らしい」 というコメントがたくさん流れていました。 もちろん、環境も大切だと思いますが、彼の 「思い切って先輩エンジニアに ペアプロ をお願いした」 こと。 その勇気が彼の品質向上に繋がった、とても前向きになれる発表でした。 きっとチームにとっても、長い目で見て開発コストを抑えることに繋がるはずなので、 ペアプロ ・モブプロは忙しい環境こそおすすめです! あとがき このPHPerKaigi2021に参加し、エンジニアの生の声を聞き、色々な考え方に直に触れることで視野が広がりました。 エンジニアの方なら、よくググったり、書籍を読んだりすると思うのですが、やはり 現場の経験から出た使えるア イデア だったり、 調べたこともない知識をインプットできる という点で、このような勉強会は貴重ですね。 皆様のより良いPHPerライフを応援しております。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは、 id:FM_Harmony です。 iOS アプリの開発プロジェクトに参画して1年が経ち、自身の中で iOS 開発の土台が固まり、 ようやく様々な技術をキャッチアップ出来るようになりました。 そこで、今回はいま学習中のSwiftUIについて、MVVMの理解もかねて記事にしてみました。 SwiftUIについては公開されたのが2019年と新しい技術ですので、 この記事がこれから学習を始める方の参考になれば幸いです。 目次 はじめに 目次 MVVMとは SwiftUIとは アプリの概要 実装 Modelの実装 ViewModelの実装 Viewの実装 デモ おわりに 参考 MVVMとは ソフトウェア アーキテクチャ の一つです。 以下、 Wikipedia より引用します。 Model-View-ViewModel (MVVM、モデル・ビュー・ビューモデル) はUIを持つソフトウェアに適用されるソフトウェアアーキテクチャの一種である MVVMはソフトウェアをModel・View・ViewModelの3要素に分割する。プレゼンテーションとドメインを分離し(V-VM / M)また宣言的Viewを分離し状態とマッピングを別にもつ(V / VM) (中略) ### Model アプリケーションのドメイン(問題領域)を担う、そのアプリケーションが扱う領域のデータと手続き(ビジネスロジック - ショッピングの合計額や送料を計算するなど)を表現する要素である。 (中略) ### View View(ビュー)はアプリケーションの扱うデータをユーザーが見るのに適した形で表示し、ユーザーからの入力を受け取る要素である。すなわちユーザインタフェースの入出力が責務である。 (中略) ### ViewModel ViewModel(ビューモデル)はViewを描画するための状態の保持と、Viewから受け取った入力を適切な形に変換してModelに伝達する役目を持つ。すなわちViewとModelの間の情報の伝達と、Viewのための状態保持のみを役割とする要素である。 実装ではしばしば、Viewとの通信はデータバインディング機構のような仕組みを通じて行う。その場合ViewModelの変更は開発者から見て自動的にViewに反映される。 私は以下のように理解しています。 View ユーザからの入力をViewModelに伝える ViewModelの変更を画面に出力する ViewModel Viewから受け取った入力でModelを変更する Modelの変更を自身に反映する Model WebやDBにあるデータにアクセスする ViewModelによる変更を永続化する SwiftUIとは iOS 向けのUI フレームワーク で、iOS13以降で利用することができます。 宣言的に部品を記述することができるのが特徴で、 Combine フレームワーク によるイベントの通知、受信と組み合わせて、 View - ViewModel間のデータ バインディング を実現できます。 ※Combine フレームワーク もiOS13以降で利用することができます 個人的な感想ですが、SwiftUIを用いることで、 簡潔なコードで MVVMパターン によるアプリ実装を行えると思います。 アプリの概要 MVVM、SwiftUIの学習として、メモアプリを作ってみました。 大まかな仕様は以下の通りです。 1行のメモを追加できる 登録したメモは登録日の新しい順に表示する メモを選んで削除できる メモをすべて削除できる 実装 それでは実装内容の紹介に移ります。 今回はメモの一覧画面、メモのViewModel、メモのモデルを作成します。 また、登録したメモは Realm で端末に永続化します。 それぞれの関係性は以下の図の通りです。 MVVMに従い、ユーザの入力によりView - ViewModel間でイベント通知が行われ、 画面の再描画や永続化処理の呼び出しが自動的に行われます。 Modelの実装 具体的な実装内容の紹介に移ります。 まずは、Modelの実装です。 今回はModelに以下の役割を持たせています。 Realmからのデータ取得 Realmへの永続化処理 import Foundation import RealmSwift class Memo : Object , Identifiable { @objc dynamic var text = "" @objc dynamic var postedDate = Date() } extension Memo { private static var config = Realm.Configuration(schemaVersion : 1 ) private static var realm = try ! Realm(configuration : config ) static func findAll () -> Results < Memo > { realm.objects( self ) } static func add (_ memo : Memo ) { try ! realm.write { realm.add(memo) } } static func delete (_ memo : Memo ) { try ! realm.write { realm.delete(memo) } } static func delete (_ memos : [ Memo ] ) { try ! realm.write { realm.delete(memos) } } } ViewModelの実装 次はViewModelの実装です。 出力としてViewに表示するメモの一覧を、入力としてメモに登録するテキスト、削除するメモ、 全削除の処理が行われたかという状態を持たせています。 各プロパティには @Published を付けることで、値の変更が行われた際に、 変更されたことを通知できるようにしてあります。 また、 AnyCancellable 型のプロパティを持たせることで、 @Publish なプロパティの変更が行われた際に、ViewModelで自動的に永続化処理が始まるようにしています。 import Foundation import Combine class MemoViewModel : ObservableObject { @Published private ( set ) var memos : [ Memo ] = Array(Memo.findAll()) @Published var memoTextField = "" @Published var deleteMemo : Memo? @Published var isDeleteAllTapped = false private var addMemoTask : AnyCancellable? private var deleteMemoTask : AnyCancellable? private var deleteAllMemoTask : AnyCancellable? init () { addMemoTask = self . $memoTextField .sink() { text in guard ! text.isEmpty else { return } let memo = Memo() memo.text = text self .memos.append(memo) Memo.add(memo) } deleteMemoTask = self . $deleteMemo .sink() { memo in guard let memo = memo else { return } if let index = self .memos.firstIndex(of : memo ) { self .memos.remove(at : index ) Memo.delete(memo) } } deleteAllMemoTask = self . $isDeleteAllTapped .sink() { isDeleteAllTapped in if (isDeleteAllTapped) { Memo.delete( self .memos) self .memos.removeAll() self .isDeleteAllTapped = false } } } } Viewの実装 最後にViewの実装です。 Viewは MemoListView と MemoRowView に分けており、 前者がメモの一覧を、後者が登録したメモの表示を行っています。 MemoListViewではViewModelで @Published を付けたプロパティを受け取り、 Listを再描画できるようにしています。 また、ユーザ操作により、 @Published を付けたプロパティの変更を行い、 プロパティ変更の通知からViewModelの処理が自動的に始まるようにしています。 import SwiftUI // MARK : MemoListView struct MemoListView : View { @ObservedObject var viewModel = MemoViewModel() @State private var isMemoTextFieldPresented = false @State private var isDeleteAlertPresented = false @State private var isDeleteAllAlertPresented = false @State private var memoTextField = "" var body : some View { NavigationView { VStack { if (isMemoTextFieldPresented) { TextField( "メモを入力してください" , text : $memoTextField ) .textFieldStyle(DefaultTextFieldStyle()) .keyboardType(.asciiCapable) } List { ForEach(viewModel.memos.sorted { $0 .postedDate > $1 .postedDate }) { memo in HStack { MemoRowView(memo : memo ) Spacer() // Buttonにすると行全体にタップ判定がついてしまったので、Text.onTapGestureを代わりに使っている Text( "削除" ).onTapGesture { isDeleteAlertPresented.toggle() } .padding() .foregroundColor(.white) .background(Color.red) } .alert(isPresented : $isDeleteAlertPresented ) { Alert(title : Text ( "警告" ), message : Text ( "メモを削除します。\nよろしいですか?" ), primaryButton : .cancel(Text( "いいえ" )), secondaryButton : .destructive(Text( "はい" )) { viewModel.deleteMemo = memo } ) } } } } .navigationTitle( "メモの一覧" ) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement : .navigationBarLeading) { Button( "全削除" ) { isDeleteAllAlertPresented.toggle() } .disabled(viewModel.memos.isEmpty) } ToolbarItem(placement : .navigationBarTrailing) { Button( "追加" ) { if (isMemoTextFieldPresented) { viewModel.memoTextField = memoTextField memoTextField = "" } isMemoTextFieldPresented.toggle() }.disabled(isMemoTextFieldPresented && memoTextField.isEmpty) } } .alert(isPresented : $isDeleteAllAlertPresented ) { Alert(title : Text ( "警告" ), message : Text ( "全てのメモを削除します。\nよろしいですか?" ), primaryButton : .cancel(Text( "いいえ" )), secondaryButton : .destructive(Text( "はい" )) { viewModel.isDeleteAllTapped = true } ) } } } } // MARK : MemoRowView struct MemoRowView : View { var memo : Memo var body : some View { VStack(alignment : .leading) { Text(formatDate(memo.postedDate)) .font(.caption) .fontWeight(.bold) Text(memo.text) .font(.body) } } func formatDate (_ date : Date ) -> String { let formatter = DateFormatter() formatter.dateStyle = .long formatter.timeStyle = .medium formatter.locale = Locale(identifier : "ja_JP" ) return formatter.string(from : date ) } } メイン部分では MemoListView を作成し、アプリ起動時にメモの一覧が表示されるようにしています。 import SwiftUI @main struct DemoApplicationApp : App { var body : some Scene { WindowGroup { MemoListView() } } } デモ 作成したアプリのデモ動画です。 概要に記載した操作が行えることを確認いただけるかと思います。 おわりに メモアプリ作成を通じて、SwiftUI、MVVMの知見が得られました。 元々、業務では MVC による iOS アプリ開発 を行っていましたが、 SwiftUIによる実装は画面の再描画を意識する必要が無くなり、処理が見通しやすくなったと感じました。 SwiftUIについては学習し始めたばかりなので、これからもキャッチアップを進めていこうと思います。 参考 Model View ViewModel - Wikipedia SwiftUIの概要 - Xcode - Apple Developer iOS13.3 @Publishedでの値更新からsinkが呼ばれなくなった?(ミス解決) - Qiita エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは。 株式会社 ラク スで先行技術検証をしたり、ビジネス部門向けに技術情報を提供する取り組みを行っている「技術推進課」という部署に所属している鈴木( @moomooya )です。 ラク スの開発部ではこれまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「 開 ( か ) 発の 未 ( み ) 来に 先 ( せん ) 手をうつプロジェクト(通称:かみせんプロジェクト)」 改め 「技術推進プロジェクト」 というプロジェクトがあります。 2020年度は通年で「無停止リリース」について取り組んでいるので、途中ではありますが紹介したいと思います。 今までの記事はかみせんカテゴリからどうぞ。 tech-blog.rakus.co.jp これまでの無停止リリースへの取り組み 前提 無停止の定義 想定している運用 検討したシステム構成 全体像 ポイント説明 DBプロキシにMariaDB MaxScaleを採用 WEBプロキシにApacheを採用 検証方法 負荷のかけ方 シナリオ説明 ミドルウェアのバージョンアップ アプリケーションとDB定義のアップデート 検証結果 残された懸念 立ち上げ時にどうするか まとめ これまでの無停止リリースへの取り組み これまで本ブログでも無停止リリースに関する記事を公開してきました。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp 今回これらを踏まえた上で検証結果をまとめることができたので改めて公開していきたいと思います。 前提 無停止の定義 ここでいう『無停止』とはエンドユーザーから見てサービスが止まっていないことを指します。 冗長化 されたサーバー クラスタ のうち、再起動のために片系が停止するといったケースは許容します。 想定している運用 サービスカットオーバーから一度も停止せずに運用していく、といったことは目指しません。技術的にはできないこともなさそうですが、そこから発生する制約やコスト増などを考慮するとBtoBのビジネスを展開している弊社としては割に合いません。 目指している運用としてはほぼ毎回リリースのたびにサービス停止を伴っている現状から、年1回程度のサービス停止を伴うメンテナンスリリースと年数回~十数回のサービス停止が不要な通常リリースという運用に切り替えていければと考えています。 検討したシステム構成 全体像 システム構成自体は適用可能なサービスが多くなるよう、あまり特殊な構成にならないようにしました。DBプロキシの前段にクエリキューイングのレイヤを入れるなどすると、より対応可能な範囲が広がりそうではありましたが機能レイヤの追加コストと、必ず必要になるほどではないと考えて今回は見送っています。 アーキテクチャ 全体像 ポイント説明 DBプロキシに MariaDB MaxScaleを採用 DBのプライマリ、 セカンダリ の入れ替えなどを制御するためにDBプロキシとして MariaDB MaxScale を採用しました。 弊社のDBは PostgreSQL が多いのですが、 DBMS 自体がオンライン DDL への対応など無停止に向けた機能が充実していたため MariaDB + MariaDB MaxScaleの構成を採用しています。 既存サービスへの適用として PostgreSQL に適応させたDBプロキシについても後述します。 WEBプロキシに Apache を採用 昨今 nginx が優勢になり Apache が過去のものという印象も多いかと思いますが、今回改めて再評価したところ Apache 2.4を採用することにしました。 Apache 2.2の頃までは1プロセスシングルスレッドでプロセスがたくさん立ち上がるせいでメモリ大食いという印象でしたが、今では1プロセスマルチスレッドで動作させることができるのでメモリ消費は大幅に抑えられています。 そして決め手となったのは、 下流 ノード(APサーバー)の死活チェックを業務リク エス トと別でチェックすることができる、Active Health Checkが利用可能ということでした(nginxにもあるけど有償版が必要でライセンスが結構高い)。これを利用することによりAPサーバーの切り離しや復旧を、リク エス トを取りこぼすことなく行うことができるようになります。 検証方法 リリース作業をHTTPリク エス ト負荷をかけた状態で行って、HTTPリク エス ト負荷にエラーレスポンスが含まれないことを目標に検証しました。 負荷のかけ方 負荷は JMeter で、認証、参照、更新の処理を用意して、秒間10リク エス トの低負荷状態と秒間100リク エス トの高負荷状態のパターンで検証しました。 JMeter の使い方については弊社ブログのこちらの記事もご参照ください。 tech-blog.rakus.co.jp シナリオ説明 検証したリリースシナリオは2つ。 ミドルウェア のバージョンアップ APサーバーの ミドルウェア と DBMS のアップデートを行います。これらは必ず再起動が必要となります。OSのアップデートについてもこのパターンでカバーできると判断しています。 処理中のリク エス トを欠損させることなく、切り離しと復旧を行う必要があります。 操作は以下のように行いました。 DB 2号機 切り離し DBMS アップデート 復帰 DB 1号機の降格とDB 2号機の昇格 DB 1号機 切り離し DBMS アップデート 復帰 AP 2号機 切り離し ミドルウェア アップデート 復帰 AP 1号機 切り離し ミドルウェア アップデート 復帰 APサーバーについては1号機2号機の違いは特にないので入れ替えても問題ないかもしれません。 4のDB昇格/降格については MariaDB MaxScaleの switchover コマンドを用いました。 アプリケーションとDB定義のアップデート APサーバー上のアプリケーションバージョンのアップデートとDB上のテーブル定義変更を行います。また、アプリケーションは予期せぬリスクを考慮して本番環境でのホットリロードは行わず再起動を行います。テーブル定義変更は再起動を伴わずに実施します。 操作は以下のように行いました。 プライマリDBにテーブル定義変更の SQL ( DDL )を投入 ( セカンダリ DBには レプリケーション により自動反映) AP 2号機 切り離し ミドルウェア アップデート 復帰 AP 1号機 切り離し ミドルウェア アップデート 復帰 テーブル定義変更は以下の制約があります。 アプリケーション設計時の場合分け表 検証結果 おおむね期待通りに動かすことができたのですが…… 『DBのプライマリ、 セカンダリ の入れ替え時に1秒だけ書き込みエラー』 1つ目のシナリオにて、DBサーバーのプライマリ、 セカンダリ の昇降格処理中に書き込みクエリに対してのみ1秒弱のエラーが発生しました。 MaxScaleが持つコネクションエラー時にリトライするオプションなど(delayed_retryやtransaction_replayなど)を試してみたものの解消することはできませんでした。 試行錯誤の結果、DB 3台によるマルチマスタ構成にすることで解決できました。ただし、マルチマスタ構成の場合でもすべてを解決できるわけではなく、フェイルオーバー時には考慮が必要です。 残された懸念 マルチマスタ構成でも通常Write可能なノードは1つに限られていますが、フェイルオーバーが発生すると別のノードがWrite可能なノードに昇格します。このとき レプリケーション が完了してから昇格できれば良いのですが、 レプリケーション 完了前に レプリケーション 対象のレコードへの書き込みが発生していると不整合が起きてしまいます。 ノード1のレコードAを更新 ノード1が切り離され「ノード1の更新内容をノード2, 3に同期」する前にノード2が書き込み可能に昇格 ノード2のレコードAを更新 1と3のレコードAの状態に不整合が生まれノード1は自動復旧できない といった状況です。 このような状況を避けるために 共同編集機能の制御 システムからの更新を追記型にする など、特定の機能に対しては設計時に考慮が必要になります。 立ち上げ時にどうするか オンプレで構築する場合は2台か3台かのコストの違いが大きいので、アクセスが少ないうちは従来どおりの2台構成+DBプロキシ(今回はMaxScale)といったDB構成が良いと思いますが、 クラウド などの仮想基盤上に構築するのであればストレージ設計は要注意(合計サイズが1.5倍)ですが、最初から3台構成にするのが良いと感じました。 DB以外の構成は適宜サービスごとに改変して使うものの、先述の構成図の通りで問題ないと思います。 まとめ 完全な無停止運用(サービス停止を一切しない)を目指さず、停止を伴うメンテナンスリリースを何度かに1回計画することを前提とすれば、それほど特殊な構成にすることなく無停止リリースはできそうでした。 今回はオンライン DDL への対応が進んでいる MySQL 系統の MariaDB で検証を進めていましたが、以下の記事でも検証している通り、オンライン DDL に対応していない PostgreSQL でも気をつければ実用上は問題なさそうだったので、 PostgreSQL + HAProxy + Patroniなどの構成でも実現できそうな可能性が見えてきました(弊社既存サービスは PostgreSQL 採用率が高いので PostgreSQL が使えると嬉しい)。 tech-blog.rakus.co.jp 引続きHAProxyなどの活用も含めてユーザーの利便性向上を目指していきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
目次 目次 はじめに 結論 前提 TypeScript、Vue.jsで躓いた点 コンポーネント指向の入りやすさ SPA開発の入りやすさ フロントエンド、バックエンド、デザイナーが分かれている難しさ 開発を通じて感じたこと 半年間の反省 最後に 参考 はじめに こんにちは。新卒のmtaaaです。 プロダクト開発にフロントエンドエンジニアとして参加して半年が経とうとしているので、「新卒エンジニアとして」と、「フロントエンドエンジニア」としての2つの視点から感じたことをお話したいと思います。エンジニアを志す学生の方や、私と同じ新卒エンジニアの方に届けば幸いです。使用技術はTypeScript、Vue.jsがメインになります。これらの技術の突っ込んだ話はあまりしないので軽い気持ちで読んでみてください。 結論 後ろはかなり文章量があるので先に結論を言ってしまうと、「新卒エンジニアにとってフロントエンド開発はとても入りやすい」です。詳しくは後述しますが、私が参加したプロダクトが「Vue.jsを採用しているSPA」というのが大きな理由となっています。個人的にエンジニアとしての第一歩として、フロントエンドという選択肢はお勧めしたいです。 前提 最初に私がプロダクトに参加する前の学習期間にどんなことをしていたか軽くお話します。入社後2ヶ月程の Java を中心とした研修の後に配属、その後さらに2ヶ月かけて JavaScript 、TypeScript、Vue.js、Vuex、SCSSといった技術を学習、プロダクトに少しずつ参加していきました。 それまでに上記の技術に触れたことはほとんどなく、 JavaScript をかじった程度でした。これらに限らず自分のプログラミングのスキルは入門者レベルで、これからやっていけるかという不安もありました。 学習方法としては基本的に各公式ドキュメントを読み進め、わからない箇所を調べたり、先輩に教えていただいたりする形を繰り返していました。 また、プロダクトは昨年初リリースしたばかりの新しい商材です。 TypeScript、Vue.jsで躓いた点 まずはメインとなる技術2つを学ぶ上で躓いた点から話していきます。フロントエンドの難しいところとして他の領域に比べて技術の移り変わりが早いために書籍があまり出版されていなかったり、調べた情報が既に古いものだったりする点があります。 TypeScriptはざっくり言うと「 JavaScript に型付けができる言語」のことです。型の違いによるエラーにコーディング時点で気付くことができ、可読性も上がりやすいです。学習は「こういうものなのか」という感覚で比較的スムーズに行っており、わからない点も実際に書く時に調べていけばそれほど困ることはないという印象でした。どちらかと言えば JavaScript と共通の基本文法の知識不足で困ることの方が多いです。 Vue.jsはざっくり言うと「 JavaScript のデータとHTML要素を同期させるための フレームワーク 」です。同じ目的の フレームワーク では有名なものにReact.jsやAngular.jsがあります。中でもVue.jsは日本語の情報が多く公開されており学習しやすいメリットがあります。こちらは学習当初から難航していました。特に ライフサイクル 、 親子関係 、 コンポーネント指向 、 Vuex といった部分に躓き、これらは今でもわからなくなっては調べ直す、を繰り返しています。本記事では脇道に逸れるので詳しくは書きませんが、Vue.jsを勉強してみたいという方はこのあたりの単語を1度調べてみてもいいかもしれません。学習コストが低い、という話をよく見かけますし実際に長期間かけたわけではありませんでしたが、少なくとも私個人としては簡単に理解できたとは言い難いです。 コンポーネント 指向の入りやすさ 学習面では難しい面ばかり書きましたが、私はこの フレームワーク を取り入れた開発は新人が入りやすい形式だと考えています。大きな理由の1つとしてVue.jsの コンポーネント 指向があります。先ほども話に上がった コンポーネント 指向をざっくり言うと、「ページの コンポーネント (パーツ)を準備しておいてその組み合わせでWebページを作り上げること」です。そして私が参加した時点で既に コンポーネント の基盤は作られており、 コンポーネント を組み合わせるだけでひとまずそれらしい見た目のものが作れることは、シンプルに開発の楽しさやモチベーションに繋がりました。 SPA開発の入りやすさ Vue.jsを採用した開発に新卒エンジニアが入りやすかった大きな理由の2つ目としてSPA(Single Page Application)という設計を採用していたことがあります。SPAは「1つのページの必要な箇所のみ変更して画面の切り替えをする アーキテクチャ のこと」です。具体的には最初のページ遷移で全体の情報を取得し、あとはユーザーの操作によって変更する情報だけをサーバーとやり取りします。この形式におけるフロントエンドエンジニアの役割は、「バックエンドと情報をやり取りし、その結果をデザインに沿ってページに反映させること」です。極端なことを言ってしまうと、サーバーから返ってくる情報をデザイン通りに表示すれば最低限は作れます。つまり、小規模な改修のような案件に着手できるようになるまでがかなり早いです。 フロントエンド、バックエンド、デザイナーが分かれている難しさ 私が参加しているプロダクトではデザイナー、フロントエンド、バックエンドが比較的きっちり分かれており、最も重要かつ難しいのはコミュニケーションです。フロントエンドエンジニアは他領域のメンバー間の橋渡し的な役割もあるためコミュニケーションは大事になります。1つのものを作るにあたって領域ごとに違う人が担当する以上細かい認識のずれはどうしても発生してしまうため、手戻りが起こることもあります。これを少しでも減らすには仕様の共有はもちろんですが、なによりコミュニケーションを取りやすい文化が大切だと感じています。 また今はフロントエンドの開発で手一杯ですが、他領域についてもある程度わかっていた方が会話がスムーズに進みますし、相手の意図も汲みやすいので、デザインやバックエンド、インフラについても勉強したいと感じています。フロントエンドの学習に集中することで早くにプロダクトに参加していけるメリットはありますが、やはり最終的には吸収する必要があります。 開発を通じて感じたこと 学習期間中にあまり意識していませんでしたが実務で重要なものとして、 Google Chrome の デベロッパ ーツールを使いこなすことと、レビューされることを意識してコーディングすることがあります。 デベロッパ ーツールはフロントエンドの開発においては本当に必要不可欠です。プロダクトに入るまでは「ログを仕込んで確認する」程度の認識でしたが、サーバーからのレスポンスの確認、styleがどの要素に正しく当たっているか、いないかの確認に加えてなんと言っても 拡張機能 の Vue.js devtools が大きな助けになりました。この 拡張機能 では各ページでどんな コンポーネント を使っているか、どんな値が渡っているかを確認したり、直接書き換えて挙動を見たりしながら実装することができます。ページの特定の部分がどんな コンポーネント で構成されているのか直感的に調べることができるので、プロダクトのソース全体の理解もかなり楽になりました。 レビューされることを意識したコーディングも重要です。これはフロントエンドに限った話ではありませんが、他のメンバーや未来の自分が見て何をしているかわかりやすいコードは相当意識してもなかなか作れないです。 フレームワーク の思想を汲み取ることやプロダクト特有の文化、書き方に合わせることも覚えておきたいです。 また、私は学習面での不足がある段階からプロダクトのソースと挙動を見つつ、小さなバグ対応等からプロダクトに参加する所謂 OJT 形式にすぐに入りました。個人差があるとは思いますが、「習うより慣れろ」というのは大きく、自分自身開発業務の中で成長を感じられましたし、やはり動くものを作ってそれがリリースされるというのは嬉しいです。実務に必要な技術を都度学びながら進めるため回り道なく身に付きます。 半年間の反省 知識不足は当然多いですが、中でも以下は重きを置いて業務や学習に取り組むべきでした。 環境構築は特に勉強不足を感じています。エンジニアとして自分の作業環境をしっかり把握しておきたいですが、参加当初の環境構築以降ほとんど触ることもなかったため、問題が起きた際に原因や対処法に検討が中々つかないです。少なくとも Node.js の知識は深めておきたいです。 次に設計についてです。特にソースの設計は実務に入るまで意識がそもそもなく、コードレビューの中で指摘いただくことも多かったです。具体的にはどのメソッド、ファイルにどれだけの責任を持たせるかやクラスの枠組みといったところは、ただ動くだけではいずれバグの原因になる恐れがあります。ここは学業と仕事とで大きく違う点です。 今までなんとなくで捉えていた単語や技術がそのままになっていることも挙げられます。プロダクト特有の単語もあり、1度調べたり質問したりするだけでは数ヶ月後には忘れてしまっているものです。取ったメモは読み返すことがとても大事です。今もこの記事を書きながら再確認しています。 これらは来年度に解消していきたいですね。 最後に フロントエンドという分野が特に注目されたのはこの数年のことで、専門的な技術者が他の領域に比べて少ないです。そのため、長い目で見て新卒エンジニアにもチャンスのある領域だと思います。もし興味の出た方は是非チェックしてみてください。今回はVue.jsを使ったSPA開発で新卒エンジニアがプロダクトに入っていきやすかった点とその理由、逆に難しかった部分や、開発で得た教訓について話してみました。ここまで読んでいただきありがとうございました。 参考 JavaScript Primer - 迷わないための入門書 #jsprimer TypeScript Deep Dive 日本語版 - TypeScript Deep Dive 日本語版 はじめに — Vue.js Vuex とは何か? | Vuex Vue.js の Composition API における親子コンポーネント間のデータ受け渡し - Qiita フロントエンドのコンポーネント設計に立ち向かう - Qiita Node.jsとはなにか?なぜみんな使っているのか? - Qiita エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
目次 はじめに スキルマップ HTML CSS JavaScript SPA(Single Page Application) JavaScriptフレームワーク パッケージ管理 TypeScript Git Linux Web知識 テスト ブラウザ コーディングルール Docker(必須ではないが知っておくと良い) 情報収集に使えるWebサイト(おまけ) まとめ おわりに はじめに こんにちは、フロントエンドチームの北嶋です。 弊社でフロントエンドチームを立ち上げてから1年以上が経ち、少しずつメンバーも増えてきました。 最近は来年度の新卒メンバーに対する育成プランを考えているのですが、昨今のフロントエンド技術は移り変わりも激しく、学ぶべき項目が多岐に渡っているため、育成プランを考えるのも一苦労です。 ネットでフロントエンド関連の情報を調べると、今では参考にならない古めの記事も多いですし「これではフロントエンド初学者は何を勉強すれば良いのか分かりにくいだろうなぁ」という気持ちでいます。 そこで、 最近のフロントエンド初学者が身に付けておくべきスキルって具体的に何があるのだろう という疑問に対する答えをスキルマップという形で整理してみましたので、今回は皆さんに共有したいと思います。 特に、駆け出しフロントエンドエンジニアの方やフロントエンドの教育担当者の皆さんの力になれればと思いますので、是非参考にしてみて下さい! スキルマップ フロントエンド初学者(駆け出しフロントエンドエンジニア)が身に付けておくと良い技術のまとめです。 基本的には WEB DEVELOPER Roadmap 2021の Frontend Roadmap のトレンドに沿うように考えられていますが、個人的な意見も多いに反映されています。 目標レベル・学習項目・参考資料という3つの観点でまとめています。 目標レベル:現場に入っても問題なく業務をこなせるレベル感(脱駆け出しエンジニア程度のイメージ)を記載しています。 学習項目:理解しておくべき項目・用語を記載しています。 参考資料:目標レベルを満たすために参考となる資料(書籍・Webサイト等)を記載しています。 フロントエンドエンジニアとしてだけでなく、Webエンジニアとして身に付けておきたい技術も含まれています。 OSS -DBを入れるかが迷う所でしたが、実際に業務していて触れる機会が多くないのでひとまずドロップしています。将来的にはWebエンジニアとして理解しておいて欲しい項目ではあります。 1. HTML 目標レベル 基本的なタグを利用したHTMLの記述が行える 発展的なタグを把握している 学習項目 HTML5 参考資料 Webサイト HTML の学習: ガイドとチュートリアル - ウェブ開発を学ぶ | MDN HTML5リファレンス 2. CSS 目標レベル CSS で簡単なスタイル指定が行える SCSSで簡単なスタイル指定が行える 詳細度を理解している 学習項目 CSS3 擬似クラス Flexbox Sass 詳細度 参考資料 書籍 Web制作者のためのCSS設計の教科書 Web制作者のためのSassの教科書 Webサイト CSS - ウェブ開発を学ぶ | MDN 100年後も崩れないCSS勉強会 · 第1回「詳細度」 3. JavaScript 目標レベル ES2015以降の記法で JavaScript を記述できる API 通信を行うコードを記述できる 非同期処理を理解している 学習項目 ES2015以降の記法 Promise async/await API 通信 ESモジュール 参考資料 Webサイト JavaScript | MDN JavaScript Primer - 迷わないための入門書 #jsprimer JavaScript Promiseの本 Udemy 【JS】ガチで学びたい人のためのJavaScriptメカニズム | Udemy 4. SPA(Single Page Application) 目標レベル SPAの概念を理解している SSR ・SSGとの違いを理解している 学習項目 SPA SSR SSG 参考資料 Webサイト ようこそ!2020年、Webフロントエンドの世界へ SPA, SSR, SSGの違いについて図解でまとめてみた 5. JavaScript フレームワーク 目標レベル コンポーネント 指向の概念を理解している Vue.js(または React.js)の公式ガイドを基本的な部分を理解している 状態管理(Flux)の概念を理解している ルーティングの機能を理解している 上記の技術を用いて簡単な アプリ制作 が行える 学習項目(Vueのみ記載) Vue.js Vuex Vue Router 参考資料(Vueのみ記載) Webサイト Vue.js公式 書籍 基礎から学ぶVue.js Vue.js入門 基礎から実践アプリケーション開発まで Udemy 超Vue.js 2 完全パック (Vue Router, Vuex含む) | Udemy Vue.js + Firebaseで作るシングルページアプリケーション | Udemy 6. パッケージ管理 目標レベル nodeの概念を理解している npmの基本的なコマンドを利用できる パッケージ管理システムを利用してプロジェクト作成が行える パッケージ管理システムでパッケージの追加・削除が行える 学習項目 node npm package. json 参考資料 Webサイト 【初心者向け】NPMとpackage.jsonを概念的に理解する 7. TypeScript 目標レベル プリミティブ型の型指定が行える 簡単なオリジナルの型を作成し、型指定を行える 外部ライブラリの型を利用できる 学習項目 TypeScriptの概念理解 型の種類 型の指定 型の作成 参考資料 書籍 プログラミングTypeScript Webサイト 仕事ですぐに使えるTypeScript TypeScriptの型入門 - Qiita TypeScript Deep Dive Udemy 【世界で7万人が受講】Understanding TypeScript 日本語版 | Udemy 8. Git 目標レベル Gitの概念を理解できている 基本的な操作が一通り行える 複数人でのGit運用を経験している 学習項目 概念理解 基本的な操作方法 参考資料 Webサイト サル先生のGit入門〜バージョン管理を使いこなそう〜 9. Linux 目標レベル Linux の基本的なコマンドを利用できる 学習項目 基本的コマンド ファイル操作系 ssh 参考資料 Webサイト 【Linux入門】コマンドライン初心者のための基礎とサンプル | UX MILK オプション含めたsshコマンドの使い方 【Linuxコマンド集】 10. Web知識 目標レベル Web開発で必要な最低限の知識を持っている 学習項目 Web知識 HTTP REST セキュリティ知識 IT知識( 基本情報技術者 レベル) 参考資料 書籍 栢木先生の基本情報技術者教室 WEBを支える技術 体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 Webサイト IT用語辞典 11. テスト 目標レベル テストの種類を把握している テストの種類ごとの目的を理解している 学習項目 テストの種類・目的 Jest 参考資料 Webサイト 【フロントエンド】コンポーネント指向(React, Vue)のテスト方針 - Qiita 12. ブラウザ 目標レベル ブラウザごとに動作に差異があることを理解している Chrome の開発者ツールの基本機能を利用できる 学習項目 ブラウザ差異 開発者ツールの使い方 Vue.js DevTools 参考資料 Webサイト Can I use... Support tables for HTML5, CSS3, etc Chrome DevTools の使い方 | murashun.jp Vue Devtools で快適なデバッグ - ROXX開発者ブログ 13. コーディングルール 目標レベル 良いコード、悪いコードの特徴を把握している 学習項目 特になし 参考資料 書籍 リーダブルコード ― より良いコードを書くためのシンプルで実践的なテクニック プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原 14. Docker(必須ではないが知っておくと良い) 目標レベル 仮想化の概念を理解している Dockerと VirtualBox の違いを理解している Dockerのメリットを説明できる 学習項目 仮想化 ホスト型 ハイパーバイザ型 コンテナ型 参考資料 Webサイト Dockerとは何か?初心者にもわかりやすく仕組みやメリットを解説 | キツネの惑星 15. 情報収集に使えるWebサイト(おまけ) JSer.info Qiita Zenn|エンジニアのための情報共有コミュニティ Github の リポジトリ の月間トレンド Trending JavaScript repositories on GitHub this month · GitHub Trending TypeScript repositories on GitHub this month · GitHub まとめ 機械的 にスキルを並べる形となってしまいましたが、参考になりましたでしょうか。 ざっくりまとめると、フロントエンド初学者の学習ロードマップとしては以下のような手順で学んでいくのが良さそうだと思いました。 HTML/ CSS / JavaScript を学ぶ JavaScript フレームワーク (Vue.jsまたはReact.js)を学ぶ パッケージ管理(node,npm)について学ぶ JavaScript のES2015以降の記法を学ぶ TypeScriptを学ぶ Web開発に必要な知識を身に付ける Web開発で必要なツールの使い方を学ぶ(Git, Linux ,ブラウザの開発者ツール等) フロントエンドのテストを理解する 一般的なコーディングルールを把握する おわりに 自分でまとめてみても「こんなに学習項目があるんだな・・・」と思ってしまったのですが、一つの指標というだけで、現場に入る前に全てを完璧に身に付けておかないといけない訳でもありません。 実際に自分自身も現場に入ってから少しずつ身に付けていった項目もありますし、業務で必要になったタイミングで学ぶ方が身に付くことも多かったりします。 ただ、このようなスキルマップを参考にすることでフロントエンド初学者の方が「この項目のスキルは自分に足りていないな」といった気付きが少しでもあれば嬉しく思います。 それでは、ここまで読んでいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは ラク ス開発エンジニアのhyoshです。 今回は久しぶりのFirebaseシリーズを投稿いたします。 過去Firebaseの多様なソリューションからチャット(RealTime Database)、認証(Authentication)とご紹介してきましたが今回はプッシュ通知(Firebase Cloud Messaging)に携わる機会がありましたのでご紹介させていただきます。 過去の投稿はよろしければ以下もご覧ください。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp Firebase Cloud Messagingについて できること 利用することによるメリット サンプル実装 Firebaseプロジェクトの作成 FCMをアプリに登録 クライアントの実装 メッセージを送ってみる フォアグラウントで通知を受け取れるようにする HTTPで通知を送ってみる まとめ Firebase Cloud Messagingについて できること Firebase Cloud Messaging(以降FCM)はFirebaseのソリューションの一つで、利用することでプッシュ通知を簡単に実現できます。 下図は 公式ガイド に記載されているFCM アーキテクチャ ですが、プッシュ通知は主にメッセージの作成(1)、転送(2,3)、受信(4)という流れで処理されます。 例えば特定タイミングでユーザーにキャンペーン情報を通知したいといったケースを考えた際、これらを全て自前で実装するとなるとかなり敷居が高くなる事は想像がつくでしょう。 一方でFCMを用いれば根幹となる1,2,3をバックエンドでFCMが実施してくれるため、開発者に必要なのはクライアントの軽微な実装のみ(※1)となり複雑な処理の中身を意識する必要がありません。 ※1…実際の開発現場では後述のように1に関しても個別実装するケースが多いかと思いますが、それでもFCMを利用することで自前で行うよりずっと簡易に行えます。 利用することによるメリット FCMを利用してプッシュ通知を実現するメリットですが、私は以下の点を感じています。 バックエンド処理の実装が不要 OSの違いを吸収してくれる( クロスプラットフォーム 対応) 導入・運用コストが低く経済的 1は先にお話した通りで、プッシュ通知を実現するにあたっての煩雑な処理は全てFCMが担当してくれるので、開発者はクライアント実装のみに注力すればよくなります。 2はFCM公式でも強く打ち出している特徴で、 iOS であっても Android であってもメッセージの作成、転送までは同じ処理を共有できるいわゆる 「 クロスプラットフォーム 」 な開発が行えます。 各端末のアプリで実施される受信処理はそれぞれのOSで実装は必要ですが、それでも各OS毎に行う作業はグッと減らせます。 そして3の特徴ですが、これだけ充実したサポートを誇っていながらFCMを利用することでかかるコストは下記の通り 無料 です。 firebase.google.com よくありがちな特 定量 から課金という事もなく、 何通送っても0円です (※2)。 後ほどサンプルで紹介もしますが、導入も非常に容易なのでありがたい限りですね。 これらのことから現在プッシュ通知実装に関し、まずFCMの名前が出てくるのも納得の理由かと感じていただけるかと思います。 ※2…2021年3月時点の情報であり、今後変更となる可能性はあります。 サンプル実装 FCMがバックエンドを担当してくれると言っても実態がイメージしづらいと思うので、ここからは実際に Android で簡単な通知を受け取れるサンプルアプリを作っていきたいと思います。 ※ 公式ガイド をベースとしているため、合わせて参照ください。 Firebaseプロジェクトの作成 まずは表示されているガイドに沿ってFirebaseにてプロジェクトを作成していきます。 1.一意となる任意のプロジェクト名称を入力します。 2. Google アナリティクスを利用することでより効果的にFirebaseのソリューションを使うことができますが、ここではひとまず利用しないでプロジェクトを作成します。 これでプロジェクト作成は完了となり、コンソール画面が表示されます。 FCMをアプリに登録 続いて作成したプロジェクトをアプリに登録し、互いをひもづけます。 1.コンソールの左メニューよりCloud Messagingをクリックし、 Android アイコンを押して設定画面に進みます。 設定は親切なガイドが表示されているので、それに従って進めていきます。 クライアントの実装 ここまででFCM側の作業は完了したので、次に通知を受信するためのクライアント側の実装を行っていきます。 1.FCMでは トーク ンという情報を用いて端末を一意に識別します。 トーク ンの実態は端末とアプリの組み合わせで一意となる文字列情報となり、これをFCMで認知できている事で狙った端末に通知が送れるという仕組みになっています。 もちろん重要情報なので取扱いには重々注意が必要となります。 トーク ンを発行するサービスがFCMから提供されているので次のように実装していきます。 // build.gradle(:app)にFCMライブラリを追加 dependencies { implementation platform( 'com.google.firebase:firebase-bom:26.7.0' ) implementation 'com.google.firebase:firebase-messaging-ktx' // この一行を追加 } package com.example.notifyapplication import android.util.Log import com.google.firebase.messaging.FirebaseMessagingService class MyMessageService : FirebaseMessagingService() { override fun onNewToken(token: String ) { Log.d( "MyMessageService" , "Refreshed token: $token " ) } } 新規にFirebaseMessagingServiceを継承したクラスを作成します。 onNewTokenはFirebaseMessagingServiceに用意されているメソッドでアプリが トーク ンを発行するためにアプリ起動時に呼び出されます。 ただし毎回呼び出される訳ではなくまだ一度も トーク ンを発行していない、何らかの要因で トーク ンを更新する必要がある(※3)といったケースで限定的に呼び出されます。 ここまでできたら一度アプリを動かしてみましょう。 ログに トーク ンが出力されているかと思います。 表示されていない場合は既に発行された後の可能性があります。 そのような場合に備えてガイドでは現在の トーク ンを取得する方法も開示されているので、以下のようにMainActivityに追加してみましょう。 override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(findViewById(R.id.toolbar)) // ここから追加 FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task -> if ( ! task.isSuccessful) { Log.w( "MainActivity" , "Fetching FCM registration token failed" , task.exception) return @OnCompleteListener } // 現行のトークンを取得 val token = task.result // ログに出力 Log.d( "MainActivity" , "Current token: $token " ) }) } これでアプリ起動時に確実に トーク ンがログに出力されるようになったかと思います。 ※3…公式ではアプリを再インストールした、アプリが新しい端末で復元された、アプリのデータを消去したなどが挙げられています。 メッセージを送ってみる 実はFCMでは GUI ベースで通知を送信できる機能が用意されているので、ここまで行えばもう自分のアプリに通知を送る事が可能です。 1.FCMコンソールよりSend your first messageのボタンを押して先に進みます。 2.通知情報を入力します。ひとまず最低限必要なタイトルと本文を入力し「テストメッセージを送信」を押します。 3.ここで トーク ンの入力を求められるので、先ほどログに出した トーク ンを入力しテストボタンを押します。 トーク ンが間違っていなければアプリの動いている端末に先ほど登録した通知が届いたかと思います。 4.テスト通知でなく正式な通知として登録するために後続を進めます。 ターゲットではひとまずアプリとする事でアプリ利用者全員に通知を送信できます。スケジュール設定では送信時間や定期的に送るかを指定できます。 確認の後、公開を押します。 5.これで通知が登録できたので、スケジュール設定で指定した時間に通知が届きます。 別の通知を登録したい場合は「新しい通知」より再度登録します。 ちなみにレポートタブからは送った通知の 開封 率といったデータも見る事ができます。 このように最もシンプルなやり方でも、複数ユーザーに対して時間指定して一斉通知を送る程度であれば簡単に行える事が理解いただけたかと思います。 フォアグラウントで通知を受け取れるようにする ここまでで通知を受け取ることはできましたが、実は今の実装だけではアプリとしてはまだ不完全です。 というのも今の状態では通知を受け取る事ができるのはアプリがバックグラウンドにある状態のみで、フォアグラウンド(操作している時)の状態では通知を受け取る事ができません。 通知の目的を考えるとフォアグラウンドで受け取る必要性は低いとも言えますが、重要な通知で常にユーザーに認識してほしい局面もあるかと思いますので、少し改造してフォアグラウンドでも通知を受け取れるようにしてみましょう。 1.先ほど作成したMyMessageServiceにonNewToken同様、継承元のFirebaseMessagingServiceで用意されている onMessageReceived を実装します。 以下ではonMessageReceivedで通知を受け取り送られてきたタイトルとメッセージの通知を生成し、画面に表示します。 override fun onMessageReceived(remoteMessage: RemoteMessage) { remoteMessage.notification?.let { it -> sendNotification(it) } } private fun sendNotification(message: RemoteMessage.Notification) { val intent = Intent( this , MainActivity :: class .java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) val pendingIntent = PendingIntent.getActivity( this , 0 /* Request code */ , intent, PendingIntent.FLAG_ONE_SHOT) val channelId = getString(R.string.default_notification_channel_id) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder( this , channelId) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(message.title) .setContentText(message.body) .setAutoCancel( true ) .setSound(defaultSoundUri) .setContentIntent(pendingIntent) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Android OS 8以降はチャネル指定が必須 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel(channelId, "チャネル説明" , NotificationManager.IMPORTANCE_DEFAULT) notificationManager.createNotificationChannel(channel) } notificationManager.notify( 0 /* ID of notification */ , notificationBuilder.build()) } -- strings.xml <resources> <string name= "app_name" >NotifyApplication< / string> //以下一行を追加 <string name= "default_notification_channel_id" >fcm_default_channel< / string> < / resources> 最後にAndroidManifest. xml にサービスを登録します。 <service android:name= ".MyMessageService" android:exported= "false" > <intent - filter> <action android:name= "com.google.firebase.MESSAGING_EVENT" / > < / intent - filter> < / service> 確認する為にコンソールよりテスト送信してみると、フォアグラウンドでも通知を受け取れるようになった事が分かるかと思います。 (分かりづらいですが左上の●が届いた通知です) このようにonMessageReceivedまで実装しておく事でバックグラウンドではFCMよりアプリを通さず直接通知を表示、フォアグラウンドではアプリ経由で通知を表示といったアプリ状態によらず常に表示が可能になります。 HTTPで通知を送ってみる 最後にオプションとしてHTTPリク エス トとして通知を送ってみましょう。 1.Firebaseコンソール−プロジェクトの設定−CloudMessagingからサーバーキーを確認します。 2.FCMの通知送信用として用意されている API は「 https://fcm.googleapis.com/fcm/send 」となるので、これに対し必要なパラメータを付与しPOSTリク エス トを投げます。 HeadersのAuthorizationのkeyには先ほど確認したサーバーキー、Content-Typeはapplication/ json を指定します。 そしてBodyにはtoに対象端末の トーク ン、notificationにタイトルと本文を指定します。 ツールなどで送信してみるとこのやり方でも端末に通知が届く事が分かるかと思います。 実際のシステムではタイミングが決まっておらず何らかの処理をトリガーに通知を送りたいといったシーンも多いかと思われますので、そのような時に活用できるでしょう。 なお今回は簡易なHTTPを用いましたが 公式ガイド で推奨されている後継の プロトコル が存在するため、可能であればそちらを使う事が望ましいです。 まとめ 今回はFirebaseを用いたプッシュ通知実装に関してご紹介させていただきましたがいかがだったでしょうか。 FCMを用いることで思ったよりも簡単に実現できることを理解いただけたのではないかと思います。 iOS との連携に関してはご紹介できませんでしたが、クライアント側の実装としてはほぼ同じとなりOS間の違いを意識することなく開発する事が可能なので、興味が湧きましたらぜひ試していただけますと幸いです。 最後までお読みいただきありがとうございました。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは、takaramです。 今回はPHPDocについて、特に 型 の重要性と、応用的で便利な書き方をご紹介したいと思います! はじめに PHPの型を使いこなしたい PHPDocとは? PHPDocの仕様 多くのツールで有効なPHPDocの書き方 型の書き方 配列型 false型 @property ローカル変数の型 まとめ おまけ:配配メール開発チームの取り組み PHP の型を使いこなしたい PHP でも近年、静的型付け言語と同じようにメソッドの引数や戻り値、クラスのプロパティなどの型宣言を書くことができるようになってきています。型宣言はPHP5.0から部分的にサポートされていましたが、本格的に使えるようになったのは2015年リリースの7.0あたりからです。 PHP 7.0: スカラー型宣言、戻り値の型宣言 PHP 7.1: nullableな型 PHP 7.4: プロパティの型宣言 PHP 8.0: union型、mixed型の追加 多くの静的型付け言語にある ジェネリクス 機能が PHP にはないなど、まだ十分とは言えない部分もありますが、このように動的型付け言語に型宣言を追加するという試みはTypeScriptや Python 、 Ruby などでも行われていて、時代の流れと言えるかもしれません。 しかしそもそも、なぜ PHP にわざわざ型を書く必要があるのでしょう?メリットとしては、以下のようなものがあります。 実行時に型チェックされる(予期しない値が渡されることを防げる) IDE で補完が効きやすくなる 静的解析がより正確に実行できる このうち実行時型チェックは、新規コードでは安心・便利な一方、型宣言のない時代のコードを引き継ぐ現場では、動いている既存コードに下手に型宣言を追加するとかえって動かなくなるというリスクも考えられます。 そのため、既存コードへの型宣言追加には二の足を踏んでいる現場も多いのではないでしょうか。 しかし、そのために IDE のコード補完などのメリットを捨ててしまうのはもったいないです。 そこで、PHPDocによる型情報の補足が重要となってきます。PHPDocは基本的にはプログラムの動作に影響しないため、型宣言にくらべると既存コードにも追加しやすいと思います。 以下ではPHPDocとその書き方について、私が担当しているプロダクト「 配配メール 」の既存コードのPHPDoc整備を進めた経験も交えて紹介していこうと思います。 PHPDocとは? そもそもPHPDocとは何か、について説明しておきましょう。そんなの知ってるよ!という方は 次のセクション まで飛ばしてください。 PHPDocとは、 PHP で書かれた下記のものについてのドキュメントを、 ソースコード のコメント内に記述するための書式、およびその書式に従って書かれたコメントを指します。 関数 定数 クラス メソッド プロパティ etc. PHPDocは /** ... */ の Docコメント という形式のコメント内に記載します。 一部のツールやライブラリはDocコメントに特定の内容を書くことで動作を変えるものもあります *1 が、基本的には単なるコメントに過ぎないためプログラムの動作には影響しないと思っていいでしょう。 例として、 psr/container の ソースコード を見てみてください。インターフェースとメソッドの説明がPHPDocで書かれていて、メソッドの引数や戻り値の説明は @param , @return のような文字列( タグ といいます)に続いて書かれているのが分かると思います。 ここでは書式の詳細な説明はしませんが、雰囲気だけでも掴んでください。 PHPDocの書式に則ってコメントを書くことは、通常のコメントと同じくチームの他の開発者や、未来の自分に向けた説明としてももちろん有用です。ただそれだけではなく、PHPDocを活用したツールが多く存在していて、それらを活用できるメリットがあります。具体的には、以下のようなツールがあります。 phpDocumentor PHPDocを元にHTML形式のドキュメントを生成してくれるツール。ライブラリのリファレンスなどで使われる。 PhpStorm PHPDocから変数等の型を検出し、コード解析、自動補完に利用する。 PHPStan , Phan , Psalm 不具合の可能性があるコードを検知してくれる静的解析ツール。引数の型の不一致や存在しないメソッド呼び出しなどを検出する。 PHPDocとこれらのツールを使いこなすことができれば、 PHP での開発を効率的に進められます。 PHPDocの仕様 このように様々なツールで利用されているPHPDocですが、実は明確な仕様というものは決まっていないのです。 言語仕様以外の PHP の標準規格を確立するPSRというプロジェクトの一部として、PHPDocの仕様 "PSR-5" の草案が作成されてはいますが、議論が中々まとまらず、2021年現在未だに標準化されていません。 そのため各ツールで有効とされる書式が微妙に異なり、「あのツールで有効な書き方がこのツールではエラーになる」といったことが発生しうる状態です。実際にPHPDocを書く際には、自分が利用するツールの仕様書や実際の動作を確認して使うのがよいでしょう。 とはいえ、どのツールも大枠の書式は一致しています。基本的な書き方をご存じない方は、 phpDocumentorのドキュメント を読んでみてください。 多くのツールで有効なPHPDocの書き方 ここからは多くのツールで有効かつ便利な、PHPDocの応用的な書き方を紹介していきます。 型の書き方 PHPDocの @param タグや @return タグ、 @var タグ等で何気なく書いている型も、より適切な書き方があるかもしれません。 配列型 PHPDocで配列型といえば普通は array ですが、それ以外にも書き方があるのをご存知でしょうか? 数値キーの配列: int[] , Clazz[] 文字列キーの配列: array<string, int> , array<string, Clazz> キーごとに値の型が異なる配列: array{id: int, name: string} 例として、名前・年齢・住所を持つHumanクラスのサンプルを下に示しています。ここに書かれているPHPDocでは、 プロパティ $propertyKeys は文字列の配列 プロパティ $property はキーが文字列、値が文字列または整数の 連想配列 コンストラクタ の引数はキー name の値が文字列、キー age の値が整数、キー address (省略可能)の値が文字列の 連想配列 であることを表しています。 <?php class Human { /** @var string[] */ private $ propertyKeys = [ 'name' , 'age' , 'address' ] ; /** @var array<string, string|int> */ private $ property = [] ; /** * Human constructor. * * @param array{ * name: string, * age: int, * address?: string * } $property */ public function __construct ( $ property ) { foreach ( $ this -> propertyKeys as $ propertyKey ) { $ this -> property [ $ propertyKey ] = $ property [ $ propertyKey ] ; } } } こうした書き方をすることで、単にarrayと書くのに対していくつかメリットがあります。 new Human(['job' => 'engineer']) のような不正な引数を静的解析で検知できる foreach ($array as $key => $value) の $key , $value の型がわかるので、 IDE で補完が効いたり、静的解析の精度が上がったりする ドキュメントとしてもわかりやすくなる int[] 形式以外の2つは残念ながらPhpStormでは未対応なのですが、静的解析ツールを利用しているならこの書き方を採用してみてください。 false型 「true か false」を表す型は bool または boolean ですが、単に true , false と書くこともできるのはご存知でしょうか? PHP の組み込み関数では、例えば file_get_contents のように、失敗したらfalseを返すような関数があります。 自作関数でもそれにならって「成功時は処理結果を、失敗時はfalseを返す」ような関数にしている場合もあると思います。そのような関数のPHPDocは、 @return string|bool よりも @return string|false と書くべきです。 もし bool と書いてしまった場合、以下のようなコードを書くと静的解析ツールに怒られます。 <?php /** * @param string $fileName * * @return string|bool */ function getContents ( $ fileName ) { return file_get_contents ( $ fileName ) ; } $ contents = getContents ( '/tmp/foo.txt' ) ; if ( $ contents === false ) { exit ( 1 ) ; } // ファイルの内容を大文字にして出力 echo mb_strtoupper ( $ contents ) ; $contents === false のときの処理もきちんとしていて、実際の動作上エラーは出ないコードですが、 getContents() の戻り値を string|bool としてしまっているため、静的解析ツールは「trueの可能性がある値を mb_strtoupper() の引数に渡している」と判断してしまうのです。 上記のコードのPHPDocを @return string|false に書き換えることで、静的解析のエラーは解消されます。 PHPStanの例。string|boolだと エラーが出る が、string|falseにすると 解消する 。 @property @property は主にクラスのPHPDocに書くタグで、 __get() , __set() を使った動的なプロパティを記述することができます。 ……という説明はググれば他にいくらでも出てくるので、今回は少し変わった使い方を紹介したいと思います。 @property を使うことで、親クラスから継承したプロパティの型を、より厳密にすることができます。 例)親クラスでDateTimeInterfaceのプロパティを、子クラスではDateTimeImmutableにする <?php class Base { /** @var DateTimeInterface */ protected $ datetime ; public function __construct () { $ this -> datetime = new DateTime () ; } } /** * @property DateTimeImmutable $datetime */ class Child extends Base { public function __construct () { $ this -> datetime = new DateTimeImmutable () ; } /** * 明日の日付を返す * * @return DateTimeImmutable */ public function getTomorrow () { return $ this -> datetime -> modify ( 'tomorrow' ) ; } } 上記の例では、Childクラスに @property DateTimeImmutable $datetime をつけることによって、 getTomorrow() メソッドのところで静的解析に怒られないようにしています( DateTimeInterface::modify は存在しないため)。 私のチームで実際に行った例としては、Webフレームワークの各クラスを継承して独自拡張しているクラスのプロパティでこれを利用しました。以下にサンプルコードを示します。 <?php namespace Framework { class Controller { /** @var Session */ protected $ session ; } class Session { } } namespace App { /** * @property Session $session */ class BaseController extends \Framework\Controller { } class Session extends \Framework\Session { public function originalMethod () : void { echo 'I am \App\Session!' ; } } class SampleController extends BaseController { public function index () : void { $ this -> session -> originalMethod () ; } } } このように、 フレームワーク の \Framework\Controller , \Framework\Session クラスを拡張し、 \App\BaseController , \App\Session クラスを作成しています。一番下で SampleController から $this->session->originalMethod() を呼び出していますが、 @property を書かない場合だと $this->session は フレームワーク 側の Session クラスだと認識されてしまい、コード補完、静的解析とも上手くいきません。 注意点として、この方法には「 @property で書いたプロパティがpublicと認識されてしまう」という欠点があります。しかしながら、上記のようなコントローラークラス等であれば、 プログラマ が自分でnewして インスタンス を扱うことはほぼ無いためあまり問題にはならないかと思います。 ローカル変数の型 PHPDocを使えば、ローカル変数にも型をつけることができます。 <?php foreach ( $ iterable as $ item ) { /** @var DateTime $item */ echo $ item -> format ( 'Y/m/d' ) . PHP_EOL; } 上記のように、foreachのループ変数の型を示す以外に、「型定義上はmixedだが人間から見ると型が明らか」という場合に便利です。 例えば下の例のように、DBのカラムから値を取得する場合「 id は integer 型のカラムだから戻り値も int だ」というのは プログラマ はわかっていても、 IDE や静的解析ツールはそこまで汲み取ってはくれません。 そのような場合にPHPDocで変数の型を明示すると便利です。 例)DBから値を取得する場合、テーブル定義を知っていれば型もわかる <?php function getUserId ( string $ email ) : int { $ pdo = new PDO ( 'pgsql:host=localhost;dbname=postgres' , 'postgres' ) ; $ statement = $ pdo -> query ( 'SELECT id FROM users WHERE email = :email' ) ; $ statement -> execute ([ ':email' => $ email ]) ; /** @var int $id */ $ id = $ statement -> fetchColumn () ; return $ id ; } まとめ 今回は「型」に絞ってPHPDocの応用的な書き方をご紹介しました。このような方法で適切に型を記述することで、 IDE の自動補完 → 開発体験の向上 静的解析の精度向上 → バグを減らせる といったメリットを享受することができます。これからPHPDocを書く際に、この記事の内容が少しでもお役に立てれば幸いです。 おまけ:配配メール開発チームの取り組み 私が所属する 配配メール 開発チームでは現在、古くからあるコードのPHPDocの整備を進めており、今回紹介した内容も多くはその中で実際に利用したものです。 以前はPHPDocが書かれていなかったり、誤った型が書かれている箇所が多くあるなど問題となっていましたが、そこから整備を進め、現在は多くの箇所で利用している共通関数・クラスの対応を完了しました。その結果、 IDE の補完が効くようになったり、誤った不要な警告が出なくなったりといった効果が出始めています *2 。 今後、さらに範囲を広げてPHPDoc整備を進めながら、現在はできていない静的解析の導入も目指していきたいと考えています。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com *1 : PHPUnit , PHP -DI など。この用途では、今後はDocコメントではなく、PHP8で導入された アトリビュート 機能に置き換わっていくかも。 *2 : なお、新規コードについてはコーディング規約とコードレビューでPHPDocが正しく書かれるようにしています。整備の対象となるコードを新たに生み出さないことも重要ですね。
アバター