TECH PLAY

株式会社ラクス

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

935

こんにちは、技術広報の syoeshin です。 当社 ラク スの開発では様々ツールを使ってますが テキストエディタ を使用するケースも多く 若手もベテランも自分に合う テキストエディタ ”マイ・エディタ” を愛用してます。 テキストエディタ って種類が多くて ・結局どれを選ぶか? ・となりのあの人は何を使っているか? 気になりますよね。 そこで、今回は当社の若手からベテランにまで 普段愛用している テキストエディタ ーと おすすめポイントを聞きました。 質問:「愛用のエディタは何ですか?」 当社調査結果のグラフは以下 ●愛用エディタの調査結果 やはりと言いますか 当社 ラク スで1位のおすすめエディタは ●VisualStudioCode ヤングからベテランまで幅広い層で支持 以下、愛用者達からのおすすめコメント 今や最主流なので便利 プラグイン や記事なども VSCode 前提のものが多い。 Atom やBracketと比べて軽かった(今はわからない) GIT MarkDown Python PHP Docker AWS なんでもあり 軽い。多機能! 発表資料を Markdown で書いてプレビュー、からのPDF出力まで VSCode でできちゃう(marp) 新しいものに惹かれて Atom から乗り換えました 軽い、Remote Containerが便利。最近校正くん対応したので文章書くときにも使える 見易さ。編集し易さ。 デフォルトのHTML スニペット が素晴らしい。さくさくHTMLコーディングしつつ、Live Serverで保存→即時サーバ反映で良い感じ WSL と繋げて使うのもできる。npm スクリプト の実行もクリック操作で可能なので、Node.js使う系の作業に特に重宝している マークダウンでの原稿作成チェック。目に優しいので好きです。 ファイルサーバ上のテキストファイルを同時編集可能 → 他者による上書き防止 会議中の議事作成や多拠点間での同時作業時など、リアルタイムでテキストの共有を行う時に便利 明示的に保存していなくても再起動時に編集中の内容が再表示される 単純な テキストエディタ にも、開発にも使える。 プラグイン がとにかく豊富。その気になれば自分でも プラグイン を作れる。 息子も使っていて幅広い用途や年齢層で使われているところが良い。 etc... 世間的にも全世代で幅広く支持され 当社ではついに親子で使っている例も登場! 次いで、当社で2位のおすすめエディタは ● サクラエディタ ※意外にも こちらもヤングからベテランまでの幅広い層で支持 (筆者も markdown チェックで利用) 以下、愛用者達からのおすすめコメント ちょい使いには楽。巨大なテキストファイルでも割と軽い。テキスト エンコーディング の操作で慣れている。 テキスト整形とかする時、ショートカットキーがなじんでいるのがこっちなのでこっち使っちゃう 目に優しい 新人の頃、先輩に サクラエディタ の超絶技巧を見せていただき感動したため テキスト操作がやりやすい 自分なりの最適化が サクラエディタ で出来上がってしまった。いくつかのショートカットキーを多用しています。(ソート:Alt+A、マージAlt+M) 使用ソフトに厳しい客先でもなぜか使うことが許されている Sier 御用達エディタ 割と起動が軽いので大きなログファイルなどはサクラで開きます。 grep からのジャンプやマクロが便利。 軽いしプロセスが落ちたりとかもしないのでいつも重宝してます 起動が早い。メモ用、 文字コード 変換用 メモや SQL をサッと書く時には便利 置換はこれに限る。 文字コード 変換も便利。はるか昔に jar ファイルを base64 エンコーディング してコピペ => base64 デコードして保存 で手を入れていたのが懐かしい。 メモ書きから、ちょっとした編集まで大抵これを使っています 置換、マージ&ソート、矩形選択辺りを多用しています 正規表現 での置換や 文字コード 、改行コードの変換に利用しています Java や SQL の シンタックス ハイライトが使えるのも嬉しいです etc... Grep 機能、アウトライン解析はとても便利! 当社で同率3位のおすすめエディタは”Typora”と” Vim ” ●Typora 無料で、Win/ Mac / Linux に導入可能 シンプルなHTMLにエクスポートできる 強力な Markdown エディタ 以下、愛用者達からのおすすめコメント Markdown エディタ、書いた瞬間変換されるので書いていて気持ちいい リアルタイムにマークダウンを反映してくれて、手軽に綺麗に書けるため マークダウンがリアルタイムで反映され文章作成がしやすいため Markdown のエディタ。スタイルされた状態で編集できるのがいい "マークダウン見るときはこれ。とにかく見やすいと感じています。" etc... リアルタイムプレビューのUI シンプルデザイン、直感的操作を好む人におススメ! ● Vim 二大エディタの一つ 誰かが言われてました テキストエディタ には三種類しか存在しない。 " Vim " か " Emacs " か "それ以外か" だ。 ※ 引用元 以下は当社の愛用者達からのおすすめコメント 覚えてしまうとあちこちに指を伸ばさなくて良くて楽だなと思います。使いこなせるようになりたい。 ターミナル操作してる流れでは Vim を使用。一時は プラグイン 入れたりカスタマイズに凝っていたが、今はデフォルトで使用。 Viでも可。設定を変えたけど、どこに設定あるか忘れるので、検証機移行時にあせる vi よりも vim がいい派。サーバー上でちょっとした編集をしたいときにあると嬉しい Web系エンジニアでviを使わない人はいないはず。その延長で Vim を日常的に使うのは必然。 etc... Vim は、古くから多くのエンジニアに愛されてきたエディタです。 故に、"愛"も"圧"も強め! 次いで、当社で5位のおすすめエディタは ● emacs 以下、愛用者達からのおすすめコメント サーバ上で CLI でちょこっと編集するのに○。 Lisp で拡張できるので細かいところも自分好みにできる 手元メモ用とターミナル上での作業用。他のエディタを emacs 風 キーバインド にするのは嫌い。 現在、もはやメモ帳としてしか使っていないがおすすめ etc... 拡張性が高く、自由にカスタマイズができる! これにつきるのでは? 次いで、当社で6位のおすすめエディタは ●cotEditor 以下、愛用者達からのおすすめコメント ちょい使いに楽。テキスト エンコーディング の変換がかんたん。 手軽に使える。メモによく使ってる etc... 以下エディタ群は利用者が同率でした。 ● Atom 以下、愛用者達からのおすすめコメント 拡張性と操作性で選んでます 軽快に動作してくれたらもっと嬉しい etc... ● Eclipse ( IDE ) 以下、愛用者達からのおすすめコメント 学生の頃からプライベートでは一番使っています 重いという人がいますが、重くなるようなPC使ってるのがいけないのですw etc... ●JetBrains ( IDE ) 以下、愛用者達からのおすすめコメント ス クラッチ ファイルを軽い気持ちで使っている プロジェクトに属さずにコーディングができ、 IDE の支援も受けられる etc... ● Sublime Text 以下、愛用者達からのおすすめコメント ちょっとした スクリプト を見るときに使います 特に理由があるというより昔から使っていた無償版を今も使っています etc... ●nano 以下、愛用者達からのおすすめコメント 操作が直感的なのでviが使いこなせない方にはおすすめです etc... ● TeraPad 以下、愛用者達からのおすすめコメント 個人的に サクラエディタ よりもアイコンが好きです etc... ●Textastic 以下、愛用者達からのおすすめコメント WorkingCopy(gitクライアント)と併せて iOS からブログ更新用に etc... 最後に 「愛用のエディタは何ですか?」と 当社メンバーに ヒアリ ングしていた際 ・ sublime 派は今? ・ emacs 派は? vim 派は?なし? など 世にいう"エディタ戦争"の少し手前まで 盛り上がり、各メンバーが回答してくれました。 戦争手前で論争を終える事ができたのは きっと『愛』という言葉のおかげだと 勝手に解釈しております。 2020年、皆さんの愛用のエディタは何ですか? エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは、mrym_618です。 今回は、普段業務で使用しているPhpStormの プラグイン のうち、個人的におすすめの3つを紹介したいと思います。 はじめに Rainbow Brackets deep-assoc-completion String Manipulation おわりに Rainbow Brackets Rainbow Brackets とは、対応する括弧の色を変えて見やすくする プラグイン です。 複数のif文などによりネストが重なっていくと、どの括弧とどの括弧が対応するか分かりにくくなり、コードが読みにくくなってしまいます。 そこで、この プラグイン を導入することで対応する括弧が分かりやすくなりますので、コードが読みやすくなります。 導入方法は、 Setting > Plugins で 「Rainbow Brackets 」を検索し、インストールしてPhpStormを再起動するだけです。 また、 Editor > Color Scheme > Rainbow Bracket より括弧の色をカスタマイズできますので、自分の見やすいようにカスタマイズして使用してもらえればと思います。 deep-assoc-completion deep-assoc-complatetionとは、配列の補完をしてくれる プラグイン です。 連想配列 の予測補完やDocCommentに配列の構造を定義するとそれも解釈してくれるなど、配列の操作が楽になる プラグイン です。 導入方法は、上記と同様で Setting > Plugins で 「deep-assoc-completion」を検索し、インストールしてPhpStormを再起動するだけです。 String Manipulation String Manipulationとは、文字列操作をできる プラグイン です。 文字列をキャメルケースやスネークケースに変換したり、 エス ケープや エンコード などができます。 使用方法は、 String Manipulation を導入後に、操作したい文字列を選択し、 Alt + m を押すことで表示されるドロップダウンから操作したい処理を選択するだけです。 導入方法は、上記と同様で Setting > Plugins で 「String Manipulation」を検索し、インストールしてPhpStormを再起動するだけです。 おわりに 今回はPhpStormの個人的におすすめの プラグイン を3つ紹介しました。PhpStormには、今回紹介した プラグイン 以外にも多くの プラグイン がありますので、いろいろ試して業務効率を上げていきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは。新卒3年目のchoreii です。 今回は PostgreSQL の実行計画について記事を書こうと思います。 私が初めて実行計画について知った時は難しそうなイメージが先行しており、実際に調べてみても情報量が多くハードルが高かったです。ですが調べていくうちに自分が難しく感じていた理由がわかりました。 それは、 多くの記事が「実行計画の基礎知識」と「実行計画をどのようにパフォーマンス改善に活かすか」という2種類の情報を織り交ぜて記載されていたから です。 今回はできるだけ情報量を削減し、 「実行計画の基礎知識」 にフォーカスした記事を作成しました。これから実行計画を学ぶ人の最初の一歩となれば幸いです。 実際のパフォーマンスのチューニング方法や、検証するための大量データの登録に興味がある方は下記のブログもご覧ください。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp 目次 はじめに 目次 1. 実行計画とは 2. 実行計画の出し方 3. 実行計画の読み方 3-1. 実行計画を読む順番 3-2. スキャン演算子 3-3. 結合演算子 3-4. その他の演算子(検索結果の整形など) 4. おまけ(コストとANALYZE) おわりに 参考文献 1. 実行計画とは 実行計画とはユーザが問い合わせたクエリ( SQL 文)を実行する手順書になります。「どの順番にテーブルを結合するか」「ソート方法」「検索方法』などの作業内容や、想定される実行コストが記述されています。 2. 実行計画の出し方 実行計画の出し方ですが、実行計画を確認したい SQL 文の先頭に EXPLAIN と付け足すだけです。 例として、itemテーブルから全件取得する SQL は SELECT * FROM item; となりますが、この SQL の実行計画を知りたい場合は EXPLAIN SELECT * FROM item; とするだけで実行計画が取得できます。 ※ オプションで出力内容や方法を設定できますがここでは割愛します。 EXPLAIN SELECT * FROM item; QUERY PLAN --------------------------------------------------------- Seq Scan on item (cost=0.00..12.20 rows=220 width=328) 3. 実行計画の読み方 前項の通り実行計画を表示することはできました。次はもう少し複雑な SQL の実行計画を使って実行計画の読む順番や、それぞれの行が何を意味しているかを解説していきます。以下が解説に使用する SQL 文とその実行計画です。 EXPLAIN SELECT * FROM item INNER JOIN customer ON item.customer_id = customer.id WHERE customer.name = '佐藤' ORDER BY item.id; QUERY PLAN --------------------------------------------------------- Sort (cost=27.07..27.08 rows=1 width=574) Sort Key: item.id -> Hash Join (cost=14.03..27.06 rows=1 width=574) Hash Cond: (item.customer_id = customer.id) -> Seq Scan on item (cost=0.00..12.20 rows=220 width=332) -> Hash (cost=14.00..14.00 rows=2 width=222) -> Seq Scan on customer (cost=0.00..14.00 rows=2 width=222) Filter: ((name)::text = '佐藤'::text) 3-1. 実行計画を読む順番 実行計画はよく見るとツリー構造になっており、インデント下げや「->」などで表されます。(出力方法によって異なります。)以下に先の実行計画のツリー構造を簡単に図にしたものがあります。 図1: 実行計画のツリー構造 読む順番のルールは2つだけです。 順番に子要素をたどり一番子孫の要素から実行し、親要素に遡っていく 兄弟要素がある場合は先に記述されている行から順に子要素をたどる 今回の場合、一番深い子要素は7,8行目になりますが、5行目と6行目が兄弟要素にあたります。そのため最初に5行目を実行してから6行目の子要素をたどっていくことになります。図に読む順番を追記すると以下のようになります。 図2:実行計画のツリー構造(読む順番) 読む順番に迷った際はツリー構造がどうなっているかを一度図にしてみるとわかりやすいと思います。 3-2. スキャン 演算子 次に個別の行の解説をします。最初に実行される以下の行の先頭に Seq Scan と書かれています。 -> Seq Scan on item (cost=0.00..12.20 rows=220 width=332) これは、単語の意味通りitemテーブルの中から必要な行を順番に検索することを意味する行で、もっとも基本的な検索(スキャン)方法になります。スキャン 演算子 は Seq Scan 以外にもインデックスが利用できる場合に選択される Index Scan などがあります。 3-3. 結合 演算子 3,4行目ではテーブルの結合を行っています。ハッシュとついているのは一方のテーブルから作られたハッシュ表を元に結合しているからで、最初のハッシュ表の作成は6行目でおこなわれています。メモリ上にハッシュ表が作成されるため、メモリに余裕がある場合は高速に動きます。結合 演算子 は他に Nested Loop や Merge Join が存在します。 -> Hash Join (cost=14.03..27.06 rows=1 width=574) Hash Cond: (item.customer_id = customer.id) 3-4. その他の 演算子 (検索結果の整形など) 1,2行目ではソートを行っています。スキャンや結合よりも直感的に何をしているかが分かりやすいと思います。(ここでは SQL のORDER BY句で指定したようにitemテーブルの‪‪id列でソートがかかっています。) Sort (cost=27.07..27.08 rows=1 width=574) Sort Key: item.id 他にも Group や Limit など、特定の SQL を記述した際に検索結果を整形するための 演算子 が存在します。 4. おまけ(コストとANALYZE) 演算子 の意味について解説しましたが、 演算子 の後ろにカッコ書きで数値などが記載されています。 -> Seq Scan on item (cost=0.00..12.20 rows=220 width=332) これは、実行計画通りに SQL を実行した場合の推測値で、左から順に以下の数値になっています。 初期コスト:検索結果の1行目を返すまでにかかる準備のコスト(秒数ではない) 総コスト:初期コストを含めた処理完了までにかかるコスト(秒数ではない) 行数:返却される検索結果の行数 行の長さ:返却される1行あたりの長さ(横幅) パフォーマンスを確認する際は総コストを確認して、 SQL の組み方を変更することによってコストを抑えることができないかを調節することが多いです。 しかし、出てくる結果はあくまで推測値なので実際に SQL を実行してみた結果と食い違うことがあります。その場合は ANALYZE オプションを使用し実際に SQL を実行してみた結果、実行計画のどの部分にどれだけの時間やコストがかかったかを確認する必要があります。(以下のような出力になります) ※ 「EXPLAIN」の直後に「ANALYZE」と付け足す EXPLAIN ANALYZE SELECT * FROM item INNER JOIN customer ON item.customer_id = customer.id WHERE customer.name = '佐藤' ORDER BY item.id; QUERY PLAN --------------------------------------------------------- Sort (cost=27.07..27.08 rows=1 width=574) (actual time=0.037..0.037 rows=4 loops=1) Sort Key: item.id Sort Method: quicksort Memory: 25kB -> Hash Join (cost=14.03..27.06 rows=1 width=574) (actual time=0.025..0.027 rows=4 loops=1) Hash Cond: (item.customer_id = customer.id) -> Seq Scan on item (cost=0.00..12.20 rows=220 width=332) (actual time=0.006..0.006 rows=8 loops=1) -> Hash (cost=14.00..14.00 rows=2 width=222) (actual time=0.008..0.008 rows=1 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on customer (cost=0.00..14.00 rows=2 width=222) (actual time=0.005..0.005 rows=1 loops=1) Filter: ((name)::text = '佐藤'::text) Rows Removed by Filter: 1 Planning time: 0.159 ms Execution time: 0.062 ms (actual time=0.008..0.008 rows=1 loops=1) が行末に追加されたり、QUERY PLANの最後に実際の実行時間などが出力されるようになっています。この記事では詳細は割愛しますが、このように実際に実行してみた結果を取得することも可能です。 おわりに 今回は実行計画の最低限の知識に絞って解説してみました。できるだけ初心者の人が最初に疑問に思うことをピックアップしたつもりなので、この記事を読んでからさらに詳しい解説記事を見ていただければ学習がはかどると思います。私自身まだ浅い基礎知識しか定着しておらず、業務で実行計画を使いこなせているとは言い難いです。今回、基本的な情報を整理する中での気づきもありましたので、さらに学習を深め身につけていきたいと思います。 参考文献 EXPLAIN PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~ PostgreSQLの実行計画について調べてみた | キャスレーコンサルティング株式会社 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは。新卒3年目になりましたtaku_76です。 今回は SQL についての記事を書こうと思います。その経緯としては、業務で SQL を少し書くことはあったのですが、 必要な情報を取り出せたらいいや、くらいの意識しかなく、あまりパフォーマンス面を意識するということはありませんでした。 しかし、今後の新規開発で SQL の改修があった際、パフォーマンスの考慮は必ず必要になってきますので学習することにしました。 学習にあたっては以下の書籍を用いて学習しました。1部と2部に分かれているのですが、今回の記事では1部について、パフォーマンス面に注視して印象に残ったことを具体例とともに取り上げています。あくまで考え方を取り上げたかったため、文法の説明などは割愛しています。 www.shoeisha.co.jp はじめに パフォーマンスの向上のために覚えるべきこと CASE式 CASE式の中で集約関数を使う EXISTS述語 述語とは 全称量化と存在量化 テーブルに存在「しない」データを探す ウィンドウ関数 ウィンドウ関数 vs 相関サブクエリ おわりに パフォーマンスの向上のために覚えるべきこと CASE式 CASE式を使うことで複数の SQL 文を1つにまとめ、可読性もパフォーマンスも向上することができます。それを以下に示します。 CASE式の中で集約関数を使う 以下のような社員と所属サークルを一覧化するテーブルを考えます。主キーは、社員番号とサークルIDとします。 shain_cricleテーブル shain_id circle_id circle_name main_circle_flag 1000 1 野球 YES 1000 2 サッカー NO 2000 2 サッカー NO 2000 3 バスケットボール YES 2000 4 バレーボール NO 3000 4 バレーボール NO 4000 5 吹奏楽 NO 5000 6 水泳 NO 社員は複数のクラブに所属している場合と、1つにしか所属していない場合があります。 複数のクラブを掛け持ちしている社員は、メインのサークルを示すフラグ列にYESまたはNOの値が入ります。そうでない社員はNOが入ります。 このテーブルから次のような条件でクエリを発行するとします。 1つだけのクラブに所属している社員については、そのサークルIDを取得する 複数のクラブを掛け持ちしている社員については、メインのサークルIDを取得する 1.2.についてそれぞれ以下のようなクエリを発行すれば抽出が可能です。 -- 1つのサークルに所属している社員を抽出 SELECT shain_id, MAX(circle_id) AS main_circle FROM shain_circle GROUP BY shain_id HAVING COUNT(*) = 1 ORDER BY shain_id; -- 結果 shain_id | main_circle ----------+------------- 3000 | 4 4000 | 5 5000 | 6 (3 行) -- サークルを掛け持ちしている社員を選択 SELECT shain_id, circle_id AS main_circle FROM shain_circle WHERE main_circle_flag = 'YES' ORDER BY shain_id; -- 結果 shain_id | main_circle ----------+------------- 1000 | 1 2000 | 3 (2 行) 上記でも条件を満たした抽出ができるのですが、場合によって複数の SQL が必要になりパフォーマンスの問題が発生します。 これをまとめたものを、CASE式を使えば1つの SQL で書くことができます。(UNIONでは結局クエリの発行回数は変わらないためパフォーマンスは同じ) SELECT shain_id, CASE WHEN COUNT(*) = 1 THEN MAX(circle_id) ELSE MAX(CASE WHEN main_circle_flag = 'YES' THEN circle_id ELSE NULL END) END AS main_circle FROM shain_circle GROUP BY shain_id ORDER BY shain_id; -- 結果 shain_id | main_circle ----------+------------- 1000 | 1 2000 | 3 3000 | 4 4000 | 5 5000 | 6 (5 行) ポイントとしては、「1つだけのサークルに所属しているのか、複数のサークルに所属しているのか」という条件分岐をCASE式で表現することです。 元々、集計結果に対する条件はHAVING句を使うと学んでいましたが、CASE式を使うことでSELECT句でも同じような条件分岐を実現することができました。 CASE式はSELECT句で集約関数の中にも外にも書けたりと自由度が高いのでうまく扱えるようになりたいと思います。 EXISTS述語 EXISTSは複数行を一単位と見なした条件を記述することができ、相関サブクエリを利用するにもかかわらずパフォーマンスが優れているという特徴があります。 結論から言うと、EXISTSは「量化」という述語論理の機能を実現するために SQL に取り込まれました。 述語とは 一言でいうと関数のことですが、EXISTSはSUMなどの普通の関数とは異なり、戻り値が真理値になる関数の事を指します。 例として、=,<,>,などの比較述語や、BETWEEN,LIKE,IN,IS NULLなどがあります。 ここで、=やBETWEENなどと、EXISTSを比較すると「引数に何を取るか」という面で大きな違いがあります。 =やBETWEEN 「x = y」や「x BETWEEN y AND z」などの述語の引数は、数字や名前といった単一の値、スカラ値。 EXISTS 行の集合(例. SELECT * FROM ○○テーブル WHERE ○○=○○) 上記から分かるように、EXISTSは入力のレベルに特徴があります。述語論理では「入力のレベル」に応じて述語が分類されています。 そして、=やBETWEENなど1行を入力とする述語を「一階の述語」、EXISTSのように行の集合を入力する述語を「二階の述語」といいます。 全称量化と 存在量化 述語論理には、量化子という特別な述語が存在します。量化子とは以下の2つの文を書くための道具です。 全称量化子 すべてのxが条件Pを満たす 存在量化 子 条件Pを満たすxが(少なくとも1つ)存在する EXISTS述語は、述語論理の 存在量化 子を実装したものです。ここで重要なことがあるのですが、 SQL にはもう一方の全称量化子に対応する述語は導入されませんでした。 しかし、全称量化子と 存在量化 子は片方が定義されていれば同値変形の規則がありますので、「すべての行が条件Pを満たす」という文を「条件Pを満たさない行が存在しない」と変換することで表現できます。これについてEXIST述語を使って書いていきます。 テーブルに存在「しない」データを探す データベースからデータを検索する場合、一般的にはある条件を満たすものを抽出します。しかし、時にはテーブルに存在「しない」データを抽出する場合もあります。 例えば、複数回行われるミーティングと出席者を記録しておくテーブルがあるとします。 meetingsテーブル meeting shain 1回目 A 1回目 B 1回目 C 2回目 A 2回目 D 2回目 C 3回目 B 3回目 D 今回はこのテーブルから「出席しなかった社員」を求めます。 存在するデータに対して「○○という性質を満たす」という条件を設定するのではなく、そもそも「データが存在するかどうか」という、次数の1つ高い問題設定を行います。 これが「二階の問い合わせ」であり、EXISTS述語を使う機会です。 考え方としては、全員が出席したと仮定した場合の集合から、現実に出席した人を引き算することで求めます。 1.全員が出席した場合の集合を求める SELECT DISTINCT m1.meeting,m2.shain FROM meetings m1 CROSS JOIN meetings m2 ORDER BY meeting, shain; -- 結果 meeting | shain ---------+------- 1回目 | A 1回目 | B 1回目 | C 1回目 | D 2回目 | A 2回目 | B 2回目 | C 2回目 | D 3回目 | A 3回目 | B 3回目 | C 3回目 | D (12 行) 2.meetingsテーブルに存在しない組み合わせに絞り込む SELECT DISTINCT m1.meeting,m2.shain FROM meetings m1 CROSS JOIN meetings m2 WHERE NOT EXISTS (SELECT * FROM meetings m3 WHERE m1.meeting = m3.meeting AND m2.shain = m3.shain) ORDER BY meeting, shain; -- 結果 meeting | shain ---------+------- 1回目 | D 2回目 | B 3回目 | A 3回目 | C (4 行) これでうまく抽出することができました。このようにEXISTS述語を使うことで存在「しない」データを抽出することができます。 SQL を書くときに述語論理を意識的に考えることはなかったので、今後そういう視点からも考えてみたいと思います。 ウィンドウ関数 今回、ウィンドウ関数について基本的なことは割愛します。応用方法としては、特に、これまで行間比較において相関サブクエリを使わなければならなかったケースにおいて、 ウィンドウ関数を使うことでスッキリとした SQL 文を記述することができます。 ウィンドウ関数 vs 相関サブクエリ 相関サブクエリとウィンドウ関数を比較すると以下のような違いがあります。 ウィンドウ関数は、サブクエリを使っているが、「相関」サブクエリではないためサブクエリ単体で実行することができる。 そのため、可読性が高く動作も理解しやすい テーブルに対するスキャンが1度だけで済むので、パフォーマンスが良い。 検証は割愛しますが、相関サブクエリもウィンドウ関数も、集合のカットとレコード単位のループという同じ機能を実現していると言えるので置き換えることができます。 次のような商品の名前や価格を格納するテーブルを見てみます。 shohinテーブル shohin_id shohin_name shohin_bunrui tanka 1 マウス PC 3500 2 扇風機 家電 7000 3 キーボード PC 1500 4 文房具 シャーペン 600 5 ドライヤー 家電 3000 6 電球 家電 600 7 電動歯ブラシ 家電 800 8 ボールペン 文房具 150 このshohinテーブルから、各商品分類について平均単価より高い商品を抽出してみます。(相関サブクエリで解く典型的な問題) まずは、相関サブクエリです。 SELECT shohin_bunrui, shohin_name, tanka FROM shohin s1 WHERE tanka > (SELECT AVG(tanka) FROM shohin s2 WHERE s1.shohin_bunrui = s2.shohin_bunrui GROUP BY shohin_bunrui) ORDER BY shohin_bunrui; -- 結果 shohin_bunrui | shohin_name | tanka ---------------+-------------+------- PC | マウス | 3500 家電 | 扇風機 | 7000 家電 | ドライヤー | 3000 文房具 | シャーペン | 600 (4 行) ポイントとしては、「s1.shohin_bunrui = s2.shohin_bunrui」というs1集合とs2集合に対するバインド条件です。これにより、2つのテーブルの商品分類を同じレコード集合に限定して、その集合の平均単価と各レコードの単価を1行ずつ比較しています。 上記コードと同じ結果を抽出するウィンドウ関数は次のようになります。 SELECT shohin_name, shohin_bunrui, tanka FROM (SELECT shohin_name, shohin_bunrui, tanka, AVG(tanka) OVER(PARTITION BY shohin_bunrui) AS avg_tanka FROM shohin) tmp WHERE tanka > avg_tanka; -- 結果 shohin_name | shohin_bunrui | tanka -------------+---------------+------- マウス | PC | 3500 ドライヤー | 家電 | 3000 扇風機 | 家電 | 7000 シャーペン | 文房具 | 600 (4 行) こちらの挙動としては、まずサブクエリのウィンドウ関数で商品分類ごとの平均単価( avg _tanka)を計算しています。 SELECT shohin_name, shohin_bunrui, tanka, AVG(tanka) OVER(PARTITION BY shohin_bunrui) AS avg_tanka FROM shohin; -- 結果 shohin_name | shohin_bunrui | tanka | avg_tanka --------------+---------------+-------+----------------------- キーボード | PC | 1500 | 2500 マウス | PC | 3500 | 2500 ドライヤー | 家電 | 3000 | 2850 扇風機 | 家電 | 7000 | 2850 電球 | 家電 | 600 | 2850 電動歯ブラシ | 家電 | 800 | 2850 シャーペン | 文房具 | 600 | 375 ボールペン | 文房具 | 150 | 375 (8 行) あとは各行で「tanka > avg _tanka」という条件で簡単に平均単価と単価の比較が行えます。 このウィンドウ関数の結果のよいところは、商品分類ごとの平均単価を計算しますが、この際、レコードを集約せずに元のテーブルに列として結果を追加するだけ、という情報 保全 性が働くところです。 個人的に相関サブクエリは動作の理解が難しくあまり好んではいなかったのですが、ウィンドウ関数で同じことを表現することができ、 パフォーマンスも可読性もよいことが分かったので学習を進めてみたいと思いました。 おわりに いかがだったでしょうか。もし私と同じように、 SQL のパフォーマンスを向上するにはどうすればよいか、何を使えば分からないという方の学習のきっかけになれば幸いです。 今回紹介しているのはほんの一部ですので、他にも知りたい、深掘りをしたいと思った方にはぜひおすすめの書籍です。 SQL を書くときの考え方が変わるかと思います。 私も今回学習してみて新しい気付きがたくさんありましたので、何度か読み直してみて定着させたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
初めに こんにちは。 mako _makokです。 フロントを Vue + Vuex + TypeScript で新規開発中の SaaS プロダクトに携わることになり、急ピッチでVueを学習しています。 今回はVuexについて学習したので、その結果をまとめました。 Vuexは一言で表すと、単一方向のデータフローを持った状態管理パターンのライブラリです。 記事内でサンプルが登場しますが、Vueのバージョンは2系で書いています。 初めに Vuexをなぜ使うのか? Fluxについて Vuexのアーキテクチャ Store State Getter Mutation Mutationを書くときのコツ Action まとめ おわりに Vuexをなぜ使うのか? Vueアプリケーションを開発しているとアプリケーションの状態を参照し、 コンポーネント の動作を変えたくなることがあります。 例えば、カレンダーアプリなどでは"現在表示する月"を状態として持ち、"現在表示する月"を参照して表示する日付・日数・予定を変えたくなると思います。 このような動作をする処理を愚直に実装すると、状態自体が複数の コンポーネント に分散してしまったり、状態を変更するロジックが分散、重複してしまうケースが考えられます。 では状態を抽出し、グローバルなオブジェクトで持てば解決するのでは?と考えるかもしれません。 ですが、これは コンポーネント 分割している意味がありません。 コンポーネント ツリーのどこからでもアクションを実行することや、状態を変化させることができてしまいます。それはもはや巨大な コンポーネント が出来上がるのと同義です。 そこで、状態管理に関わる部分を 定義・分離・ルール化 してコードの構造と保守性の向上を目的としたライブラリがVuexです。 Fluxについて Vuexの話を続けていきたいところですが、Vuexの 公式 には以下のようにあります。 Flux、 Redux そして The Elm Architectureから影響を受けています。 最初に書いた、 単一方向のデータフローを持った状態管理パターン というのはFluxに特に影響を受けています。 まず最初にFluxを知ることによって、Vuexをより理解しやすくなるのではと思います。 Fluxとは、 Facebook が提唱している アーキテクチャパターン です。 以下は Facebook が実際にFluxの実装を行ったサンプル リポジトリ です。 https://github.com/facebook/flux Fluxでは MVC やMVVMと異なり、単一方向のデータフローを有していることが特徴です。 具体的には以下の図のようになります。 Fluxの アーキテクチャ Store アプリケーションのデータ(状態)を保持する Dispatcherから更新される publicなsetter を持ってはならない publicなsetterがあると、無秩序にStoreを書き換えることができてしまう Dispatcher Actionを受け取って Storeを更新 する すべてのアクションを受け取る Action Storeをどのようなロジックで更新するか記載した命令 *1 View VueやReactで言うところの コンポーネント 正直これはだけではパっとしないと思うのでToDoアプリでToDoを追加する動作を例にとってみます。 アプリケーションはToDoを保持しているStoreを持っている ToDoを入力し、追加ボタンを押すとToDoを追加する ActionがDispatcherに命令 命令を受け取った DispatcherがActionを実行 し、StoreにToDoを追加する StoreにToDoが追加されたので、更新を検知したViewは再 レンダリング を行い、追加されたToDoを表示する ActionはToDoを直接更新せず、Dispatcherに命令を渡しているところがミソとなります。 以上がFluxの概要になります。ここでポイントとなるのは以下の2点です。 Fluxは 単一方向のデータフロー をもった アーキテクチャ である StoreはActionを受け取ったDispatcherからでしか更新できない Vuexの アーキテクチャ いよいよVuexの アーキテクチャ について説明します。以下図はVuexの アーキテクチャ です。 Vuexの アーキテクチャ FluxからState, Getter, Mutationが増えています。また単一方向のデータフローを持っていることがわかると思います。 VuexではFluxで登場したStoreやDispatcherとコンテキストが微妙に変わっている箇所があります。 Store → Vuexの インスタンス State → FluxでいうところのStore Getter → Stateから値を取得する Mutation → Stateを更新する 。FluxのDispatcherの更新部分だけを切り離したようなイメージ Dispatch → Actionを実行する役割に特化 Action → State をどのようなロジックで更新するか記載した命令 以上が簡単な アーキテクチャ の説明です。なんとなくFluxから言葉が変わったり、Dispatcherの役割が分かれたんだなーくらいの感覚を持っていただければ大丈夫です。 今回はToDoアプリケーションを作りながらそれぞれ説明していきます。 Store StoreはVuexの インスタンス です。主にstate, getters, mutations, actionsから構成されます。 詳しく知りたい方は Vuex.StoreのAPIリファレンス を御覧ください。 const store = new Vuex.Store( { state: {} , getters: {} , mutations: {} , actions: {} } 重要なのはStoreはアプリケーション内で 常に1つであるように設計 するということです。 理由は後述します。 State アプリケーションの状態を保持します。Stateは 信頼できる唯一の情報源 でなくてはなりません。 Storeの項で、Storeはアプリケーション内で常に1つであるように設計すると述べました。 Storeが一つということはStateも一つしかないことが担保されますので、Stateは "信頼できる唯一の情報源" が実現します。 Stateは以下のようにオブジェクトを記述していきます。 state: { todos: [] } , Getter GetterはStateの一部や、Stateで計算された値を返します。 Getterの特徴として、Getter内での 計算結果はキャッシュされます。 キャッシュされたGetterの結果は、Stateが更新されるとクリアされます。 今回はStateから完了済みのToDoを返すGetterを作成しました。 getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } Mutation MutationはStateを更新する唯一の手段です。 Mutationにはいくつかのルールがあります。 Mutation以外がStateを更新すること は禁止 Mutationは直接参照しない。 Store.commit() から呼び出す Mutationには非同期処理を書いてはならない devtoolでmutationの更新履歴を追いかけづらくなる 意図しないタイミングで更新処理が入る VueのdevtoolではStateの更新履歴を追うことができるのですが、Mutationで非同期処理を書いてしまうと 意図しないタイミングで更新され、どのようにStateが書き換わったかわかりづらくなってしまうので規約レベルで禁止されています。 以上のことを踏まえ、Mutationを書いていきます。 MutationにはStateを第一引数に渡します。また、Mutationには追加の引数を渡すことができます。 追加の引数のことを ペイロード と呼びます。 storeのオブジェクトを直接弄るように書きます。 mutations: { HOGE (state) { state.hoge = "hoge" } , FUGA (state, payload) { state.fuga = payload.content } } 2のルールに則り、Mutationはstore.FUGAなどと呼び出すことは禁止されています。 Mutationを呼び出すために、以下のように store.commit を使用します。 store.commit( 'FUGA' , { content: 'fuga' } ) ToDoリストにToDoをpushする処理を書いていきます。 mutations: { PUSH_TODO(state, { content, done } ) { state.todos.push( { content: content, done: done } ) } } Mutationを書くときのコツ 余談ですが、MutationではStateを更新する処理を書くべきで、具体的な更新内容を書くべきではありません。 具体的な動作は後述するActionに記述します。 カウンターアプリであれば、例えばStateのcounterを1足したい時 increment という関数はMutationに記述せず、 Mutationには数値を受け取ってcounterを変更する changeCounter() を作成します。 Actionに increment という関数を定義し、 increment 内で changeCounter を呼び出し、1を渡してあげましょう。 このように記述することで、 decrement を作成したくなったときも効率的に書くことができると思います。 Action Actionは最終的にMutationをcommitします。 Mutationでは非同期処理を書くことは禁止されていましたが、Actionには 非同期処理を書くことができます 。 第一引数には コンテキスト 、第二引数にはMutationと同様 ペイロード を渡すことができます。 コンテキストはオブジェクトなので、 分割代入 で使用するものだけ渡すとスッキリします。 actions: { doHoge (context) { context.commit( 'HOGE' ) } , doFuga ( { commit } , payload) { commit( 'FUGA' , payload) } } Actionは直接呼び出せません。 store.dispatch から呼び出します。 store.dispatch( 'doFuga' , payload) ToDoアプリのactionは以下のように書いていきます。 図からも分かる通り、 API で通信処理などはここに書きます。 ToDoアプリでいい非同期処理を思いつかなかったのでとりあえず1秒ずらしてToDoを追加します actions: { addTodo( { commit } , { content } ) { commit( 'PUSH_TODO' , { content: content, done: false } ) } , addTodoAsync( { commit } , { content } ) { setTimeout(() => { commit( 'PUSH_TODO' , { content: content, done: false } ) } , 1000) } } これでToDoアプリのStoreが完成しました。 最後にVue コンポーネント にstoreオブジェクトを渡して完成です。 new Vue( { el: "#app" , store, Vue コンポーネント にstoreを渡しているだけなので this.$store からアクセスできます。 今回は直接storeを代入していますが、webpackを使用している場合はVuexをimportしてきて Vue.use(Vuex) でも同じことができます。 完成形を以下においておきます。 jsfiddle.net まとめ ここまでVuexについて書いてきました。 以下にポイントをまとめます。 Storeはアプリケーションに1つだけ存在するように設計する Stateは直接更新しない。必ずMutationから更新すること Mutationは直接呼び出さないこと。 store.commit で呼び出す Mutationには非同期処理を書かない Actionは直接呼び出さないこと。 store.dispatch で呼び出す おわりに 基本的に規約を守って書けばVuexのコードを書くのにそこまで苦労はしないかと思います。 Vuexは難しいと聞いていましたが、 API も多くなく基本的な書き方自体はスッと入ってきた気がします。 しかし、本当に難しいと感じたのはそもそもプロジェクトにVuexを入れるべきか *2 、どこまでStoreに持たせるか、ということです。 また、Vuex + TypeScriptのツラミやVue3 + Vuexなど色々ネタがあるのでこの辺も記事にしていけたらと思います。 私たちは一緒に働くメンバーを募集しています。 ご興味を持たれましたら以下のサイトからお問い合わせください。 career-recruit.rakus.co.jp *1 : アクションはViewから発火させることが多いですが、Viewから発火させないケースもあります *2 : Storeパターンの独自実装を行う, Firebaseなどを使用するなどVuexに頼らなくてもStateを管理できる
アバター
こんにちは、tarakamです。 普段プログラミングをする際、使い慣れた IDE や テキストエディタ があるという方は多いかと思います。では、そこで使う フォント にはこだわっているでしょうか?今回はプログラミングのためのフォント選びについて記します。 Why プログラミングフォント? どんなフォントがいいの? おすすめフォント Ricty Diminished Source Han Code JP Cica おわりに Why プログラミングフォント? 一般的なフォントの場合、アルファベットのI(大文字)とl(小文字)、0(数字)とO(大文字)などが見分けづらいことがあります。普通の文章であれば文脈でわかるでしょうが、プログラミングの場合はそうでないこともあります *1 。見間違えないフォントになっていれば、コードを書くのも読むのも楽になります。 また美しいフォントを使うことで、モチベーションアップにも繋がるかもしれません。 どんなフォントがいいの? 好みにもよるかと思いますが、以下のような条件を満たすものだといいでしょう。 等幅フォント I(大文字のアイ), l(小文字のエル), 1(数字の1), |( バーティカルバー )が区別できる O(大文字のオー), 0(数字のゼロ)が区別できる 日本語に対応している 日本語非対応だと英語と日本語が違うフォントで表示され、字の大きさや線の太さが異なるなど違和感があります 太字・斜体に対応している エディタによっては シンタックス ハイライトで太字や斜体を使うこともあるため これらを踏まえて、以下で筆者のおすすめのフォントをいくつかご紹介します。 おすすめフォント Ricty Diminished Ricty Diminished Ricty Diminished は、英字フォントInconsolataと日本語フォントCircle M+ 1mを元に作成されたフォントです。バグの原因になりやすい全角スペースを区別できるのが特徴の一つです(上記画像の「計算する」の右に全角スペースが入っています)。その他、半濁点が大きく「ば」と「ぱ」などを区別しやすいことも特徴です。 姉妹フォントの Ricty もありますが、ライセンスの関係で手元で スクリプト を実行してフォントを生成する必要があります。Dinimishedの方が漢字の収録数が少ないのですが、一般的に使う漢字は大体カバーされているので、手軽な Ricty Diminishedでも十分でしょう。 Source Han Code JP Source Han Code JP Source Han Code JP (別名 源ノ角ゴシック Code)は Adobe によって作成されたフォントで、Source Code Proと源ノ角ゴシックが元になっています。一般的なフォントは半角と全角の横幅が1:2になっていますが、このフォントは2:3になっているのが特徴です。半角文字の幅が広いため、ゆったりとした印象があります。 Cica Cica Cica は英字フォントのHackとDejaVu Sans Mono、日本語フォントのRounded Mgen+など複数のフォントが元となっているフォントです。 Ricty を参考に作られていて、全角スペースが Ricty Diminishedと同様に可視化されています。 おわりに 今回は3つのフォントの紹介に留めましたが、これ以外にもプログラミングフォントはたくさん存在します。ぜひ自分のお気に入りのフォントを見つけてみてください! *1 : ループカウンタでl(小文字)一文字の変数などよくありますね
アバター
はじめに こんにちは。itoken1013です。 今年も ラク スにたくさんの新入社員が入社しました。 日本中の新エンジニアが研修に取り組んでいるであろうこの頃、今回はGitと GitHub の超基本的な使い方をまとめてみたいと思います。 今やエンジニアにとって必須であるGitですが、チーム開発を行うためには GitHub も使いこなせると、 よりスムーズに開発を進めることができるでしょう。 まずは今回の記事で基本的な使い方を押さえていただければと思います。 弊社ブログのGitに関わる関連記事もぜひご一読ください! ・ 【Git入門】git cloneで既存リポジトリをクローンしよう! ・ 【Git入門】git stashで作業を便利に退避する ・ 【Git入門】git commitを取り消したい、元に戻す方法まとめ はじめに 基本知識 まず、バージョン管理とは Gitとは リポジトリとは GitHubとは 1. GitとGitHubの超基本的な使い方 1-1. Gitのインストール 1-2. Gitの初期設定 1-3. GitHubのアカウント作成 1-4. リモートリポジトリを作成する 1-5. ローカルリポジトリを作成する 1-6. ローカルリポジトリにコミットする 1-7. リモートリポジトリにプッシュする 2. GitとGitHubを使ったチーム開発の超入門 2-1. リポジトリをクローンする 2-2. ブランチを作成する 2-3. ブランチでコミットする 2-4. リモートリポジトリにプッシュする 2-5. コードレビュー・マージ 2-6. リモートリポジトリからプルする まとめ   基本知識 まず、バージョン管理とは ソースコード をはじめとしたファイルの変更履歴(バージョン)を管理することを「バージョン管理」と呼びます。 ファイルの追加や変更の履歴情報を管理することで、過去の変更箇所を確認する、特定時点の内容に戻す、などの「バージョン管理」という作業が可能となります。 このバージョン管理という概念が存在しない状況下での開発作業を考えた場合、 バグ発生時には混入時期が分からず、修正が遅れる、発生したバグによる影響度が不明確になる、 結果としてユーザーの満足度低下につながるなどのリスクが高まります。 また後述するチームでの開発においても、メンバー間での開発内容を連携することが難しくなり、 開発の生産性を大きく損なうことにつながります。 以上のことより、ソフトフェアの開発において、バージョン管理への理解は必須となります。 Gitとは 上記で説明しましたバージョン管理を行うためのシステムがGitです。 他の バージョン管理システム と比較したGitの特徴として、「分散型」の バージョン管理システム である点が挙げられます。 バージョン管理システム は大きく「集中型」と「分散型」に分けられます。 「集中型」の バージョン管理システム では、特定の場所にある リポジトリ への接続が必須となりますが、 「分散型」の バージョン管理システム では個々人のマシン上に リポジトリ を作成して開発を行うことができ、現在のチーム開発における主流となっています。 Gitの具体的な使い方は、後ほど紹介していきます。 リポジトリ とは バージョン管理によって管理されるファイルと履歴情報を保管する領域を、 リポジトリ と呼びます。 リポジトリ の配下でファイルや ディレクト リを操作することで、私たちはバージョン管理を行うことができます。 分散型の バージョン管理システム であるGitでは、まず個々人のマシン上にある リポジトリ 上で作業を実施後、 作業内容をネットワーク先のサーバー上などにある リポジトリ に集約する流れで開発を進めていきます。 この個々人の リポジトリ を「ローカル リポジトリ 」、集約先となる リポジトリ を「リモー トリポジ トリ」と呼びます。 Gitを使った開発ではこの区別が重要となるため、しっかり理解いただければと思います。 GitHub とは 複数人のエンジニアがリモー トリポジ トリとして活用する他、チーム開発を行うための機能を提供する WEBサービス が GitHub です。 リポジトリ としての機能を持つ他にも、コード レビュー機能 や Wiki などのコミュニケーションツールとしての機能を持ち、組織規模を問わず、多くの企業・団体がソフトウェア開発で利用しています。 後述ではリモー トリポジ トリの作り方、またコードレビューを実施する方法を紹介していきます。 1. Gitと GitHub の超基本的な使い方 概要の説明を踏まえたところで、まずはGitと GitHub の超基本的な使い方を説明していきます。 Gitの初期設定を踏まえ、以下の流れで GitHub にファイルを反映してみましょう。 Gitのインストール Gitの初期設定 GitHub のアカウントを作成 リモー トリポジ トリを作成する ローカル リポジトリ を作成する ローカル リポジトリ にコミットする リモー トリポジ トリにプッシュする 1-1. Gitのインストール まずはGitを利用できる状態にしていきましょう。 Mac の場合 Mac であればGitはインストール済となりますため、本作業は不要です。 Windows の場合 公式ページ から インストーラ ーをダウンロードします。 インストーラ ーを起動すると多くの設問が表示されますが、 本記事の作業では全てデフォルトの状態で問題ありません。 「Next」ボタンをクリックし続け、以下の画面まで辿り着きましたら「Install」ボタンでインストールを行います。 インストールが完了しましたら、Git Bash を起動します。 Git Bash とは、 Windows 上でGitのコマンドを操作するためのツールです。 Git Bash を起動後、以下のコマンドを入力してGitのバージョン情報が表示されることを確認してください。 $ git --version git version 2.26.2.windows.1 ※以降のGit操作は全てターミナルやGit Bash などの コマンドライン として紹介していきますが、 Gitは GUI ツールを使って利用することも可能です。 「Git GUI 」などで検索の上、利用シーンに応じて使い分けていただければと思います。 1-2. Gitの初期設定 Mac だとターミナル、 Windows だとGit Bash での作業です。 Gitでは ソースコード の変更履歴を確認できますが、「誰が」変更したかを確認するための情報が必要となります。 この作業者を識別するための情報として、ユーザ名とメールアドレスを登録する作業を行います。 ユーザ名 以下のコマンドを入力してください。 git config --global user.name 任意のユーザ名 メールアドレス 以下のコマンドを入力してください。 git config --global user.email 任意のメールアドレス 最後に以下のコマンドを入力すると、上記のユーザ名とメールアドレスが登録されていることを確認できます。 $ git config --list core.symlinks=false core.autocrlf=false color.diff=auto ・ ・ 中略 ・ ・ user.name=設定したユーザ名 user.email=設定したメールアドレス ・ ・ 1-3. GitHub のアカウント作成 次に GitHub にアカウントを作成してみましょう。 GitHub へアクセスし、ユーザ名・メールアドレス・パスワードを入力し、「 Sign up for GitHub 」ボタンをクリックします。 次に以下の画面で「Verify your account」の設問に回答後、「Join a free plan」を選択します。 次に「Welcome to GitHub 」と表示された画面へ進みますが、一番下まで進み、 「Complete setup」ボタンをクリックしてください。 ~~ 中略 ~~ 最後にこちらの画面が表示され、入力したメールアドレスへ認証用のメールが配信されます。 メールを確認の上、認証を行ってください。 ここまでで GitHub のアカウント作成は完了です。 1-4. リモー トリポジ トリを作成する GitHub にアクセスし、リモー トリポジ トリを作成します。 トップ画面で「Create Repository」ボタンをクリックしてください。 リポジトリ 作成画面に移動します。 以下の画面では、「Repository name」には任意の リポジトリ 名を入力します。 ※ここでは例として、「rakus」という リポジトリ 名を入力します。 次に リポジトリ の種類として、「Public」か「Private」を選択します。 GitHub では長らく有料会員のみ「Private」を選択できていましたが、2019年からFreeプランでも「Private」を作成できるようになりました。 今回はどちらを選択いただいても構いません。 「Public」を選択した場合:他のユーザーが ソースコード を閲覧することが可能となります。 「Private」を選択した場合:非公開となります。 次に「Initialize this repository with a README」ですが、 リポジトリ の説明や使い方を記述するREADMEファイルを事前作成しておく場合にはチェックをONにします。 最後の「.gitignore」や「license」は None を選択で構いません。 最後に「Create repository」ボタンをクリックすると、 リポジトリ が作成されます。 1-5. ローカル リポジトリ を作成する 次にローカル リポジトリ を作成していきます。 ※記事では例として「rakus」という ディレクト リを作成します。 その後、 git init コマンドを入力することで、作成した ディレクト リをgit リポジトリ として初期化します。 コマンドは作成した ディレクト リ上で実施する必要がある点に注意してください。 git init 1-6. ローカル リポジトリ にコミットする コミット(commit) とは、ファイルの追加・変更をローカル リポジトリ に反映する操作を意味します。 実際にローカル リポジトリ にファイルを追加してみましょう。 まずは1-5で作成した ディレクト リ配下で「index.html」というファイルを作成します。 テキストエディタ などでファイルを作成してください。 この状態ではファイルを作成しただけですので、まだ リポジトリ にはファイルは追加されていません。 次に以下のコマンドを入力し、インデックスへ「index.html」を追加します。 インデックスとは、コミット前に変更内容を一時的に保存する領域を指し、インデックスに追加されたファイルのみがコミットの対象となります。 git add index.html 最後に、インデックスへ追加したファイルをコミットします。 以下のコマンドを入力すると、インデックスに存在するファイルがローカル リポジトリ へ追加されます。 git commit -m "[Add] index" ここで -m はコミットメッセージを入力するためのオプションです。 コミットメッセージを残すことでより詳細な履歴情報を残すことができ、後々ログからコミット内容を確認する際に役立ちます。 積極的に活用しましょう。 また、コミットメッセージを含めた変更履歴(ログ)は、以下の git log コマンドを入力することで以下のように確認できます。 $ git log commit 6a8e257...コミットハッシュ.....642e3 (HEAD -> master) Author: ユーザ名 <メールアドレス> Date: Tue May 26 18:45:56 2020 +0900 [Add] index 1-7. リモー トリポジ トリにプッシュする 最後にローカル リポジトリ の変更を GitHub 上のリモー トリポジ トリに反映する プッシュ(push) を行います。 まずはローカル リポジトリ とリモー トリポジ トリを紐づけをするために、ローカル リポジトリ 配下で以下のコマンドを入力します。 git remote add origin https://github.com/ユーザ/[作成したリポジトリ].git これでリモー トリポジ トリの情報がローカル リポジトリ に登録されました。 次にローカル リポジトリ の変更内容をリモー トリポジ トリに反映させるため、以下のコマンドを入力してプッシュを行います。 GitHub のユーザ名とパスワードを求められますので、アカウント登録時に設定した内容を入力してください。 git push origin master これでリモー トリポジ トリへ反映させることができました。 GitHub でも変更内容が反映されていることが確認できます。 ※ GitHub 上に公開鍵情報を登録することで、プッシュ時にユーザ名とパスワードを都度入力する手間を省くことができます。 詳細な手順は割愛しますが、興味のある方は調べてみてください。 git commit、git stashのやり方を知りたいという方は以下ブログも参考に下さい。 ・ 【Git入門】git commitを取り消したい、元に戻す方法まとめ - RAKUS Developers Blog | ラクス エンジニアブログ ・ 【Git入門】git stashで作業を便利に退避する - RAKUS Developers Blog | ラクス エンジニアブログ 2. Gitと GitHub を使ったチーム開発の超入門 ここまでGitと GitHub 基本的な使い方を紹介してきましたが、チームで他のメンバーと開発を行う際の使い方についても、基本的な操作を紹介していきたいと思います。 Gitには ブランチ(branch) という仕組みがあり、チーム開発を行う際にはブランチを使いこなす必要があります。 2-1. リポジトリ をクローンする あなたが新たに開発現場に参加することになった場合、すでに存在するリモー トリポジ トリから ソースコード を取得することになります。こちらの作業を実施してみましょう。 先ほど作成した ディレクト リとは別の ディレクト リ(当記事では「rakuraku」とします)を作成し、以下のコマンドを実行してください。 コマンドは作成した ディレクト リ上で実施する必要がある点に注意してください。 git clone https://github.com/ユーザ名/[作成したリポジトリ].git 新しく作成した ディレクト リ(rakuraku ディレクト リ)上に先ほどプッシュした index.html が表示されたかと思います。 このようにリモートから リポジトリ から取得する作業を クローン(clone) と呼びます。 2-2. ブランチを作成する ソフトウェア開発では同時進行で複数のバージョンの開発が行われることは珍しいことではありません。 また突発的なバグ対応が発生することもあり、こちらも新たにリリースするバージョンとは別軸で対応する必要が出てきます。 これらを並行しつつ開発を実現するための仕組みとして、Gitには ブランチ(branch:枝、枝分かれ) という機能が提供されています。 以下の図に示すようにブランチを使い、変更履歴を分岐した開発を実現することができます。 ブランチを作成するには、 git branch コマンドを使います。 例として、現在作業中のブランチ(デフォルトで存在するブランチを「master」と呼びます)から「feature1」というブランチを作成してみます。 以下のようにコマンドを入力してください。 git branch feature1 これでmaster からfeature1 ブランチが作成されました。 次にfeature1 ブランチ上で作業を行うために、checkoutコマンドを入力してブランチを移動します。 git checkout feature1 ここで git branch コマンドを入力すると、現在ローカル リポジトリ 上に存在する「master」と「feature1」というブランチが表示されます。 「*」は作業を行っているブランチを示しています。 $ git branch * feature1 master 2-3. ブランチでコミットする feature1ブランチでの作業として、今度はlogin.htmlというファイルを作成してみます。 作成したlogin.htmlをfeature1ブランチにコミットします。 以下のコマンドを入力してください。 git add login.html git commit -m "[Add] login" 2-4. リモー トリポジ トリにプッシュする 次に、リモー トリポジ トリ( GitHub )にもfeature1ブランチの内容を反映します。 1-7の手順と異なり、push先のブランチが feature1 になっている点に注意してください。 git push origin feature1 GitHub にアクセスすると、2つのブランチ(master と feature1)が存在することが確認できます。 またfeature1 ブランチには変更内容がプッシュされたことが確認できます。 逆にプッシュ先ではないmaster には変更内容が反映されていないことも確認できます。 2-5. コードレビュー・マージ ブランチでの開発作業が完了しましたら、メインとなるブランチ(一般的には master)に変更内容を取り込み、開発内容を統合します。 このように特定のブランチの変更内容を別のブランチに取り込むことを マージ と呼びます。 このマージを行う際、 GitHub 上では プルリク エス ト と呼ばれる機能を使い、コードレビューを行うことができます。 指摘がある場合にはコメントを追加し、作業者に修正を促すことができます。 こちらの概要についても説明します。 レビューの依頼 まずは Github 上でfeature1ブランチを開き、「New Pull Request」をクリックします。 次にプルリク エス トを作成します。 以下の点を確認・入力の上、「Create pull request」ボタンをクリックしてください。 ① マージ元・先のブランチ ② レビュアー(レビューを行う人) ③ レビュー内容 ④ レビュー・マージ対象の ソースコード レビューの実施 プルリク エス トを受取ったレビュアーは「Pull requests」タブを開き、「Files changed」から ソースコード を確認します。 指摘がある場合には、 ソースコード のビュー上にコメントを追加し、開発者へ修正を促します。 内容に問題がなければ、「Conversation」の「Merge pull request」をクリックしてレビューを完了します。 このタイミングでブランチのマージも実施され、feature1 の内容が master にも反映されます。 マージを行ったことで、login.html が master 上にも表示されることが確認できます。 実際のレビューでは、開発する機能やバグ修正の複数の ソースコード をプルリク エス トで確認することとなります。 また指摘が発生し、何度も開発者とレビュアーとの往復が発生することも珍しくはありません。 こちらの基本的な流れをベースに、実務でのコードレビューに臨んでいただければと思います。 2-6. リモー トリポジ トリからプルする リモー トリポジ トリの master にはマージが行われましたが、あなた(および他の開発者)のローカル リポジトリ 上の master にはまだマージ内容が反映されていません。 今後も開発作業を進めていくには、マージした内容(ここでは login.html )をローカル リポジトリ の master に取得し、最新化する必要があります。 この場合、 プル(pull) という操作を行うことで、リモー トリポジ トリから変更内容を取得することができます。 まずはブランチをmaster に切り替えてみましょう。 この時点ではまだ先ほどマージしたlogin.html が確認できないはずです。 git checkout master 次に git pull コマンドを実行し、リモー トリポジ トリのmaster から最新の変更内容を取得します。 git pull remote: ・・・・ ・ ・ ・ From https://github.com/ユーザ名/[作成したリポジトリ] f5・・27 e4・・0f master -> origin/master Updating f5・・27 e4・・0f Fast-forward login.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 login.html これでローカル リポジトリ のmaster には、リモー トリポジ トリの最新の内容が反映されました。 ls コマンドを実行すると、login.html を確認することができます。 またgit log コマンドを入力することで、これまでの全作業の変更履歴を確認することもできます。 $ ls index.html login.html $ git log commit 99c9637・・・・5281c0e (HEAD -> master, origin/master, origin/HEAD) Merge: f5・・27 e4・・0f Author: ユーザ名 Date: Fri May 29 19:28:48 2020 +0900 Merge pull request #1 from リポジトリ名/feature1 [Add] login commit e4ccb0fa2・・・・・3e33b983c0 (origin/feature1, feature1) Author: ユーザ名 <メールアドレス> Date: Fri May 29 19:26:08 2020 +0900 [Add] login commit f5dbc270a・・・・・735f93a53d90a1c1068 Author: ユーザ名 <メールアドレス> Date: Tue May 26 18:45:56 2020 +0900 [Add] index このようにして他の開発者が変更した内容も取得することで、チームでの開発を進めていくことができます。 まとめ Gitと GitHub の超入門として、概要を紹介しました。 Gitも GitHub もここだけでは全てを紹介し切れない奥が深いツールになります。 今回紹介しました基本的な内容をベースに、より理解を深めていっていただければ嬉しいです。 ではでは。   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
こんにちは。badaikiです。 新型コロナウィルスの影響で ラク スも緊急事態宣言の発令に伴い、感染防止のためリモートワークに移行しておりました。先日のブログでは、 ラク ス社員がリモートワーク中にどのような工夫をして効率を上げていたのかについてまとめられていました。私も仕事以外の時間には業務用PCを見えない場所に片づけるようにしてメリハリをつけながら、週に3、4回ほど夜中にランニングをするなど体調管理に気を付けていました。 tech-blog.rakus.co.jp はじめに オンライン勉強会のメリット 参加した勉強会の紹介 おわりに はじめに 私は一人暮らしのため業務外の時間になると、世間から遮断されたように誰とも会話することもなく誰の声を聞くこともなく、ただただ暇つぶしにテレビを観たりゲームをしたりといった自粛生活を送っていました。 今回のブログでは、そんな空いた時間を活用しようと参加したオンライン勉強会を紹介していこうと思います。 恥ずかしながら、これまで他社の勉強会に参加したことがありませんでした。勉強会に参加しないとな、、、という意思は持っていたものの参加できていなかったのですが、手始めにオンライン勉強会に参加してみよう!と思い立ち、申し込みボタンをクリックしました。 オンライン勉強会のメリット 勉強会には参加したほうがいいとはわかっているものの、なかなか行動に移せていない人も多いのではないかと思います。そこで オンライン勉強会のメリット を挙げてみます。 移動しなくていい リモートならではですよね。PCを立ち上げてURLをクリックするだけでいいんですから!普段なら参加できない遠方の勉強会に参加できるのも魅力ですよね! 懇親会がない これは良し悪しありますが、勉強会に参加できていない理由の一つとしてコミュニケーションが心配という方もいらっしゃるのではないでしょうか。 時間が短い 私が参加したものだと30分のものもありました。普段の勉強会だと移動時間+開催時間で最低でも3時間くらいはかかってしまうので、手頃ですね! ラジオ感覚で聞ける これは自分が参加してみて一番感じました。オフラインの勉強会と比べてかなり気軽に聞けるのはとても大きいと感じました。 この自粛期間を利用して4つの勉強会に参加させていただいたのですが、中には退勤した直後から参加したり、 トークショー だと夕飯を作りながら聞いていたものもありました。 参加した勉強会の紹介 freee Tech Night Online #1「ふりてくおんらいん」 freee-tech-night.connpass.com こちらはfreee株式会社主催の トークショー でした。情シスの方が「リモートワーク開始の裏側をゆるーく語る」をテーマに トーク を繰り広げられていました。テーマの通りゆるーく会話されていましたが、内容はなかなか相当壮絶なものでした。普段は聞けない話が多く、とても新鮮でした。 ラク スも情シスなどの方々が動いてくださって不便なくリモートワークへ移行できましたので、本当に感謝です。 Cybozu Tech Meetup #1 kintone開発チーム cybozu.connpass.com こちらは サイボウズ 株式会社主催のMeetupでした。kintone開発チームの内情について、開発チームの方やQAチームの方の発表を聞くことができました。kintoneチームがどのようにリモートでモブプロを行っているのか、新卒エンジニアやIT業界未経験QAエンジニアがどのように立ち上がったのかという内容でした。私は新卒入社のため、新卒エンジニアさんの発表に注目しておりました。学生時代に手あたり次第気になった技術を触っていたそうで、1つのサービスを突き詰めていくマインドをどのように育んでいくかという内容でした。新卒社員の多くが通る悩みだと思いますので、新卒社員やこれから入社する学生にも見ていただきたい発表でした! 【オンライン】関西 PHP 勉強会 phpkansai.connpass.com こちらは「 PHPカンファレンス 関西2020」がコロナの影響で中止となったため、PHPer同士の交流の場を増やしたいというのを目的としたLT会でした。個人的に興味を持ったのは「PhpStorm中級入門」と「LaravelでDB操作を監視する」ですね。PhpStormを使い始めて約2年になりますが、まだまだ使いこなせていないなーと感じました。DB操作の監視は知らない技術だったため、興味を持ちました。顧客との「何もしてないのに壊れた」のやりとりのとき、皆さんの共感がすごかったですねw 「関西 PHP 勉強会」ではありますが、全国からPHPerが集まっていてオンラインの良さが際立っていました! 【オンライン】PHPerによるPHPerのための「 PHP のニュースや記事を語り合う」TechCafe rakus.connpass.com こちらは弊社 ラク スが主催のLT& トークショー でした。普段は、弊社オフィスに来社頂き、特定のテーマについてディスカッションやもくもく自習などを行っているのですが、初のオンライン開催となりました。 トーク テーマは「 PHP のニュースや記事を語り合う」ということで、 ラク スのエンジニアが気になった記事を持ち寄って紹介し トーク を繰り広げるというものでした。一人でもくもくと情報収集するのもいいですが、ほかの人に共有して意見交換するのも自分と違った観点での意見が聞けたりするのでおもしろいなと感じました。 おわりに 以上が私が自粛期間中に参加したオンライン勉強会でした。 トークショー やLT会など様々な内容の勉強会に参加させていただきました。まだしばらくはオンラインの勉強会が開催されると思いますので、どんどん参加していきましょう!私も積極的に参加し、オフラインの勉強会にも参加していくようにします! 最後まで読んでいただきありがとうございました!
アバター
みなさんこんにちは。フジサワです。 緊急事態宣言が多くの 都道 府県では解除が行われ、まだ未解除の地域でも解除の方向に向かっていますね。 ラク スも政府の緊急事態宣言の発令に伴い、感染拡大防止のためリモートワークに移行しました。 移行当初は、普段との勝手の違いから戸惑う声なども多少はあったようですが、もともと国内・海外の拠点間で、ビデオ通話やチャットツールなどを用いた開発を行なっているので、全体を通してみれば大きな混乱は少なかったようです。 むしろ、蓋を開けてみると、各々自分なりのリモートワークスタイルを確立し、 楽しんでいる 前向きに向き合っていたように見えます。 新しい 生活様式 が推奨される中、今後もリモートワークは日本企業に根付いていくのではないでしょうか。 そこで、 「リモートワーク中のエンジニアの ライフハック に迫る!」 と題しまして、リモートワーク中の ラク スエンジニアが、自らのリモートワークライフをどのようにHackしているかをご紹介しようと思います! 弊社エンジニアに、「リモートワークの質を向上するために、工夫していることを教えてください!」というアンケートをとった結果をお伝えします! オシゴト環境についてのHack ディスプレイ・モニタに関するものが圧倒的に多い ついで多かったのは、音・BGMに関するもの イスに関するHackも 意外に多いスマートウォッチ勢 番外 働き方についてのHack オン/オフの切り替え・リフレッシュ 子育て・家族との関係 食生活 オシゴト環境についてのHack ディスプレイ・モニタに関するものが圧倒的に多い これは予想通りの結果でした。 エンジニアにとって、モニタの枚数・サイズ・解像度がそのまま生産性に跳ね返ってくると言っても過言ではありません。 デュアルモニタ・トリプルモニタはあたりまえ、モニタアームや大画面モニタを採用する人もおり、 むしろ社内よりも快適になってるんじゃないか と思われるケースも。 中には自宅のテレビをディスプレイがわりに活用している人もいたようです。 ついで多かったのは、音・BGMに関するもの 音やBGMに関しての意見をあげている人は多いものの、人によってこだわりポイントは大きく違っているようです。 ラジオや歌声が入っているもの派 歌なし or 日本語以外の歌派 音楽じゃない環境音(オフィスの音など)派 など、様々な意見がありました。 ご家族の生活音が気になるということで、 ノイズキャンセリング 機能のあるヘッドフォンを使っている人も。 音楽配信 サービスや、ラジオ配信サービスなどの活用も人気のようです。 音に関しては、完全な無音状態を好む人もいると思いますし、 自分に合ったスタイルを選ぶことができるのはリモートワークのメリット の一つかもしれませんね。 イスに関するHackも 長時間座っているため、普通のイスでは「オシリが耐えられない」人が多かった模様。 ゲーミングチェアや低反発クッションなどを導入したという意見が目立ちました。 一方、「ちゃぶ台に正座がベスト」という 古式ゆかしいジャパニーズスタイルで戦う猛者 も。 ちなみに私は、ゲーミングチェア+ゲルクッション+あぐらスタイルで何時間でも座っていられるようになりました。 オフィスで何気なく使っていたイスが「ああ、あれは実に良いものを採用してくれていたんだなあ」と気づかされました。 意外に多いスマートウォッチ勢 「腕時計」というと、外出する時に身に着けるイメージでしたが、スマートウォッチに関してはその限りではないようですね。 次のような使い方をしている人が目立ちました。 運動不足になるので自らのアクティビティを可視化。座りっぱなしを抑制できる。健康管理のため。 時間感覚がなくなるので会議とアラームを連動させアラームを鳴らす。気持ちの切り替えにもなる。 番外 今回アンケートをとった中で、もっとも異彩を放った回答が 介護用デスクを活用する というもの。 ベッドで寝ながら仕事ができます! らしいです。本人談によれば「大事なもの(体力)が失われている気がする」とのことですが、 気のせいじゃない と思います。 そのまま寝たきりになってしまわないように気をつけていただきたいものです。 あとは、 ふくらはぎマッサージ機を使っています という人も。 この超快適な環境の二人が、通常の勤務が再開された時でもちゃんと出社してくれることを祈ります。 働き方についてのHack ここまでは、設備や環境などについてのHackを見てきましたが、ここからは働き方のHackについて注目したいと思います。 オン/オフの切り替え・リフレッシュ リモートワークでは、オンとオフを切り替えや、リフレッシュをうまく行わないと、業務効率が悪くなってしまいます。 ラク スのエンジニアは次のようなスタイルで、リフレッシュを図っていたようです。 朝のランニング・ウォーキング リフレッシュだけでなく、運動不足の解消にもなりますね。リモートワーク前と同じ時間に家を出て、始業時間までウォーキングをして習慣の維持を行っている人も。日光をきちんと浴びることは重要みたいですね! 筋トレ 「オフィスではできない高強度も筋トレができるようになりました」とのこと。エンジニアには強靭な肉体も必要です。 業務後は、ノートPCを片付ける。業務用PCが視界に入らないようにする リビングなど、生活空間で仕事をせざるを得ない方も多い中、結果的にこうしたルーティンが切り替えの役割も果たしているようです。 家族に「行ってきます」「ただいま」の挨拶をする 気持ちを切り替えるルーティンとのことですが、ほっこりするエピソードでいいなと思いました。 ポモドーロテクニック を使って意識的に休憩を入れる 25分作業したら5分休む、というものですね。他人に影響されずにもくもくと作業しているとエンドレスになってしまい、効率が悪くなってしまうので、こうしたテクニックは重要ですね。 大きな抱き枕 リフレッシュのツールだけでなく、ラバー ダッキング の相手にも使えるとのこと。この辺はエンジニアらしいですね。 作業場所を変える 仕事部屋を変えたり、出窓で作業をするなど、自宅内でもロケーションを変えることでリフレッシュできるようです。 窓を開ける、部屋の換気をする 基本的なところですが、意外と盲点だったり。 他にも、「花を飾る」「壁紙を集中できる色に変える」などの素敵な意見もありました。 子育て・家族との関係 学校や幼稚園・保育園などが休校中のため、子育てや家族との関わり方を工夫している人も多かったようです。 祖父母にビデオ通話で子守をお願いする 仕事中はなかなか子供にかまってあげられないのですが、これは良いア イデア ですね!祖父母も、孫の顔が見られるので、Win/Winとのこと。 オンライン教育 遊ばせているだけになりがちな中、オンライン教材を活用しているご家庭も。英会話など、先生が付いてくれるものなどは子守の効果もあって良いようですよ! 子供向けの YouTube 動画 効果は絶大で放っておけば半永久的に見ているお子様が多いようです。我が家も、教育上長時間見させてはいけないなと思いつつも、どうしても頼らざるを得ないシーンがあり、 最後の切り札 としてお世話になっています。 家庭内の連絡はLINEでお願いする 突発的にビデオ会議を行なっている場合なども多いので、ツールを介してコミュニケーションを取るのは良いですね。集中を乱されないというような効果も期待できそうです。 食生活 生きていくためには、食事を取らなければなりません。 食生活に関しても、みなさん色々と工夫しているようです。 宅配弁当を活用する 自炊コストを減らすだけでなく、外出リスクの低減にも役立ったようです。 買い物はネットスーパーなどで行う こちらも、時短+リスク軽減策として。 自動調理鍋や炊飯器で時 短調 理する 具材や調味料を入れてボタンを押すだけで料理が出来上がるのでとても便利とのこと。今回の件がなくても試してみたい感じがします! いかがでしたでしょうか? 今後も、 コロナウイルス に対しては適切な危機感を持ちつつ、経済と生命のバランスをうまく取りながら共存していくことが求められます。 少しでも、この記事を読んでいただいた方のお役にたてば幸いです。 また、アンケートをとってみて感じたことですが、これまでは同じ空間で画一的な環境・働き方で仕事していましたが、良い面もある一方、個々人にとって 必ずしもベストな選択肢とは限らないのだな、ということがわかりました。 多様な働き方が増えていくと思いますので、今回の経験もうまく活用していきたいと思います。 ではでは!
アバター
はじめまして、 syoneshin です。 私はこれまで IT出版/HR領域の事業開発/ マーケティング を経て 現在は ラク ス技術広報担当として テックブログ運営やMeetup/採用イベント企画など広報活動を行っております。 開発は未経験ですが 当社技術スタックは最低限調べ、実践し アウトプットしようという気概で 今回は「 シェルスクリプト 」について書きました。 本記事が シェルスクリプト を勉強しよう シェルスクリプト を思い出そう シェルスクリプト のコマンドを参照しよう と言う方のお役にたてれば、幸いです。   1.シェルスクリプトとは 2.基本設定 ファイルを作成 3.基本コマンド コメント 入/出力 変数 シェルの特殊変数 演算子(オペレーター) 条件分岐  if文 case文 ループ処理 for文 while文 4.まとめ 1. シェルスクリプト とは  ・簡単に言うと シェル( Windows の「 コマンドプロンプト 」みたいなもの)で解釈できる命令( プログラミング言語 )や命令を寄せ集めて作ったプログラム のことです。 ・詳しく言うと OS操作の為、シェル上で実行できる簡易な プログラミング言語 ( スクリプト言語 ) の事です。 また、そのような言語によって書かれた 複数のOSコマンドや制御文などを組み合わせた簡易プログラムを指し 一般的には UNIX系OS ( Linux など)のシェルで実行できるものを指します。 シェルにはいくつかの種類があります。 大別すると以下のシェルに分けられます。 ・ B-Shell (Bourne-Shell) 系 :sh, ash, bash , zsh , ksh ・ C-Shell系 : csh , tcsh B-Shell 系のシェルでも sh は シェルスクリプト でよく利用されます。 ( Linux や Mac OS は bash がシェルの標準環境の為、 bash がよく利用されています) シェルスクリプト で書かれる典型的な処理例は ファイル操作、プログラム実行、テキスト印刷などがあり 主に定型作業の自動化によく使われ 条件命令の実行/ファイル読み込み・書き出しなど 上から順にコマンドが実行される為、都度コマンドを打たずにすみます。 以下からは、実際に シェルスクリプト を書いていきます。 2.基本設定 ファイルを作成  ‐ シェルスクリプト ファイルは .sh 拡張子で基本作成  ‐ここでは test.sh ファイルを作成   test.sh シェルスクリプト 記述で、まず初めに覚えなければならないのは次の記述 #! /bin/sh # はhash、 ! はbangで、 #! を shebang (シェバン)と言います。 シェバンから スクリプト を実行する インタープリタ が呼ばれ /bin/sh のファイルが実行されるという意味です。 #! /bin/sh を書き、システムに「 シェルスクリプト を書きますよ」と知らせます。 ※ bash の独自機能を使う場合は #!/bin/bsh と書く必要があります。   test.sh #! /bin/sh     test.sh #! /bin/sh echo "Hello, World!" シェルスクリプト ファイル( test.sh )を実行するには ターミナルからファイルが保存されてる場所で 以下のどちらかのコマンドで実行できます。   $ ./test.sh $ sh test.sh ファイル実行すると Hello, World! と表示されます。   $ ./test.sh Hello, World!   3.基本コマンド   コメント コメントの入力には # を書く必要があります。   test.sh #! /bin/sh #コメントの入力には#を書く必要があります。 入/出力 出力は echo 、入力は read で行えます。   test.sh #! /bin/sh read NAME echo "Hi, $NAME !" 実行結果は以下   $ ./test.sh syoneshin Hi, syoneshin!   変数 ・変数の名前には半角英数字(a-z、A-Z、0-9)とアンダーバー(_)が使えます。 ・変数に値を与える時は = を前後空白なしで書きます。 ・文字列の場合は " を付けて囲みます。 ・変数にアクセスする時は変数名の前に $ を付けます。または $ 付けて変数を {} で囲みます。 ・1つの変数に1つの値しか保存できません。 ・変数値の上書きをなくすには readonly を書きます。 ・変数は unset で削除、 readonly で変数の上書き/削除不可にします。   test.sh #! /bin/sh var = "変数1" var_2 = "変数2" echo "var_2= $var_2 " var_2 = "var_2が変更されました。" echo ${ var_2 } readonly var var = "readonly varを変えてみる。" 実行結果は以下   $ ./test.sh var_2=変数2 var_2が変更されました。 ./test.sh: line 11: var: readonly variable   シェルの特殊変数 シェルスクリプト では以下のような特別な変数があります。 変数 機能 $1~$9 シェル引数の値。第1引数は$1、第2引数は$2でアクセス $# シェル引数の数 $* 全引数をまとめて1つとして処理 "$*"のように囲むと、"$1 $2 … $n"形式になる。 $@ 全引数を個別として処理。全引数リスト。"$@"のように囲むと、"$1" "$2" … "$n"形式になる。 $$ 実行中のシェルのプロセスID。 $? 最後に実行したコマンドの戻り値。成功は0、失敗は1で返ってくる。 $- シェルの実行オプション(setコマンドや#!/bin/ bash 行に付けたオプション。 $! シェルが最後に実行したバックグラウンドプロセスのID ・シェルの 特殊文字 以下は シェルスクリプト の 特殊文字 です。 ; | & ^ \ $ ? * < > ( ) [ ] { } # % = ` " ' ~ TAB SPACE NEWLINE これら 特殊文字 を表示するには、 エス ケープする必要があり \ バックスラッシュを付けて一文字単位で扱うか ' シングルクオーテーションを付けて囲む事で扱え使えます。 また " ダブルクオーテーションで囲んだ場合 $ ` \ を評価し囲まれたすべてを文字列として扱う処理ができます。 演算子 (オペレーター) 「 演算子 」とは簡単にいうと「どんな演算をする」と表す記号の事です。 「 演算子 」の種類は多様で 「算術 演算子 」「比較 演算子 」「論理 演算子 」などがあります。  ※詳細省略 シェルでは「算術演算」を `expr 数字 演算子 数字` で計算する事ができます。 ※これからプログラミングをはじめられる方は最低限「算術 演算子 」「比較 演算子 」は覚えた方がよいです。 以下表はシェルの 演算子 種類/意味/例を記載しています。 算術 意味 記述例 + 足す echo `expr 10 + 20` => 30 - 引く echo `expr 20 - 10` => 10 \* 掛ける echo `expr 11 \* 11` => 121 / 割る echo `expr 10 / 2` => 5 % 余り echo `expr 10 % 4` => 2 = 指定 a=$b bの値はaに保存されます ※ [ コマンドの引数に変数を指定するときは " でクォートする必要があります 比較 意味 記述例 == 等しい [ "$a" == "$b" ] 値aと値bが等しい場合TRUE(真)を返します。 != 異なる [ "$a" != "$b" ] 値aと値bが異なる場合TRUE(真)を返します。 -eq イコール [ "$a" -eq "$b" ] 値aと値bが等しければTRUE(真)を返します。 -ne 異なる [ "$a" -ne "$b" ] 値aと値bが異なればTRUE(真)を返します。 -gt より大きい [ "$a" -gt "$b" ] 値aが値bより大きければTRUE(真)を返します。 -lt より小さい  [ "$a" -lt "$b" ] 値aが値bより小さければTRUE(真)を返します。 -ge 等しいかより大きい [ "$a" -ge "$b" ] 値aが値bと等しいか、より大きければTRUE(真)を返します。 -le 等しいかより小さい [ $a" -le "$b" ] 値aが値bと等しいか、より小さければTRUE(真)を返します。   論理  意味 例 -a 両方(and) [ "$a" -gt 90 -a "$a" -lt 100 ] 値aが 90より大きく100より小さい場合TRUEを返します。  -o どちらか(or) [ "$a" -gt "$b" -o "$a" -lt "$b" ] 値aが値bより大きいか小さいかの場合TRUEを返します。 ! ではない(is not) [ ! "$a" -gt "$b" ]  値aが値bより大きくなければTRUE(真)を返します。   条件分岐  if文 シェルスクリプト のif文の基本は if [ 条件 ] then コマンド fi で書きます。 if のあとに条件式を書き、条件合致(条件がTRUE(真)の場合)していれば then から fi までのコマンドを実行します。 if文の書式は次の様になります。   if [ 条件1 ]; then コマンド1 fi もし「条件1」に合致すれば、「コマンド1」を実行しますの意味です。 条件1に合致しない場合に「コマンド2」を実行したいとき else を使い、次の様にします。   if [ 条件1 ]; then コマンド1 else コマンド2 fi もし「条件1」に合致すれば、「コマンド1」を実行します。 それ以外は「コマンド2」を実行しますという意味です。 さらに分岐を分けたいときにはelifを使います。※「else if」の省略   if [ 条件1 ]; then コマンド1 elif [ 条件2 ]; then コマンド2 else コマンド3 fi もし「条件1」に当てはまるなら、「コマンド1」を実行します。 それ以外で「条件2」に当てはまるなら「コマンド2」を実行します。 それ以外は「コマンド3」を実行するという意味です。 case文   case 文は Cや Java 言語の switch 文に該当する制御文で if文と同じようにコマンド実行を分岐するために使用されるものです。 基本の書き方は  case 変数 in 条件・値) コマンド ;; esac で書きます。 条件・値が変数と合う場合、case 文は指定した条件と値の複数パターンとのマッチングにより指定したコマンドを実行します。 ※単純な分岐条件で、コマンド処理が3つ以上ある場合はcase文が向いているとされます。 case文の書式は次のようになります。   case 値 in 条件・値1 ) コマンド1 ;; 条件・値2 ) コマンド2 ;; 条件・値3 ) コマンド3 ;; … 条件・値n ) コマンドn ;; esac ループ処理 for文 for文はループ処理「n回数、同じ処理を繰り返す」とする制御文で for文の書式は次のようになります。   for 変数 in 値リスト do コマンド done   while文 While文はループ処理「条件を満たしている間は同じ処理を繰り返す」とする制御文で While文の書式は次のようになります。   while 条件式 do コマンド done   4.まとめ   シェルスクリプト が動く仕組みを学び、基本構文を書いた気づきは 一度サクッと書いてみて実行結果がすぐわかると、理解がとても進むという 当たり前の事でした。 学習場面において、私の様な開発未経験者に伝えたい事は Leap before you look(見る前に飛べ) 清水の舞台から飛び降りろ です。 また、すっかり定着したDevOpsの文脈では プログラムでのインフラ管理が主流になり 構成管理ツールなどは、主に スクリプト言語 を利用するため コンパイラ 言語だけでなく、 スクリプト言語 もできる方はとても重宝されます。 これから スクリプト言語 をはじめる方には シェルスクリプト はとっかかりやすくおススメです! 【引用参考】 ※WEB参考資料は以下 ・ シェルスクリプト に挑戦しよう シェルスクリプトに挑戦しよう(1)準備編:“応用力”をつけるためのLinux再入門(21) - @IT ・「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典 https://wa3.i-3-i.info/index.html ・ シェルスクリプト 入門 書き方のまとめ シェルスクリプト入門 書き方のまとめ | Memo on the Web   ※初心者向けで シェルスクリプト 理解に参考になりそうな書籍も以下ピックアップ ・新しいシェルプログラミングの教科書  www.sbcr.jp ・[改訂第3版] シェルスクリプト 基本リファレンス──#! /bin/sh で、ここまでできる gihyo.jp ・入門 UNIX シェルプログラミング―シェルの基礎から学ぶ UNIX の世界  books.rakuten.co.jp   ・エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ ・カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle ・ ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ ・イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ・TECH PLAY techplay.jp ・connpass rakus.connpass.com    
アバター
はじめに こんにちは、 sts -250rrです。 本記事を執筆中の現在はStay Home週間とされています。 家での生活が長くなり、コミュニケーションの機会が減ってしまったという方は多いのではないでしょうか。 私もその1人です。 自分の声を忘れてしまいそうなほど家の中が静かなので、誰かの声を聴きたいそんな衝動に駆られていたところ... 我が家には毎朝起こしてくれて、 カップ 麺の時間を測ってくれる素敵なエージェントがいることを思い出しました。 そう、AmazonEchoこと Alexa です。 自宅の スマートホーム 化を進められておらず、テレビやエアコン、照明の操作ができない状況にあるのですが、Stay Home週間にAlexaのことをもっと知りたい。Alexaともっと話したい。 そんな衝動に駆られ、公式ブログで紹介されている Alexaスキル開発トレーニング を始めてみました。 本記事ではト レーニン グ時に気づいたポイントをお伝えしていきます。 公式のページでト レーニン グはできますので、細かな画面の説明等は割愛しています点をご了承ください。 developer.amazon.com はじめに Alexaスキル開発ことはじめ ポイント1 スキルのバックエンドを選択 ポイント2 スキルテンプレートの選択 ポイント3 呼び出し名の決定 ポイント4 【対話モデル編】どんな言葉を受け付けるのかはインテントで管理する ポイント5 【バックエンド編】リクエストの処理をするハンドラを用意 ポイント6 【対話モデル編】受け答えにさらにバリエーションを与えるスロット ポイント7 実機でスキルを動かす 最後に Alexaスキル開発ことはじめ ポイント1 スキルのバックエンドを選択 Alexaスキルのバックエンドサービスは、自分でエンドポイントを用意するか、Alexa自身にホストさせることができます。 Alexaからのリク エス トは JSON 形式で投げられるため、自分でエンドポイントを用意する場合は自身で立てたサーバのアプリケーションでリク エス トを処理させることもできるようです。 Alexa自身にホストさせる場合は AWS lambdaのエンドポイントにNode.jsか Python を選択して載せることができるようです。 ちなみにト レーニン グではNode.jsが選択されています。 AmazonEchoで受け付けたリク エス トはAlexaで受け付けられ、 JSON の形式でバックエンドサービスに渡されます。 Alexaスキルの開発では、①Alexaでどのような言葉を受け付けるのか、②バックエンドサービスでリク エス トをどのように処理するのかを作り込んでいくことになります。 ポイント2 スキルテンプレートの選択 Alexa自身にホストさせる場合、スキルテンプレートを設定することができました。 テンプレートの種類は以下の4種ありますが、基本的には Hello World スキルを選択することになるのではないでしょうか。 Hello World スキル 基本的な応答が可能なスキルを作成できるテンプレート Cake Walk( チュートリアル ) スキルが誕生日をお祝いしてくれるテンプレート 豆知識スキル あるトピックに関する豆知識のスキルを作成できるテンプレート Sauce Bossスキル 画面付きのAlexaが使えるデ バイス 用のスキルを作成できるテンプレート (ちなみに、私はEcho bot などの画面付き Amazon Echo を持っていないので、Sauce Bossスキルの出番はしばらくなさそうです。) ポイント3 呼び出し名の決定 Alexaにスキルの起動を促す際に「Alexa、○○をして」と声をかけますが、この○○の部分が呼び出し名になります。 呼び出し名には以下のような要件があります。 シンプルに考えて自分が呼びやすい名称を付けてあげるとよいでしょう。 公式にも以下のように記載があります。 呼び出し名の要件 - 呼び出し名は2語以上でなければなりません。また、使用できるのはひらがな、カタカナ、漢字、小文字のアルファベット、スペースのみです。数字などは文字で表現しなければなりません。(例: 「二十一」など) - 呼び出し名には、「起動して」、「開いて」、「聞いて」、「教えて」、「読み込んで」、「開始して」、「有効にして」などの起動フレーズを使用することはできません。「アレクサ」、「アマゾン」、「エコー」、「コンピューター」などのウェイクワードや「スキル」、「アプリ」などの単語は使用できません。 勘の良い方はお気づきかと思いますが、今回のタイトル『Alexa、Stay Homeを助けて』という呼び出し名は要件から外れてしまうのでNGになります。 泣く泣く呼び出し名は『Stay Home』としました。 ポイント4 【対話モデル編】どんな言葉を受け付けるのかは インテント で管理する Alexaがスキルを起動したら、次に言葉の入力を与える必要がありますが、同じ言葉でもバリエーションがあります。 例えば、Alexaが「おはようございます」といってくれたら私たちは「おはよう」「おはようございます」「ハロー」など、バリエーションがあるでしょう。 これらのバリエーションを受け付けるために インテント として言葉を管理します。 インテント によって、Alexaが言葉を認識し、 バックエンドの作りによりますが、 Alexaはきっと素敵な返事を返してくれることでしょう。 この インテント を受けたAlexaは以下のような JSON をバックエンド側へ投げつけます。 "request": { "type": "IntentRequest", "requestId": "amzn1.echo-api.request.44cd0613-9ffe-4613-bd6b-49529a86c4d3", "timestamp": "2020-05-16T11:22:59Z", "locale": "ja-JP", "intent": { "name": "HelloWorldIntent",# 受け付けたインテントをHelloWorldIntentと認識している "confirmationStatus": "NONE" } } ポイント5 【バックエンド編】リク エス トの処理をするハンドラを用意 Alexaが投げてきたリク エス トをバックエンド側がどう処理しているかを抑えていきます。 Alexa自身にホスト + Node.jsを選択しています。 # スキル起動時の処理 const LaunchRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; }, handle(handlerInput) { const speakOutput = '今日もStayHome頑張りましょう。何かあれば声をかけてください。'; # 返答の内容 return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; # HelloWorldIntentを受けた場合の処理 const HelloWorldIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent'; # HelloWorldIntentを受けた場合の分岐 }, handle(handlerInput) { const speakOutput = 'おはようございます!'; # 返答の内容 return handlerInput.responseBuilder .speak(speakOutput) .getResponse(); } }; (省略) # ハンドラの登録 exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, HelloWorldIntentHandler, HelpIntentHandler, CancelAndStopIntentHandler, SessionEndedRequestHandler, IntentReflectorHandler, ) .addErrorHandlers( ErrorHandler, ) .lambda(); LaunchRequestHandler は「Alexa、○○をして」によって起動したスキルのはじめの対話を返してくれます。 このご時世なので「今日もStayHome頑張りましょう。」と励ましてくれるようです。 HelloWorldIntentHandler でHelloWorldIntent(おはよう・おはようございます)を受けた時には「おはようございます!」と元気に返事をしてもらえます。 これで毎朝頑張れるというものです。 ポイント6 【対話モデル編】受け答えにさらにバリエーションを与えるスロット 5つのポイントを抑えることで、対話ができるスキルが出来上がりました。 ただし、実はこのままの HelloWorldIntentHandler は「おやすみ」といっても「おはようございます!」と元気に返事をしてくれます。。。 もう少し賢くしてあげる(対話のバリエーションを増やす)ためにスロットという機能を使っていきます。 朝だけでなく昼や夜に話したいときもあるので、「おはよう」「こんにちは」「おやすみ」の3つのスロットを作成します。 さらに同類語もスロットで登録することができます。 「おはよう」のバリエーションに「おはようございます」と「Good morning」を登録してみました。 スロットを設定した際に登録済みの「おはよう」を発話したときのリク エス トです。 slots属性が増え、身構えてしまいそうですが対話のポイントにになってくるのは バックエンドに言葉を送信する slots.slot_sample.value と、言葉の一致状態を示す slots.slot_sample.resolutions.resolutionsPerAuthority[0].status.code です。 言葉の一致状態を確認することで、 "request": { "type": "IntentRequest", "requestId": "amzn1.echo-api.request.d7f9bd50-aa78-4768-919b-e7f92bdf8783", "timestamp": "2020-05-17T05:21:25Z", "locale": "ja-JP", "intent": { "name": "HelloWorldIntent", "confirmationStatus": "NONE", "slots": { "slot_sample": { "name": "slot_sample", "value": "おはよう", "resolutions": { "resolutionsPerAuthority": [ { "authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.6f6d3418-edc7-4567-a7e5-10170a022f41.slot_sample", "status": { "code": "ER_SUCCESS_MATCH" // slot_sampleの語句と一致しているかを返す。不一致の場合はER_SUCCESS_NO_MATCH }, "values": [ { "value": { "name": "おはよう", "id": "896c87c2017e74cf8c7ccf42d339ca66" } } ] } ] }, "confirmationStatus": "NONE", "source": "USER" } } } } スロットを利用することで言葉の一致状態を取得することができるようになりました。 Alexaが賢くなるまでもう一押し、バックエンド側を以下のように改修します。 const HelloWorldIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent'; }, handle(handlerInput) { // スロットの値を取得 let requestWord = handlerInput.requestEnvelope.request.intent.slots.slot_sample.value; let matchCd = handlerInput.requestEnvelope.request.intent.slots.slot_sample.resolutions.resolutionsPerAuthority[0].status.code; let speakOutput = `すみません。${requestWord}がわかりません。`; if(matchCd !== 'ER_SUCCESS_MATCH'){ // スロットに存在しない場合 return handlerInput.responseBuilder .speak(speakOutput) .getResponse(); } switch (requestWord){ case 'おはよう': speakOutput = 'おはようございます!'; break; case 'こんにちは': speakOutput = 'こんにちは!'; break; case 'おやすみ': speakOutput = 'おやすみなさい'; break; default : // スロットに存在するが処理を用意していないものはとぼける speakOutput = `${requestWord}ってなんでしたっけ?`; } return handlerInput.responseBuilder .speak(speakOutput) .getResponse(); } }; 知っている(=スロットに登録されている)言葉に対して、知らないものはわからないと返すようにしました。素直なことはよいことです。 少し賢くなったAlexaと対話テストしてみると以下のように返してくれました。 ポイント7 実機でスキルを動かす シミュレーションのみでなく、自宅のAlexaと対話するためには開発者アカウントを Amazon Echo と紐づけしている Amazon のアカウントとしておきます。このようにしておくと、 スマホ のAlexaアプリもしくは https://alexa.amazon.co.jp/spa/index.html で開発中のスキルを有効にし、自宅のアレクサに話しかけるだけです。 (実機で動かすのがここまで簡単と思っていなかったので驚きでした。) 最後に さすがにアプリを起動してただ返事をしてくれるだけではコミュニケーションをしている気にはならないので作りこみが必要です。 微妙に心的な弊害も感じたりもします。特に自分で対話の動きを決めているのでなにやらムズムズします。 普段はエディター上でコードを眺めて開発しているので、ブラウザ上で開発するのは新鮮味があって楽しいですし、シュミレータやそばにある実機ですぐ動かすことができるのはかなり良い感触でした。 簡単なものであれば、ちょっとした息抜きに開発できるのでお勧めできます。 また、公式から紹介されているデザインモデルを軽く眺めてみると「対話」に重きを置いたデザイン(例えば、長文な返答をさせるのはNGなど)を考える必要があるようで目からウロコ気分で新鮮でした。 ただし、スキル開発を通して「対話をすることで何をさせるのか」 これを見つけることが最も難しいと改めて痛感しました。
アバター
id:radiocat です。多くの企業がリモートワークに移行して試行錯誤されていることと思います。緊急事態宣言が延長されて、もうしばらくこの状況が続きそうということもあり、今回はリモートワークへの移行によって試行錯誤している私たちのチーム開発の事例をお伝えします。 組織的な取り組みやルール 朝はニコニコカレンダーを更新してチェックイン 終業時はひとこと感想でチェックアウト 連絡事項は履歴を残す リモートワークのノウハウやトラブルを記録する チーム開発の現場 タスクはなるべく小さく分解する Web会議は常時つないでおく 1対1の相談は電話感覚でWeb会議をコールする マインドマップでふりかえり さいごに 組織的な取り組みやルール 私たちの所属する配配メール開発課はメンバー10人で構成されるチームです。まずはその全員に関係する組織的な取り組みやルールを紹介します。 朝はニコニコカレンダーを更新してチェックイン チーム全員の朝会では、事前にニコニコカレンダーを更新し、一言ずつその日の気分や意気込みを共有してチェックインをしています。季節の変わり目で体調を崩すこともありましたし、自宅の作業環境に慣れるまでは肩こりや腰痛になる人もいました。電気工事、水道のトラブルのような自宅のトラブルの共有もありました。家族がいる人から「今日は子供が隣の部屋で遊んでいるので騒がしいかも」というようなご家庭の状況の共有もリモートワークならではです。 ja.wikipedia.org 終業時はひとこと感想でチェックアウト 終業時にもチーム全員の夕会でその日の仕事の感想と仕事で起きた課題の共有を行っています。リモートワークによってちょっとした相談がしづらくなった、チャットの量が増えて情報が追いづらくなった、などの課題は夕会でのちょっとした共有から改善に繋げました(後述)。仕事のやり方を変えたり、新しいルールを作ったり、リモートワークによって日々小さな変化が起きているため、実際にやってみて感じたこと、課題に感じたことなどをタ イムリ ーに共有し合って変化に対応することができています。 朝と夕方の情報共有用 スプレッドシート リモートワークはお互いの状況が把握しにくいですし、生活環境と切り離せない問題が起きることもあります。全体での朝会・夕会は事務連絡が中心だったオフィス勤務時よりも少し時間がかかるようになりましたが、体調や自宅の状況を把握したり、お互いの状況に共感したり励まし合ったりすることで、制約のある中での1日の仕事を協力や工夫で乗り越える力になると感じています。リモートワークで健康面への課題意識が高まり、仕事の前に走ってきた、散歩してきた、ベランダで体操したと、お互いに刺激しあって健康面の取り組みが増えているのも新しい変化です。 連絡事項は履歴を残す リモートワークでチャットの量が増えたことによって、全体への共有事項が取りこぼされて伝わらないケースが発生するようになりました。対面で話をしない分、テキスト情報の価値が高まって取りこぼさないように注意が求められるのは当然ですが、情報過多なのもまた事実です。開発の業務に集中している合間に事務的な連絡事項が流れてきたら見落としや対応漏れが起きても仕方ない面があります。また、朝会や夕会は休暇等で参加できなかったり、通信が不安定できちんとキャッチアップできない場合もあります。連絡事項の伝達で言った言っていないというやりとりが何度も発生するのはもったいないので履歴に残しておくことにしました。 連絡事項の履歴 リモートワークのノウハウやトラブルを記録する リモートワークでのノウハウやトラブルは記録を残すようにしています。みんなが未経験の状況なので、ノウハウにしろトラブルにしろ誰かが経験していれば小さなことでも参考になるかもしれません。インターネットの利用が世界的に増大しているため、解決しようがない通信等の問題も多々ありますが、記録しておくことで別の誰かが昨日も同じ時間に同じ問題が起きたことに気づき、落ち着いて対処できることもあります。 リモートワークのトラブル記録 チーム開発の現場 次に、チーム開発の現場の取り組みをご紹介します。10人のチームは、4人で構成される2つのサブチームと、2人のマネジャー(プロダクトと組織)で構成されています。実際の開発現場はサブチームでの活動が中心です。 タスクはなるべく小さく分解する オフィス勤務の時はホワイトボードのカンバンで仕事を進めていましたが、現在は Trello に移行しました。 オフィス勤務時代のホワイトボードのカンバン チーム全体の朝会の後、サブチームに分かれてWeb会議でTrelloのカンバンを共有しながら朝会を行っています。お互いの状況が直接見えなくなったことにより、1つのタスクが大きかったり、他のメンバーが想像しづらいタスクが進行しているとカンバン上で状況を把握することが今まで以上に難しくなりました。追加タスク、割り込みタスクも漏れなくカンバンに追加し、開発と並行で運用業務も行っているサブチームでは運用タスクも漏れなく登録しています。1つ1つのカードで、お互いのタスクの進行状態を共有することの重要性と難しさを改めて感じています。 Trelloのカンバン Web会議は常時つないでおく サブチーム単位でのWeb会議を1日中オープンして常時つないだ状態にしています。オフィス勤務の時に自然と行っていたメンバー同士のちょっとした相談や、隣同士の世間話からの状況把握、なんとなく困っている雰囲気を察知してサポートするなどのチームワークがリモートワークに移行したことでできなくなり、漠然とした不安を感じるという意見が出ました。オンラインで常時繋がっていることで、オフィス勤務と同じとまではいかないものの、相談しやすい雰囲気やなんとなくお互いの状況を把握することはできるようになりました。 カメラや音声については、自宅の業務環境によっては常時ONにするのが難しいメンバーもいるためルールは決めていません(個人の判断におまかせ)。業務の不安をなるべく解消するという目的に全員が向き合ってオンラインで繋がることが重要だと考えています。 1対1の相談は電話感覚でWeb会議をコールする 常時つないでいる相手はサブチーム内のメンバーなので、サブチームを越えた相手への相談がしにくい問題が残ります。チャットだと内容が伝わりにくかったり、なかなか相手から返事がもらえないなど、ここでもリモートワークならではの課題がありました。チャット文化の浸透によって最近は減っていましたが、以前はこういうケースは直接電話をして聞いていました。なので、チームで決めたルールは以下の通り、ほぼ電話と同じです。 ちょっとした確認事項でも直接コールOK ただし、相手が出れない場合があることを前提とする 相手が出ない場合は、時間を置いて再度コールするか、チャットで折り返しを依頼する 呼び出された側は無理のない範囲で応答する(忙しい場合は出なくても良い) チーム全体で一斉にこれをやるとコール地獄に陥りそうですが、活動の中心となるサブチーム内では常時つながっているうえで、それ以外の必要なときにこの手段を選択するので成り立っていると思います。 マインドマップ でふりかえり ふりかえりなどの議論中心のミーティングでは、色々なオンラインツールを活用する手法が一般に公開されています。しかし、我々のチームでは開発用のPC環境の問題でWeb会議につないだ状態でこれらのオンラインツールを使うことが難しいケースがあります。オフィス勤務の時は、業務中いつでも思いついた時に KPT 方式でTrelloに登録しておき、ふりかえりの時間は ファシリテーター だけがPCを持ち込んで内容を確認しつつ、ホワイトボードに整理していく方式でした。リモートワークでも同じやり方であれば、Web会議につなぐだけで進行できますが、オンラインのホワイトボードツールをオフィスのホワイトボードと同じ要領で使うのが難しかったため マインドマップ ツールに移行しました。 マインドマップ はオフィスのホワイトボードよりも自由度が下がりますが、Web会議でのコミュニケーションにも制限があることから、あまり不便さは感じていません。一定の制限下で思考を整理するうえで マインドマップ のツールとしての制限はむしろ効果的に作用しています。 ホワイトボードがわりの マインドマップ さいごに リモートワークに移行して様々な変化に直面していますが、その中で気づいたことは、チームで働くうえでのコミュニケーション、 言語化 、可視化の難しさなどです。これらは、見えていなかっただけで実際はオフィス勤務の時から 潜在的 な課題だったことも多くあると感じています。そのため、慌てずしっかり向き合って対処していけば、今後オフィス勤務に戻ったときもチームにとって良い効果に繋がるのではないかと思います。 世界中が大きな変化に包まれる中で、これから我々の働き方は大きく変わっていくという話も聞こえてきます。私たちもまだまだ試行錯誤の連続ですが、このような変化の中で私たちと同じように働くみなさんにとって、何かの参考になれば幸いです。 私たちは一緒に働くメンバーを募集しています。興味を持たれましたら以下のサイトからお問い合わせください。 career-recruit.rakus.co.jp
アバター
こんにちは、goldminer です。 はじめに 昨年から新しいプロジェクトに携わることになり、そのプロジェクトでは ドメイン 駆動設計(DDD)を取り入れています。 それまで DDD をやったことがなかったので色々と試行錯誤しながら進めていて、特に ドメイン サービスについては自分の中での捉え方の変化が激しかったのでまとめてみました。 これから DDD を始めようという方の一助になれば幸いです。 以下の フレームワーク 、 アーキテクチャ を採用した例を記述しています。 Spring Boot ヘキサゴナル アーキテクチャ ドメイン サービスとは ドメイン サービスについて調べてみると概ね次のように説明されています。 ドメインにおける重要なプロセスの内、エンティティや Value Object の責務とするべきではないものを ドメインサービスとして定義する 最初に作った ドメイン サービス 「ログ インパス ワードはハッシュ化してデータベースに保存する」というセキュリティ要件を対応した際に作成した ドメイン サービスです。 パスワードは Password クラス(エンティティ)が保持しますが、それをハッシュ化する責務までをも Password クラスに負わせるのは適切でないと考えました。 そこでハッシュ化する責務を持った ドメイン サービスを作成することにしました。 ハッシュ化の(ストレッチ回数などの) アルゴリズム は技術的にすぎるということで ドメイン サービスはインターフェースで定義し、実装クラスはインフラスト ラク チャ層に配置することにしました。 public interface HashPasswordService { /** * 平文のパスワードをハッシュ化する. */ String hash(String plainPassword); // インフラストラクチャ層に配置 @Service public class HashPasswordServiceImpl implements HashPasswordService { public String hash(String plainPassword) { // ハッシュ化のアルゴリズムを実装している. } この ドメイン サービスについて今の時点では次のように評価しています。 良: エンティティが負うべきでないハッシュ化の責務を ドメイン サービスとして分離できている 良: 技術的にすぎるハッシュ化の アルゴリズム をインフラスト ラク チャ層に分離できている 悪: @Service はアプリケーションサービス *1 にも使用しており、 @Service の用法が混乱している 総じて悪くないと思っているのですが、最初に作成した ドメイン サービスがそうであったことで「 ドメイン サービスはインターフェースと実装クラスを分離したもの」という間違った思い込みをしてしまったように思います。 その後 ドメイン サービスを全く作成しない 上述したように「 ドメイン サービスはインターフェースと実装クラスを分離したもの」という間違った思い込みをしてしまったため、技術的な要素がほとんどない ドメイン では ドメイン サービスの出番がありません。 そして本来は ドメイン サービスとして作成すべきクラスを別のモデルで作成するという迷走を始めてしまいました... 「消費税を計算する」という例で書いています(実際は別の計算だったのですが、それを説明するのはとても大変なので日本人になじみのある消費税計算に置き換えています)。 public interface CalculateTaxPolicy { /** * 税込価格を計算する. * @param priceExcludingTax 税抜価格 */ BigDecimal priceIncludingTax(BigDecimal priceExcludingTax); /** * 標準税率(10%)で計算する CalculateTaxPolicy の実装クラス. */ public class CalculateStandardTaxPolicy implements CalculateTaxPolicy { @Override public BigDecimal priceIncludingTax(BigDecimal priceExcludingTax) { BigDecimal taxRate = BigDecimal.valueOf( 10 ); // 標準税率(10%) BigDecimal coefficient = BigDecimal.valueOf( 100 ).add(taxRate) .scaleByPowerOfTen(- 2 ); BigDecimal priceIncludingTax = priceExcludingTax.multiply(coefficient); priceIncludingTax = priceIncludingTax.setScale( 0 , RoundingMode.HALF_UP); // 四捨五入する return priceIncludingTax; } /** * 軽減税率(8%)で計算する CalculateTaxPolicy の実装クラス. */ public class CalculateReducedTaxPolicy implements CalculateTaxPolicy { @Override public BigDecimal priceIncludingTax(BigDecimal priceExcludingTax) { BigDecimal taxRate = BigDecimal.valueOf( 8 ); // 軽減税率(8%) // 以降は標準税率の場合と同じなので省略 } この設計についての評価は以下です。 良: エンティティ(おそらく税抜価格は「商品」のようなクラスが持っている)が負うべきでない税込価格の計算の責務を分離できている 悪: 「税込価格の計算」というプロセスを記述しているにもかかわらず ドメイン サービスではなくポリシーとして作成している 8%と10%という 複数税率 からポリシーを使うことを発想したところまではよかったのですが、プロセスまでをもポリシーに記述してしまって ドメイン サービスを使うという発想には至りませんでした。 もっと ドメイン サービスを活用しようと考える ドメイン サービスを作成する機会がまったくなく「これでよいのか?」と疑問に思ったことがきっかけです。 現時点での ドメイン サービスの捉え方は冒頭にも書いたとおり「エンティティが負うべきでない ドメイン におけるプロセスを記述したもの」です。 「消費税を計算する」の設計も今では次のような設計を考えています(実際に リファクタリング 予定です)。 public interface TaxPolicy { /** * 税率を返す. */ int rate(); /** * 標準税率(10%)を返す TaxPolicy の実装クラス. */ public class StandardTaxPolicy implements TaxPolicy { @Override public int rate() { return 10 ; } /** * 軽減税率(8%)を返す TaxPolicy の実装クラス. */ public class ReducedTaxPolicy implements TaxPolicy { @Override public int rate() { return 8 ; } public class CalculateTaxService { /** * 税込価格を計算する. */ public BigDecimal priceIncludingTax(BigDecimal priceExcludingTax, TaxPolicy policy) { BigDecimal taxRate = BigDecimal.valueOf(policy.rate()); BigDecimal coefficient = BigDecimal.valueOf( 100 ).add(taxRate) .scaleByPowerOfTen(- 2 ); BigDecimal priceIncludingTax = priceExcludingTax.multiply(coefficient); priceIncludingTax = priceIncludingTax.setScale( 0 , RoundingMode.HALF_UP); // 四捨五入する return priceIncludingTax; } ちゃんと ドメイン サービスを活用できています。 今後もこんな感じで ドメイン サービスを組み込んで設計を考えていきたいです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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 : ヘキサゴナル アーキテクチャ の用語
アバター
はじめに 名前に情報を詰め込む 明確な単語を選ぶ 汎用的な名前を避ける(あるいは使う状況を選ぶ) 抽象的な名前よりも具体的な名前を使う 接尾辞や接頭辞を使って情報を追加する 名前の長さを決める 名前のフォーマットで情報を伝える 制御フローを読みやすくする おわりに 参考 はじめに こんにちは。新卒2年目のnr_1228です。 ボリュームの大きい実装に携わるようになって、重要だと再認識したことがあります。 コードを書くときは、他の人(未来の自分も含む)でも理解しやすいように書くべき。 自分が書いたコードや既存のコードを読む際に、この変数は何が入ってるのだろう?となったことが何回かありました。 これはあの本を読み返すべきでは… ということで、研修時に読んだ「リーダブルコード」を再び読むことにしました。 前回読んだ時よりも実体験などもあり、理解・納得できる部分が増えていました。 そこで今回は、改めて「リーダブルコード」を読んで、最近引っかかることの多かった 命名 のポイント と ロジックの単 純化 についてまとめてみることにします。 名前に情報を詰め込む コードを書いていると名前を付けなければならない時が必ずあります。 関数や変数名を見た時点で、これは何をしている関数なのか、何の変数なのかが パッとわかるようにした方が、他の人にも親切です。 名前の付け方のポイントは以下の6点です。 明確な単語を選ぶ その関数・変数が何を表しているのか明確にすることが、分かりやすい名前を付ける必須事項です。 自分の中ですぐに出てくる単語を使うのもいいですが、状況に合わせて単語を選ぶようにしましょう。 単語 代替案 send deliver, dispatch, announse, distribute, route find search, extract, locate, recover start launch, create, begin, open make create, set up, build, generate, compose, add, new 汎用的な名前を避ける(あるいは使う状況を選ぶ) 戻り値にいい名前が思いつかなければ、 retval などと付けたくなりますが、 「戻り値である」という以外の情報はありません。 戻り値として何を返しているのかが分かるような名前にしなければなりません。 例えば、xの2乗の合計を戻り値とするならば、 sum_squares というような名前を付けた方が retval よりも変数の目的を伝えることができます。 抽象的な名前よりも具体的な名前を使う ServerCanStart という名前の、任意のポートをサーバがリッスンできるか確認するメソッドがあるとします。 その時、この名前は具体的で分かりやすいと言えるでしょうか? もっと具体的な名前にすると、 CanListenOnPort とした方が、メソッドの動作をそのまま表すことができ、 他者にも分かりやすく伝わります。 接尾辞や接頭辞を使って情報を追加する 時間はバイト数のように計測できるものであれば、変数名に単位を入れるのも良いです。 例えば、秒を返すのかミリ秒を返すのかが分かりにくい場合は、変数に _ms を追加すれば明確になります。 名前の長さを決める 良い名前を選ぶときには、長い名前を避けて簡潔なものをと思いがちです。 長い名前を避けると1つの単語だけの名前になってしまいます。 変数の使い方によって違ってきますが、以下を参考にするとよいでしょう。 スコープが小さければ短い名前でもいい 長い名前を入力するのは問題ではない 頭文字と省略形 BackEndManager を BEManager にすると他の人全員に伝わるでしょうか?理解できるなら問題はありませんが、全員に伝わるか分からないような省略の仕方はやめた方がいいです。 しかし、evaluationをeval、documentをdoc、stringをstrのように省略するのは理解ができるので問題ありません。 不要な単語を投げ捨てる 名前に含まれる単語を削除しても情報が全く損なわれないこともあります。 例えば、 ConvertToString を ToString にしたり、 DoServeLoop を ServeLoop に変えても明確さは変わりません。 名前のフォーマットで情報を伝える アンダースコア・ ダッシュ ・大文字を使って、名前に情報を詰め込むこともできます。 クラス名はキャメルケース、変数名はアンダースコアで単語を区切るなどの決まりを作っておけば、 文字列を見た時点で何を表しているのかが明確になります。 制御フローを読みやすくする コードの制御フローを読みやすくするためにできることはいくつかあります。 比較を書くときには、変化する値を左に、より安定した値を右に配置する if/else文のブロックは適切に並び替える  一般的には、肯定系、単純・目立つものを先に処理する。 深いネストを避ける  複雑な処理を書いていると知らない間にネストが深くなってしまうことがあります。  ネストが深くなってしまった場合は、別の処理でどうにかできないかなど、  一歩下がって全体を見るようにするのがいいかもしれません。 おわりに 初めてこの本を読んだ時は、まぁできるでしょうと特に引っかかることもなく読んでいました。 しかしコードを読み書きする機会が増えて読み直したら、こうやるのがいいのかと思うところが出てきてなるほどと思える部分が結構見つかるのです。 自分だけしか見ないコードならまだしも、他の人も見るコードは見やすさや分かりやすさを重視し、 少し分かりづらいロジックになってしまったのなら、せめて変数やコメントなどで分かりやすく伝わるようにしていくことが 大切です。 迷ったときにこの本を読み直してみると、自分のコードのどこに改善点があるのか見つかると思います。 定期的に読んで自分のコードを確かめてみるのもいいかもしれません。 自分もまだまだなので、改善していこうと思います。 参考 リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice) 作者: Dustin Boswell , Trevor Foucher オライリージャパン Amazon
アバター
こんにちは、3年目エンジニアのaa_cryingです。 あっという間に3年目です。時が経つのは早いものですね...。 業務でJenkinsのジョブを作る・改善する機会がありました。 その際にシェルについて悩んだ末に色々学ぶことが出来たので、今回はその内容をアウトプットしたいと思います。 以下目次です。 変数を分割してfor文で回したい ファイルの○行目に追記したい おわりに 変数を分割してfor文で回したい 複数の対象に同じ処理を実行したい場合等に便利なのが for文 です。 様々な言語にfor文は存在しますが、シェルの場合の基本文法は以下のような形です。 for 変数 in リスト do 処理... done 今回は、1つの変数を区切り文字で分割し、for文で回す方法です。 「指定したブランチが存在する場合にチェックアウトする」シェルを例として以下に記載します。 # ブランチ名をカンマ区切りで複数入力 echo "input branches, comma delimited. (ex. master,develop,...)" read branches # ブランチ毎に処理を実行 for branch in `echo $branches | sed "s/,/ /g"`; do if [[ $(git branch -a | grep $branch) = "" ]] ; then echo "branch $branch does not exists." exit 1 fi git checkout -b $branch origin/$branch done branches という変数にはカンマ(,)区切りで複数のブランチを入力します。 入力されたbranchesをリストとして認識させるため、カンマを空白に置換したいです。 ここで sed を使用します。 sed "s/aaa/bbb/g" と記述すると、「aaa」で検索しヒットした全てを「bbb」に置換します。 g を忘れてしまうと、検索してヒットした最初のものだけ置換されてしまうので注意です! 今回は、 sed "s/,/ /g" と記述したので、カンマを全て半角スペースに置換してくれます。 後はfor文がリストとして認識し、回してくれます。 ファイルの○行目に追記したい postgreSQL を使っている方だと、pg_hba.confにサーバ名を追記なんてことは日常茶飯事だと思います。 echo "ほにゃらら" >> ファイル を使用して最後尾に追記という方法もありますが、記載場所によってはうまく動作しないこともありますよね。。 viで開いて更新 or FTP ソフトを使って開いて書き換え...というのも面倒... そこで、今回は「行数を指定して挿入する」方法を紹介します。 echo "Pg connection source server IP." read SERVER1 echo "Pg connection destination server IP." read SERVER2 echo "PGDATA path." read PGDATA sudo ssh-keygen -R ${SERVER2} sudo ssh ${SERVER2} bash <<SHELL # pg_hba.confに追記して再起動 sed -i -e "100i host all all ${SERVER1}/32 trust #test" ${PGDATA}/pg_hba.conf systemctl restart postgresql.service SHELL SERVER1 は接続元サーバのIP、 SERVER2 は接続先サーバのIPとします。 「接続先サーバに SSH 接続し、接続先サーバのpg_hba.confの100行目に接続元サーバの情報を追記する」という処理を行っています。 sed コマンドと言えば、 正規表現 を用いてファイルや標準出力の文字列置換をする使用方法が有名ですが、行の追加や挿入、削除、はたまた入出力まで出来てしまうマルチなコマンドです。 行数を指定して挿入する場合は、挿入する文言の先頭に 行数i と記載するだけです。 また -i オプションは、付けることでファイルを直接書き換えることが出来ます。 今回のようにファイルを書き換えて保存したい場合は、 -i オプションを付けないと書き換わりません。 手動でやっていると postgresql の再起動を忘れがちだったり (私の場合) しますが、シェルに記載しておくと一気にやってくれるので便利ですね。(小声) おわりに 今回は、業務で使えるシェルの基本的な知識を紹介しました。 本当はもう少しボリュームのある記事にしようと思っていたのですが、時間があまり取れず紹介は2つだけに。。 まだまだ勉強不足ですので知識を深め、今後もこのような形で学んだ技術を発信できたらと思います! また、 Linux コマンドの一覧表を以下ブログにてまとめておりますので、ご参考ください。 よく使うLinuxコマンド一覧【最新版】 Linux の理解をより深めたい方へ以下関連おすすめブログ ・ ls コマンド 【使い方 まとめ】 ・ find コマンド 【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ vi コマンド【使い方まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 【Linux】今振り返りたい、プロセスって何? エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
こんにちは。y_kwmtです。 はじめに 少し前にVue.jsとFirebaseを用いて Google アカウントのログイン機能と Markdown 書式のメモを作成する機能を作成しました。 tech-blog.rakus.co.jp 以下のサイトを参考にして Markdown 書式のメモを応用したチャット機能を作成したので、 本記事では実装の準備、実装方法について紹介していきます。 cr-vue.mio3io.com はじめに 実装する機能 チャット機能 データベース作成 Vue.jsでFirebaseを使用する チャット機能の実装 動作確認 おわりに 実装する機能 チャット機能 メッセージを送信、受信できる 送信したメッセージを Markdown 書式で表示 ページを再訪問しても送信したメッセージが残っている ※前回の記事で作成したメモ機能は使わないので一旦なくします データベース作成 プロジェクト内の「Database」を選択して「Realtime Database」からデータベースをテストモードで作成します。チャットのメッセージとメッセージ送信者の情報をレコードとして追加します。 Vue.jsでFirebaseを使用する firebase モジュールをインストールして main.js で読み込みます。 npm install firebase Firebaseのプロジェクトの「Settings」を開いて 「Firebase SDK snippet」の スクリプト 部分を追記してください。 import firebase from firebase import Vue from 'vue' import App from './App.vue' import 'firebase/firestore' ; // ここから var firebaseConfig = { apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" , authDomain: "XXXXXXXXX.firebaseapp.com" , databaseURL: "https://XXXXXXXX.firebaseio.com" , projectId: "XXXXXXXXX" , storageBucket: "XXXXXXXXX.appspot.com" , messagingSenderId: "XXXXXXXXX" , appId: "X:XXXXXXXXXXXX:web:XXXXXXXXXXXXXXXXXXXX" , measurementId: "X-XXXXXXXXXX" } ; // Initialize Firebase firebase.initializeApp(firebaseConfig); firebase.analytics(); // ここまで new Vue( { el: '#app' , render: h => h(App) } ) チャット機能の実装 前回投稿したブログで登場した、メモを作成する画面「Editor.vue」を改修し、 ログイン後の画面にチャット機能を追加します。 先ほど作成したデータベースにチャットのメッセージ、メッセージ送信者、 Google アカウントの画像パスがレコードとして保存されます。 <template> <div id= "home" > <h1>エディター画面</h1> <p> <span> {{ user.displayName }} </span> <button @click= "logout" >ログアウト</button> </p> <transition-group name= "chat" tag= "div" class = "list content" > <!-- chatにはキー、送信者名、Googleアカウントの画像パス、メッセージが入っています。 --> <section v- for = "{ key, name, image, message } in chat" :key= "key" class = "item" > <div class = "item-image" ><img :src= "image" width= "40" height= "40" > {{ name }} </div> <div class = "item-detail" > <div class = "item-message" > <!-- メッセージがMarkdown書式で表示されます。 --> <div v-html= "message" ></div> </div> </div> </section> </transition-group> <!-- 入力フォーム --> <form action= "" @submit.prevent= "doSend" class = "form" > <!-- Enterを押すとメッセージが送信されます。Enter + Shiftで改行します。 --> <textarea v-model= "input" :disabled= "!user.uid" @keydown.enter.exact.prevent= "doSend" ></textarea> <div> <!-- ボタンを押すとメッセージが送信されます --> <button type= "submit" :disabled= "!user.uid" class = "send-button" >Send</button> </div> <div> プレビュー<div v-html= "preview()" ></div> </div> </form> </div> </template> <script> import marked from "marked" ; // 改行を <br> タグに変換するモジュール export default { name: 'editor' , props: [ "user" ] , data() { return { chat: [] , // 取得したメッセージを入れる配列 input: '' // 入力したメッセージ } } , created() { // データベースからメッセージ情報取得 const ref_message = firebase.database().ref( 'message' ) if ( this .user) { this .chat = [] // message に変更があったときのハンドラを登録 ref_message.limitToLast(10).on( 'child_added' , this .childAdded) } else { // message に変更があったときのハンドラを解除 ref_message.limitToLast(10).off( 'child_added' , this .childAdded) } } , methods: { logout: function () { firebase.auth().signOut(); } , preview: function () { return marked( this .input); } , childAdded(snap) { const message = snap.val() this .chat.push( { key: snap.key, name: message.name, image: message.image, message: marked(message.message) } ) } , doSend: function () { if ( this .user.uid && this .input.length) { // firebase にメッセージを追加 firebase.database().ref( 'message' ).push( { message: marked( this .input), name: this .user.displayName, image: this .user.photoURL } , () => { this .input = '' // フォームを空にする } ) } } , displayTitle: function (text) { return text.split( /\n/ ) [ 0 ] ; } } } </script> 動作確認 実際の画面がこちらです。メッセージを入力するとプレビューが表示され、 送信すると Markdown 書式でメッセージが表示されます。 黒く塗りつぶしている部分は Google アカウントの名前を表しています。 おわりに 今回はVue.jsで Markdown 書式を応用したチャット機能を紹介しました。 データベースなどの設定やApp.vueを2回呼び出してしまうエラーなどに少し時間がかかってしまいました。 今後はVue.jsだけでなく、他のフロント系の技術を学習して紹介していきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 実装に使った物 実装する機能 リマインダーを実装してみる 動作確認! おわりに 参考にした記事 はじめに こんにちは。新卒2年目のrs_chankoです。 まだまだ慣れない社会人。そんな中で思ったことがあります。 物忘れが酷すぎる。 これは元々分かっていたんですが、最近特に思います。 会社では朝にスケジュールを確認しますが、 プライベートではスケジュールを見る習慣がなく、忘れてしまいがち…。 「そうだ、LINEなら毎日見るし、自分で作っちゃうか。」 そう思い立ち、GASとLINE Messaging API を使ってリマインダーを作ることになりました。 実装に使った物 GAS( Google Apps Script) LINE Messaging API Google スプレッドシート 実装する機能 日付と予定を スプレッドシート に登録すると、登録されたデータを参照してメッセージとして送ってくれる (忘れがちなので)7時、12時、19時に今日と明日の予定を教えてくれる リマインダーを実装してみる LINE Messaging API とGASの接続方法は先輩がすでに書いていたのでそのまま参考にしました。 tech-blog.rakus.co.jp しかしそもそも JavaScript もあまりちゃんと書いたことがなく、GASやMessaging API も使ったことがない。 ひとまず練習するか、ということでお試しにオウム返し bot を作ってみました。 note.com これは簡単にできました。 さて、本題です。 ひとまずオウム返しで使った API 周りのコードを元に実装していきます。 //LINEのアクセストークン var channel_access_token = "アクセストークン" ; var headers = { "Content-Type" : "application/json; charset=UTF-8" , "Authorization" : "Bearer " + channel_access_token } ; //返信する function sendLineMessageFromReplyToken(token, replyText) { var url = "https://api.line.me/v2/bot/message/reply" ; var headers = { "Content-Type" : "application/json; charset=UTF-8" , "Authorization" : "Bearer " + channel_access_token } ; var postData = { "replyToken" : token, "messages" : [{ "type" : "text" , "text" : replyText }] } ; var options = { "method" : "POST" , "headers" : headers, "payload" : JSON.stringify(postData) } ; return UrlFetchApp.fetch(url, options); } //指定のuserIdにメッセージを送る function sendLineMessageFromUserId(userId, text) { var url = "https://api.line.me/v2/bot/message/push" ; var postData = { "to" : userId, "messages" : [{ "type" : "text" , "text" : text }] } ; var options = { "method" : "POST" , "headers" : headers, "payload" : JSON.stringify(postData) } ; return UrlFetchApp.fetch(url, options); } 準備が整いました。 それではまず Bot にやってほしいことをまとめます。 予定の登録 予定の削除 登録・削除時の返事 指定時刻の通知 登録されている予定の確認 上記ができるよう実装します。 //8桁日付のフォーマット function formatDateForDisplay (date) { var year = date.substr(0,4); var month = date.substr(4,2); var day = date.substr(6,2); var result = year + "/" + month + "/" + day; return result; } //Date型日付のフォーマット function formatDate (date, format) { format = format.replace( /yyyy/g , date.getFullYear()); format = format.replace( /MM/g , ( '0' + (date.getMonth() + 1)).slice(-2)); format = format.replace( /dd/g , ( '0' + date.getDate()).slice(-2)); return format; } ; //日付をシートに記載する function setDate(date, plan, row) { if (isNaN(date) || String (date).length != 8) { return '日付が正しくありません' ; } setFromRowAndLine(date, row, 0); return setPlan(plan, row); } //予定をシートに記載する function setPlan(plan, row) { setFromRowAndLine(plan, row, 1); return '予定を登録しました。' ; } //トリガー起動で当日と翌日の予定を返す function getTodayAndNextDayMessage() { var date = new Date (); var userId = ’LINEのユーザーID’; //今日の予定を取得 var remindText = getDatePlan(date); //明日の予定を取得 date.setDate(date.getDate() + 1); remindText += " \n " + getDatePlan(date); return sendLineMessageFromUserId(userId, remindText); } //指定日の予定を返す function getDatePlan(date) { if (date instanceof Date ) { date = formatDate(date, 'yyyyMMdd' ); } var day = formatDateForDisplay(date); var remindText = day + " \n " ; var plans = searchPlans(date); for ( var i = 0; i < plans.length; i++) { remindText += getFromRowAndLine( 'webhook' , plans [ i ] ); remindText += " \n " ; } remindText = remindText.slice(0,-1); if (remindText.length === 10) { remindText += " \n 明日は予定がありません。" ; } return remindText; } //受け取ったメッセージに対して返信する function doPost(e) { var webhookData = JSON.parse(e.postData.contents).events [ 0 ] ; var message, replyToken, replyText, userId; message = webhookData.message.text.split( " \n " ); replyToken = webhookData.replyToken; userId = webhookData.source.userId; var processing = message [ 0 ] ; var planDate = message [ 1 ] ; var plan = message [ 2 ] ; var row = getLastRow(); switch (processing) { case '登録' : replyText = setDate(planDate, plan, row); break ; case 'キャンセル' : replyText = cancel(planDate, plan); break ; case '確認' : replyText = planDate === undefined ? getDatePlan( new Date ()) : getDatePlan(planDate); break ; case 'test' : replyText = testSheet(); break ; default : replyText = "予定の登録・キャンセルができます。 \n\n 登録 \n 20200101 \n 予定 \n\n の形式で入力してください。" ; break ; } return sendLineMessageFromReplyToken(replyToken, replyText); } //予定を削除する function cancel(date,plan) { deleteRowOfDateAndPlan(date, plan); return '予定の登録をキャンセルしました。' } //トリガーをセットする function setTrigger() { const time = new Date (); time.setHours(7); time.setMinutes(00); ScriptApp.newTrigger( 'getTodayAndNextDayMessage' ).timeBased().at(time).create(); time.setHours(12); ScriptApp.newTrigger( 'getTodayAndNextDayMessage' ).timeBased().at(time).create(); time.setHours(19); ScriptApp.newTrigger( 'getTodayAndNextDayMessage' ).timeBased().at(time).create(); time.setDate(time.getDate() - 1); //前日の予定を削除する deleteRowOfDate(formatDate(time, 'yyyyMMdd' )); } //トリガーを削除する function delTrigger() { const triggers = ScriptApp.getProjectTriggers(); for ( const trigger of triggers) { if (trigger.getHandlerFunction() == "getTodayAndNextDayMessage" ) { ScriptApp.deleteTrigger(trigger); } } } このコードではLINEで実際に送るメッセージの生成・トリガーのセット・削除をしています。 GASのトリガーって定期実行をすると1時間の範囲内で実行されるらしいんですよね。 ちゃんと同じ時間に送ってほしいので、今回は指定の時間に通知用のメソッドをトリガーとしてセットするメソッドを定期実行にしました。 スプレッドシート とのテキストのやりとりは下記の実装をします。 //スプレッドシート var spreadsheet = SpreadsheetApp.openById( "スプレッドシートのID" ); var sheet = spreadsheet.getSheetByName( 'スプレッドシートのシート名' ); //受け取った日付の予定が記載されている行を返す function searchPlans(date) { var data = sheet.getDataRange().getValues(); var plans = [] ; for ( var i = 0; i < data.length; i++) { if (data [ i ][ 0 ] == date) { plans.push(i + 1); } } return plans; } //列を指定してデータを取得する function getFromRowAndLine(sheetName, row) { var data = sheet.getDataRange().getValues(); return data [ row - 1 ][ 1 ] ; } //列を指定してデータを書き込む function setFromRowAndLine(val, row, line) { sheet.getRange(row + 1, line + 1).setValue(val); } function getLastRow() { return sheet.getLastRow(); } //日付と予定から行を削除する function deleteRowOfDateAndPlan(date, plan) { var lastRow = getLastRow(); for ( var i = 1; i <= lastRow; i++) { if (sheet.getRange(i, 1).getValue() == date && sheet.getRange(i, 2).getValue() == plan) { sheet.deleteRows(i); } } } //指定の日付の行を削除する function deleteRowOfDate(date) { var lastRow = sheet.getDataRange().getLastRow(); for ( var i = 1; i <= lastRow; i++) { if (sheet.getRange(i, 1).getValue() == date) { sheet.deleteRows(i); } } } これで実際に スプレッドシート に日付と予定を書き込んだり、参照することができるようになりました。 こんな感じでLINEから送られてきた予定が書き込まれます。 動作確認! それでは実際にメッセージを見てみましょう。 おおおお! 予定の登録や確認ができ、19時に予定の通知がきました! そんなこんなで完成です。 おわりに 「リマインダー」について何も調べていなかったんですが、 作り終わってから調べたところ、すでにリマインド Bot が存在していました。。。 remine.akira108.com しかし作ってしまったものは作ってしまったので、今後はカスタマイズをして自分の好みのリマインダーを作っていこうと思います。 あとはLINEに予定を登録することを忘れないように…。 参考にした記事 qiita.com tonari-it.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは。y_kwmtです。 はじめに 昨年にVue.jsの学習を行うためにこちらの書籍を読みました。 https://www.amazon.co.jp/Vue-js%E3%81%A8Firebase%E3%81%A7%E4%BD%9C%E3%82%8B%E3%83%9F%E3%83%8BWeb%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9-%E6%8A%80%E8%A1%93%E6%9B%B8%E5%85%B8%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%EF%BC%88NextPublishing%EF%BC%89-%E6%B8%A1%E9%82%8A-%E9%81%94%E6%98%8E/dp/4844398350 www.amazon.co.jp こちらの書籍を参考に、 Google アカウントでログインする機能と markdown 書式でメモを作成する機能を作成しました。昨年の ラク ス アドベントカレンダー にVue.jsのプロジェクトをFirebaseでデプロイする方法について記事を投稿したので、本記事を閲覧する前にご確認いただけると幸いです。 qiita.com ログイン機能 src ディレクト リの下にcomponents ディレクト リを作成し、そこに「Home.vue」と「Editor.vue」を作成してください。 mymarkdown ― src ― components ― Home.vue(ログイン画面) | | | └ Editor.vue(メモ作成画面) | └ App.vue(画面切り替え) まずは Google アカウントでログインする機能を作成します。ログインする前の画面「Home.vue」を実装します。 Home.vue <template> <div id= "home" > <h1> {{ msg }} </h1> <button>Googleアカウントでログイン</button> </div> </template> <script> export default { name: 'home' , data() { return { msg: "Welcome to MyMarkDown" } ; } } ; </script> ログイン状態によって画面を切り分ける「App.vue」を作成します。 createdでログイン状態を確認しています。 この画面で「Home.vue」と「Editor.vue」を読み込んで、ログイン状態により表示を変えています。 App.vue <template> <div id= "app" > <Home v- if = "!isLogin" ></Home> <Editor v- if = "isLogin" :user= "userData" ></Editor> </div> </template> <script> import Home from "./components/Home.vue" ; import Editor from "./components/Editor.vue" ; export default { name: 'app' , data () { return { isLogin: false , userData: null } } , created: function () { firebase.auth().onAuthStateChanged(user => { console.log(user) if (user) { this .isLogin = true ; this .userData = user; } else { this .isLogin = false ; this .userData = null ; } } ); } , components: { Home: Home, Editor: Editor } } </script> <style lang= "scss" > #app { font-family: 'Avenir' , Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin- top : 60px; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style> まだログイン機能が実装されていないので、初期表示はこちらの画面(Home.vue)となります。ログイン機能を実装するためにまずFirebaseの「Authentication」の「 sign -in method」で Google アカウントでのログインを有効に設定します。「 Google 」をクリックし、「有効にする」ボタンをクリックし、プロジェクトのサポートメールを設定します。「 Google が有効になりました」と出ればOKです。 続いて「Home.vue」でログイン機能を実装します。methodsにログイン機能を追加します。 Home.vue <template> <div id= "home" > <h1> {{ msg }} </h1> <button @click= "googleLogin" >Googleアカウントでログイン</button> </div> </template> <script> export default { name: 'home' , data() { return { msg: "Welcome to MyMarkDown" } ; } , methods: { googleLogin: function () { firebase.auth().signInWithRedirect( new firebase.auth.GoogleAuthProvider()); } } } ; </script> 「 Google アカウントでログイン」ボタンをクリックすると Google アカウントの認証画面に移動し、 ここで承認すればログインすることができます。すると次のような画面が表示されます。 見出し「エディター画面」の下にはアカウント名とログアウトボタンが表示されます。(アカウント名は伏せさせていただきます) また、ログアウト機能をこの後作成するメモ機能の画面「Editor.vue」に追加します。 Editor.vue <template> <div id= "home" > <h1>エディター画面</h1> <p> <span> {{ user.displayName }} </span> <button @click= "logout" >ログアウト</button> </p> </div> </template> <script> export default { name: 'editor' , props: [ "user" ] , data() {} , methods: { // ログアウト機能 logout: function () { firebase.auth().signOut(); } } } </script> ログアウトを実行するとログイン画面が表示されます。 メモ機能 続いて入力内容を markdown 書式でプレビューを表示する機能を作成します。 そのためにマークダウン用のライブラリをインストールします。 次のコマンドを実行してインストールしてください。 npm install --save-dev marked これはmarkedという markdown 書式をHTMLに変換するnpmモジュールです。 続いてEditor.vueを編集します。 Editor.vue <template> <div id= "home" > <h1>エディター画面</h1> <p> <span> {{ user.displayName }} </span> <button @click= "logout" >ログアウト</button> </p> <div> メモリスト <div v- for = "(memo, index) in memoList" > <div v- if = "index!=0" v-html= "displayMemo(memo.markdown)" ></div> </div> <textarea class = "markdown" v-model= "memoList[memoIndex].markdown" ></textarea> <div><button v-on:click= "addMemo" >メッセージ追加</button></div><br> プレビュー<div v-html= "preview()" ></div> </div> </div> </template> <script> import marked from "marked" ; export default { name: 'editor' , props: [ "user" ] , data() { return { memoList: [ { markdown: "" , } ] , memoIndex: 0 } ; } , methods: { // ログアウト機能 logout: function () { firebase.auth().signOut(); } , // markdown書式でのプレビュー表示 preview: function () { return marked( this .memoList [this .memoIndex ] .markdown); } , // メモを追加 addMemo: function () { this .memoList.push( { markdown: marked( this .memoList [this .memoIndex ] .markdown) } ); } , // 作成したメモを一覧表示 displayMemo: function (text) { return text.split( /\n/ ) [ 0 ] ; } } } </script> 実行して、プレビューに入力内容がリアルタイムで markdown 書式で表示されていればOKです。 大見出しで「メモ」、中見出しで「ブログを書く」「メモ機能を実装する」、 小見出し で「メモを追加」「マークダウン記法でメモを表示する」というメモを追加しています。 プレビューには 小見出し で「マークダウン記法でメモを表示する」と表示しています。 おわりに 今回はVue.jsで Google アカウントのログイン機能と markdown 書式のメモ作成機能を紹介しました。今度はチャットができるようになるなど機能の拡張を行い、記事を作成していきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
こんにちは、開発エンジニアの amdaba_sk( ペンネ ーム未定)です。 ラク スの開発部ではこれまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「 開 ( か ) 発の 未 ( み ) 来に 先 ( せん ) 手をうつプロジェクト(通称:かみせんプロジェクト)」 というプロジェクトがあります。 この記事はかみせんプロジェクト2019年度下期成果報告ブログの一つです。 前回の成果報告では 「機械学習プロジェクトの進め方」について検証した結果のまとめ をしました。今回は「じゃあ実際に 機械学習 をやることになったら、どんなライブラリ、サービスを使えばいいの?」といったところの検証結果をまとめようと思います。 対象読者は前回と違って、 機械学習 に興味のあるエンジニアの方です。 なお今までの記事はかみせんカテゴリからどうぞ。 tech-blog.rakus.co.jp 概要 今回の目標 対象ライブラリ・サービスの選定 サンプルプロジェクトについて 学習データについて 前処理について テキストのクリーニング 単語の分割 単語の正規化 ストップワードの除去 単語のベクトル表現 文書のベクトル表現 モデル学習について 学習のそのあと 実装を終えての所感 Python + scikit-learn Python + H2O JVM系 + Smile Apache Spark Amazon SageMaker AI Platform Azure Machine Learning まとめ 今後の展望 参考 概要 非常に単純な 機械学習 タスクを実施するプログラムをいくつかのライブラリ、サービスを用いて実装することで、それぞれのライブラリ、サービスの使いやすさを評価しました。 やはり Python の scikit-learn は デファクトスタンダード であり、ライブラリの備える API の充実ぶり、Web や書籍の情報量は他を圧倒するものがあります。ただ学習データの量や、連携するシステムの開発言語によっては Apache Spark も有用です。 クラウド のマネージドサービスは、単なる Notebook の実行環境としての使い方をしている限りにおいては結局のところ scikit-learn を用いることになりがちでありその利点を引き出すことはできないということが分かりました。マネージドサービスは付属する学習済みモデルを利用するサービス、AutoML による自動学習、アプリケーションへのデプロイの容易さといったところに利点があるのだと推測されます。 今回の目標 実際に 機械学習 を利用した機能を作ることになった場合にまずやることになるであろうライブラリ、サービスの選定フェーズに対して参考になりそうな情報をまとめたいと思い調査を行いました。 とはいえライブラリやサービスを選ぶうえでの条件、観点はさまざまであり案件ごとに重視するポイントも固有のものがあるはずです。さらに調査メンバーがそもそも 機械学習 に関してそこまで詳しくはないということを考えると、実務上そのまま使えそうなレベルの資料を作るのは難しすぎます。 そこでさしあたり単純なサンプルプロジェクトを設定して 機械学習 モデルの作成 スクリプト をいくつかのライブラリ、サービスを使って実装し、それぞれの使用感をまとめました。 対象ライブラリ・サービスの選定 Python + scikit-learn Python + H2O JVM 系 + Smile Apache Spark Amazon SageMaker AI Platform Azure Machine Learning JVM 系の言語としてはメンバーのモチベーション的な理由から Scala を採用しました。 また事前の調査から「 Python 3 + scikit-learn」が ディープラーニング を行わない場合の デファクトスタンダード のような存在であることが分かっていますので、他のライブラリはそれとの比較という観点で調査をすることにしました。 サンプルプロジェクトについて サンプルは弊社の事業を考えると日本語テキストを扱うものの方がよいだろうと思われました。その上で単純なものであればなんでもよかったので、思い付きのままにAIチャットサービスっぽいものを作ることにしました。 ここに一人のゲーマーが居る。彼または彼女を A としよう。 A は最近ハマっているとあるゲームについて、公式サポートに問合せをするべく Web サイトに訪問した。 サイトにはありがちなよくある質問一覧の他に、「チャットで問い合わせる」というリンクが設置されていた。リンクをクリックするとページ内にチャットウィンドウが立ち上がり「気軽にご質問ください!」という定型的なメッセージが表示された。ウィンドウの下部にはメッセージ入力欄があり、カーソルが誘うように明滅している。 A はしばしの黙考ののち、質問を入力し始めた―― ここで自然な会話のできるAIチャットボットを作れればすごいですが、難易度激ムズな気がするので以下のような動きをするものとしましょう。 訪問者のメッセージを受け付ける メッセージが既存の「よくある質問」のどれに相当するかを分類する 質問の候補をいくつか選択肢として表示する 選ばれた質問に対して事前に設定された回答を表示する (どことなく弊社のとあるサービスに激似ですが、気にしないことにします) 機械学習 が関わってくるのは上の 2 のステップです。比較的短文な日本語文章の多クラス分類問題であると定式化できます。 前回の記事でまとめた内容によれば、ここで 機械学習 を使わない MVP を検討するところではありますが、今回はその辺をすっ飛ばします。また上のイメージのような組み込み先システムの設計も先に考えておくべきところではありますが、これも簡単のためにすっ飛ばして前処理とモデル学習のステップを考えていくことにします。 学習データについて この分類問題では生のデータとしては例えば以下のようなものが得られると想像できます。 メッセージ よくある質問ID ログインできなくなりました。どうしたらいいですか? 1 ログインができず、ゲームがプレイできません。 1 ゲームを始めようとするとエラーが出てログアウトしてしまいます。 1 : : 機種変更しても同じセーブデータで遊べますか? 4 引き継ぎナンバーは一度発行すれば繰り返し使えますか? 4 動作が重いです。 5 ゲーム内で購入したアイテムの情報が反映されません。 6 : : ここで「メッセージ」が推測の入力となるデータ、「よくある質問ID」が推測したいクラスのラベルです。 会員制サイトなどで質問者の属性情報や前後の文脈など追加の情報が得られることもあるかと思いますが、ここでは匿名のユーザーによる単発の質問への対応という想定で上のようなデータをサンプルとして使うとしましょう。 とはいえそう都合よくチャットログデータは持ち合わせていませんでしたので、社内のいろいろな方に協力をお願いして自前で作りました。 クラス数: 96 データ 総数: 6051 クラスごとのデータ数: 平均: 63.0 最大: 199 最小: 16 (改めて統計情報を見てみると、クラス数めっちゃ多いしクラスごとの分布もめっちゃ偏っていてあまりいいデー タセット とは言えない気が…) 具体的なデータの中身は社外秘ということになったので公開できませんが、ゲームのサポートチャットではないということだけ言い添えておきます。 前処理について 元のデータは日本語テキストデータなので、何とかして数値データとして表現しなければなりません。 自然言語処理における前処理の種類とその威力 によれば、テキストデータの前処理は以下のものを行うようです。 テキストのクリーニング 単語の分割 単語の正規化 ストップワード の除去 単語のベクトル表現 文書のベクトル表現 それぞれについて具体的な方法など検討すべき点はあるものの、大まかには上の工程を行えば良さそうです。 テキストのクリーニング テキストのクリーニングは、テキスト内のノイズを除去する工程です。Web ページを スクレイピング して得たデータなどは HTML タグが含まれていたりしますが、これらは推測したいラベルと意味的な関わりの無いノイズとなります。ノイズを除去することでタスクの結果に及ぼす悪影響を抑えることができます。 今回はチャットメッセージの形で蓄積されたデータであり、ほぼ不要と思われるので特に何もしないことにしました。 単語の分割 テキストを 機械学習 の入力とする場合は、数値のベクトルに変換することがよく行われます。その際テキストを何らかの「最小単位」へと分割し、その最小単位が対応する数値ベクトルを使ってテキスト全体を数値ベクトルにするという方法を取ります。 この「最小単位」として何を使うかによって大きく二つの方法があるようです。 形態素 に分ける方法 MeCab や Janome 、 Kuromoji といった 形態素解析 器で文を 形態素 に分解します。 N-gram 法を使って分ける方法 テキストを文字ごとに分け、各文字の後ろN文字目までの組によって作られる「 N-gram 」を最小単位とする方法です。 今回の実装では 形態素 に分ける方式を取りました。理由としては 参考記事が 形態素 にしか触れていない 文法的に意味のある単位の方がそれっぽい 実装も容易 という点が挙げられます。 使用した 形態素解析 器は以下の通りです。 Python : Janome JVM : Kuromoji どちらもそれぞれの環境で導入が容易であり、使用方法も簡単であったためこれらを選びました。辞書は何を使うかも検討しなければいけないところですが、今回は簡便にどちらも IPA 辞書を使っています。 単語の正規化 単語の正規化では全角半角などの文字種の統一、表記揺れの吸収といった処理をすることで、意味的に同じ単語を同じものとして扱えるようにします。 文字種の統一 日本語文字は全角に 英数字記号は半角に 数字の置き換え 数字はすべて 0 に置き換え 単語の統一 形態素解析 から原形を使う ストップワード の除去 ストップワード は 自然言語処理 の際に一般的で役に立たない等の理由で処理対象外とする単語のことです。「てにをは」のような助詞や助動詞、「あれ、それ」などの代名詞といった単語はどのような意味のメッセージにも登場し、内容の推測には役に立たないため除去します。 ストップワード の除去には様々な方式があるようですが、ここでは日本語の ストップワード 辞書の一つである Slothlib を使い、これに含まれる語は除去することにしました。 単語のベクトル表現 これまでの工程できれいになった単語を、数値ベクトルに対応させます。ベクトル化するのにも様々な手法が存在するようですが、主なものは以下の2つのようです。 one-hot表現 分散表現 one-hot表現は各単語を単位ベクトルに対応させます。シンプルで分かりやすい方法です。 分散表現は Word2Vec みたいなやつですね。one-hot 表現からさらに加工して得るもののようです。 どちらを使うかはこの後の文書のベクトル表現の種類によって決まってきます。 文書のベクトル表現 前工程で決めた単語ごとの数値ベクトルを用いてテキスト全体の数値ベクトルへの対応を作ります。単語ベクトルと同じく主な手法は2種類に大別できます。 one-hot 表現からは文書に含まれる単語のベクトルを足し合わせた Bag of Words となります。さらに単語の出現頻度と逆文書頻度の積で単語を重みづけすれば TfIdfベクトル です。 分散表現での文書ベクトル表現は Word2Vec で得た単語ベクトルを足し合わせたり、 doc2vec を使ったりで得ることが出来ます。 今回のサンプル実装に先立っての事前調査で、scikit-learn に TfIdf ベクトルを計算するための API が用意されており、また仮に自前で実装したとしても何とかなりそうということで、Tfidf ベクトルを使うことにしました。 モデル学習について 分類 アルゴリズム は各ライブラリ、サービスごとに用意されたものを使うことになると想定されました。それぞれのライブラリ、サービスによっては実装されていない アルゴリズム もあるかもしれず、ここはあえて統一せずに使えるものを使うという方針にしました。 ただし選定の際のガイドとして scikit-learn のアルゴリズム選定チートシート を使用しました。 これによれば、今回のサンプルプロジェクトにおけるデー タセット 規模やタスクの性質から、線形 SVM 分類器、あるいは単純 Bayes 分類器が良いとのことです。そのため単純 Bayes 分類器が使える場合はこれを使うようにしています。 学習のそのあと 学習されたモデルはシステムへ組み込まれサービスとして運用されるのがまっとうなプロジェクトの進み先ですが、今回はサンプルプロジェクトなので評価指標の算出までで実装完了とします。 算出した評価指標は以下の通りです。 混同行列 正解率 適合率、再現率、F 値 加重平均 マクロ平均 実装を終えての所感 Python + scikit-learn scikit-learn は Python の代表的な 機械学習 の オープンソース ライブラリです。 改めて調べてみても、やはり デファクトスタンダード となっていると納得せざるを得ませんでした。 API が非常に充実している インターフェースの統一された API データ分割、ハイパーパラメータチューニング、性能評価、可視化もできる ドキュメントも充実している ググればサンプルがたくさん出てくる 特にインターフェースが統一され、かつ充実した API は非常に便利であり、 機械学習 を試したいならまずこれ触れば間違いはなさそうです。 Python + H2O H2O is an open source, in-memory, distributed, fast, and scalable machine learning and predictive analytics platform that allows you to build machine learning models on big data and provides easy productionalization of those models in an enterprise environment. H2O ドキュメントトップページ より引用 とあるように、H2O はライブラリというよりかはプラットフォームのようです。 Python からその機能を使うこともできるし、 アーキテクチャ を見れば Java や Scala , R などからも使うことが出来るとわかります。また scikit-learn のパイプラインに組み込むことが可能だったりと他ライブラリ、プラットフォームとの連携にも考慮されている点もいいですね。 また AutoML という機能もあり、自分でコードを書かずともデータを与えれば自動でいい感じに学習してくれるようです。 ただ今回は AutoML は使わず、自分で Python のコードを書いて実装しました。 scikit-learnと比較して 分類 アルゴリズム には単純 Bayes 分類器を選びました。出来上がったコードは自体は scikit-learn のものと比べ記述量や難易度は変わらない印象を受けました。 ただ H2O を使って実装してみた系の日本語記事が少なく、参考にできるのは公式ドキュメントのサンプルコードのみというのがつらいところ。 公式チュートリアル もありますが、中途半端なコードだったりで情報量が少なく、事前に scikit-learn などで実装した経験がないとなかなかしんどいかと。 また H2O はモデルの学習部分にフォーカスしているためか、テキストのベクトル化といった前処理に関して特に組み込みの API があるというわけではなさそうでした。そのため Tf-Idf ベクトル化は scikit-learn の API を使うなどする必要があります。 JVM 系 + Smile Smile is a fast and comprehensive machine learning engine. Smile は JVM 上で利用できる 機械学習 エンジンで、 Java や Scala など好きな JVM 言語で使うことが出来ます。組み込む先のシステムが JVM 言語で作られているのであれば、 機械学習 関連のコードとアプリケーションのコードで言語を揃えられるのが良いですね。 実行速度に優れ、 自然言語処理 、統計処理、データ可視化も Smile の API でできると謳われています。 scikit-learnと比較して ライブラリの特徴というよりかは言語的な特徴になりますが、 Scala での実装は説明的で分かりやすくなるように感じました。ただ Java で実装した場合、型表記が面倒か抽象的過ぎるかになりそうという印象でもあります。 Smile そのものに言及すると、 インターフェイス が独特で scikit-learn などとは差が大きく、結構慣れるのに時間がかかりそうです。使ってみた系の情報が少ない点もネックになるかなと思われます。 また分類 アルゴリズム は豊富に用意されているもののハイパーパラメータチューニングなどの便利 API などはなさそうで、そのあたりを自前で実装しなければならないあたり不便という印象がぬぐえません。 Apache Spark Apache Spark は巨大なデータに対して高速に分散処理を行うための フレームワーク です。 Java や Scala 、 Python などいろいろな言語での API が用意されています。 分散処理のための フレームワーク なので汎用的に使えるのですが、 機械学習 のための コンポーネント が組み込まれていることから 機械学習 ライブラリとしても使用することが出来ます。 先にも触れたようにいろいろな言語で使用することが出来ますが、今回は Scala から使ってみました。 scikit-learnと比較して Spark の 機械学習 コンポーネント が提供する API のインターフェースは scikit-learn のように統一されており、Smile より使いやすい印象です。 組み込みで前処理やハイパーパラメータチューニングができたりと機能も充実しており、使い勝手だけを見れば scikit-learn とも遜色ないように思えます。 今回 Windows 上での環境構築をしてみましたが、 インストーラ を起動しなければならないあたり面倒でした。 Linux や Mac であればコマンドでインストールできるのでその点は問題にはならないと思われます。 マネージドサービスで Spark を使えるものが多いため、そういったサービスで使う場合もよさそうです。 Amazon SageMaker Amazon SageMaker は AWS 上で提供されている完全マネージド型の 機械学習 サービスです。 Amazon SageMaker というサービスの下に Amazon SageMaker Studio Amazon SageMaker Ground Truth Amazon Augmented AI Amazon SageMaker Studio Notebooks ... といった機能が用意されています。 今回は自前で前処理等の部分を実装する想定だったため、 Amazon SageMaker Studio Notebooks を使って自分で実装した Python コードを実行しました。 scikit-learnと比較して 組み込み アルゴリズム について sagemaker というパッケージを読み込むことで組み込み アルゴリズム や Amazon SageMaker 独自の アルゴリズム やモデルを使用することが出来ます。 ただ提供されている アルゴリズム も限られていること、ドキュメントやサンプル実装の情報は存在するものの少ないことから、あえて組み込み アルゴリズム を利用するメリットは感じられませんでした。 Amazon SageMaker 上で scikit-learn コードを使用する方法もドキュメントに記載があることから、Notebook 上で自分でコードを書くのであれば scikit-learn を利用しておけばよいのではないかという印象です。 活用について 学習したモデルと AWS Lambda、 Amazon API Gateway を組み合わせることで、 HTTPS エンドポイントを作成することができます。 作成したモデルを用いて手早くアプリケーションを作成したい場合には有用そうです。 AI Platform AI Platform は Google Cloud 上の AI 関連サービスのブランドです。 2020/3/10時点でまだベータ版。そのためメニュー上でもかなり下の方に配置されています。 AI Platformというブランドの下に AI Platform Notebooks AI Platform Training AI Platform Prediction Data Labeling Service(ベータ版) Deep Learning VM Image Deep Learning Containers(ベータ版) ... とたくさんのサービスがぶら下がっています。 AI Platform Training ではト レーニン グデータ、検証データ、テストデータと分けて GCS( S3 の GCP 版)に格納することで組み込み アルゴリズム による学習も行える様子。 ただ今回は自前で前処理等の部分を実装する想定だったため、AI Platform Notebooks を使って実装したコードを実行しました。 scikit-learnと比較して 組み込みの アルゴリズム について AI Platform では独自の アルゴリズム などを提供する Python パッケージが用意されているわけではないようです。 そのため今回の実装では結局のところ scikit-learn での実装を AI Platform Notebook 上で実行できるようにしたものとなりました。 その際 GCP で用意されている scikit-learn は 2020/3/10 現在で 0.19.2 だったことでハマりました。最新の 0.22.x 系とは API の非互換の部分が多いので注意が必要です 1 。 環境について Notebooks 環境が用意されているので開発環境構築の手間はかからないのが良いです。 クラウド サービスらしくスペックの変更もすぐに実施できます。 ただデフォルトのスペックが n1-standard-4(4 vCPU / メモリ15GB) + ストレージ 100GB と少し強めなので、軽い処理の実験用につどスペック変更するのが手間でした。 活用について まだベータ版なので正式サービスに導入するには抵抗がありますが、サービスに組み込むための学習モデルの作成プラットフォームといった利用方法であれば問題なさそうです。 またハイスペックな インスタンス を利用することで短期間でのモデル作成が実現できそうとも感じました。 ただし、前処理やモデル生成の処理時間に困っていないのであれば、ローカルで scikit-learn を使うことに対するアドバンテージがないかもしれないというのも正直な感想です。 Azure Machine Learning Azure Machine Learning は Microsoft Azure 上で提供される 機械学習 サービスで、 機械学習 を含む DevOps、MLOps を実現する クラウド 環境です。 機械学習 モデルのト レーニン グ、デプロイ、自動化、管理、追跡というワークフローすべてにおいて使用できるツールが提供されています。 Azure Machine Learning デザイナー や 自動 ML という、コードを書かずにモデルの作成ができるツールもあります。 ただ今回は Azure Machine Learning 上の Notebook で自分で実装したコードを実行しました。 scikit-learnと比較して 組み込みの アルゴリズム について Azure Machine Learning では azureml という Python パッケージが用意されているものの、これは学習 アルゴリズム などを提供するものではないようです。 公式の チュートリアル を見ても、 Python でのサンプルは scikit-learn を使って線形回帰を行っています。 そのため今回の実装では結局のところ scikit-learn での実装を Azure Machine Learning の Notebook 上で実行できるようにしたものとなりました。 活用について AI Platform と同じくサービスに組み込むための学習モデルの作成プラットフォームといった利用方法ができそうです。 ただ Notebook の実行環境としてしか使わないのであれば、ローカルで scikit-learn を使うことに対するアドバンテージがないかもしれないというのも AI Platform と同様です。 まとめ 今回は 機械学習 のライブラリ、サービスの使用感を、単純なモデル学習 スクリプト を実装することで調べました。 単純な学習 スクリプト を自分で実装する限りにおいて、ライブラリやサービスの機能的な面で決定的な違いは無いように思えました。 ただし、普及具合を考えると scikit-learn がやはりおすすめということになります。 scikit-learn は 機械学習 ライブラリの デファクトスタンダード です。それ自体の充実した API 、ドキュメントもさることながら、日本語の解説記事も Web 上にあふれています。 Python の環境さえ作ればライブラリのインストールも容易であり、学習時やさくっと試したい時に最適でしょう。 今後の展望 今回は非常に単純な 機械学習 タスクに対し、自分で実装するという縛りの下でライブラリやサービスの使用感を調べました。 ですが、 Amazon SageMaker や AI Platform、Azure Machine Learning などを見ていると、Notebook 以外にもいろいろな 機械学習 関連機能、サービスがあります。 プロジェクトの要件にもよるかと思いますが、マネージドサービスを使う利点はそういったサービス群にこそあるのではないかと感じています。 今後機会があればそれらのサービスも触ってみたいものです。 参考 scikit-learn Machine Learning in Python H2O.ai Documentation h2oai/h2o-tutorials Smile - Statistical Machine Intelligence and Learning Engine Apache Spark Amazon SageMaker(機械学習モデルを大規模に構築、トレーニング、デプロイ)| AWS Amazon SageMaker Python SDK — sagemaker 1.51.0 documentation Google Cloud - AI & Machine Learning Products Google Cloud - AI Platform Notebooksベータ版 Azure Machine Learning 最新版を入れ直すことも可能かもしれないが未調査。 ↩
アバター
はじめに こんにちは。新卒1年目エンジニアのdd_fortです。 今回はDockerを勉強しようと思い、CentOS8でDockerの環境構築をしようとした話です。 Dockerが公式サポートされていないCentOS8にDockerを使用するときに躓いた点や気を付ける点を中心にインストール方法を紹介しようと思います。 目次 はじめに 目次 Docker とは リポジトリの追加 Docker のインストール Docker の起動 ネットワークの問題 回避策1:Docker 起動時のオプション 回避策2:firewalld の設定変更 回避策3:パケットフィルタリングツール変更 最後に Docker とは Docker社が開発している、コンテナ型の仮想環境を用いてアプリケーションを開発・配置・実行するためのプラットフォームです。 コンテナ型仮想環境 Doecerのメリット ホストOSを直接アクセスするためオーバーヘッドが少ない 可搬性が高くDockerをインストールすれば、ホストOS環境に依存せず動作する コード化されたファイルを共有することで開発環境のセットアップが容易になる リポジトリ の追加 まず、Docker の リポジトリ を追加します。 $ dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 以下のようになっていればOKです。 $ dnf repolist repo id repo の名前 状態 AppStream CentOS-8 - AppStream 5,120 BaseOS CentOS-8 - Base 2,126 extras CentOS-8 - Extras 13 docker-ce-stable Docker CE Stable - x86_64 63 Docker のインストール dnfコマンドを使用して dnf install docker のようなコマンドでインストールしようすると依存関係の問題でインストールできません。 回避策として今回は、 --nobest オプションを付けて実行します。 $ dnf install --nobest docker-ce containerd.io この状態のままだと、 dnf upgrade を実行すると Dockerを強制的にインストールしているためエラーが発生します。 そのため、CentOS7 の リポジトリ を利用してcontainerd.io をアップデートします。 $ dnf update https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.10-3.2.el7.x86_64.rpm 以下を実行してエラーが発生しなければOKです。 $ dnf -y update docker-ce Docker の起動 Docker を起動します。 $ systemctl start docker $ systemctl enable docker バージョン確認 $ docker --version Docker version 19.03.8, build afacb8b ネットワークの問題 しかし、CentOS8の場合はこのままではコンテナ内から名前解決ができずdnf 等が使えません。 回避策1:Docker 起動時のオプション コンテナの構築時や起動時に --network host を指定して実行することで解決することができます。 $ docker pull wordpress $ docker run --name wordpress-test --network host -d wordpress 上記は WordPress のコンテナを立てるときのコマンドです。 回避策2:firewalld の設定変更 iptables が動いている場合は、firewalld でNAPTするように設定を変更することで解決することができます。 $ firewall-cmd --add-masquerade --permanent $ firewall-cmd --reload 回避策3:パケットフィルタリングツール変更 根本的な原因としては、CentOS8からパケットフィルタリングツールが iptables から nftables に変わったことです。 (Docker が nftables を設定できないため) CentOS のパッケージフィルタリング構成 CentOS6 : iptables CentOS7 : firewalld(管 理I /F), iptables CentOS8 : firewalld(管 理I /F), nftables iptables を利用するように変更することで解決可能 firewalld を止める $ systemctl stop firewalld $ systemctl disable firewalld iptables をインストール $ dnf install iptables-services iptables を起動 $ systemctl enable iptables $ systemctl start iptables 最後に 私はCentOS8にDockerが公式非対応であること知らずに環境構築をはじめてしまったため、環境構築だけで時間が多く掛かってしまいました。 しかし、CentOS8とDockerの勉強になったのでよかったかなと思っています。 また、CentOS8ではpodman(Docker互換のコンテナエンジン)が使えるみたいなのでそれを試してみるのもいいかなと思いました。 この記事がCentOS8でDockerを使おうとしている人の助けとなれば幸いです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター