トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

トレタのテックトーク -リモートワークの環境の作り方-

こんにちは。トレタ PjMの藤田です。先日の投稿に引き続き、トレタで長年行われているテックトークという開発メンバーによるフリートークの場について紹介します。

テックトークとは

隔週に一回開催し、当番の発表者が最近の気になる技術情報であったり、業務する中での技術的な学びを社内に発信する場です。 全体30分の前半はLT(ライトニングトーク)、後半はその内容について参加者内で議論、という形式で行なっています。

今週のテックトーク

今週の発表者はサーバーサイドエンジニアの森田さんです。森田さんのご自宅の開発環境(物理)についてご紹介いただきました。基本的な仕事環境として、森田さんが普段使っている、Mac(Macbook ProとMac mini)やディスプレイ(2枚)、キーボード、椅子、Webカメラ、ヘッドフォンなど紹介いただきました。

森田さんの環境

中でもリモートワークならではのポイントをピックアップして、いくつか紹介します。

1. ディスプレイの使い分け

2枚のディスプレイを使われているので、どんな使い分けをされているのか伺ってみました。32インチの4Kディスプレイ(メイン)は、ブラウザ、IDE、など主に開発系のウィンドウ。Macbook Proは、Slack、Google Meet、画面共有するタブ、などコミュニケーション関連のウィンドウ。27インチの縦置き4Kディスプレイは、サブディスプレイとして、メモ書きや、ChatGPT、Spotify、Twitterなど、業務を補助するツールのウィンドウを配置しているそうです。

リモートワークだとSlackやGoogle Meetで会話しながらコードやドキュメントを確認するシーンが結構あるので、ウィンドウが複数あると重宝しますし、人それぞれの使い方のコツがありそうですね。

2. 昇降デスクでスタンディング

またリモートだと座りっぱなしになりがちなので、会議中はスタンドで作業されているそう。FlexiSpot E7Hのブラック(160×70×2.5cm)を使用されているそうです。注文時に追加料金で、「らくらく家財宅急便」を頼んだが、プロが2人がかりで40分のなかなか大変な作業だったので、頼んでよかったそうです。

私も最近、昇降デスクやスタンディングで作業するためのツールを検討していて、参考になりました。

3. 仕事前に軽くにストレッチ

プランクや腕立てなどの軽い筋トレ、ストレッチポールでの肩甲骨剥がし、柔軟ストレッチなどトータルで30分ぐらいストレッチをしてから仕事を始めているそうです。以前は整体に通っていたけど、引越してストレッチを始めてから通わなくて良くなったそう。

ずっと同じ姿勢だと肩も凝りますし、可動域も狭くなるので、私も適度にストレッチをしています。

4. 温度湿度計で環境管理

暑い時は気温ではなく、意外と湿度の場合があるので、その時は湿度を下げたりして対応しているそうです。実は私も同じ温度湿度計を持っているのですが、季節の変わり目などで服を変える際の参考にしたり、外気と室内温度はまたちょっと違うので温度湿度計は結構便利です。

まとめ

自分でも日々環境づくりは気にしていますが、他のメンバーの環境を覗いてみると、自分とはまた違う部分もあり参考になりました。トレタは全社リモートワークなので、「リモート手当て」いう福利厚生があり、毎月定額が給与と一緒に振り込まれます。それらを活用して各々が工夫して自分の仕事環境を作っています(PC等仕事に必須のツールは支給されます)。

トレタでは一緒に働くメンバーを募集しているので、フルリモートで仕事してみたいエンジニアの方は是非一緒に働きましょう!

紹介いただいたグッズの詳細

週報のすすめ

こんにちは、トレタ VPoEの北川です。

開発部の取り組みとして、週報を書くことを始めました。

週報とは、いわゆる業務内容の報告を週の終わりに記載し提出するものです。 日報でもよかったのですが、あまり負担にならないように週報にしました。 まだ始めたばかりなので取り組みの結果はまだわかりませんが、なぜ週報を始めたのか、目的や意図についてこのブログに書こうと思います。

自分のための週報

週報をやろうと思ったきっかけはこちらのブログです。

kakehashi-dev.hatenablog.com

