TECH PLAY

株式会社ラクス

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

935

こんにちは。エンジニアのrs_shoです。 投稿は4回目になります。今回は 排他制御 についてお話ししようと思います。 はじめに 排他制御の種類 楽観ロック(楽観的排他制御) 悲観ロック(悲観的排他制御) それぞれの特徴 Javaにおける排他制御 Semaphore CountDownLatch synchronizedメソッド データベースのLOCK おわりに 参考資料 はじめに そもそも 排他制御 とは何か、ご存じでしょうか。 排他制御 とは、簡単に言うと、処理Aをしている間、他の処理は処理Aが終わるまで待つ、という制御のことです。 身近な例えで言うと、共有フォルダにある Excel などを誰かが開いて編集している間、 他の人は閲覧のみ可能で編集は不可の状態(設定によってはできますが…)のことです。 排他制御 の種類 排他制御 はただ処理待ちをするだけではなく、大きく分けて2つ種類があります。(厳密にはもっと細かく分かれていると思います) 楽観ロック(楽観的 排他制御 ) と 悲観ロック(悲観的 排他制御 ) です。 楽観ロック(楽観的 排他制御 ) 楽観ロックは同時更新は起こらないであろう、という前提の 排他制御 のことです。 更新対象のデータをロック(編集不可)することはせず、 更新時に「手元のデータの編集開始時点の状態」と、「更新対象データの状態」が同じかを確認して更新を行います。 誰でも編集・更新していいけど、更新時に他の人が上書きしていたら更新できないよ!っていう制御です。 個人的には「楽観的(前向きな考え)という割には、更新時にデータが吹っ飛ぶ可能性があって怖いな」と思いますね。 悲観ロック(悲観的 排他制御 ) 悲観ロックは同時更新が起こる可能性がある、という前提の 排他制御 のことです。 更新対象のデータをロックして、自分の編集・更新が終わるまで、他の人が編集できない状態にしてしまいます。 編集中は見たり、コピーを作ることはできても、原本に手を加えることはできないよ!っていう制御です。 こちらの方が自分が開いている間は誰も更新できないので、なんとなく安心感がありますね。 それぞれの特徴 先程説明した楽観ロック・悲観ロックについて、特徴や違いを挙げていこうと思います。 前提 楽観ロック:同時更新は起きないであろう 悲観ロック:同時更新が起きるかもしれない 整合性チェック 楽観ロック:データ編集終了(更新)時 悲観ロック:データ編集開始時 どの処理に向いているか 楽観ロック 同時更新がめったに起きない処理(単体で行う処理) 不整合が起きてもやり直せる処理 短時間で終わる処理 悲観ロック 同時更新が頻繁に起こる可能性がある処理(分担する処理) 不整合が起きてほしくない処理 長時間続く処理 Java における 排他制御 僕は業務中にある種別の中のカテゴリ内で番号が重複しないように実装しようと思い、 排他制御 について調べました。 (例えば、動物という種別の、哺乳類カテゴリの1:象, 2:イルカ …といった感じで、IDが重複しないように実装したかった) 上記はシーケンスを使えばいい、と思うかもしれませんが、カテゴリ毎にIDを1からスタートする場合、 カテゴリを追加する度にシーケンス生成が必要になるので、あまり現実的ではありません。 ですが、DB内で保持しているIDの最大値を取得するだけでは、採番処理が同時に行われた際に最大値が重複し、結果採番されたIDが重複してしまいます。 僕の個人的な解釈になりますが、調べた中で 排他制御 に使用できそうな方法を軽くご紹介しようと思います。 (いずれどこかでより詳しく深堀りしてみたいと思います。) Semaphore アクセス数を制限して、設定した値を超える数の処理が発生した場合、処理待ちをさせる 通常の 排他制御 はSemaphoreのロックが1つ(1つ以上は実行させない)の状態と同じ ロックを解放する方法が特殊で、実装を誤ると正常に機能しない(処理実行可能数を増やし続けてしまい、意図した 排他制御 ができない) CountDownLatch 複数の処理をブロック丸ごとロックする時に有効 引数にロック数を指定して、処理毎にロック数を減算、0になったらロックを解除する 複数メソッドにまたがってロックしたいときなどに有効だが、ロック数が0になったらロックが解放されるので、引数で渡す値には注意が必要 synchronizedメソッド メソッドの修飾子や 入れ子 で使用することで、同時実行をブロックできる 修飾子に追加する or 処理ブロックを 入れ子 にしてくくるだけで実装できる ただし、複数の継承先から参照されるクラスの場合は、 インスタンス 毎に処理が同時実行されてしまう可能性がある データベースのLOCK LOCK文を実行してテーブルのロックを取得、そのテーブルにアクセスしている処理があれば、解放されるまで待つ データ自体にロックがかかるので、整合性を保ちやすい ただ、 RDBMS の種類によっては、SELECTなどでもロックを取得してしまい、 デッドロック が発生したり、勝手に トランザクション をコミットされたりしてしまうため、注意が必要 おわりに 以上、 排他制御 についてざっと説明させていただきました。扱いが難しいですが、使いこなせればデータの整合性を保証できます。 この記事を通して 排他制御 について知っていただく、調べてみるきっかけになれば幸いです。 紹介した方法についても、いずれ深堀りしていこうと思います。 参考資料 排他制御(楽観ロック・悲観ロック)の基礎 【Java】マルチスレッド処理 - 排他制御 Javaの排他制御(ロック)に関係するクラスまとめ PostgreSQLは、SELECTもロックを獲得する エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 株式会社 ラク ス チャットディーラー開発課のエンジニアRakusMoritaです。 2021年3月26日(金)~3月28日(日)開催のPHPerKaigi2021に、 ラク スエンジニア7名が参加してきました。 phperkaigi.jp PHPer(ペチパー)によるPHPerのためのこの大規模イベントは、今年はオンラインでの開催でした。 オンラインでありながらも、豪華な登壇者、絶えず流れるコメント、主催者の勉強になるコントなどなど・・・ お祭り騒ぎのような雰囲気伝わってきて、ワイワイと非常に楽しい勉強会でした。 ラク スは当イベントのスポンサーとして参加 させていただいている他、社内から2名が登壇しました。 この記事では、PHPerKaigi2021に参加した社内のエンジニアが、参加したセッションの内容をまとめましたので、ご紹介したいと思います。 各セッションのスライドも用意しておりますので、PHPerな人、これからPHPerになる人は新たな発見があること間違いなしです。 ~目次~ はじめに 3/27(土) 実践ATDD 〜TDDから更に歩みを進めたソフトウェア開発へ〜 負荷試験の観点から見るGraphQLにおけるPHPのコードチューニング 目的に沿ったDocumentation as Codeをいかにして実現していくか PHPでCSVを安心して扱うために PHPで学ぶ、セッションの基本と応用 PHP8になった今の時代に、PHPの「エラー」「例外」そして「Error」をおさらいしておこう Laravel のメール認証の内部実装を掘り下げる PHPWebアプリケーションパフォーマンスチューニング PHP でもアーキテクチャテストしたい! 3/28(日) そのコード、フレームワークの外でも動きますか? 無駄な物をなるべく作らないリプレイス戦略 なるせ先生のPHP学~PHP8新機能スペシャル~ 今こそ理解するDI(Dependency Injection) プログラマ三大美徳を実現するデプロイフローを目指して PHPのDI、attributesとこれから DNSを制する者はインターネットを制す!DNSの世界/市川@cakephper 新社会人のコード品質カイゼン記録 あとがき 3/27(土) 実践ATDD 〜TDDから更に歩みを進めたソフトウェア開発へ〜 report by id:radiocat speakerdeck.com ATDDとはAcceptance test-driven developmentの略で、日本語にすると受け入れ テスト駆動開発 です。 アジャイル 開発では開発要件をユーザーストーリーとして表現し、それが実現できていることを開発の完了条件として受け入れテストを実施する手法がありますが、 それを駆動型で開発に取り入れるやり方がATDDです。登壇者の現場で考えられている、中心となる2本柱が次の内容です。 四象 限におけるQ2を強化する 四象 限とは技術面とビジネス面の2軸と、開発チーム支援と製品批評の2軸を組み合わせたもので、Q2はその中でビジネス面と開発チーム支援の領域です。顧客視点の高レベルテストで自動化と手動テストを組み合わせるところがポイントです。 テストピラミッドを登る テストピラミッドとは ユニットテスト を土台として、サービステスト、UIテストと上位に階層化したテストレイヤーに分類してテストを概念化したもので、上位のUIテストのほうが重厚化してしまう アンチパターン に陥らないように必要に応じてテストピラミッドを登っていくことがポイントです。 知識的情報だけでもボリュームたっぷりでしたが、さらに PHP で作られた Webサービス を題材とした ケーススタディ では、自動受け入れテストツールを使った実践例も紹介されています。ATDDの自動化領域と手動テストとの共存のさせ方、 ユニットテスト などのTDDの手法との組み合わせ方などについても語られており、実践に向けた応用方法の示唆に富む内容でした。知識のインプットだけでなく実践に向けたインプットにも役立つボリュームたっぷりなセッションだったので、今後も資料を読み返して現場で実践活用したい内容です。 負荷試験 の観点から見るGraphQLにおける PHP のコードチューニング report by id:Y-Kanoh speakerdeck.com API で利用するクエリ言語である GraphQL は、REST と違い、複数のクエリを1度のリク エス トで行うことができます。 そのため、複数のクエリ発行のために何度もレスポンスを待つ必要がなく、 レイテンシは REST と比べて速くなる特性があります。 しかしこの仕組み上、秒間のリク エス ト数低下や、短時間に処理が集中してしまいCPU負荷が高くなること、 重いクエリが含まれると全体のレスポンスに影響を与えることなど、デメリットも存在します。 利用時には、取得するデータを絞る仕組みや、複雑すぎるクエリを制限する仕組み、 PHP の場合は処理向上のためのOPCache導入などを行なって、コードチューニングを行う必要があります。その詳しい勘所について説明されていました。 REST との比較を行いながらわかりやすく説明していただけたので、両者のメリットデメリットなども理解できました。 実際使ってみての勘所を説明いただけていたので、GraphQL の導入を考えるかたはぜひ確認していただければと思います。 目的に沿ったDocumentation as Codeをいかにして実現していくか report by id:Y-Kanoh speakerdeck.com 開発者がチームに join し、開発を始められる状態になるまでのオーバヘッドを削減する方法が、システムの理解を助けるドキュメントです。 しかし、更新漏れによる誤った理解を防ぐために、ドキュメントはメンテナンスを継続的に行わなければなりません。一方、開発と切り離された運用でのメンテナンスは、システムとの乖離を修正するまでの時間も長くなってしまい、 継続的なメンテナンスも難しくなってしまいます。 そこで、この発表では、システムとドキュメントをそれぞれ情報の集合と考え、 各情報同士が紐づいていない状態が増えることを「システムとドキュメントの乖離が大きくなった」と位置付けることで、 この問題の解決策を探っています。 その方法として、PHPDocなどのように、”システムとドキュメントの間に構造化データを用意し、 その構造化データをもとにドキュメントを作成する方法”や、OpenAPIのように “構造化データを先に用意し、 そこからシステムとドキュメントを作成する” 方法などが紹介されていました。 また、具体的に対策を行うためのツールも紹介されており、 どのような仕組みで対策を行うことができるのか想像しやすい内容でした。 ドキュメントのメンテナンス問題は私自身も思い当たることが多く、 発表内容の前半は胸が痛い内容でした。エンジニアらしく問題の本質を分析し、 仕組みでそれをカバーすることを考えさせられる内容でした。 PHP で CSV を安心して扱うために report by id:tsudachantan speakerdeck.com 他サービスとのデータ連携やバルクデータ入出力などで使い勝手が良く、根強く利用されている CSV ファイル。 PHP での CSV 処理は癖が強く、一見安全に対応できたように見えて運用面で深刻な問題を抱えることがあります。 現状とその解決方法について丁寧にお話いただきました。 fw3/streams OSに依存しない安定した入出力と、発生していた問題の根本解決としてライブラリfw3/streamsを紹介されていました。 以下が特徴です。 OSと PHP バージョンの組み合わせに影響されず動作する 安全かつ確実に入出力が可能である mb_convert_encordingを使った文字セットの変更ができる 妥当な文字セット自動検出が行える OSに影響されない改行コード出力を行える 変換できない文字があった場合の代替手段を設定できる ライブラリの説明に沿って様々な環境やパターンを網羅して CSV の扱い方について発表されており、大変勉強になりました。 PHP で学ぶ、セッションの基本と応用 report by id:soachr speakerdeck.com 以下の章立てで発表されていました。 生い立ち 技術的な仕組み 最低限の周辺知識 PHP 以前に、そもそもHTTPでセッションが使われるようになった背景から、現在どのようにセッションが使われているのかまでを紹介された上で、じゃあ実際に PHP はどのようにセッションを実現しているのか、という内容まで紹介されていました。 今までふわっとしていた PHP のセッションについて理解できました。 ログイン機構があるシステムに関わっている方はとりあえずこの発表を聞けば問題ないと思うくらい、わかりやすい&すっと理解できる内容でした。 新卒時代のときにこの発表に出会っていればもっとスムーズに理解できたのでは...とこの発表で初めてセッションについて学んだ方が羨ましいと思うくらいです。新卒の育成担当をしている身としては、ぜひ学習カリキュラムに入れさせていただきたいと強く感じました。 PHP8になった今の時代に、 PHP の「エラー」「例外」そして「Error」をおさらいしておこう report by id:tsudachantan speakerdeck.com PHP には「エラー」を知らせる仕組みがたくさん用意されていますが、それぞれの違いが答えられるでしょうか。 PHP のエラーの扱いはバージョンごとに進化しており、それが混乱する原因にもなりえます。 とにかく不用意に\Throwable、\Errorをキャッチすることは危ない!というメインの主張を。 では、そもそもエラーとは?という説明からお話しされており、納得しながら整理できました。 まだまだ PHP 歴が浅い自分や、わかっているけど人に説明するのは難しいといった方にも役に立つ内容だと思います。 「Throwable/Error/Exception」についての棲み分けについての認識がクリアになり、効果的な例外の使い方について考える機会になりました。 Discordのチャンネルでも様々な意見が交換されており、チーム開発での意識のすり合わせの大切さを感じました。 Laravel のメール認証の内部実装を掘り下げる report by id:Y-Kanoh speakerdeck.com PHP の フレームワーク であるLaravelは、さまざまなロジックが既に用意されており、 メール認証の仕組みも、少しの実装を行うことで、簡単に利用することができます。 しかし、既存のロジックは手軽さのために、拡張性が犠牲になっている部分があり、 独自の仕組みを組み込みたい場合は、内部ロジックを理解した上での改修が必要です。 メール認証の場合、この拡張性を損なっている原因は、App User モデルの責務が多すぎることです。 App User の持っている責務を明確化して、それぞれの依存関係を理解した上で、 分離独立させることにより、拡張性の高いロジックに作り替える方法を紹介いただいていました。 近年、機能が多くなりすぎて批判されることもある Laravel ですが、内部の依存関係を理解し、 責務に沿って作り替えれば上手く付き合っていけることを学べた発表でした。 PHPWebアプリケーションパフォーマンスチューニング report by id:soachr speakerdeck.com パフォーマンスチューニングについて、体系的にかつ具体的に説明されていました。 パフォーマンスチューニングの大原則の考え方である「推測するな、計測せよ」を軸として、どのように再現・計測・原因仮説、からの対策を取るのかを、Webアプリケーションを実現する ミドルウェア ごとに紹介されていました。 自身もパフォーマンス・チューニングを業務で行っていたのですが、まだ知らない視点や、計測時のコマンド、対策を知れてとても勉強になりました。 パフォーマンス・チューニングをやったことがない人で「なにから初めて何をすればいいのかわからない」方にもおすすめです。 PHP でも アーキテクチャ テストしたい! report by id:radiocat speakerdeck.com 弊社のリードエンジニア川並が アーキテクチャ テスト について発表しました。 コードレビューが機能している状況においても、 アーキテクチャ 観点でしっかりレビューするのは難しく、開発初期にしっかり検討していた設計方針がいつのまにか泥団子状態ということも起こりえます。 アーキテクチャ を維持するために、クラスの依存関係や実装ルールをコード化して自動テストするのが アーキテクチャ テストです。 発表では PHP の フレームワーク である deptrac と phpat を使った アーキテクチャ テストの実例がデモを交えて紹介されました。 デモで使われたサンプルコードが以下で公開されています。 github.com アーキテクチャ は一度決めたら終わりではなく、 アーキテクチャ テストが アーキテクチャ を育て、進化させていく!という、希望に満ちたまとめで勇気をもらえるお話でした。 3/28(日) そのコード、 フレームワーク の外でも動きますか? report by id:Y-Kanoh speakerdeck.com アプリケーションの長期運用には、ビジネスサイド要因による仕様変更の他にも、 フレームワーク のバージョンアップ/メンテナンスの終了や、 時代の変化によって利用していた フレームワーク が陳腐化してしまうなど、リプレースを求められることがあります。 そのような時に、 フレームワーク にガッツリ依存したコードになっていると、 大半のコードを書き直す必要が出てきてしまいます。 この発表では、リプレースやリニューアル時に飛型しないために、 チームで作成するコードを フレームワーク から分離し、 環境の変化に強いコードを作成する例を紹介していただけました。 発表中には、実際にLaravelで実装されたコードを、 Symfony に移植するサンプルコードを説明していただき、 具体的にどのような効果が得られるかを体験できました。 また、最後におっしゃっていた、違う フレームワーク や、違う仕組み、違う言語など、 「バリエーション」に強いコードにすることで、結果的に保守性を向上させるという考えが、 とても共感できました。 資料の中に ソースコード のリンクもあるので興味のある方は覗いてみてください。 無駄な物をなるべく作らないリプレイス戦略 report by id:MasaKu speakerdeck.com レガシーソースのリライトについてのお話でした。 リプレイス戦略は以下の段階で難易度が上がっていきます。 リファクタリング リプレイス リライト リライトとは、既存機能を完全に一から書き直すという作業であり、この作業を実施するには、そもそも なぜリライトが必要なのか という課題を明確にして、どのように書き直すかの方針を新たに決定する必要があります。 リライトを始めるには基本的なこととして、現状の仕様を完全に理解する必要があります。 そのための方法は コードリーディング リファクタリング 設計の振り返り 実際にサービスを使ってみる などの方法を行います。 また、実際のユーザと直接対話することも重要です。 サービスが提供している価値はどこにあるのかを再認識するためにも、ユーザストーリーを立てて、本当にリライトが完了するかを見ていく必要があります。 ご発表の中で リファクタリングを限界までしても現状の問題が解決しないと思ったらリプレイス という判断基準をご紹介いただき、とても理解しやすいご説明でした。 なるせ先生の PHP 学~PHP8新機能 スペシャ ル~ report by id:Y-Kanoh PHP8の新機能であるmatch式、NullSafe 演算子 、Attributeを、某テレビ番組風に紹介していただけました。 match式 フォールスルー(brakeがないと次の処理を実行してしまう)がなくて事故が起きにくい マッチする条件がないとエラーになるから安全 再帰 処理で使いやすい コードの見通しが良くなる NullSafe 演算子 オブジェクトがNullの場合、指定されたメソッドが実行されない 似たようなものでNull合体 演算子 や、 エルビス 演算子 がある エルビス 演算子 の” エルビス ”は、エルヴィス プレスリー の髪型が語源 Attribute 言語としてサポートされるようになった アノテーション 今の形になるまで様々な議論があった アトリビュート を読み取って トランザクション を張るなどの応用がありえる また、新機能を単に紹介するだけでなく、その機能の便利なところや、 ちょっとした裏話も共有していただけて、ドキュメントを読むだけでは得られない内容でした。 個人的には、エルヴィス プレスリー が初耳でした。 今こそ理解するDI( Dependency Injection) report by id:MasaKu speakerdeck.com DIについて詳しく再認識させていただけたご発表でした。 というのも、個人的にDIについていろいろと調べていたことがあったのですが、結局これがDIなのかな? といったぼんやりとした理解だったので、今回のご発表を聞き、少し理解が進んだように感じました。 DIとは保守性の高いコードを書くことを目的とした設計原則とパターンのセットであり、 疎結合 を実現することを目的とした デザインパターン です。 概念としては、制御の逆転を行い、必要になった時だけ呼び出す、という流れで外部からオブジェクトを使用するようにします。 例えば、メールを送信するメソッドを例にすると、外部から該当のメール送信メソッドを呼び出す際、メソッド内でメール送信オブジェクトを生成してしまうと、そのメソッドはメソッド内で生成したオブジェクトを自由に付け替えることができなくなくなります。 検証のタイミングでは、検証用のメールサーバを利用して、本番では AWS のメールサーバを利用する、など使い分けをしたい場合、そのメソッド内でオブジェクトを生成してしまうと、コードを修正しなければオブジェクトの付け替えができません。 こういった密結合の状態を回避するのがDIです。 なお、DIの説明がある際にDIコンテナの話も良く出てくるが( フレームワーク の標準機能として搭載されている場合が多い)、DIを実現するためにDIコンテナが必要なわけでなく、DIを実現しやすくするための工夫として存在しているものなので、DIコンテナは必須ではないようです。 また、類似の デザインパターン として、サービスロケーターの話もよく登場するが、目的はDIと同じだが実現する手段がが異なる デザインパターン とのことです。 プログラマ 三大美徳を実現するデプロイフローを目指して rebort by id:Jazuma プログラマ三大美徳を実現するデプロイフローを目指して from 智也 鈴木 www.slideshare.net 株式会社 M & A Cloud 所属 @yamotuki さんによるセッションです。 「 ベンチャー におけるプロダクトやチームの成長とデプロイフロー自動化」というサブテーマのもと話が進みました。 (デプロイフローにおける) プログラマ の三大美徳 怠惰 :同じ作業の繰り返しは面倒くさい →自動化したい 傲慢 :デプロイ手順をミスってエラーになるのはダサい →自動化したい 短期 :デプロイ作業に2時間もかけたくない →2秒で終われ! デプロイフロー自動化の歴史 サービス開発当初はデプロイフローが自動化されていませんでした。 開発者の人数が少ないのでやっている時間がない 売上が立っていないので運用フロー効率化よりも機能追加優先 自動化のノウハウがない 自動化文化がない ユーザーアクセスが少なく、障害発生リスクがない しかし、サービスが軌道に乗ってくると自動化をする理由が出てきました。 売上が立った 開発者が増えて手動作業だとミスが起こる可能性が大きくなった デプロイフローそのものが複雑になり手動作業がつらくなる 運用に時間を取られて機能追加もおろそかに なによりめんどくさことはしたくない! このような経緯でデプロイフロー自動化が段階的に進みました。 セッションの中で 「プロダクトとチームの成長は自動化と密接に関係している」 と述べられていたのが印象的でした。 エンジニアはつい自動化それ自体が目的になりがちですが、チームやプロダクトがどのようなフェーズにあり、どんな問題を解決するために自動化をするのかということが重要だと思いました。 PHP のDI、attributesとこれから rebort by id:rakusMorita speakerdeck.com DI( Dependency Injection・依存性の注入)とは、簡単に言うと Dependency :使われるオブジェクトを Injection:使う側のオブジェクトに渡す ということです。DIについては詳しく説明しませんが、 具象クラス(具体的な実装をしているクラス)との処理の結合を避けて、抽象クラスと処理を結合させることで、変更に強くすることが基本的な考え方です。 注入とは、 インスタンス を抽象クラスから作成して動かすというものです。まだ具体的な実装ができていなくてもダミーの インスタンス を作りやすい(モックの作成がしやすい)ので、その結果、実装もそうですが、 単体テスト なども非常にやりやすくもなります。 DIの歴史とポイント DIは Java から始まった PHP5でクラスの機能が強化され、DIっぽいことができるようになった。 近年 PHP でもDIが標準的な思想として認知されつつある(型指定が当たり前に/interfaceが使いやすくなった/autoloadでrequire不要に等々) 今までの型指定のない PHP 的な書き方もできますし、いい意味で Java っぽさも取り入れた実装もできるようになってきて、 PHP は良いとこ取りな言語に進化してきましたね。 APC やOPchaceなどによるコードキャッシュにより、実行速度も向上し、ますますDIがやりやすくなりました。 今時な フレームワーク (Laravel、 Symfony 、 CakePHP あたり)はDIコンテナを持っている(あるいは持とうとしている)ということは、特に意識しなくてもDIを使えるようになってきたと言えるでしょう。 PHP の動向 PSR-11という インターフェイス が普及 異なる フレームワーク やライブラリのを使っていても同じように呼び出せるDI用の インターフェイス が使えるようになりました。 PHP -DIというDI用のライブラリの存在 PSR-11互換。 フレームワーク と組み合わせて使えるので便利です。 @Inject( アノテーション )記法が廃止になって#[Inject]( アトリビュート )になった アノテーション は結局のところPHPDocだったので、文字列の解析になるので重かったのが、 アトリビュート だと言語としてサポートされていて、動作が格段に速くなりました。 Autowireという機能 明示的にInjectの必要がなくなり、設定ファイル書かなくても作れるようになりました。 DIがシームレスに使える=意識せずともDIのメリットを享受できるように開発できる ということですね。素晴らしい。 DIコンテナは今後も自然に広く使われていくことになるでしょう。 DNS を制する者はインターネットを制す! DNS の世界/市川@cakephper report by id:MasaKu ドメイン 名ハイジャックの恐ろしさについて改めて身に染みたご発表でした。 悪意あるユーザが名前解決先のIPを書き換えてしまうため、ユーザ側としては悪意あるWebページに遷移してしまっていることを認識できません( HTTPS にも対応させることができる)。 また、この問題に気づきにくくする厄介な方法として、常に悪意あるWebページに遷移させるのではなく、10人に1人だけ悪意あるページに遷移させるなどするとより気づきにくくなります。 過去の事象として、名前解決先のIPを返す レジストラ の 脆弱性 を突かれて情報改ざんされ、MXレコードが書き換えられたせいでメールも乗っ取られた、という事件も発生したようです。 この問題は レジストラ 側の問題になるため、対策のしようがないため、 改ざんを検知したらいち早く対応するなどの運用が必要 となります。 また、 DNS の歴史についてもご説明がありました。詳しい仕様についてはこの場では割愛しますが、面白かったエピソードとして、お子さんの YouTube 閲覧時間制限のために、 DNS パケットの解析を行い、アクセス制限を追加したというお話がありました。 DNS のクエリはどのIPの利用者が何時にどのアドレスの名前解決をしたか、という情報が暗号化されずに送信されるため、プライバシー上の問題もあるようです。(お子さんのプライバシーにかかわるため、上記対策は中断したとのこと) ODoHという仕組みを利用して DNS のメッセージを暗号化する ことも現在提案されているようです。 新社会人のコード品質 カイゼン 記録 rebort by id:rakusMorita speakerdeck.com ラク スのエンジニアの発表でした。 指摘が多く、コード品質が良いとは言えない状態から、どのように品質をアップさせてきたのかの発表でした。 チェックリストも、コミット前のコードの見直しも色々やってみたところ・・・ 目立った効果がありませんでした。しかし・・・! ペアプロ / モブプロ これで、大きく品質が向上したようです。 先輩エンジニアの視点や考え方がリアルタイムでわかるので、「どういうところに気を付ければいいのか」などがわかるようになったとのことです。 「 ペアプロ をしてもらえる環境が素晴らしい」 というコメントがたくさん流れていました。 もちろん、環境も大切だと思いますが、彼の 「思い切って先輩エンジニアに ペアプロ をお願いした」 こと。 その勇気が彼の品質向上に繋がった、とても前向きになれる発表でした。 きっとチームにとっても、長い目で見て開発コストを抑えることに繋がるはずなので、 ペアプロ ・モブプロは忙しい環境こそおすすめです! あとがき このPHPerKaigi2021に参加し、エンジニアの生の声を聞き、色々な考え方に直に触れることで視野が広がりました。 エンジニアの方なら、よくググったり、書籍を読んだりすると思うのですが、やはり 現場の経験から出た使えるア イデア だったり、 調べたこともない知識をインプットできる という点で、このような勉強会は貴重ですね。 皆様のより良いPHPerライフを応援しております。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは、 id:FM_Harmony です。 iOS アプリの開発プロジェクトに参画して1年が経ち、自身の中で iOS 開発の土台が固まり、 ようやく様々な技術をキャッチアップ出来るようになりました。 そこで、今回はいま学習中のSwiftUIについて、MVVMの理解もかねて記事にしてみました。 SwiftUIについては公開されたのが2019年と新しい技術ですので、 この記事がこれから学習を始める方の参考になれば幸いです。 目次 はじめに 目次 MVVMとは SwiftUIとは アプリの概要 実装 Modelの実装 ViewModelの実装 Viewの実装 デモ おわりに 参考 MVVMとは ソフトウェア アーキテクチャ の一つです。 以下、 Wikipedia より引用します。 Model-View-ViewModel (MVVM、モデル・ビュー・ビューモデル) はUIを持つソフトウェアに適用されるソフトウェアアーキテクチャの一種である MVVMはソフトウェアをModel・View・ViewModelの3要素に分割する。プレゼンテーションとドメインを分離し(V-VM / M)また宣言的Viewを分離し状態とマッピングを別にもつ(V / VM) (中略) ### Model アプリケーションのドメイン(問題領域)を担う、そのアプリケーションが扱う領域のデータと手続き(ビジネスロジック - ショッピングの合計額や送料を計算するなど)を表現する要素である。 (中略) ### View View(ビュー)はアプリケーションの扱うデータをユーザーが見るのに適した形で表示し、ユーザーからの入力を受け取る要素である。すなわちユーザインタフェースの入出力が責務である。 (中略) ### ViewModel ViewModel(ビューモデル)はViewを描画するための状態の保持と、Viewから受け取った入力を適切な形に変換してModelに伝達する役目を持つ。すなわちViewとModelの間の情報の伝達と、Viewのための状態保持のみを役割とする要素である。 実装ではしばしば、Viewとの通信はデータバインディング機構のような仕組みを通じて行う。その場合ViewModelの変更は開発者から見て自動的にViewに反映される。 私は以下のように理解しています。 View ユーザからの入力をViewModelに伝える ViewModelの変更を画面に出力する ViewModel Viewから受け取った入力でModelを変更する Modelの変更を自身に反映する Model WebやDBにあるデータにアクセスする ViewModelによる変更を永続化する SwiftUIとは iOS 向けのUI フレームワーク で、iOS13以降で利用することができます。 宣言的に部品を記述することができるのが特徴で、 Combine フレームワーク によるイベントの通知、受信と組み合わせて、 View - ViewModel間のデータ バインディング を実現できます。 ※Combine フレームワーク もiOS13以降で利用することができます 個人的な感想ですが、SwiftUIを用いることで、 簡潔なコードで MVVMパターン によるアプリ実装を行えると思います。 アプリの概要 MVVM、SwiftUIの学習として、メモアプリを作ってみました。 大まかな仕様は以下の通りです。 1行のメモを追加できる 登録したメモは登録日の新しい順に表示する メモを選んで削除できる メモをすべて削除できる 実装 それでは実装内容の紹介に移ります。 今回はメモの一覧画面、メモのViewModel、メモのモデルを作成します。 また、登録したメモは Realm で端末に永続化します。 それぞれの関係性は以下の図の通りです。 MVVMに従い、ユーザの入力によりView - ViewModel間でイベント通知が行われ、 画面の再描画や永続化処理の呼び出しが自動的に行われます。 Modelの実装 具体的な実装内容の紹介に移ります。 まずは、Modelの実装です。 今回はModelに以下の役割を持たせています。 Realmからのデータ取得 Realmへの永続化処理 import Foundation import RealmSwift class Memo : Object , Identifiable { @objc dynamic var text = "" @objc dynamic var postedDate = Date() } extension Memo { private static var config = Realm.Configuration(schemaVersion : 1 ) private static var realm = try ! Realm(configuration : config ) static func findAll () -> Results < Memo > { realm.objects( self ) } static func add (_ memo : Memo ) { try ! realm.write { realm.add(memo) } } static func delete (_ memo : Memo ) { try ! realm.write { realm.delete(memo) } } static func delete (_ memos : [ Memo ] ) { try ! realm.write { realm.delete(memos) } } } ViewModelの実装 次はViewModelの実装です。 出力としてViewに表示するメモの一覧を、入力としてメモに登録するテキスト、削除するメモ、 全削除の処理が行われたかという状態を持たせています。 各プロパティには @Published を付けることで、値の変更が行われた際に、 変更されたことを通知できるようにしてあります。 また、 AnyCancellable 型のプロパティを持たせることで、 @Publish なプロパティの変更が行われた際に、ViewModelで自動的に永続化処理が始まるようにしています。 import Foundation import Combine class MemoViewModel : ObservableObject { @Published private ( set ) var memos : [ Memo ] = Array(Memo.findAll()) @Published var memoTextField = "" @Published var deleteMemo : Memo? @Published var isDeleteAllTapped = false private var addMemoTask : AnyCancellable? private var deleteMemoTask : AnyCancellable? private var deleteAllMemoTask : AnyCancellable? init () { addMemoTask = self . $memoTextField .sink() { text in guard ! text.isEmpty else { return } let memo = Memo() memo.text = text self .memos.append(memo) Memo.add(memo) } deleteMemoTask = self . $deleteMemo .sink() { memo in guard let memo = memo else { return } if let index = self .memos.firstIndex(of : memo ) { self .memos.remove(at : index ) Memo.delete(memo) } } deleteAllMemoTask = self . $isDeleteAllTapped .sink() { isDeleteAllTapped in if (isDeleteAllTapped) { Memo.delete( self .memos) self .memos.removeAll() self .isDeleteAllTapped = false } } } } Viewの実装 最後にViewの実装です。 Viewは MemoListView と MemoRowView に分けており、 前者がメモの一覧を、後者が登録したメモの表示を行っています。 MemoListViewではViewModelで @Published を付けたプロパティを受け取り、 Listを再描画できるようにしています。 また、ユーザ操作により、 @Published を付けたプロパティの変更を行い、 プロパティ変更の通知からViewModelの処理が自動的に始まるようにしています。 import SwiftUI // MARK : MemoListView struct MemoListView : View { @ObservedObject var viewModel = MemoViewModel() @State private var isMemoTextFieldPresented = false @State private var isDeleteAlertPresented = false @State private var isDeleteAllAlertPresented = false @State private var memoTextField = "" var body : some View { NavigationView { VStack { if (isMemoTextFieldPresented) { TextField( "メモを入力してください" , text : $memoTextField ) .textFieldStyle(DefaultTextFieldStyle()) .keyboardType(.asciiCapable) } List { ForEach(viewModel.memos.sorted { $0 .postedDate > $1 .postedDate }) { memo in HStack { MemoRowView(memo : memo ) Spacer() // Buttonにすると行全体にタップ判定がついてしまったので、Text.onTapGestureを代わりに使っている Text( "削除" ).onTapGesture { isDeleteAlertPresented.toggle() } .padding() .foregroundColor(.white) .background(Color.red) } .alert(isPresented : $isDeleteAlertPresented ) { Alert(title : Text ( "警告" ), message : Text ( "メモを削除します。\nよろしいですか?" ), primaryButton : .cancel(Text( "いいえ" )), secondaryButton : .destructive(Text( "はい" )) { viewModel.deleteMemo = memo } ) } } } } .navigationTitle( "メモの一覧" ) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement : .navigationBarLeading) { Button( "全削除" ) { isDeleteAllAlertPresented.toggle() } .disabled(viewModel.memos.isEmpty) } ToolbarItem(placement : .navigationBarTrailing) { Button( "追加" ) { if (isMemoTextFieldPresented) { viewModel.memoTextField = memoTextField memoTextField = "" } isMemoTextFieldPresented.toggle() }.disabled(isMemoTextFieldPresented && memoTextField.isEmpty) } } .alert(isPresented : $isDeleteAllAlertPresented ) { Alert(title : Text ( "警告" ), message : Text ( "全てのメモを削除します。\nよろしいですか?" ), primaryButton : .cancel(Text( "いいえ" )), secondaryButton : .destructive(Text( "はい" )) { viewModel.isDeleteAllTapped = true } ) } } } } // MARK : MemoRowView struct MemoRowView : View { var memo : Memo var body : some View { VStack(alignment : .leading) { Text(formatDate(memo.postedDate)) .font(.caption) .fontWeight(.bold) Text(memo.text) .font(.body) } } func formatDate (_ date : Date ) -> String { let formatter = DateFormatter() formatter.dateStyle = .long formatter.timeStyle = .medium formatter.locale = Locale(identifier : "ja_JP" ) return formatter.string(from : date ) } } メイン部分では MemoListView を作成し、アプリ起動時にメモの一覧が表示されるようにしています。 import SwiftUI @main struct DemoApplicationApp : App { var body : some Scene { WindowGroup { MemoListView() } } } デモ 作成したアプリのデモ動画です。 概要に記載した操作が行えることを確認いただけるかと思います。 おわりに メモアプリ作成を通じて、SwiftUI、MVVMの知見が得られました。 元々、業務では MVC による iOS アプリ開発 を行っていましたが、 SwiftUIによる実装は画面の再描画を意識する必要が無くなり、処理が見通しやすくなったと感じました。 SwiftUIについては学習し始めたばかりなので、これからもキャッチアップを進めていこうと思います。 参考 Model View ViewModel - Wikipedia SwiftUIの概要 - Xcode - Apple Developer iOS13.3 @Publishedでの値更新からsinkが呼ばれなくなった?(ミス解決) - Qiita エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは。 株式会社 ラク スで先行技術検証をしたり、ビジネス部門向けに技術情報を提供する取り組みを行っている「技術推進課」という部署に所属している鈴木( @moomooya )です。 ラク スの開発部ではこれまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「 開 ( か ) 発の 未 ( み ) 来に 先 ( せん ) 手をうつプロジェクト(通称:かみせんプロジェクト)」 改め 「技術推進プロジェクト」 というプロジェクトがあります。 2020年度は通年で「無停止リリース」について取り組んでいるので、途中ではありますが紹介したいと思います。 今までの記事はかみせんカテゴリからどうぞ。 tech-blog.rakus.co.jp これまでの無停止リリースへの取り組み 前提 無停止の定義 想定している運用 検討したシステム構成 全体像 ポイント説明 DBプロキシにMariaDB MaxScaleを採用 WEBプロキシにApacheを採用 検証方法 負荷のかけ方 シナリオ説明 ミドルウェアのバージョンアップ アプリケーションとDB定義のアップデート 検証結果 残された懸念 立ち上げ時にどうするか まとめ これまでの無停止リリースへの取り組み これまで本ブログでも無停止リリースに関する記事を公開してきました。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp 今回これらを踏まえた上で検証結果をまとめることができたので改めて公開していきたいと思います。 前提 無停止の定義 ここでいう『無停止』とはエンドユーザーから見てサービスが止まっていないことを指します。 冗長化 されたサーバー クラスタ のうち、再起動のために片系が停止するといったケースは許容します。 想定している運用 サービスカットオーバーから一度も停止せずに運用していく、といったことは目指しません。技術的にはできないこともなさそうですが、そこから発生する制約やコスト増などを考慮するとBtoBのビジネスを展開している弊社としては割に合いません。 目指している運用としてはほぼ毎回リリースのたびにサービス停止を伴っている現状から、年1回程度のサービス停止を伴うメンテナンスリリースと年数回~十数回のサービス停止が不要な通常リリースという運用に切り替えていければと考えています。 検討したシステム構成 全体像 システム構成自体は適用可能なサービスが多くなるよう、あまり特殊な構成にならないようにしました。DBプロキシの前段にクエリキューイングのレイヤを入れるなどすると、より対応可能な範囲が広がりそうではありましたが機能レイヤの追加コストと、必ず必要になるほどではないと考えて今回は見送っています。 アーキテクチャ 全体像 ポイント説明 DBプロキシに MariaDB MaxScaleを採用 DBのプライマリ、 セカンダリ の入れ替えなどを制御するためにDBプロキシとして MariaDB MaxScale を採用しました。 弊社のDBは PostgreSQL が多いのですが、 DBMS 自体がオンライン DDL への対応など無停止に向けた機能が充実していたため MariaDB + MariaDB MaxScaleの構成を採用しています。 既存サービスへの適用として PostgreSQL に適応させたDBプロキシについても後述します。 WEBプロキシに Apache を採用 昨今 nginx が優勢になり Apache が過去のものという印象も多いかと思いますが、今回改めて再評価したところ Apache 2.4を採用することにしました。 Apache 2.2の頃までは1プロセスシングルスレッドでプロセスがたくさん立ち上がるせいでメモリ大食いという印象でしたが、今では1プロセスマルチスレッドで動作させることができるのでメモリ消費は大幅に抑えられています。 そして決め手となったのは、 下流 ノード(APサーバー)の死活チェックを業務リク エス トと別でチェックすることができる、Active Health Checkが利用可能ということでした(nginxにもあるけど有償版が必要でライセンスが結構高い)。これを利用することによりAPサーバーの切り離しや復旧を、リク エス トを取りこぼすことなく行うことができるようになります。 検証方法 リリース作業をHTTPリク エス ト負荷をかけた状態で行って、HTTPリク エス ト負荷にエラーレスポンスが含まれないことを目標に検証しました。 負荷のかけ方 負荷は JMeter で、認証、参照、更新の処理を用意して、秒間10リク エス トの低負荷状態と秒間100リク エス トの高負荷状態のパターンで検証しました。 JMeter の使い方については弊社ブログのこちらの記事もご参照ください。 tech-blog.rakus.co.jp シナリオ説明 検証したリリースシナリオは2つ。 ミドルウェア のバージョンアップ APサーバーの ミドルウェア と DBMS のアップデートを行います。これらは必ず再起動が必要となります。OSのアップデートについてもこのパターンでカバーできると判断しています。 処理中のリク エス トを欠損させることなく、切り離しと復旧を行う必要があります。 操作は以下のように行いました。 DB 2号機 切り離し DBMS アップデート 復帰 DB 1号機の降格とDB 2号機の昇格 DB 1号機 切り離し DBMS アップデート 復帰 AP 2号機 切り離し ミドルウェア アップデート 復帰 AP 1号機 切り離し ミドルウェア アップデート 復帰 APサーバーについては1号機2号機の違いは特にないので入れ替えても問題ないかもしれません。 4のDB昇格/降格については MariaDB MaxScaleの switchover コマンドを用いました。 アプリケーションとDB定義のアップデート APサーバー上のアプリケーションバージョンのアップデートとDB上のテーブル定義変更を行います。また、アプリケーションは予期せぬリスクを考慮して本番環境でのホットリロードは行わず再起動を行います。テーブル定義変更は再起動を伴わずに実施します。 操作は以下のように行いました。 プライマリDBにテーブル定義変更の SQL ( DDL )を投入 ( セカンダリ DBには レプリケーション により自動反映) AP 2号機 切り離し ミドルウェア アップデート 復帰 AP 1号機 切り離し ミドルウェア アップデート 復帰 テーブル定義変更は以下の制約があります。 アプリケーション設計時の場合分け表 検証結果 おおむね期待通りに動かすことができたのですが…… 『DBのプライマリ、 セカンダリ の入れ替え時に1秒だけ書き込みエラー』 1つ目のシナリオにて、DBサーバーのプライマリ、 セカンダリ の昇降格処理中に書き込みクエリに対してのみ1秒弱のエラーが発生しました。 MaxScaleが持つコネクションエラー時にリトライするオプションなど(delayed_retryやtransaction_replayなど)を試してみたものの解消することはできませんでした。 試行錯誤の結果、DB 3台によるマルチマスタ構成にすることで解決できました。ただし、マルチマスタ構成の場合でもすべてを解決できるわけではなく、フェイルオーバー時には考慮が必要です。 残された懸念 マルチマスタ構成でも通常Write可能なノードは1つに限られていますが、フェイルオーバーが発生すると別のノードがWrite可能なノードに昇格します。このとき レプリケーション が完了してから昇格できれば良いのですが、 レプリケーション 完了前に レプリケーション 対象のレコードへの書き込みが発生していると不整合が起きてしまいます。 ノード1のレコードAを更新 ノード1が切り離され「ノード1の更新内容をノード2, 3に同期」する前にノード2が書き込み可能に昇格 ノード2のレコードAを更新 1と3のレコードAの状態に不整合が生まれノード1は自動復旧できない といった状況です。 このような状況を避けるために 共同編集機能の制御 システムからの更新を追記型にする など、特定の機能に対しては設計時に考慮が必要になります。 立ち上げ時にどうするか オンプレで構築する場合は2台か3台かのコストの違いが大きいので、アクセスが少ないうちは従来どおりの2台構成+DBプロキシ(今回はMaxScale)といったDB構成が良いと思いますが、 クラウド などの仮想基盤上に構築するのであればストレージ設計は要注意(合計サイズが1.5倍)ですが、最初から3台構成にするのが良いと感じました。 DB以外の構成は適宜サービスごとに改変して使うものの、先述の構成図の通りで問題ないと思います。 まとめ 完全な無停止運用(サービス停止を一切しない)を目指さず、停止を伴うメンテナンスリリースを何度かに1回計画することを前提とすれば、それほど特殊な構成にすることなく無停止リリースはできそうでした。 今回はオンライン DDL への対応が進んでいる MySQL 系統の MariaDB で検証を進めていましたが、以下の記事でも検証している通り、オンライン DDL に対応していない PostgreSQL でも気をつければ実用上は問題なさそうだったので、 PostgreSQL + HAProxy + Patroniなどの構成でも実現できそうな可能性が見えてきました(弊社既存サービスは PostgreSQL 採用率が高いので PostgreSQL が使えると嬉しい)。 tech-blog.rakus.co.jp 引続きHAProxyなどの活用も含めてユーザーの利便性向上を目指していきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
目次 目次 はじめに 結論 前提 TypeScript、Vue.jsで躓いた点 コンポーネント指向の入りやすさ SPA開発の入りやすさ フロントエンド、バックエンド、デザイナーが分かれている難しさ 開発を通じて感じたこと 半年間の反省 最後に 参考 はじめに こんにちは。新卒のmtaaaです。 プロダクト開発にフロントエンドエンジニアとして参加して半年が経とうとしているので、「新卒エンジニアとして」と、「フロントエンドエンジニア」としての2つの視点から感じたことをお話したいと思います。エンジニアを志す学生の方や、私と同じ新卒エンジニアの方に届けば幸いです。使用技術はTypeScript、Vue.jsがメインになります。これらの技術の突っ込んだ話はあまりしないので軽い気持ちで読んでみてください。 結論 後ろはかなり文章量があるので先に結論を言ってしまうと、「新卒エンジニアにとってフロントエンド開発はとても入りやすい」です。詳しくは後述しますが、私が参加したプロダクトが「Vue.jsを採用しているSPA」というのが大きな理由となっています。個人的にエンジニアとしての第一歩として、フロントエンドという選択肢はお勧めしたいです。 前提 最初に私がプロダクトに参加する前の学習期間にどんなことをしていたか軽くお話します。入社後2ヶ月程の Java を中心とした研修の後に配属、その後さらに2ヶ月かけて JavaScript 、TypeScript、Vue.js、Vuex、SCSSといった技術を学習、プロダクトに少しずつ参加していきました。 それまでに上記の技術に触れたことはほとんどなく、 JavaScript をかじった程度でした。これらに限らず自分のプログラミングのスキルは入門者レベルで、これからやっていけるかという不安もありました。 学習方法としては基本的に各公式ドキュメントを読み進め、わからない箇所を調べたり、先輩に教えていただいたりする形を繰り返していました。 また、プロダクトは昨年初リリースしたばかりの新しい商材です。 TypeScript、Vue.jsで躓いた点 まずはメインとなる技術2つを学ぶ上で躓いた点から話していきます。フロントエンドの難しいところとして他の領域に比べて技術の移り変わりが早いために書籍があまり出版されていなかったり、調べた情報が既に古いものだったりする点があります。 TypeScriptはざっくり言うと「 JavaScript に型付けができる言語」のことです。型の違いによるエラーにコーディング時点で気付くことができ、可読性も上がりやすいです。学習は「こういうものなのか」という感覚で比較的スムーズに行っており、わからない点も実際に書く時に調べていけばそれほど困ることはないという印象でした。どちらかと言えば JavaScript と共通の基本文法の知識不足で困ることの方が多いです。 Vue.jsはざっくり言うと「 JavaScript のデータとHTML要素を同期させるための フレームワーク 」です。同じ目的の フレームワーク では有名なものにReact.jsやAngular.jsがあります。中でもVue.jsは日本語の情報が多く公開されており学習しやすいメリットがあります。こちらは学習当初から難航していました。特に ライフサイクル 、 親子関係 、 コンポーネント指向 、 Vuex といった部分に躓き、これらは今でもわからなくなっては調べ直す、を繰り返しています。本記事では脇道に逸れるので詳しくは書きませんが、Vue.jsを勉強してみたいという方はこのあたりの単語を1度調べてみてもいいかもしれません。学習コストが低い、という話をよく見かけますし実際に長期間かけたわけではありませんでしたが、少なくとも私個人としては簡単に理解できたとは言い難いです。 コンポーネント 指向の入りやすさ 学習面では難しい面ばかり書きましたが、私はこの フレームワーク を取り入れた開発は新人が入りやすい形式だと考えています。大きな理由の1つとしてVue.jsの コンポーネント 指向があります。先ほども話に上がった コンポーネント 指向をざっくり言うと、「ページの コンポーネント (パーツ)を準備しておいてその組み合わせでWebページを作り上げること」です。そして私が参加した時点で既に コンポーネント の基盤は作られており、 コンポーネント を組み合わせるだけでひとまずそれらしい見た目のものが作れることは、シンプルに開発の楽しさやモチベーションに繋がりました。 SPA開発の入りやすさ Vue.jsを採用した開発に新卒エンジニアが入りやすかった大きな理由の2つ目としてSPA(Single Page Application)という設計を採用していたことがあります。SPAは「1つのページの必要な箇所のみ変更して画面の切り替えをする アーキテクチャ のこと」です。具体的には最初のページ遷移で全体の情報を取得し、あとはユーザーの操作によって変更する情報だけをサーバーとやり取りします。この形式におけるフロントエンドエンジニアの役割は、「バックエンドと情報をやり取りし、その結果をデザインに沿ってページに反映させること」です。極端なことを言ってしまうと、サーバーから返ってくる情報をデザイン通りに表示すれば最低限は作れます。つまり、小規模な改修のような案件に着手できるようになるまでがかなり早いです。 フロントエンド、バックエンド、デザイナーが分かれている難しさ 私が参加しているプロダクトではデザイナー、フロントエンド、バックエンドが比較的きっちり分かれており、最も重要かつ難しいのはコミュニケーションです。フロントエンドエンジニアは他領域のメンバー間の橋渡し的な役割もあるためコミュニケーションは大事になります。1つのものを作るにあたって領域ごとに違う人が担当する以上細かい認識のずれはどうしても発生してしまうため、手戻りが起こることもあります。これを少しでも減らすには仕様の共有はもちろんですが、なによりコミュニケーションを取りやすい文化が大切だと感じています。 また今はフロントエンドの開発で手一杯ですが、他領域についてもある程度わかっていた方が会話がスムーズに進みますし、相手の意図も汲みやすいので、デザインやバックエンド、インフラについても勉強したいと感じています。フロントエンドの学習に集中することで早くにプロダクトに参加していけるメリットはありますが、やはり最終的には吸収する必要があります。 開発を通じて感じたこと 学習期間中にあまり意識していませんでしたが実務で重要なものとして、 Google Chrome の デベロッパ ーツールを使いこなすことと、レビューされることを意識してコーディングすることがあります。 デベロッパ ーツールはフロントエンドの開発においては本当に必要不可欠です。プロダクトに入るまでは「ログを仕込んで確認する」程度の認識でしたが、サーバーからのレスポンスの確認、styleがどの要素に正しく当たっているか、いないかの確認に加えてなんと言っても 拡張機能 の Vue.js devtools が大きな助けになりました。この 拡張機能 では各ページでどんな コンポーネント を使っているか、どんな値が渡っているかを確認したり、直接書き換えて挙動を見たりしながら実装することができます。ページの特定の部分がどんな コンポーネント で構成されているのか直感的に調べることができるので、プロダクトのソース全体の理解もかなり楽になりました。 レビューされることを意識したコーディングも重要です。これはフロントエンドに限った話ではありませんが、他のメンバーや未来の自分が見て何をしているかわかりやすいコードは相当意識してもなかなか作れないです。 フレームワーク の思想を汲み取ることやプロダクト特有の文化、書き方に合わせることも覚えておきたいです。 また、私は学習面での不足がある段階からプロダクトのソースと挙動を見つつ、小さなバグ対応等からプロダクトに参加する所謂 OJT 形式にすぐに入りました。個人差があるとは思いますが、「習うより慣れろ」というのは大きく、自分自身開発業務の中で成長を感じられましたし、やはり動くものを作ってそれがリリースされるというのは嬉しいです。実務に必要な技術を都度学びながら進めるため回り道なく身に付きます。 半年間の反省 知識不足は当然多いですが、中でも以下は重きを置いて業務や学習に取り組むべきでした。 環境構築は特に勉強不足を感じています。エンジニアとして自分の作業環境をしっかり把握しておきたいですが、参加当初の環境構築以降ほとんど触ることもなかったため、問題が起きた際に原因や対処法に検討が中々つかないです。少なくとも Node.js の知識は深めておきたいです。 次に設計についてです。特にソースの設計は実務に入るまで意識がそもそもなく、コードレビューの中で指摘いただくことも多かったです。具体的にはどのメソッド、ファイルにどれだけの責任を持たせるかやクラスの枠組みといったところは、ただ動くだけではいずれバグの原因になる恐れがあります。ここは学業と仕事とで大きく違う点です。 今までなんとなくで捉えていた単語や技術がそのままになっていることも挙げられます。プロダクト特有の単語もあり、1度調べたり質問したりするだけでは数ヶ月後には忘れてしまっているものです。取ったメモは読み返すことがとても大事です。今もこの記事を書きながら再確認しています。 これらは来年度に解消していきたいですね。 最後に フロントエンドという分野が特に注目されたのはこの数年のことで、専門的な技術者が他の領域に比べて少ないです。そのため、長い目で見て新卒エンジニアにもチャンスのある領域だと思います。もし興味の出た方は是非チェックしてみてください。今回はVue.jsを使ったSPA開発で新卒エンジニアがプロダクトに入っていきやすかった点とその理由、逆に難しかった部分や、開発で得た教訓について話してみました。ここまで読んでいただきありがとうございました。 参考 JavaScript Primer - 迷わないための入門書 #jsprimer TypeScript Deep Dive 日本語版 - TypeScript Deep Dive 日本語版 はじめに — Vue.js Vuex とは何か? | Vuex Vue.js の Composition API における親子コンポーネント間のデータ受け渡し - Qiita フロントエンドのコンポーネント設計に立ち向かう - Qiita Node.jsとはなにか?なぜみんな使っているのか? - Qiita エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
目次 はじめに スキルマップ HTML CSS JavaScript SPA(Single Page Application) JavaScriptフレームワーク パッケージ管理 TypeScript Git Linux Web知識 テスト ブラウザ コーディングルール Docker(必須ではないが知っておくと良い) 情報収集に使えるWebサイト(おまけ) まとめ おわりに はじめに こんにちは、フロントエンドチームの北嶋です。 弊社でフロントエンドチームを立ち上げてから1年以上が経ち、少しずつメンバーも増えてきました。 最近は来年度の新卒メンバーに対する育成プランを考えているのですが、昨今のフロントエンド技術は移り変わりも激しく、学ぶべき項目が多岐に渡っているため、育成プランを考えるのも一苦労です。 ネットでフロントエンド関連の情報を調べると、今では参考にならない古めの記事も多いですし「これではフロントエンド初学者は何を勉強すれば良いのか分かりにくいだろうなぁ」という気持ちでいます。 そこで、 最近のフロントエンド初学者が身に付けておくべきスキルって具体的に何があるのだろう という疑問に対する答えをスキルマップという形で整理してみましたので、今回は皆さんに共有したいと思います。 特に、駆け出しフロントエンドエンジニアの方やフロントエンドの教育担当者の皆さんの力になれればと思いますので、是非参考にしてみて下さい! スキルマップ フロントエンド初学者(駆け出しフロントエンドエンジニア)が身に付けておくと良い技術のまとめです。 基本的には WEB DEVELOPER Roadmap 2021の Frontend Roadmap のトレンドに沿うように考えられていますが、個人的な意見も多いに反映されています。 目標レベル・学習項目・参考資料という3つの観点でまとめています。 目標レベル:現場に入っても問題なく業務をこなせるレベル感(脱駆け出しエンジニア程度のイメージ)を記載しています。 学習項目:理解しておくべき項目・用語を記載しています。 参考資料:目標レベルを満たすために参考となる資料(書籍・Webサイト等)を記載しています。 フロントエンドエンジニアとしてだけでなく、Webエンジニアとして身に付けておきたい技術も含まれています。 OSS -DBを入れるかが迷う所でしたが、実際に業務していて触れる機会が多くないのでひとまずドロップしています。将来的にはWebエンジニアとして理解しておいて欲しい項目ではあります。 1. HTML 目標レベル 基本的なタグを利用したHTMLの記述が行える 発展的なタグを把握している 学習項目 HTML5 参考資料 Webサイト HTML の学習: ガイドとチュートリアル - ウェブ開発を学ぶ | MDN HTML5リファレンス 2. CSS 目標レベル CSS で簡単なスタイル指定が行える SCSSで簡単なスタイル指定が行える 詳細度を理解している 学習項目 CSS3 擬似クラス Flexbox Sass 詳細度 参考資料 書籍 Web制作者のためのCSS設計の教科書 Web制作者のためのSassの教科書 Webサイト CSS - ウェブ開発を学ぶ | MDN 100年後も崩れないCSS勉強会 · 第1回「詳細度」 3. JavaScript 目標レベル ES2015以降の記法で JavaScript を記述できる API 通信を行うコードを記述できる 非同期処理を理解している 学習項目 ES2015以降の記法 Promise async/await API 通信 ESモジュール 参考資料 Webサイト JavaScript | MDN JavaScript Primer - 迷わないための入門書 #jsprimer JavaScript Promiseの本 Udemy 【JS】ガチで学びたい人のためのJavaScriptメカニズム | Udemy 4. SPA(Single Page Application) 目標レベル SPAの概念を理解している SSR ・SSGとの違いを理解している 学習項目 SPA SSR SSG 参考資料 Webサイト ようこそ!2020年、Webフロントエンドの世界へ SPA, SSR, SSGの違いについて図解でまとめてみた 5. JavaScript フレームワーク 目標レベル コンポーネント 指向の概念を理解している Vue.js(または React.js)の公式ガイドを基本的な部分を理解している 状態管理(Flux)の概念を理解している ルーティングの機能を理解している 上記の技術を用いて簡単な アプリ制作 が行える 学習項目(Vueのみ記載) Vue.js Vuex Vue Router 参考資料(Vueのみ記載) Webサイト Vue.js公式 書籍 基礎から学ぶVue.js Vue.js入門 基礎から実践アプリケーション開発まで Udemy 超Vue.js 2 完全パック (Vue Router, Vuex含む) | Udemy Vue.js + Firebaseで作るシングルページアプリケーション | Udemy 6. パッケージ管理 目標レベル nodeの概念を理解している npmの基本的なコマンドを利用できる パッケージ管理システムを利用してプロジェクト作成が行える パッケージ管理システムでパッケージの追加・削除が行える 学習項目 node npm package. json 参考資料 Webサイト 【初心者向け】NPMとpackage.jsonを概念的に理解する 7. TypeScript 目標レベル プリミティブ型の型指定が行える 簡単なオリジナルの型を作成し、型指定を行える 外部ライブラリの型を利用できる 学習項目 TypeScriptの概念理解 型の種類 型の指定 型の作成 参考資料 書籍 プログラミングTypeScript Webサイト 仕事ですぐに使えるTypeScript TypeScriptの型入門 - Qiita TypeScript Deep Dive Udemy 【世界で7万人が受講】Understanding TypeScript 日本語版 | Udemy 8. Git 目標レベル Gitの概念を理解できている 基本的な操作が一通り行える 複数人でのGit運用を経験している 学習項目 概念理解 基本的な操作方法 参考資料 Webサイト サル先生のGit入門〜バージョン管理を使いこなそう〜 9. Linux 目標レベル Linux の基本的なコマンドを利用できる 学習項目 基本的コマンド ファイル操作系 ssh 参考資料 Webサイト 【Linux入門】コマンドライン初心者のための基礎とサンプル | UX MILK オプション含めたsshコマンドの使い方 【Linuxコマンド集】 10. Web知識 目標レベル Web開発で必要な最低限の知識を持っている 学習項目 Web知識 HTTP REST セキュリティ知識 IT知識( 基本情報技術者 レベル) 参考資料 書籍 栢木先生の基本情報技術者教室 WEBを支える技術 体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 Webサイト IT用語辞典 11. テスト 目標レベル テストの種類を把握している テストの種類ごとの目的を理解している 学習項目 テストの種類・目的 Jest 参考資料 Webサイト 【フロントエンド】コンポーネント指向(React, Vue)のテスト方針 - Qiita 12. ブラウザ 目標レベル ブラウザごとに動作に差異があることを理解している Chrome の開発者ツールの基本機能を利用できる 学習項目 ブラウザ差異 開発者ツールの使い方 Vue.js DevTools 参考資料 Webサイト Can I use... Support tables for HTML5, CSS3, etc Chrome DevTools の使い方 | murashun.jp Vue Devtools で快適なデバッグ - ROXX開発者ブログ 13. コーディングルール 目標レベル 良いコード、悪いコードの特徴を把握している 学習項目 特になし 参考資料 書籍 リーダブルコード ― より良いコードを書くためのシンプルで実践的なテクニック プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原 14. Docker(必須ではないが知っておくと良い) 目標レベル 仮想化の概念を理解している Dockerと VirtualBox の違いを理解している Dockerのメリットを説明できる 学習項目 仮想化 ホスト型 ハイパーバイザ型 コンテナ型 参考資料 Webサイト Dockerとは何か?初心者にもわかりやすく仕組みやメリットを解説 | キツネの惑星 15. 情報収集に使えるWebサイト(おまけ) JSer.info Qiita Zenn|エンジニアのための情報共有コミュニティ Github の リポジトリ の月間トレンド Trending JavaScript repositories on GitHub this month · GitHub Trending TypeScript repositories on GitHub this month · GitHub まとめ 機械的 にスキルを並べる形となってしまいましたが、参考になりましたでしょうか。 ざっくりまとめると、フロントエンド初学者の学習ロードマップとしては以下のような手順で学んでいくのが良さそうだと思いました。 HTML/ CSS / JavaScript を学ぶ JavaScript フレームワーク (Vue.jsまたはReact.js)を学ぶ パッケージ管理(node,npm)について学ぶ JavaScript のES2015以降の記法を学ぶ TypeScriptを学ぶ Web開発に必要な知識を身に付ける Web開発で必要なツールの使い方を学ぶ(Git, Linux ,ブラウザの開発者ツール等) フロントエンドのテストを理解する 一般的なコーディングルールを把握する おわりに 自分でまとめてみても「こんなに学習項目があるんだな・・・」と思ってしまったのですが、一つの指標というだけで、現場に入る前に全てを完璧に身に付けておかないといけない訳でもありません。 実際に自分自身も現場に入ってから少しずつ身に付けていった項目もありますし、業務で必要になったタイミングで学ぶ方が身に付くことも多かったりします。 ただ、このようなスキルマップを参考にすることでフロントエンド初学者の方が「この項目のスキルは自分に足りていないな」といった気付きが少しでもあれば嬉しく思います。 それでは、ここまで読んでいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは ラク ス開発エンジニアのhyoshです。 今回は久しぶりのFirebaseシリーズを投稿いたします。 過去Firebaseの多様なソリューションからチャット(RealTime Database)、認証(Authentication)とご紹介してきましたが今回はプッシュ通知(Firebase Cloud Messaging)に携わる機会がありましたのでご紹介させていただきます。 過去の投稿はよろしければ以下もご覧ください。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp Firebase Cloud Messagingについて できること 利用することによるメリット サンプル実装 Firebaseプロジェクトの作成 FCMをアプリに登録 クライアントの実装 メッセージを送ってみる フォアグラウントで通知を受け取れるようにする HTTPで通知を送ってみる まとめ Firebase Cloud Messagingについて できること Firebase Cloud Messaging(以降FCM)はFirebaseのソリューションの一つで、利用することでプッシュ通知を簡単に実現できます。 下図は 公式ガイド に記載されているFCM アーキテクチャ ですが、プッシュ通知は主にメッセージの作成(1)、転送(2,3)、受信(4)という流れで処理されます。 例えば特定タイミングでユーザーにキャンペーン情報を通知したいといったケースを考えた際、これらを全て自前で実装するとなるとかなり敷居が高くなる事は想像がつくでしょう。 一方でFCMを用いれば根幹となる1,2,3をバックエンドでFCMが実施してくれるため、開発者に必要なのはクライアントの軽微な実装のみ(※1)となり複雑な処理の中身を意識する必要がありません。 ※1…実際の開発現場では後述のように1に関しても個別実装するケースが多いかと思いますが、それでもFCMを利用することで自前で行うよりずっと簡易に行えます。 利用することによるメリット FCMを利用してプッシュ通知を実現するメリットですが、私は以下の点を感じています。 バックエンド処理の実装が不要 OSの違いを吸収してくれる( クロスプラットフォーム 対応) 導入・運用コストが低く経済的 1は先にお話した通りで、プッシュ通知を実現するにあたっての煩雑な処理は全てFCMが担当してくれるので、開発者はクライアント実装のみに注力すればよくなります。 2はFCM公式でも強く打ち出している特徴で、 iOS であっても Android であってもメッセージの作成、転送までは同じ処理を共有できるいわゆる 「 クロスプラットフォーム 」 な開発が行えます。 各端末のアプリで実施される受信処理はそれぞれのOSで実装は必要ですが、それでも各OS毎に行う作業はグッと減らせます。 そして3の特徴ですが、これだけ充実したサポートを誇っていながらFCMを利用することでかかるコストは下記の通り 無料 です。 firebase.google.com よくありがちな特 定量 から課金という事もなく、 何通送っても0円です (※2)。 後ほどサンプルで紹介もしますが、導入も非常に容易なのでありがたい限りですね。 これらのことから現在プッシュ通知実装に関し、まずFCMの名前が出てくるのも納得の理由かと感じていただけるかと思います。 ※2…2021年3月時点の情報であり、今後変更となる可能性はあります。 サンプル実装 FCMがバックエンドを担当してくれると言っても実態がイメージしづらいと思うので、ここからは実際に Android で簡単な通知を受け取れるサンプルアプリを作っていきたいと思います。 ※ 公式ガイド をベースとしているため、合わせて参照ください。 Firebaseプロジェクトの作成 まずは表示されているガイドに沿ってFirebaseにてプロジェクトを作成していきます。 1.一意となる任意のプロジェクト名称を入力します。 2. Google アナリティクスを利用することでより効果的にFirebaseのソリューションを使うことができますが、ここではひとまず利用しないでプロジェクトを作成します。 これでプロジェクト作成は完了となり、コンソール画面が表示されます。 FCMをアプリに登録 続いて作成したプロジェクトをアプリに登録し、互いをひもづけます。 1.コンソールの左メニューよりCloud Messagingをクリックし、 Android アイコンを押して設定画面に進みます。 設定は親切なガイドが表示されているので、それに従って進めていきます。 クライアントの実装 ここまででFCM側の作業は完了したので、次に通知を受信するためのクライアント側の実装を行っていきます。 1.FCMでは トーク ンという情報を用いて端末を一意に識別します。 トーク ンの実態は端末とアプリの組み合わせで一意となる文字列情報となり、これをFCMで認知できている事で狙った端末に通知が送れるという仕組みになっています。 もちろん重要情報なので取扱いには重々注意が必要となります。 トーク ンを発行するサービスがFCMから提供されているので次のように実装していきます。 // build.gradle(:app)にFCMライブラリを追加 dependencies { implementation platform( 'com.google.firebase:firebase-bom:26.7.0' ) implementation 'com.google.firebase:firebase-messaging-ktx' // この一行を追加 } package com.example.notifyapplication import android.util.Log import com.google.firebase.messaging.FirebaseMessagingService class MyMessageService : FirebaseMessagingService() { override fun onNewToken(token: String ) { Log.d( "MyMessageService" , "Refreshed token: $token " ) } } 新規にFirebaseMessagingServiceを継承したクラスを作成します。 onNewTokenはFirebaseMessagingServiceに用意されているメソッドでアプリが トーク ンを発行するためにアプリ起動時に呼び出されます。 ただし毎回呼び出される訳ではなくまだ一度も トーク ンを発行していない、何らかの要因で トーク ンを更新する必要がある(※3)といったケースで限定的に呼び出されます。 ここまでできたら一度アプリを動かしてみましょう。 ログに トーク ンが出力されているかと思います。 表示されていない場合は既に発行された後の可能性があります。 そのような場合に備えてガイドでは現在の トーク ンを取得する方法も開示されているので、以下のようにMainActivityに追加してみましょう。 override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(findViewById(R.id.toolbar)) // ここから追加 FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task -> if ( ! task.isSuccessful) { Log.w( "MainActivity" , "Fetching FCM registration token failed" , task.exception) return @OnCompleteListener } // 現行のトークンを取得 val token = task.result // ログに出力 Log.d( "MainActivity" , "Current token: $token " ) }) } これでアプリ起動時に確実に トーク ンがログに出力されるようになったかと思います。 ※3…公式ではアプリを再インストールした、アプリが新しい端末で復元された、アプリのデータを消去したなどが挙げられています。 メッセージを送ってみる 実はFCMでは GUI ベースで通知を送信できる機能が用意されているので、ここまで行えばもう自分のアプリに通知を送る事が可能です。 1.FCMコンソールよりSend your first messageのボタンを押して先に進みます。 2.通知情報を入力します。ひとまず最低限必要なタイトルと本文を入力し「テストメッセージを送信」を押します。 3.ここで トーク ンの入力を求められるので、先ほどログに出した トーク ンを入力しテストボタンを押します。 トーク ンが間違っていなければアプリの動いている端末に先ほど登録した通知が届いたかと思います。 4.テスト通知でなく正式な通知として登録するために後続を進めます。 ターゲットではひとまずアプリとする事でアプリ利用者全員に通知を送信できます。スケジュール設定では送信時間や定期的に送るかを指定できます。 確認の後、公開を押します。 5.これで通知が登録できたので、スケジュール設定で指定した時間に通知が届きます。 別の通知を登録したい場合は「新しい通知」より再度登録します。 ちなみにレポートタブからは送った通知の 開封 率といったデータも見る事ができます。 このように最もシンプルなやり方でも、複数ユーザーに対して時間指定して一斉通知を送る程度であれば簡単に行える事が理解いただけたかと思います。 フォアグラウントで通知を受け取れるようにする ここまでで通知を受け取ることはできましたが、実は今の実装だけではアプリとしてはまだ不完全です。 というのも今の状態では通知を受け取る事ができるのはアプリがバックグラウンドにある状態のみで、フォアグラウンド(操作している時)の状態では通知を受け取る事ができません。 通知の目的を考えるとフォアグラウンドで受け取る必要性は低いとも言えますが、重要な通知で常にユーザーに認識してほしい局面もあるかと思いますので、少し改造してフォアグラウンドでも通知を受け取れるようにしてみましょう。 1.先ほど作成したMyMessageServiceにonNewToken同様、継承元のFirebaseMessagingServiceで用意されている onMessageReceived を実装します。 以下ではonMessageReceivedで通知を受け取り送られてきたタイトルとメッセージの通知を生成し、画面に表示します。 override fun onMessageReceived(remoteMessage: RemoteMessage) { remoteMessage.notification?.let { it -> sendNotification(it) } } private fun sendNotification(message: RemoteMessage.Notification) { val intent = Intent( this , MainActivity :: class .java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) val pendingIntent = PendingIntent.getActivity( this , 0 /* Request code */ , intent, PendingIntent.FLAG_ONE_SHOT) val channelId = getString(R.string.default_notification_channel_id) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder( this , channelId) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle(message.title) .setContentText(message.body) .setAutoCancel( true ) .setSound(defaultSoundUri) .setContentIntent(pendingIntent) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Android OS 8以降はチャネル指定が必須 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel(channelId, "チャネル説明" , NotificationManager.IMPORTANCE_DEFAULT) notificationManager.createNotificationChannel(channel) } notificationManager.notify( 0 /* ID of notification */ , notificationBuilder.build()) } -- strings.xml <resources> <string name= "app_name" >NotifyApplication< / string> //以下一行を追加 <string name= "default_notification_channel_id" >fcm_default_channel< / string> < / resources> 最後にAndroidManifest. xml にサービスを登録します。 <service android:name= ".MyMessageService" android:exported= "false" > <intent - filter> <action android:name= "com.google.firebase.MESSAGING_EVENT" / > < / intent - filter> < / service> 確認する為にコンソールよりテスト送信してみると、フォアグラウンドでも通知を受け取れるようになった事が分かるかと思います。 (分かりづらいですが左上の●が届いた通知です) このようにonMessageReceivedまで実装しておく事でバックグラウンドではFCMよりアプリを通さず直接通知を表示、フォアグラウンドではアプリ経由で通知を表示といったアプリ状態によらず常に表示が可能になります。 HTTPで通知を送ってみる 最後にオプションとしてHTTPリク エス トとして通知を送ってみましょう。 1.Firebaseコンソール−プロジェクトの設定−CloudMessagingからサーバーキーを確認します。 2.FCMの通知送信用として用意されている API は「 https://fcm.googleapis.com/fcm/send 」となるので、これに対し必要なパラメータを付与しPOSTリク エス トを投げます。 HeadersのAuthorizationのkeyには先ほど確認したサーバーキー、Content-Typeはapplication/ json を指定します。 そしてBodyにはtoに対象端末の トーク ン、notificationにタイトルと本文を指定します。 ツールなどで送信してみるとこのやり方でも端末に通知が届く事が分かるかと思います。 実際のシステムではタイミングが決まっておらず何らかの処理をトリガーに通知を送りたいといったシーンも多いかと思われますので、そのような時に活用できるでしょう。 なお今回は簡易なHTTPを用いましたが 公式ガイド で推奨されている後継の プロトコル が存在するため、可能であればそちらを使う事が望ましいです。 まとめ 今回はFirebaseを用いたプッシュ通知実装に関してご紹介させていただきましたがいかがだったでしょうか。 FCMを用いることで思ったよりも簡単に実現できることを理解いただけたのではないかと思います。 iOS との連携に関してはご紹介できませんでしたが、クライアント側の実装としてはほぼ同じとなりOS間の違いを意識することなく開発する事が可能なので、興味が湧きましたらぜひ試していただけますと幸いです。 最後までお読みいただきありがとうございました。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは、takaramです。 今回はPHPDocについて、特に 型 の重要性と、応用的で便利な書き方をご紹介したいと思います! はじめに PHPの型を使いこなしたい PHPDocとは? PHPDocの仕様 多くのツールで有効なPHPDocの書き方 型の書き方 配列型 false型 @property ローカル変数の型 まとめ おまけ:配配メール開発チームの取り組み PHP の型を使いこなしたい PHP でも近年、静的型付け言語と同じようにメソッドの引数や戻り値、クラスのプロパティなどの型宣言を書くことができるようになってきています。型宣言はPHP5.0から部分的にサポートされていましたが、本格的に使えるようになったのは2015年リリースの7.0あたりからです。 PHP 7.0: スカラー型宣言、戻り値の型宣言 PHP 7.1: nullableな型 PHP 7.4: プロパティの型宣言 PHP 8.0: union型、mixed型の追加 多くの静的型付け言語にある ジェネリクス 機能が PHP にはないなど、まだ十分とは言えない部分もありますが、このように動的型付け言語に型宣言を追加するという試みはTypeScriptや Python 、 Ruby などでも行われていて、時代の流れと言えるかもしれません。 しかしそもそも、なぜ PHP にわざわざ型を書く必要があるのでしょう?メリットとしては、以下のようなものがあります。 実行時に型チェックされる(予期しない値が渡されることを防げる) IDE で補完が効きやすくなる 静的解析がより正確に実行できる このうち実行時型チェックは、新規コードでは安心・便利な一方、型宣言のない時代のコードを引き継ぐ現場では、動いている既存コードに下手に型宣言を追加するとかえって動かなくなるというリスクも考えられます。 そのため、既存コードへの型宣言追加には二の足を踏んでいる現場も多いのではないでしょうか。 しかし、そのために IDE のコード補完などのメリットを捨ててしまうのはもったいないです。 そこで、PHPDocによる型情報の補足が重要となってきます。PHPDocは基本的にはプログラムの動作に影響しないため、型宣言にくらべると既存コードにも追加しやすいと思います。 以下ではPHPDocとその書き方について、私が担当しているプロダクト「 配配メール 」の既存コードのPHPDoc整備を進めた経験も交えて紹介していこうと思います。 PHPDocとは? そもそもPHPDocとは何か、について説明しておきましょう。そんなの知ってるよ!という方は 次のセクション まで飛ばしてください。 PHPDocとは、 PHP で書かれた下記のものについてのドキュメントを、 ソースコード のコメント内に記述するための書式、およびその書式に従って書かれたコメントを指します。 関数 定数 クラス メソッド プロパティ etc. PHPDocは /** ... */ の Docコメント という形式のコメント内に記載します。 一部のツールやライブラリはDocコメントに特定の内容を書くことで動作を変えるものもあります *1 が、基本的には単なるコメントに過ぎないためプログラムの動作には影響しないと思っていいでしょう。 例として、 psr/container の ソースコード を見てみてください。インターフェースとメソッドの説明がPHPDocで書かれていて、メソッドの引数や戻り値の説明は @param , @return のような文字列( タグ といいます)に続いて書かれているのが分かると思います。 ここでは書式の詳細な説明はしませんが、雰囲気だけでも掴んでください。 PHPDocの書式に則ってコメントを書くことは、通常のコメントと同じくチームの他の開発者や、未来の自分に向けた説明としてももちろん有用です。ただそれだけではなく、PHPDocを活用したツールが多く存在していて、それらを活用できるメリットがあります。具体的には、以下のようなツールがあります。 phpDocumentor PHPDocを元にHTML形式のドキュメントを生成してくれるツール。ライブラリのリファレンスなどで使われる。 PhpStorm PHPDocから変数等の型を検出し、コード解析、自動補完に利用する。 PHPStan , Phan , Psalm 不具合の可能性があるコードを検知してくれる静的解析ツール。引数の型の不一致や存在しないメソッド呼び出しなどを検出する。 PHPDocとこれらのツールを使いこなすことができれば、 PHP での開発を効率的に進められます。 PHPDocの仕様 このように様々なツールで利用されているPHPDocですが、実は明確な仕様というものは決まっていないのです。 言語仕様以外の PHP の標準規格を確立するPSRというプロジェクトの一部として、PHPDocの仕様 "PSR-5" の草案が作成されてはいますが、議論が中々まとまらず、2021年現在未だに標準化されていません。 そのため各ツールで有効とされる書式が微妙に異なり、「あのツールで有効な書き方がこのツールではエラーになる」といったことが発生しうる状態です。実際にPHPDocを書く際には、自分が利用するツールの仕様書や実際の動作を確認して使うのがよいでしょう。 とはいえ、どのツールも大枠の書式は一致しています。基本的な書き方をご存じない方は、 phpDocumentorのドキュメント を読んでみてください。 多くのツールで有効なPHPDocの書き方 ここからは多くのツールで有効かつ便利な、PHPDocの応用的な書き方を紹介していきます。 型の書き方 PHPDocの @param タグや @return タグ、 @var タグ等で何気なく書いている型も、より適切な書き方があるかもしれません。 配列型 PHPDocで配列型といえば普通は array ですが、それ以外にも書き方があるのをご存知でしょうか? 数値キーの配列: int[] , Clazz[] 文字列キーの配列: array<string, int> , array<string, Clazz> キーごとに値の型が異なる配列: array{id: int, name: string} 例として、名前・年齢・住所を持つHumanクラスのサンプルを下に示しています。ここに書かれているPHPDocでは、 プロパティ $propertyKeys は文字列の配列 プロパティ $property はキーが文字列、値が文字列または整数の 連想配列 コンストラクタ の引数はキー name の値が文字列、キー age の値が整数、キー address (省略可能)の値が文字列の 連想配列 であることを表しています。 <?php class Human { /** @var string[] */ private $ propertyKeys = [ 'name' , 'age' , 'address' ] ; /** @var array<string, string|int> */ private $ property = [] ; /** * Human constructor. * * @param array{ * name: string, * age: int, * address?: string * } $property */ public function __construct ( $ property ) { foreach ( $ this -> propertyKeys as $ propertyKey ) { $ this -> property [ $ propertyKey ] = $ property [ $ propertyKey ] ; } } } こうした書き方をすることで、単にarrayと書くのに対していくつかメリットがあります。 new Human(['job' => 'engineer']) のような不正な引数を静的解析で検知できる foreach ($array as $key => $value) の $key , $value の型がわかるので、 IDE で補完が効いたり、静的解析の精度が上がったりする ドキュメントとしてもわかりやすくなる int[] 形式以外の2つは残念ながらPhpStormでは未対応なのですが、静的解析ツールを利用しているならこの書き方を採用してみてください。 false型 「true か false」を表す型は bool または boolean ですが、単に true , false と書くこともできるのはご存知でしょうか? PHP の組み込み関数では、例えば file_get_contents のように、失敗したらfalseを返すような関数があります。 自作関数でもそれにならって「成功時は処理結果を、失敗時はfalseを返す」ような関数にしている場合もあると思います。そのような関数のPHPDocは、 @return string|bool よりも @return string|false と書くべきです。 もし bool と書いてしまった場合、以下のようなコードを書くと静的解析ツールに怒られます。 <?php /** * @param string $fileName * * @return string|bool */ function getContents ( $ fileName ) { return file_get_contents ( $ fileName ) ; } $ contents = getContents ( '/tmp/foo.txt' ) ; if ( $ contents === false ) { exit ( 1 ) ; } // ファイルの内容を大文字にして出力 echo mb_strtoupper ( $ contents ) ; $contents === false のときの処理もきちんとしていて、実際の動作上エラーは出ないコードですが、 getContents() の戻り値を string|bool としてしまっているため、静的解析ツールは「trueの可能性がある値を mb_strtoupper() の引数に渡している」と判断してしまうのです。 上記のコードのPHPDocを @return string|false に書き換えることで、静的解析のエラーは解消されます。 PHPStanの例。string|boolだと エラーが出る が、string|falseにすると 解消する 。 @property @property は主にクラスのPHPDocに書くタグで、 __get() , __set() を使った動的なプロパティを記述することができます。 ……という説明はググれば他にいくらでも出てくるので、今回は少し変わった使い方を紹介したいと思います。 @property を使うことで、親クラスから継承したプロパティの型を、より厳密にすることができます。 例)親クラスでDateTimeInterfaceのプロパティを、子クラスではDateTimeImmutableにする <?php class Base { /** @var DateTimeInterface */ protected $ datetime ; public function __construct () { $ this -> datetime = new DateTime () ; } } /** * @property DateTimeImmutable $datetime */ class Child extends Base { public function __construct () { $ this -> datetime = new DateTimeImmutable () ; } /** * 明日の日付を返す * * @return DateTimeImmutable */ public function getTomorrow () { return $ this -> datetime -> modify ( 'tomorrow' ) ; } } 上記の例では、Childクラスに @property DateTimeImmutable $datetime をつけることによって、 getTomorrow() メソッドのところで静的解析に怒られないようにしています( DateTimeInterface::modify は存在しないため)。 私のチームで実際に行った例としては、Webフレームワークの各クラスを継承して独自拡張しているクラスのプロパティでこれを利用しました。以下にサンプルコードを示します。 <?php namespace Framework { class Controller { /** @var Session */ protected $ session ; } class Session { } } namespace App { /** * @property Session $session */ class BaseController extends \Framework\Controller { } class Session extends \Framework\Session { public function originalMethod () : void { echo 'I am \App\Session!' ; } } class SampleController extends BaseController { public function index () : void { $ this -> session -> originalMethod () ; } } } このように、 フレームワーク の \Framework\Controller , \Framework\Session クラスを拡張し、 \App\BaseController , \App\Session クラスを作成しています。一番下で SampleController から $this->session->originalMethod() を呼び出していますが、 @property を書かない場合だと $this->session は フレームワーク 側の Session クラスだと認識されてしまい、コード補完、静的解析とも上手くいきません。 注意点として、この方法には「 @property で書いたプロパティがpublicと認識されてしまう」という欠点があります。しかしながら、上記のようなコントローラークラス等であれば、 プログラマ が自分でnewして インスタンス を扱うことはほぼ無いためあまり問題にはならないかと思います。 ローカル変数の型 PHPDocを使えば、ローカル変数にも型をつけることができます。 <?php foreach ( $ iterable as $ item ) { /** @var DateTime $item */ echo $ item -> format ( 'Y/m/d' ) . PHP_EOL; } 上記のように、foreachのループ変数の型を示す以外に、「型定義上はmixedだが人間から見ると型が明らか」という場合に便利です。 例えば下の例のように、DBのカラムから値を取得する場合「 id は integer 型のカラムだから戻り値も int だ」というのは プログラマ はわかっていても、 IDE や静的解析ツールはそこまで汲み取ってはくれません。 そのような場合にPHPDocで変数の型を明示すると便利です。 例)DBから値を取得する場合、テーブル定義を知っていれば型もわかる <?php function getUserId ( string $ email ) : int { $ pdo = new PDO ( 'pgsql:host=localhost;dbname=postgres' , 'postgres' ) ; $ statement = $ pdo -> query ( 'SELECT id FROM users WHERE email = :email' ) ; $ statement -> execute ([ ':email' => $ email ]) ; /** @var int $id */ $ id = $ statement -> fetchColumn () ; return $ id ; } まとめ 今回は「型」に絞ってPHPDocの応用的な書き方をご紹介しました。このような方法で適切に型を記述することで、 IDE の自動補完 → 開発体験の向上 静的解析の精度向上 → バグを減らせる といったメリットを享受することができます。これからPHPDocを書く際に、この記事の内容が少しでもお役に立てれば幸いです。 おまけ:配配メール開発チームの取り組み 私が所属する 配配メール 開発チームでは現在、古くからあるコードのPHPDocの整備を進めており、今回紹介した内容も多くはその中で実際に利用したものです。 以前はPHPDocが書かれていなかったり、誤った型が書かれている箇所が多くあるなど問題となっていましたが、そこから整備を進め、現在は多くの箇所で利用している共通関数・クラスの対応を完了しました。その結果、 IDE の補完が効くようになったり、誤った不要な警告が出なくなったりといった効果が出始めています *2 。 今後、さらに範囲を広げてPHPDoc整備を進めながら、現在はできていない静的解析の導入も目指していきたいと考えています。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com *1 : PHPUnit , PHP -DI など。この用途では、今後はDocコメントではなく、PHP8で導入された アトリビュート 機能に置き換わっていくかも。 *2 : なお、新規コードについてはコーディング規約とコードレビューでPHPDocが正しく書かれるようにしています。整備の対象となるコードを新たに生み出さないことも重要ですね。
アバター
はじめに こんにちは、 @rs_tukki です。 最近外に出られない日々が続いているので、自宅で完結できる趣味が増えた気がします。 さて、今は Android のWebViewがアツいみたいなので、それに関連してるようでしてない気がする話を少し。 はじめに 実装したかった仕様 実際の仕様 原因 どう修正したか まとめ 参考 実装したかった仕様 今回私が開発していた Android アプリは全体的にWebViewに依存しており、 まず API で認証処理を行ってから、取得したアクセス トーク ンを使ってWebサイトにログインするという流れを取っています。 アプリ( API )「君のサイトにログインしたいんだけど。まずIDとPASS投げるから認証して」 サーバ「オッケー、認証は問題ないね。君用のアクセス トーク ンあげるからこれくっつけてアクセスしてね」 API での通信を行う場合は、OkHttp3のCookiejarクラスを実装した独自の Cookie ストアを使用し、 レスポンスで受け取った Cookie を明示的にCookieManagerに保存する処理を行っていました。 class SharedCookieStore() : CookieJar { // CookieManagerはアプリ全体で共通のインスタンスとして定義する private val cookieManager = CookieManager.getInstance() // レスポンスの内容からCookieを永続化するメソッド override fun saveFromResponse(url: HttpUrl, cookies: MutableList <Cookie>) { val urlString = url.toString() cookies.map(Cookie :: toString) .forEach { cookieManager.setCookie(urlString, it) } sync() } private fun sync() { cookieManager.flush() } } val apiModule = module { single { SharedCookieStore() } bind CookieJar :: class // SharedCookieStoreクラスをインスタンス化 factory { buildHttpClient( get ()) } // 上記のSharedCookieStoreクラスを注入 private fun buildHttpClient(cookieJar: CookieJar): OkHttpClient { val dispatcher = Dispatcher() val builder = OkHttpClient.Builder() .dispatcher(dispatcher) .cookieJar(cookieJar) // SharedCookieStoreをOkHttpClientのcookieJarに指定(以下省略) これでCookieManagerに必要な Cookie が保存されましたので、あとはこれを使ってWebViewを開いてあげましょう。 アプリ(WebView)「今から君のサイトにアクセスするね。アクセス トーク ンはこれで っ Cookie 」 サーバ「はいはい、 トーク ン問題ないからアクセスしていいよー」 後は、このアクセス トーク ンの有効期限が切れるまでサイトへのアクセスが可能という仕様にするつもりでした。 実際の仕様 さて、このアクセスしたサイトですが、実は アクセス トーク ンの有効期限とKeyを保持したまま、定期的に Value だけ更新される という仕様が組み込まれています。 サーバ「ごめん、今君が使ってる Cookie 、値が変わったんだわ。次のアクセスからこっち使ってね」 アプリ(WebView)「えっ」 そして、この後再度アクセスしようとすると アプリ(WebView)「次このページにアクセスするね…えーっとアクセス トーク ンはこれかな? っ Cookie 」 サーバ「んー、その Cookie 知らない値だわ。申し訳ないけどログインからやり直して」 アプリ(WebView)「えっ」 というわけで、なぜかWebViewは新しい Cookie を使うことなく認証に失敗してしまいました。 原因 (サーバ側で既にある Cookie の Value を更新しただけなら、CookieManagerに自動的に反映されてそうなもんだけどな…) と思いながらWebViewの実装やらCookieManagerの仕様やらを見返していたのですが、ここに勘違いがありました。 spitfire-tree.hatenadiary.org 曰く、 Android アプリケーションで cookie を管理する際、デフォルトの動作はアプリとは非同期で揮発性のメモリに展開された値を最大数分(?)程度の遅れで不揮発な領域に書き込みに行くようです。 (中略) 実際には cookie に {user_id: 1} のような値を書き込むわけですが、それが不揮発性メモリと同期される前にアプリケーションを即時に終了させると、次回実行時に( cookie の expire が実行時より後に設定されていようと)不揮発性メモリに残った値を参照してアプリの状態を復元するため、今行ったログイン処理がなかったことにされてしまう可能性が存在する、ということです。 つまり、今貰った新しい Value を裏で永続化する前に次のアクセスを行ってしまったことで、 キャッシュとして残っていた古い Value を使ってしまい不整合が発生した…ということのようです。   どう修正したか Cookie を永続化できていなかったのが原因なわけですから、通信ごとに永続化してやればいいわけです。 WebViewのFragmentに内部クラスとしてWebViewClientを継承したクラスを作成し、 onPageFinishedのメソッドをオーバーライドして現在のアクセス トーク ンを明示的に永続化します。 class WebViewFragment() { private inner class MyWebViewClient( val isOtherWindow: Boolean ) : WebViewClient() { override fun onPageFinished(view: WebView?, url: String ?) { // Webviewでの遷移時に現在のアクセストークンを永続化する CookieManager.getInstance().flush() super .onPageFinished(view, url) } } 最初に書いた通り、 API 通信の時にはきっちり永続化しているんですけどね… WebViewでも同じ対応が必要という認識がすっぽり抜け落ちていました。反省。 class SharedCookieStore() : CookieJar { // CookieManagerはアプリ全体で共通のインスタンスとして定義する private val cookieManager = CookieManager.getInstance() // レスポンスの内容からCookieを永続化するメソッド override fun saveFromResponse(url: HttpUrl, cookies: MutableList <Cookie>) { val urlString = url.toString() cookies.map(Cookie :: toString) .forEach { cookieManager.setCookie(urlString, it) } sync() } // Cookieを永続化する private fun sync() { cookieManager.flush() } } まとめ さて、今回は Android における Cookie の仕様についてお話ししました。 CookieManager.flush() 、忘れるなよ!絶対だぞ! 参考 CookieJar - OkHttp - OkHttp AndroidのWebViewにクッキーを設定したい Android の cookie 管理と CookieManager と flush() - happy lie, happy life エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
はじめに こんにちは。インフラエンジニアの gumamon です! 〇aaS、コンテナ、 オーケストレーション 。インフラ界隈でも便利なツールが普及しつつある昨今ですが、根強く使われ続けているのが シェルスクリプト です。 シェルスクリプト の用途は 主に「シェルコマンドの自動実行(とエラーハンドリング等)」であり、インフラエンジニアとしては業務効率化のツールとして重宝する一方、事故(バグ)が発生してしまうと重大な障害につながる危険なものでもあります。 今回は、これを(初心者でも)比較的安全に書けるようになる。 ひいては シェルスクリプト の品質管理が楽になる「2つの VSCode のアドオン」を紹介します。 VSCode = Visual Studio Code 、 Microsoft 製の ソースコード エディタです。 インフラエンジニアの場合「 vim で書くし」という方も多いと思うのですが、慣れてしまうと超便利です。 インテリジェントなコード補完や校正機能は、コードレビューの 工数 も削減出来てGood。 はじめに アドオンの紹介 さっそく使ってみる( その1: ShellCheck ) さっそく使ってみる( その2: ShellFormat ) まとめ チーム/組織 でlintを導入するメリット アドオンの紹介 順次2つ、ご紹介します。 インストール方法/使い方についてはリンク先に動画がありますのでそちらをご参照ください。 ShellCheck (検証ver = v0.14.0) (エディタで表示された)シェルの記述に対し、問題が無いかをチェックします。 問題のある記述について、なぜダメなのか、どう直せば良いのかを事細かに説明してくれます。 チェック内容はリアルタイムに更新されるので、問題の有無を確認しながらコーディングが出来るのも良いポイントです。 ShellFormat (検証ver = v7.0.1) インデントや改行など、構文のフォーマットを修正してくれます 。 例:if構文の;doをどこで改行するか。 これにより ソースコード のフォーマットが一意になり、複数名で書いている場合は非常に読みやすくなります。 リンク先の動画についての補足 VSCode を初めて使われる方は、コマンドパレット(動画でコマンドを実行している部分)の呼出しで 少し迷われるかもしれません。コマンドパレットはショートカット(Ctrl+Shift+P)を使うか、メニューから[表示]→[コマンドパレット]で呼び出せます) さっそく使ってみる( その1: ShellCheck ) まず、ShellCheck をOFFにした状態がこちら。 ShellCheck=OFF ファイルの一覧を読み込み、日付付きのファイル名としてコピーするだけの スクリプト です。 何か気になるところはありますか? 気になるところを探しつつ次へ。 ↓ ↓ ↓ ↓ ↓ ShellCheck=ON わんさか指摘点が出てきました。 波線の色は深刻度を表しています(黄色 > 青色)。今回は発生していませんが、Syntax Errorレベルだと赤の波線で表示されます。 各波線部分は、マウスオーバーすると QuickFix というリンクが出て来て、なぜダメなのかを説明してくれます。 それによると・・ SC2006 ` `囲みはいくつかの問題があるレガシーコード。$( ) を推奨 SC2086 変数は "" で囲むこと。split防止 SC2153 スペルミスの可能性。Variableが割り当てられていない。 SC2162 while read は -r オプションを付けるべき ⇒全部直してみます。 ShellCheck=ON(fixed) 綺麗になりました! 今回指摘された部分は何れも Bash の記法上、実行してもエラー扱いになりません。問題無く動いて exit 0 してしまいます。 つまり 「ShellCheckを通していないと 検証/レビュー時に見落とすリスクがある」 と言うことです。 こういう呪われたシェルは、 「いざ本番というタイミングで発火する」 ものなので、ShellCheckを入れておいて損は無い(というか積極的に使った方が良い)と個人的には思います。 さっそく使ってみる( その2: ShellFormat ) まず、ShellFormat を実行する前のコードをご覧ください。 (ShellFormatは コードを開いて Shift+Alt+F を実行することで瞬時に校正を行います。) ShellFormat (before) style1~3 は別々の人が書いたと思ってください。 何れも問題のない記述ですが、読みづらい。インデントもそろっていないので、レビュー時にロジックを誤認してしまうかもしれません。 ShellFormat を実行してみます。 ↓ ↓ ↓ ↓ ↓ ShellFormat (after) 全て同じ書式に統一されました! 見やすい! ShellFormatは既に書き終わったコードにも適用することができます。 つまり、いつ誰が書いたのかわからないグチャグチャのコードに対してShellFormatを実行すると、 論理を変えることなく見やすい状態にすることが出来る訳です。 こちらのアドオンも使わない理由は特に見あたりません。 まとめ 今回紹介したアドオンは、いわゆる「lint」の一種です。 lint= ソースコード を読み込んで内容を分析し、問題点を指摘してくれる静的解析ツール。 ※ IT用語辞典 e-words より lintを導入するメリットは個人単位でも享受出来ますが、チーム/組織の運用に組み込んで導入するとより大きなメリットを享受することができます。 チーム/組織 でlintを導入するメリット 品質向上 ソースコード の品質を一定レベル保証出来る 潜在的 なバグを事前に潰すことが出来る コスト削減 教育をする側もされる側も楽になる レビューをする側もされる側も楽になる 組織単位で統一されたコードの書式であれば、ジョブローテ時の立ち上げコストが削減できる 納品速度の向上 レビューがサッと終わる ソースコード の品質管理は常に頭を悩ませる課題の一つです。 その中でも、構文のチェックは 本来注力すべき開発の本質ではないので、自動化するに越したことはありません。 やってみようかな?と思われた方、10分で導入出来ますのでお試し頂ければ幸いです! 以上、最後までお読み頂きありがとうございました。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
こんにちは、株式会社 ラク スで先行技術検証を行っている技術推進課の @t_okkan です。 技術推進課では、新サービス立ち上げ時の開発速度アップを目的に、現在 ラク スでは採用されていない新しい技術の検証を行う、技術推進プロジェクトがあります。 今回はその技術推進プロジェクトで、GraphQLについて検証を行いましたので、その結果の報告を行います。 なお、別テーマの取り組みや、過去の取り組みに関しては、こちらからご覧ください。 tech-blog.rakus.co.jp GraphQL GraphQLの言語仕様 クエリ言語 スキーマ言語 GraphQLのアーキテクチャ スキーマファーストな開発 検証してわかったこと フロントエンドとバックエンドの実装を切り離せ、お互いを疎結合にできる 共通の定義ファイルを元に実装を行うため、APIの仕様が明確になり実装の手戻りの防止や開発速度の向上が見込める その他わかったこと REST APIとGraphQLのAPIを1つのアプリケーションで運用できる DDDとGraphQLの相性が良い マイクロサービスアーキテクチャとの相性が良い GraphQLが向いているケース GraphQLが向いていないケース GraphQLのエコシステム GraphQLサーバー GraphQLクライアント その他エコシステム GraphiQL・GraphQL Playground GraphQL Code Generator GraphQL Multipart Request dataloader GraphQL Depth Limit Apollo Studio まとめ GraphQL GraphQLとは、 Facebook が2015年の React.js Conf 2015 で発表した、クライアントとサーバーの通信のための言語仕様になります。 グラフ理論 を用いて複雑なデータを階層構造にしてデータの取得を行います。元々は2012年に Facebook がネイティブモバイルアプリで使用するために開発しましたが、現在は OSS となっており GraphQL Foundation によってエコシステムの開発などが進められています。 graphql.org GraphQLを導入している企業としては、 GitHub 、 Twitter 、Yelp、Shopify、 Netflix などがあげられます。 GraphQLの仕様は2017年まで頻繁にリリースされたいましたが、2018年以降はリリースがなく安定していると言えます。 spec.graphql.org 実装言語や通信方式には縛りはありませんが、通信方式に関しては プロトコル はHTTP、HTTPメソッドはPOST、 データ形式 は JSON が推奨されています。 対応言語は公式ドキュメントで公開されています。 graphql.org GraphQLの言語仕様 クエリ言語 データの取得や更新の操作を指定する言語です。基本的にはクライアント側でクエリ言語を構築し、GraphQLサーバーにリク エス トとして送信します。 基本的なオペレーションとして、Query、Mutation、Subscriptionが存在します。その他にもFragementやVariables、Directivesなどの重要な言語仕様がありますが、詳細は 公式ドキュメント もしくは GraphQL Spec で確認してください。 Query データの取得、読み込み系の処理を担当します。 REST API のGETに相当します。 Mutation データの書き込み、更新系の処理を担当します。 REST API のPOST、PUT、DELETEに相当します。 Subscription WebSocketを利用した双方向のリアルタイムデータ通信を行います。サーバー側からクライアント側にリアルタイムで通知を送信できます。 スキーマ言語 GraphQLサーバーの API の仕様を定義します。サーバー側に スキーマ ファイルを配置し、GraphQLの型システムと API の操作を定義します。 ここでは主な仕様のみ紹介しますので、その他の仕様に関しては 公式ドキュメント と GraphQL Spec で確認してください。 Schema GraphQLサーバーで実行可能な操作(Query, Mutation, Subscription)を定義します。Schemaで宣言した操作がクライアントで実行できる操作となります。 Scalars GraphQL型システムのプリミティブ型を宣言します。GraphQL型システムには組み込み型として、String( UTF-8 の文字列)、Int(符号付き32ビットの整数)、Float(符号付き不動小数点)、Boolean(true, falseの論理値)、ID(一意の識別子でStringと同じ文字列)が存在します。開発者が独自にCustom Scalar型を定義できます。 Types GraphQL型システムの型で開発者が独自で定義できます。型は固有のオブジェクトで対応する複数のフィールドを持つことができます。アプリケーションの特性を反映できます。 GraphQLの アーキテクチャ GraphQLクライアント クエリ言語を構築し、データの取得やデータの更新操作を指定し、GraphQLサーバーにリク エス トを送信します。 GraphQLサーバー GraphQLクライアントから送信されたクエリを解析し、クエリで指定されたオペレーションを実行しデータを返却します。Query Parser、Query Validation、Resolverで構築されています。 Query Parser GraphQLサーバーでクライアントからリク エス トされたクエリ言語がGraphQLの仕様を満たしているか 構文解析 を行います。 構文解析 後にクエリ言語を 機械語 に変換します。基本的にはGraphQLサーバーのライブラリによって実装されています。 Query Validation Query ParserでGraphQLの 構文解析 をした後に、 スキーマ ファイルで定義されたGraphQLサーバーの仕様とクエリ言語の検証を行います。クエリ言語で宣言されている各オペレーションとResolverのナビゲーションを行います。基本的にはGraphQLサーバーのライブラリによって実装されています。 Resolver スキーマ ファイルで定義した型と操作に基づいて、サーバー側にて各 プログラミング言語 で実装を行います。GraphQLサーバーの ビジネスロジック やデータベースなどの永続化データ、またはバックエンドの API にアクセスし必要なデータを取得しレスポンスとして返却します。開発者が各 プログラミング言語 で実装します。 GraphQLの アーキテクチャ スキーマ ファーストな開発 GraphQLを導入することで スキーマ ファーストな開発が可能になります。 開発初期に API の仕様からGraphQLの スキーマ ファイルを定義し、その スキーマ ファイルを元にフロントエンドとバックエンドがそれぞれ実装します。 API の仕様が実装前に明確となるため、フロントエンドとバックエンドの実装を並行に行え、かつ結合した際にエラーが起きづらくなることを期待できます。 検証してわかったこと GraphQLの導入を検証し スキーマ ファーストな開発を行うことにより以下のようなことがわかりました。 フロントエンドとバックエンドの実装を切り離せ、お互いを 疎結合 にできる 共通の定義ファイルを元に実装を行うため、 API の仕様が明確になり実装の手戻りの防止や開発速度の向上が見込める フロントエンドとバックエンドの実装を切り離せ、お互いを 疎結合 にできる 従来の REST API ではSPAなどでフロントエンドとバックエンドを分離をしたい場合、開発の担当を分離することはできてもフロントエンドがバックエンドの API と直接通信していたため、実装を分離できずお互いのI/Fを確認しながら開発を行っていました。そのため、開発速度の低下やでき上がった API が想定とは異なる場合は手戻りが発生していました。 そこでGraphQLを導入することで スキーマ ファイルの存在により、バックエンドとフロントエンドの実装が隠蔽され、 疎結合 に分離できることがわかりました。 実装の分離 バックエンドは スキーマ ファイルで定義されているクエリと型に合わせたデータを提供し、フロントエンドは スキーマ ファイルにて定義されているクエリを実行し定義されているデータを取得することになります。お互い確認するのが スキーマ ファイルになり、それ以降の実装について関心がなくなるため実装を分離できます。実装を分離できることにより、バックエンドの実装や アーキテクチャ の変更による影響を受けづらくなります。 また、お互いの実装が分離されることにより各開発チームの最適な開発手法を取り入れることができます。 バックエンドは画面を意識せずビジネス ドメイン 知識に基づいた API を構築でき、フロントエンドは API の仕様を意識せず画面で必要なデータのみを取得できます。 共通の定義ファイルを元に実装を行うため、 API の仕様が明確になり実装の手戻りの防止や開発速度の向上が見込める GraphQLを導入することで、バックエンドは スキーマ ファイルに定義されているクエリと型を実装し、フロントエンドは スキーマ ファイルに定義されているクエリを実行して型の値を取得します。お互い スキーマ ファイルで定義されていない実装をすると、Query Validationでエラーが発生します。そのため、フロントエンド・バックエンドのどちらかが主導で仕様を変更できなくなります。仕様を変更する場合は、 スキーマ ファイルを変更してからお互いの実装を変更する必要があります。 スキーマ ファイルが API の仕様を明確にするので、仕様の齟齬による手戻りを防ぎ、それぞれの実装に集中できるので開発速度の向上が期待できるかと思います。 その他わかったこと 上述のこと以外で検証を通じてわかったことは以下になります。 REST API とGraphQLの API を1つのアプリケーションで運用できる GraphQLの仕様を実装しているライブラリには、Spring BootやLaravel、Expressとと言ったFrameworkと統合するためのライブラリが存在します。そのため、既存の REST API を一気にGraphQLに移行するのではなく、新機能や一部の機能のみ先行してGraphQLに移行できます。 DDDとGraphQLの相性が良い 先述したビジネス ドメイン をGraphQLの型システムに変換しやすいことから、DDDとGraphQLの相性が良いと考えられます。 AWS のreInvent:2019のBuilding modern APIs with GraphQLのセッションでもDDDとGraphQLとの親和性について紹介されています。(35:39あたりからです) www.youtube.com 登壇者の方のブログでもDDDとGraphQLの相性がよいと紹介されています。 GraphQL and DDD: the Missing Link | HackerNoon マイクロサービス アーキテクチャ との相性が良い Netflix では モノリス な API からマイクロサービスへ移行する際にGraphQLを導入しました。GraphQLを導入後にさらにサービスが増加しGraphQLのResolverの実装が複雑化し ボトルネック になっていたため、 Apollo 社が提唱している Apollo Federationを導入しました。 Apollo Federationは複数のGraphQLサービスを1つのGraphQL Gateway で集約しGraphQLサーバーとして提供する仕組みです。またその際に自社で開発したGraphQLをSpring Bootに統合するための実装を、Domain GraphQL Spring Boot Frameworkという フレームワーク として OSS で公開しています。 Home - DGS Framework GraphQLが向いているケース GraphQLの導入が向いているケースとして、適切に ドメイン を分割できるアプリケーションが考えられます。 GraphQLは導入すれば複雑な仕様を解消するツールではありません。同じクエリを扱う SQL ではデータベースの正規化で関係を整理するのと同様に、GraphQLにおいてもまずはアプリケーションの仕様を適切に分割できるかを検討してください。仕様を分割できる場合は、その分割の粒度に合わせてGraphQLの型を設計します。 例えば、ビジネス ドメイン 単位でGraphQLの型を設計することでバックエンドの実装をシンプルにできるのではないかと思います。 画面駆動から ドメイン 駆動の API 開発になり、画面に合わせた実装がなくなるためController層やView層といったフロントエンドと会話する層の実装が楽になるかと思います。 ドメイン とGraphQLの型 ビジネス ドメイン をGraphQLの型に変換することで、「検証でわかったこと」欄に上げたようなGraphQLの特徴を活かしながら導入できると思います。 この条件を満たしていれば、後述する向いていないケースに該当しない限り、基本的にはどのWeb API にも導入できるかと思います。 GraphQLが向いていないケース GraphQLの導入が向いていないケースとしては、 メディアファイルを扱う API データベースのテーブルを直接操作する API が考えられます。 GraphQLの データ形式 は JSON 形式が推奨されています。そのため周辺のエコシステムも JSON 形式を前提として実装されています。ファイルアップロードの機能を提供しているライブラリもありますが、メディアファイルを扱う場合は、GraphQLとは別の API を提供すべきかと思います。 また管理型のシステムなど、データベースのテーブルを直接操作するようなアプリケーションにも向いていないのではと考えています。GraphQLを導入するためのオーバーヘッドが高いため、 モノリス な構成か REST API で構築すべきかと思います。ただ Prisma や Hasura などテーブルとGraphQLの型が1対1になるようなツールを導入する場合は、検討の余地があるかと思います。 GraphQLのエコシステム GraphQLのエコシステムやその他のツールは公式のドキュメントでまとめられています。今回は検証で利用したツールを中心に紹介します。 GraphQL Landscape GraphQLサーバー 今回は Java とNodeでGraphQLサーバーを構築しました。それぞれで有効なライブラリを紹介します。 Java graphql- java GraphQLの仕様を Java で実装しているライブラリです。クライアントからのクエリのパーサーや、 スキーマ ファイルとの検証を実装しています。 Java でWebフレームワークを利用しない場合はもっとも有効な選択肢となります。 Hello from GraphQL Java | GraphQL Java graphql- java -spring Spring BootとGraphQLを統合するためのライブラリです。内部でgraphql- java を参照しているため、GraphQLの仕様はカバーできています。 @SpringBootTest に相当する @GraphQLTest を提供しています。 About GraphQL Spring Boot - GraphQL Java Kickstart Domain GraphQL Spring Boot Framework( DGS ) 先述した Netflix がGraphQLを導入し、 Apollo Federationを実現させた際に利用した フレームワーク です。Spring BootとGraphQLを統合し、テストライブラリの提供やSpring Securityとの統合をサポートしています。 Apollo Federationで必要な機能をサポートしているため、マイクロサービスとGraphQLの組み合わせを検討している場合は有効なライブラリであると考えられます。 Home - DGS Framework Node GraphQL.js GraphQL Foundationが実装しているライブラリです。GraphQLの仕様を準拠しており信頼性は高いが Apollo Serverに比べると低機能なため検証などで使用できると考えられます。 Getting Started With GraphQL.js | GraphQL Apollo Server Apollo 社によって開発されている フレームワーク です。NodeでGraphQLサーバーを構築する際の デファクト 的存在となっています。dataloaderやサーバー側のキャッシュなど機能が豊富で、 Apollo Federationを利用することでマイクロサービス アーキテクチャ との相性もよいです。 Introduction to Apollo Server - Apollo GraphQL Docs Express GraphQL Expressで構築されているアプリケーションに ミドルウェア としてGraphQL API を追加できます。 GitHub - graphql/express-graphql: Create a GraphQL HTTP server with Express. Apollo Server Plugin Expressで構築されているアプリケーションに ミドルウェア として Apollo Serverの機能を統合できます。 Choosing an Apollo Server package - Apollo GraphQL Docs GraphQLクライアント Apollo Client Apollo 社が開発しているライブラリです。React, Vue.js, Angular, iOS , Android に対応しています。機能が充実しており、ドキュメントや2次情報も充実しています。基本的には Apollo Clientを利用するべきであると思います。 Introduction to Apollo Client - Apollo GraphQL Docs Relay Facebook が開発している フレームワーク です。ReactとReact Nativeに対応しており、事前にクエリを コンパイル できるなどより安全にGraphQLのクライアントを構築できます。しかし、 フレームワーク であり学習コストが高いことや、React Hooksに未対応であることが懸念点として上げられます。 Relay その他 その他の選択肢として GraphQL Request や urql 、 graphqurl などがあります。 JavaScript フレームワーク との統合はサポートされていません。使用範囲が限られる場合は選択してもよいと思います。 また プロトコル にHTTP、HTTPメソッドにPOST、 データ形式 に JSON を指定すれば、クライアントツールを利用せずにクエリをリク エス トできます。ただしその場合はクエリの解析や、レスポンスの マッピング などの機能を独自で実装する必要があります。 その他エコシステム GraphiQL・GraphQL Playground GraphQL API のクライアントツールです。クエリの実行や、 スキーマ ファイルからドキュメントを自動生成することもできます。基本的にGraphQLサーバーのライブラリには開発環境用として内包されています。 github.com github.com GraphQL Code Generator スキーマ ファイルから自動で型定義ファイルを生成するツールです。TypeScriptや Java などの静的型付け言語に対応しています。 CLI も提供しており、ローカル環境で自動生成することもできます。GraphQLサーバーとクライアントのどちらの型定義ファイルを生成できます。 Home – GraphQL Code Generator GraphQL Multipart Request multipart/form-dataを利用したGraphQLでファイルアップロードを行う場合の仕様を定めています。この仕様を各GraphQLサーバーとクライアントのライブラリが実装をしています。GraphQLでファイルアップロードを行う場合はまずこの方法を選択すべきと思います。またライブラリを選定する場合もこの仕様を実装しているかを判断軸にすべきだと思います。GraphQLでファイルアップロードを行う他の手段としては、別 API を用意して登録先の識別子をGraphQLで登録するか、ファイルデータを Base64 で エンコード してGraphQLで登録する方法があります。 github.com dataloader GraphQLでは型同士が接続している場合にN+1問題が発生しやすいです。その回避策としてdataloaderを活用する方法があります。dataloaderは Facebook が提供している JavaScript のライブラリで、このライブラリを基に各 プログラミング言語 で移植されています。一意のIDを集合型でdataloaderに集約し、その集合体を利用して登録されている処理によって一括でデータを取得する仕組みになっています。そのため バッチ処理 とも言われています。N+1問題以外でも利用されています。 github.com また、dataloaderを利用することでバックエンドの負荷が高くなることもあるので、N+1問題を受け入れる選択もあるそうです。 Apollo Serverではサーバー側のキャッシュを利用する方法を推奨しています。 Data sources - Apollo GraphQL Docs GraphQL Depth Limit GraphQLの アンチパターン に循環参照があります。GraphQLの方がお互いに結合している場合に発生し、多段にデータが紐づいてしまいバックエンドの負荷が高くなります。対策としてクエリの深さを制限する方法があります。 graphql-depth-limit というライブラリや、各GraphQLサーバーのライブラリでも提供されています。 Apollo Studio GraphQLは単一のエンドポイントで API を提供するため、エンドポイント単位でのメトリクスの計測ができません。 Apollo Studioを利用すると、クエリごとに実行数や処理時間を計測でき、バックエンドの ボトルネック を発見できます。しかし、 Apollo Serverか 対応しているライブラリ でGraphQLサーバーを構築する必要があります。 Introduction to Apollo Studio - Apollo GraphQL Docs Apollo Studio以外でメトリクスを計測する方法として、マイクロサービスで利用されている Open Tracing を利用する方法もあります。 まとめ GraphQLの検証で得た知見のまとめは以下のようになります。 GraphQLを導入することで、フロントエンドとバックエンドでお互いの実装が切り離せ 疎結合 にできる 共通の定義ファイルを元に実装を行うため、 API の仕様が明確になり開発速度の向上が期待できる GraphQLを導入する前にアプリケーションの仕様を分割できるかを検討する必要がある DDDやマイクロサービス アーキテクチャ との相性が良い GraphQLと REST API は同じアプリケーションで共存できるため、段階的に移行することができる 検証のご紹介は以上になります。GraphQLの導入事例が徐々に増えてきており、エコシステムの強化も進んでいる印象です。 既存の REST API をGraphQLに移行する場合や、新規の API をGraphQLで開発することを検討されている方は是非参考にしてください。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
こんにちは。 株式会社 ラク スで先行技術検証を行っている「技術推進課」の堀内( id:yhoriuchi )です。 ラク スの スマホ アプリ開発 ではCI/CD環境にBitriseを採用しているのですが、 iOS アプリ開発 の一部で使っているだけで十分に活用できているという状況ではありませんでした。 今回、技術推進プロジェクトの一貫として スマホ のCI/CDに取り組み、その中でBitriseを熟知し、最大限活用できるようにしました。 情報量が多くてその全てをお伝えすることはできませんが、調べても情報があまり出てこなかった"Bitrise CLI "をご紹介してみようと思います。 目次 目次 Bitriseとラクスが採用した理由 Bitrise CLIとは インストール方法 ローカルでの実行方法について Bitrise CLI実行時の環境変数 スゴイと叫ばずにはいられなかった機能 最後に Bitriseと ラク スが採用した理由 Bitriseについては多くの記事でも紹介されていますが、概要を理解してもらうには 公式サイトの説明 が分かりやすいので引用しておきます。 Bitriseはモバイルアプリ開発(iOS, Android, Xamarin, …)における 継続的インテグレーション・デリバリー(CI/CD) プラットフォームをサービス(PaaS)として提供しています。 ソフトウェアプロジェクトの開発・自動化を手助けするためのツール・サービスの集合体です。 数回のクリックであなたのアプリのテストやデプロイ作業を自動化しましょう! ラク スでBitriseを採用した理由は、 スマホ 対応に特化していることと、ワークフローと呼ばれる可視化されたフロー図でビルドプロセスが分かりやすくなっていることが大きいです。 また、 スマホ に特化していることもあって iOS 、 Android だけでなく、FlutterやReact Nativeなどにも対応しています。 プラットフォームを問わず スマホ アプリ全般をサポートし、充実した機能があるので、Bitriseを使っていて開発で困ることは無さそうに思います。 しかし、Bitriseが万能とはいえ、なんらかの理由でBitriseが停止した際にビルドやデリバリーに影響が出てしまっては困ります。 そんな時にも備えて対策を検討した際に出てきたのがBitrise CLI でした。 Bitrise CLI とは Bitrise CLI は読んで字の如く、Bitrise Command Line Interfaceのことです。 ローカル実行が可能で、コードが GitHub で公開されているため誰でも利用することができます。当然Bitriseのアカウントも不要です。 これを使えば懸念しているBitrise停止といった不慮の事故に見舞われたとしてもなんとかできそうです。 インストール方法 オープンソース なのでコードをビルドしないといけないのかと考えてしまうかもしれませんが、下記のコマンド一発です。 brew update && brew install bitrise Homebrewを使いたくない、あるいは Linux 環境にインストールしたい場合は下記。(v1.45.1の場合) curl -fL https://github.com/bitrise-io/bitrise/releases/download/1.45.1/bitrise-$(uname -s)-$(uname -m) > /usr/local/bin/bitrise 環境構築にまで気を配っているところが素敵ですね。 ローカルでの実行方法について 実行方法も至って簡単なのですが、その前にワークフローの設定が記載された bitrise.yml を用意する必要があります。 これはイチから作る必要は無く、Bitriseにログインしてワークフローエディタを開くとダウンロードできるようになっているので心配無用です。 具体的には下記のbitrise.ymlメニューからダウンロードできます。 bitrise.ymlの詳細をお見せすることはできませんが、内容は 公式サイトが参考になると思います 。 ここまで来れば実行は簡単で、bitrise.ymlを保存した ディレクト リで下記を実行するだけ。(下記の"SimpleBuild"はワークフロー名) bitrise run SimpleBuild すると下記のように アスキーアート で"BITRISE"のロゴが表示されたあと、ステップが実行されているのが分かります。 bitrise run ちなみに下記は同じワークフローをbitrise.ioで実行したログです。若干見た目が異なりますが、出力される内容はほぼ同じです。 bitrise.io Bitrise CLI 実行時の 環境変数 実行が簡単なことがお分かり頂けたと思いますが、通常BitriseでGit リポジトリ から ソースコード を取得する場合、 リポジトリ のURLとブランチ名はワークフローの設定ではなく、1つ上の階層にあるアプリケーションの設定に記載し、ステップの中では用意された 環境変数 を参照することになると思います。 残念ながらこの設定( 環境変数 )はbitrise.ymlに記載されないため、自前で 環境変数 としてexportしておく必要があります。 具体的な 環境変数 名は GIT_REPOSITORY_URL と BITRISE_GIT_BRANCH の2つです。 他にもbitrise.ioが使う環境変数 はいくつもありますが、弊社では今のところこの2つだけで足りています。 これを毎回exportするのが手間なので弊社では スクリプト を作って運用することにしました。 参考までに弊社で作成した スクリプト (一部抜粋版)を載せておきます。 #!/bin/sh WORKFLOW=$1 if [ -z "${WORKFLOW}" ]; then echo "第1引数でビルド対象のワークフローを指定してください" exit 1 fi export GIT_REPOSITORY_URL="{{リポジトリのURL}}" export BITRISE_GIT_BRANCH="{{ブランチ名}}" ssh-add ~/.ssh/id_rsa bitrise run ${WORKFLOW} スゴイと叫ばずにはいられなかった機能 最後に1つだけBitrise CLI でスゴイ!と思った機能を紹介したいと思います。 それがワークフローエディタです。とりあえず下記のコマンドを実行してみてください。 bitrise :workflow-editor すると、なんということでしょう、ブラウザが立ち上がってワークフローエディタが使えるじゃないですか! (下記のような画面が表示されます) bitrise workflow-editor スタックと呼ばれる 仮想マシン の管理機能が無いので言い過ぎになってしまいますが、これってBitriseの機能そのものだったりします。 オープンソース でここまで使えることに驚きを隠せませんでした。万が一に備えようと調べ始めた CLI 環境ですが、十分すぎる機能が提供されているので安心してBitriseを使えると思いました。 最後に いかがだったでしょうか。Bitrise CLI の情報でお役に立つ内容があったでしょうか。 実のところ、 スマホ アプリ開発 に着手した直後はビルドサーバーを社内に構築しようと考えていました。しかし、ビルドマシンのメンテコスト(機器、OS、 SDK 、その他ソフトウェアなどのメンテの手間)を考えると割りに合わないと判断し、CI/CD環境を提供してくれる クラウド サービスを利用することにしました。 今回、Bitriseには十分な機能と柔軟な環境が用意されていると改めて知ることができたので、この先もBitriseを活用していくことで開発を効率よく進めていくことができそうです。
アバター
目次 目次 はじめに styled-componentsとは 使用環境 環境構築 styled-componentsでの装飾 リンクの装飾 propsを使ったリンクの装飾 リンク以外の装飾 VSCodeの拡張機能 おわりに 参考 はじめに 初めまして。フロントエンドチーム 新卒1年目のhy094です。 業務でstyled-componentsを使う機会があったのでまとめたいと思います。 styled-componentsとは CSS in JSの一つです。 JSの中にスタイルを記述できるので、 CSS ファイルが必要なくなることや typo をエラーで教えてくれたりするメリットがあります。 また、 コンポーネント 単位で装飾するためReactとの親和性が高いです。 使用環境 上記の通り、Reactとの親和性が高いためReactを使用します。 折角なので弊社のブログ記事に書かれている内容を装飾していきます。 使用する環境・ ソースコード などはこちら↓ tech-blog.rakus.co.jp Reactの入門記事になります。ぜひご覧ください。 ※本記事は上の記事の内容を実施した直後という状態を想定して進めていきます。 環境構築 上記の記事だけだとstyled-componentsがインストールされていないので、 追加でインストールします。 npm install styled-components package. json に "styled-components": "^5.2.1", のような記述があれば問題なく成功しています。 styled-componentsでの装飾 リンクの装飾 元記事をそのまま実施していただいている場合、 フォルダ構成は以下のようになっていると思います。 ├── node_modules/ ├── package.json ├── public/ ├── README.md ├── src/ │ ├── page │ │ ├── one.js │ │ └── two.js │ └── routes.js └── yarn.lock まずは コンポーネント を配置するためのフォルダをsrc以下に作成します。 src/components 次に、src/components以下にLink コンポーネント を作成します。 src/components/Link.js import React from "react" ; import styled from 'styled-components' export const Link = ( { to,children } ) => { return <StyledLink href= { to } > { children } </StyledLink> } ; const StyledLink =styled.a` //ここにスタイルを記述 outline: none; text-decoration: none; display: inline-block; width: 19.5%; margin-right: 0.625%; text-align: center; line-height: 3; color: black; background: yellow; &:hover { background: orange; } &:active { background: red; color: white; } ` //ここにスタイルを記述 以降にお好きなスタイルを記述してください。 今回は MDNのリンクの装飾 をお借りしたいと思います。 次に作成したLink コンポーネント をアプリの方でimportします。 src/page/one.js import React from 'react'; - import { Link } from 'react-router-dom'; + import { Link } from '../components/Link'; import Two from './two'; class One extends React.Component{ render(){ return ( <div> test_one<br/> <Link to='/two'>twoへ</Link> </div> ) } } export default One; src/page/two.js import React from 'react'; - import { Link } from 'react-router-dom'; + import { Link } from '../components/Link'; import One from './one'; class Two extends React.Component{ render(){ return ( <div> test_two<br/> <Link to='/'>oneへ</Link> </div> ) } } export default Two; 見ていただくと分かる通り、差分は2行目のimport文のみです。 ここまでの作業でリンクのスタイルが変わっています。 propsを使ったリンクの装飾 「リンクといえばこのスタイル」という規則が決まっていれば、 今後は <Link>○○</Link> を使うことでclassなどを指定する必要がなくなります。 しかし今の表示だと自分がoneにいるのかtwoにいるのか分かりにくいですね。 そこでoneとtwoでスタイルを変えたいと思います。 src/components/Link.js import React from "react" ; import styled, { css } from 'styled-components' export const Link = ( { to,children,fontColor,isBluePattern } ) => { return <StyledLink href= { to } fontColor= { fontColor } isBluePattern= { isBluePattern } > { children } </StyledLink> } ; const StyledLink =styled.a` //ここにスタイルを記述 outline: none; text-decoration: none; display: inline-block; width: 19.5%; margin-right: 0.625%; text-align: center; line-height: 3; color:$ { (props) => props.fontColor } ; $ { (props) => props.isBluePattern ? (css` background: aquamarine; &:hover { background: aqua; } &:active { background: blue; color: white; } `): (css` background: yellow; &:hover { background: orange; } &:active { background: red; color: white; } `) } ` src/page/one.js import React from 'react' ; import { Link } from '../components/Link' ; import Two from './two' ; class One extends React.Component { render() { return ( <div> test_one<br/> <Link to= '/two' fontColor= "blue" isBluePattern= { false } >twoへ</Link> </div> ) } } export default One; src/page/two.js import React from 'react' ; import { Link } from '../components/Link' ; import One from './one' ; class Two extends React.Component { render() { return ( <div> test_two<br/> <Link to= '/' fontColor= "red" isBluePattern= { true } >oneへ</Link> </div> ) } } export default Two; 少し無理矢理感もありますが、これでページごとにスタイルが変わります。 color:${(props) => props.fontColor}; で、 <Link> に指定した fontColor の色が文字色となります。 oneは青、twoは赤ですね。 また、 $ { (props) => props.isBluePattern ? (css`    //以下略 三項演算子 と css によってまとめてスタイルを指定できます。 isBluePatternがtrueの時、 青背 景のボタン風リンクになります。 リンク以外の装飾 const StyledLink = styled.a でリンクの装飾ができました。 ではリンク以外の装飾はどうするのでしょうか。 答えは単純で h1 なら styled.h1 、 div なら styled.div です。 VSCode の 拡張機能 ここまで作業するとLink.jsは以下のような表示になっているのではないでしょうか。 見にくいですね。また、 CSS の補完も効きません。 そこで便利なのが VSCode の 拡張機能 vscode-styled-components です。 この 拡張機能 を使うと・・・ 非常に見やすくなり、補完も効くようになります。 styled-componentsを書くならぜひ抑えておきたい 拡張機能 だと思います。 おわりに 今回はstyled-componentsのさわりについて紹介させていただきました。 スタイルの話やデザイン関連の話はあまりできませんでしたが もしそちらにご興味ある方は弊社デザイナーチームのブログがあるので、 よかったらご覧ください!↓ note.com 現在はチームの話などが多いですが、今後記事数はどんどん増えていくと思います。 styled-componentsと親和性の高いatomic-designについて記事ができることを密かに楽しみにしています。 参考 https://qiita.com/snishinon/items/9ea9c2f981ef081e825f https://zenn.dev/syu/articles/0f92abf7f0b5c5 https://qiita.com/taneba/items/4547830b461d11a69a20 https://www.webprofessional.jp/style-react-components-styled-components/ エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
はじめに こんにちは、開発エンジニアの amdaba_sk( ペンネ ーム未定)です。 今回は PHP のお話です。例えば以下のような配列があったとしましょう。 <?php $ target = [ 'ほげ' , 'ふが' , 'ぴよ' , ] ; これをソートしたいとします。ただそれだけなら、 <?php sort ( $ target ) でおしまい、 Q.E.D. ! でもいいのですが、 PHP には他にもいろいろな配列のソート方法が用意されていますよね。 この記事は、それらいろいろなソート方法を紹介し、特に日本語文字列を値に持つ配列の場合もっと「イイ感じ」にする方法がありますよというお話です。 なお、ソートに限らず PHP の配列機能について知りたいという方は、弊社ブログのこちらの記事も併せてチェックしてみてくださいね。 tech-blog.rakus.co.jp もくじ はじめに もくじ PHP の配列ソート関数いろいろ 標準の配列ソート関数 - sort SORT_REGULAR SORT_STRING 日本語文字列をイイ感じに並べる sort 関数に SORT_LOCALE_STRING フラグを指定する intl 拡張を使う - Collator::sort または collator_sort 独自ルールを実装する - usort 実装例:いろは順 おわりに PHP の配列ソート関数いろいろ お決まりですが、こういうときまずは公式の「 PHP マニュアル」を見に行くようにしましょう。 PHP は公式マニュアルがとても充実していますよね。配列のソートについても、それについてまとめた専用のページがあります。 www.php.net 関数名 ソートの基準 キーと値の相関関係 ソート順 関連する関数 array_multisort() 値 連想配列 の場合は維持し、数値添字配列の場合は維持しない 最初の配列、あるいはソートオプション array_walk() asort() 値 維持する 昇順 arsort() arsort() 値 維持する 降順 asort() krsort() キー 維持する 降順 ksort() ksort() キー 維持する 昇順 asort() natcasesort() 値 維持する 大文字小文字を区別しない自然順 natsort() natsort() 値 維持する 自然順 natcasesort() rsort() 値 維持しない 降順 sort() shuffle() 値 維持しない ランダム array_rand() sort() 値 維持しない 昇順 rsort() uasort() 値 維持する ユーザー定義 uksort() uksort() キー 維持する ユーザー定義 uasort() usort() 値 維持しない ユーザー定義 uasort() 配列をソートする関数が表でまとめられ、それぞれの関数のソートの基準(キー or 値)、キーと値の相関、ソート順、関連する関数が一覧できます。各関数ごとの詳細ページへのリンクもあって、勉強にも役立ちます。 余談ですが、ソートの基準とキーと値の相関が情報として入ってくるのは、すべての配列が 連想配列 な PHP の特徴的なところですね。 さて、マニュアルは PHP の一般の配列に関するものですが、本記事では文字列を値として持つ、一次元の連番整数値添字の配列について考えます。例えばいくつかの静的型付け言語だと、対象配列が次のように型付けされる場合です 1 。 Java : List<String> , C# : List<string> , TypeScript: string[] , Scala : List[String] , F#: string list , Haskell : [Text] また、すでに暗黙的に前提としていますが、特に日本語の文字を含む文字列を想定しています。 このような問題設定の下で、ここでは sort 関数について詳しく見ていくことにしましょう。 標準の配列ソート関数 - sort www.php.net sort ( array &$array , int $flags = SORT_REGULAR ) : bool sort は配列を昇順にソートする関数です。 第一引数 $array にソートしたい配列への参照を受け取って、ソートに成功したかどうかを真偽値で返します。引数で渡した配列は、この関数の実行によって変更されます。破壊的な作用を持つ関数ということです。 またオプションの第二引数 $flags に整数で表されたフラグを取り、要素の大小関係の判定方法を切り替えることが出来ます。使える値は以下の通りです。 SORT_REGULAR - 通常通りに項目を比較します。 詳細は 比較 演算子 で説明されています。 SORT_NUMERIC - 数値として項目を比較します。 SORT_STRING - 文字列として項目を比較します。 SORT_LOCALE_STRING - 現在の ロケール に基づいて、文字列として項目を比較します。 比較に使う ロケール は、setlocale() 関数で変更できます。 SORT_NATURAL - 要素の比較を文字列として行い、 natsort() と同様の「自然順」で比較します。 SORT_FLAG_CASE - SORT_STRING や SORT_NATURAL と (ビットORで) 組み合わせて使い、 文字列のソートで大文字小文字を区別しないようにします。 これらはすべて、 PHP のグローバルな定数として定義されています。いくつかピックアップしてみましょう。 SORT_REGULAR SORT_REGULAR は sort の第二引数 $flags のデフォルト値です。この値が指定された場合、要素の大小関係の判定には宇宙船 演算子 <=> (と同等の処理)が使われます。 宇宙船 演算子 の詳細については 公式マニュアルの該当するページ を参照してほしいのですが、 SORT_REGULAR が指定された場合の sort は、すべての要素が文字列である前提であれば、次に取り上げる SORT_STRING と変わりません。 ただしマニュアル上でも以下のような警告があるように、要素に複数の型が混在する場合は注意が必要です。 警告 flags が SORT_REGULAR の場合に 複数の型が混在する配列をソートする場合には、注意してください。 sort() が期待しない結果を出力することがあります。 この件に関する詳細は、かなり古い記事ではありますが、以下が参考になります。 hnw.hatenablog.com SORT_STRING SORT_STRING が指定された場合 sort 関数は各要素を文字列であるとして大小関係を比較します。 文字列であるとして比較するとはつまり、文字列を文字の配列であるとして、 文字コード の数値的大小関係に基づく辞書式順序で比較する 2 ということです。 例えば 'abc' と 'abd' を比較する場合、以下のように先頭から一文字ずつ文字の大小を比較していきます。 文字位置 'abc' 'abd' 比較 1 a a a = a 2 b b b = b 3 c d c < d 全体 'abc' 'abd' 'abc' < 'abd' 初めて違いの出た文字位置の文字の大小で、文字列全体の大小が決まります。ちなみに文字列の終端は、どんな文字よりも小さいと判定されます。 PHP においては、最終的に C 言語の memcmp 関数を用いる実装がされています 3 。 日本語文字列をイイ感じに並べる ここで以下のような配列をソートすることを考えてみましょう。 順位 文字列 読み UTF-8 文字コード 値 1 あぶりだし アブリダシ E38182 E381B6 E3828A E381A0 E38197 2 あまガミ アマガミ E38182 E381BE E382AC E3839F 3 ういーん ウイーン E38186 E38184 E383BC E38293 4 アフロディテ アフロディテ E382A2 E38395 E383AD E38387 E382A3 E38386 5 アフロディーテ アフロディーテ E382A2 E38395 E383AD E38387 E382A3 E383BC E38386 6 アプロディテ アプロディテ E382A2 E38397 E383AD E38387 E382A3 E38386 7 アマガミ アマガミ E382A2 E3839E E382AC E3839F 8 ウィーン ウィーン E382A6 E382A3 E383BC E383B3 9 一遍上人 イッペンショウニン E4B880 E9818D E4B88A E4BABA 10 悪人正機 アクニンショウキ E682AA E4BABA E6ADA3 E6A99F 11 阿闍梨 アジャリ E998BF E9978D E6A2A8 上表は sort 関数に SORT_STRING を指定して並べ替えた順に記載しています。各文字列の UTF-8 文字コード 値を 16 進数表示で付けました。これを見てもらうと、前節で説明した通りの順序に並んでいることが分かります。 一方で、ぱっと見てこの順序は「イイ感じ」でしょうか? 少し考えれば納得できそうですが、おそらくぱっと見だと「なんでこんな順序になっているの?」と思ってしまうのではないでしょうか。 世界にはいろいろな言語があり、使用している文字も違います。それぞれの言語での最適な文字の並び順が、 文字コード の大小とは一致しないこともあります。日本語だと、文字列は基本「読み」の順に並べるのが普通ですよね。 さて、ようやく本題にたどり着きました。日本語文字列を PHP で「イイ感じ」にソートするにはどのようにすればいいでしょうか? 先に結論をいうと、以下の 3 つの方法があります。 sort 関数に SORT_LOCALE_STRING フラグを指定する intl 拡張を使う - Collator::sort または collator_sort 独自ルールを実装する - usort 一つずつ見ていきましょう。 sort 関数に SORT_LOCALE_STRING フラグを指定する 標準のソート関数である sort は、先にも説明した通りオプションの第二引数 $flags によって要素の大小関係の判定方法を切り替えることが出来ます。 $flags に SORT_LOCALE_STRING が指定された場合、 SORT_STRING と同様各要素を文字列であるとして大小関係を比較しますが、その際、現在の ロケール に基づいて地域化された比較ルールを用います。 文字列を文字の配列であるとして先頭から一文字ずつ文字の大小を比較するという点は SORT_STRING の時と同様なのですが、文字同士の大小比較ルールが単純な 文字コード の大小比較ではありません。 SORT_LOCALE_STRING を使った場合、 PHP は内部的には C 言語の strcoll 関数を使って文字列の比較します 4 。これによって ロケール が示す地域の言語に適した方法で文字の大小比較をしてくれるというわけです。 先ほどのサンプル配列を ロケール が ja_JP.UTF-8 の環境下で、 SORT_STRING と SORT_LOCALE_STRING のそれぞれでソートした結果を比較すると、下のようになります。 --- SORT_STRING +++ SORT_LOCALE_STRING @@ @@ Array ( 0 => 'あぶりだし' 1 => 'あまガミ' 2 => 'ういーん' - 3 => 'アフロディテ' - 4 => 'アフロディーテ' + 3 => 'アフロディーテ' + 4 => 'アフロディテ' 5 => 'アプロディテ' 6 => 'アマガミ' 7 => 'ウィーン' - 8 => '一遍上人' + 8 => '阿闍梨' 9 => '悪人正機' - 10 => '阿闍梨' + 10 => '一遍上人' ) 比較結果を見ると、「ひらがな → カタカナ → 漢字」という文字種ごとの並び順は SORT_STRING の時と同様です。しかし漢字文字列だけを見ると、「ア → アク → イチ」と読みの順に並んでいて、より日本語の文字列として自然と思える並び順になっていると言えます。 より詳細にどのような比較ルールになっているのかというと、申し訳ないのですがにわか仕込みの C 言語ぢからが足りず、分かりませんでした。おそらく PHP を コンパイル した際の処理系に依存するものと考えているのですが、実際のところどうなのでしょう。教えてつよつよな人……! intl 拡張を使う - Collator::sort または collator_sort www.php.net オブジェクト指向 型 public Collator::sort ( array &$arr , int $sort_flag = ? ) : bool 手続き型 collator_sort ( Collator $coll , array &$arr , int $sort_flag = ? ) : bool PHP をビルドする際に、国際化用拡張モジュール (intl 拡張) を有効にすることで、 ICU ライブラリのラッパーを使うことが出来るようになります。ライブラリで提供される機能はいくつもありますが、ここで注目するのは Collator です。 Collator は、 ロケール に応じた適切な並び順を考慮した文字列比較機能を提供するクラスです。並び順のルールは UCA に準拠しています。 Collator を使って配列を並べ替えるには、 インスタンス メソッドの Collator::sort か、あるいは collator_sort 関数を使います。 使い方は標準の sort 関数とほぼ同じで、引数 $arr にソートしたい配列への参照を受け取って、ソートに成功したかどうかを真偽値で返します。引数で渡した配列は、この関数の実行によって変更されます。破壊的な作用を持つ関数というところも同じです。 またオプションの引数 $sort_flag に整数で表されたフラグを取り、要素の大小関係の判定方法を切り替えることが出来ます。使える値は以下の通りです。 Collator::SORT_REGULAR - 通常の比較 (型を変更しない) Collator::SORT_NUMERIC - 数値としての比較 Collator::SORT_STRING  - 文字列としての比較 省略した場合のデフォルトは Collator::SORT_REGULAR ですが、要素がすべて文字列である場合は Collator::SORT_STRING を指定した場合と結局のところ同じになります 5 。そして Collator::SORT_STRING が指定された場合、 Collator::sort は内部的に ICU ライブラリで提供される C 言語の関数 ucol_strcoll 6 を使用して文字列の比較をします 7 。 ロケール ja_JP.UTF-8 が有効な環境下で、サンプル配列を標準の sort + SORT_LOCALE_STRING と Collator::sort + Collator::SORT_STRING のそれぞれでソートして比較してみましょう。 <?php namespace Tests\Unit; use PHPUnit\Framework\TestCase; use Collator; class CollatorSortTest extends TestCase { /** * ロケールの設定(SORT_LOCALE_STRING 用) */ public static function setUpBeforeClass () : void { parent :: setUpBeforeClass () ; setlocale ( LC_COLLATE, 'ja_JP.UTF-8' ) ; } /** * sort + SORT_LOCALE_STRING と Collator::sort + Collator::SORT_STRING の * ソート結果を比較するテストケース * @return void */ public function testCollatorSort () { $ sample = [ 'あぶりだし' , 'あまガミ' , 'ういーん' , 'アフロディテ' , 'アフロディーテ' , 'アプロディテ' , 'アマガミ' , 'ウィーン' , '一遍上人' , '悪人正機' , '阿闍梨' , ] ; $ sortLocalString = $ this -> sortAndReturn ( fn ( &$ arr ) => sort ( $ arr , SORT_LOCALE_STRING ) , $ sample ) ; $ sortCollator = $ this -> sortAndReturn ( fn ( &$ arr ) => Collator :: create ( 'ja_JP.utf8' ) -> sort ( $ arr ) , $ sample ) ; $ this -> assertEquals ( $ sortLocalString , $ sortCollator ) ; } /** * 配列にソート関数を適用して返す * @param callable $sortFunc ソート関数 * @param array $arr 対象配列 * @return array */ private function sortAndReturn ( callable $ sortFunc , array $ arr ) : array { $ sortFunc ( $ arr ) ; return $ arr ; } } 実行するとこのテストケースは失敗して、以下の差分出力が出て来ます。 --- Expected (sort + SORT_LOCALE_STRING) +++ Actual (Collator::sort + Collator::SORT_STRING) @@ @@ Array ( 0 => 'あぶりだし' - 1 => 'あまガミ' - 2 => 'ういーん' - 3 => 'アフロディーテ' - 4 => 'アフロディテ' - 5 => 'アプロディテ' - 6 => 'アマガミ' - 7 => 'ウィーン' + 1 => 'アフロディーテ' + 2 => 'アフロディテ' + 3 => 'アプロディテ' + 4 => 'アマガミ' + 5 => 'あまガミ' + 6 => 'ウィーン' + 7 => 'ういーん' 8 => '阿闍梨' 9 => '悪人正機' 10 => '一遍上人' ) 比較結果を見ると、「かな文字 → 漢字」という並び順は相変わらずですが、 Collator::sort では sort + SORT_LOCALE_STRING とは違って、ひらがなとカタカナの区別がなくなり、音の順で並べられるようになりました。また漢字文字列同士であればやはり読みの順に並んでいて、 sort + SORT_LOCALE_STRING よりもさらに日本語の文字列として自然と思える並び順になっていると言えます。 独自ルールを実装する - usort www.php.net usort (array &$array , callable $callback ): bool sort + SORT_LOCAL_STRING や Collator::sort でも満足できないこだわり派の方には、独自に比較関数を実装する方法をご紹介しましょう。 usort は第一引数 $array にソートしたい配列への参照を受け取って、ソートに成功したかどうかを真偽値で返します。引数で渡した配列は、この関数の実行によって変更されます。破壊的な作用を持つ関数ということです。 sort と異なるのは第二引数がフラグではなく、要素を比較するための関数であり、かつ必須であるという点です。無理やり シグネチャ を上と同じように書くならば、第二引数のコールバック関数は以下のようになるでしょうか。 $callback (mixed $element1 , mixed $element2 ): int 配列の要素を引数として二つ取り、整数値を返す関数です。返り値の int は、最初の引数 $element1 のほうが二番目の引数 $element2 より大きい場合は正の数を、等しい場合はゼロを、そして小さい場合は負の数を返すように実装します。 このコールバック関数によって、好きなルールでソートを実現することが出来るという寸法です。要件に合わせて適切なルールを実装しましょう。ちなみに昇順降順の切替も、返り値の正負を反転させることで実現することが出来ます( ursort が無いのはそのためでしょう)。 実装例:いろは順 せっかくなので ursort を使った独自ソート関数の実装をやってみましょう。 ursort を使うのであれば、配列の各要素文字列からソートキー(よみがな等)を別途作成して付け加え、それを使ってソート、なんてこともできるでしょうが、ここでは以下の簡単な条件で実装してみます。 ソート対象配列の要素文字列はすべて「ひらがな」で構成される ただし濁音、半濁音、長音、拗音、促音に相当する文字は含まれないものとする 各文字列は辞書式順序で順序比較する 各文字の順序は「 いろは順 」に従う できあがりはこちらです。 <?php class IrohaOrder { /** @var array $iroha いろは順マスタ */ private $ iroha = [ 'い' , 'ろ' , 'は' , 'に' , 'ほ' , 'へ' , 'と' , 'ち' , 'り' , 'ぬ' , 'る' , 'を' , 'わ' , 'か' , 'よ' , 'た' , 'れ' , 'そ' , 'つ' , 'ね' , 'な' , 'ら' , 'む' , 'う' , 'ゐ' , 'の' , 'お' , 'く' , 'や' , 'ま' , 'け' , 'ふ' , 'こ' , 'え' , 'て' , 'あ' , 'さ' , 'き' , 'ゆ' , 'め' , 'み' , 'し' , 'ゑ' , 'ひ' , 'も' , 'せ' , 'す' , 'ん' , ] ; /** * 文字列配列をいろは順に並べる * @param array $arr * @return bool ソートできたかどうか */ public function sort ( array &$ arr ) : bool { try { usort ( $ arr , fn ( $ a , $ b ) => $ this -> compare ( $ a , $ b )) ; return true ; } catch ( RangeException $ e ) { return false ; } } /** * 文字列を二つ受け取っていろは順に従って順序を決める * @param string $a * @param string $b * @return int <=> の仕様に沿った整数値 * @throws RangeException 引数の文字列にいろは順が付けられない場合 */ public function compare ( string $ a , string $ b ) : int { $ lenA = mb_strlen ( $ a ) ; $ lenB = mb_strlen ( $ b ) ; $ ret = 0 ; for ( $ i = 0 ; $ i < min ([ $ lenA , $ lenB ]) ; $ i ++ ) { $ c = $ this -> getCharIndex ( mb_substr ( $ a , $ i , 1 )) ; $ d = $ this -> getCharIndex ( mb_substr ( $ b , $ i , 1 )) ; $ ret = $ c <=> $ d ; if ( $ ret !== 0 ) { break ; } } return $ ret ?: $ lenA <=> $ lenB ; } /** * ひらがな一文字を取っていろは順での順位を返す * @param string $c ひらがな一文字 * @return int いろは順で何番目か * @throws RangeException 引数の文字列にいろは順が付けられない場合 */ private function getCharIndex ( string $ c ) : int { $ ret = array_search ( $ c , $ this -> iroha, true ) ; if ( $ ret === false ) { throw new RangeException ( "Character ${$c} is not supported!" ) ; } return $ ret ; } } 使い方のサンプルも兼ねて、テストも簡単に作ってみました。 <?php namespace Tests\Unit; use PHPUnit\Framework\TestCase; use IrohaOrder; class IrohaOrderTest extends TestCase { /** @var IrohaOrder $irohaOrder */ private $ irohaOrder ; public function setUp () : void { $ this -> irohaOrder = new IrohaOrder () ; } /** * ひらがな文字列配列がいろは順に並ぶことの確認 * @return void */ public function testIrohaOrderSort () { $ expected = [ 'いしき' , 'いんかん' , 'ろうか' , 'はにわ' , 'におう' , 'におうもん' , 'ほとけ' , 'ほんき' , 'へいし' , 'へんろ' , 'とうき' , ] ; $ sorted = $ this -> shuffleAndSort ( fn ( &$ arr ) => $ this -> irohaOrder -> sort ( $ arr ) , $ expected ) ; $ this -> assertEquals ( $ expected , $ sorted ) ; } /** * 配列をシャッフルしてソート関数を適用して返す * @param callable $sortFunc ソート関数 * @param array $arr 対象配列 * @return array */ private function shuffleAndSort ( callable $ sortFunc , array $ arr ) : array { shuffle ( $ arr ) ; $ sortFunc ( $ arr ) ; return $ arr ; } } 実行してみましょう。 PHPUnit 9.5.2 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 00:00.004, Memory: 4.00 MB OK (1 test, 1 assertion) うまく動いているようです。 おわりに いかがでしたでしょうか? 本記事では、日本語文字列を値として持つ一次元の連番整数値添字の配列を対象として、 PHP で利用可能なソート方法をいくつか取り上げて具体例とともに紹介しました。ポイントをまとめると以下のようになります。 PHP で配列をソートする方法はいろいろある シンプルな sort 関数の結果は時に「イイ感じ」にならない PHP で日本語文字列を「イイ感じ」の順序で並べる方法は 3 通り その 3 通りの方法は以下の通りです。 sort 関数で SORT_LOCAL_STRING フラグを指定する 最も低コスト 実際の並び順は 処理系依存 (?) intl 拡張の Collator::sort または collator_sort を使う 拡張の有効化が必要で少し面倒 UCA に準拠した順序でのソートが可能 独自ルールを実装する 最も高コスト 並び順ルールを自由に決められる それでどの方法が一番「イイ感じ」なのかというと、結局要件次第にはなってしまうものの、個人的には 2 番の intl 拡張の Collator::sort または collator_sort を使う方法が以下の点で「イイ感じ」だと思います。 Unicode の技術標準として定められた仕様に準拠できる 外部のよくテストされたライブラリを使用できる 仕様の標準さと実装コストのバランスがよい 以上、 PHP で日本語の文字列配列をイイ感じにソートする話でした。少しでもみなさんの PHP ライフの参考にしていただけたら幸いです。 ※ 本記事に記載したサンプルコードは php 7.4.15 ( cli ) で動作を確認しています。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 言語によっては他にもっといい型があるかもしれませんが、その辺はスルーでお願いします。 ↩ https://ja.wikipedia.org/wiki/ 辞書式順序 ↩ https://github.com/php/php-src/blob/94d96b3c979a60e47abe209506c3947a16abff40/Zend/zend_operators.c#L2684 ↩ https://github.com/php/php-src/blob/94d96b3c979a60e47abe209506c3947a16abff40/Zend/zend_operators.c#L1976 ↩ https://github.com/php/php-src/blob/94d96b3c979a60e47abe209506c3947a16abff40/ext/intl/collator/collator_sort.c#L51 ↩ https://unicode-org.github.io/icu/userguide/collation/api.html#compare ↩ https://github.com/php/php-src/blob/94d96b3c979a60e47abe209506c3947a16abff40/ext/intl/collator/collator_sort.c#L168 ↩
アバター
noriharu3 です。 業務で AWS の Lambda を使う機会があったので、簡単にまとめてみました。 Lambdaとは? Lambdaの嬉しいところ インフラの管理が不要 使った分だけの支払い Lambdaの場合 どういうことができるのか?苦手なのか? Lambdaが適さないケース Lambda関数開発 環境構築 ローカルPCでLambda関数を作成する ローカルPCでLambda関数を実行する AWSにデプロイする API Gateway+Lambdaにリクエストを送ってみる まとめ Lambdaとは? AWS のドキュメント *1 には、次のように記載されています。 AWS Lambda は、サーバーのプロビジョニングや管理の必要なしにコードを実行できるコンピューティングサービスです。 簡単に言うと、「サーバーを構築しなくとも、コードを実行できるよ」ということです。 図 *2 でいうと、こちらがわかりやすいと思います。 Lambdaの嬉しいところ では、Lambdaの嬉しいところ、メリットについて書いていきたいと思います。 インフラの管理が不要 インフラの管理といっても色々あると思います。 とりあえずセキュリティについて、次のことは AWS *3 が責任をもって対応すると言ってくれています。 AWS Lambda については、 AWS が基盤となるインフラスト ラク チャ、基盤サービス、 オペレーティングシステム 、アプリケーションプラットフォームを管理します。 なので、セキュリティについて開発者は主に次だけしっかりやればいいことになります。 IAMの権限 コードのセキュリティ( 脆弱性 ) 機密データの保管とアクセス管理 古いですが、セキュリティ以外では次のことを担保すると述べていますね。 *4 – キャパシティ – スケール – デプロイ – 耐障害性 – モニタリング – ロギング – セキュリティパッチの適用 なるほど。サーバーやOSの構築だけでなく、スケール管理、モニタリングなどもLambdaの標準サービスとして付帯している。 インフラのメンテナンス時間や定期的なダウンタイムもない。 たしかにこれは運用している人 からし たら嬉しい。 使った分だけの支払い 実際に、LambdaとEC2の月額費用を比較してみましょう。 毎日0時に Python コード(Lambdaで実行した場合の平均時間1分)を実行するものとします。 ※ 計算しやすくするため、1ヶ月は30日とする Lambdaの場合 ちなみに、Lambda では、指定してメモリ量に比例した CPU パワーとその他のリソースが割り当てられます。 メモリはLambdaで指定できる上限の10240MB(10GB)で計算します。 Lambda に512 MB のメモリを割り当て、30回実行し、毎回の実行時間が 60 秒間だった場合、 1 か月のコンピューティング料金 合計コンピューティング (秒) = 30 × 60 秒 = 1,800 秒 合計コンピューティング (GB-秒) = 1,800 × 10,240 MB ÷ 1024 = 18,000 GB-秒 合計コンピューティング – 無料利用枠 = 1 か月の請求コンピューティング GB-秒 18,000 GB-秒 - 400,000 GB-秒の無料利用枠 < 0 1 か月のリクエスト料金 30 件のリクエスト – 1,000,000 件の利用無料枠のリクエスト < 0 合計月額料金 合計料金 = コンピューティング料金 + リクエスト料金 = 0 USD + 0 USD = 0 USD/月 この段階で、EC2の負け確定ですねw 負け戦ですが、EC2の料金はこちら *5 を参照ください。 どういうことができるのか?苦手なのか? できることがたくさんあると思いますが、公式の資料 *6 には下記が記載されていました。 API サーバーの代わり アラート通知 etc Lambdaが適さないケース Lambdaにもいくつか制約があるので注意です。気になったものは下記になります。 大量のリソースが必要となる処理 Lambdaで指定できるメモリの上限 *7 は10240MB(10G) 900秒以上時間がかかる処理 Lambdaで指定できる タイムアウト の上限は900秒 *8 (15分)。900秒以上かかると、Lambdaはエラーを返します。 ペイロード *9 が6MB以上のリク エス トbodyまたはレスポンスbody リク エス トbodyまたはレスポンスbodyの ペイロード が6MB以上あった場合、Lambdaはエラーを返します。 OS、ネットワーク、ストレージレベルで制御したい 好みのOSを選定したい Lambdaは、 Amazon Linux 2 *10 がベースになっています。 Lambda関数開発 続いて、実際にLambdaで実行するコード(以下、Lambda関数)を作成し、動かしてみようと思います。 環境構築 ローカルPCでLambda関数を作成する ローカルPCでLambda関数を実行する AWS にデプロイする API Gateway +Lambdaにリク エス トを送ってみる 環境構築 公式 *11 を参考に、Docker と AWS SAM CLI をインストールします。 Windows , Mac , Linux で手順が異なるようなので、詳細は公式のドキュメントを見てください。以下、 Mac での手順です。 $ brew install docker $ brew tap aws/tap $ brew install aws-sam-cli また sam コマンドのリファレンスはこちら *12 。 ローカルPCでLambda関数を作成する sam init コマンドで、アプリケーションのプロジェクトを作成します。 このLambda関数は、 {"message":"hello world"} というレスポンスを返します。 $ sam init Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 What package type would you like to use? 1 - Zip (artifact is a zip uploaded to S3) 2 - Image (artifact is an image uploaded to an ECR image repository) Package type: 1 Which runtime would you like to use? 1 - nodejs12.x 2 - python3.8 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore3.1 7 - nodejs10.x 8 - python3.7 9 - python3.6 10 - python2.7 11 - ruby2.5 12 - java8.al2 13 - java8 14 - dotnetcore2.1 Runtime: 1 Project name [sam-app]: Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates AWS quick start application templates: 1 - Hello World Example 2 - Step Functions Sample App (Stock Trader) 3 - Quick Start: From Scratch 4 - Quick Start: Scheduled Events 5 - Quick Start: S3 6 - Quick Start: SNS 7 - Quick Start: SQS 8 - Quick Start: Web Backend Template selection: 1 ----------------------- Generating application: ----------------------- Name: sam-app Runtime: nodejs12.x Dependency Manager: npm Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./sam-app/README.md sam build コマンドでビルドし、実行できる状態にします。 $ sam build Building codeuri: hello-world/ runtime: nodejs12.x metadata: {} functions: ['HelloWorldFunction'] Running NodejsNpmBuilder:NpmPack Running NodejsNpmBuilder:CopyNpmrc Running NodejsNpmBuilder:CopySource Running NodejsNpmBuilder:NpmInstall Running NodejsNpmBuilder:CleanUpNpmrc Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided ローカルPCでLambda関数を実行する sam local start-api コマンドで、 API Gateway を模したHTTPサーバーを作成し、擬似的な API Gateway を経由した動作確認を行うことができます。 $ sam local start-api Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET] You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template 2021-03-05 17:50:58 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit) Invoking app.lambdaHandler (nodejs12.x) 別ターミナルで http://127.0.0.1:3000/hello にアクセスします。 お、レスポンスが返ってきましたね。 $ curl http://127.0.0.1:3000/hello {"message":"hello world"} AWS にデプロイする sam deploy -g コマンドで、 AWS にデプロイします。 -g オプションを付けると、デプロイ設定を対話的にすすめることができます。 $ sam deploy -g Configuring SAM deploy ====================== Looking for samconfig.toml : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: AWS Region [us-east-1]: ap-northeast-1 #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: y HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y Save arguments to samconfig.toml [Y/n]: y Looking for resources needed for deployment: Found! (以下長いので、省略) API Gateway +Lambdaにリク エス トを送ってみる デプロイは完了しているので、後はリク エス トを送るだけです。 $ curl https://**********.execute-api.ap-northeast-1.amazonaws.com/Prod/hello {"message":"hello world"} まとめ EC2と比較して、Lambdaを使うと大幅なコスト削減ができるかもしれないので、魅力ですね。 また、インフラの管理を AWS に任せることで、運用業務にかかるコストの削減も見込めます。 ただ、Lambdaにはいくつか制約があり、適さないサービスや処理があるので、選定する際は注意です。 また SAM CLI を使えば、 AWS アカウント持っていなくても、さくっとローカルで Lambda 関数を動かすことができるので、興味のあるかたは是非やってみてください。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html *2 : https://www.bit-drive.ne.jp/managed-cloud/column/images/column14/img_01.jpg *3 : https://d1.awsstatic.com/serverless-jp/Security%20Overview%20of%20AWS%20Lambda_JP.pdf *4 : https://d1.awsstatic.com/webinars/jp/pdf/services/20150701_AWS-BlackBelt-runcodeinthecloud.pdf *5 : https://aws.amazon.com/jp/ec2/pricing/on-demand/ *6 : https://d1.awsstatic.com/webinars/jp/pdf/services/20150701_AWS-BlackBelt-runcodeinthecloud.pdf *7 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-console.html *8 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-console.html *9 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/gettingstarted-limits.html *10 : https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html *11 : https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html *12 : https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html
アバター
技術広報の syoneshin です。 今回は当社の開発組織メンバー達に 『おすすめのITエンジニア向けイベント』 と おすすめの理由を聞きました。 質問:皆さんの「おすすめのエンジニア向けイベント」 を教えてください。 【目次】 『PHPerKaigi』 『AWS Summit 』 『JJUG CCC』 『Web × PHP TechCafe』 『PostgreSQLアンカンファレンス』 『なるセミ』 『PHP Conference Japan』 『デブサミ・デブサミ関西・デブスト』 『Builders Box』 『プロダクトマネージャーカンファレンス』 『自動化大好きエンジニアLT会』 ITエンジニア向けイベント情報が検索できるサイト 6選 まとめ まず当社開発メンバーが選んだ「おすすめのITエンジニア向けイベント」は 『PHPerKaigi』 phperkaigi.jp 以下はおすすめ理由やポイント イベント自体はカジュアルな雰囲気で、参加者間での交流も盛んな印象です。 開催日3/27 に「 PHP でも アーキテクチャ テストしたい!」の発表テーマで登壇します! 開催日3/28に LT登壇します!是非、ご参加下さい! 次いで、当社開発メンバーが選んだ「おすすめのITエンジニア向けイベント」は 『 AWS Summit 』 partners.awscloud.com 以下はおすすめ理由やポイント AWS の最新情報、導入事例などが知れて勉強になりおすすめです。 基礎的な セミ ナー時間もあるので初心者にもおすすめです! 次いで、当社開発メンバーが選んだ「おすすめのITエンジニア向けイベント」は 『 JJUG CCC』 www.java-users.jp 以下はおすすめ理由やポイント 直近の Java の動向や流行りを知れるため、おすすめです。 Java 関連の技術や事例に関するセッションが豊富。 JJUG CCC 2020 Fallには当社メンバー2名が登壇しました! 次いで「おすすめのITエンジニア向けイベント」は 当社主催のイベント 『Web × PHP TechCafe』 rakus.connpass.com 以下はおすすめ理由やポイント レベルは高すぎず、会話ベースの進行のため、オンライン参加がしやすく、ラジオのように聞きながら情報をピックアップできる点がおススメです。 ゆるく雑談形式で最新のトピックを知ることができるので良いです。 外部から一緒に語り合ってくれる方も、聞き専門の方も増えているイベントです!是非、ご参加下さい! 次いで「おすすめのITエンジニア向けイベント」は 『 PostgreSQL アンカンファレンス』 pgunconf.connpass.com 以下はおすすめ理由やポイント PostgreSQL の新機能や内部的な仕組み、お試し系の検証結果などを知ることができて勉強になります。 毎年メジャーバージョンアップの時期に実施されるので、情報収集がてら参加するのは良いと思います。 次いで「おすすめのITエンジニア向けイベント」は 『なる セミ 』 nrs-seminar.connpass.com 以下は気になった理由やポイント 設計系ではよくお世話になっているイベントの一つです。 毎回テーマは違いますが、参考になるイベントが多いです! 次いで「おすすめのITエンジニア向けイベント」は 『 PHP Conference Japan』 phpcon.connpass.com 以下は気になった理由やポイント 2020開催のイベントには当社メンバー2名もLT登壇! 毎年、人も活気もすごいイベントです! 次いで「おすすめのITエンジニア向けイベント」は 『 デブサミ ・ デブサミ 関西・デブスト』 event.shoeisha.jp 以下はおすすめの理由やポイント デブサミ 関西は関西では数少ない大きなイベント。著名人も多く登壇されており、直接お話を伺え、刺激を受けやすいと思います。 デブストは同年代のエンジニアがやっていることを知れる、いい機会でした。 今期の デブサミ 関西とデブストにはそれぞれ当社メンバーも登壇しました! 次いで「おすすめのITエンジニア向けイベント」は 『Builders Box』 buildersbox-online.com 以下はおすすめの理由やポイント Sansan社が主催しており、著名な方のセッションが聞ける貴重なイベント。 国内の Saas 企業とコラボしたイベントなどもあり、内容はどれも面白くおすすめ。 次いで「おすすめのITエンジニア向けイベント」は 『プロダクトマネージャーカンファレンス』 2020.pmconf.jp 以下はおすすめの理由やポイント PdM意外の方でも、どうプロダクトへ貢献すべきかを理解する良い機会になります。 前回イベントで、PdMの最新情報をキャッチアップできました。 次いで「おすすめのITエンジニア向けイベント」は 当社主催のイベント 『自動化大好きエンジニアLT会』 rakus.connpass.com 以下は気になった理由やポイント テストやインフラ構成管理など、様々な分野における自動化が取り上げられていました。 LT登壇者が多く、豊富な自動化の事例が学べるイベントです! その他、以下のITエンジニア向けイベントを、当社エンジニア達が推薦しておりました。 『Spring Fest』 jsug.doorkeeper.jp 『 VSCode Meetup』 vscode.connpass.com 『Vue Fes Japan』 vuejs-jp.org 『CloudNative Days』 cloudnativedays.jp 『 スクラム フェス大阪』 www.scrumosaka.org 『 ソフトウェアテスト 自動化カンファレンス』 testautomationresearch.connpass.com 『 CSS Nite 』 cssnite.jp などなど 全50件近くの「おすすめのITエンジニア向けイベント」が 当社内で共有されました。 ITエンジニア向けイベント情報が検索できるサイト 6選 ここでは、ITエンジニア向けイベントの情報が探せるサイトをご紹介します。 TECHPLAY techplay.jp connpass connpass.com DoorKeeper www.doorkeeper.jp Street academy www.street-academy.com Peatix https://peatix.com/ peatix.com OpenCU www.opencu.com まとめ 以上、いかがだったでしょうか。 昨年からITエンジニア向けイベントもオンライン開催が主流になり 皆さんも、イベントを「はしご」する機会が増えたのではないかと思います。 当社も情報発信と交流を通じた見識を広める機会として、週1~2回ほど多様なテーマでイベントを主催しております。 もし、当社イベントに少しでもご興味をお持ちいただけましたら 、是非ご参加下さい。 主催イベント一覧 rakus.connpass.com 本記事でご紹介した おすすめのITエンジニア向けイベント が皆さまの情報探索の一助となれば幸いです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 技術広報のyayawowoです。 いつも ラク スのエンジニアブログのご購読、そしてエンジニアイベントへのご参加、ありがとうございます。 今回は、『 開発戦略・マネジメント・設計 』をテーマに実施した、2021年最初の ラク スMeetup 2Daysの様子をお届けします! 本記事では、2/17(水)にお届けした 『PdM・インフラ戦略』 について紹介させていただきます。 ※2/16(火)【Meetup】PM・ リファクタリング 戦略は こちら はじめに イベントテーマ概要 発表の紹介 ロバストネス分析を用いた設計と工数見積もり JavaCCとSpring Expression Languageを用いたユーザ定義項目 開発を止めるという選択 インフラ業務のモデリングについて考えてみた おわりに イベントテーマ概要 Day2では人気の楽楽シリーズを担当しているエンジニア陣を中心に、大規模な SaaS 開発におけるエピソードや、多数のサービスを展開中の ラク スが構想しているインフラ戦略を紹介しました。 今回は以下サービスに携わるエンジニア3名と、 ラク ス全体のインフラ基盤を支えるエンジニア1名の計4名が登壇させていただきました。 楽楽勤怠 楽楽精算 楽楽明細 発表の紹介 それではここから各発表内容と資料を共有させていただきます! ロバストネス分析 を用いた設計と 工数 見積もり まずは楽楽精算のサブリーダである坂田が、設計工程で取り入れている ロバストネス分析 を用いた設計と 工数 見積もりについて、紹介させていただきました。 目新しい手法ではありませんが、システム構成を三つの要素で抽象化し、それらの関係性を非常に簡単な図で表現することができる優れた手法です。 またこれを行うことにより改修範囲の要 素数 が 定量 的に洗い出せることから、楽楽精算開発チームでは、これらの分析結果を応用した 下流 工程の 工数 見積もりも行っています。 今回はこれらの取り組みとその効果に関して紹介しました。 speakerdeck.com JavaCC とSpring Expression Languageを用いたユーザ定義項目 次に、楽楽勤怠チームの山口の発表です。 楽楽勤怠にてカスタム項目というユーザが楽楽勤怠に標準で持っているプロパティの値を利用して、独自に計算式を定義できる機能を開発しています。 この機能を開発する際は計算式をどうやって評価し、計算式からどうやって計算結果を算出するのかが肝となりました。 この肝となった部分についてフロントエンドとバックエンドの役割分担や実現方法を紹介しました。 speakerdeck.com 開発を止めるという選択 ラク スでは、開発チームに プロダクトマネジメント の人員を各商材配置し、意思決定から価値の提供までのスピードをあげる取り組みを行っています。 しかし、一言に「 プロダクトマネジメント 」といってもその取り組みに唯一解はなく広範囲に渡るため、試行錯誤しながら日々取り組んでいるのもまた現実です。 プロダクトマネジメント の大きな目的である、「求めている顧客に早く価値を届ける」という目的と、自分の過去の経験が邪魔をしたことで、失敗した 経験談 を超上流(サービス仕様)決定に携わっている松浦が紹介しました。 speakerdeck.com インフラ業務の モデリング について考えてみた 最後は、 ラク ス全体のインフラ基盤の責任者である竹田より、インフラ業務の モデリング についてです。 大規模な SaaS 開発の裏側では Saas サービスのサービス・機能特徴に合わせた独自技術がどんどん導入されています。 今回は アプリ開発 職よりはるかに少ないメンバーで組織運営を行う組織の中で、 増え続けるサービス、技術の深い理解 サービス・事業要件に応えるインフラ基盤 「安定・安心・安全(3A)」 を効率よく実現させ、コスト部門として設備管理にかかる費用の低減を続けるにはこれから何をしていくべきかを考察し、ご紹介しました。 speakerdeck.com おわりに 2021年最初の ラク スMeetupはどうでしたか? 今回の4名の発表が、皆さまにとって新しい気づきや成長につながる機会となっていますと幸いです! 今後も ラク スMeetupでは日々のエンジニアの取り組みを発信してまいりますので、次回もぜひご参加いただけますと幸いです。 また、前日に開催した 【Meetup】PM・リファクタリング戦略 も別記事にまとめておりますので、是非ご確認ください! そして直近ですが、 PdM がテーマのイベントを3/18(木)に開催予定です! プロダクト設計、開発、デザインの PdM にご興味のある方は、ぜひconnpassをご確認いただければと思います。 ご参加お待ちしております! rakus.connpass.com
アバター
はじめに 技術広報のyayawowoです。 いつも ラク スのエンジニアブログのご購読、そしてエンジニアイベントへのご参加、ありがとうございます。 今回は、『 開発戦略・マネジメント・設計 』をテーマに実施した、2021年最初の ラク スMeetup 2Daysの様子をお届けします! 本記事では、2/16(火)にお届けした 『PM・ リファクタリング 戦略』 について紹介させていただきます。 ※2/17(水)【Meetup】PdM・インフラ戦略は こちら はじめに イベントテーマ概要 発表の紹介 14年目のサービスと今後も歩むためのリファクタリング戦略 仮想基盤サーバのリプレイスに伴うインフラ設計 入社4ヶ月の新入りPdMの取り組み 変化の時代に活かす「みんなのプロジェクトマネジメント」 おわりに イベントテーマ概要 Day1では開発、インフラ、 プロダクトマネジメント 、プロジェクトマネジメントの4つの立場のエンジニアから、今年度 ラク スがチャレンジしてきました取り組みを紹介しました。 今回は以下サービスに携わるエンジニア4名が登壇させていただきました。 配配メール クルメル 楽楽販売 発表の紹介 それではここから各発表内容と資料を共有させていただきます! 14年目のサービスと今後も歩むための リファクタリング 戦略 現在14年目になる配配メールでも長年続くサービスならではの過去からの負債がありました。 また、過去の ソースコード を参考にすることも少なくないので負債は日々増えるばかり… いつか リファクタリング したいと思いながらも肥大化してしまった負債に手が出せないジレンマがありました。 しかし、このままではダメだと一念発起し問題に向き合う事を決め、リリースサイクルに影響を与えず円滑に リファクタリング を進める為に実施した工夫について、配配メール開発担当の西原が紹介しました。 speakerdeck.com 仮想基盤サーバのリプレイスに伴うインフラ設計 次に、「配配メール」「クルメル」のインフラ開発担当である小西の発表です。 ひと言で「設計」といっても様々な事を検討し、形にする必要があります。 基本設計・詳細設計・移行設計・運用設計などの各フェーズでの設計を行い、問題なく実行できるようにする必要があります。 今回は、仮想基盤サーバのリプレイスを通じて実際に行った設計の一部をご紹介し、今後のサービス運用と継続的な改善に繋がるインフラチームとしての設計方針を発表しました。 入社4ヶ月の新入りPdMの取り組み 楽楽販売(旧名:働くDB)はローンチから10年以上、たくさんのユーザ様に利用されているシステムです。 これまで営業 / CS / 企画 / 開発とお互いの領域を研ぎましていたフェーズから、今後のさらなる成長を目指し、各部門を超え組織横断でプロダクト強化を行うための活動について、入社直後の永橋がPdMとしてどう取り組んだかをご紹介しました。 
入社4ヶ月 新入りPdMの取り組み from Tsuyoshi Nagahashi www.slideshare.net 変化の時代に活かす「みんなのプロジェクトマネジメント」 最後に、配配メール開発チームのエンジニア リングマ ネージャである大塚の発表です。 「プロジェクトマネジメント」はプロダクト開発の役割であると同時にエンジニアのスキルセットでもあります。 プロジェクトをゴールに導くこのスキルセットは不確実な変化の時代にエンジニアが取るべき行動のヒントを与えてくれます。 今回はこれまでの SaaS プロダクト開発の現場で実践してきた事例を「プロジェクトマネジメント」の視点でご紹介し、チームのリーダーやマネージャーを目指す人はもちろん、変化の時代を生き抜く全てのエンジニアにおすすめしたい「みんなのプロジェクトマネジメント」についてお話ししました。 speakerdeck.com おわりに 今年度 ラク スがチャレンジしてきました取り組みは、いかがでしたでしょうか? ラク スの取り組みが、皆さまにとって新しい気づきや成長につながる機会となっていますと幸いです! 今後も ラク スMeetupでは日々のエンジニアの取り組みを発信してまいりますので、次回もぜひご参加いただけますと幸いです。 また、翌日に開催した 【Meetup】PdM・インフラ戦略 も別記事にまとめておりますので、是非ご確認ください! そして直近ですが、 PdM がテーマのイベントを3/18(木)に開催予定です! プロダクト設計、開発、デザインの PdM にご興味のある方は、ぜひconnpassをご確認いただければと思います。 ご参加お待ちしております! rakus.connpass.com
アバター
株式会社 ラクス のrakusMoritaです。 2021年2月22日にオンラインで開催された Laravel Meetup Tokyo Vol.13 に参加したので、内容のポイントをまとめてみました。 どの話も興味深く、そして実践しやすい内容だったので共有させていただきます。 laravel-meetup-tokyo.connpass.com Laravelと継続的デプロイ スピードと質を求められている状況下での基本構成 注意点等 継続的なデリバリのために組織として取り組むこと DDD入門とLaravel DDDの理解でよくある間違い 結局DDDって何? DDDのメリット どうやって実践するの? よく聞く軽量DDDとはどう違うの? 実装するには Laravel8で使えるJavaScriptパッケージ「Inertia.js」が便利 TDD視点から見るRequestクラスの依存性 まとめ Laravelと継続的デプロイ スピードと質を求められている状況下での基本構成 クラウド ・コスト削減 ・スケーラビリティが容易 コンテナ ・作業時間短縮 ・DevOpsとの相性良い 注意点等 ログの構造化は必須 AWS のCloudWatch等で、ログは構造化( JSON 化)しておくとのこと。 視認性が格段にアップして開発や デバッグ ・調査の時短になる。 vendor内をコンテナ化していると、ビルドに時間がかかったりする場合がある 安定性は向上するので、どちらを取るかは組織内で要相談。 デプロイを自動化していたとしても、突然デプロイが失敗することもある デプロイが短時間でできると思っていても、デプロイ当日にパニックになることもあるので、余裕を持ったスケジュール組むこと。 そして、定期的なデプロイをして、突然の「動かない」を極力なくす。 継続的なデリバリのために組織として取り組むこと 運用できる人を増やす 一部の人しか触れないではなく、なるべく多くの人が携わる。 関係者を巻き込みながら、少しずつやれることを増やしていく 体制面でも継続可能な状況を作ることが理想。 ログの構造化は確かに必須ですね。個人的に即効性があって良いと思いました。 DDD入門とLaravel 最近よく耳にする「 ドメイン 駆動設計」、通称「DDD(domain-driven design)」ですが、具体的にわかりにくいと思いませんか? 今回具体的にどういうことなのかを掘り下げた内容が聞けて勉強になりました。 DDDの理解でよくある間違い 「 アーキテクチャ で、層に分かれて実装すれば良い」  これ、間違いです 「 DDDでデータベース肥大化対策どうやるの?」  実は関係ありません 「 MVC ではDDDはできないのでは?」  これも全く関係ありません 「DDDで実装したけど、全然楽になりません」  長期的に見ると楽になるはず・・・ 結局DDDって何? 開発スタイルのひとつ 「実現したいこと」 や 「解決したい問題」 、それを 「 ドメイン 」 という。 その「やりたいこと」を起点として開発していくのがDDD。 実装言語や フレームワーク 、ストレージや アーキテクチャ などは含まれない 一般的な非機能要件は含まれない。 機能要件が含まれる。 DDDは、どういう アーキテクチャ で、どういう言語、 フレームワーク 、データベース・・・などの技術的な要素とは一切関係なく、 何を作るのか? それを考えて実現していくことだったのですね。 一般的な「 ドメイン 」と違うのが理解し難くしている原因の一つかもしれません。 DDDのメリット 何をしたいかをまず考えるため、先を見越した設計ができる 開発チームで共通の認識が生まれ、認識のずれからくるやり直しや確認が減る 突然の仕様変更に困ったことはありませんか?システムや機能の根幹を揺るがしかねない事態になる可能性だって往々にしてあります。 そういう事態を未然に防ぎやすいのがDDDの特徴です。 「何を実現したいか」が関係者で共有ができているため、設計段階から将来の変更を見越したものが作りやすいというわけです。 膨大な改修コストや、目的からずれた不要な機能開発とはこれでおさらばです。 どうやって実践するの? カスタマーサービス チームに加わったり企画会議に参加して、開発以外の概念理解や知識をつける ユーザー層や実現したいこと、チーム構成は変わっていくため、継続的にコミュニケーションや分析を行う チーム全員で ドメイン (会社が提供したい価値)モデルを導き出し、全員で同じ認識と同じ言語で共通理解をする 言葉の認識を合わせていくことが大切とのこと。 例えば「ユーザー」という言葉でも、エンジニアは「DBのユーザーテーブルのことだな」と思っていても、実際は「会員」を指しているのかもしれないし、「有料会員」のことを指すのかもしれない。 まずはその共通認識を行うことが第一歩。 文脈でもその意味は変わってくるので、そのバックグラウンドに基づく知識が共有できていれば、迷いやすれ違いが少なくなるとのこと。 よく聞く軽量DDDとはどう違うの? 軽量DDDとは、DDDで得られた知識を反映しやすい実装パターン、構造だけを採用したもので、DDDとは別物です。 こちらの意味だけが先行して、DDDの本質を見失う人も多そうな印象ですね。 実装するには Laravel等を用いて開発するときは、DDDの知識を落とし込みやすいパターンを無理に最初から実現しなくても良い 処理の共 通化 を行わず、まずは分析と知識に基づいて、クラスにする 同じような箇所はコピペでも良い。あとから共 通化 させるほうが収束しやすいし、 リファクタリング もしやすい。 まずは本当に共 通化 すべきもののみ共 通化 すること。 余談ですが、「設計をちゃんと考えるようになってからコピペが増えた」なんて話もちらほら聞きます。 DDDは詳しく知らなかったので、聞きながら実践イメージもわき、非常に興味深かったです。 Laravel8で使える JavaScript パッケージ「Inertia.js」が便利 Laravel8で使える、ビューとのデータのやり取りが容易になる JavaScript パッケージ「Inertia.js」でお手軽にモダンなSPAが構築できるというお話もありました。 軽く紹介があったので、調べて簡単にまとめてみました。 Inertia.jsとはLaravel8の標準認証ライブラリ「Jetstream」で使われている、フロントエンドとバックエンドのデータ連携技術 Vueファイルとのデータ連携がテンプレートエンジンと同じように扱えるため、SPA化も容易 Vue.jsなどでSPAを実現するには、 Ajax の制御やVue側でルーティングを行う必要があり、開発コストがかさみやすいですが、それが不要になります。 Laravelのルーティングの記述で、 Ajax 通信・ルーティングも一緒にコン トロール できるので楽にSPAを実現できるのが魅力的ですね。 TDD視点から見るRequestクラスの依存性 Requestクラスにはユーザー認証や情報の保持、バリデーションなど、色々な情報がありすぎて、 ユニットテスト が書きづらい バリデーションと認証が共存しているなど、テストクラスの文脈がぶれることがあるので、何をしているテストかわからない。何をテストすればいいかわかりにくいという内容で、そこから転じて 「なんでもやってるクラスはテストがつらい。」 この心の叫び、エンジニアあるあるではないでしょうか? 設計や実装時にはそう思われないクラスづくりが大切だと改めて考えさせられました。 まとめ 色々気づきや発見のある有意義な時間でした。 個人的にはDDDの概念が理解できたことが大きな収穫でした。 ドメイン 駆動はいわば「本質を見失わない開発」ということだったのですね。 また参加してみたいと思います。
アバター
はじめに こんにちは。itoken1013です! 度々お送りしています超入門シリーズ、今回ご紹介するのは Bootstrapの使い方 です! Bootstrapを利用することで、簡単にページデザインを仕上げることができます。 HTML/ CSS は分かるけどBootstrapには触れたことのない方、今まで体系的には理解せずにBootstrapを利用していた方にオススメの内容です。 それでは解説していきたいと思います! はじめに Bootstrapとは まず、フロントエンドとは? では、Bootstrapとは? Bootstrapを使うことによるメリット レスポンシブWebデザインに対応している 導入のしやすさ、汎用性 コンポーネントが多数用意されている Bootstrapのセットアップ グリッドシステム よく使うコンポーネント フォーム ボタン テーブル 画像 おわりに   Bootstrapとは まず、フロントエンドとは? Bootstrapはフロントエンドの開発で使うための フレームワーク ですが、まずはフロントエンドが何かを説明します。 (厳密な定義からは逸脱しますが)今回のご説明の範囲では、フロントエンドとは HTML、 CSS 、 JavaScript を使って開発するブラウザ上のUI(ユーザ・インタフェース)部分 と解釈いただければと思います。 ユーザが見ることができ、操作を行うことでシステムに命令を与えるための領域、とも言うことができます。 フロントエンドの開発で必要な技術要素は多岐に渡りますが、より詳細な情報については当社のエンジニアが書いた以下の記事を読むとご理解いただけるかと思います。 tech-blog.rakus.co.jp では、Bootstrapとは? それではBootstrapのご説明ですが、Bootstrapは フロントエンドの開発で利用する CSS フレームワーク に位置付けられます。 CSS は フレームワーク を利用せずとも自前のコーディングで装飾を施すことができますが、Bootstrapをはじめとした フレームワーク を導入することで効率的に CSS を仕上げることが可能です。 特にBootstrapは後述の通り、HTMLの各要素へ規定のクラス名を指定するだけでデザインを実現できるなど、 フレームワーク を利用しない場合と比べて圧倒的に早くデザインを仕上げることができてしまいます。 また フレームワーク であるため、一定のルールをもってコーディングできる点はチーム開発において有効であると考えることができます。 Bootstrapはもともと Twitter 社が開発し、2021年2月時点ではバージョン5.0.0が最新版となっています。 いまや世に CSS フレームワーク は数多く存在しますが、Bootstrapはその先駆けとなる フレームワーク でした。 getbootstrap.jp Bootstrapを使うことによるメリット 上記でBootstrapを使うメリットに触れましたが、より詳細に特徴3点を説明していきます。 レスポンシブWebデザインに対応している 多くの方がBootstrapを使う最大のメリットとして挙げるのが、レスポンシブWebデザインに対応している点です。 レスポンシブWebデザインとはPC、 タブレット 、 スマホ 等のデ バイス で異なる画面サイズにおいて、最適なレイアウトデザインへ切り替える手法です。 Bootstrapでは関単にレスポンシブWebデザインに対応したスタイル指定を行うことができ、デ バイス ごとに異なるHTMLを用意する手間を省くことができます。 導入のしやすさ、汎用性 Bootstrapの導入手順は後述しますが、とても簡単です。 また構築するプロダクトの規模や種類を問わずに利用できる汎用性があります。 このように手軽にデザインを反映できる点は大きなメリットと言えるでしょう。 コンポーネント が多数用意されている Bootstrapではデザイン性に優れた各 コンポーネント (ボタンやフォームなど)が提供されています。 さらにこれらの コンポーネント を利用するための手順は、各HTML要素に指定されたclassを追記するだけで実現できます。 非デザイナーのエンジニアでも、簡単な手順で一定レベルのデザインを実現できます。 以降では、定番となる コンポーネント を紹介したいと思います。 Bootstrapのセットアップ それではここから簡単な使い方を紹介していきます。 まずはBootstrapを使える状態とするため、セットアップを行いましょう。 ※今回は CDN (コンテンツ・デリバリー・ネットワーク)を使わず、Bootstrapをダウンロードして利用できる状態にしていきます。 まずは公式ページにアクセスし、Bootstrapをダウンロードしてください。 getbootstrap.jp 上記ページの「Compiled CSS and JS」配下のダウンロードボタンをクリックすると、Bootstrapのコード一式のダウンロードが開始されます。 ダウンロード完了後、Zipファイルを解凍すると css フォルダとjsフォルダが表示されるはずです。 今回はこの2フォルダを任意のフォルダ配下にコピーし、同列にindex.htmlを作成します。 <!DOCTYPE html> < html lang = "ja" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title > Rakus </ title > < link href = "css/bootstrap.min.css" rel = "stylesheet" > </ head > < body > < h1 > Hello, Rakus! </ h1 > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > </ html > 上記index.htmlではダウンロードしてきた「bootstrap.min. css 」および「bootstrap.min.js」を読み込んでいる点をご確認ください。 またBootstrapでは jQuery を読み込む必要があり、「bootstrap.min.js」よりも前に「 jquery .min.js」を指定しています。 ファイルの作成が完了しましたら、ブラウザで確認してみましょう。 開発者コンソールも開き( Windows であればF12、 Mac であればCommand +Option + I )、特にエラーが表示されていなければセットアップ完了です。 グリッドシステム では実際にコーディングをしながら、Bootstrapの使い方を説明してまいります。 まずはBootstrapを使う上で重要な グリッドシステム からです。 グリッドシステムは先述したレスポンシブWebデザインを実現するために必要な仕組みであり、横幅を 12分割 してHTML要素を配置していきます。 HTML要素にはグリッド(格子)の数を指定していくことで、横幅を指定することができます。 コーディングを行うにあたっては、以下の4つの基本ルールに従う必要があります。 ① divタグを配置し、class=”container” または ”container-fluid”を指定する ② 1の中にdivタグを配置し、class=”row”を指定する ③ 2の中に要素を配置し(複数) 、class=”col-{prefix}-{columns}”を指定する ④ 3で配置した複数要素の{columns}を合計12とする 上記のルールに従ってindex.htmlを修正してみましょう。 今回は1行を4分割して要素を表示してみます。 <!DOCTYPE html> < html lang = "ja" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title > Rakus </ title > < link href = "css/bootstrap.min.css" rel = "stylesheet" > </ head > < body > < header > ヘッダーです </ header > < div class = "container-fluid" > < div class = "row" > < div class = "col-md-2 border border-dark" > 2 </ div > < div class = "col-md-2 border border-dark" > 2 </ div > < div class = "col-md-2 border border-dark" > 2 </ div > < div class = "col-md-6 border border-dark" > 6 </ div > </ div > </ div > < footer > フッターです </ footer > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > </ html > 上記をブラウザで表示すると、指定したグリッドの個数分、行が分割されていることが確認できます。 ちなみにルール③における class=”col-{prefix}-{columns}” の prefix ですが、上記では「md」としています。 ここでコードを少し書き換え、「col-md-〇」の隣に「col- sm -〇」を追記してみます。 <!DOCTYPE html> < html lang = "ja" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title > Rakus </ title > < link href = "css/bootstrap.min.css" rel = "stylesheet" > </ head > < body > < header > ヘッダーです </ header > < div class = "container-fluid" > < div class = "row" > < div class = "col-md-2 col-sm-6 border border-dark" > 2 </ div > < div class = "col-md-2 col-sm-2 border border-dark" > 2 </ div > < div class = "col-md-2 col-sm-2 border border-dark" > 2 </ div > < div class = "col-md-6 col-sm-2 border border-dark" > 6 </ div > </ div > </ div > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > </ html > 次に画面を表示し、画面サイズを小さくしてみましょう。 分割された4要素の比率が変わるタイミングがあるはずです。 このようにBootstrapでは 画面サイズごとにprefixを指定でき 、レスポンシブWebデザインを実現しています。 この画面サイズの境界を ブレークポイント と呼び、最新のv5.0.0では ブレークポイント を区切りに以下6種類のprefixを利用できます。 デ バイス 画面サイズ prefix スマホ 576px以下 xs (eXtra Small) タブレット 576px以上 ~ 768px未満 sm (SMall) PC(小) 768px以上 ~ 992px未満 md (MidDle) PC(中) 992px以上 ~ 1200px未満 lg (LarGe) PC(大) 1200px以上 ~ 1400px未満 xl (eXtra Large) PC(特大) 1400px以上 xxl (eXtra eXtra Large) 以上がグリッドシステムの基本となります。 Bootstrapを利用していく上でこのグリッドシステムへの理解は重要となりますので、ぜひ以下の公式ページもご確認ください。 getbootstrap.jp よく使う コンポーネント 上記「Bootstrapを使うことによるメリット」欄にて、Bootstrapには高いデザイン性の コンポーネント が用意されている点に触れました。 Bootstrapでは各HTML要素のclassに決められたクラス名を指定することで、 CSS を実装せずに簡単にデザインを適用することができます。 以降ではこれらの コンポーネント でもよく利用するであろうものについて、サンプルを紹介していきます。 フォーム まずはフォームです。とても簡単です。 formタグ内に以下2つのclassを指定していくことで、簡単にデザイン済のフォームを作成できます。 .form-group:formタグ内に用意するdivタグで指定し、フォーム要素のグルーピングを行います。 .form-control:inputタグなどの各フォーム要素に指定します。 サンプル画面、コードはこちらです。(コードはBody要素のみを記述します) < body > < div class = "container-fluid" > < form > < div class = "form-group" > < label > Email </ label > < input type = "email" class = "form-control" placeholder = "Email" > </ div > < div class = "form-group" > < label > Password </ label > < input type = "password" class = "form-control" placeholder = "Password" > </ div > < button type = "submit" class = "btn btn-primary" > Button </ button > </ form > </ div > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > ボタン 次はボタンです。ボタンは用途に応じ、"btn btn-XXXX"という形式でクラス名を指定します。 公式ページで紹介されているクラスを載せたコードを示します。 getbootstrap.jp < body > < div class = "container-fluid" > < form > < div class = "form-group" > < label > Email </ label > < input type = "email" class = "form-control" placeholder = "Email" > </ div > < div class = "form-group" > < label > Password </ label > < input type = "password" class = "form-control" placeholder = "Password" > </ div > < button type = "button" class = "btn btn-primary" > Primary </ button > < button type = "button" class = "btn btn-secondary" > Secondary </ button > < button type = "button" class = "btn btn-success" > Success </ button > < button type = "button" class = "btn btn-danger" > Danger </ button > < button type = "button" class = "btn btn-warning" > Warning </ button > < button type = "button" class = "btn btn-info" > Info </ button > < button type = "button" class = "btn btn-light" > Light </ button > < button type = "button" class = "btn btn-dark" > Dark </ button > < button type = "button" class = "btn btn-link" > Link </ button > </ form > </ div > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > ボタンについては上記用途別のクラス指定の他、背景色の透過やサイズ変更を実施できます。 詳細は上記公式ページのリファレンスをご確認ください。 テーブル テーブルへの指定方法もとても簡単です。 対象となるtableタグのclassに対して"table"を指定の上、デザインに応じて追加のクラス名を指定するだけです。 よく使われるクラス名を示します。 .table-bordered:テーブルセルに枠線をつける .table-striped:テーブル内の1行ずつ交互に色を変える .table-hover:カーソルの乗っている行をハイライト表示する .table-responsive:レスポンシブテーブルとし、水平方向にスクロールさせる 以下では個人的によく使う".table-striped"を指定したテーブルをサンプルに示します。 < body > < table class = "table table-striped" > < thead > < tr > < th scope = "col" > # </ th > < th scope = "col" > イベント名 </ th > < th scope = "col" > 開催日 </ th > </ tr > </ thead > < tbody > < tr > < th scope = "row" > 1 </ th > < td > UI/UXデザイナーLT会 - vol.2 </ td > < td > 3/3 </ td > </ tr > < tr > < th scope = "row" > 2 </ th > < td > フロントエンドTechCafe </ td > < td > 3/10 </ td > </ tr > < tr > < th scope = "row" > 3 </ th > < td > エディタ好きは語りたいLT会 </ td > < td > 3/17 </ td > </ tr > < tr > < th scope = "row" > 4 </ th > < td > PdM Tips LT会 </ td > < td > 3/18 </ td > </ tr > < tr > < th scope = "row" > 5 </ th > < td > おすすめの技術書LT会 </ td > < td > 3/24 </ td > </ tr > </ tbody > </ table > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > 画像 最後は画像です。画像の加工ももちろん CSS を編集して対応できますが、Bootstrapで指定のクラス名を付与することでとても簡単に実現できます。 対象となるimgタグに対して指定するクラス名のうち、よく使われるものを示します。 .img-responsive:画面サイズに応じてレスポンシブに画像サイズを変更する .img-thumbnail:画像の枠線に丸みを持たせ、サムネイル状に表示する .img-circle:画像をサークル形に加工して表示する .rounded float-left(right):画像の表示位置を左(右)に指定する。 サンプルは"img-thumbnail"です。サムネイルの枠線が判別しやすいよう、背景色も変更しております。 <!DOCTYPE html> < html lang = "ja" > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < title > Rakus </ title > < link href = "css/bootstrap.min.css" rel = "stylesheet" > </ head > < body > < div class = "text-center" style = "background-color: black;" > < img src = "image/img-sample.png" class = "img-thumbnail rounded" > </ div > < script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></ script > < script src = "js/bootstrap.min.js" ></ script > </ body > </ html > おわりに 今回は超入門的なBootstrapの使い方を紹介しましたが、ご理解いただけましたでしょうか? Bootstrapは歴史の長い CSS フレームワーク ながら、今なお進化しております。 基本を理解すれば今後のバージョンアップにも追随していけるかと思いますので、ぜひこのブログをスタートラインとし、Bootstrapの便利機能の数々に触れていっていただけますと幸いです! ではでは!   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター