エキサイト株式会社で就業型インターンをさせていただきました。

こんにちは、エキサイト株式会社でインターンをさせていただいている木下です。
今回は、2〜3月の2ヶ月間、就業型インターンをさせていただいて学んだことをご紹介します。

自己紹介

趣味は、アニメ・漫画を見ること、サッカーをすることです。

高校3年で、授業でプログラミングに触れて興味を持ち、情報工学科に入学しました。
大学2年から、アプリ開発に興味を持ち、9月にエキサイト株式会社でのハッカソンインターンの「Booost」に参加しました。
そして、エキサイト株式会社に就業型で働いてみたいと思い、2〜3月の2ヶ月間、就業型インターンをさせていただきました。

技術的なことでは、アプリ開発に広く興味があり、LaravelやRuby on Rails、ReactなどでWebアプリを個人開発、SwiftでiOSアプリを個人開発やチーム開発しています。
また、ハッカソンにもよく参加しています。

インターンで行ったこと

ヘルスケア事業部に配属され、「恋ラボ」「お悩み相談室」「電話占い」の3サービスのサーバーサイド開発に携わりました。

  • 「恋ラボ」「お悩み相談室」のコラム記事周りの開発
    • コラム一覧ページの作成や、コラム記事と無料相談ページ下にコラム最新5件を表示、TOPページにコラム最新3件を表示等
  • SEO関連の画像タグの属性修正、TD(title, description)修正、カノニカルやインデックス修正

学び

インターンでは、実際にサービスを開発・運用している現場に初めて参加したこともあり、多くの学びがありました。

コードを書く上での意識

コードというのは書いた人がいなくなった後も残り続けていくものであるため、コードを書く際は、まず前提に求める挙動をすること、そして、他の人が読んだときに、分かりやすく、改修しやすいことが大事だと学びました。

また、既存のコードに手を加えるときや、コードレビューをするときなど他人のコードを読む機会がありましたが、結構大変だと感じたため、読む人の苦労を減らすということでも可読性のよいコードを書くことは重要だと学びました。
そのために、命名規則はもちろん、何を実装するためにコードを書くのか、コードのロジックを言語化して明確にしてから実装することが大切だと学びました。

チーム開発

実際にサービスを開発・運用している現場での開発方式を知り、コードレビューをもらうことで、チーム開発において、大切なこと、気をつけるべきことを学ぶことができました。

サービスを運用していくということ

当たり前かもしれませんが、サービスの運用には、様々な方々が関わっています。
エンジニア、企画、デザイナーなど様々な立場の方々が様々な視点からサービスを視て、日々より良いモノにしています。
そのため、エンジニアはコードを書くだけでなく、他の視点からの意見も聞きながら、エンジニアの視点からの意見を言っていくことで、チームとしてサービスをより良いものにしていけると学びました。

問題を解決する力

機能を実装する中で、思うように動かないことや困った時に、調べたり、人に質問したりと、解決する力が身につきました。
また、どう実装するかを考えるときに、複数のパターンを考え、メリットとデメリットを書き出すことで、よりよい実装方法を考えることが大事だと学びました。

複数のタスクを並行して処理する力

複数のタスクを並行して行わなければならない時に、優先順位づけやそれぞれにかかる時間の見積もりをしました。
見積もりは、思ってたより時間がかかることが多かったですが、複数のタスクを並行して処理していく力が身につきました。

また、当たり前ですが、きちんと連絡をすることや確認することを1つ1つやっていくことが大切だと学びました。

ミスしても、次に生かすこと

仕事をしている中で、コードレビューで指摘されたことや、ミスしてしまったことも多々ありました。
それらをただ反省するだけではなく、次同じことをしないようにどうすればいいのか考え、改善するということがとても重要だと学びました。

主体性、行動力

初めは、オンラインということや自分が質問することは相手の迷惑になるのではないかと思っていたところもあり、質問しづらかったです。
ですが、一人で詰まって時間が過ぎるよりも、人に聞くことで解決でき、相手も教えることで学びがあるということを感じ、タスクや実装についての疑問点があれば、積極的にメンターやエンジニアの方、企画の方に質問していくことができました。
その中で、指示を待っているのではなく、自分から質問するなど主体的に行動することが大切だと学びました。

技術面

実際の現場で使われている技術やコード、開発方式を知り、コードレビューをもらい、教えていただくことで、多くの知識、技術を身につけることができました。
知らない技術に対してインプットすることと、それを実装でアウトプットすることで、より多くのことを吸収できたと思います。

キャリア面

インターンでは、実際に社員の方と同じように働いていました。
そして、インターン中にエンジニアの方々とお話させていただく機会をメンターの方が作ってくださり、エンジニアになった理由、やりがい、エンジニアを続けている理由、キャリアなど、様々な質問をして、お話を聞くことができました。

その中で、今まで漠然としていたエンジニアという職業が少し明確になり、自分がどうなりたいのか、エンジニアとしてどう生きていくのかなどキャリアに関して、具体的に考えることができました。
自分の中で、将来のことで悩んでいたところがあったのですが、エンジニアの方々とお話ししていく中で、現時点での答えを見つけられたと思います。

SEOという新しい知識

SEOは、開発のなかでは、優先順位が低くなってしまいがちですが、そのサービスがユーザーに見られ、使ってもらうためにはとても重要なものです。
今回、SEOに関するタスクを行い、SEOという新しい視点からコードを見ることで、最初はカノニカルやインデックスなどおまじないだと思っていたコードも理解できるようになり、サービスを運用する上での学びとなりました。

リリースできた達成感

今回実装した「恋ラボ」「お悩み相談室」のコラム記事周りの開発では、リリースして新しいページや表示が追加されるなど、目に見える成果が大きかったため、達成感があり、とても嬉しかったです。

最後に

エキサイト株式会社での2ヶ月のインターンは、技術面でもチーム開発という面でも多くの学びがありました。
また、様々な方々とお話ししたことで、エンジニア像やエンジニアとしての生き方などキャリア面でも多くの学びが得られました。
メンターの方々をはじめエンジニアの方々、人事の方々のおかげで、とても楽しく、貴重な経験をさせていただきました。
短い期間でしたが、本当にありがとうございました。

新卒デザイナーが社内カンファレンス運営をやり切った話①

こんにちは!21新卒デザイナーのかじもとです!

2022年2月18日にエキサイトHD初・過去最大級イベントの『excite×iXIT TechCon』を開催しました〜〜〜!👏

開催についての目的や意義などは、実行委員長のおおしげさんがまとめてくださいました…!ぜひ読んでみてください😉

tech.excite.co.jp

 

このカンファレンスで私自身もLT枠に登壇したのですが、運営スタッフとしても関わらせていただきました!当日の運営はもちろんのこと、開催するまで数ヶ月かけて準備をしてきたので、その記録になれば…なブログを数回に分けて投稿します〜!

はじまり

開催経緯は上記事にあるように、社内技術組織の活性化・外部参加への練習になるようになど意味を込めて「初の社内カンファレンスをやるぞ!」とスタートされました。

が、元々わたし自身は技術組織活性化の1チームに所属していたのみで、「カンファレンス開催するにあたりデザイナーさんがいると助かる」みたいな経緯で参加しました。

初めは「ウェブサイトのデザインをお願いしたい」とかなり具体的で『依頼されて制作する』ような入り方と聞いていたので、「せっかくやるのに企画はできないのかな、モヤモヤ…」などと考えていました😂(初開催だからこそ模索しながらの仮案だったと後々知ります笑)