こちらを読んでから自分でも実際に日報を書くのを数ヶ月やってみました。

始めたのが自分がVPoEになったタイミングでもあったので、自分が普段何をやっているのか、何を考えて行動しているのか、というのをメンバーに向けて発信する目的でやってみました。

実際にやってみて良かったのが、日々の振り返りをするきっかけとなることです。

マネージャーになると、いろいろな人と都度コンテキストスイッチをしながら会話をしているので、一日の終わりの時間になると午前中の会話を忘れていたりします。

その中で1日の終わりにやったことを書き出して(たまに忘れて次の日の朝に書いたり)、そこから何がわかったのか、どういう思考プロセスをしたかを書いていくと自分の頭の中が整理されます。その場では深く考えられなかったことも、この振り返りの時点で整理していくと新しくわかることもあります。

あわせて次やることも書き出していくので、明日やることがクリアになり、一旦頭から離せるので気も楽になります。

自分だけではなく部内のメンバーに制度としてやってもらう目的の一つはこの「振り返り」をやってもらうことです。今日一日の業務を振り返ってみて、何か新しい気づきはあったか、何か試してみて成功した/失敗したことがあったかを振り返る。何かあれば整理して言語化をして書く。そうすることで「経験」したことをしっかりと「経験値」として身につける手助けになってくれると考えています。

もし何も書くことがないな、となればそれは無関心に物事をすすめてやり慣れた方法で一日を過ごしただけかもしれません。物事の捉え方ややり方を見直すチャンスにもなります。

言語化」というのも一つ大きな目的です。日常的にチーム内で会話はしますが、自分が考えていることを文章としてアウトプットする、という機会は意外と少ない気がします。この開発者ブログもアウトプットを行う一環ですが、なかなかメンバー全員が頻度高く更新することが今は行えていません。

言語化する能力はとても重要だと考えていて、チームメンバーに齟齬なく漏れなく適切に伝えたり、ミーティングで相手の立場に立ってわかりやすく伝えたり、コーディングも基本的には人が読むものなので正しく言語化されたものをコードとして表現する必要があります。

文字にして伝える能力はすぐに身につくものではなく日々続けて磨かれるものなので、週報で自分の考えを短くても常に言語化して書く習慣になればと考えています。

みんなのための週報

週報は専用のSlackチャンネルがあり、フォームに入力して投稿する形式にしています。

テンプレートは前述のブログのテンプレートを参考にしています。

  • 今週やったこと:今週行った業務を書き出します
  • わかったこと:やったことからそこで得た気づきや考えたことなどを書きます
  • 次やること:今週の続きの業務や予定されている次の業務、わかったことから繋がったNextAction」を書きます
  • ひとりごと:雑談です。今日あった小さな幸せでもいいし、プライベートなことでもなんでも

投稿された内容はSlackチャンネルですべて一望できる形になっています。そのため他の人が書いた週報もすべて見ることができます。

自分が日報をやっていて良かったことの一つに、他の人が日報見ていてくれていて情報や考えが広く共有されていることです。

「日報にあったあれを今日やると思うんですけど」とか、「日報で言ってたあれのことですよね」とか、思わぬところで伝わっていて関連情報を教えてくれたり、説明が省けたりすることがありました。

ミーティングなどで特定の関係者内で共有するのとは異なり、皆が不特定多数に共有することであまり接点の少ない人にも伝わったり、逆にその人の動きもよく見えてくるようになります。そういった環境になることで、自分がサポートできる人を見つかったりサポートしてもえらったり、横のつながりの柔軟度があがると考えています。

さいごに

ということで週報を始めてみて三日ぼうずで終わるかもしれませんが、個人的にはみんなのひとりごとを読むだけでも面白いので、長く続くといいな、と思っています。

奥野さんと社員のリファクタリング部屋 -ディレクトリの名付け方

「奥野さんと社員のリファクタリング部屋」は、リファクタリングに励むトレタの社員と技術顧問の奥野さん ( @okunokentaro ) の間で実際に行われた会話を切り取った開発現場実録コンテンツです。

技術顧問: 奥野さん
三度の飯よりリファクタリングが好き
今回の質問者: 武市さん
トレタ在籍2年。沖縄在住のフロントエンジニア

今回の質問

前回に引き続き、Webアプリケーション (Next.js) のプロダクトのリファクタリングを進めている武市さんから、ディレクトリ構造のリファクタリングについての質問です。

tech.toreta.in

前回の指摘も踏まえて、新しいディレクトリ構造とその定義を考えてきました。


┗ server
 ┃ ┣ boundary -- 外部システムとのやり取りを行うためのエンドポイント。
 ┃ ┃ ┗ mojito
 ┃ ┃ ┃ ┗ mojitoClient.ts
 ┃ ┣ handlers -- リクエストやエラーのハンドリングを行う。具体的には、HTTPリクエストを受け取り、適切なユースケースを呼び出して処理結果を返す。
 ┃ ┃ ┗ item
 ┃ ┃ ┃ ┣ delete
 ┃ ┃ ┃ ┃ ┗ deleteHandler.ts
 ┃ ┃ ┃ ┣ get
 ┃ ┃ ┃ ┃ ┗ getHandler.ts
 ┃ ┃ ┃ ┗ put
 ┃ ┃ ┃ ┃ ┗ putHandler.ts
 ┃ ┣ models -- BFF固有のオブジェクトやエラーを定義する。
 ┃ ┃ ┗ conflictError.ts
 ┃ ┣ repositories -- データの永続化層とやり取りを行う。データベースや外部APIとの通信を担当。
 ┃ ┃ ┣ daleteItem
 ┃ ┃ ┃ ┣ adaptResult
 ┃ ┃ ┃ ┗ delete.ts
 ┃ ┃ ┣ getItem
 ┃ ┃ ┃ ┗ get.ts
 ┃ ┃ ┗ updateItem
 ┃ ┃ ┃ ┣ adaptResult
 ┃ ┃ ┃ ┗ update.ts
 ┃ ┗ useCases -- ドメインロジックを含む。ビジネスルールを実装し、リポジトリと連携してデータの取得、更新、削除を行う。
 ┃ ┃ ┗ item
 ┃ ┃ ┃ ┣ deletItem.ts
 ┃ ┃ ┃ ┣ getItem.ts
 ┃ ┃ ┃ ┗ updateItem.ts

ディレクトリを分ける目的を考える

奥野 まず、「ディレクトリを細かく作りたいのはなぜか」という本質に立ち替えってみましょう。例えば、srcっていうディレクトリに全てのファイルが全て兄弟で並んで、何百個というファイルがフラットに並んでいても別に構わないし、そういった構造をとることが可能か不可能かでいったら、可能ですよね。

でも、なぜそうはしたくないのか、なぜファイルを分けたくなるのか、というところを考えてみましょう。それもファイル名のアルファベット順で分けることだってできるのに、なぜboundaryに分けてhandlersで分けるのか、というところですね。

こういった分け方をするのであれば、ディレクトリを分けるルールを決めるだけではなく、そのルールに従い続けられる環境をどうやって構築して、その環境を維持するかも一緒に議論しないといけません。

つまり、ディレクトリを分けたら終わりではなくて、今後作るファイルをディレクトリ分けのルールに従わせ続けることが目的ですよね。ディレクトリの分け方を決めて満足してはダメで、1年後、2年後まで維持し続けられるのか、どうやってルールの適用を自動化するかを考えましょう。そう考えた時に、このディレクトリのルールをどうやって守り続けますか?

武市 これは奥野さんのプロジェクトを参考にさせていただいてますが、参照可能なディレクトリの範囲を決めて、それ以外を参照してた場合にはCIの時点で落とすっという処理が、僕も適切だと思っています。(編注:eslintなどのルールを組み合わせることを指しています。)

今回で言うと、例えばここではserverの配下にmodelsというものがありますが、このserver配下のmodels内のファイルはserverより上のディレクトリのファイルは参照してはいけない、というルールは簡単に導入できるなと考えていました。

奥野 そうですね。 その場合、依存のルールを厳しめに作り、依存の方向に制約をかけることでなにが嬉しいかというと、例えばテストを作る時の負担が減りますね。「このレイヤーにテストを書きたい」と考えた時に、「どのレイヤーはモックにしよう」という方針をたてやすくなる。

守られていなかったら、ファイルごとにものすごく激しい密結合を生んでいるファイルもあれば、ちゃんと疎結合になってるファイルもあればで、ファイルの実装を一個一個読んでいかないとテストの方針が立てられない。依存のルールが決まっていることによって、このディレクトリに入っているファイルだったら依存のルールが統一されているお陰で、一つのテスト方針でディレクトリ内全てのファイルに対してテストが同じように繰り返し作成できる、という流れに繋げられる。

モックをどういう粒度で作っていくか考える時に、依存の粒度が揃っているのはすごくテストを書く上で扱いやすくなりますね。

それって本当にリポジトリ?

奥野 こういうディレクトリに分けをするときは、「分けて満足してはダメで、分けた後にそれを維持し続ける仕組みをどうやってメンテナンスするか」がとても重要になってくる。

そう考えると、今回の分け方で妥当なのかっていうと、boundary以外のhandlers models repositories useCasesはちょっと怪しいなって思っています。特にrepositoriesで分ける必要に本当にあるのか、という部分。

useCasesboundaryが分かれていればそれで十分なのではないかという考え方も自分は持っていて。repositoriesで分けたい理由が明確になってないうちにrepositoriesというディレクトリを置くルールに決定してしまうと、そこを中心にテストでモックを準備したり、なにかのファイルを作成するときに要らぬ手数が増えたりすることになるのではないかという懸念があります。 useCasesboundaryで十分なところに、わざわざリポジトリを設けることで迂回して遠回りすることになりかねないから、そのrepositoriesで分けたい理由はちゃんと聞いておきたいです。

武市 はい、useCasesはバックエンドから返ってくるものを扱うので、モックするのが正直面倒だと思っています。useCasesはビジネスロジックを中心に扱いたいので、バックエンドからどんな値が返ってくるかまでをモックしたくないな、と考えました。

奥野 なるほど。でもuseCasesのテストでバックエンドをモックをしたいなら、この場合boundaryをモックすれば十分とも見られます。なのでuseCasesboundaryの間にrepositoriesを置きたいという価値はちゃんと議論しましょう。

武市 useCasesでやることの中には、repositoriesgetItemとかdeleteItemを両方呼ぶ可能性もあります。

例えば、updateItemのユースケースの場合、名前がすでに使われていないかデータベースに一回取得しにいくので、updateItemのユースケースの中ではリポジトリのgetItemも呼ぶ必要があります。

そのような場合にリポジトリを分けておけば、汎用性高く使いまわすことができるというのがuseCasesrepositoriesを分けるメリットかなと思ってます。

奥野 それはリポジトリという名前で呼んではいるけど、Repository Patternの踏襲にはなっていなくて、あくまでもuseCasesの中の共有処理に過ぎないのでは、と感じました。 全体のユースケース = シナリオのように扱える部分があって、粒度の細かいユースケースを組み合わせて一つの大きなシナリオを組み立てているという感じですね。なので今のディレクトリ構成案では、repositoriesが最小のユースケースであり、useCasesと今呼んでいるものはもっと大きいシナリオのような粒度ではないかと思いました。

ということは「ユースケース」という言葉に対する認識が自分と武市さんの間で揃っていないし、「ユースケース」という言葉の粒度を定義しないとチームの他のメンバーにも伝わりにくくなってしまいます。

意味が伝わりやすい名前にする

奥野 たとえば、Clean Architecture *1の本に書いてあったとか、達人プログラマー *2に書いてあったとかであれば、「あの本でいうユースケースです」みたいに説明すればいいと思うんですが、色々なところからつまみぐいを繰り返している結果、全体的によくわからないアーキテクチャになってしまっている気配があります。

リポジトリというものはDDD(ドメイン駆動設計)*3の言葉ですよね?Clean ArchitectureとDDDを両立することもできるけど、分かって組み合わせないと、かいつまんだだけの全体的に何がしたいか伝わりづらいアーキテクチャになってしまう。今回の場合、このアプリケーションではDDDを実践していないので、そこで無理にrepositoriesという言葉を使う必要もないと思っています。

あくまでも複数のユースケースを連ねるものだから、ユーススケースの粒度を細かくしたものにすぎなくて、ドメイン駆動設計としてのリポジトリではない。言葉だけ拝借してるけどルールがちゃんと定まってないから、「ユースケース」や「リポジトリ」という言葉では武市さんの説明を聞いても自分はあんまりピンときてなかったんですよ。

これは、武市さんのやりたいこと、やろうとしてることを否定したいのではなく、やろうとしてることはわかるんだけど、語彙からそれが伝わってこない、っていうところがポイントですね。

例えば、さっきのupdateItemというユースケースを例にすると、getItemで商品情報を取得し、取得した後にupdateItemを行う…というようにデータベースの操作と密にもなりつつ、ドメインロジック・ビジネスロジックとしてもこう取り扱っておきたい、みたいな粒度がありますよね。

そんな複数の処理のコンビネーションをなんと呼ぶべきか、そしてその一個一個をなんと呼ぶべきかというところを整理していくと、もうちょっと納得感のある切り方になると思います。自分は、ドメイン駆動設計を実践しておらずモノリシックな処理をとにかく細分化したいという今の段階において、ここに凝った名前をつける意味はあんまりないと思っていて、自分が担当しているプロダクトではhandlers-sharedと名付けています。そこではHTTPハンドラがいっぱいあって、そのハンドラが一つ一つ細かい操作を決めるんだけど、複数のハンドラで共有したい概念があったらそれはhandlers-sharedに置いてます。

自分の場合はhandlersの中で共有したいものなのでhandlers-sharedに置くけど、武市さんの例の場合だったらuseCases/sharedとかにするとよいかと思います。useCasesの粒度であることに変わりはないけど、useCasesの中で単独で使われるか、共有で使われるかというところの違いでしかありません。

useCasesuseCases/sharedで分けるのがしっくりこなければ、極端な話、全部useCasesに突っ込んでuseCasesboundaryだけでいいんじゃないかというのが自分の最初の主張なんですよ。

最初にboundary以外全部しっくりこないって言い方をしましたが、boundaryuseCasesmodelsの3つでも十分回ると思ってます。大切なのは名前が何かではなく、ファイル間の依存関係がスパゲティのように絡まないかということです。

ルールを納得させる

武市 確かにそうですね。自分の考えとしては、ユースケースはデータベースのことを知らないようにしたくて、ディレクトリを分けた理由としてリポジトリはDBのことを隠す役割ために分けたいからと考えていました。

奥野 どのシステムに繋ぐかを隠してその操作の抽象を取り扱ってるという考え方は合っていると思うけど、武市さんの感覚でリポジトリと名付けて「でも世でいうリポジトリとは異なります」だと、今後チームに参入する人に納得してもらうには武市さんの話術にかかってくると思うんですよ。世でいうリポジトリとは異なるのはなぜなのか?を毎回説明することになる。それだったら説明しづらい言葉を入れるよりも、もうちょっとフラットに通じる名前にしたらいいんじゃないかっていうのが自分の考え方ですね。

ちなみに自分のとこではside-effect(副作用)って呼んでます。

外部に対して何らかの変更をもたらす、追加したり消したりとか、そうゆうハンドラ関数における副作用ですね。なのでそのハンドラが本来何をしたいのかっというside-effectというものがいくつも並ぶことによって何らかの目的を達成させます。武市さんの言葉を借りるとユースケースですね。

自分の前に携わっていた案件だと一つのハンドラー内はincomingside-effectoutgoingの3つに分けていました。

┗ handlers
 ┃ ┣ users
 ┃ ┃ ┣ get
 ┃ ┃ ┃ ┣ incoming
 ┃ ┃ ┃ ┣ side-effect
 ┃ ┃ ┃ ┗ outgoing

全てのハンドラに対して一様に必ずこの3つに分けていて、リクエストっていうのは必ずバリデーションをしないといけないし、認証認可の文脈でも何らかの処理が必ず発生する。エンドポイントというのは入ってきたものを検閲するポイントが必ず必要になってくる、それがincomingになってる。

incomingで合格した値っていうのは、そこから何か処理を呼んだり、書き込んだ消したり、必ず何らかの副作用を起こします。他のシステムに通信を飛ばしたり、そういうハンドラの副作用となる部分を全部side-effectに入れてます。

さらにそのside-effectが終わった後の結果っていうのは何らか返したいっていう欲求が絶対ある。それはHTTPのハンドラを実装してる以上、何かしらのHTTPレスポンスを返したいっていうのは当然の振る舞いなので、そこをoutgoingディレクトリ内の処理で、レスポンスのバリデーションをしたりとかレスポンスのBodyの構築をしたりとかをする。だから、「入口」・「やること」・「出口」で分けている。

武市 なるほど。

奥野 自分が前に携わっていた案件の言葉を使って、武市さんのこのディレクトを説明すると、今はuseCasesincomingside-effectoutgoingが全て詰まっていますね。そのside-effectの中でもうちょっと分けておきたいなっていう単独化というか抽象化を、武市さんの言葉でいうリポジトリでやってたわけですよ。

このディレクトリに名付ける名前は正直なんでもよくて、みんなが納得してみんなで守れたらそれでいい。武市さんが「リポジトリ」って言葉を使うことを自分は何も禁止しないし、まったく否定する権利もないけど、ちょっとだけ忠告すると「リポジトリ」って言葉にはすでに色が付きすぎているから、「リポジトリ」じゃないものに「リポジトリ」って付けたときに他人に抱かせる抵抗感はそれだけ大きくなるよ、っていうものです。

武市 そうですね、本来の目的からけっこう外れちゃってますね。

奥野 「リポジトリ」と名付けたらRepository Patternを想起させるものでないと、人によっては「リポジトリちゃうやんけ」となる。

これはちょうど「リファクタリングとともに生きるラジオ」のデザインパターンの回 *4でも言ったんだけど、Strategy PatternとかSingleton Patternと、名前を付けるだけですぐ何をしたいのか世界中の人が共通で分かるっていうところがメリットで、Repositoryもそれなりに市民権を得ている。だからそういう言葉ほどそれに忠実であった方が求められる。

バウンダリ(外部システムとの連携部分)を隠蔽したいってのは分かるけど、それはバウンダリを隠蔽してるだけでリポジトリを模してるとは思えなかった。そうでないものに「リポジトリ」って名付けたときに他者を納得させるにはどうすればいいか、ってところで頭を抱えることになると思います。だから自分のとこではRepository Patternを踏襲してはいないため、リポジトリって言葉を意図的に避けていて、あえて使ってないんです。

でも結局やりたいことは、武市さんのここに書いてることと自分のとこも一緒です。それは外部と内部の抽象化をしたいのと、全体的な一連の結合テストにその個別のブラックボックスを取り扱いたくないっていう部分。だからやりたいことは一緒で、あとはそれをどう見せるかと、どうチームを納得させるか。

リードエンジニアに求められるポジションというか素養って、ルールを作る力じゃなくて、作ったルールを納得させる力なんですよ。ルールって作っても従ってもらえなければ破綻するので、ルールを作るだけじゃなくて、これに従ってねっと言って、「OK、従います」って周りのチームメイトに納得させる力なんです。そうなった時にリポジトリっていう言葉を使ってまで危険な橋を渡るのかっていうことです。

武市 めちゃめちゃ納得です!!

奥野 だからこのディレクトリツリーと、そこからくるやりたいことの説明はなにひとつ間違ってないんだけど、勇気がいる行いだと思いました。そこをもうちょっと冷静に考えてみたときに、リポジトリじゃないものをリポジトリと呼ぶのは説得力に欠けると立ち返るのであれば、他の言葉を選んだ方が無難ですね。

武市 そうですね。これから入ってくる人がわかりやすくなるようにディレクトリで役割を持たせよう、というのを目的にしていたのに裏面に出ていました。ありがとうございます!

To Be Continued…

PR

奥野さんがパーソナリティを務める「リファクタリングとともに生きるラジオ」も配信中です。リファクタリングに興味のある方はぜひチェックしてください!

refactoradio.com

© Toreta, Inc.

Powered by Hatena Blog