TECH PLAY

株式会社ラクス

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

953

技術広報の yayawowo です。 SQL で条件分岐を用いるには、どのように記述すれば良いでしょうか? 今回は、SELECT文やUPDATE文で利用する条件分岐方法として、「CASE式」をご紹介します! CASE式の使い方を習得いただくため、お手元で実行可能な SQL 文付きで解説します。 是非、実践しながら習得ください! ※本説明では、 PostgreSQL 9.6を利用します。 テーブルの準備 CASE式をマスターしよう CASE式の基本的な使い方 式を使った場合 曖昧判定(LIKE句)を使った書き方 複数の条件分岐を使った書き方 CASE式をUPDATEでも使ってみよう CASE式 まとめ ◆ 【 SQL 入門】 PostgreSQL 関連記事 ・ 【SQL入門】INSERT まとめ ・ 【SQL入門】UPDATE まとめ ・ 【SQL入門】DISTINCT 使い方 ・ RDBMSとDBMSについて【初心者向け】 ・ SQLの基本【まとめ】 ・ 【RDBMS】PostgreSQLインストール・コマンド入門編 テーブルの準備 まず、CASE式の解説に入る前に今回使うテーブルを作成します。 テーブルの列定義とCREATE文は以下の通りです。 ◆ 列定義 列名 データ型 PK animal _no integer ○ animal_name text animal_breed text animal_sex text ◆ SQL 文 --テーブル作成SQL文 CREATE TABLE sample_animal ( animal_no integer primary key, animal_name text, animal_breed text, animal_sex text ); 上記の通り、テーブルが完成しましたのでデータも入れていきたいと思います。 ◆ SQL 文 --SQL文:データ追加 INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex) VALUES ( 1 , ' 犬 ' , ' 柴犬 ' , ' 女 ' ); INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex) VALUES ( 2 , ' 犬 ' , ' 柴犬 ' , ' 男 ' ); INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex) VALUES ( 3 , ' 犬 ' , ' チワワ ' , ' 男 ' ); ◆実行結果 animal _no animal_name animal_breed animal_sex 1 犬 柴犬 女 2 犬 柴犬 男 3 犬 チワワ 男 データ準備までできましたので、早速CASE式の説明に入っていきたいと思います! CASE式をマスターしよう CASE式の基本的な使い方 まずは、CASE式の基本的な使い方をご説明します。 基本的な書式は以下の通りです。 SELECT文を用いてテーブル検索をする際に、良く利用します! ◆ 書式 SELECT *, CASE [条件の対象となるカラム名] WHEN [条件A] THEN [処理A] WHEN [条件B] THEN [処理B] WHEN [条件C] THEN [処理C] ELSE 処理D END FROM [テーブル名]; 「WHEN」の後に条件式を記載し、「THEN」の後にその条件を満たした際の処理を記述します。 「ELSE」には、どの条件式にも当てはまらない際の処理を書きましょう! また、最後にENDで閉じるのをお忘れなく! では、上記の書式を使って先ほど作成したテーブルを検索してみます。 柴犬なのか、柴犬以外なのかをCASE式を利用して見てみます。 ◆ 例1 animal_breedが「柴犬」👉「柴犬です」と表示         それ以外👉「柴犬以外です」と表示 ◆ SQL 文 --CASE式:柴犬判定 SELECT animal_no,animal_name, CASE animal_breed WHEN ' 柴犬 ' THEN ' 柴犬です ' ELSE ' 柴犬以外です ' END FROM sample_animal; ◆実行結果 animal _no animal_name case 1 犬 柴犬です 2 犬 柴犬です 3 犬 柴犬以外です 上記の通り、正しく検索ができましたでしょうか? 式を使った場合 先ほどのCASE式は、WHENの後に指定した条件と要素が=(イコール)の際に利用する記述方法です。 こちらの記述方法以外に、条件に式を書いて判定する方法もあります。 条件に式を使った例は、以下の通りです。 CASEの後ろに [条件の対象となるカラム名] を記載しておりましたが、式を使う場合は不要です。 ◆ 例2 animal _no が3以上 👉「柴犬以外です」と表示      それ以外👉「柴犬です」と表示 ◆ SQL 文 --CASE式:柴犬判定(式を使った場合) SELECT animal_no,animal_breed, CASE WHEN 3 <= animal_no THEN ' 柴犬以外です ' ELSE ' 柴犬です ' END FROM sample_animal; ◆実行結果 animal _no animal_breed case 1 柴犬 柴犬です 2 柴犬 柴犬です 3 チワワ 柴犬以外です 曖昧判定(LIKE句)を使った書き方 CASE式の条件式では、LIKE句を使うことで ワイルドカード を利用できます。 早速例題を見てみましょう! ◆ 例3 animal_breedに「柴」がつく👉「柴犬です」と表示          それ以外👉「柴犬以外です」と表示 ◆ SQL 文 --CASE式:柴犬判定(LIKE句を使った場合) SELECT animal_no,animal_breed, CASE WHEN animal_breed LIKE ' %柴% ' THEN ' 柴犬です ' ELSE ' 柴犬以外です ' END FROM sample_animal; ◆実行結果 animal _no animal_breed case 1 柴犬 柴犬です 2 柴犬 柴犬です 3 チワワ 柴犬以外です チワワの場合は、「柴犬以外です」と判定されていることが分かると思います。 また、LIKE句にて利用する検索方法を一覧にてまとめましたので、こちらもご参考ください。 検索名 検索方法 前方一致検索 LIKE '●%' 後方一致検索 LIKE '%●' 部分一致検索 LIKE '%●%' 完全一致検索 LIKE '●' 否定検索 NOT LIKE '%●%' ※部分一致にて否定検索する際の記述 複数の条件分岐を使った書き方 複数の条件を 入れ子 (CASE式の中にCASE式)構造にして、記述することもできます。 ◆ 例4 条件①  animal_sexが「男」 且つ、   条件②    animal_breedが「チワワ」👉「人気」と表示            それ以外👉「おすすめ」と表示 それ以外👉「定番」と表示 ◆ SQL 文 --CASE式:複数条件での判定 SELECT animal_no,animal_breed,animal_sex, CASE animal_sex WHEN ' 男 ' THEN CASE animal_breed WHEN ' チワワ ' THEN ' 人気 ' ELSE ' おすすめ ' END ELSE ' 定番 ' END FROM sample_animal; ◆実行結果 animal _no animal_breed animal_sex case 1 柴犬 女 定番 2 柴犬 男 おすすめ 3 チワワ 男 人気 いかがでしょうか? CASE式を 入れ子 構造にすることで、複数条件を指定した処理を実現することができます。 用途に応じて使い分けてください。 CASE式をUPDATEでも使ってみよう CASE式は、UPDATE文でも利用可能となっております。 早速以下例題をやって、理解を深めてみましょう。 ◆ 例5 animal_sexが「女」👉「男」      それ以外👉「女」 現在テーブルに登録されているanimal_sex(性別)を変更します。 ◆ 変更前の結果 animal _no animal_name animal_breed animal_sex 1 犬 柴犬 女 2 犬 柴犬 男 3 犬 チワワ 男 では、UPDATEをかけていきます。 ◆ SQL 文 --CASE式:UPDATE文への応用 UPDATE sample_animal SET animal_sex = CASE animal_sex WHEN ' 女 ' THEN ' 男 ' ELSE ' 女 ' END ; --全件検索 SELECT * from sample_animal; ◆ 変更後の結果 animal _no animal_name animal_breed animal_sex 1 犬 柴犬 男 2 犬 柴犬 女 3 犬 チワワ 女 性別が正しく更新されましたでしょうか? CASE式は、SELECT文だけでなく、UPDATE文でも応用することができますので覚えておきましょう。 CASE式 まとめ いかがでしたでしょうか? 今回は、 SQL 入門としまして『CASE式 まとめ』をご紹介させていただきました。 実際にお手元で SQL を動かすことで、より理解を深めることができたのではないでしょうか。 改めまして、本記事がCASE式を学ぶ方にとって、少しでもお役たてれば幸いです。 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 )です。 ラク スの開発部ではこれまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「技術推進プロジェクト」 というプロジェクトがあります。 このプロジェクトで「WEBアプリケーションのDockerコンテナ移行」にまつわる検証を進めているので、その中間報告を共有しようかと思います。 本検証での想定環境 CIに不必要な部分は後回し 既存アプリでコンテナ化の障害になった部分 OSコマンドを利用している ミドルウェアとの密結合 オンライン系とバッチ系の密結合 ひとまず目指す状態 プロセス相乗りの影響 ログが複数出力される まとめ 続きの記事も書きました。 tech-blog.rakus.co.jp 本検証での想定環境 Docker Compose k8s も下期に検証できたらいいなぁ GitLab CI CIでの動作をひとまず目標として本番運用に必要な検証は後回し 対象のサービスは20年以上運用されたレガシーな PHP アプリ LAMP 全盛期に開発されたアプリ 構成を一部抜粋するとこんな感じ。 WEBサーバーにDBサーバーも相乗りしている構成で、詳しくは後述しますが PHP プログラムと Postfix /Cronは密結合している状態です。 CIに不必要な部分は後回し Dockerコンテナ化してCIを回しやすくする 1 ことを最優先として、本番運用に必要な要件や理想論的な設計は無理に追わないようにします。 CIを活発に回しやすくすることで、その後の改善難易度が下がると想定しています。 ログ収集の仕組み DBや設定ファイルの永続化 冗長性確保 例えば、上記のような観点はついでの範囲でやれるならやるが無理はしない。 Dockerコンテナ化を最優先。 既存アプリでコンテナ化の障害になった部分 OSコマンドを利用している まず、解決課題に上がったのがこちらの課題でした。 PHP プログラムから、 awk や find などのOSコマンドを呼び出している部分がありました。 今では ウェブアプリケーション からOSコマンドを叩くことはあまりしないと思いますが、今から約20年前―― LAMP 2 が提唱されて間もない頃です――には、OSとアプリケーションの分離といった概念も今ほど浸透していなかったように思います 3 。 各種処理を実装するにあたって、今ほどライブラリエコシステムも充実していなかったということもあり、OSコマンドを活用することは当時の状況では合理的だったと思います。 いわゆる、 レガシーシステム と呼ばれる ウェブアプリケーション では多く採用されていると思われます。 なお、当該アプリケーションは Linux + Apache + PostgreSQL + PHP のLAPP構成です。 しかし、Dockerコンテナ化を進めるにあたっては課題となります。 解決策としてはいくつかの方法が考えられます。 OSコマンドで行っている処理を PHP 実装に置き換える コンテナイメージにOSコマンドをインストール ホストのOSコマンドを呼び出す権限を付与 理想としては1の方法なのですが、利用しているOSコマンドの種類が20以上、利用箇所も100を超える部分で利用しています。 改修コストを掛けたところでサービスの顧客提供価値は変わりません。 となると、ビジネス的にはゴーサインは出せないでしょう。 3の方法はそもそもこんなことができると思ってもいなかったのですが、社内で中間発表を行った際にこんな事ができると教えてもらいました。 ただし、この方法はセキュリティ面もさることながら 4 、コンテナ化して得られるはずのポータビリティがDockerコンテナ実行環境のホストOSにインストールされているコマンドによって、オミットされてしまうので避けたいです。 となると、現実的な案としては2の方法になるかと思います。 「Dockerコンテナでの実行は余計なコマンドがない分セキュアになる」というメリットが薄れはするものの、現行の余計なOSコマンドまで揃っている状態に比べれば、利用するOSコマンドしか存在しない分だけセキュアになりますし、対応するコストもDockerfile内でコマンドインストール命令を1行追加するだけです。 コンテナイメージのサイズが若干増えるデメリットもありますが、全体で見れば微々たるデメリットだと思います。 最終的にはOSコマンドへの依存はなくしたいですが、Dockerコンテナ化してテスタビリティを上げてからのほうが依存の解消もやりやすそうです。 Dockerコンテナ化を優先するのであれば、2の方法が最良だと思います。 ミドルウェア との密結合 次の課題はこちらです。 この課題は、詳しく見ると2つに分けることができて PHP プログラムから設定ファイルを書き換えて ミドルウェア をリロードしている ミドルウェア の動作をトリガーに PHP プログラムが実行されている の2つとなります。 素直にコンテナ設計をしていくと ミドルウェア は PHP コンテナとは別コンテナになると思いますが、上記の処理が含まれている場合に素直に分けることができません。 まず1つ目の課題については、王道な設計として 設定ファイルをDockerコンテナ外に出して永続化 永続化された設定ファイルを更新 Dockerコンテナを再起動 があります。 しかしこの設計ですと… 設定ファイルを永続化するストレージをどうする? リロードした場合と再起動した場合で ミドルウェア にアクセスできないタイミングが増える? と課題が増えます。 2つ目の課題については ミドルウェア によるトリガーをHTTPリク エス トなどに変換して投げる仕組みと、リク エス トを受け付けて PHP プログラムを起動する仕組みを作れば対応できそうです。 しかし、例によって該当箇所が複数あること、この改修を行っても顧客提供価値が変わらないことから初手では取りにくい対応です。 この課題については、まだ既存処理の理解を進めている最中なのでまた方針が変わるかも知れませんが、今回はCIに利用できるところまで持っていくという前提です。 そのため、最初は割り切って PHP コンテナに相乗りさせようと思っています。 同一コンテナ内であれば既存の処理通り、設定ファイルのリロードもできますし、 PHP プログラムの起動も可能になります。 ただし、この方針はCIで動作させることを前提としたものになります。 本番運用を視野に入れると設定ファイルが永続化されないといった問題や、ログファイル出力の課題が出てきます。 それでもDockerコンテナ化によってCI環境が簡略化され、活発にCIを活用することができるようになれば問題となっている部分の解決もやりやすくなると考えています。 まずはDockerコンテナ化。 オンライン系とバッチ系の密結合 3つ目の課題は、先述の ミドルウェア の件と似ているのですが、オンライン系とバッチ系が1つのコードベースになっていることです。 既存の仕組みではCronから PHP プログラムを呼び出すことで実行制御を行っています。 これ自体は問題ないのですが、コンテナ アーキテクチャ におけるバッチ実行制御というと以下のようなものが王道かと思います。 バッチ処理 を実行するバッチコンテナの外にスケジューラーを用意 スケジューラーが バッチ処理 を実行するバッチコンテナを起動 バッチコンテナは処理が終わったら停止 今回はCIでの利用をターゲットに定めているので、スケジューラーによる実行制御は必要ありません。 そのため、課題として見えているものの顕現しているわけではないので、あまり問題にならないので外部スケジューラーの準備や、外部スケジューラーからの起動を受け付ける仕組みの導入は見送っています。 大雑把に対応するのであればバッチ系のコードを分離できていない以上、オンライン系も含めたコードベースを持つバッチ用コンテナイメージを用意して、コンテナ起動時の引数で実行するプログラムを選択するような仕組みが一番楽でしょうか。 オンライン系が混在しているため、 ソースコード の修正が入ったときにはバッチ用コンテナイメージも更新しなければならないのが手間ではありますが…。 バッチ系の分離もオンライン系と共有している ソースコード の扱いをどうするかなど、コード管理上の課題に波及してしまうので今回はDockerコンテナ化を最優先として後回しにしています。 ひとまず目指す状態 ここまで触れた課題を考慮した結果、まず目指す状態を上記の状態と設定しました。 見ての通り、ほとんどそのままコンテナ化します。 PostgreSQL コンテナ部分については本番運用時はコンテナではなく VM だったり、ベアメタルだったりという選択肢もあると思いますが、CIで利用する分にはデータも永続化せずに毎回リセットされた方が都合が良いです。 ただし、プロセスを相乗りするのはDockerコンテナの作法から外れることは間違いないので、(今回はあまり大きな問題ではないですが)後述のように別の課題が生まれてきます。 プロセス相乗りの影響 他にも課題となる影響があるかも知れませんが、プロセスの相乗りによって発生する4つ目の課題と認識しているのはログ出力についてです。 ログが複数出力される stdout, stderrの2種類で対応できないログ出力が行われる。 ログの種類 access .log (stdoutに出力) error.log (stderrに出力) php .log cron maillog php .log, cron, maillogの扱いを考えないといけない。 本番で扱うとしたら Dockerコンテナ内でログエージェントを持つ すべてstdout/stderrにラベル付きで出力してDockerコンテナ外で分離する の2択かと思います。 CIで使えればいい(=エラー検知されたら人力で確認できればいい)ので 「3. ホストをマウントしてログファイル出力」 で対応します。 冗長化 とか考え出すと問題が出てきそうですが、今回は後回しにします。 まとめ OSコマンドの利用を排除する ミドルウェア の設定ファイルをアプリケーションから更新しない どうしても必要なら設定管理マネージャーとなるサービスを立てて最低限の独立性を保つ せめて バッチ処理 だけでも 疎結合 にする できれば、単体のアプリケーションとして実行可能にできると理想的 今から設計、開発する場合には最初からDockerコンテナで動作させるケースが多いと思うので自然と回避できる部分が多いと思いますが、 LAMP 環境全盛期の レガシーシステム なアプリケーションをリアーキテクトする場合の参考にはなるかと思います。 これらの方針をもとに下半期に検証を進めて、実際にやってみてどうだったか報告できればと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 現状でもCIは回しているが、CI実行するバージョンを切り替えるたびにCI用DBの マイグレーション が必要になるなど不便な状況になっている。 ↩ Linux + Apache + MySQL + PHP / Perl / Python という構成。 ↩ 歯切れが悪いのは20年も前となると私が学生だった頃で、趣味で ウェブアプリケーション も書いていたもののプロダクションレベルで携わってきたわけではないのでちょっと自信がないためです。 ↩ 現状がOS上で直接動作している状況なので、それに比べるとセキュリティリスクが高いわけではないとは思います。 ↩
こんにちは。開発課のtaku_76です。 最近業務で機能開発をしているときに、要件として実現する内容が単純であっても手を加えるコードが複雑であったため機能改修に時間がかかることがありました。 そこから リファクタリング の意識が強くなったため、社内で行われた リファクタリング の輪読会に参加したり、個人的に書籍を読んだりしているので今回は リファクタリング の基礎について記事を書こうと思います。 リファクタリングとは リファクタリングのメリット 可読性の向上 コードの変更が容易になる 開発スピードが向上する リファクタリングの対象 わかりにくい名前 重複コード 変更可能なデータ 長い関数 基本的なリファクタリングの紹介 関数として切り出す 条件の分解 条件の統合 ガード節による置き換え 最後に 参考書籍 リファクタリング とは リファクタリング とは、ソフトウェアの外部の振る舞いを保ったままで内部の構造を改善していくことです。 リファクタリング によってコードの可読性が上がったり、改修時のコードの変更を容易にしたりすることができます。 可読性が高まることで、設計時や実装、テストなどの工程の助けにもなりますので結果的に今後の開発にも役立ちます。 リファクタリング のメリット リファクタリング を行うメリットとして次のようなことがあります。 可読性の向上 リファクタリング を行うことで可読性が上がり、ソフトウェアを理解しやすくなります。 リファクタリング を行う前はコードを読むのに時間がかかったり、意図のわからないコードがあり理解が困難なことがあります。 それらに対して リファクタリング を行うことでコードの目的がわかるようになり、実現したいことを明確に表現することができます。 コードの変更が容易になる 整理されたコードは変更が簡単に行えます。 仮に重複コードがあった場合、同じ変更を複数箇所で行う必要があります。 しかし リファクタリング によって重複コードを除いておくことで一箇所の変更だけで済み、修正漏れなどの心配もありません。 また、複雑な条件分岐が存在している場合は1つ条件を加えることの難易度が上がります。 複雑な条件分岐は、意図しない デグレ を発生される危険性があります。 開発スピードが向上する リファクタリング によって内部設計が優れているコードは、新規開発時にどこを変更すれば良いかすぐ判断ができます。 また、うまくモジュール化されているとコードを修正するために理解する箇所が限定されます。 機能開発を進めていく中で、テスト時にバグが見つかったとしても デバッグ が容易ですぐ対応することもできます。 このように開発時に無駄なことが省かれるので、開発スピードを向上することに繋がります。 リファクタリング の対象 リファクタリング の対象をいくつか紹介します。 他にも様々なパターンがありますが、コードを読むときに記載しているようなことがあれば リファクタリング を行うきっかけとなります。 わかりにくい名前 コードの理解を進めるために大切なのは適切な名前付けです。 そのためクラス、関数、変数などに意図のわからない名前や、名前と異なる処理が混じっている場合には変更する必要があります。 また、良い名前が思いつかない時は設計が固まっていない可能性がありますので設計を見直しましょう。 重複コード 同じコードの構造が複数存在している場合は、1箇所にまとめることでコードが改善されます。 重複コードがあると、コピーされた箇所に出くわすたびに、差分がないか注意する必要があります。 そして修正時には重複部分をもれなく同様に修正しなければなりません。 変更可能なデータ 変更可能なデータは予期せぬ挙動や、厄介なバグを引き起こす原因となりやすいです。 仕様変更で処理が変わったときに意図しない値に書き変わる可能性もあるため、設計時に可変にすべきか不変にすべきか注意が必要です。 長い関数 周知の事実ですが、関数が長くなればなるほどコードの理解が難しくなります。 長いコードを見つけた時は関数として切り出せる処理がないか確認しましょう。 その中でパラメータや一時変数が多すぎる関数は、関数を切り出してもその分だけパラメータの受け渡しが必要になりますので先に一時変数を減らす必要があります。 基本的な リファクタリング の紹介 リファクタリング の手法は書籍で多く紹介されています。 今回は簡単な例ですが基本的な リファクタリング と条件分岐の リファクタリング をいくつか紹介します。 ※考え方を重視しているのでクラス設計は考慮していません。 関数として切り出す 処理ごとのまとまりを独立した関数として切り出します。(関数名に注意) コードを読んでいて何をしているのか調べなければならない箇所があるのなら、目的を示す名前で関数として抽出するべきです。 関数にすることで目的がすぐ分かるため中身を細かく気にする必要がなくなります。 JavaScript で以下に簡単な例を示します。 function printOwing(invoice) { printBanner(); let unpaidMoney = calculateUnpaidMoney(); // 明細の印字 console.log( `name: ${invoice.customer} ` ); console.log( `amount: ${unpaidMoney} ` ); } 上記の関数で、コメントで「明細の印字」と補足している箇所があります。 このような何をするかを説明したコメントで始まるコードが見つかったときは、必要に応じて関数に切り出すことでコードが見やすくなります。 function printOwing(invoice) { printBanner(); let unpaidMoney = calculateUnpaidMoney(); printInvoiceDetails(unpaidMoney); function printInvoiceDetails(unpaidMoney) { console.log( `name: ${invoice.customer} ` ); console.log( `amount: ${unpaidMoney} ` ); } } 関数を切り出す際の注意点として、目的にふさわしい 命名 をしなければ逆に理解しにくいコードのとなるので 命名 には注意が必要です。 また、逆に関数にすることで分かりにくくなってしまっているコードに関しては関数を取り除いてインライン化を行う場合もあります。 条件の分解 複雑な条件の処理は、プログラムを複雑にする原因の一つです。 様々な条件に応じて処理をするコードを書くだけで、長い関数となり読みにくくなります。 その結果、そのコードの「意図」を理解するのが難しくなります。 解決策として、必要に応じて意図に沿った名前の関数の呼び出しに置き換えることで意図を明確にできます。 条件分岐の場合は、条件判定と条件ごとの処理をそれぞれ関数に置き換えることがおすすめされています。 JavaScript で例として以下のような、土日だけ割引される料金計算があるとします。 if (days [ today.getDay() ] == "土曜日" || days [ today.getDay() ] == "日曜日" ) { price = quantity * plan.specialRate; } else { price = quantity * plan.regularRate + plan.regularServicePrice; } まず、曜日判定の条件記述を抽出します。 if (specialDayOfWeek()) { price = quantity * plan.specialRate; } else { price = quantity * plan.regularRate + plan.regularServicePrice; } function specialDayOfWeek() { return days [ today.getDay() ] == "土曜日" || days [ today.getDay() ] == "日曜日" ; } 次に、then節を関数に抽出します。 if (specialDayOfWeek()) { price = specialPrice(); } else { price = quantity * plan.regularRate + plan.regularServicePrice; } function specialDayOfWeek() { return days [ today.getDay() ] == "土曜日" || days [ today.getDay() ] == "日曜日" ; } function specialPrice() { return quantity * plan.specialRate; } 最後にelse節を関数に抽出します。 if (specialDayOfWeek()) { price = specialPrice(); } else { price = regularPrice(); } function specialDayOfWeek() { return days [ today.getDay() ] == "土曜日" || days [ today.getDay() ] == "日曜日" ; } function specialPrice() { return quantity * plan.specialRate; } function regularPrice() { return quantity * plan.regularRate + plan.regularServicePrice; } 好みもあると思いますが、金額計算を参考 演算子 にしてもよいかもしれません。 price = specialDayOfWeek() ? specialPrice() : regularPrice(); このように修正することで、金額は特別な曜日だったら割引され、そうでなければ通常価格であると直感で分かるかと思います。 条件の統合 複数の条件判定がありそれぞれ条件は異なりますが、結果が同じ場合があります。 このような条件記述は単一の結果を返す条件判定に統合します。 条件を統合するメリットは以下2つあります。 複数の判定をまとめることで、行っている判定が1つであるという意図を明示できる 条件判定を抽出して関数としてまとめることができる 注意点として、条件判定を統合しても他箇所に影響がないかを事前に確認する必要があります。 また、複数の判定が別々のもので単一の判定としてまとめることで可読性が落ちるようならこの リファクタリング は行いません。 以下過程は割愛しますが、 JavaScript で簡単な例を示します。 if (player.accountLevel < 100) return 0; if (player.loginPeriod < 100) return 0; それぞれ条件結果が同じなので、条件判定を取り出し論理 演算子 を使って統合します。 結果として得られた条件判定を関数化することで判定は1つである意図が明示できます。 if (noBonusAccount()) return 0; function noBonusAccount() { return player.accountLevel < 100 || player.loginPeriod < 100; } ガード節による置き換え 条件には以下2つの形式があります。 then節とelse節の両方が正常動作 正常動作と例外的な動作 例外的な動作に対しては、成立した時点でリターンすることをガード節と呼びます。 ガード節を使用することで主要な処理を明確に伝えることができます。 また、コード上ではネストを減らすことができるので可読性の向上につながります。 function getPayAmount() { let result; if (isDead) { result = deadAmount(); } else { if (isSeparated) { result = separatedAmount(); } else { if (isRetired) { result = retireAmount(); } else { result = normalPayAmount(); } } } return result; } deadAmount()とseparatedAmount()とretireAmount()は例外的な動作として扱われているため、成立した段階でreturnするように修正します。 function getPayAmount() { if (isDead) return deadAmount(); if (isSeparated) return separatedAmount(); if (isRetired) return retireAmount(); return normalPayAmount(); } 最後に 今回は リファクタリング の初歩ということで概要と例の紹介をしました。 読んだ本の内容をすぐにすべて反映するということはできませんが、どうすれば可読性の向上、変更を容易にできるか常に意識して機能改修していきたいと思います。 参考書籍 www.amazon.co.jp www.amazon.co.jp エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
はじめに ラク スでメールディーラーを開発している hirobex です。 2022/09/24(土) ~ 09/25(月)の3日間に渡って PHP Conference 2022が開催されました。 phpcon.php.gr.jp ラク スはブロンズスポンサーとして協賛し、 エンジニアも4名が登壇した他、多くのエンジニアが参加しました。 そこで、今回は参加者による参加レポートを紹介させていただきます。 もくじ はじめに もくじ 09/24(土)1日目 Track 1 リリースして11年経過したPHPアプリケーションにPHPStanを導入した PHP メモリ管理術 Track 2 なるべくJavaScriptを書かないでSymfonyのUIをリッチにする、『Symfony UX』 Laravel を低速化する技術 フィーチャートグルを使って素早く価値を検証する ローンチから16年目のWebサービスに、どうやってフィーチャートグルを実装しているか Track 3 PHPで学ぶシステム設計 依存関係のコントロール編 PHPバージョンアップのための依存ライブラリ更新との付き合い方 正規化理論ことはじめ -数学的背景から理解する正規化の初手- 09/25(日)2日目 Track 1 PHPの今とこれから2022 Track 2 少人数チーム開発でのレガシープロダクトとの向き合い方 ラクスからの登壇セッションのご紹介 Slimでサブシステムを構築してレガシーサービスにモダンな光を差し込ませた話 PostgreSQL + TimeScaleDBでログ管理検討 自作したプログラムを Packagist に登録して世界中の PHPer にインストールしてもらおう PHPerが再利用可能な情報提供でオフショア先とコード品質向上に取り組む まとめ PHPerのためのコミュニティ PHPTechCafe 09/24(土)1日目 Track 1 リリースして11年経過した PHP アプリケーションにPHPStanを導入した report by id:Jazuma speakerdeck.com Chatwork株式会社 山下祐さんによる発表です。 本番環境でエラーが発生することを防ぐために静的解析ツール(PHPStan)を導入した事例が紹介されました。 (導入前はnullを参照する・ライブラリのアップデートで型チェックが厳格化した等のエラーが発生していました。) 導入への道のり 静的解析によって解決したい問題を決める⇒その問題を解決できる解析レベルを決定する baselineを作成し、既存のエラーは検知対象外にする(エラーはあるものの本番環境では動いているため) baseline: 検知対象外のエラーを定義したファイル CIでPHPStanを実行する 導入して得られたメリット 問題のあるコードにリリース前に気づけるようになった 思い切った リファクタリング が気軽にできるようになった レビューコストの削減 ライブラリアップデートが安心してできるようになった。 感想 既存のエラーは本番環境の動作に影響しないため、検知対象外にするという運用がコストとリターンのバランス的に良いと思いました。 PHP メモリ管理術 report by hiro_ji speakerdeck.com PHP のメモリ不足が発生する仕組みと、メモリ消費量を節約する方法について解説していただきました。 メモリ消費量の削減ポイント 変数に値を乗せすぎない バッファや スワップ を上手に使用する memory_limitを設定する場合は2*N(Nは 自然数 )MB GC が走るタイミングを調節する 私自身、Allowed memory size of...に遭遇した際は盲目的にメモリを増やすということが多かったため、 実務に活かせる非常にためになる内容でした。 Track 2 なるべく JavaScript を書かないで Symfony のUIをリッチにする、『 Symfony UX』 report by mrstsgk_rks speakerdeck.com Symfony UXを使うことで得られるメリットを Symfony UXの種類と特徴、注意点とともに解説していただきした。 個人的には、「 JavaScript で設定するデータを PHP で記述」できることが、一番魅力的に感じました。 他のメリットとしては、 必要以上に JavaScript を書かなくてよくなる 必要以上に API を作る必要がなくなる などを挙げていただいています。 JSをなるべく書かずにフロントエンドをリッチにできるので、 PHP の活用法が広がって非常に勉強になる発表でした。 Laravel を低速化する技術 report by mrstsgk_rks speakerdeck.com Laravelを高速化することは考えたことはよくありますが、低速化させることを考えるのは斬新だと感じました。 以下の2種類の視点からの低速化を紹介していただきました。 インフラ視点 アプリケーション視点 フィーチャートグルを使って素早く価値を検証する report by rakusMorita speakerdeck.com 流行りのフィーチャートグルを使って、試験的に試作機能を一部のユーザにデリバリーすることで、 その機能の使用データを集められ、リスクを低減した状態で本実装に移せるというものでした。 フィーチャートグルには リリーストグル 実験トグル 運用トグル 権限トグル の4種類があり、今回はその中の 「実験トグル」 を使った検証例の紹介でした。 コードを変えることなく、一部のユーザにだけ機能を表示し、プロダクトの仮説検証やデータによる意思決定を行うために役立つというものです。 検証用の機能として、必要最低限の実装で、不要ならそのまま削除できるようにします。 その機能を本採用するなら実装について再検討し、本格的に実装するという流れです。 新しい開発スタイルを知ることができました。 フィーチャートグルについて詳しく知りたい方向けには こちら のスライドが紹介されていましたので、気になる方はチェックしてみてください。 ローンチから16年目の Webサービス に、どうやってフィーチャートグルを実装しているか report by rakusMorita speakerdeck.com レガシーコードで書かれた Webサービス にフィーチャートグルを導入した貴重なお話でした。 リリーストグルを使用し、開発速度向上の効果があったようです。 導入方針は下記の通りです。 必要最低限の機能で実装する 導入することに比重をおく  →レガシーコードは一旦そのままにし、導入後に リファクタリング を行う とにかく導入して、開発速度が上がったときに リファクタリング を行うという考えは、多くの現場でも役に立つ気がしました。 Track 3 PHP で学ぶシステム設計 依存関係のコン トロール 編 repory by: id:Jazuma speakerdeck.com 成瀬 允宣さんによる発表です。 プログラムにおける依存 例えばユーザの入力値を受け取って インスタンス を生成しDBに保存する... という処理をするクラスは、 インスタンス のもとになるクラス、DBアクセスを行うライブラリに依存する ⇒ DBアクセス用ライブラリに有料化・サービス終了等の変更があるとプロダクトコードが大きな影響を受ける 依存関係逆転の原則 上位モジュール( ビジネスロジック に近いクラス)が下位モジュール(具体的な技術要素を扱うクラス)に依存してはいけない 実装クラスが抽象クラスに依存させるべきである というルールから成り立つ原則です。 プログラム以外における依存 サービスの仕様を特定の人物のみが把握している(人への依存) あるチームのサービスが複数のサービスから利用されている(チームへの依存) 複数のサービスから依存されている場合、障害発生時の影響が大きく、機能改修のリードタイムが落ちる 成瀬さんはチームへの依存をメインコンテンツとして取り上げていました。 チームへの依存の制御 上で挙げた あるチームのサービスが複数のサービスから利用されている というケースの場合、 API を提供することでサービスへの依存を制御することができるとのことでした。 PHP バージョンアップのための依存ライブラリ更新との付き合い方 report by hiro_ji speakerdeck.com PHP バージョンアップ時の注意点や依存ライブラリの管理施策について、過去事例を交えて紹介していただきました。 特にRenovateを用いた定期的なライブラリ更新については、 PHP バージョンアップ時の負担を削減できる有用な運用方法だと感じました。 Renovate とは? 更新できるライブラリがあれば、そのライブラリを更新するためのプルリク エス トを自動的に作成してくれるツール 正規化理論ことはじめ -数学的背景から理解する正規化の初手- report by id:akikuchi_rks DB設計をする際に重要な概念である正規化について、数学的背景に着目して解説していただきました。 関数従属性や情報無損失分解など難しそうな単語が出てくる分野ではありますが、適宜例を用いて解説してくださっているので数学が苦手な方にも分かりやすい発表になっていました。 私自身、正規化の概念については既になんとなく理解していましたが、第二、第三正規化で行う関数従属性に沿った分解が「関数従属性に沿った分解は必ず情報無損失分解となる」という数学的背景があることまでは知らなかったため、勉強になりました。 今回の発表では第1〜第2正規化のみの解説であったので、今後こちらの発表者の方の違う正規化の解説があれば是非聞きたいです。 09/25(日)2日目 Track 1 PHP の今とこれから2022 report by shimizu_s PHP という言語は知っているけども、ほかの言語と比べて何がどう違うのかよくわからない... という PHP 初心者の方にお勧めできる講演でした。 話の主な概要としましては、 PHP にはどのような長所があるのかから始まり、これまでの PHP の歴史を踏まえてこれからの課題や改善点、そしてPHP8.2の変更点となっております。 自分は今年から PHP を使った開発をしており、公演内容は非常に分かりやすく為になりました。 私見 ですがその中でも為になった点は、 歴史:2021年11月に PHP 財団の設立と、それまでに至った経緯 改善点:PHP8では JIT による高速化 PHP8.2の変更点:動的プロパティの廃止 です。 特に動的プロパティの廃止については、今後に向けて、現在の開発でも留意すべきと感じました。 Track 2 少人数チーム開発でのレガシープロダクトとの向き合い方 report by id:Jazuma speakerdeck.com Growfit株式会社 くろきりさんの発表です。 くろきりさんの参画時、プロダクトへの技術的負債が蓄積していました。 (Fatコントローラー・エラー処理の未実装等) はじめは順調に負債の返済が進んだものの、問い合わせ対応や定型運用作業等 日々のタスクに時間がとられる状況になりました。 そこで、「より開発に集中できる環境」「 リファクタリング を継続的に行う仕組み」の作成が始まりました。 より開発に集中できる環境を作るために、カスタマーサポートチームの定型作業を管理画面から実行できるようにする・ タスク管理を導入し、納期や優先度を設定するといった仕組みが導入されました。 Growfitさんではデザインや文言修正依頼の頻度が高いため、Viewの リファクタリング を優先的に行う方針を定めて リファクタリング が進められました。 (対象箇所が多いため、効果がより見込める箇所に絞って リファクタリング するという意図があったとのことです) ラク スからの登壇セッションのご紹介 ここからは弊社から登壇させて頂いたセッションの内容をご紹介します。 Slimでサブシステムを構築してレガシーサービスにモダンな光を差し込ませた話 report by id:radiocat www.docswell.com サービス開始から15年のレガシーなサービスに新たなサブシステムを構築するにあたり、モダンな技術要素を取り入れた話です。 PHP でモダンな フレームワーク と言えばLaravel一択な雰囲気もある中で、開発要件に必要な機能や学習コストなども考慮してLaravelとSlimを比較したうえで フレームワーク を選定しました。 Slimの特徴や実装にあたって苦労した点なども紹介しています。 PSR準拠の機能拡張や書きやすさを重視した ユニットテスト の導入はレガシーな既存システムにも応用しやすいアプローチであり、レガシーサービスにモダンな光を差し込ませるひとつの事例となる話でした。 PostgreSQL + TimeScaleDBでログ管理検討 report by id:radiocat speakerdeck.com PHP のテーマではありませんが、 PostgreSQL に関する事例の紹介です。 TimeScaleDBは PostgreSQL の 拡張機能 です。 時間とともに増大する時系列データを一定期間経過後に圧縮する機能があります。 このTimeScaleDBを使って、全体の50%以上を占める膨大な操作ログデータを圧縮して管理する方法を検証した事例を紹介しました。 以下が検証の結果のまとめです。 圧縮後のデータサイズは約10%になり、圧縮効果が非常に高いことがわかった ただし、圧縮されたデータが検索対象になる場合は解凍処理を挟むため非常に遅くなる 分割カラムを効果的に活用することで検索速度が遅くなるのを回避することができる 分割カラムは検索のキーとなるカラムを分割カラムに指定することでレコードを分けて圧縮するため、検索速度低下を防ぐことができる仕組みです。 TimeScaleDBの機能を活用することで検索速度を保ちつつ、データを圧縮してデータサイズを抑えたデータベース運用が可能になります。 自作したプログラムを Packagist に登録して世界中の PHPer にインストールしてもらおう report by id:radiocat speakerdeck.com Packagistは PHP のツールやライブラリを一般に公開するための リポジトリ です。 Packagistに登録されたものを実際に利用するにはComposerを使うため、Composer用のパッケージの定義を行って、Packagistの公式サイトで登録するまでの流れがスライドで紹介されています。 自作したプログラムをローカルに眠らせている人はぜひこのスライドを参考のうえPackagistに登録してみてください。 PHPerが再利用可能な情報提供でオフショア先とコード品質向上に取り組む report by id:radiocat speakerdeck.com オフショアのコード品質を上げるために取り組んでいる具体的な事例の紹介です。 弊社は ベトナム のオフショアチームと開発していますが、 ベトナム では国の事情の違いもあって母国語の技術情報が日本のように潤沢にはありません。 そのため、コード品質を上げるために日本のエンジニアからのフィードバックをたくさん行い、その内容を学習教材として活用してもらう取り組みを行っています。 根気強く続けていくことが大切であり、以下のような対策を行って継続的に取り組んでいます。 納期の制約があるため、対応必須のフィードバックと今後のために読んでおいてほしいフィードバックに分ける 過去のフィードバックを事例集として再利用可能な形で蓄積する まとめ PHP バージョンアップやレガシー改善のセッションが多くあり、 レガシーシステム と向き合う苦労が伝わってきました。 PHP で作られた製品が長く利用されている証拠だと思います。 PHPerのためのコミュニティ PHPTechCafe ラク スでは PHP に特化したイベントを毎月開催しております。 その名も「 PHPTechCafe 」!! 次回は10/24(月)に『 PHP のリーダブルなコード』 をテーマに開催します! まだまだ参加者を募集していますので、ぜひお気軽にご参加ください。 👉 PHPerのための「PHPのリーダブルなコード」を語り合うPHP TechCafe 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 年目の ke-suke0215 です。 今回、 axois について調べてみました。 axios は非同期で API 呼び出しを簡単に行うことができるライブラリです。 しかし、簡単がゆえに内側でどのように動いているか曖昧な人も多いのではないでしょうか。 axios の中身を理解するには、よく一緒に使われる async と await の理解が重要になってきます。 また、 async と await の理解には Promise についての理解が必要になり、Promise は非同期処理の記述に使うものです。 なので、非同期処理、Promise、async と await、最後にメインの axios の順で説明していきます。 サンプルプログラムは TypeScript で記述しています。 目次 はじめに 目次 非同期処理とは Promise について pending, resolve, reject の 3 つの状態がある Promise を動かしてみる 状態を変更する then と catch async と await axios の中身で行われていること まとめ 非同期処理とは 非同期処理は字からも分かる通り、同期処理ではない処理のことです。 具体的には下のように表されます。 同期処理:実行した処理の終了を待って次の処理に進む動き 非同期処理:実行した処理の終了を待たずに次の処理に進む動き 言葉だけだと分かりづらいため、実際のプログラムを見ながら説明していきます。 ここでは 2 つの引数(文字列)を受け取り、 setTimeout を用いて 1 秒後に 1 つ目の引数を表示し、その直後に 2 つ目の引数を表示するプログラムを考えたいと思います。 実行時には引数に "引数1" と "引数2" を入れているので、実行した1秒後に 引数1 引数2 と表示されるのが期待する振る舞いです。 const sampleFunc = ( str1: string , str2: string ) : void => { // 1秒後に実行 setTimeout (() => { console .log ( str1 ); } , 1000 ); console .log ( str2 ); } ; sampleFunc ( "引数1" , "引数2" ); しかしこのプログラムを実行すると、下のように直ちに 引数2 が表示され、その 1 秒後に 引数1 が表示されます。 引数2 引数1 これが非同期処理です。 setTimeout で 1 秒待っている間、TypeScript は処理の終了を待たずに次に進んでしまいます。なので 引数2 が先に表示されてしまうのです。 期待する振る舞いを実現するためには、 setTimeout の処理が終了してから次に進んでほしいので、ここでやりたいことは非同期処理を同期処理のように扱うことです。 Promise について Promise は一言で表すと『非同期処理の状態を監視するためのオブジェクト』です。 非同期処理を同期処理のように扱える書き方の 1 つになります。 具体的に説明していきます。 pending, resolve, reject の 3 つの状態がある これが Promise を考える上で重要な概念になってきます。3 つの状態の意味は下記のようになっています。 pending:待機(処理の完了を待っている) resolve:解決(処理が成功) reject :拒否(処理が失敗) Promise は常にこの 3 つのうちどれかの状態になっています。 はじめは待機を表す pending になっており、処理の内容によって状態を変化させます。 期待通りであれば成功を意味する resolve 、期待にそぐわない場合は失敗を意味する reject に変更するのが基本的な使い方です。 Promise を動かしてみる 先程のプログラムに少し変更を加え、 setTimeout の中で条件分岐を追加して Promise を使ってみます。 第 1 引数に文字列を入れて関数を実行すれば成功とし、1 秒後に第 1 引数を表示して直後に第 2 引数を表示します。 第 1 引数が空文字なら失敗とし、第 1 引数が空文字である旨を伝えるメッセージを出力します。 まだ説明していない記述もありますが、一旦スルーしてください。 const sampleFunc = ( str1: string , str2: string ) : void => { new Promise < void >(( resolve , reject ) => { setTimeout (() => { if ( str1 !== "" ) { console .log ( str1 ); resolve (); // 状態をresolve(成功)に変更 } else { reject (); // 状態をreject(失敗)に変更 } } , 1000 ); } ) .then (() => { console .log ( str2 ); } ) . catch (() => { console .log ( "第1引数が空文字です" ); } ); } ; sampleFunc ( "引数1" , "引数2" ); 今回は先程と同様 "引数1" と "引数2" を引数にいれているので、実行した 1 秒後に 引数1 引数2 と出力されます。 Promise を使用していない記述では 引数2 が先に表示されていましたが、今回は期待通りの動きです。 プログラムの詳細を見ていきましょう。 状態を変更する コメントでも記載していますが、6 行目の resolve() と 8 行目の reject() が状態を成功と失敗に変更する記述です。 これは Promise を インスタンス 化する際の引数に入れる、コールバック関数の 2 つの引数が変更する関数名に該当します。 str1 が空文字ではない場合は状態を resolve にしたいので、値を出力してから resolve() を実行し、空文字の場合は reject() を実行することで状態を reject にしています。 then と catch Promise が非同期処理を制御できるのは、状態によってその後の処理を変える仕組みを持っているからです。 Promise の処理の後には、 .then と .catch を続けることができます。 具体的には、Promise の中の処理が終了したとき状態が resolve であれば then の引数の中が、 reject であれば catch の引数の中が実行されるようになっています。 今回は resolve() が実行されて処理の終了時には Promise の状態が resolve になっているので、then の引数の中身が実行され、catch は無視されます。仮に引数である str1 を空文字で実行した場合、then は無視されて catch の引数の中身が実行される動きとなります。 したがって、特定の処理(今回の場合は setTimeout )の終了を待ってから次の処理を行いたい場合、 Promise の中で最初の処理を実行 状態を resolve に変更 then の引数に次の処理を記述 このようにすることで実現できます。 以上が Promise における非同期処理の基本的な説明です。 async と await ここまでで見てきた Promise は、次に実行したい処理を then や catch に入れていました。 ですが async と await を使うと then などを使用しなくても非同期処理を同期処理のように動かすことができるので、よりシンプルに書くことができます。 Promise の節に記述したプログラムを async と await に書き換えたものを見てみます。 const sampleFunc = async ( str1: string , str2: string ) : Promise < void > => { await new Promise < void >(( resolve , reject ) => { setTimeout (() => { if ( str1 !== "" ) { console .log ( str1 ); resolve (); // 状態をresolve(成功)に変更 } else { reject (); // 状態をreject(失敗)に変更 } } , 1000 ); } ); console .log ( str2 ); } ; sampleFunc ( "引数1" , "引数2" ); 出力結果は Promise の時と同様に下記のようになります。 引数1 引数2 順を追って説明します。 async は同期処理として扱いたい一連の処理を記述した関数の前につけます。 次に、await です。await には以下のようなルールがあります。 await の次で Promise を インスタンス 化する async をつけた関数の中に書く Promise オブジェクトの前に await をつけることで、その Promise オブジェクトが値を返すのを待つようになります。 つまり Promise 内の処理が終了するまで次の処理に進まなくなるのです。 これにより非同期処理を同期処理のように扱うことができます。 await をつけた処理が終了したときに状態が resolve であればそのまま次の処理に進み、 reject であればエラーとなります。 今回は省略していますが、 try と catch で囲むことでエラー後の処理を書くことができます。 この例では制御する非同期処理は 1 つですが、複数ある場合には async と await で then などを省略できるメリットがより顕著に感じられるはずです。 axios の中身で行われていること ようやく本題の axios についてです。 冒頭でも述べましたが、axios は非同期で API 呼び出しを行うことができます。 また、先程説明した async,await と一緒に使われることが多いです。 例として郵便番号をパラメータとして渡すと住所を返す API を使用します。 引数に郵便番号を入れるとその住所を取得する関数を作成し、実行してみます。 それではサンプルプログラムを見ていきましょう。 import axios from "axios" ; const sampleFunc = async ( zipcode: string ) : Promise < void > => { // APIを呼び出す const response = await axios. get( "https://zipcloud.ibsnet.co.jp/api/search" , { params: { zipcode: zipcode } , } ); console .log ( response.data ); } ; sampleFunc ( "7830060" ); こちらのプログラムを実行すると、次のような出力となります。 { message: null, results: [ { address1: '高知県', address2: '南国市', address3: '蛍が丘', kana1: 'コウチケン', kana2: 'ナンコクシ', kana3: 'ホタルガオカ', prefcode: '39', zipcode: '7830060' } ], status: 200 } きちんと住所の情報が帰ってくることが確認できます。 それではプログラムの解説に移ります。 axios はライブラリなので、1 行目でインポートしています。 今回は get を使用していますが、post や delete を使うこともできます。 引数に URL を入れ、必要であればパラーメタを指定することで API を呼び出すことができます。 先程までは setTimeout を利用し、明示的に 1 秒処理を待っていたのでわかりやすかったです。 API の呼び出しについても具体的な待機時間は場合によりますが、通信するのに一定の時間がかかるため await を使用しないとデータを取得する前に console.log(response.data); が動いてしまいます。 axios は「Promise ベース」と言われますが、この面で 2 つのことを自動的にやってくれています。 Promise の インスタンス 化 resolve と reject へ自動的に状態を変更 await のルールを説明した部分で、 await の次で Promise を インスタンス 化する と書きました。 今回のプログラムでは await の後に axios が来ており、一見 Promise を インスタンス 化していないように思えます。 しかしこのとき axios は、裏側で自動的に Promise を インスタンス 化してくれているのです。 また、通信が成功したかどうかによって Promise の状態を、resolve もしくは reject に変えてくれています。 これらによって Promise をあまり意識せずに「async と await つけて axios で API 呼び出せばいい感じに動く」ということが実現されています。 まとめ axios が内側でどのような処理を行っているのかを、遡って見てきました。 Promise から順を追って見ていくと、わかりやすかったと思います。 内側の処理を理解することで、実行する位置やエラーの拾い方などで迷うことが減るのではないでしょうか。 参考にしていただければ幸いです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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年目の koki _matsuraです。 本日は、Next.jsとVercel、Supabaseを用いて簡単なアプリを高速で開発する手順についてお話しできればと思います。 アジェンダ は以下の通りです。 Next.jsとは ReactとNext.jsの違い Next.jsの特徴 Vercelとは Supabaseとは ToDoアプリ作成 Supabaseにデータベースを用意 VercelでNext.jsプロジェクトを作成・デプロイ・GitHub連携 VercelとSupabaseの連携 GitHubからクローン Vercelから環境変数を取得 Supabaseのデータベースに接続 コード編集 終わりに 参考文献 Next.jsとは Next.jsはReactベースのアプリケーション フレームワーク です。 公式サイトではNext.jsとはReactを用いたWeb アプリ開発 で生じる問題を全て解決する フレームワーク だと紹介されています。 ReactとNext.jsの違い サーバの有無 これがNext.jsとReactの1番の違いです。 Next.jsはサーバー機能を持っているのですが、Reactはサーバー機能を持っていません。そのため、Next.jsは単体でWEBアプリを動かすことができます。Reactはサーバーを別に用意し、サーバー用のモジュールや ディレクト リなどを考えないといけないため、学習のコストが高くなります。 フレームワーク かライブラリか Next.jsはアプリケーション フレームワーク としてWEBアプリケーションの土台として使われ、Reactは部分的にDOMの値で表示を変化させることに特化しているViewライブラリとして使われます。 部分導入 Next.jsは フレームワーク なので、部分導入はできません。一方、Reactはライブラリなので Ruby on Rails や Django の フレームワーク に取り入れることが可能になっています。 Next.jsの特徴 画像の最適化 Next.jsにはimgタグの代わりとなるImageタグがあり、これを使うことで画像の次世代フォーマットであるWebPへ自動で変換し、高速に画像を表示することができます。 ファイルベースルーティング 通常、WEBページを表示したい場合は特定のフォルダ配下にindex.htmlを配置します。しかし、Next.jsでは導入時点で"pages"というフォルダがあり、その配下にファイルを配置すると自動でパスが生成されます。 ハイブリッド レンダリング Reactでは CSR (Client Side Rendering)にのみ対応しています。 CSR はページのサイズが大きい時にローディング時間が長くなってしまうというデメリットがあり、 SEO 的にも悪くなると考えられます。 一方、Next.jsでは CSR だけでなく、 SSR (Server Side Rendering)にも対応しており、ページごとに個別に レンダリング 方法を設定できます。また、プレ レンダリング も可能で、最初にページにアクセスする際にHTMLを提供するため、 レンダリング の速度を大幅に軽減することが期待できます。 ファストリ フレッシュ ソースコード に変更があったときにその箇所のみが再描画する機能です。これにより効率的に開発を進めることができます。 以上のことから、WEB アプリ開発 における開発者の手間を省いてくれる フレームワーク になっています。 Vercelとは Next.jsを開発したVercel Inc.が提供してる ホスティング サービスです。 GitHub などの リポジトリ と連携することで簡単に作成したWEBアプリを数十秒でデプロイできます。 Supabaseとは SupabaseはSupabase Pte. Ltd.が開発している開発者向け オープンソース のデータベースプラットフォームです。 SupabaseはFirebaseと比較し、大きな違いとして、データベースが挙げられます。FirebaseはNoSQLを用いているのに対し、Supabaseは PostgreSQL を用いています。また、Supabaseの管理画面はとても直感的で個人的には調べなくても操作しやすいです。なので、普段からリレーショナルデータベースを触っている人からすれば、Firebaseよりも学習コストを少なく始められるものになっています。 ToDoアプリ作成 これから実際に先ほど紹介させていただいた「Next.js」「Vercel」「Supabase」を用いて、入力した文字列がリスト型に出力される基本的な機能しか持たないToDoアプリを作成、デプロイするまでを手順を追って説明したいと思います。 Supabaseにデータベースを用意 まずはSupabaseにデータベースを用意していきます。 Supabase のサイトで「 Sign in」しましょう。 アカウントをお持ちでない方は「Start your project」をクリックしてください。 下記の画面が表示されれば、「 Sign in with GitHub 」を押し、 GitHub と連携しましょう。 成功すれば、下記のような画面が表示されます。この画面左上にある「New Project」をクリックします。 Organization・Name・Database Password・Regionはご自由に設定してください。 設定が終われば、「Create new project」をクリックします。 ホーム画面が表示されていれば成功です。 では、本題となるデータベースを作成します。サイドバーから「 SQL Editor」を選択後、左上に表示される「New query」をクリックします。 すると、エディターが表示されますので下記のようなコードを入力し、右下の「RUN」をクリックし実行させます。 ToDoアプリを作成するため、ID、タイトル、達成したか、作成した時間をカラムとして持たせます(今回の記事ではID・タイトルのみでも問題ありません)。 テーブルが作成されたかは、サイドバーから「Database」をクリックし、表示された画面にコード通りのテーブルがあるかで判断できます。 正常に実行されていれば、下記の画像のようになります。 以上でSupabase上でデータベースが作成できました。 次はVercel上でNext.jsのプロジェクトを作成し、デプロイ、 GitHub 連携していきましょう。 VercelでNext.jsプロジェクトを作成・デプロイ・ GitHub 連携 Vercel のサイトで「Continue with GitHub 」をクリックしましょう。 下記のような画面が表示されるので、右上から「Add New Project」をクリックしましょう。 Next.jsのプロジェクトを作成したいのでテンプレートを選択しましょう。 下記の画像ではGit リポジトリ を作成しています。自分のアカウントを「GIT SCOPE」で選択し、「REPOSITORY NAME」には自由に名前をつけてください。 「Create private Git Repository」はチェックを入れるとprivate リポジトリ として作成されます。 「Create」をクリックするとGit リポジトリ が作成され、自動でデプロイまでしてくれます。 デプロイ完了後、 ダッシュ ボードに戻ると下記の画像のようになっています。 「View Git Repository」をクリックすると自分のGitアカウントに リポジトリ が作成されていることが確認できます。「Visit」を押すと、作成したプロジェクトがデプロイされていることが確認できると思います。 以上で、Vercel上でNext.jsプロジェクトを作成、デプロイ、 GitHub との連携が完了しました。 次はVercelとToDoアプリ用のデータベースを作成したSupabaseを連携をします。 VercelとSupabaseの連携 まず、先ほどの作成したプロジェクトが表示されている画面から「Settings」に移動します。 「Browse Marketplace」をクリックし、「Supabase」を検索します。 検索結果に二つ出てきますが、「Supabase」と書かれている方を選択します。 「Add Integration」をクリックしましょう。 Supabaseをどのアカウントに統合するのかを選択します。 この画面ではどのプロジェクトにSupabaseを統合するのかを設定します。 「All Projects」を選択すれば、すべてのプロジェクトに統合されます。今回はToDoアプリだけに統合したいので、「Specific Projects」を選択します。そして、該当するプロジェクトを選択しましょう。 選択が終われば、「CONTINUE」をクリック。 Vercel上で先ほど作成したプロジェクトとSupabaseで作成したデータベースをそれぞれ選択し、「Add Integration」をクリックして連携します。 これでVercelとSupabaseの連携は終わりました。 次は作成されたGit リポジトリ をクローンします。 GitHub からクローン 自身の GitHub にアクセスすると、先ほどVercel上で作成したプロジェクトがあるので、 SSH をコピーしましょう。 CLI を開き、下記のコマンドを実行し、ローカル環境にクローンします。 クローンができれば、好きなコードエディターで開き、下記のコードでローカル開発サーバーを起動します。 起動が終われば、 http://localhost:3000 にアクセスしてみましょう。 テンプレートと同じプロジェクトが表示されれば、成功です。 Vercelから 環境変数 を取得 Vercelで作成したプロジェクトには、下記のような連携したSupabaseの 環境変数 が「Settings」の「Environment Variables」にあります。 Vercel上の 環境変数 を取得するために CLI で下記のコマンドでVercelにログインします。 「Ok to proceed?」には「y」と入力すると、ブラウザが開くので、「Continue with GitHub 」を選択します。ブラウザに「 CLI Login Success」と表示されるとログイン成功です。 次にVercelプロジェクトをローカル環境にクローンしたプロジェクトにリンクします。下記のコマンドを入力します。 該当するプロジェクトなら「y」を入力します。 プロジェクトをリンクできたので、下記のコマンドを入力することでプロジェクトの 環境変数 を取得します。 成功すれば、プロジェクトに「.env」が作成されます。ここにはSupabaseの 環境変数 が含まれています。 この 環境変数 はGitにあげてはいけないのでファイル名を「.env.local」に変更し、無視されるようにします。 以上で、Vercelの 環境変数 を取得できました。 次はこの 環境変数 を用いて、Supabaseのデータベースに接続します。 Supabaseのデータベースに接続 Supabaseで作成したデータベースに接続するためにはSupabaseクライアントが必要となるので、下記の2つのコマンドで型定義とSupabaseクライアントをインストールします。 インストールが完了すれば、「utils/supabase.ts」を作成し、次のコードを入力します。このコードでは、Supabaseクライアントを初期化しています。 Supabaseクライアントを用いて、データベースを操作する準備ができたので、実際にコードを編集していきます。 コード編集 現時点のコードはNext.jsのテンプレートのものなので、コードを編集します。入力部と出力部を用意して、シンプルなToDoアプリを作りましょう。 入力部の コンポーネント 「/components/InputToDoForm. tsx 」を作成します。コードは下記のようにします。 pushTodo関数でデータベースのテーブルtodosに入力内容を追加しています。 fetchTodosは入力部、出力部両方で使用するのでHooks化しています。 出力部の コンポーネント 「/components/ToDoList. tsx 」を作成します。コードは下記のようにします。 fetchTodosを記述している「Hooks/useAddTodo.ts」を作成します。コードは下記のようにします。 fetchTodosはデータベースtodosから全件取得してきます。 2022/10/11 上記コードのuseEffect内で誤りがあったため修正いたしました。 コンポーネント の作成、内部の処理ができたので、テンプレートのコードが記述されている「pages/index. tsx 」を下記のように編集します。 編集が終われば、ローカル環境を立ち上げ、 http://localhost:3000 にアクセスします。入力部と"todoリスト"の文字列があれば問題ありません。 入力部に適当な文字列をうち、その文字列が"todoリスト"の文字列の下にリストで表示されていれば、完成です。 「テスト1」「テスト2」「テスト3」と3度入力した場合は以下のようになります。 入力と出力に問題はなかったので、 GitHub にプッシュします。 そして、プッシュ後、Vercelにログインすると自動でビルド・デプロイをしてくれます。 Vercelの該当プロジェクトの画像がテンプレートのものからToDoアプリのものに変わっていればデプロイが終わっています。 終わりに Next.jsとVercel、Supabaseを用いた簡単なアプリを開発する手順についてご紹介させていただきました。 Supabaseのデータベース作成は非常に簡単で、Vercelも GitHub の連携さえすれば、自動でビルド・デプロイしてくれるので開発だけに集中できました。 是非、Next.jsのアプリケーションを作ろうとしている方はSupabase+Vercelを使ってみてください。 参考文献 supabase.com reffect.co.jp weseek.co.jp zenn.dev エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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年目の hachimd です! 先日、先輩エンジニアの方に「 Java でソートする時って Collections 使うんですよね?」って話をしたら「いやいや、 Java のソートは Stream が便利だよ!」って教えていただきました。 そこで今回は、Stream を使って、どうやってソートするのか、どう便利なのかを、Collections を使ったソートと比較してゼロから解説してみようと思います。 考え方から言及しているので、ソートの方法が全くわからない人でも大丈夫です。 なお、今回は JDK11 を使用しています。 目次 はじめに 目次 基本的なソートの考え方 Collections を使ったソート 要素の大小関係が明らかなとき 大小比較の方法を制御したい時 Collections.sort のデメリット Stream を使ったソート Stream を使った単純なソート Stream を使った『人オブジェクト』のソート 3 種類の整数を返す処理でソート comparing によるキーの指定だけでソート 複数のキーでソート 最後に 参考書籍   基本的なソートの考え方 ソートは一言で言うと、「昇順 or 降順で並び替えること」と言えます。 ここで、「名前」と「年齢」を持つ『人オブジェクト』を並び替える際に、「まず名前順で並び替え、名前が同じ時は年齢順で並び替える」というルールにすると、単に昇順・降順では並べられないと感じてしまいますが、『人オブジェクト』の大小関係を決める際に「名前を最優先、次点で年齢」と考えると、あくまで『人オブジェクト』の大小関係に従って昇順・降順に並べているのでシンプルになります。 つまり、ソートしたい要素に対して、どのように大小を決定するかを決めてやれば、あとは API を使ってソートができるということです。 【重要】ソートするのに必要なことは、要素の大小関係を決めてあげること Collections を使ったソート ここではまず、大小関係が明らかなものをソートする方法と、大小関係が明らかでない『人オブジェクト』をソートする方法を解説します。 どちらも Stream が使えるようになる以前によく使われていた、 Collections.sort() を使って解説をして、 Collections.sort() のデメリットにも言及します。その後、 Stream を使ったシンプルでわかりやすいソートの方法を解説していきます。 要素の大小関係が明らかなとき 数値や文字列のように大小関係が明らかなときは、大小関係を決めてやらなくてもソートすることができます。また、ソートの結果は自然順序(明らかな大小関係に基づく昇順)になります。 ソートするには Collections.sort() を呼び出すだけです。 List<Integer> numbers = Arrays.asList( 5 , 4 , 8 , 3 , 1 ); // ソートを実行 Collections.sort(numbers); // 結果を出力 for ( int num: numbers){ System.out.print(num + " " ); // 1 3 4 5 8 } 大小比較の方法を制御したい時 次に、age と name をプロパティにもつ Person をソートすることにします。 Person オブジェクトの年齢差を返す ageDifference メソッドも定義しています。 public class Person { private final int age; private final String name; public Person(String name, int age) { this .name = name; this .age = age; } public int getAge() { return age; } public String getName() { return name; } @Override public String toString() { return "Person{" + "age=" + age + ", name='" + name + ' \' ' + '}' ; } public int ageDifference( final Person other) { return this .age - other.age; } } Person の大小関係がどう決まるのかは我々が定義してあげる必要があります。 Java では、要素の大小比較の方法を自分で決定するには Comparator というインタフェースを利用します。 Comparator は関数型インタフェースで、抽象メソッドとして compare メソッドが定義されています。 cpmpare メソッドの実際の処理に「大小比較の方法」を記述していきます。また、この処理はある決まりに従って書く必要があります。具体的には、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返す」ような処理になります。 (参考: Comparator インタフェースの compare メソッド ) それでは「まず年齢順で並び替え、年齢が同じ時は名前順で並び替える」というルールで、実際にソートをする処理を見ていきましょう(ここでは Collectons を使ったソートはめんどくさいなと感じてもらえれば大丈夫です)。 まずはコードを見てみましょう。 List<Person> people = Arrays.asList( new Person( "John" , 20 ), new Person( "Sara" , 21 ), new Person( "Jane" , 21 ), new Person( "Greg" , 35 ) ); // compareメソッドをオーバーライドしてPersonオブジェクトの大小比較の方法を定義する // 比較方法:年齢で比較して同じなら名前で比較 Comparator<Person> personComparator = new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { int ageDiff = p1.ageDifference(p2); if (ageDiff != 0 ) { return ageDiff; } else { int nameDiff = p1.getName().compareTo(p2.getName()); return nameDiff; } } }; // 年齢でソートする // 第1引数:ソート対象のpeople // 第2引数:Personの大小比較方法が定義されたComparator Collections.sort(people, personComparator); // 並びを確認 for (Person person : people) { System.out.println(person); } // ソート結果 // Person{age=20, name='John'} // Person{age=21, name='Jane'} // Person{age=21, name='Sara'} // Person{age=35, name='Greg'} それでは解説です。 重要なのは Person オブジェクトの大小比較の方法を定義する部分です。 ここでは、compare メソッドの実装の決まりに従うと、 2 つの Person オブジェクト p1, p2 が引数 p1 が p2 より 小さい とする場合は 負の整数 を返す p1 が p2 より 大きい とする場合は 正の整数 を返す 両方が 等しい 場合は 0 を返す ような処理にする必要があります。 また、並べ方は「まず年齢順で並び替え、年齢が同じ時は名前順で並び替える」というルールですので、Person の大小関係と compare メソッドで返す値の対応は以下のようになります。 p1 の年齢が p2 の年齢より小さければ p1 は p2 より 小さい ( 負の整数 を返す) p1 の年齢が p2 の年齢より大きければ p1 は p2 より 大きい ( 正の整数 を返す) もし年齢が同じなら、 p1 の名前が p2 の名前より小さければ p1 は p2 より 小さい ( 負の整数 を返す) p1 の名前が p2 の名前より大きければ p1 は p2 より 大きい ( 正の整数 を返す) 名前の大小も同じなら、 p1 と p2 の大小は 同じ ( 0 を返す) 上記のコードの実装では 1,2 は年齢差を返すことで実現しています。 3,4,5 は String クラスに用意された compareTo()メソッドを使って実現しています。 なお、Comparatorのcompareメソッドをオーバーライドする部分に関して、 ラムダ式 を使って処理だけを直接引数に渡すことも可能です。 Collections.sort(people, (p1, p2) -> { int ageDiff = p1.ageDifference(p2); if (ageDiff != 0 ) { return ageDiff; } else { int nameDiff = p1.getName().compareTo(p2.getName()); return nameDiff; }}); ※ 補足 compareTo()は String クラスに用意された 2 つの文字列を辞書的に比較するメソッド。 Comparable インタフェースの実装であり、これも、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返す」ように実装されている。 (参考: Comparable インタフェースの compareTo メソッド ) Collections.sort のデメリット コードを見ただけでは何をしているか分かりにくい 上の実装のようなコードを理解するには、Comparator インタフェースの compare メソッドをどのように実装するかを知っている必要があります。さらに、正の整数を返すのか負の整数を返すのか常に覚えておくことはなかなか大変です。しかもそのような処理を書く必要があるのでコード自体も長く読みづらいものににってしまいます。 元のリストが破壊されてしまう このデメリットはとても重要です。 Collectons の sort メソッドは、ソートしたいリストの要素を直接並び替えています。プログラミングの世界では、このようにオブジェクトを直接変更するようなメソッドは破壊的メソッドと呼ばれます。破壊的メソッドを使うときは特に注意が必要です。それは、オブジェクトを直接変更してしまうと、後でまたそのオブジェクトを利用する際にソートされているのかされていないのかなどを意識しなければならず、処理を追うのが大変になりバグが混入しやすくなるからです。そのため、元のオブジェクトは変更せず、処理結果の新しいオブジェクトを返すような非破壊的メソッドを利用することが好ましいと言えるでしょう。 Stream を使ったソート それでは Stream を使って見やすくかつ簡潔に記述できるソート方法を解説していきます。 ここまで Collections を使ったソートを説明してきましたが、「Collections を使うソートは大変だな」と感じていただければそれで大丈夫です。 Stream はデータの集まりに対して、さまざまな処理(ソートや絞り込み、各データに対する処理など)を簡潔に記述できるようにするインタフェースです。 Stream を使うことで、正の整数 or 負の整数 or 0 を返す処理(compare メソッドの実装)を意識しなくても柔軟なソートができるようになります。 もちろん今まで通り、 3 種類の整数を返す処理を書いてソートすることもできます。 ここでは、『人オブジェクト』に対して、これまで通り 3 種類の整数を返す処理を Stream を使って書くところから始め、コードを改良していきながら、最後に、compare メソッドの実装を意識しなくてもソートできるような方法を紹介します。 Stream を使った単純なソート Stream を使った『人オブジェクト』のソートに行く前に、数値のように要素の大小関係が明らかなものをソートする方法について触れておきます。 List<Integer> numbers = Arrays.asList( 5 , 4 , 8 , 3 , 1 ); List<Integer> sortedNumbers = numbers.stream().sorted().collect(toList()); Stream でソートをする場合は sorted メソッドを使用します。 大小関係が明らかな場合は、引数なしで使うことで自然順序でソートできます。 また、これは非破壊的メソッドなので、ソート結果を新しい変数に格納しています。 collect(toList()) は sorted メソッドの戻り値型が Stream なので型を List に戻しているだけです。 また、 Integer は Comparable インタフェースを実装している(自然順序が定義されている)ので、以下のように、 naturalOrder() や reverseOrder() を使用して昇順、降順にすることもできます。 // 昇順 List<Integer> sortedNumbers = numbers.stream().sorted(Comparator.naturalOrder()).collect(toList()); // 降順 List<Integer> sortedNumbers = numbers.stream().sorted(Comparator.reverseOrder()).collect(toList()); ※Person クラスが Comparable インタフェースを実装していれば、同様に naturalOrder() や reverseOrder() を使用できます(今回は Comparable は実装していません)。 Stream を使った『人オブジェクト』のソート それでは Stream を使った『人オブジェクト』のソートを解説していきます。 3 種類の整数を返す処理でソート Comparator インタフェースの compare メソッドを実装して大小関係(比較方法)を定義するのはこれまでと同じです。 先ほどの繰り返しになりますが、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返すような処理」を渡してあげます。 年齢でソート // Comparatorはラムダ式を使って処理だけを直接渡す List<Person> sortedPeopleByAge = people.stream().sorted((person1, person2) -> person1.ageDifference(person2)).collect(toList()); 名前でソート List<Person> sortedPeopleByName = people.stream().sorted((person1, person2) -> person1.getName().compareTo(person2.getName())).collect(toList()); 大小関係が明らかでない場合は、sorted メソッドの引数に Comparator を入れます( ラムダ式 で入れています)。 Collections のソートと比較して、非破壊的メソッドになっているのは良いことですが、どんな整数を返すか意識する必要があるので、まだ、それほどメリットが感じられません。次は comparing メソッドを使って改良していきます。 (参考: Stream クラスの sorted メソッド ) comparing によるキーの指定だけでソート comparing メソッドは、ソートに使うキーを返す関数を受け取り、そのキーで大小比較する Comparator を返します。 例えば、「Person を受け取って Person の name を返す関数」を受け取ると、Person の name でソートする Comparator を返すことができます。 つまり、「名前の大小関係を使う」ということを指定してあげれば、「3 種類の整数を返す Comparator 」を返してくれます。 言い換えれば compare メソッドを実装した Comparator をキーの指定だけで作ってくれるとても便利なやつです。 List<Person> sortedPeopleByName = people.stream().sorted(comparing((Person person) -> person.getName())).collect(toList()); 3 種類の整数を返す処理ではなく、ソートするキーを返す処理を渡すだけになり、どんな整数を返すのかを考えることが無くなりました! キーを返す処理自体を定数としてやるとコードも見やすくなります。 final Function<Person, String> byName = person -> person.getName(); final Function<Person, Integer> byAge = person -> person.getAge(); List<Person> sortedPeopleByName = people.stream().sorted(comparing(byName)).collect(toList()); List<Person> sortedPeopleByAge = people.stream().sorted(comparing(byAge)).collect(toList()); メソッド参照を使うとさらに簡略化できます。 List<Person> sortedPeopleByName = people.stream().sorted(comparing(Person::getName)).collect(toList()); List<Person> sortedPeopleByAge = people.stream().sorted(comparing(Person::getAge)).collect(toList()); ここまで見やすく簡略化できると、Stream の機能を使わない理由がないのがわかってくるのではないでしょうか。 正の整数を返すんだったかな?負の整数を返すんだったかな?なんて迷うこともなく、コードも記述しやすく理解しやすいものになりました。 (参考: Comparator インタフェースの comparing メソッド ) 複数のキーでソート 最後に、年齢で比較した後に名前で比較して『人オブジェクト』をソートしてみます。 Stream を使うとこの処理も非常に簡単に書けます。comparing に続けて thenComparing メソッドを使うだけです。 List<Person> sortedPeopleByAgeAndName = people.stream().sorted(comparing(Person::getAge).thenComparing(Person::getName)).collect(toList()); 序盤に紹介した、 comparing メソッドの実装を自分で書いて Collections.sort を使ってソートしたコードと比較すると、非破壊的メソッドになりコードも非常にシンプルでわかりやすいものになっていますね。 ソートするなら Stream が圧倒的に便利です。 (参考: Comparator インタフェースの thenComparing メソッド ) 最後に 今回は Stream を使って簡潔にソートをする方法を、従来の Collections を使用した方法と比較して解説しました。 これからソートを使う人も、これまで Collections でソートをしていた人も、ぜひ Stream を使ってシンプルでわかりやすいコードで実装してみてください! 参考書籍 Java による関数型プログラミング Java8 ラムダ式と Stream   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_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 TechCafe。 2022年5月のイベントでは「静的解析」について語り合いました。 弊社のメンバーが事前にまとめてきた静的解析ツールやその使い方の情報にしたがって、他の参加者に意見を頂いて語り合いながら静的解析について学びました。 今回はその内容についてレポートします。 rakus.connpass.com 静的解析とは 一般的な使い方 編集中コードの検証 CIに組み込む 実行時の型検査について PHPDocを書かないと型が通らなくなる? テストコードを静的解析の対象に入れるか? PSRとの関係性 代表的なPHP静的解析ツール PHPMD PHP_CodeSniffer (phpcs) PHPStan Psalm PhpStorm PHPコマンドによる文法チェック 編集後記 静的解析とは Wikipedia からの引用が紹介されました。 コンピュータのソフトウェアの解析手法の一種であり、ファイルを実行することなく解析を行うこと。 ソースコード に対して行われることが多く、少数ながらオブジェクトコードに対して行う場合もある。 ja.wikipedia.org 具体例として、 PHP の ソースコード に対してプログラムを実行せずに解析し、問題点を検出するイメージです。 一般的な使い方 今回は以下の二つを挙げて、紹介されました。 編集中コードの検証 IDE を利用し、コーディング中に静的解析を行うことをイメージして紹介されました。 例として「 PHP 文法の誤りを表示」「不適切コードの指摘」「コード補完」を挙げられていました。 その際に、次のような様々な意見がありました。 PHPerならPhpStormを使用していることが多いため、恩恵は受けていると思う。 コードを書いている際に、下に赤い線で表示されている。 コンパイル しない言語で作る場合、実行時エラーとなる前に気づけるのは、非常に心強い味方となる。 CIに組み込む コードを定期的/自動的に静的解析を行うことをイメージして紹介されました。 具体例としては、以下の説明がありました。 GitにPushした際に自動的に解析を行い、不適切なコードやルール違反を指摘する。 静的解析の実行をGit hooksに組み込んでいる場合もある。 GitにPushし、編集したコードで警告が検出されれば、Pushを拒否するようにも出来る。 PhpStormでコミットする際に、チェックを走らせる事や、自分で選んだコード解析ツールを走らせる事もできる。 メリットとして、以下のような事が紹介されました。 コードレビューの観点が明確になる事で、より有益な話に時間を使えるようになる。 人に指摘されるより気が楽である。 実行時の型検査について 参加者から「実行時の型検査」について考えを聞く質問があり、大変盛り上がりました。 (以下が質問と合わせて貼られたリンクになります。) https://stitcher.io/blog/we-dont-need-runtime-type-checks この記事は PHP の現場で紹介された。 PHP ランタイムが型チェックを行うため、メソッドの戻り値の型を PHP の言語機能でintと記載した場合、実行時にStringを戻り値として返却するとタイプエラーで落ちる。 Docコメントに at return int と記載すれば静的解析のときに弾かれるため、二箇所に return を書く必要があるのは面倒である。 これについては、次のような様々な意見がありました。 自社内でもレビュアーによって意見が割れている。 Docコメントだけでなく、メソッドの戻り値の型を記載して欲しい人。 両方記載は面倒くさいため、言語機能としてサポートされている型はメソッドの戻り値の型を記載し、サポートされていない型はDocコメントに記載する人。 レビューコスト下げるために静的解析を入れているが、意見が割れるため返ってコストが上がってしまっている。 これには PHP の歴史的背景もある。 元々はメソッドの戻り値に型指定ができないため、Docコメントへ記載し、静的解析でチェックする事でしのいできた。 メソッドの戻り値に型指定できるようになった今、「Docコメントで静的解析によるチェック」、「言語仕様として縛りを入れる」のどちらが良いのか? 最終的には以下の方針が挙げられました。 今から新規作成の場合は、言語仕様でもチェックした方が良い。 既存処理への修正の場合、元々静的解析チェックのみで統一されていた箇所は、そのまま「Docコメントに戻り値を記載」で統一でも良い。 しかし、Docコメントはただの文字列であるため、言語仕様で縛れるように少しづつ リファクタリング していく方が良い。 PHPDocを書かないと型が通らなくなる? また、質問者様の考えは以下であったようです。 原則、メソッド戻り値の型宣言は記載する。 Docコメントは ジェネリック スのような必要と判断した場合のみ記載する。 上記以外の基準は、PHPStanでレベルを上げた際に、Docコメントを記載しないとエラーと判定された場合に記載する。 これについては、次のような様々な意見がありました。 PHPStanでしかチェックできないものも多いので、今後方針に悩む箇所が発生しそうだ。 PHPStanでレベルを上げる事によりエラーとなる場合は、他のツールを併用する事で、少しづつPHPStanでメンテする範囲を緩める方法もある。 PHP 言語の型指定が表現豊かではないので、表現豊かにすると実行時にそれだけ解析して処理が重くなるため、Docコメントの方に書いておいたほうが PHP 全体の利益になる。 今は言語仕様が過渡期であるため、 PHP の利点(途中でエラー中断せず最後まで実行)を残すためにノーチェックに出来るオプションが希望されている。 メソッド戻り値の型宣言をCS-Fixerで一括で記載する方法もある。 自動置き換えによる信頼性を疑問視しているので、検出だけ担当するのは良さそう。 テストコードが存在すれば品質は担保できる。 最終的には、チーム皆で話し合って方針を決めて行くのが大事だとまとめられました。 テストコードを静的解析の対象に入れるか? 話の流れから「CIとかで解析を回すときにテストコードは解析対象に入れるか否か」のアンケートが取られました。 このアンケートには、次のような様々な意見がありました。 テストコードを解析するメリットが分からない。 プロジェクト内で PHP の有名なライブラリを確認したが、解析対象になっているものが多かった。 変更部分のみテストできる機能があれば便利である。 CS-Fixerを使用しているが、PHPStanは面倒なので除外にすることが多い。 解析の対象に入れてデメリットは特にないため、基本方針として解析の対象としている。 議論の余地はあるようですが、解析対象として入れるほうが優勢でありました。 PSRとの関係性 PSRとは PHP -FIGが策定している PHP の標準規約集です。 規約は各ルールがほぼ独立しており、好きな規約のみを選んで採用することができます。 www.php-fig.org PSR1とか2とか12とかはコーディング規約に関するものなので取り入れている静的解析ツールも多いのではないか PSR2は現在では非推奨だが、昔からの名残で残っているものもある 代表的な PHP 静的解析ツール PHPMD コードの複雑性を検知してくれるものです。 具体例を挙げると、バグになりそうなコード、最適ではないコード、複雑な表現、未使用のパラメータ・メソッド・プロパティなどを検出してくれるツールです。 これについては、次のような様々な意見がありました。 インストール方法は色々あり、最近だとComposerが便利。直接GtiHubから落とすことも出来る。 コマンドで実行した場合、PHPMDで検出対象のファイルや ディレクト リを指定、結果のフォーマット選択、ルールセット指定の手順である。 ルールセットは、コードサイズや、設計関連ルール、ネーミング、未使用コード検出などのルールが予め定義されている。 xml ファイルを配置し、必要なルールのみ適用、または、不要なルールを削除し、個別ルール(最大値や最小値など)へ変更することも可能である。 実行例 [ root@vg110 core ] # vendor/phpmd/phpmd/src/bin/phpmd test .php text codesize,controversial,design,naming,unusedcode /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseMethodName The method test_function is not named in camelCase. /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseParameterName The parameter $param_string is not named in camelCase. /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseVariableName The variable $param_string is not named in camelCase. phpmd.org PHP _CodeSniffer (phpcs) コーディング規約の違反を検出するライブラリです。 PSRや PEAR などの様々なコーディング規約を指定して検査を実施してくれます。 これについては、次のような様々な意見がありました。 独自の規約を追加することも可能である。 インストール方法は色々あり、Composerや GitHub からなど、好みの方法で導入できる。 コーディング規約の違反を自動で修正するphpcbfも付属している。 全て修正する事は出来ず、修正出来た物も目視チェックは必要である。 完全に信用する訳ではなく、phpcsの指摘があるファイルをユーザに通知し、修正は手動で行う運用をしている。 phpcbfは結構正確だが、phpcsに問題がある。 改行やインデントについて、コード上は正常であっても、CS-Fixerがエラーと判定するケースがたまにある。 実行例 $ phpcs /path/to/code/myfile.php FILE: /path/to/code/myfile.php -------------------------------------------------------------------------------- FOUND 5 ERROR ( S ) AND 1 WARNING ( S ) AFFECTING 5 LINE ( S ) -------------------------------------------------------------------------------- 2 | ERROR | Missing file doc comment 20 | ERROR | PHP keywords must be lowercase; expected " false " but found | | " FALSE " 47 | ERROR | Line not indented correctly; expected 4 spaces but found 1 47 | WARNING | Equals sign not aligned with surrounding assignments 51 | ERROR | Missing function doc comment 88 | ERROR | Line not indented correctly; expected 9 spaces but found 6 -------------------------------------------------------------------------------- コーディング規約の指定 # インストールされているコーディング規約を確認 $ phpcs -i The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz and Zend # コーディング規約を指定して実行(デフォルトはPEAR) $ phpcs --standard=PSR12 /path/to/code/myfile.inc # デフォルトのコーディング規約を変更 $ phpcs --config-set default_standard PSR12 規約のカスタマイズ phpcs. xml ファイルを設置して独自のコーディング規約を設定できる。 <? xml version = "1.0" ?> <ruleset name = "Custom Standard" > <rule ref = "PSR12" > <!-- "PSR12" の中で除外するルール --> <exclude name = "Generic.Files.LineLength" /> </rule> <!-- 追加するルール --> <rule ref = "PEAR.WhiteSpace.ObjectOperatorIndent" /> <!-- 除外するファイル・ディレクトリ --> <exclude-pattern> node_modules/ </exclude-pattern> </ruleset> github.com PHPStan こちらも同じくComposerやDockerから利用可能です。 PHARからもダウンロード可能です。 ただし、Composerが無いとPHPStanの 拡張機能 は使えません。 解析の厳密さはオプションで変更可能で、PHPStanの場合はレベル0から9で設定可能です。 レベル0が一番ゆるく、レベル9が最も厳密となっている レベル0は基本的なチェックで、PSRと同等のチェックレベル レベル9では、混合型(mixed)についても厳密であるレベル(混合型(mixed)は、別の混合型(mixed)に渡す操作しか許可されない)になる PHPStanの公式に記載がありますが、以下の理由から使用方法はレベル0から順番に対応していくのが正攻法のようです。 初めからレベル9を設定すると、エラー件数が膨大となり、何から手を付けたらいいか分からなくる。 上位のレベルでエラーを検知した際は、下位のレベルで検知されるエラーも合わせて修正を行わないと、エラーは解消されない 歴史の長いプロジェクトでは、レベル0の設定でも多くのエラーが検出されます。 全ての検出されたエラー対応が困難な場合は、ベースラインの設定を推奨します。 ベースラインを設定することにより、以下のようなことが出来ることが紹介されました。 ある時点で検出したエラー内容を基準とし、それ以降の静的解析の実行で、基準としたエラー内容を報告しないように出来る。 既存コードで検出されているエラーを除外出来るため、新しいコードと変更されたコードで検知されたエラーのみに注力することが出来る。 カスタムルールも設定できるようになっており、 phpstan-rules と phpstan-strict-rules を使用して拡張することが出来る。 これについては、次のような様々な意見がありました。 レベル5からレベル6の間が深い河である レベル6は「タイプヒントの欠落を表示」であるため、クリア難易度が高い ベースラインの概念があることは有難い 別のツールでPHPStanのベースラインと同様の事を行ったが、非常に辛かった ベースラインの概念は他ツールでは、Psalmにもある サイボウズ さんでは「ベースラインを自動実行する」取り組みを行っていて面白そう(※) phpstan.org ※ 情報元の紹介はありませんでしたが、記事化にあたって調べたところ参考になるスライドがありました。  ツールはPHPStanではないですが、適応出来そうです。 効果的な静的解析の CI導入パターンを求めて / Great static analysis with CI - Speaker Deck Psalm こちらもPHPStanと同様で、厳密さをレベルで調節できます。 ただし、レベルの強弱がPHPStanと逆になっており、レベル1が最も厳しく、レベル8が一番ゆるい設定になっています。 良い点として、次のように紹介されました。 検知された違反ルールがなぜ不適切なのか理由が解説されるため、納得感を得やすくなっている。 これがなんで悪いの? と思うときがあるが、理解ができると直すモチベーションも得られるのではないか。 例 psalm.dev PhpStorm 編集中に解析を行い、危険な箇所に対して下線で示すか、ハイライトしてくれます。 解析方法は PHP ファイルをPhpStormで開くだけです。 文法の誤りをハイライトし、重要度によってハイライト部分の色が変更されるため見やすい。 プロファイルの編集で解析内容を編集でき、任意の解析を追加する事もできる。 他の解析ツールをインストールし使用すことも可能。 pleiades.io PHP コマンドによる文法チェック 少し本筋とは違いますが、「静的解析を調べる際に、 php -l で文法チェックができることを見つけた。」と紹介されました。 そのため、文法の間違いについては、静的解析ツールを使用せずにエラー検知する事が出来ます。 これについては、次のような様々な意見がありました。 php -l で静的解析できることを初めて知った。 静的解析かと言われると疑問がある。一応解析は行っているので意味は合っている? 全ファイルを対象に php -l を実行したことが何度かある。 おそらく全ファイルに対して一括置換のような処理を実行したタイミング。 または、 PHP のメジャーバージョンアップ後に粗探しとして調査するタイミング。 PHP のバージョンアップ後に一旦実行し、エラー検知した場合は早急に対応が必要であるため。 編集後記 以上、静的解析の概要と代表的なツールについて取り上げました。 PHP TechCafeでは今まで取り上げることがなかった話題でしたので、主催者/参加者ともに盛り上がりを見せていました! 今後も静的解析の活用方法や、新たなニュースに着目していきたいと思います! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
技術広報の yayawowo です。 今回は、 Linux 上でファイルや ディレクト リ内容を一覧表示する際に利用する、 『ls コマンド』 について紹介します! ls コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明させていただきます。 【目次】 ls コマンドとは? ls コマンドの使い方 基本書式 ls コマンドのオプション一覧 表示フォーマット関連 出力フォーマット関連 サイズ関連 時間関連 ソート関連 ls コマンドの活用例 Linux関連のおすすめブログ 終わりに ls コマンドとは? lsコマンドは、ファイルや ディレクト リの一覧を表示するためのコマンドです。 ls コマンドの使い方 基本書式 ls コマンドの基本書式は、以下の通りです。 $ ls [ オプション ] [ ファイル/ディレクトリ ] ファイルや ディレクト リの一覧を表示させるには、対象のファイル/ ディレクト リ名を指定する必要があります。 また、ls コマンドには多くのオプションがあります。 以下にまとめておきますので、用途に合わせて使い分けください。 ls コマンドのオプション一覧 表示フォーマット関連 オプション 説明 -l 詳細情報を表示 -o グループ情報以外の詳細情報を表示 -n 所有者/グループ名の代わりにユーザIDとグループIDとし、詳細情報を表示 -a .(ドット)ファイルも含めて表示 -A 「.」「..」以外の.(ドット)ファイルも含めて表示 -d ディレクト リ内容を表示せず、 ディレクト リ名のみを表示 出力フォーマット関連 オプション 説明 -1 リストを1件1行で表示 -m リストをカンマ区切りで表示 -C リストの出力を列(縦)にソート表示 -x リストの出力を行(横)にソート表示 -q 表示不可能な文字を?で表示 -F ファイル/ ディレクト 名の後にタイプ識別子(*/=>@|のどれか)を付けて表示 -p ディレクト リ名の後にのみ、/を付けて表示 サイズ関連 オプション 説明 -k -l と併用し、1KB単位のサイズ形式で表示 時間関連 オプション 説明 -c -l と併用し、ファイル属性の変更時間(ctime)を表示 -u -l と併用し、最終アクセス日を表示 ソート関連 オプション 説明 -S ファイルサイズが大きい順に表示 -t ファイル更新日が新しい順に表示 -v 数字順にソート表示 -r 並び順を反転させて表示 ls コマンドの活用例 前提としまして、 /home 配下に以下 ディレクト リとファイルを準備しております。 /home  ┗ sample  ┗ sample2  ┗  hoge .txt  ┗ hoge2.txt これを使い、ls コマンドの活用例をご紹介します! 詳細情報を表示(-l) localhost:/home# ls -l total 8 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 所有者/グループ名の代わりにユーザIDとグループIDとし、詳細情報を表示(-n) localhost:/home# ls -n total 12 -rw-r--r-- 1 0 0 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 0 0 0 Sep 13 09:40 hoge2.txt drwxr-xr-x 2 0 0 37 Sep 13 09:12 sample drwxr-xr-x 2 0 0 37 Sep 13 09:12 sample2 .(ドット)ファイルも含めて表示(-a) localhost:/home# ls -a . .. hoge.txt hoge2.txt sample sample2 リストを1件1行で表示(-1) localhost:/home# ls -1 hoge.txt hoge2.txt sample sample2 ディレクト リ名の後にのみ、/を付けて表示(-p) localhost:/home# ls -p hoge.txt hoge2.txt sample/ sample2/ ファイルサイズが大きい順に表示(-S) ※ -l と -S の複数オプション利用のため、コマンド実行時は -lS と定義しています。 localhost:/home# ls -lS total 8 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt ファイル更新日が新しい順に表示(-t) ※ -l と -t の複数オプション利用のため、コマンド実行時は -lt と定義しています。 localhost:/home# ls -lt total 8 -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample 並び順を反転させて表示(-r) ※ -l と -t と -r の複数オプション利用のため、コマンド実行時は -ltr と定義しています。 # ファイル更新日順に表示 localhost:/home# ls -lt total 8 -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample # ファイル更新日順を反転し、表示 localhost:/home# ls -ltr total 8 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt Linux 関連のおすすめブログ tech-blog.rakus.co.jp Linux コマンドのまとめ記事です! 本ブログがあれば、 Linux 操作に困らないと思います。 tech-blog.rakus.co.jp Linux 上でエディタを触る機会が多い方向け! vi コマンドの基本的な使い方を目的別にまとめております。 tech-blog.rakus.co.jp Linux 上に存在するログを調査するにあたり、良く用いる文字列検索を行う grep コマンドの記事です。 grep コマンドの中でも、実務でよく使っている検索方法を併せて紹介しています! tech-blog.rakus.co.jp 2つのファイルを比較して違い(差分)を出力するdiff コマンド。 diffコマンドの表示オプションを知りたい方は、是非ご確認ください。 tech-blog.rakus.co.jp Linux 上でファイルや ディレクト リ検索時に利用するfind コマンドについて紹介! find コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明しております。 終わりに いかがでしたでしょうか? 今回はファイルや ディレクト リの一覧を表示したい際に良く用いる、ls コマンドをご紹介させていただきました。 また、ls コマンドのオプションも今回ご紹介させていただきましたが、利用用途に合わせて使い分けていただくことで業務効率を上げることができます! ls コマンドは、 Linux を触る方にとっては基本のキかと思います。 もし、ls コマンドを触るときに「どのオプション使うんだっけ?」と不安になった方は是非本記事をご参考いただけますと幸いです。 最後までお読みいただきありがとうございました! ◆ その他おすすめブログ ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【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
弊社で毎月開催し、 PHP エンジニアの間で好評いただいている勉強会「 PHP TechCafe」。 2022年3月のイベントでは『PHPerのための「Laravel9について語る」』をテーマに語り合いました。 弊社のメンバーがLaravel9の新機能などの情報を元に、他の参加者に意見をいただいて語り合いながらLaravel9について理解を深めました。 今回はその内容についてレポートします。 rakus.connpass.com PHP TechCafeとは PHPerのための「Laravel 9 について語る」 Laravel9の特徴 PHP8対応 LTSが消えた ハイペースなマイナーバージョンアップ Laravel9の新機能や変更点 Symfony Mailer Flysystem 3.x Improved Eloquent Accessors / Mutators Enum Eloquent Attribute Casting Implicit Route Bindings With Enums Forced Scoping Of Route Bindings Controller Route Groups Full Text Indexes / WhereClauses Slot Name Shortcut Checked / Selected Blade Directives whereNot clause Improved Ignition Improved route:list CLI Output アップデートの落とし穴 app/Http/Middleware/TrustProxies.php の修正 $headersの修正 編集後記 PHP TechCafeとは 本題に入る前に「 PHP TechCafe」について軽く説明します。 「 PHP TechCafe」とは弊社が主催しているエンジニア向けのイベントで、エンジニア同士で技術について話し合う憩いの場(カフェ)です。 月に1回開催し、コロナ禍の現在はオンラインで開催しています。 対象者は PHP 入門の初級エンジニアからシニアエンジニアを幅広くカバーし、学びの場を提供してエキスパートまでの自己成長を支援することを目的にしています。 「 PHP TechCafe」は以下の3部構成です(日によって変わることもあります)。 ライトニング トーク (LT) PHPer's NEWS 特集 2022年3月の特集は『PHPerのための「Laravel 9 について語る」』をテーマに開催いたしました。 今回はその中で紹介された内容や盛り上がったポイントをレポートします。 PHPerのための「Laravel 9 について語る」 Laravel9の特徴 まずはお約束のLaravel9の特徴からです。 PHP8対応 PHP8に対応し、8未満には対応しなくなりました。 LTSが消えた どんどんバージョンを上げていきましょう!、という意味かもしれませんね。 ハイペースなマイナーバージョンアップ Laravel9は、短いスパンで次々とマイナーバージョンアップを重ねていることにも注目が集まり、話題となりました。 マイナーバージョンアップで新機能がいくつも追加されています。 意外と使えそうな機能もよくあるので、新機能を使いたくなったら上げなきゃいけないですね。 Laravel9の新機能や変更点 Symfony Mailer Laravel標準の メーラー がSwift Mailerから Symfony Mailerに変更されました。 そもそもSwift Mailerってメンテナンスが止まっているのでLaravelもこちらに乗り換えたようです。 結構互換性の無いものもあるので、しっかり見て変更しましょう。 インターフェースも変わってしまったんですね。Classを呼んでるところだけ置き換えたらOKという感じでもないですね。しっかり置き換えないといけない。 Sending Emails with Mailer (Symfony Docs) Flysystem 3.x Storage ファサード によって提供されており、ファイル操作系処理を強化するFlysystemがバージョンアップしました。 S3とか FTP などを利用している場合はドライバのアップデートが必要です。 挙動も変わっているんですよね。PutやWrite、Writestreamなどを使うとデフォルトでファイルを上書きするようになるので、注意しないといけないです。 存在しないファイルを指定すると以前はNullが返ってきていましたが、例外が返ってくるようになりました。 File Storage Abstraction for PHP - Flysystem Improved Eloquent Accessors / Mutators これはEloquentのモデルについてです。 Laravel9 以前 <?php public function getNameAttribute ( $ value ) { return strtoupper ( $ value ) ; } public function setNameAttribute ( $ value ) { $ this -> attributes [ 'name' ] = $ value ; } ↑ モデルにアクセサーとミューテタに プレフィックス 付きのメソッドを定義する必要がありました。 Laravel9 <?php use Illuminate\Database\Eloquent\Casts\Attribute; public function name () : Attribute { return new Attribute ( get : fn ( $ value ) => strtoupper ( $ value ) , set : fn ( $ value ) => $ value , ) ; } ↑ プレフィックス なしのメソッドに戻り値の型を指定(Attribute)することで、アクセサーとミューテタが定義可能となりました。 ルーティング 9.x Laravel Enum Eloquent Attribute Casting PHP8.1以上で稼働させている場合のみ動作して、モデルに挿入する値を Enum 型でキャスト可能にします。 <?php use App\Enums\ServerStatus; /** * The attributes that should be cast. * * @var array */ protected $ casts = [ 'status' => ServerStatus :: class , ] ; Eloquent:ミューテタ/キャスト 9.x Laravel Implicit Route Bindings With Enums ルートパラメータを Enum 型で指定することができます。 型に一致しないパラメータが指定されたら、404が返されます。 Enum の定義 <?php enum Category : string { case Fruits = 'fruits' ; case People = 'people' ; } ルーティングの記載 <?php Route :: get ( '/categories/{category}' , function ( Category $ category ) { return $ category -> value ; }) ; Enum が使えるようになったから、こういうところにも使っていこうっていうことですかね。 どこを見たら良いかわかりやすいですね。 404にしてくれるのがありがたい。無理やり動かすのは流石につらいので。 ルーティング 9.x Laravel Forced Scoping Of Route Bindings 親のモデルと子のモデルを使用してRoute model bindingを行いたい場合、子のモデルにはカスタムキーを使用する必要がありました。 Laravel9 以前 <?php use App\Models\Post; use App\Models\User; Route :: get ( '/users/{user}/posts/{post:slug}' , function ( User $ user , Post $ post ) { return $ post ; }) ; それが、scopeBindings()を使用することで、カスタムキーなしでも子のモデルに対してRoute model bindingを行えるようになりました。 Laravel9 <?php use App\Models\Post; use App\Models\User; Route :: get ( '/users/{user}/posts/{post}' , function ( User $ user , Post $ post ) { return $ post ; }) -> scopeBindings () ; Route model bindingとは、例えばこのコードの場合、RouteパラメータのところにUserやPostやモデル名を指定しています。UserのところにID1が入ったとしたらID1のUserのモデル インスタンス を自動的に取ってきてくれるというものです。 今まではカスタムキーで”post:slug”を定義する必要があったのですが、それがLaravel 9からScope Bindingを使えば不要となり、シンプルに書きやすくなったようですね。 ルーティング 9.x Laravel Controller Route Groups 全てのルートに共通のコントローラをグループとして定義できるようになりました。 Laravel8 <?php # 何度もController名を書かないといけない use App\Http\Controllers\OrderController; Route :: get ( '/orders/{id}' , [ OrderController :: class , show ]) ; Route :: post ( '/orders' , [ OrderController :: class , store ]) ; Laravel9 <?php use App\Http\Controllers\OrderController; Route :: controller ( OrderController :: class ) -> group ( function () { Route :: get ( '/orders/{id}' , 'show' ) ; Route :: post ( '/orders' , 'store' ) ; }) ; コントローラごとにグループ分けができるようになりました。 この変更にはこんな声がありました。 ヤンチャな実装する人だったら、まとまりを無視して変なところに定義を書いたりすることがありますが、Laravel9だとそこは強制されるのでヤンチャできなくなりますね。 概念としてコントローラが上になったような気がして、個人的にはちょっと嫌だなって思いますね。コントローラがルートを決めたんじゃないかというニュアンスになるので。 ルートとコントローラが密結合になったんじゃないかという印象を持ちました。ここまでやるならそもそも定義書かなくてよくない?という感じもしますね。 ルーティング 9.x Laravel Full Text Indexes / WhereClauses 指定した列に FULLTEXT INDEX を作成できます。※ MySQL か PostgreSQL <?php $ table -> text ( 'bio' ) -> fullText () ; FULLTEXT INDEX がある列に対して、WHERE句を作成することもできます。 <?php $ users = DB :: table ( 'users' ) -> whereFullText ( 'bio' , 'web developer' ) -> get () ; これすっごくありがたいです。どデカいテキストの部分一致検索みたいなやつは、 巨大掲示板 とかになってくると Elasticsearch にするとかでないと対応できなかったんです。 PostgreSQL にしろ MySQL にしろテーブルとかインデックスの型の定義がすごく独特で大変なんです。しかも標準 SQL に定義されていない機能なので正直ダルいんですよ…。だから欲しかった人は本当に欲しかったものだと思います。 今まではCreate Indexとか SQL を直書きしないと駄目ですよね。それを検索するときもwhereじゃなくてwhereRawとか使って SQL 直書きするしかなかったんですよ。それが公式にサポートされたから作れるようになったんですね。 データベース:クエリビルダ 9.x Laravel Slot Name Shortcut Blade関連ですね。 X-slotタグを短く書けるようになりました。 Laravel9 以前 <x-alert> <x-slot name = "title" > Server Error </x-slot> </x-alert> Laravel9 < x-slot : title> Server Error </x-slot> これはサッと読めるようになるので、どんどん使っていきたいですね。   Bladeテンプレート 9.x Laravel Checked / Selected Blade Directives こちらもBlade関連。 @checked  チェックボックス をONに指定できる <?php < input type = "checkbox" name = "active" value = "active" @checked ( old ( 'active' , $ user -> active )) /> @selected セレクトボックスにてデフォルトで選択されている項目を指定できる <?php < select name = "version" > @ foreach ( $ product -> versions as $ version ) < option value = "{{ $ version }}" @selected ( old ( 'version' ) == $ version ) > {{ $ version }} </ option > @ endforeach </ select > @checkedって書いていたらそこの チェックボックス をオンに出来ますよとか、@selectedにしたらデフォルトで選択されている項目を指定できます。今まで 三項演算子 で書いていたものがBladeで書けるようになって、痒いところに手が届くようになりました。 Bladeテンプレート 9.x Laravel whereNot clause クエリビルダでずっとサポートされていなかった、whereNotがようやく使えるようになりました。 whereNotは何回かリジェクトされて9.3でやっと取り込まれた経緯があるそうです。 できることなら肯定形で書きたいです。でも SQL の構文として存在するものはサポートしてほしい気はしますね。今までそれをあえて入れなかったのは、否定形を入れずに綺麗なものを目指すんだという強い意思があったのかもしれないですね。 SQL の構文としてはあるけど、Laravelには無いから今回取り入れたという感じですかね。あえて書きたいケースもありますし。他のすべてのメソッドにはNotがあるけれど、whereにだけ無いと。 データベース:クエリビルダ 9.x Laravel Improved Ignition 開発中の例外発生時などに表示されるIgnitionが新しくなりました。 ダークテーマや「エディタで開く」を選べるようになりました。 リリースノート 9.x Laravel Improved route:list CLI Output route:listの CLI が見やすくなりました。 最近 CLI の見やすくなるアップデートが割と多いですね。 本当に見やすくなりました。ただ一方で PHPUnit Printerに外部ライブラリを入れて綺麗にしていた人は一気に全部崩れたみたいです。なので外して公式にし直すというのがウチではありました。 以前は色も何もついてなくて、”…”もついてなくて、縦バーで区切ってましたね。 リリースノート 9.x Laravel アップデートの落とし穴 アップデートガイドのところでここの PHP ファイルだけ開いて修正してね、ということです。ここだけ手作業ということで、ハマりそうですね。 app/Http/Middleware/TrustProxies. php の修正 変更前 use Fideveloper\Proxy\TrustProxies as Middleware 変更後 use Illuminate\Http\Middleware\TrustProxies as Middleware $headersの修正 変更前 protected $headers = Request::HEADER_X_FORWARDED_ALL; 変更後 protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_POST | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB ; Composerをアップデートしてもダメで、Bootstrapのキャッシュを消さなきゃいけないのでこの作業が必要になるようです。 ここはつまづきますね。「キャッシュ周りでアップデートしたのに何で古い方を読みにいってるの?」ってことが起こってました。 Upgrade Guide - Laravel - The PHP Framework For Web Artisans 編集後記 メジャーバージョンアップだけではなく、マイナーバージョンアップでも次々に機能追加がされたりとさらに開発が活発化している印象でした。 LTSがなくなったのは我々開発者としては痛いところですが、これは長期サポートのコストをLaravelの開発をどんどん前に進めることに充てるというアグレッシブな思想があるからかもしれませんね。 ここでは語りつくせない変更もまだまだあるので、リリースノートは要チェックです。 今後もLaravelの進化から目が離せません! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
はじめに 皆さんこんにちは、開発課のthree_yagiです。 現在の業務では不具合などが発生したときの原因調査を担当することが多く、本番環境のログの調査をよく行っています。 Linux 上に存在するログを調査するにあたって、必須ともいえるのが文字列検索を行う grep コマンドです。 こちらの記事では、 grep コマンドについて私が実務でよく使っている検索方法と併せて紹介していきます。 目次 はじめに 目次 grep コマンドの基本 基本構文 よく利用するオプションと正規表現 オプション 正規表現 利用例(基本編) 基本の検索 AND検索 OR検索 NOT検索 大文字と小文字を区別しないで検索 マッチした行数を表示 マッチした行のうち〇行だけ表示 マッチした行の前後の行も表示する 正規表現で様々な条件で検索する 利用例(応用編) grepした文字をハイライト表示 圧縮ファイルをgrepする grepコマンド まとめ   grep コマンドの基本 grep は 検索対象のファイルから指定した文字列を含む行を表示する Linux コマンドです。 正規表現 とオプションを駆使することで様々な条件での検索が行えます。 基本構文 $ grep [オプション] 検索文字列 対象ファイル よく利用するオプションと 正規表現 実際によく利用しているオプションについて記載します。 これらを使いこなせれば一通りの検索はできるかなと思います。 オプション オプション 説明 -E 拡張正規表現 (ERE)を利用する ※このオプションなしでも 正規表現 の「. * ^ $ [ ]」は利用可能 -e [検索文字列] オプションの引数として検索文字列を指定する このオプションを複数回使用することでOR検索が可能 -v 結果を反転する。検索文字列を含む行以外を表示 -i 検索文字列の大文字と小文字を区別しない -c マッチした行ではなく、マッチした行数を表示 -m [数字] [数字]行分だけ表示する -B [数字] マッチした行の前 [数字] 行を表示 -A [数字] マッチした行の後 [数字] 行を表示 -C [数字] マッチした行の前後 [数字] 行を表示 -h 出力する行の前にファイル名を付けないようにする -n 頭にそのファイル内での行数を表示 正規表現 正規表現 を利用することで柔軟な検索ができるようになります。 拡張正規表現 の列が「〇」の 正規表現 はオプションで「-E」を指定する必要があります。 正規表現 意味 拡張正規表現 . 任意の 1 文字 * 直前の 1 文字または パターンが 0 回以上繰り返す ^ 行の先頭を表す $ 行の末尾を表す [ ] 括弧内の任意の 1 文字が存在する ( ) パターンのグループ化 〇 + 直前の 1 文字 または パターンが 1 回以上繰り返す 〇 ? 直前の 1 文字 または パターンが 0 回または 1 回だけ存在 〇 {n} 直前の 1 文字 または パターンが n 回繰り返す 〇 | 2 パターンのうちどちらか片方 〇 利用例(基本編) 実際の利用例を見ながら利用方法について確認してみましょう。 検索対象のテストファイル(test.txt)には 都道 府県がローマ字で記載されたファイルを使用しています。 # テスト用ファイル $ cat test .txt hokkaido aomori iwate miyagi akita yamagata ︙ miyazaki kagoshima okinawa 基本の検索 まずは単純に指定した文字列を含む行を表示してみます。 # 【検索条件】'yama' を含む行を表示 $ grep ' yama ' test .txt yamagata toyama yamanashi wakayama okayama yamaguchi AND検索 grep の結果を |(パイプ) でつなぐことで1つ目の grep の検索結果に再度 grep をかけることになり、AND検索が可能です。 # 【検索条件】'yama' と 'oka'を含む行を表示 $ grep ' yama ' test .txt | grep ' oka ' okayama OR検索 OR検索はオプションの「-e」を使って検索文字を複数指定する方法と、 正規表現 を利用する方法があります。 正規表現 を利用する場合は 拡張正規表現 の「|」を使用するので、オプション「-E」を指定する必要があります。 どちらも結果は同じになるのでお好きな方を利用してください。 # 【検索条件】'yama' または 'oka' を含む行を表示 # 「-e」を使ってOR検索 $ grep -e ' yama ' -e ' oka ' test .txt # 正規表現でOR検索 $ grep -E ' yama|oka ' test .txt # 結果は同じ yamagata toyama yamanashi shizuoka wakayama okayama yamaguchi fukuoka NOT検索 ○○を含む行以外を検索したい場合は、検索結果を反転する「-v」オプションを利用します。 #【検索条件】 'yama'を含まない行を表示 $ grep -v ' yama ' test .txt hokkaido aomori iwate miyagi akita fukushima ibaraki ⁝ 複数指定する場合 #【検索条件】 'yama' と 'oka'を含まない行を表示 # OR検索の結果を「-v」で反転させればどちらも含まない行を表示できます $ grep -v -e ' yama ' -e ' oka ' test .txt $ grep -v -E ' yama|oka ' test .txt ( 結果省略 ) 大文字と小文字を区別しないで検索 デフォルトでは文字の大文字と小文字を区別した状態で検索を実行します。 大文字と小文字を区別せずに検索する場合は「-i」オプションを利用します。 # オプションなしだと'Yama'を含む行しか対象とならないのでいずれの行も出力されません $ grep ' Yama ' test .txt # オプションありだと'yama'も対象となるので結果が出力されます $ grep -i ' Yama ' test .txt yamagata toyama ⁝ マッチした行数を表示 「-c」オプションを用いることで検索結果の行ではなく行数が表示されます。 #【検索条件】'yama'を含む行の合計の行数を表示 $ grep -c ' yama ' test .txt 6 マッチした行のうち〇行だけ表示 「-m」オプションで結果を表示する行数を指定できます。 #【検索条件】'yama'を含む行のうち頭から2行分だけ表示 $ grep -m 2 ' yama ' test .txt yamagata toyama マッチした行の前後の行も表示する 「-B」「-A」「-C」オプションを利用することでマッチした行の前後の行も表示できます。 「-B」「-A」で前と後それぞれの表示する行数を指定でき、「-C」で前後まとめて行数を指定できます。 ログを調査する際にはよく使うオプションです。 #【検索条件】 'tokyo' を含む行を前後1行も含めて表示 # 「-B」「-A」で前後それぞれ指定 $ grep -B 1 -A 1 ' tokyo ' test .txt # 「-C」でまとめて指定 $ grep -C 1 ' tokyo ' test .txt chiba tokyo kanagawa #【検索条件】 'tokyo' を含む行を前3行,後2行も含めて表示 $ grep -B 3 -A 2 ' tokyo ' test .txt gunma saitama chiba tokyo kanagawa niigata 正規表現 で様々な条件で検索する #【検索条件】'〇a〇a〇a'という文字列を含む行を表示 # '.'は任意の1文字 $ grep ' .a.a.a ' test .txt yamagata kanagawa yamanashi wakayama okayama kagawa nagasaki # こちらも同じ条件での検索となる # '( )' グループ化 # '{n}'直前の文字のn回の繰り返し $ grep -E ' (.a){3} ' test .txt #【検索条件】'a'で始まる行を表示 # `^`は行頭を意味する $ grep ' ^a ' test .txt aomori akita aichi #【検索条件】'a'で始まり先頭以外にも'a'を含む行を表示 # '*'は直前の文字の0回以上の繰り返し # '.'と組み合わせた '.*' は任意の0 or n文字を表す $ grep ' ^a.*a ' test .txt akita 利用例(応用編) grep した文字をハイライト表示 --color=always で検索した文字列に色を付けることができます。 検索結果が大量のときや、 正規表現 で検索していてどこからどこまでがマッチしているか確認したいときなどに便利です。 $ grep --color = always -E ' (.a){3} ' test .txt このように表示されます 圧縮ファイルを grep する ログファイルなどは圧縮された状態で保存されていることが多いかと思います。 圧縮されたファイルに対しては zgrep コマンドを利用することで grep と同じように検索できます。 grep と同じオプションや 正規表現 も利用でき、使用方法としては grep と同じになります。 $ zgrep -i ' Yama ' test .gz grep コマンド まとめ grep コマンドは Linux を利用するにあたって必須ともいえるコマンドです。 使いこなせるようになればファイルの検索などのスピードが劇的にアップします。 今回紹介したのは一部のオプション、 正規表現 となります。 他にも有用なものはたくさんあるのでぜひご自身で調べてみてください。 ◆ Linux の理解をより深めたい方へ以下関連おすすめブログ ・ ls コマンド 【使い方 まとめ】 ・ よく使うLinuxコマンド一覧【最新版】 ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ vi コマンド【使い方まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【Linux】今振り返りたい、プロセスって何?   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
こんにちは! ラク スでインフラ開発部というところに所属している akiponx です。 今回は CDN の一つ。 AWS が提供しているCloudFrontで WordPress を高速化してみた話を書いてみます。 使ったサービスは ACM ... Amazon の無料 SSL証明書 Route53 ... DNS EC2 ... オリジンサーバ ELB ... ALBを利用 S3 ... ログ置き場 CloudFront ... CDN CloudFront Functions ... IP制限, Basic認証 AWS WAF ... アクセス制限 あたりを使って実装していきます。 目次 目次 1. CloudFrontとは? 2. CloudFront用語 オリジンサーバ エッジサーバ ディストリビューション オリジンドメイン 3. CloudFrontの料金 CloudFront 無料枠 CloudFront オンデマンド料金 4. CloudFrontを使う準備 5. CloudFrontの設定方法 6. CloudFrontでWordPressを配信する デフォルトのビヘイビアの編集 7. CloudFrontでWordPressを配信するときの注意点 おまけ アクセス制限 8. まとめ 1. CloudFrontとは? CDN の一つがCloudFrontです。 CDN とは、Contents Delivery Network の略で、コンテンツを配信するネットワークという意味合いです。 CloudFrontは AWS が提供する CDN で世界中にエッジサーバが存在しているため、どこからアクセスしても爆速でレスポンスが返ってきます。 2. CloudFront用語 CloudFrontを語るには、以下の用語はおさえておきたいところです。 CDN の基本用語とも被るところはありますので「知ってる!」という方はすっ飛ばしてください。 オリジンサーバ エッジサーバ ディストリビューション オリジン ドメイン キャッシュビヘイビア では順番に説明していきます。 オリジンサーバ CloudFrontが配信するコンテンツが置いているサーバのことです。( AWS でいうとEC2とかS3とか) CloudFrontのエッジサーバにキャッシュがなかった場合、オリジンサーバまでリク エス トが届きます。 エッジサーバ 世界中に存在しているCloudFrontのキャッシュサーバたちのことです。 ブラウザでアクセスすると、まずエッジサーバにリク エス トが行くように DNS の設定を行います。   エッジサーバがキャッシュを持っていなかったときは、オリジンサーバにリク エス トが行きます。 逆にエッジサーバがキャッシュを持っていれば、そのままエッジサーバがキャッシュされたページをブラウザに返します。 ディストリビューション CloudFrontが配信するサイト…というか設定…のことを言います。 複数のサイトを1つの ディストリビューション で設定することも可能ですが、サイトごとにキャッシュの設定を変更したい場合などもあるので個人的には1 ディストリビューション につき、1サイトとしたほうが柔軟性は高いと思います。 本記事では1 ディストリビューション 、1サイト構成で説明していきます。 オリジン ドメイン ブラウザからアクセスさせたい ドメイン のことです。 例えば、 https://rakus.co.jp/ へのアクセスをエッジサーバ経由にしたい場合、CloudFrontのオリジン ドメイン 部分に rakus.co.jp を設定します。 3. CloudFrontの料金 CloudFront 無料枠 1TBのデータ転送(アウト) 1,000万件のHTTP, HTTPS のリク エス ト 200万件のCloudFront Functionsの呼び出し CloudFront オンデマンド料金 エッジサーバからインターネットへのデータ転送(アウト)の料金 (GB 単位) 10TBまで0.114(USD) 次の40TBまで0.098(USD) 次の100TBまで0.086(USD) オリジンサーバからエッジサーバへのデータ転送(アウト)の料金 (GB 単位) 0.060USD HTTPメソッドリク エス ト料金(1万件当たり) HTTP: 0.0090(USD) HTTPS : 0.0120(USD) CloudFront Functions (100万件当たり) 0.10(USD) 詳しくは 公式 をご覧ください。 4. CloudFrontを使う準備 ドメイン を用意 ( DNS 登録含む) ACM ( AWS が提供している無料の SSL証明書 ) ELB or S3 (コンテンツがおかれているオリジンサーバ) ※ ACM は 米国東部( バージニア 北部)(us-east-1)リージョン で発行しなければCloudFrontでは使えません。 ※オリジンサーバの構築場所に東京リージョンを使う場合、東京リージョンで ACM の発行も必要です。  (2か所で設定するのめんどくさいですが。) 5. CloudFrontの設定方法 さて、それではそろそろ実際にCloudFrontの始め方、設定方法を見ていきましょう。 まずは、CloudFront ディストリビューション 作成ボタンをクリックします。 続いて各項目を入れていきます。 オリジン CloudFrontにオリジンサーバを教えてあげる項目です。 オリジン ドメイン ELBかS3の バケット を指定(今回はELB) マッチビューアー アクセスできる プロトコル を選択 両方アクセスさせたいときはマッチビューワー オリジンパス 「/」を入れればOK 名前 基本的には何でもいいですが、サイト名とかわかりやすいのにするといいと思います デフォルトのキャッシュビヘイビア CloudFrontのキャッシュを持たせる設定を行う項目です。 初期設定ではCloudFront経由でアクセスした全リク エス トに対してキャッシュの設定されてしまいますが、後で URI 毎にキャッシュの設定が可能です。 オブジェクトを自動的に圧縮 Yesにしておくとよい。転送量が減って気持ち節約になります ビュー ワープロ トコルポリシー Redirect HTTP to HTTPS にしておくのが無難ですかね 許可されたHTTPメソッド サイトに合わせて設定してください 静的サイト…GET,HEAD 動的サイト…GET,HEAD,OPTIONS,PUT,POST,PATCH,DELETE 今回は WordPress なのでこっち キャッシュキーとオリジンリク エス ト 基本的に触らないくていい 設定 エッジサーバについての設定を行う項目です。 料金クラス すべてのエッジロケーションを使用する AWS WAF ウェブ ACL アクセス制限やWAFをいれたい場合はここで設定を追加 ※ もちろん AWS 側でルールを作る必要あり 代替 ドメイン アクセスさせたい ドメイン 名を記載(複数記載OK) CloudFrontを使う準備に記載した ドメイン を入力してもらえればOK 例) www.rakus.co.jp, rakus.co.jp など カスタム SSL証明書 ACM で取得した証明書をプルダウンから選択 標準ログ記録 必要な場合はオンにして、ログを保存するS3 バケット を設定 IPv6 対応していなければオフに 以上でCloudFrontの初期設定は完了です。 最期に「 ディストリビューション の作成」をクリックしましょう。 6. CloudFrontで WordPress を配信する さて、 ディストリビューション の作成が完了したので続いては WordPress 特有の設定を入れていきましょう。 オリジンサーバに WordPress をインストール ELBの設定 今回の投稿では上記については割愛させてもらいます。 <m(__)m> 「 WordPress インストール」というような記事でググって入れてください <m(__)m> 最低限、CloudFrontで WordPress を配信するだけなのであればここまでの設定で配信可能です。(多分。) が、このままでは WordPress の管理画面にアクセスできず、 記事の更新 WordPress のアップデート プラグイン のインストール などなどが管理画面上から行えないため、辛いです。 そのため、 WordPress 管理画面へのアクセスができるようにキャッシュをコン トロール しなければいけません。 その設定を入れていきます。 作成した ディストリビューション を編集するために設定画面に遷移します。 ビヘイビア > ビヘイビアを作成 をクリック パスパターン パスパターンを指定して、指定したパスにアクセスが来たときのキャッシュの挙動を設定 キャッシュしてはいけないパスパターン /wp-admin/* ( WordPress をインストールしたパスに合わせてください。) *. php * preview * オリジンとオリジングループ ディストリビューション 名が出てくるので作成した ディストリビューション の名前に合わせてください ビューワー デフォルトのキャッシュビヘイビアで設定した物と同じ設定を入れる キャッシュキーとオリジンリク エス ト Legacy chache settings ヘッダー:すべて (キャッシュしないように設定) 上記の設定でキャッシュしてはいけないパスパターンを作成してください。 - キャッシュしてはいけないパスパターン - /wp-admin/* (WordPressをインストールしたパスに合わせてください。) - *.php - \*preview\* デフォルトのビヘイビアの編集 デフォルトのビヘイビアを編集する前にキャッシュポリシー、オリジンリク エス トポリシーを作成します。 デフォルトのビヘイビアに作成したキャッシュポリシー、オリジンリク エス トポリシーをアタッチするイメージです。 ■ キャッシュポリシー まずはキャッシュポリシーを作成します。 CloudFrontトップ画面 > ポリシー > キャッシュ > キャッシュポリシーを作成 名前 わかりやすい名前なら何でも。 別の ディストリビューション にもアタッチできるので汎用的なキャッシュポリシー名にするのも良き 説明 適当に説明文を入れる キャッシュキーの設定 ヘッダー Host, CloudFront-Forwarded-Proto を入れてください Host:ALBが振り分けられなくなります CloudFront-Forwarded-Proto:EC2が80番しか開けていない場合これがないと表示崩れます 設定できたら作成をクリックして、キャッシュポリシーを作成します。 ■ オリジンリク エス トポリシー 続いて、オリジンリク エス トポリシーの作成をやっていきます。 CloudFrontトップ画面 > ポリシー > オリジンリク エス ト > オリジンリク エス トポリシーを作成 名前 キャッシュポリシーと一緒 説明 キャッシュポリシーと一緒 オリジンリク エス トの設定 ヘッダー キャッシュポリシーと一緒 クエリ文字列 * preview * cookie comment_author_* wordpress _test_ cookie wordpress _logged_in_* wp-settings-* 設定できたら作成をクリックして、オリジンリク エス トポリシーを作成します。 ここまでできたら、デフォルトのビヘイビアを編集していきます。 ■ デフォルトのビヘイビア さて、キャッシュポリシーとオリジンリク エス トポリシーが出来たので、デフォルトのビヘイビアの編集をしていきます。 CloudFrontトップ画面 > ディストリビューション > 作成した ディストリビューション > ビヘイビア > デフォルト > 編集 キャッシュキーとオリジンリク エス ト キャッシュポリシー さっき作ったキャッシュポリシーを選択 オリジンリク エス トポリシー さっき作ったオリジンリク エス トポリシーを選択 編集箇所はここだけです。 変更を保存しましょう。 さて設定もできたので、CloudFront経由でアクセスしてみましょう。 できた!! 7. CloudFrontで WordPress を配信するときの注意点 CloudFrontで WordPress を配信することができるようになりました。 私が初めてこの作業をやったときにハマったポイントを、いくつか記載しておきます。 LB配下に WordPress をインストールしたときはwp-config. php に とある記述 が必要 管理画面にアクセスできなかった… キャッシュの設定はご注意を 記事を更新するたびにCloudFrontのキャッシュをクリアしないといけない Wodpressに プラグイン があるのでそいつを使うと便利 テーマはなどの更新は多分検知されない… というところでしょうか。 おまけ アクセス制限 CloudFrontでアクセス制限を掛けたいときってありますよね?(例えば検証機とか。) 接続元がCloudFrontの IPアドレス になっていた、ELBのIPになっていたりとサーバ側で制限をかけるのが結構めんどくさいです。 そんな時に役立つのが AWS WAF, CloudFront Functions です! IP制限したいな~と思ったら下記を試してみてください<m(__)m> AWS WAF CloudFront Functions また、CloudFront以外からのアクセスを遮断したい!みたいなこともあるかと思います。 悪い人がhostsファイルなどでサーバに直接アクセスできるようにしてくるかもしれません。 そんな時は一つの方法として、CloudFrontが付与したカスタムヘッダーをLBが判定する方法が手っ取り早くて楽だと思います。 しかし、最近だともう少し楽にできる方法もあるみたいです。 お時間あれば調べてみてください。 8. まとめ 長い記事を呼んでいただき、ありがとうございました。 CloudFrontを使うと運用がめんどくさくなることもありますが、サイト自体が軽量化でき、 SEO 対策にもなります。 以前、 WordPress で作った弊社オンデマンドサイトはアクセス集中が起きると必ず落ちていましたが、CloudFront経由で配信するようにしてからは(多分)1度も落ちていません。 アクセス集中で困っている! すぐ高負荷になって困っている! という方は、一度CloudFrontや他の CDN の構成を検討してみてもいいかもしれないです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
技術広報の yayawowo です。 いつも ラク スのエンジニアブログをお読みいただき、ありがとうございます! 今年度3回目となる ラク スMeetupは、 『 開発速度向上のためのリファクタリング術 〜負債をきっちり返済しよう〜 』 でした! テーマは『技術的負債・生産性向上』です。 ローンチ5年〜20年を迎える3プロダクトを支える、弊社のバックエンドエンジニアの3名が登壇しました! なお、本イベントは以下のような方にオススメとなっております。 ◆ こんな方にオススメ! ・ ラク スのプロダクト、組織に興味がある方 ・長期プロダクトの リファクタリング を検討している方 ・UI刷新、オフショア開発に興味がある方 ・ SaaS 開発に携わるエンジニアの話が聞いてみたい方 発表の紹介 サポートチャットサービスをローンチしてから5年間で発生した負債と対策 レガシーなシステムのリファクタリングに取り組んで学んだこと 20年以上のレガシーシステムで始めるリファクタリングの半歩 秋開催!おすすめ技術イベント ラクスのエンジニア/デザイナーと話をしてみたい方へ 終わりに 発表の紹介 それではここから各発表内容と資料を共有させていただきます! イベントの詳細は以下をご確認ください。 rakus.connpass.com サポートチャットサービスをローンチしてから5年間で発生した負債と対策 登壇:酒井 幸教 [所属:チャットディーラー開発課/担当プロダクト: ChatDealer ] speakerdeck.com 1本目は、チャットディーラー開発課の酒井さんによる発表です。 システム開発 を行う中で、様々な条件によって技術的負債は生み出されてしまいます。 サポートチャットボットを提供するサービス『ChatDealer』はローンチされてから5年目であり、 ラク スでは新しめのサービスです。 しかし、開発を進める中で様々な技術的負債が生じております。 本発表では、以下ポイントを中心にお話させていただきました。 『ChatDealer』で技術的負債が生じた経緯 技術的負債の解消に向けた対策 レガシーなシステムの リファクタリング に取り組んで学んだこと 登壇:ファム ブイテー ニャン [所属:配配メール開発課/担当プロダクト: 配配メール ] speakerdeck.com 続いて、配配メール開発課にてブリッジSEを担当しているニャンさんの発表です。 レガシーなシステムでは、古いコードの書き方、保守性・可読性が悪い書き方などがよくあると思います。 リファクタリング はこのようなシステムで生産性を向上するための一つの手段です。 私は約15年稼働しているメール配信システムのブリッジエンジニアとして、オフショアチームと一緒に リファクタリング を実施してきました。 リファクタリング の経験で良かったことと苦労したこと、そこから学んだ リファクタリング する時に注意することをご紹介しました。 なぜ リファクタリング を実施しないといけないのか リファクタリング で良かったことと苦労したこと リファクタリング する時に注意すること 20年以上の レガシーシステム で始める リファクタリング の半歩 登壇:四方 大輔 [所属:メールディーラー開発課/担当プロダクト: MailDealer ] speakerdeck.com ラストは、メールディーラー開発課の四方さんが発表しました! 20年以上サービスが続くメールディーラー。 そんな社内最長老であるサービスに突如言い渡されたUI刷新プロジェクト。 流行りのUIにしたい?新しい フレームワーク を使う!? フロンドエンドとバックエンドは密結合!!? こんなシステムどうやってUI刷新するの??本当に安全にリリースできるの??? 私たちがメールディーラーUI刷新プロジェクトを通して得た、 " レガシーシステム でもできる"安全な リファクタリング の始め方についてお話しました。 秋開催!おすすめ技術イベント ラク スでは、定期的にエンジニア/デザイナー向けの技術イベントを開催しております。 その中から9月~10月に開催する、技術イベントをご案内いたします。 ◆ LT会 9/21(水)開催: エンジニアの勉強法ハックLT- vol.10 9/22(木)開催: エンジニアのためのDX 10/12(水)開催: コードレビュー LT会 - vol.3 10/19(水)開催: プロジェクトマネジメント Tips LT会 vol.5 10/20(木)開催: QA Tips LT会 - vol.2 10/26(水)開催: UI/UXデザイナーLT会 - vol.9 10/27(木)開催: Reactをもっと語りたい! ◆ TechCafe 9/27(火)開催: PHPerのための「PHPカンファレンス2022」を語り合うPHP TechCafe 9/28(水)開催: 「k8s」を語るCloud Native TechCafe #2(ゲスト:bells17様) ◆ Meetup 10/5(水)開催: アーキテクチャカイゼンで課題解決に挑む、エンジニア達 1つでもご興味があるものがございましたら、お気軽にご参加ください! 採用イベントも開催中!こちらも合わせてご確認ください。 ・9/26(月)開催: SREチームの仕事紹介/カジュアル説明会 ラク スのエンジニア/デザイナーと話をしてみたい方へ 当社では、一緒に働くエンジニア/デザイナーを積極的に募集しております! 現在募集している職種は、以下サイトよりご確認ください。 career-recruit.rakus.co.jp 「まだ応募する段階では…」 という方は、是非 カジュアル面談 もご検討ください! 【こんな方におすすめ】 ポジションが経験にマッチするか確認したい 働き方/環境・体制/事業・プロダクト/文化/制度を詳しく知りたい 応募前に選考の概要を聞きたい(人物像、基準など) エンジニア・デザイナーの人となりを知りたい 以下申込フォームとなります。 rakus.hubspotpagebuilder.com 「イベントで登壇していた●●さんと話してみたい・・・」 などご要望がありましたらその旨をご記入の上、お申込みください! お気軽にどうぞ 😊 終わりに 『開発速度向上のための リファクタリング 術 〜負債をきっちり返済しよう〜』はいかがでしたでしょうか? ローンチ5年〜20年を迎える3プロダクトを支える、最前線エンジニアによる技術取り組みを発表させていただきました。 本発表が SaaS 開発に携わるエンジニア/デザイナーの皆様にとって、一つでもご参考になれば幸いです。 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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です。 業務でよく使う機会がある(私はよくある)diffコマンドですが、調べてみると知らなかったオプションがたくさん… ※ diff ${file1} ${file2} の通り、簡単に 使えるが故に 今までちゃんと調べたことはありませんでした。 今回は、そんなdiffコマンドの表示オプションを中心に紹介できればと思いますので、よろしければご覧ください。 diffコマンドとは よく使うオプション diffコマンドのオプションで変わる表示形式 -uオプション:unified形式 -cオプション:context形式 -yオプション:side by side形式 --suppress-common-lines(共通行非表示)と組み合わせる -W(表示幅指定)と組み合わせる --colorオプション:色表示(番外編) 最後に 参考文献   diffコマンドとは diffコマンドは、 2つのファイルを比較して違い(差分)を出力するコマンド です。 またリダイレクトを使えば、コマンド実行結果などの文字列比較も行うことができます。 以下、例 ###ファイル比較(基本) $ diff file1.txt file2.txt 1c1 < test --- > tests ###リダイレクトしたコマンド実行結果(文字列)を比較 $ diff < ( echo ' test ' ) < ( echo ' tests ' ) 1c1 < test --- > tests よく使うオプション diffコマンドで よく使うオプション のご紹介です。 私は今回調べるまで、patchファイルを作るときに -u を使ったりするくらいでしたが、便利なオプションがたくさんありました。 オプション 説明 -c context形式で差分を表示 ! (変更点)や + (追加), - (削除)で表示される -u unified形式で差分を表示 変更点は + , - で表示される -y --side-by-side 横並びで差分を表示 | (変更点)や < (削除), > (追加)で表示される -q --brief 差分があれば、差分がある旨メッセージを出力 ※差分は出ない ※差分がなければ出力もなし -s 差分があれば、差分を出力 無ければ、差分がない旨メッセージを出力 -b 空白の差分は無視 -i --ignore-case 大文字小文字の区別をしない --suppress-common-lines 共通行を表示しない ※-yオプションと併用で効果あり -W --width=${NUM} 表示幅を指定する ※-yオプションと併用で効果あり (デフォルト: 130カラム) --color 色付きで差分表示する ※diffutils3.4以上で有効 diffコマンドのオプションで変わる表示形式 よく使うdiffコマンドのオプションの違いでどのように表示形式が変わるのか、いくつか実際にご紹介したいと思います。 比較するファイルは下のものを使用します。 test1.txt ファイルに手を加え test2.txt を作成しましたので、 それぞれ説明の際は、 test1.txt を 変更前 、 test2.txt を 変更後 とさせていただきます。 # cat test1.txt あいうえお かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも やゆよ らりるれろ わをん アイウエオ # cat test2.txt あいうゑお かきくケこ さしすせそ たちつてと ららららら なにぬねの はひふへほ まみむめも やゆよよよ らりるれろ わをん ちなみに、オプションなしでdiffコマンドを使って比較するとこんな出力となります。 この文量なら何とかなりますが、差分がもっと増えると、正直何が何だか分かりにくい… # diff test1.txt test2.txt 1 ,2c1, 2 < あいうえお < かきくけこ --- > あいうゑお > かきくケこ 4a5 > ららららら 8c9 < やゆよ --- > やゆよよよ 11d11 < アイウエオ # -uオプション:unified形式 まずは、unified形式です。 --- の部分は変更前のファイルを、 +++ は変更後のファイルを表しており、 変更後に存在しない行は - 変更後にのみ存在する行は + が行頭についてます。 こちらのオプションは見やすさで選ぶというよりも、patchを当てたりするため、使うことが多い気がします。 # diff -u test1.txt test2.txt --- test1.txt 2022-08-22 18:23:54. 717925300 + 0900 +++ test2.txt 2022-08-23 09:18:48. 147925300 + 0900 @@ -1 , 11 + 1 , 11 @@ -あいうえお -かきくけこ +あいうゑお +かきくケこ さしすせそ たちつてと +ららららら なにぬねの はひふへほ まみむめも -やゆよ +やゆよよよ らりるれろ わをん -アイウエオ # -cオプション:context形式 次に、context形式です。 *** の部分は変更前のファイルを、 --- は変更後のファイルを表しており、 変更のあった行は ! 変更後に存在しない行は - 変更後にのみ存在する行は + 行頭についています。 こちらのオプションも、一目で見てわかるという感じではありませんね。 # diff -c test1.txt test2.txt *** test1.txt 2022-08-22 18:23:54. 717925300 + 0900 --- test2.txt 2022-08-23 09:18:48. 147925300 + 0900 *************** *** 1 , 11 **** ! あいうえお ! かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも ! やゆよ らりるれろ わをん - アイウエオ --- 1 , 11 ---- ! あいうゑお ! かきくケこ さしすせそ たちつてと + ららららら なにぬねの はひふへほ まみむめも ! やゆよよよ らりるれろ わをん # -yオプション:side by side形式 次に、side by side(横並び)形式です。 非常に見やすい(直感的にわかりやすい)表示となっており、すべての比較で使いやすいとまでは言いませんが 私が一番頻繁に使用するdiffコマンドのオプションになります。(オススメ!) 左側に変更前・右側に変更後のファイルが表示されており、変更行があれば真ん中に記号がつきます。 変更のあった行は | 変更後に存在しない行は < 変更後にのみ存在する行は > が表示されます。 以下の様に、直感的にわかりやすい表示となっております。 (ご覧の端末の幅によってはコマンド結果がきれいに表示できていないかもしれませんが、ご了承ください) # diff -y test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ さしすせそ さしすせそ たちつてと たちつてと > ららららら なにぬねの なにぬねの はひふへほ はひふへほ まみむめも まみむめも やゆよ | やゆよよよ らりるれろ らりるれろ わをん わをん アイウエオ < # -y オプションを知らなかった時は、 diffコマンドが見づらいのでリモートサーバからわざわざローカルPCに比較ファイル持ってきて WinMerge を 使っていました。 -y オプションにはさらに見やすくなるオプションもありますので、以下にてご紹介させていただきます。 --suppress-common-lines(共通行非表示)と組み合わせる diff -y コマンドに --suppress-common-lines オプションを加えると、差異のある行のみを表示してくれます。 通常共通行も表示され、それはそれで便利なこともあるのですが、 --suppress-common-lines オプションを使うことで 簡潔に表示させることができます。 # diff -y --suppress-common-lines test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ > ららららら やゆよ | やゆよよよ アイウエオ < # -W(表示幅指定)と組み合わせる 例で使っているような各行の文字数が少ない場合、または多い場合 diff -y だけでは少し見づらいこともあります。 そんな時には -W ${カラム数} (デフォルト:130カラム)オプションをつけることで表示幅を変更することもできます。 今回比較に使用しているファイルは各行の文字数が少ないので、30カラムを指定してみます。 # diff -y -W 30 test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ さしすせそ さしすせそ たちつてと たちつてと > ららららら なにぬねの なにぬねの はひふへほ はひふへほ まみむめも まみむめも やゆよ | やゆよよよ らりるれろ らりるれろ わをん わをん アイウエオ < # これでかなり見やすくなりました。 さらに、1つ前に紹介した --suppress-common-lines を組み合わせると、差異のある行のみをさらに見やすく表示できます。 # diff -y -W 30 --suppress-common-lines test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ > ららららら やゆよ | やゆよよよ アイウエオ < # ちなみに、1行当たりの文字数が多いと、途中で切れてしまうので -W 170 など広めに設定すれば見やすくなります。 (ご覧の端末の幅によってはコマンド結果がきれいに表示できていないかもしれませんが、ご了承ください) ###デフォルトの130だと最後まで見れない # diff -y file1.txt file2.txt 1234567891011121314151617181920212222324252627282930313233343 | 1234567891011121314151617181920212222324252627282930313233343 ###幅を170にするとファイルの端の文字まで確認できる # diff -y -W 170 file1.txt file2.txt 123456789101112131415161718192021222232425262728293031323334353637383940 | 123456789101112131415161718192021222232425262728293031323334353637383950 # --colorオプション:色表示(番外編) こちらはdiffコマンドのオプション番外編となりますが、 diffutils のバージョン3.4以降で使用できる色表示オプションになります。 CentOS7の公式 リポジトリ で提供されている diffutils は3.3系が最新でしたので使えませんが、CentOS8系からは使用できるかと思います。 こんな感じで、diffを色表示できるので視覚的に見やすいです。 ※epel リポジトリ にて、 colordiff というパッケージも配布されているようですので、 --color オプションが使えない方は、 インストールしてみてください。 diff --color実行結果 最後に 今回は、diffコマンドの表示形式を見やすく、ファイル比較を楽にするためのオプションについて紹介しました。 記事内にも記載しておりますが、diffコマンドについて詳しく調べるまでは、業務でリモートサーバ上のファイルを比較するとなると毎回ローカルPC上に持ってきて WinMerge を使っておりました。 特に -y のオプションは WinMerge に似た出力となり直感的に変更点がわかりやすいということから、今や -y オプションに頼りきりです。笑 diffコマンドを使いこなして、 “楽” にファイル比較をしましょう。 というわけで、diffコマンドのオプション紹介でした。 参考文献 DIFF GNU diff utilities - News: diffutils-3.4 released [stable]     エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
特集「 Xdebug の活用方法」を語る 弊社で毎月開催し、 PHP エンジニアの間で好評いただいている PHP TechCafe。 2022年2月のイベントでは 「 Xdebug の活用方法」 について語り合いました。 弊社のメンバーが事前にまとめてきた Xdebug の基礎知識や使い方の説明資料にしたがって、他の参加者に意見を頂いて語り合いながら Xdebug の活用方法を学びました。 今回はその内容についてレポートします! rakus.connpass.com 特集「Xdebugの活用方法」を語る デバッグツールについて Xdebugとは 導入方法 公式のインストール手順 Xdebugの便利な機能 Step Debugging ステップデバッグとは デバッグ方法 (PhpStorm) 1. 受信デバッグ接続のリッスンを有効にする 2. ブレークポイントをセット 3. デバッグセッションの開始 ステップデバッグでできること デバッグセッション再開 ステップオーバ (F8) ステップイン (F7) ステップアウト (F8) 強制ステップイン 停止している処理での調査 フレーム調査 変数の調査 / 更新 式の評価 その他テクニック 停止している行を表示 ウォッチリストに変数を追加 ブレークポイントのミュートモード その他の機能 1. エラーレポート 詳細 php.ini var_dump()の強化 2.スタックトレースの追加 3.トレーシング トレースとは 4. プロファイリング 機能の概要 使い方 5.Code Coverage Analysis 機能の概要 使い方 カバレッジ 編集後記 デバッグ ツールについて デバッグ ツールとはバグを除去するときに使用するツールです。 ※ デバッグ (debug) は de(除去) - bug(不具合)という意味です。 多くの デバッグ ツールは以下の基本性能を備えています。 ブレイクポイント 実行中のプログラムを任意の箇所で一時停止する ステップ実行 ソースコード を1ステップずつ実行する 変数の可視化・変更 実行中のプログラムの変数の値を確認したり変更する 関数・式の実行 デバッグ 中に任意の関数や式を実行する デバッグ ツールがないとバグ修正が大変になるケースとして、以下が挙げられました。 大量に デバッグ ログを仕込むことになる 処理を通すことが難しい部分を デバッグ する時 同時実行など再現が難しい場合 デバッグ 用に入れた処理が本番に残ってしまって大災害を引き起こす その他、var_dumpなどで手軽にコードの動きを見たい場合はそちらを活用するなど、 「ツールとコードの両者を柔軟に使えると良い」という意見もありました。 Xdebug とは PHP で デバッグ を行う上で便利な機能を提供する、 拡張機能 です。 PHP においては、 デバッグ ツールの デファクト ツールになっているものです。 多機能で、基本的な デバッグ ツールとしての機能だけでなく、様々な機能を持っています。 デバッグ の機能が使われることが多いですが、他にも様々な便利機能があり順に紹介されました。 導入方法 Xdebug は C言語 で実装されており、 コンパイル されたファイル .soファイル を組み込む( php .iniに読み込み設定を追記)ことで有効になります。 導入手順は公式のものを使用する方法と、Dockerを使用する方法の2つが紹介されました。 公式のインストール手順 Linux : 公式リポジトリ こちらの方法ではメリットとして最も手軽であることが挙げられましたが、デメリットとして最新バージョンが入らないこともあるようでした。 Xdebug の最新バージョンはv3系ですが、Ubuntu20.04ではv2系が入ってしまうため、注意が必要です。 PECL(ピクル) ※ PECL : PHP の 拡張機能 やライブラリなどを追加するためのパッケージ管理ツール php .iniへの設定も自動で行ってくれるため、 Mac ユーザーにとっては便利だという紹介がありました。 ソースをコンパイル こちらの方法が必要なケースとしては 特定のバージョンが必要 ネットワーク、セキュリティの関係上パッケージ管理ツールが使用できない といったことが挙げられました。 また、「手順が難しいわけではないが、コマンドを検索しソースから コンパイル される場合に、 実際に何が行われているかということを理解してから行う方がよい のではないか?」という意見もありました。 Dockerで使う 公式イメージの説明 Dockerfileの例 FROM php:8.1-cli RUN pecl install xdebug \ && docker-php-ext-enable xdebug docker-php-ext-enable を記述すると、コンテナ上の PHP で Xdebug が有効化されます。 自身のプロジェクトの状況や環境に合わせて、様々な方法が選択できる点が非常に良いと思いました! また、 デバッグ の際に デバッグ ツールを使用するかどうかのアンケートの結果、ツールを使用しない方が多数派だったようです。 その結果を受けて、 Xdebug やdumpを利用することのメリット/デメリットが解説されました。 Xdebug のデメリットとしては動作が重い点が挙げられ、 php .iniで設定を消すなどして軽量化を図ったという経験が語られていました。 dumpのデメリットとしては、消し忘れが事故につながる点が挙げられ、できるだけログに出力するようにしているという方法が語られました。 他にも 新卒で入ったときに先輩から 「ウェブブラウザの画面には出すな事故るから」 って言われましたね。 「何かAAAって出てきたんだけど」って。そんな報告聞きたくない!冷や汗すごいと思う。 「var_dumpで事足りるじゃん」って宗教になってしまいました。「いやそれはないから目を覚ませ」って言った記憶があります。 などの体験が語られていました。 最後に Xdebug を簡単に入れられない古いサービスとかだとやむなし Xdebug が使える人はどんどん使っていくほうが良い という結論に至りました。 Xdebug の便利な機能 Step Debugging Xdebug の機能について、PhpStormの画面を使って紹介されました。 ステップ デバッグ とは 任意の行で処理を止めながら行う、 デバッグ のことです。 デバッグ 方法 (PhpStorm) 1. 受信 デバッグ 接続のリッスンを有効にする 2. ブレークポイント をセット 3. デバッグ セッションの開始 対象のページをリロードすると、 ブレークポイント で処理が止まります。 ステップ デバッグ でできること デバッグ セッション再開 次の ブレークポイント へ進む 次に通った ブレークポイント にて再度処理が止まる ステップオーバ (F8) 次の行へ処理を進める 進める行のメソッドがある場合、メソッド内の処理はスキップされる メソッド内に ブレークポイント がある場合は、そこで止まる "強制ステップオーバ" を使うことで、スキップもできる ステップイン (F7) メソッド内の処理を調べたい時に利用 止まっている行にあるメソッド内の処理に入って先頭処理で止まる ステップアウト (F8) 調査中のメソッド内に問題がないことがわかった時に利用 現在のメソッドから抜けだして、呼び出し元の処理で止まる 強制ステップイン ステップインでは サードパーティ のライブラリなどのメソッドへ入ることができない 強制ステップインでは、これらのメソッド内の処理へ入ることができる このあたりの機能を見るだけでも、var_dumpで デバッグ するよりも色々なことができることが分かります。 ここで紹介された機能について、 「基本的にはこのステップアウトぐらいまでは割とどういう IDE でもありますかね。」 「強制ステップインはPhpStormにユニークな機能として実装されていますね。」 「正直強制ステップインはあまり使わずに何とかなっていたので、意図して使い分けたりとかはしてなかったですね。」 といった経験が語られました。 停止している処理での調査 よくコードを追っていると行を見失うことがありますが、「停止している行を表示」するアイコンを押すと止まっている行に移動してくれます。 それらの機能について紹介されました。 フレーム調査 どこから呼び出された処理かを確認できます。 変数の調査 / 更新 現在の変数に格納された値の確認 値の編集も可能 式の評価 選択した部分の式評価 アイコンから任意の式での評価結果確認も可能 こちらの機能については Xdebug で止めながら、途中に適当な評価式を書いて変数の中身を見る必要がなく、直接確認できるというメリットが紹介されました。 その他テクニック その他、いくつか紹介された機能を挙げておきます。 停止している行を表示 デバック時に停止している行を見失った時に使用 ウォッチリストに変数を追加 変数を監視リストとして登録可能 ブレークポイント のミュートモード ONにして以降の ブレークポイント で処理を止めなくなる Xdebug で最も使用される、ステップ デバッグ についての紹介は以上でした。 その他の機能 続いて、その他便利機能が5つ紹介されました。 まずはエラーレポートを向上させてくれる機能の紹介です。 こちらは大きく分けてvar_dumpの強化、 スタックトレース 追加の2つがあります。 1. エラーレポート 詳細 まずは、 php .iniの xdebug .modeをdevelopにする必要があります。 php .ini xdebug.mode=develop var_dump()の強化 var_dumpの出力を成形したり、装飾するためにHTMLエラーを有効にする必要があります。 html_errors=1 補足情報として、 php.ini の html_errors 設定が有効のときしかキレイにならないという注意点が挙げられました。 公式リファレンス こちらのサンプルとしては、arrayに色々な値を入れてvar_dumpで出力しています。 var_dump()の強化 サンプルコード <?php $ sampleArray = [ 1 , // int 0.1 , // float true , // bool "string" , // string [ "nest1" , [ "nest2" , [ "nest3" ]]] // array ] ; var_dump ( $ sampleArray ) ; こちらの出力結果をブラウザ上で表示すると、以下の結果になります。 developモードがOFFのとき developモードがONのとき この結果を受けて、developモードをONにしたときのメリットとして以下の点が挙げられました。 改行などを成形、intが緑でFloatがオレンジといったように色がつき、見やすくすっきりする ネストしている配列に、3つ目以降が省略されて表示される なお、ネストについては xdebug.var_display_max_depth を設定することで表示する階層を制御できます。 その他、 コマンドライン 上でも色を付ける方法が紹介されました。 こちらは xdebug.cli_color を設定することで表示される、var_dump()の結果に色を付けることができます。 参加者からも「var_dumpはプレタグで図った記憶がありますね」というコメントが挙がりました。 これをきっかけに 「この Xdebug できれいになっているのも、 HTMLのプレタグを付けてくれている っていうのがありますね。HTML化して共有してくれていると。」 「 Xdebug 入れずにvar_dumpしたらページのソースを見ると改行されているのが分かるって感じになりますね。ブラウザ上だとbrとかあるけど……」 「それでプレタグで囲ったらってことですね。」 「printlnなんかも使えますね。その辺り使ってわかりやすくできます。」 という話題で盛り上がりました。 2. スタックトレース の追加 エラーが起こった際、developモードをONにすると綺麗に出力してくれます。 developモードがOFFのとき developモードがONのとき ここでは注意点として 「 Xdebug ありでvar_dumpに吐き出すと、HTMLありで見にくくなる」 「var_dumpの結果をログに吐き出すときは developモードをoffにしたほうが良い 」 ということも紹介されました。 3.トレーシング トレースとは 関数がどういう経路で出力されているかを確認したり、関数の戻り値を確認することで、システムの全体像を把握することです。 Xdebug を使用することで関数呼び出しの履歴を出力できるため、以下のメリットが挙げられました。 関数がどのような経路で呼ばれているか、全体像を把握できる 引数、戻り値も確認できる また、 xdebug .mode=traceに設定するとトレーシングがオンになると紹介がありました。 php .ini(設定例) xdebug.mode=trace xdebug.trace_format=0 xdebug.output_dir=/tmp/tracing xdebug.start_with_request=no 続いてサンプルコードを使用し、実際に出力を確認しました。 サンプルコード <?php class SampleClass { public function a () { $ this -> b () ; } private function b () { var_dump ( "tracing" ) ; } } $ sampleClass = new SampleClass () ; xdebug_start_trace () ; $ sampleClass -> a () ; xdebug_stop_trace () ; $ sampleClass -> a () ; 実行結果 trace.1373756769.xtというファイルが出力されました。 Time列が実行時間、Mem列が使用しているメモリです。 Function列が呼び出している関数と場所を表しています。 また、矢印(->)でネストの深さも表しています。 この結果について参加者から 「traceの実行時間まで出るのすごいですね。」 というコメントがあり、それをきっかけに 「 ボトルネック を調べられるの便利 ですよね。DBのI/Oのアクセスとかなら SQL いじるとかありますし。」 「遅そうなところにこういうのを仕込んで、 PHP の処理は遅くないけど内部実行のDBアクセスに時間かかってるなあって 原因の切り分けがしやすそう ですね。」 というメリットが会話で挙げられました。 また、以下の補足情報も紹介されました。 xdebug.collect_assignments 関数に渡された引数の値を出力できる xdebug.collect_return 関数の戻り値の値を出力できる xdebug.trace_format で出力フォーマットを選択できる 1(コンピューター可読形式):実行結果 これについては、 「公式が分析用の スクリプト を準備してくれている」 「 GitHub の中に載っているんですがこの スクリプト に食わせて実行すると結構分析してくれます。 自分で分析用のプログラムとか組んでアレンジ することも出来るかもしれません。」 「人間には読めない形で出るのかと思ってました。関数ごとの呼び出しされた回数とかが出てきましたね。」 「一回データとして取り込んでしまえばこっちのものですからね。」 といった便利な活用方法が紹介されていました。 2(HTML):実行結果 この結果については、「人にやさしい」という意見が出ていました。 その他にも設定が多数あり、「結構いろいろできるんだな」という Xdebug の多機能さに感心する声もありました。 4. プロファイリング 機能の概要 処理の監視や記録を行う機能です。 処理に時間がかかっている箇所や、リソース消費の激しい箇所を特定することができます。 使い方 こちらもiniファイルに設定が必要です。 php .ini 設定 profile の設定を有効化 xdebug.mode=profile profile の出力先 xdebug.output_dir=/tmp/profiling これらを設定し PHP のプログラム実行すると、 xdebug.output_dir で指定した ディレクト リにファイルが出力されます。 出力されたファイルは人間には分かりにくいので実行結果を可視化するツールが公式で紹介されており、 Webgrind が個人的に使いやすいと紹介がありました。 この機能の活用シーンとしては パフォーマンスが悪い処理の ボトルネック 特定 意図しない箇所で例外処理されてしまって原因特定が困難な時 「実行したけれどどこで落ちたかわからない」ときにこれを実行すれば「ここで止まったな」というのがプロファイリングの結果からわかる といった紹介がありました。 また、参加者から 「PhpStormで開くと定義した場所にそのままコードジャンプ出来るので楽しいです」 というコメントがあり、これについて 処理が重なっているところを押したら、該当のコードへジャンプ出来るということです。 便利ですね! さすがPhpStorm! など、PhpStormへのポジティブな声が挙がりました。 他にも注意事項として、 現状の php .ini 設定の場合は、すべてのリク エス トが profiling されてしまう 処理が重い スクリプト を気にせず実行しまくっていると、プロファイルの実行結果だけでディスク容量をかなり食ってしまうことになる string xdebug.start_with_request を trigger に設定することで profiling を開始したいタイミングを指定できるため、不用意に実行されないようにしたほうが良いと思う といった点が挙げられました。 5.Code Coverage Analysis 機能の概要 処理を通過した箇所を記録することができます。 単体テスト などで、そのプログラムがどの程度テストできているかを把握できます。 使い方 基本的には PHPUnit と組み合わせるのが一般的です。 PHPUnit のコードカバレッジ も内部で Xdebug のコード カバレッジ を利用しています。 php .ini の設定はおそらく不要です ソースコード 上で カバレッジ を取得したい箇所を xdebug_start_code_coverage() と xdebug_stop_code_coverage() で挟むだけ xdebug_get_code_coverage() を実行することで上記で挟んだ箇所の カバレッジ を取得できます。 ここでは公式のサンプルコードを用いて話題が進みました。 Xdebug 公式サイト functionAとBが存在し、Bに6と10を与えて結果をもらってくる PHP ファイルがあるとします。 ここにstart_code_coverageを入れてget_code_coverageを実行し、var_dumpに出力させると実行結果が出てきます。 <サンプル > <?php xdebug_start_code_coverage ( XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE ) ; function a ( $ a ) { return ; echo $ a * 2.5 ; } function b ( $ count ) { if ( $ count > 25 ) { echo "too much \n " ; } for ( $ i = 0 ; $ i < $ count ; $ i ++ ) { a ( $ i + 0.17 ) ; } } b ( 6 ) ; b ( 10 ) ; var_dump ( xdebug_get_code_coverage ()) ; <実行結果> array '/home/httpd/html/test/xdebug/docs/xdebug_get_code_coverage.php' => array (size=11) 5 => int 1 6 => int -2 7 => int -2 10 => int 1 11 => int -1 13 => int 1 14 => int 1 16 => int 1 18 => int 1 19 => int 1 21 => int 1 実行結果がキーバリューの形で出力されます。 キー 対象ファイルの行数 値 : カバレッジ 取得結果 1: 実行した -1: 実行していない -2: デッドコードになっている まず 5 => int 1 に着目します。 サンプルコードの5行目 return; はreturnが実行できたので「1」となっています。 6 => int -2 は直前の5行目でreturnしており、その後の処理が絶対に実行されないので「-2」となっています。 11行目 if ($count > 25) は$countが25以上の時に実行されるコードですが、 サンプルコードは6,10しか渡しておらず条件を満たさないため実行されません。 そのため「-1」となっています。 カバレッジ 以前 ラク スエンジニアブログにて、テストコードの書き方をご紹介致しました。 tech-blog.rakus.co.jp その際に使用したコードの カバレッジ を見てみましょう。 DiceClassに対して作られたテストコードがどの程度カバーできているかを表しています。 結果は全て100%となっています。 テストケースとしての精度が高く、 カバレッジ としては問題無いですね。 このように、オールグリーン(100%)になっているかどうかをCode Coverageで確認することができます。 これによるメリットとして、 単体テスト のテストコードがどの程度書けているかを確認できるのはもちろん、「デッドコード」になっている箇所を 早期に見つけることができる 。 中々分岐に入らないケースですね。実際にリリースすると 「全然入っていない分岐があるけど、論理的にデッドコードじゃない?」 みたいなものがわからなかったりします。 そういったところも比較的実行し続ければある程度判断できるんじゃないかなと思います。 現実的じゃないですが本番環境やそれ相当のステージ環境に カバレッジ 処理を組み込んでぐるぐる回すことで「ずっと入っていない」ものを判断できると思います。 カバレッジ で一番知りたいのは PHPUnit がちゃんと通っているかですよね。網羅しているかどうかが一番重要になるパターンだと思うので。 Xdebug が提供しているっていうのが面白い ですね。燃える話です など、 Xdebug の機能の豊富さに改めて関心する声が多数挙がりました。 編集後記 以上、 Xdebug の概要と大まかな機能について取り上げました。 ラク スでも今まで取り上げることが無かった話題でしたので、主催者/参加者ともに盛り上がりを見せていました! 今後も Xdebug の活用方法や、新ニュースに着目していきたいと思います! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
Gitを使用していると「あ!間違ったファイルをインデックスに上げてしまった!」ということ、ありますよね? (わたしはよくあります) 本投稿ではそんな git add の取り消し方法 についてまとめさせていただきます。 Gitを使い始めたばかりの方から、Gitコマンドについて学び直したいという方まで、開発の際に参考にしていただければ幸いです。 弊社テックブログの関連記事として、Gitの入門記事が以下にもございますのでよろしければ合わせてご一読ください。 【超入門】初心者のためのGitとGitHubの使い方 【Git入門】git stashで作業を便利に退避する 【Git入門】git commitを取り消したい、元に戻す方法まとめ 【Git入門】git cloneで既存リポジトリをクローンしよう! 【Git入門】git pullって?fetchとmergeとの使い分けをご紹介 目次 目次 git addとは? git addを取り消したい! git init直後のgit addの取り消し 前回のコミット後のgit addの取り消し git restoreを使用する方法 git resetを使用する方法 まとめ git add とは? まずはコマンド自体のおさらいです。 git add とは、 作業中の ディレクト リで行った修正をインデックスに追加するコマンド のことです。 (作業中 ディレクト リは「ワークツリー」とも呼ばれます) インデックスに追加することで、変更を加えたファイルをコミット対象とすることができます。 git add を取り消したい! 続いて、さっそく本題の git add の取り消し方法についてです。 git add を取り消す際は、「 git init 直後(コミットの無い状態)」と「コミットを打った以降」でコマンドが異なるので、それぞれの方法をご紹介します。 git init 直後の git add の取り消し Gitでバージョン管理をする手始めとして、まずは git init コマンドで対象 リポジトリ をGit管理下に置くための初期化を行います。 下記に、 git init sample.txt ファイルを作成(サンプル用の空ファイル) sample.txt をインデックスに追加 の流れを記載します。 $ git init Initialized empty Git repository in [初期化リポジトリのパス]/.git/ $ touch sample.txt $ git status On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) sample.txt $ git add sample.txt $ git status On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: sample.txt コミットの無い状態で、 sample.txt ファイルをインデックスに追加しました。 この状態から git add を取り消すには、 git rm コマンドを使用します。 $ git rm --cached [ファイル名] git rm コマンドはGit管理下にあるファイルを削除するためのコマンドです。 --cached オプションを使用することで、指定したファイルをインデックスから削除することができます。 (上述の git status 実行後にも (use "git rm --cached <file>..." to unstage) と記載されていますね) この --cached オプションを使用せずに git rm を実行してしまうと、ファイル自体が削除されてしまうので気をつけてください。 下記に実行例を記します。 $ git rm --cached sample.txt rm 'sample.txt' $ git status On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) sample.txt 無事にファイルをインデックスから削除することができました。 -r オプションを使用することで、 ディレクト リを削除対象にすることもできます。 $ git rm --cached -r [ディレクトリ] また、インデックスに追加した全ての修正を取り消す場合は、ファイル名や ディレクト リ名無しでも実行可能です。 $ git rm --cached -r . 前回のコミット後の git add の取り消し 続いて、既にコミットが打たれている場合の取り消し方法をご紹介します。 (こちらの方が使用頻度としては高いと思われます) 現在のローカルブランチの状態を以下とします。 $ git log --oneline 6f099b1 (HEAD -> main) first commit この状態から以下手順でファイルをインデックスに追加します。 sample.txt ファイルを修正(既に該当ファイルに対してコミットが打たれている状態) 修正後の sample.txt をインデックスに追加 $ echo 'modify' > sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add sample.txt $ git status On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: sample.txt コミットが存在する状態で、修正を加えた sample.txt ファイルをインデックスに追加しました。 この状態から git add を取り消すには、 git restore 、もしくは git reset コマンドを使用します。 $ git restore --staged [ファイル名] $ git reset HEAD [ファイル名] git restore を使用する方法 git restore コマンドは特定の時点まで変更を元に戻すコマンドです。 --staged オプションを使用することで、指定したファイルをインデックスから削除することができます。(インデックスの復元) (上述の git status 実行後にも (use "git restore --staged <file>..." to unstage) と記載されています) この --staged オプションを使用せずに git restore を実行した場合、ワークツリー内の変更も失われてしまうので注意してください。 (インデックスにファイルがある場合は問題ありません) 下記に実行例を記します。 $ git restore --staged sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt 無事にインデックスから削除できました。 全ファイルを対象とする場合は下記のように実行してください。 $ git restore --staged . git reset を使用する方法 もう一つの手段として、 git reset コマンドを使用して取り消すことも可能です。 reset コマンドも restore 同様に、特定の時点まで変更を元に戻すコマンドです。 ( restore の方がより新しいコマンドです) 下記に実行例を記します。 $ git reset HEAD sample.txt Unstaged changes after reset: M sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt 無事にインデックスから削除できました。 こちらも先ほどまでと同様に、全ファイルを対象とする場合はファイル名無しで動作します。 $ git reset HEAD また、補足ですが今回使用した git reset は内部のオプションとして --mixed を実行した際と同じ動きとなっています。 (デフォルトで --mixed オプションが動作しています) $ git reset --mixed HEAD [ファイル名] まとめ Git入門ということで、 git add の取り消し方法についてご紹介しました。 Gitは異なるコマンドでもオプションによって同じ動きをするコマンドが多くあるので、ぜひ今回の記事も開発の際の参考にしていただければと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
はじめに Room A PHP で NFC リーダーを実装する 僕が Illuminate を読む理由 テスト環境のインフラ・運用コストを下げたい話〜全部入りEC2を超えていけ 開発体験を爆上げするLaravel Dacapoマイグレーションサポートツールのススメ 実践!ユニットテスト入門 HTTPリクエストの行方 - Laravelがレスポンスを返すまで Laravel FormRequest にアクセサ機能を追加して、リクエストクラスをスッキリさせた 誰でも簡単に始められるBDD(ビーチ駆動開発)のススメ Room B FeatureToggle戦略と運用方法 今あらためて考える ~ PHPに型定義をする理由 ~ 実践PHPStan まとめ はじめに ラク スの配配メールで PHP エンジニアをしている、mrstsgk_rksです。 2022年8月27日(土)に PHPカンファレンス 沖縄が開催されました。 弊社からもエンジニアが参加いたしましたので、そのうち4名が参加したセッションのレポートをご紹介いたします! では、レポートスタート! なお、レポートはRoomAからBの順で開始時間順に記載しています。 Room A PHP で NFC リーダーを実装する report by id:Y-Kanoh speakerdeck.com 個人的に「ハードにつなぐ系は Python ばかりでズルい…」というのは共感です 笑 しかし、だからといって NFC リーダを PHP で扱って ICカード を読み取る発想はありませんでした 笑 発表では FFI というPHP7.4で導入された PHP から C言語 のライブラリを呼び出す仕組みを使って、 NFC リーダーのデータを読み込む方法についてデモを交えて解説いただきました。 FFI の存在は知っていましたが、具体的にどう使うのか想像がついていなかったので「なるほど・・・」と思いながら聴いていました。 Web以外での PHP の活用方法が広がると楽しいですね。 僕が Illuminate を読む理由 report by id:hirobex speakerdeck.com Laravelの本体であるIlluminateの読むメリットや、実例を交えて読み方の解説をしていただきました。 ドキュメントにないような便利メソッドの発掘ができたり、 OSS 貢献ができたりと Illuminateを読むと良いこと尽くしですね! テスト環境のインフラ・運用コストを下げたい話〜全部入りEC2を超えていけ report by id:Jazuma speakerdeck.com 株式会社 NetStat の中榮健二さん(@n_1215)による発表です。 本番環境では AWS の各種マネージドサービスやコンテナを利用する一方で、 社内環境やテスト環境ではインフラコストを抑えるためにEC2 インスタンス 一台に全てのMWをインストールして運用していたようです。 しかし、金銭的コストが抑えられる一方で運用保守コストがかさむ問題が発生しました。 そこで VPS の他、Heroku, GAEなど各種Paas系サービスが検討されました。 セッションでは最終的に選ばれたサービスには言及されませんでしたが、以下のような注意点が紹介されました。 インフラコストには人件費もあるので、金銭的コストだけに目を向けるとよくない DBサーバはコストが高いので、アプリケーションと同居させるのもあり cronや非同期処理も含めるとコストが高くなるので注意 開発体験を爆上げするLaravel Dacapo マイグレーション サポートツールのススメ report by id:Y-Kanoh speakerdeck.com LaravelのMigrationサポートライブラリ Laravel-Dacapo の生みの親であるucan さんの発表です。 不要になった マイグレーション 用ファイルが残る、最新のテーブル構成が読みづらいなどの課題があるLaravelの マイグレーション を、Laravel-Dacapoを使って YAML ファイルでわかりやすくまとめる方法を解説していただいています。 実践! ユニットテスト 入門 report by id:Jazuma speakerdeck.com プログラミングをするパンダさんによる発表です。 テストコードの書き方として、以下のようなテクニックが紹介されました。 テストケースを日本語で書く テストメソッドが何をしているのか説明する arrange / act / assertパターンで書く arranege: 事前条件 act: テスト対象メソッドを実行する assert: 検証観点 いろんなassertionを知る assertSame / assertException / assertContain等 setUp / tearDownで前後の処理をする 重複している処理を共 通化 することが目的 dataProviderでテストケースをまとめる 同じロジックを複数の入力値でテストする場合に使う ただし、早すぎる抽象化には要注意 コードの意図を明確に表現する、重複する処理を共 通化 する、早すぎる抽象化を避ける、等 プロダクトコードのノウハウを活かせる部分も多くありました。 HTTPリク エス トの行方 - Laravelがレスポンスを返すまで report by id:hirobex speakerdeck.com タイトルの通り、リク エス トを受けてからLaravelがレスポンスを返すまでの一連の流れを説明していただきました! HTTPの基本的な仕様から、 PHP がどうやってWebサーバーと連携しているか、DBとの連携はどうやっているか、などの深い内容まで解説していただきました! こういった仕様を理解することで、よりエンジニアとしてステップアップできそうだ、と感じる非常に勉強になるセッションでした! Laravel FormRequest にアクセサ機能を追加して、リク エス トクラスをスッキリさせた report by id:Y-Kanoh docs.google.com とある理由から アンチパターン が複数含まれたリク エス トを自サービス内のRequestクラスで整形することで扱いやすくした事例について紹介されていました。 詳しくは こちらの記事 に記載されているそうです! 誰でも簡単に始められるBDD(ビーチ駆動開発)のススメ report by id:Y-Kanoh speakerdeck.com そりゃ海でPC開いたら画面見えませんよね。 潮が満ちてきて海が迫ってき、最終的には暑さにやられるようです。 沖縄ならではの開発手法(?)ですが、BDDをやるかたは参考になると思います!! (進捗は期待しない方がいいそうです) Room B FeatureToggle戦略と運用方法 report by id:radiocat speakerdeck.com FeatureToggleは「コードを書き換えずにシステムの振る舞いを変更できるようにする開発手法」です。 用途に応じて大きく4つの種類があることが紹介されました。 Release Toggles トランクベース開発ですぐにマージできる 開発途中はフラグOFFにしておくことで本番環境に影響を与えずに開発できる Experiment Toggles A/Bテストや カナリア テストを実現するフラグ 特定のユーザーやグループに対してトグルをON/OFFする Ops Toggles システム動作の運用制御 パフォーマンスの影響などを制御し迅速に切り戻しできる Permissioning Toggles 特定のユーザーのみに機能を開放する 有料課金機能などで使われる 試験的なものではなく長期的に利用される 発表者の現場ではGitによるfeatureブランチで開発をしていましたが、メインブランチとfeatureブランチで取り込みが必要、コンフリクトも発生、リリース時にトラブルがあると切り戻しが発生するなどの課題があってFeature Toggleを導入するに至ったようです。 実際に導入してみると以下のような課題があったことが共有されました。 基本的にif分岐になるのでコード量が多くなる フラグONとOFFの両方の状態を担保しないといけないのでテストケースが増える リリース後に不要なコードを消さないといけない 最後の不要コード削除に関しては、事前に後で消す範囲を決めておいて一括で削除するライブラリを自前で開発されて対策されているようです。 その内容についてPHPerKaigi 2022で発表された資料が公開されています。 PHPコードを消すライブラリを作った - Speaker Deck この対策によってコード削除の手間を削減できて、Feature Toggleで中・大規模の新規開発でもトランクベースの開発を維持できるようになったとのことです。 FeatureToggleは以前から存在する概念で、発表の中で共有された課題があって導入に踏み切れないケースも多いと思っていました。 しかし、今回の発表のように課題に対するノウハウや事例が溜まってきており、今後広まっていく可能性を秘めていると感じました。 今あらためて考える ~ PHP に型定義をする理由 ~ report by id:hirobex speakerdeck.com PHP で型定義するメリットを フィードバックサイクル コーディングの生産性 コードのメンテナンス性 の3つの観点で語っていただきました。 どれも非常に魅力的なメリットばかりで、可能な限り型定義すべきだと思いました! 実践PHPStan report by id:Y-Kanoh tadsan.fanbox.cc PHPStanで型をつけて既存コードの型を検査することを目的に、 PHP での基本的な型の考え方から最近の PHP で発生する型宣言とPHPDocの選択問題などに触れておりました。 また、 PHP で表現しきれない”型”をPHPStanを使ってどう的確に表現し、さらに実行時に型がどうなっているかなどを確認しながら型安全なコードを実現する方法を説明いただきました。 (謎の PHP 用語”mixed”…) まとめ 今回はオンライン参加と会場参加の開催でした。 前年の PHPカンファレンス 沖縄2021では、オンラインのみの開催だったのですが 、今年はオンライン参加だけでなく会場参加でも参加できることに少し嬉しさを感じました。 弊社ではPHPTechCafeを毎月開催しています。 rakus.connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
技術広報の yayawowo です。 今回は、 Linux 上でファイルや ディレクト リ検索時に利用する 『find コマンド』 について紹介します! find コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明させていただきます。 【目次】 find コマンドとは find コマンドの使い方 基本書式 オプション一覧 演算子/アクション一覧 find コマンドの活用例 終わりに ◆ Linux の理解をより深めたい方へ以下関連おすすめブログ ・ ls コマンド 【使い方 まとめ】 ・ よく使うLinuxコマンド一覧【最新版】 ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ vi コマンド【使い方まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【Linux】今振り返りたい、プロセスって何? find コマンドとは find コマンドは、検索するためのコマンドです。 ファイルや ディレクト リを検索する際に用います。 find コマンドの使い方 基本書式 find コマンドの基本書式は以下の通りです。 $ find 検索場所 [ オプション ] ファイル名 ファイルを検索するには、そのファイルがどこにあるのかを指定する必要があります。 また、find コマンドには多くのオプションがあります。 以下にまとめておきますので、用途に合わせて使い分けください。 オプション一覧 オプション 説明 -name ファイル名を指定検索 -iname 文字の大小を区別せず、ファイル名を指定検索 -type f ファイルのみを対象に検索 -type d ディレクト リを対象に検索 -type p 名前付きパイプを対象に検索 -empty ファイル容量が0のファイル/ ディレクト リを対象に検索 -size ファイル容量を指定検索 -path ファイルパスを指定検索 -ipath 文字の大小を区別せず、ファイルパスを指定検索 -newer 指定したファイルの更新日時後に更新された、ファイル/ ディレクト リを検索 -anewer 指定したファイルの更新日時後にアクセスされた、ファイル/ ディレクト リを検索 -mtime 日数 最後にデータが更新された日時を検索 -atime 日数 指定日数以前にアクセスされた、ファイル/ ディレクト リを対象に検索 -mmin 時間 指定分数に更新された、ファイル/ ディレクト リを対象に検索 - amin 指定分数にアクセスされた、ファイル/ ディレクト リを対象に検索 演算子 /アクション一覧 演算子 /アクション 説明 -a 複数条件検索 -and 複数条件(AND検索) -or 複数条件(OR検索) -not 条件不一致検索 -exec 検索結果に対してコマンドを実行 find コマンドの活用例 指定したファイル名を検索する(-name) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # 「sample2.txt」を指定検索 # findコマンドと-name localhost:/home/dir1# find /home/dir1/ -name sample2.txt /home/dir1/sample2.txt ファイルのみを対象に検索(-type f) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # ファイルのみを対象に検索 # findコマンドと-type f localhost:/home/dir1# find /home/dir1/ -type f /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt ディレクト リを対象に検索(-type d) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # ディレクトリのみを対象に検索 # findコマンドと-type d localhost:/home/dir1# find /home/dir1/ -type d /home/dir1/ /home/dir1/dir1_1 /home/dir1/dir1_2 ファイル容量を指定検索(-size) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル容量が10byte以下のファイルを検索 # findコマンドと-size localhost:/home/dir1# find /home/dir1/ -size -10c /home/dir1/sample2.txt /home/dir1/sample3.txt 指定したファイルの更新日時後に更新された、ファイル/ ディレクト リを検索(-newer) ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 「sample.txt」より後に更新したファイル/ディレクトリを検索 # findコマンドと-newer localhost:/home/dir1# find /home/dir1/ -newer sample.txt /home/dir1/dir1_1 /home/dir1/dir1_2 最後にデータが更新された日時を検索(-mtime 日数) ※日数の定義  今日:0  昨日:1 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 今日更新されたファイル/ディレクトリを検索 localhost:/home/dir1# find /home/dir1/ -mtime 0 /home/dir1/ /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt /home/dir1/dir1_1 /home/dir1/dir1_2 # 最後にデータが更新されたファイル/ディレクトリを検索 # findコマンドと-mtime localhost:/home/dir1# find /home/dir/ -mtime 1 find: /home/dir/: No such file or directory 指定分数に更新された、ファイル/ ディレクト リを対象に検索(-mmin 時間) ※時間の定義  1分:1  6時間:60分×6時間=360  12時間:60分×12時間=720 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 30分以内に更新されたファイル/ディレクトリを検索 # findコマンドと-mmin localhost:/home/dir1# find /home/dir1/ -mmin -30 /home/dir1/ /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt /home/dir1/dir1_1 /home/dir1/dir1_2 複数条件(AND検索)(-and) -type f と -mtime 日数 を組み合わせて検索します。 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 今日更新されたファイルのみを検索 # findコマンドと-and localhost:/home/dir1# find /home/dir1/ -type f -and -mtime 0 /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt 複数条件(OR検索)(-or) -size を組み合わせて検索します。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル容量が1byte以下又は、15byte以下のファイルを検索 # findコマンドと-or localhost:/home/dir1# find /home/dir1/ -size -1c -or -size -15c /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt 条件不一致検索(-not) -type f と -not を組み合わせて、ファイル以外を検索します。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル以外を検索 # findコマンドと-not localhost:/home/dir1# find /home/dir1/ -not -type f /home/dir1/ /home/dir1/dir1_1 /home/dir1/dir1_2 終わりに いかがでしたでしょうか? 今回はファイルや ディレクト リ検索にて良く用いる、find コマンドの使い方をご紹介させていただきました。 find コマンドはオプションや、 演算子 等を使い分けることで様々な検索方法ができます。 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
はじめに こんにちは。新卒3年目のhy094です。 今回は、先日社内で開催したTypeScript勉強会の資料を公開します。 この資料は、前半は私が作成し後半は一年後輩のたぐち君が作成しています。 TypeScriptとは関係がないですが、たぐち君の記事(note)も紹介しておきます。 デスクトップの整理に悩んでいる方はぜひ見ていってください! note.com はじめに 前提 資料公開 スライドの中身 参考にさせていただいた書籍・サイト おわりに では、本題に入ります。 前提 TypeScript初心者 向けに作成した資料です JavaScript で書かれたコードのTypeScript移行を目的としています 移行に不要な箇所はあまり触れていません JavaScript の構文も紹介しています 資料公開 スライドの中身 スライドをみる時間がない方向けに、ざっくりどのような内容が書かれているかを記載します。 TypeScriptとは(4〜6ページ) TypeScriptにするメリット 型(8〜19ページ) プリミティブ型 文字列・数値・真偽値・undefined・null (BigInt・シンボルは省略) リテラル 型 object型 オブジェクト リテラル 配列 unknown, any, never ユニオン(合併)型・インターセクション(交差)型 基本的な構文(7,20,21ページ) 演算子 制御構文 関数(22〜26ページ) 関数宣言・アロー関数式 デフォルト引数 可変長引数 this引数 インターフェース(27〜32ページ) type interface 高度な型(33,34ページ) 型ガード 型 アサーション モジュールシステム(35〜39ページ) import・export type宣言 npmパッケージモジュール DefinitelyTyped 自作の型定義ファイル ビルド関連(40〜51ページ) コンパイル ・ コンパイル オプション tsconfig. json webpackタ スクラン ナー webpack.config.js 参考にさせていただいた書籍・サイト 主に以下の書籍・サイトを参考にさせていただきました。その他はスライドに記載しています。 プログラミングTypeScript プロを目指す人のためのTypeScript入門 サバイバルTypeScript これらは個人的に、TypeScriptの参考書3種の神器だと思っています。超オススメです。 おわりに 資料作成に際して、自身の知識がより深まりました。 なんとなく使っていたものを改めて説明するというのは、やはり難しいですね。 ありがたいことに勉強会自体は好評で、録画も社内で見ていただけているようです。 (勉強会後にアンケートを取っており、後日フロントエンドチームのnoteで公開予定です。) 録画の公開はできませんが、資料を見ていただき少しでもTypeScriptへの学びになれば嬉しいです! フロントエンドチームのnoteです。ぜひご覧ください! note.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
こんにちは!株式会社 ラク スの@kzak_24と申します。 インフラ開発部 SRE課に所属しております。 さて今回は、 現在 アサイ ンされている新規システムの開発プロジェクトにて、フロントエンドの技術選定を担当した時の経験 をまとめようと思います。 フロントエンドは未経験だった為、色々と試行錯誤を行いました。 未経験なりにどのような基準を設けて技術選定を行なったか 、皆さまの意思決定の参考になれば幸いです。 目次 SREチームの紹介 前提 チームの背景 検討内容と採用理由 言語 / FW 状態管理 スタイル テスト まとめ 最後に SREチームの紹介 まず始めに、少しだけSREチームについて紹介させてください。 ラク スのSREチームは2021年に発足した比較的新しい組織であり、下記の2つのチームに分かれています。 BP(Business Platform)チーム 社内業務システムの開発/保守/運用をメインに担当するチーム DevOpsチーム プロダクトを横断した自動化や運用改善をメインに担当するチーム 現在BPチームは4名、DevOpsチーム1名で構成されています。 私はBPチームに所属しており、このチームで今回のプロジェクトをスタートさせました。 ラク スのSREチームにご興味ある方は、以下もご参考になさってください。 ・ SREエンジニア | エンジニア職種紹介 | 株式会社ラクス 中途採用 ・ Webアプリケーションエンジニア/Go, TypeScript | エンジニア職種紹介 | 株式会社ラクス 中途採用 前提 今回は、以下のような前提の元で技術選定を行いました。 新規システムとして過去の負債がないまっさらな状態から開発をスタートできる できるだけモダンな技術を使用する(社内の ベンチマーク 的な意味を込めて) 開発するアプリケーションは SPA(Single Page Application) の構成にする 一部ページで SSR (Server Side Rendering)が必要になる チームの背景 バックエンド専門メンバーのみで、フロントエンドの経験は乏しい モダンなフロントエンドの開発経験は、ほぼない これらの前提を踏まえて、今回のプロジェクトにおけるフロントエンドの技術選定については、経験値の低さをカバーすることを重要視し、情報収集のしやすさや学習モチベーションの維持を含めた 「学習コスト」 を最優先することとしました。 また次点で以下の3点を優先することとしました。 社内の利用実績 トレンド 保守性 ※ 2022年 8月 24日 追記 SREチームでフロントエンドの技術選定をしている理由についてのコメントを頂いたので、SREチームの背景を交えて経緯について補足させていただきます。 SREチームの紹介 に記載した通り、BPチームは社内向けの共通基盤の開発・運用を担当しており、アプリケーションエンジニアとしても活動しています。 SREにアプリケーションエンジニアがいる理由は、SREチームが新たなノウハウを各サービスへ展開することをミッションの1つとしている為です。 ラク スではサービスごとに開発チームが存在しており、技術導入なども各チームで判断していますが以下のような課題もあります。 サービスの機能開発と並行稼働の為、導入が思うように進まない そこで、SREチームが社内向けの共通基盤の開発・運用を通し、先行して新しい技術の調査・導入を行うことで、そのノウハウを各サービスに展開し、技術導入を推進するという動きをしています。 その際、以下のように役割分担しています。 BPチーム:技術調査・導入 DevOpsチーム:各サービスへの展開 こういった背景からアプリケーションの開発知識が必要になるので、SREチームにアプリケーションエンジニアが在籍しています。 今回ご紹介するフロントエンドの技術選定は、BPチームの技術調査・導入の活動についての事例となります。 チームの背景 に記載した通り、バックエンド専門のメンバーのみだったので、フロントエンドはフロントエンド専門チームに任せるか?といった議論もありましたが、「過去事例に囚われず、フラットに検討すべき」という判断と「フロントエンドにもチャレンジしたい」という思いから、敢えて自分たちで担当することにしました。 検討内容と採用理由 今回は、以下4つを検討しました。 言語 / FW 状態管理 スタイル テスト 言語 / FW 言語に関しては、近年 デファクトスタンダード になりつつあることと、バックエンド専門で静的型付け言語に慣れているメンバーが多いということで、TypeScriptに決定しました。 また、FWは次の2つから検討しました。 React Vue.js 検討にあたり、判断材料とする為に次のようなことを実施しました。 フロントエンド専門チームへの ヒアリ ング チュートリアル の実践 その結果、今回の選定方針をもとに以下のような比較をすることができました。 React Pros JSX記法のメンバー受けがよく、学習モチベーションが保てそう 関数 コンポーネント 主体で宣言的にかけるので、コードが読みやすく、保守性が高い 直近でリリースした社内の他プロダクトで利用実績がある Cons Vue.jsと比べると学習コストはやや高い ドキュメントの充実度は低い Vue.js Pros 利用者が多く、情報が得られやすいので学習コストが低い 日本語ドキュメントが多い シンプルな設計で拡張性が高い 社内での利用実績がReactより多い Cons SFC 記法のメンバー受けがよくなく、学習モチベーションは低い 世界的なトレンドはReactに劣る 決定内容と理由 決定内容 Reactを採用する 理由 チーム内での評判がよく、モチベーション高く学習を続けていくことができると考えました。 また、保守性の高さや コンポーネント の再利用性もReactの方がチーム内での評価が良かったことも理由です。 Reactを採用するにあたり、 SSR の実現の為に Next.js も採用しました。 状態管理 状態管理に関しては、Reactを使用することを前提として代表的なライブラリである下記の3つから検討しました。 Redux Recoil React Context 状態管理のライブラリについては、主に公式ドキュメントやWebの記事などから情報を収集し、比較検討を行いました。 Redux Fluxベースの状態管理ライブラリです。 Pros 柔軟性が高い Reduxが定めるベストプ ラク ティスのRedux ToolKitがある 1つのグローバルなストアにStateを保持するので管理が容易 Cons 学習コストが高い 今回のプロジェクトで開発するアプリケーションにはToo Muchである Recoil Meta社製の状態管理ライブラリです。 Pros Atom という単位で一意なキーをもったグローバルStateを保持するので、理解しやすい 学習コストが低い割に、機能的には十分 Cons Atom が増えすぎると管理が難しくなる まだメジャーバージョンリリースしていない(執筆時点でのLatestはv0.7.5) React Context Reactが標準で提供しているContext API です。 Pros React標準なので、導入ハードルが低い Hooks( useContext )が提供されているので、使い勝手が良い Cons 管理するStateが増えてくるとProviderのネストが深くなり、視認性が悪くなる 祖先 コンポーネント まで辿ってツリーを更新する為、頻繁に レンダリング が発生してしまう 決定内容と理由 決定内容 Recoilを採用する 理由 今回開発するアプリケーションの規模から、ReduxではToo Much、React Contextでは若干不足と考えたので、Recoilを採用しました。 また、基本的に Atom をHooksで操作するだけのシンプルさや学習コストの低さも魅力的でした。 メジャーバージョンのリリースはまだでしたが、実際にプロダクション利用している他社事例もあった為、その点に関しては問題なしと判断しました。 スタイル スタイルに関しては、まず CSS の管理方法について、次のような思いがありました。 CSS に詳しいメンバーがいない為、なるべく CSS ファイルの管理は避けたい スコープはできるだけローカルに閉じて、堅牢性をあげたい 上記の思いを踏まえつつ、方針を考慮した結果、下記の2つから検討しました。 CSS Module styled-components(CSS in JS) 簡単なプロトタイプを実装し、使い勝手や学習コストを比較検討しました。 CSS Modules CSS ファイルをJSからimportしてスタイルを当てる手法です。 Next.jsでは標準でサポートされています。 Pros Next.jsに標準でサポートされている為、導入コストが低い コンポーネント 単位でスコープを閉じられる Cons CSS ファイルを管理することになる 社内に利用実績がない styled-components CSS in JSのライブラリです。 Pros コンポーネント のコードと同居させられるので、スコープについてほぼ考えなくて良い 直近でリリースした社内の他プロダクトで利用実績がある Cons コンポーネント に依存したカスタマイズをするので、移行が難しい 静的な CSS よりもパフォーマンスが低い 決定内容と理由 決定内容 styled-components( CSS in JS)を採用する 理由 JSファイル内に CSS を記述できるため、以下の通り前提の思いを2つともクリアできる点が決め手でした。 スコープについてほぼ考えなくて良くなる CSS ファイルを作成しなくても良い また、社内でも利用実績があり、情報収集の容易さという点でもメリットがありました。 テスト 最後にテストに関してですが、まずフロントエンドのテスト方針をどのように設定すべきか全く知識がなかった為、社内のフロントエンドチームに ヒアリ ングしました。 そこで Testing Trophy の考え方を教えていただきました。 Testing TrophyとはReact Testing Libraryの作者であるKent C. Dodds氏が提唱する JavaScript のテスト方針です。 今回はその考えに則り、Unit Test及びIntegration Testの層を厚くする方針としました。 その前提の元、テストライブラリは下記の2つを検討しました。 React Testing Library Enzyme テストランナーについては、ほぼ デファクトスタンダード になってきていると思われることと、Next.jsに標準で組み込まれていることから、 Jest を採用しました。 テストは、スタイルの検討の際に実装していたプロトタイプの中で使用し、使い勝手や学習コストを比較検討しました。 React Testing Library Kent C. Dodds氏によるReactテストライブラリです。 Pros Next.jsの 公式ドキュメント でJestと合わせた構成が推奨されている 実際にユーザーにどう見えるかを基準にしたBDD寄りの考え方がチーム内で評判が良い スナップショットテストを実施でき、改修時のリスクを減らせる 直近でリリースした他プロダクトで利用実績がある Cons Enzymeに比べるとコードの記述量が多い Enzyme Airbnb 社製のReactテストライブラリです。 Pros shallow renderのテストは書きやすい コードの記述量は比較的少なくできる コンポーネント のpropsやstateに直接アクセスできる Cons ユーザー目線ではないテストができ上がりがち 決定内容と理由 決定内容 React Testing Libraryを採用する 理由 ユーザーにどう見えるかを基準にしたBDD寄りの方針で作られています。 そのため、本質的なテストをすることができる点に関して、チーム内で評価されたことが決め手でした。 また、関数などのUnit TestはJestで、 コンポーネント 同士のIntegration TestはReact Testing Libraryでという明確な使い分けができ、Unit Test、Integration Testを充実させるテスト方針とマッチすると考えました。 まとめ 最終的に今回採用した技術は以下になります。 言語 / FW 状態管理 スタイル テスト ・TypeScript ・React ・Next.js ・Recoil ・styled-components( CSS in JS) ・Jest ・React Testing Library 最後に 最後までご覧いただきありがとうございます。 今回は、フロントエンド未経験のSREエンジニアが技術選定を担当した経験についてご紹介しました。 技術選定はシステム要件、チームの背景、スケジュールなど様々な要因を考慮する必要があり、非常に良い経験となりました。 SREチームではフロントエンドだけではなく、バックエンドではGoを使用した フルスクラッチ 開発や、 AWS EKSを使用した Kubernetes 基盤の構築など様々な取り組みを進めております。 今回紹介したこと以外にもたくさんの情報を発信していけるように、今後も取り組んで参ります。 ◆ 直近で開催予定の採用イベントをご紹介! career-recruit.rakus.co.jp career-recruit.rakus.co.jp エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com