初めて参加したミーティングでは、なぜ開催するのかやウェブサイトである必要性など根掘り葉掘り。何度かミーティングを重ねて目的や達成したいことなどを共有し、活動の方針や運営チームが発足されて、手探りのカンファレンス運営が始まりました。

開催のために準備したこと

「作る専門として参加したくはない〜!」言いつつも、イベントを開催するにあたり準備するものは多く、結果として色々と作っていました。

ですが、「なぜ作るか理由をきちんと考えること」をメンバーと一緒にできたので、企画から参加という理想の運営像で出来たな〜と振り返ってます。(もちろん作ることは大好きなので多くても全然問題なかったです✌️)

一番初めの準備したものは、カンファレンスの顔となるキービジュアル作りでした。

概念を見える化する「キービジュアル」

過去に開催した前例もなく、カンファレンスに対するイメージは人それぞれ。それを統一するため、みんなが共通で連想できるイメージを手始めに考えました。

まずは実際のカンファレンスはどんな風にやっているのかを集めたり、各々が思うカンファレンスのイメージを集めて討論。基本的にオンラインでミーティングをしていたので、miroを使ってディスカッションしていきました。

実際のmiro
画像検索やPinterestを使ってイメージ画像を集めました

十数名で行ったワークでしたが、「カンファレンス」に対してこれだけ色々なイメージがあった訳です🤔 

ここから似ているものや近しいイメージ同士でグループ化して、カラフル・シンプル・宇宙っぽい…のようにタイトルをつけます。全部の要素を選ぶと大変なことになってしまうので、いいなと思ったものを投票してラフ案を作成するための選択肢を絞ります。

イメージを形にしてみる

投票で選ばれたのはこの3つ。選ばれた際の理由もちょっぴり記載します。

カラフル系

  • ポップで堅すぎない、元気な感じがある
  • 始まりなので賑やかに見せたい

シンプル系

  • 遠目でも分かりやすい、シンプルさがいい
  • ホールディングスのカラーと合わせやすそう

宇宙系

  • IT系と宇宙っぽさや未来感がマッチしそう、クールな印象
  • 始まりとビッグバンを掛け合わせられそう

どれもそれぞれ選んだ理由があり、それをうまく落とし込めるかデザイナーの頑張りどころ💪 それぞれのイメージから1枚絵だったりロゴタイプだったりを作ります。

色々とバリエーションを出せるように、イメージを参考にしながら自分でもイメージを追加してひたすら案を出す出す…Illustratorと睨めっこしながら、シンプル系5案・カラフル系4案・宇宙系3案の合計12案を作成しました!

f:id:KAJIJI_Design:20220322223624j:plain

作った12案たち

イメージと作成意図も記載。いろんな手法で作成できて楽しかったです😉

イメージ決定

メンバー内で投票した結果、カラフル系の2案目のこちらに決定しました!

丸・三角・四角の質素な形を組み合わせて、バラバラにサイズを変えてみたりギュッとグループにして別の形として見せることもでき、色味の印象はそのままに形の見せ方で横展開がしやすいものになってます。

この形や色をベースに、カンファレンスで必要なクリエイティブを作っていきました…!他クリエティブについては次回ブログに書きます〜!

おまけ:なぜか作ったフォント

タイトル部分のtech con beginningの文字、実はオリジナルのフォントにしていて、大文字・小文字・数字だけですがフォントを作りました。

adobe Illustratorの作業スペース

 

Image from Gyazo

大文字・小文字・数字くらいなら打てます

需要低めですが欲しい方はお声掛けください😂

次回に続く…

「WEラブ赤ちゃんプロジェクト」古都に馴染むクリエイティブ制作を考えた!

はじめまして、エキサイト株式会社・デザイナーの小野寺です。 こちらの記事でレポートを執筆した西場とともに、「WEラブ赤ちゃんプロジェクト」のデザイン・ディレクションを担当しています。

前回は「WEラブ赤ちゃんプロジェクト」の概要とともに、主に交通機関に掲載された実際の制作物と、制作時データの違いなどをメインにレポートしました。

今回は、私が「京都」という歴史ある街に掲示されるクリエイティブを制作する過程で出合った気づきなどをテーマにお伝えしたいと思います!

京都の街が素敵なのには理由がある

普段旅行には行かない人でも、修学旅行などの機会で京都には行ったことがあるよ、という方も多いのではないでしょうか。

古都の面影を今でも多く残す京都の街歩きは、タイムスリップしたような、非日常感を味わうことができると思います。

しかし、そんな素敵な体験は、大切に保存されている古い建築物などだけが生み出しているわけではない、ということを今回改めて学びました。

歴史遺産に近いほど厳格な「京都府景観条例」

1200年の年月に育まれた歴史都市である京都の街並みを守るために、京都市では2007年に「京都府景観条例」という、屋外広告や建築物にまつわる条例を制定しています。

簡単に内容を説明すると、京都市内の「建築物デザイン」「建物の高さ」「広告物」に、「配色」や「掲載場所」「高さ」などに関して規制・ガイドラインを設け、街並みの調和を保つための条例のようです。ガイドラインの厳しさは、地域別に設定され、歴史的建築物の近くになればなるほど厳格になっていきます。

多くの広告物や看板は、街並みの中で「いかに見てもらうか」「覚えてもらうか」といったポイントでレイアウトや配色が考えられていることが多いです。制限を設けなければ、そうしたバラバラに目を引く色の無法地帯と化してしまい、美しい景観が損なわれてしまう、というのは納得です。

▼京の景観ガイドライン - 広告物編 https://www.city.kyoto.lg.jp/tokei/cmsfiles/contents/0000056/56450/guideline_all.pdf

(このガイドラインを作り上げた人々がまずすごい)

景観の守り方:派手な色はNG!マクドナルドやセブンイレブンも例外はない!

どういうこと?と思われた方はぜひwebで画像検索してみてください。 見慣れた大手企業さん達がガイドラインに合わせてコーポレートカラーを調整して京都の街に馴染んでおられます。

🔍京都 景観色

どの色ならOKなのか、という基準はガイドラインに「マンセル値」で表記されています。とても簡単にいうと、明度と彩度の高い「派手な」色はアウト、少し明るめの規制対象色は、使う面積を少なくしてインパクトを弱めてね、ということが示されています。

ガイドラインの一例

京の景観ガイドライン- 広告物編より

「WEラブ赤ちゃんプロジェクト」のキーカラーを調整する

さて、今回のプロジェクトの制作物の中には光栄なことに、ガイドライン上規制がかかる、風情ある地域に掲示されるクリエイティブもいくつか含まれており、ご担当者さまから別途キーカラーの調整が必要、とのご連絡をいただいておりました。

デジタルを主戦場とする我々にとっては、多く建築業界などでのスタンダードとなっている「マンセル値」自体が馴染みが薄く、四苦八苦しつつもブランドカラーのイメージを崩さずにガイドラインを守れる配色を以下のプロセスで選定し直しました。

▼プロセス

先方のご担当者さまより、今回は「マンセル値の彩度6以下」という指定をいただき、最終的にはDICのカラーコードでセーフな色かチェックをしてくださるということだったので、入稿時に指定しているCMYKのコードをDICカラーに変換して弊社でもツールでマンセル値を確認しながら、また色見本帳とにらめっこをしながら色を決める、という流れで最終的な色を決めました。

下の画像の通り、マンセル値を彩度6以下にすることで、少し黄色みがかったマイルドな色になりましたね!

とはいえ、素材によってどんな色が出るのか、刷るまでわからないのが印刷物・・!実際のクリエイティブはどのようになったのでしょう・・!

実際のラッピングバスはこうなりました!

▼入稿データ

▼実際のクリエイティブ

太陽光や写真の具合もありますが、イメージしていたよりも少し鮮やかに、心配するほどには渋い仕上がりにはならなかったようです😀 ほっと一安心する瞬間です。

その他にも前回の地下鉄に引き続き、商店街のフラッグや、バスロータリーの柱などにも「WEラブ赤ちゃんプロジェクト」の赤ちゃんが続々出現中です! 今回制作したグッズ・広告を通じて、少しでも多くの人に「みんなが温かく見守る子育て」について再認識してもらえたら嬉しいです。

最後に

今回の京都府の官民が一体になった「京都府子育て環境日本一推進会議」様とのコラボは、歴史都市ならではの「景観色」についての理解を深め、また、初めて現地視察を行ったことで、机上では体感できなかった改善点なども見つかる良い機会となりました。

プロジェクトのデザインガイドラインをブラッシュアップしつつ、今後ともコラボレーションする団体さまと調和するクリエイティブ制作を行なっていきたいと考えています。

🎉Canva勉強会を開催しました🎉

こんにちは。21卒デザイナーの山崎です。 先日Canpa Proアカウントが事業部で解禁されたので「第1回Canva勉強会」を開催しました。

参加人数は第1回と第2回で合計26名になりました!

何でやったの?

現在エキサイトではAdobeアカウントを利用しているビジネス職や企画職の方が多いという課題があり、Adobeでやっている仕事をCanvaで代用してコストカットを行いたいという目的でCanva布教説明会を開催しました。

Canva説明会では、便利な機能やデータの命名規則など基本的なことを説明しました。

ただ説明しても分からないので、実際にバナーを製作しながらCanvaの機能を説明してデモンストレーションを行いました。

このバナーを0から作るデモンストレーションを行いました!(このウェビナーは架空のイベントです。)

終わりに

デモンストレーションを行ったことでCanvaの魅力をより伝えることができてよかったです!

この説明会をきっかけにCanvaに切り替えてくれる社員が増えればいいなと思いました!

最後に、エキサイトではデザイナー、フロントエンジニア、バックエンドエンジニア、アプリエンジニアを絶賛募集しております!

興味があれば連絡いただければと思います🙇‍♀️

それではまた!

www.wantedly.com

第6回定期勉強会「CTOと討論会」

f:id:ixit_someya:20220324162159p:plain
第6回定期勉強会「CTOと討論会」
canva(https://www.canva.com/)より作成

こんにちは、iXITの染谷です。
3月の勉強会は「CTOと討論会」でした。
exciteHD CTOの藤田さんにエンジニアとしての在り方を語っていただきつつ、エンジニアの疑問に答えていただく貴重な機会でした!

CTOのお話

1. 芯となる思考・ビジョンを持つ

2. 組織の中での自分のアイデンティティを考える

3. 多くのことに好奇心を持つようにする

4. 強いメンタル

1. 芯となる思考・ビジョンを持つ

exciteHDであればデジタルネイティブ発想で心躍る未来を作る」など。
芯となる考えを持っておくことで、時代が変わっていっても、その考えを元に新しいものを生み出すことができる。

2. 組織の中での自分のアイデンティティを考える

エンジニアは先人たちが築き上げた様々な分野の知識を横断して用い、課題を解決する存在である。 そのため、コンピュータなどの知識のみならず、統計、経済、社会学など、あらゆる分野の知識が必要になる。
そのような知識を持っておくことで、応用が効くようになり、より柔軟で適切な課題解決方法を生み出すことができると考える。
エンジニアには既存のツールを使用するだけでなく、様々な学問の基礎を理解するように努めてほしいと考えている。

様々な分野への知識を持つことで、エンジニアとしてのアイデンティティが確立されるはず。

3. 多くのことに好奇心を持つようにする

様々分野を学ぶためには好奇心を持つことが肝要。 また、好奇心を抱くためには心身のリソースを常に確保しておくことも重要である。
好奇心の種を探すには、本やRSSリーダーSNSなどがおすすめ。
インプットと同時にアウトプットを行うことも重要。特に対象がソフトウェアなどPC上で完結するものなら実際に触るとより理解を深めるとこができる。

4. 強いメンタル

強いエンジニアには強いメンタル。
・誰よりも先に率先して行動を起こす
・環境に依存しない
・つらくなったら「1. 芯となる思考・ビジョンを持つ」の自分の目的に立ち返る

エンジニアとのQA

Q. 課題を紐解くときに、先人の知識を学ぶとのことでしたが、どのようにして知識集めするといいでしょうか?
(心理学、統計学をいきなり学ぶのはムズカシイので..)
A. 自分にとって不足している部分・知識を埋めるように情報収集する 自分の知らないことについて知る ネットなどで論文などを読む、本を読んで体型的に学ぶ、コードを書く(実践する)


Q. 藤田さんのお給料はどのくらい?
A. みんなが思っているほどはもらっていない笑
仕事でやりたいことができることを重要視しているので、ある程度の生活水準が満たせるお給料がもらえればいいと思っている。


Q. 今気になってる分野は何?
A. web3関連と量子コンピュータが気になっている。
web3はスマートコントラクト、NFT、暗号通貨などが特に面白いと思っている。
量子コンピュータは社会に与えるインパクトが大きく、プログラミングの形も大きく変わる可能性があり、面白い。

過去回

tech.excite.co.jp

tech.excite.co.jp

tech.excite.co.jp

tech.excite.co.jp

tech.excite.co.jp

Javaで形態素解析!SudachiをSpring bootで利用してみよう

こんにちは。いつものtaanatsuです。
今日はSpring bootにSudachiを入れてさっぱりさせていきたいと思います。
それではやっていきましょうか。

Spring bootの準備

Spring bootのプロジェクトはSpring Initializrを使うと楽に作れます。
ひとまず必要最小限で作っていきましょう。
Javaのバージョンはお使いの環境に合わせて選択してください!

f:id:taanatsu:20220317163617p:plain
Spring Initializr

GENERATEボタンを押下するとZIPファイルがダウンロードされるので
展開してIDEで開きます。
今回はIntelliJ IDEAで作業していきます。

IntelliJ IDEAだとGradleのくるくるボタンを押下すると、自動で必要なライブラリを集めてきてくれます。
便利ですね!

f:id:taanatsu:20220317163730p:plain
Gradle

とりあえずControllerを作ってみる

/src/main/java/com/example/demo/配下に、controllerディレクトリを作り、SudachiController.javaを入れます。
▼▼▼▼ f:id:taanatsu:20220317164809p:plain

SudachiController.javaの中身は以下のようにします。

package com.example.demo.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/")
public class SudachiController {
    @GetMapping("/")
    public String index() {
        return "hello";
    }
}

ここまでできたら右上の三角マークを押します。

f:id:taanatsu:20220317165309p:plain
実行ボタン

するとコンパイルされるので、待ちます。
コンパイルが終わると http://localhost:8080 にアクセスするとページが表示されると思います。

Sudachiを導入する

今回のSpring bootはライブラリ管理ツールに「Gradle」を使っているので、
以下の行をdependenciesの中に追加します。

implementation group: 'com.worksap.nlp', name: 'sudachi', version: '0.5.3'

f:id:taanatsu:20220317170209p:plain

その後、Gradleのくるくるボタンを押します。

f:id:taanatsu:20220317163730p:plain
Gradle

コレで準備完了です。

Sudachiの必要なもの(辞書など)を用意する

Sudachiを使うには、設定ファイルが必要です。
必要なのは「sudachi.json」と「char.def」です。
これらはSudachiのGitHubリポジトリから取得できます。

上記2つのファイルを
/src/main/resources/配下にsudachiディレクトを作成し、その中に入れます。

次に、形態素解析に必要な辞書「system_core.dic」を準備します。
この中の、どれでもいいですがひとまずsudachi-dictionary-latest-core.zipをダウンロードしてきます。
コレも解凍して、「system_core.dic」名前にして/src/main/resources/sudachi/配下に保存します。

f:id:taanatsu:20220317172501p:plain
Sudachiに必要なファイルの準備

コレで準備完了です。(2回目)

Sudachiで形態素解析をする

SudachiController.javaの中身を以下のように変えていきます。

package com.example.demo.controller;

import com.worksap.nlp.sudachi.Dictionary;
import com.worksap.nlp.sudachi.DictionaryFactory;
import com.worksap.nlp.sudachi.Morpheme;
import com.worksap.nlp.sudachi.Tokenizer;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/")
public class SudachiController {
    @GetMapping("/")
    public String index() throws IOException {
        // 形態素解析したい文章
        final String text = "こんにちは、世界";

        // 設定ファイルの読み込み
        final Path sudachiSettingJsonPath = new ClassPathResource("sudachi/sudachi.json").getFile().toPath();
        final String sudachiSettingJson = Files.readString(sudachiSettingJsonPath);

        // 辞書ファイルの読み込み
        final String sudachiDictionaryDirectory = new ClassPathResource("sudachi/").getFile().toPath().toAbsolutePath().toString();
        final Dictionary sudachiDictionary = new DictionaryFactory().create(sudachiDictionaryDirectory, sudachiSettingJson);

        // 形態素解析を行うインスタンスの作成
        Tokenizer tokenizer = sudachiDictionary.create();

        // 形態素解析の実行
        final List<Morpheme> tokenList = tokenizer.tokenize(Tokenizer.SplitMode.C, text);

        // 形態素解析の結果をとりあえず変形
        final String result = tokenList.stream()
                .map(morpheme -> morpheme.surface() + "は" + "「" + morpheme.readingForm() + "」と読み、品詞は「" + morpheme.partOfSpeech().get(0) + "」で、標準形は「" + morpheme.normalizedForm() + "」です。<br>")
                .collect(Collectors.joining());

        return result;
    }
}

そしてビルドボタンを押下し、コンパイル終了後に
http://localhost:8080 にアクセスしてみましょう!

f:id:taanatsu:20220317172929p:plain

形態素解析、されましたね!!

終わりに

自然言語処理系はPythonがやはり強いですが、
Javaでやると型がしっかりしていてその分保守性が上がりそうですね!

みなさんもぜひ、Javaでも自然言語処理をしてみてください。

……あ、今回はサンプルなのでControllerに全部処理を書いていますが、ServiceやRepositoryを使って分けて処理を書くほうがいいですね!
プロジェクトで使う際はご注意を!

それでは、また次回!

GitHubのIssueでは、Milestoneが役に立つという話

f:id:excite-takayuki-miura:20220323161337p:plain

こんにちは。 エキサイト株式会社の三浦です。

皆さんは、GitHubでIssueを使っているでしょうか? 今回は、Issueを使う場合、併せてMilestoneを使うのがオススメ、という話をします。

GitHubのIssue

GitHubには、Issueという機能があります。

コードを書いているときや使用しているときに、なにか問題や改善点を発見することもあると思いますが、そういった場合にIssueに書き込むことで、TODOリストとして保存しておくことや、他の人に問題点を共有できたりします。

非常に便利な機能なのですが、便利であるがために問題が発生することもあります。

f:id:excite-takayuki-miura:20220323145442p:plain

(当たり前ですが)Issueをたくさん使っていると、このように大量のIssueができてしまいます。

こうなると大変で、どのIssueを優先的に、いつまでに対応するべきかがとてもわかりづらくなってしまうのです。

そこで有用になってくるのが、「Milestone」という機能になります。

Milestone

Milestoneを作成し、各Issueに設定することで、文字通りそれぞれのIssueのマイルストーンを設定することができます。

f:id:excite-takayuki-miura:20220323162052p:plain

f:id:excite-takayuki-miura:20220323145703p:plain

f:id:excite-takayuki-miura:20220323161150p:plain

Milestoneのタイトルや説明に詳細を記し、オプションで日付を設定することで、そのIssueをどのタイミングまでにやるべきかを明確に示すことができるようになるのです。

またIssueの画面では、Milestoneでフィルタリングすることもできるので、特定のMilestoneのIssue一覧も簡単に出すことができ、管理が非常に容易になります。

f:id:excite-takayuki-miura:20220323161913p:plain

最後に

GitHubには様々な機能があります。

そのために使っていない機能がある場合も多いと思いますが、よく見てみると便利な機能がたくさんあったりするので、積極的に使っていきましょう!

Mockitoのテストをクリーンに保つための機能

はじめに

こんにちは、エキサイト株式会社でインターンをさせていただいている山内です。 今回はMockitoを使ってユニットテストを書いていた際に遭遇したUnnecessaryStubbingExceptionというエラーについてご紹介します。

状況

SpringBootでのサンプルコードは以下のようになっています。

// SampleRepository.java
public interface SampleRepository {
    Boolean hoge();

    Boolean fuge();
}
// SampleService.java
public interface SampleService {
    Boolean hoge();
}
// SampleServiceImpl.java
@Service
@RequiredArgsConstructor
public class SampleServiceImpl implements SampleService {
    private final SampleRepository sampleRepository;

    @Override
    public Boolean hoge() {
        return sampleRepository.hoge();
    }
}
// SampleServiceImplTest.java
@ExtendWith(MockitoExtension.class)
public class SampleServiceImplTest {
    @Mock
    private SampleRepository sampleRepository;

    @InjectMocks
    private SampleServiceImpl sampleService;

    @Test
    @DisplayName("サンプルテスト")
    public void sampleTest() {
        Mockito
                .when(sampleRepository.hoge())
                .thenReturn(true);

        Mockito
                .when(sampleRepository.fuge())
                .thenReturn(true);

        Assertions.assertEquals(true, sampleService.hoge());
    }
}

テストを実行すると、下記のようなエラーが出ます。

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.

原因

エラーログの通り、不要なスタブが定義されていることが原因です。

今回の例で言うと、SampleRepository.javaではhoge()とfuge()というメソッドが定義されていますが、SampleService.javaで使われているのはSampleRepository.hoge()のみです。つまり、SampleRepositoryImplTest.javaで定義されている以下の部分は今回テストしたいSampleService.hoge()では使われていないため不要なスタブとして検出されているのです。

Mockito
        .when(sampleRepository.fuge())
        .thenReturn(true);

スタブとは

スタブとは、テストしたい物とは別のメソッドの振る舞いを定義してあげるものです。つまり、テストしたいメソッド内で他のメソッドを呼んでいる場合に他のメソッドの動作を保証しなくてもテストが書け、それぞれのメソッドごとに動作を保証することができるというものです。

解決方法

解決方法はシンプルで、以下のように不要なスタブを消してあげるだけです。

// SampleServiceImplTest.java
@ExtendWith(MockitoExtension.class)
public class SampleServiceImplTest {
    @Mock
    private SampleRepository sampleRepository;

    @InjectMocks
    private SampleServiceImpl sampleService;

    @Test
    @DisplayName("サンプルテスト")
    public void sampleTest() {
        Mockito
                .when(sampleRepository.hoge())
                .thenReturn(true);

//        Mockito
//                .when(sampleRepository.fuge())
//                .thenReturn(true);

        Assertions.assertEquals(true, sampleService.hoge());
    }
}

その他の解決方法もあり、こちらのMockitoブログで言及されています。

なぜこのようなエラーを出すのか

このようなエラーを出している理由は、テストを読みやすく、クリーンに保つためです。 テストをクリーンに保つことで、そのテストで本当にしたいことが明確になり、見通しの良いコードになると思います。

最後に

このインターンを通して、「良いコードを書く」ということはとても難しく、日々意識して書いていくことで身に付いていくものだと実感しています。今回ご紹介したMockitoの不要なスタブの検証もその一歩になるのではないかと思っています。

まだまだ未熟ですが、これからも良いコードを意識して書いていきたいと思います!

最後までお読みいただきありがとうございました!

「WEラブ赤ちゃんプロジェクト」制作物の確認に京都へ!

f:id:excite_nishiba:20220315090111p:plain

こんにちは。エキサイト株式会社・デザイナーの西場です。

ウーマンエキサイト発足の『WEラブ赤ちゃんプロジェクト』という取り組みがあります。

woman.excite.co.jp

このたび、このプロジェクトに賛同いただいた
京都府子育て環境日本一推進会議様の制作物を現場にて確認するため
プロデューサー・ディレクターと共に京都へ行ってまいりました。

今回は20種類以上と制作物の点数も多く、
大きさ・掲載場所・素材等も多種多様だったので
見る方のシチュエーションなどを加味し、
適切な色味・内容・レイアウトについて都度チームで話し合い、検討しました。

しかし、印刷はデジタル媒体と違い
刷り上がるまでどのような色味になるのか正確にはわかりません。
素材によって仕上がりも違い
屋内・屋外の違いやライティングによって見え方も変わります。

実際に目にするまでは想像の範囲でしかなく、、、
緊張しながら見つけましたが
沢山掲示いただき、
仕上がりも綺麗で感動しました!


f:id:excite_nishiba:20220310155837j:plainf:id:excite_nishiba:20220310155841j:plainf:id:excite_nishiba:20220310155843j:plainf:id:excite_nishiba:20220310155846j:plainf:id:excite_nishiba:20220310155955j:plain


やはり社内で作業している時とは迫力が違いますね。

他社様の制作物と共に現場で確認することにより
メリハリによる明確な伝え方、素材ごとの適切な色味、設置場所への配慮、等
より良く改善していくための気づきもありました。

また、皆さまの目に触れている場面を見て、
改めて、子育てにやさしい社会づくりのお手伝いになれれば嬉しいな、と感じました。


この後も、ラッピングバスや商店街フラッグなど多く制作物が登場する予定で、
京都府子育て環境日本一推進会議×WEラブ赤ちゃんプロジェクト』は続きます。
ぜひ「泣いてもかましまへん!」と赤ちゃん、ママ・パパにエールを!

f:id:excite_nishiba:20220310154859p:plain

Spring Bootで、環境ごとに異なる値を持つモデルクラスを作るオススメ方法

こんにちは。 エキサイト株式会社の三浦です。

コードを書いていると、たまに環境ごとに異なる値を使いたくなるときがあります。 例えば、開発環境と本番環境で使用するDBが異なる場合は、DBのURLは環境ごとに異なるはずです。

今回は、Spring Bootでそのような環境ごとに異なる値をモデルクラス内で使いたい場合の、オススメの方法を紹介します。

環境ごとに異なる値

コードを書く時、たまに環境ごとに異なる値を使いたくなることがあります。 Spring Bootでは、そのような値を扱う方法の1つとして、 application.yml というものを提供しています。

例えば、 local 環境と prod 環境で別々の値を持ちたい時は、

application-local.yml

data_1: local_value

application-prod.yml

data_1: prod_value

というファイルを用意し、実行時にファイル名をそれぞれ指定すれば、コード内で data_1 を呼び出すと、指定したファイルの値を取得することができるようになるのです。

この application.yml 内のデータを、モデルクラスで使いたい場合があるとしましょう。 以下のような場合です。

public class SampleImageModel {
    /**
     * 画像ドメイン
     * TODO: ここに、application.ymlから値を持ってきたい
     */
    private String imageDomain;

    /**
     * 画像パス
     * この値は、DB等からとってきてそのまま入れる
     */
    private String imagePath;

    /**
     * 画像URLを取得する
     * @return 画像URL
     */
    public String getImageUrl() {
        return this.imageDomain + this.imagePath;
    }
}

方法はもちろんいくつかありますが、個人的にオススメの方法を紹介します。

オススメ取得方法

application.ymlの準備

まずは application.yml を環境ごとに用意します。 ここまでは同じです。

image:
  domain: https://sample/

コードからapplication.ymlのデータを呼び出す

続いて、コードから以下の方法で application.yml を呼び出します。

package sample;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

@ConstructorBinding
@ConfigurationProperties(prefix = "image")
@RequiredArgsConstructor
public class SampleImageConfig {
    /**
     * 画像ドメイン
     */
    @Getter
    private final String domain;
}

取得方法は他にもありますが、こうすることで、例えばスキーマは別管理にしたいときに、

package sample;

import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

@ConstructorBinding
@ConfigurationProperties(prefix = "image")
@RequiredArgsConstructor
public class SampleImageConfig {
    /**
     * 画像ドメイン
     */
    private final String domain;

    public String getDomain() {
        return "https://" + domain;
    }
}

こうできるなど、より柔軟性をあげることができたりします。

モデルクラスにデータを入れる

最後に、モデルクラスにデータを入れるには、Factoryクラスを使用します。

まずはモデルクラスで、コンストラクタからデータを入れられるようにします。

package sample;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class SampleImageModel {
    /**
     * 画像ドメイン
     * TODO: ここに、application.ymlから値を持ってきたい
     */
    private final String imageDomain;

    public SampleImageModel(String imageDomain) {
        this.imageDomain = imageDomain;
    }

    /**
     * 画像パス
     * この値は、DB等からとってきてそのまま入れる
     */
    private String imagePath;

    /**
     * 画像URLを取得する
     * @return 画像URL
     */
    public String getImageUrl() {
        return this.imageDomain + this.imagePath;
    }
}

その上で、Factoryクラスを作成します。

package sample;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class SampleImageModelFactory {
    private final SampleImageConfig sampleImageConfig;

    public SampleImageModel create() {
        return new SampleImageModel(this.sampleImageConfig.getDomain());
    }
}

これを作れば、後はこのモデルを生成したい時は、以下のようにすれば簡単に作れるようになります。

// SampleImageModelFactoryはDIして使う
SampleImageModel sampleImageModel = sampleImageModelFactory.create().setImagePath("sample/image.jpg");

この方法を取ることで、「ドメインをあらかじめ application.yml から持ってくる」などのことを考えずにモデルクラス使えるようになります。

最後に

今回は個人的なオススメ方法を紹介しましたが、あくまで個人的な考えのものであり、もしかしたらもっと良い方法があるかもしれません。 あくまで一例として参考にしていただければと思います。

【業務効率化】制作ヒアリングシートを復活させた話

f:id:excite_ny:20220310224627p:plain

こんにちは!21卒デザイナーの山﨑です。

今回は「制作ヒアリングシートを復活させた話」をしたいと思います。

制作ヒアリングシートって何?

制作ヒアリングシートとは、ビジネスやエンジニアがクリエイティブに仕事を依頼する際に記入するシートの事です。

ヒアリングシートに記入したらGoogleスプレッドシートに記入されるようになっています。

f:id:excite_ny:20220310125505p:plain

f:id:excite_ny:20220311122306p:plain
スプレッドシートに情報が反映される

何故使われていなかったのか?

去年の4月ごろにはすでに出来ていたシステムだったのですが、長らく放置されていました。

その原因は2つありました。

ヒアリングシートの質問数と回答必須項目が多く、記入側のモチベを低下させていた。

②「ビジネス側から仕事が来る」→「ヒアリングシートを渡す」という文化を定着しきれなかった為、活用の機会が失われていた。

質問の項目数を減らす

一番初めのヒアリングシートの項目数はざっと23項目ありました。

質問項目

  1. メールアドレス
  2. 案件名
  3. 納品物
  4. 制作の目的
  5. ターゲット
  6. コンバージョン
  7. SEO対策はするのか
  8. 必要な機能
  9. リリース予定時期
  10. 納品希望日
  11. 既存URL(あれば)
  12. 競合
  13. デザインテーマ、コンセプト
  14. 希望のイメージ(参考サイトなどURLあれば)
  15. 対応ブラウザ
  16. 希望のフォント
  17. サーバーの有無
  18. ドメインの有無
  19. ロゴデータの有無
  20. 画像や素材の有無
  21. 原稿データの有無
  22. SNSの有無
  23. そのほか特記すべきこと

かなり多いですね。

大体ヒアリングシートを記入する方は「作って欲しいものは決まってるけど、フォントとか雰囲気もよく分からない…」という方が大半だと思います。

そんなフワッとしたイメージのままで「競合は?サーバーの有無は?ドメインの有無は?画像や素材はあるの?」など質問攻めに合うと記入者のモチベーションは低下してしまいます。

f:id:excite_ny:20220310152400p:plain
困るビジネス

そこで、最低限の質問のみに絞ることでモチベ低下を防ごうと考えました。

f:id:excite_ny:20220310225231p:plain
質問数を減らしたヒアリングシート1

f:id:excite_ny:20220310225252p:plain
質問数を減らしたヒアリングシート2

f:id:excite_ny:20220310225304p:plain
質問数を減らしたヒアリングシート3

質問項目

  1. 案件名
  2. 納品物
  3. 納品希望日
  4. 制作の目的
  5. ターゲット
  6. 必要な機能
  7. コンバージョン
  8. SEO

23項目から8項目、名前やメールアドレス・デザインイメージなどを約三分の一まで減らしました。

そして従来ではセクションも分けないものになっていたのですが、こまめにセクションを分ける事でサクサク画面遷移で切替えられるようにしています。

slackの通知機能をつける

二つ目の『「ビジネス側から仕事が来る」→「ヒアリングシートを渡す」という文化を定着しきれなかった為、活用の機会が失われていた。』に関しては、

ヒアリングシートに記入されても通知がない

②ビジネス側への周知が薄い

というのが原因でした。

その問題を解決するために以下の施策を行っていただきました。

ヒアリングシートが記入されたらslack通知がチャンネルに行く

②事業部の締め会でヒアリングシートの周知を広める

f:id:excite_ny:20220310230622p:plain
ヒアリングシートに記入されたらslackのチャンネルに通知が行く様子

f:id:excite_ny:20220310231552p:plain
締め会で発表する様子

この2つの施策を行い、デザイナー個人にDMで仕事が来て「誰がどんなタスクを負っているのか・誰の手が空いているのかわからない」という問題を解消し、

①ビジネスorエンジニアがヒアリングシートで依頼する

②クリエイティブ全体で仕事を誰が担当するか話し合う

アサインされたデザイナーと依頼者で再度ヒアリングを行う

このような「クリエイティブ全体で仕事を受ける流れ」を作っていけたらいいなと思います。

終わりに

最後に、エキサイトではデザイナー、フロントエンジニア、バックエンドエンジニア、アプリエンジニアを絶賛募集しております!

興味があれば連絡いただければと思います🙇‍♀️

それではまた!

www.wantedly.com

認証・決済APIの移行を無事完了しました(Yahoo! ID連携v2移行)

エキサイトの菅間です。 普段は、電話占い・お悩み相談室・恋ラボなどのToC向け課金プラットフォームの開発を行っています。

今回、Yahoo! ID連携 v1のクローズに伴うv2への移行を担当し、認証・決済に関するAPIのエンドポイントの移行を無事に完了したので振り返りをしたいと思います。

プロジェクトの背景

Yahoo!版電話占いはYahoo! ID連携を使ってログイン機能、コイン購入機能を実装しています。 今回は、Yahoo! ID連携 v1のクローズに伴うv2への移行を担当しました。

プロジェクトの概要は下記の通りです。

  • プロジェクト期間:2021年11月 ~ 2022年2月
  • プロジェクトのゴール:問題を発生させずプロジェクトの移行を完了させる。

プロジェクトは、自分1名で主導して行いました。 全体の進捗はマネージャーと企画の方に相談、コードレビューや相談は事業部の開発メンバーに相談しながら進めました。

移行の対象

  • Yahoo! ID連携 v2への移行
    • エンドポイントの切り替え
      • 認証
      • 決済
  • APIのレスポンスの変更とそれに伴う改修

移行の結果

  • Yahoo! Wallet API移行:1月に移行完了
  • Yahoo! ID連携v2移行:2月に移行完了

結論としては、本記事執筆時点ではトラブルが発生することなく、運用ができています。 また、不要なファイルも900ファイル以上削除することができました。

プロジェクトの移行が完了したので、振り返り・反省を行っていきたいと思います。

良かった点

まずはプロジェクトの良かった点を振り返りたいと思います。

  • 問題が発生することがなく、プロジェクトを移行できた。
  • リファクタリングを進めることができた。
  • 認証・認可・OAuth2.0周りに関してキャッチアップできた。

問題が発生することがなく、プロジェクトを移行できた。

プロジェクトのゴールである「問題を発生させずプロジェクトの移行を完了させる。」ことが達成できたのが1番良かったです。

無事に移行を完了させるために下記点を意識しました。

タスクの管理

以下理由でプロジェクト管理にスプレッドシートを活用しました。

  • 企画の人にも進捗を共有する。
  • 社内の別プロジェクトでも使われているため導入コストが軽い・ある程度最適化されたテンプレートが存在する
  • 無料
  • その日からすぐ使える

スケジュール管理

タスクを細分化して、それぞれに期限を設けるのですが、「アラートを出すタイミング」は意識をしました。 スケジュールの進捗が遅れた場合は、都度上長へ相談・共有を行いました。

今回のプロジェクトでは、Yahoo社から配布されるSDKのリリースが遅れた関係もあり、当初の期限では厳しくなりました。 その際もいち早く上長に相談し、先方とスケジュール調整に入ることができました。

リスク管理

スケジュールに間に合いそうにない場合の解決策としてメンバーの増員が考えられます。 仮にそのような状況になった場合に、素早くプロジェクトの概要を掴んでもらうためにGoogle Driveにドキュメントの一元管理・整備を行いました。

また、Pull Requestを事業部の幅広いメンバーにお願いし、何となくプロジェクトを知ってもらえるようにしました。
(レビューしてくださったみなさんありがとうございます。)

リファクタリングを進めることができた。

今回の移行対象のリポジトリには2つのサービスが同居していました。 1つはサービス終了済みなため、サービスは動いていないが、コードは残っている状態でした。

検索でヒットする、初見の人が困惑するなど開発者体験が良くないため、今回の移行に伴いほぼ全て削除しました。

認証・認可・OAuth2.0周りに関してキャッチアップできた。

プロジェクトというより個人的な良かった点なのですが、認証認可に関しての改修経験を積むことができました。

qiita.com

反省点

次に、プロジェクトの反省点を振り返りしたいと思います。

  • スケジュールの不確実性を明らかにすることにもっと着手すべきだった。
  • プロジェクト初期に客観的なフィードバックを経験者である先輩にもっと早くもらうべきだった。

スケジュールの不確実性を明らかにすることにもっと着手すべきだった。

プロジェクトの初期は、わからないことがたくさんあります。
どれくらい時間がかかるのか、見積もりが問題がないのか?など解像度が低い状態です。

今回は、サービスの開発やSEO系のタスクも並行して行なっており、プロジェクト初期に初速を出すことができませんでした。
初速が出せないリスクとして、何かあったときの対応が後手に回ってしまいます。

そのため、上長と既存のタスクの調整をし、初速を出すことに注力すべきでした。
次回からは、プロジェクトのタスクを網羅する、鍵となりそうなタスクを仕分けする、ざっと見積もりをする時間を確保する動きをしたいと思います。

プロジェクト初期に客観的なフィードバックを経験者である先輩にもっと早くもらうべきだった。

社内には様々なプロジェクトをこなしてきた先輩がいるので、もっと早い段階で巻き込むことができたら、よりスムーズに進めることができたと思います。

プロジェクトの振り返り

1人プロジェクトでしたが、事業部の先輩とプロジェクトの振り返りを行いました。 客観的にフィードバックを以下のようにいただきました。

良かった点

当事者意識を持ってプロジェクトの移行を完遂した。

  • 先方の担当者とメールのやり取りを率先して行った。
  • 古いソースコードの削除やリファクタリングなどを主体的に行った。
  • 関連する箇所のドキュメントの更新を行なっていた。

また、以下のようなフィードバックを総会でいただきました。

YahooSDKバージョンアップにおいて開発による実装だけで無く、当事者意識でyahoo担当者と密に連絡を取りバージョンアップ完了不具合も無く、うやむやになっていた連携部分の仕様が整備されました

.

自ら能動的に動き、施策にも細かく丁寧に向き合っている姿勢が素晴らしく、Yahooのv2移行について、先方との調整も含めてスピード感をもって対応しています

プロジェクトの進め方が良かった。

  • 計画書、テスト項目、タイムテーブルなどの資料を作成・共有し、緻密にスケジュール管理ができていた。
  • 様々な人にレビューをお願いすることによって、プロジェクトを知ってもらい、巻き込むことができていた。リスク管理として良かった。

カンファレンスへの登壇や既存の運用系も積極的に行なっていた。

  • 移行のプロジェクトだけではなく、それ以外のタスクも行なっていた姿勢が良かった。

tech.excite.co.jp

改善点

プロジェクトの初速が出ておらず、初期はプロジェクトが不透明だった。

「1人でやれらないといけないことだが、もっと周りの人を頼っても良い」とのことでした。

目的はプロジェクトを無事に完了させることなので、目的意識が大事ですね。

概ね、先ほどの反省点で出た内容を振り返りました。

最後に

そんなエキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。

www.wantedly.com

Terraformのディレクトリ構造と設計指針の一例を紹介します

エキサイト株式会社の武藤です。

エキサイトではAWSの構成管理にTerraformを採用しているサービスがいくつかあります。 Terraformのディレクトリ構造について検索してみると、様々なパターンが出てきます。 どのパターンが最適なのか、選択に迷ってしまう方も多いと思います。 今回は私が担当しているE・レシピについて、ディレクトリ構造と設計指針を紹介します。参考になれば幸いです。

全体構成

まずはディレクトリの全体構成についてです。

├── application
│   ├── web_server   // EC2作成
│   │   ├── dev
│   │   │    └── v1
│   │   └── prod
│   │      └── v1
│   └── modules   
├── gateway
│   ├── web_alb     // ALB作成
│   │  ├── dev
│   │  │    └── v1
│   │  └── prod
│   │     └── v1
│   └── modules 
└── infra
   └── vpc           // VPC作成
        ├── dev
        ├── modules
        └── prod

一例として、インフラリソースの作成単位にVPC、EC2、ALBがあるとします。 それぞれに対して、infra, application, gatewayというレイヤーを設けており、ディレクトリもそのように階層を分けています。 VPCは、最初に作られるインフラリソースです。その後、EC2、ALBの作成が行われます。 作成するリソースに依存関係があるように、レイヤーにも依存関係を考えます。

  • infra : VPC作成
  • application : EC2作成
  • gateway : ALB作成

このように依存関係があることで、作成するインフラリソースの順番、破棄する順番を示して、運用ルールとしています。 新しくインフラリソースを追加する際は、どこのレイヤーに依存しているかを考えてディレクトリを追加します。

moduleディレクトリは、基本的に各レイヤーごとにmoduleを作るようにします。 moduleが使われる範囲を狭めて、管理しやすくしています。

workspace 機能を使わない

Terraformには環境ごとの構成差分を管理するためにworkspace機能が用意されています。 しかし、弊チームでは可読性やわかりやすさを重視するため、workspace機能を使わずにディレクトリ階層によってdev, prodを分けています。 ディレクトリで示すことで、ひと目で環境差異が把握できる点、map関数、lookup関数を使わずにシンプルに書ける点があります。 (メンバーのTerraform習熟度が高ければ、workspaceを使う方が効率的なケースもあると思います。)

ディレクトリの環境分けの方法では重複コードも出てきますが、そこは諦めています。。

module化するタイミング

公式ドキュメントの考え方に則って考えています。 www.terraform.io

過度にmodule化すると全体構成が複雑になってしまい、メンテナンスしにくくなってしまいます。

We do not recommend writing modules that are just thin wrappers around single other resource types. If you have trouble finding a name for your module that isn't the same as the main resource type inside it, that may be a sign that your module is not creating any new abstraction and so the module is adding unnecessary complexity. Just use the resource type directly in the calling module instead.

上記では、リソースの薄いラッパーになるようなmodule化は推奨しないと説明しています。 基本的には複数のリソースを意味のある単位でmodule化しています。

moduleを定数として扱う

過度なmodule化に注意しつつ、極力重複する記述は避けたいところです。 AWSの場合は、セキュリティグループの設定が様々なリソース作成のたびに出てきますので、共通化したい設定の一つです。 セキュリティグループのインバウンド, アウトバウンドルールは、社内オンプレからのアクセス、AWSネットワークからのアクセスなど、同じIPレンジを使うことが多いので共通の定数として扱います。

下記は、定数を出力するだけのmoduleを作成し、リソースで読み込むサンプルコードです。

├── constants
│   ├── output.tf
│   └── security_group_rules.tf     // セキュリティグループに関する定数
# security_group_rules.tf
locals {
  # エキサイトAWSネットワーク
  security_group_excite_aws_network = {
    from_port = ****
    to_port   = ****
    protocol  = "tcp"
    cidr_blocks = [
       ***.***.***.***/**,
       ***.***.***.***/**,
       ***.***.***.***/**
    ]
    description = "hogehoge"
  },
  # ICMP
  security_group_icmp = {
    from_port = -1
    to_port   = -1
    protocol  = "icmp"
    cidr_blocks = [
      "0.0.0.0/0"
    ]
    description = "ICMP Rule"

  }

...
}
# 定数を読み込むリソースファイル
module "constants" {
  source = "../constants"
}

module "ec2" {
  source = "../modules/ec2"

...

  security_group_rule_ingress = [
    module.constants.security_group_excite_aws_network,
    module.constants.security_group_icmp,

  ]

...
}

Terraformのlocal valuesの場合、外部からの入力できなくなるため、定数の用途で扱えます。

下記の記事を参考にさせていただきました。 qiita.com

最後に

Terraformのディレクトリ構造と設計指針について、一例を紹介しました。

今回は、可読性やわかりやすさを重視したディレクトリ構造と設計指針で実装を進めました。 何を重視するかはチームメンバーやサービスによって変わると思います。 メンバーと話し合いながら、運用しやすいTerraformを書きましょう。

参考記事

www.terraform.io

qiita.com

AWS GlueでSparkのDataFrameとしてOracleテーブルの情報を取得する

f:id:e125731:20220309103322p:plain

エキサイト株式会社 エンジニアのあはれん です。

弊社では、アプリケーションのデータベースとしてはAmazon RDS for Oracleを利用し、 データ分析にAmazon Redshiftを使っています。

Amazon RDS for Oracleデータ(データストア)からAmazon Redshift(データターゲット)にデータを転送するため、AWS Glueを利用しています。

今回は、AWS Glueを使ってデータを転送する際に発生した問題とその対処方法について説明します。

問題

AWS Glue ジョブを実行時に以下のエラーが発生しました。

pyspark.sql.utils.IllegalArgumentException: Oracle identifier cannot be more than 30 characters. 

Oracleの識別子(テーブル名)が30文字を超えている」というエラーです。

Oracle 12cR1以前は30文字以内という仕様になっていましたが、Oracle 12cR1以降は128文字まで利用可能になっています。 弊社で利用しているOracleは12cR1以降のものでしたので、アプリケーションで使っている時は128文字でも利用できていました。

この件をAWSのサポートセンターに相談したところ、 2022年3月時点では、 GlueのJDBCドライバーの接続種別(connectionType)Oracleを指定した場合、 Glue サービス側で当該エラーを出力している状況となっており、利用者側から回避することができないという回答をいただきました。

対処方法として、SparkのDataFrameとしてOracle テーブルの情報を取得する方法を提案いただきました。

これまでは、GlueのJDBCドライバーを利用して設定したデータカタログからOracleテーブルの情報を取得していましたが、 SparkのDataFrameとしてOracle テーブルの情報を取得することにしました。

対処方法

df = spark.read \
    .format("jdbc") \
    .option("url", "[JDBC データストアのURL]") \
    .option("dbtable", "[テーブル名]") \
    .option("user", "[データベースのユーザ名]") \
    .option("password", "[データベースのパスワード]") \
    .load()

SparkのDataFrameの取得方法は上記のようになります。 詳細は以下のドキュメントを参照ください。

spark.apache.org

JDBC データストアのURLについてAWS公式が、データベースエンジンごとの構文を紹介しています。

Oracleの場合は以下の構文パターンになります。

jdbc:oracle:thin://@host:port/service_name
jdbc:oracle:thin://@host:port:SID

docs.aws.amazon.com

SparkのDataFrameとしてデータを取得後は、AWS Glueで利用されているDynamicFrameに変換します。

DynamicFrame.fromDF([変換するDataFrame],[GlueContextクラスオブジェクト],[結果の DynamicFrame の名前])

docs.aws.amazon.com

DynamicFrameに変換後は、Glueで自動生成されてるスクリプトと同じ処理を行うことができます。

コード例

import sys

from awsglue.context import GlueContext
from awsglue.dynamicframe import DynamicFrame
from awsglue.job import Job
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# SparkのDataFrameとしてOracle テーブルの情報を取得する
df = spark.read \
    .format("jdbc") \
    .option("url", "[JDBC データストアのURL]") \
    .option("dbtable", "[テーブル名]") \
    .option("user", "[データベースのユーザ名]") \
    .option("password", "[データベースのパスワード]") \
    .load()

# DataFrameをDynamicFrameに変換
datasource0 = DynamicFrame.fromDF(df, glueContext, 'datasource0')

// 以降はGlueで自動生成されてるスクリプトと同じ処理で問題ない
applymapping1 = ApplyMapping.apply(....

その他

ジョブのバージョンや利用言語について

Glue version :Glue 2.0 - Support spark 2.4, Scala 2, Python 3
Language: Python 3

Glueの接続

AWS Glue ジョブはAWS Glue 接続を使用して特定の種類のデータストアにアクセスします。 今回の場合も、Amazon RDS for Oracleデータ(データストア)にアクセスするために設定しました。設定方法に関しては以下を参照ください。

docs.aws.amazon.com

最後に

同じエラーが出た方のお役に少しでもなれたらと思います。 最後まで読んでいただきありがとうございます。

エキサイトではデザイナー、フロントエンジニア、バックエンドエンジニア、アプリエンジニアを絶賛募集しております! 興味がありましたらご連絡ください。

www.wantedly.com

【Excite × iXIT TechCon2022】Core Web Vitalsの取り組みに関してLTをしました。

f:id:excite_sugama:20220303165158p:plain

エキサイト株式会社L&C事業部の菅間です。 普段は電話占い・お悩み相談室・恋ラボといったToC向け課金プラットフォーム事業の開発に関わっています。

今回はExcite × iXIT TechCon2022に「終わらないSEO対策と向き合うために」というテーマでLTを行いました。

Excite × iXIT TechCon2022とは?

詳しくはこちらの記事をご確認ください。

tech.excite.co.jp

終わらないSEO対策と向き合うために

発表内容の結論としては、システムは日々成長し、変化するため、一時的な対策では意味がなく、改善し続ける体制・文化の構築が必要になるという主張で発表をしました。

発表内容の本編は下記で公開しています。

speakerdeck.com

LTを振り返って

今回、登壇者には参加者からのフィードバックをもらえる仕組みとなっていました。

  • 現在SEOに関するタスクをしているので、非常に為になった
  • 資料がとてもわかり易く、発表もハキハキとして聞き取りやすく、締めの宣言もナイスでした。
  • 単純に対策というより、悪化の要因からの仕組み作りっていうまとまりかたがよかったです

など、30を超えるフィードバックをいただけました。 発表した良かった!と思えるので素敵な仕組みですね。

今回をきっかけに外部発信の機会を増やしていこうと思います!