トレタ開発者ブログ

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

5年目エンジニアの考えるエンジニアとして"圧倒的成長"する方法

始めに

皆様、こんにちは!
Toretaのサーバサイドエンジニア兼佐久間まゆちゃんのプロデューサーの@hiroki_tanakaです。
この記事はトレタ Advent Calendar 2019の11日目の記事です。
他の方がテクニカルな記事を書いている中、私は"想い"を投稿します。

自己紹介

  • 社会人歴:5年目
  • 新卒で独立系SIerに4年間在籍。ITコンサルタントとして設計〜リリースまでの一気通貫PJに従事し慌ただしい日々を過ごす。
  • 2019/11/1よりToretaにサーバサイドエンジニアとしてJoin。
  • 大手企業の基幹系システム構築からWeb系自社プロダクト開発に変化し、全てが新鮮で色々戸惑いながらも日々邁進中。
  • Ruby歴:1年半・Java歴:2年・SQL歴:4年。

記事の目的

新人エンジニア Advent Calendar 2016文系出身の2年目エンジニアが『情熱プログラマー』を読んで新人に伝えたいことという記事を投稿したのですが、3年ぶりの続編です。
2019年は人生初の転職もあり自分のエンジニアとしてのキャリアを見つめ直したことや、久々に『情熱プログラマー』を読んだ時の3年前との感じ方の変化からエンジニアとしての成長という観点で語っていこうと思います。
(他のエンジニアの方の役に少しでも立てれば、とても嬉しいです。)
タイトルの"圧倒的成長"は一昔前のバズワードを使ってみたかっただけです。

情熱プログラマー ソフトウェア開発者の幸せな生き方

情熱プログラマー ソフトウェア開発者の幸せな生き方

  • 作者:Chad Fowler
  • 出版社/メーカー: オーム社
  • 発売日: 2010/02/26
  • メディア: 単行本(ソフトカバー)

1. スペシャリストになろう

ほかに何も知らないことがスペシャリストだって勘違いしているんじゃないか
何かのスペシャリストであるということを、単にほかのことを知らないという意味で使っている人が多すぎる。その技術的な知識には深みがないんだ。
スペシャリストは他に何も知らないことの言い訳ではないんだ。

自称「Javaエンジニア」だった私にはとても刺さりました。
Rubyを1年半・Javaを2年書いていますが、じゃあ、「何故、Rubyプログラムは動くのか?」や「Javaのコンパイルの仕組みは?」と聞かれたら、私は答えられません。
そもそもプログラミング言語やOSという普段当たり前に使用しているアプリケーション実装の下位の部分を詳細に理解しようとしたことがありませんでした。
1~2年目は目の前のアプリケーションをプログラミング言語という道具で自分の開発すべき機能を実装するが精一杯でした。
しかし、5年目にも関わらず、その次元に居ては技術的に深みのない自称スペシャリストになってしまいます。
「プログラムは何故動いているのか」というそんな当たり前の質問にまず答えられるようになりたいと思います。
そして、自分が使用しているライブラリやFWといった道具の原理原則や設計思想は説明できるようになって、初めてスペシャリストの第一歩だと思っています。

2. オレ、作文的なのは得意っすよ

文章を書くことが仕事の一部になるとすれば、もっと作文技術を磨いたほうがいい。
たとえプログラマとして優秀であっても、自分自身を言葉で表現できなければ、グローバルに分散したチームではあまり有能な人材とは見なされない。
そもそも母国語で自分の考えを他人にわかりやすく組み立てられないのに、どうしてプログラミング言語ならできるって言える?
アイディアを言葉にして論理的な結論に導く能力は、将来の保守担当者に理解できるように明快な設計とシステム実装を生み出す能力とそれほど違わない。

言葉で自分のしたいことを説明するのはとても難しいですし、私はとても苦手です。口頭ではなく、文章なら尚更です。
なので、私は「プログラムで表現して、動く機能を見せれば良い」と考えていました。
ですが、母国語で自分の考えを他人にわかりやすく組み立てられないのに、どうしてプログラミング言語ならできるって言える?とある通り、 どうして日本語で説明出来ないことがRubyやJava・SQLでなら説明出来るようになるのでしょうか。
(今思えば、謎です…)
また、様々な働き方が増えてきた今、コミュニケーション手段が文章のみという場面も多くなり、トレタでも毎週リモートワークの日を設けています。
(先日は全社員が一週間全てリモートワークのリモートウィークも試験的に行いました。)
チーム全員が別の場所で働いている中で自分が何をしたか、どのように設計したか、チームに何をしてほしいかをしっかり出来る説明できるスキルは技術力と同じくらい重要なスキルだと実感しています。

3. 一番の下手くそでいよう

どんなバンドで演るときも一番下手なプレイヤーでいろ。チームで一番下手くそでいるのは、バンドで一番下手くそでいるのと同じ効果がある。
チームで一番下手くそでいると、どういうわけか自分自身が賢くなるんだ。
自分の生み出すコードや設計が以前よりエレガントになり、難しい問題をますます創造的なソリューションで解決できるようになる。

実は上記の文章に私の言いたいことは全て集約されています。
IT業界は移り変わりの激しい業界なので4〜5年目となるともう会社では中堅でチームを任せられたりマネジメント側に回ったりします。
マネージャーとしてのキャリアを積んでいくならば、それでも良いと思います。 ですが、エンジニアとして技術を深めていくならば、そのタイミングでもう一度自分が一番下手くそな環境に行くのが良いと思います。

私は3~5年目の時に100人規模のPJに所属していたのですが、気づくと私より技術が出来る人は数える程でした。
非常に忙しかったのですが、自分が技術的に優れていると思える&周りからそう思われているので正直、居心地良かったです。
「技術力あってマネジメントも出来るようになってきてるオレ、スゲー」状態でした。
ただ、技術的に成長できたかと言うとNOです。 そうです、技術の自己研鑽を止めてしまっていたのです。
そんな中でわずかに残っていたエンジニア心から自分の技術力を高めていない状況に危機感を覚えました。
(自分のRailsの知識が4.2で止まっていることを自覚した時、本気でまずいと思いました。)

現在はまさに自分が一番下手くそで周りは皆出来る人ばかりなので、正直、会話一つ一つから自分の知識不足を痛感します。
ただ、追いつこうとして2年前に止まったエンジニアとしての成長曲線が再度動き出したことも同時に感じます。
一番下手くそな環境に行ったことは正解でした。

最後に

『情熱プログラマー』の最後に書かれていることがエンジニア生活の全てを表しているのではないか、と3年前に思ったのですが今読んでもやはりそう思います。
これからもクリエイティブで楽しいエンジニアライフを送りたいと思います。
今後は自分が成長するのは勿論ですが、チームとしての成長にも貢献出来るように自分のバリューを発揮していきたいです。
ゆくゆくは自分の技術の腕で皆を引っ張っていけるように。

ソフトフェア開発はやりがいがあって、しかも報われる仕事だ。
芸術活動のようにクリエイティブでありながら、芸術とは違って、具体的で数量化出来る価値を生み出せる。
ソフトウェア開発は楽しい!

CSからエンジニアにジョブチェンジしました

この記事は トレタ Advent Calendar 2019 の10日目です。

こんにちは。iOSエンジニアの@yukimura03です。

気づけばトレタで働き始めて2年が経ちますが、エンジニア歴は8ヶ月くらいの初心者です。
今日のアドベントカレンダーでは、他職種からジョブチェンジしてみてどう感じたか、という話をしようと思います。

前提

最初に書いた通り、エンジニア歴は1年未満の初心者エンジニアです。
今年3月まではトレタのCS(カスタマーサクセス)部に所属する派遣社員でした。
実際にトレタの台帳を使っている店舗の方と電話をして、使い方の説明をしたり、トラブルシューティング的な対応をしたりしていました。

よかったこと

プロダクトにより深く関わることができる

これまではCSでユーザーのサポート的なことをしていたため、実際のユーザーの声をたくさん聞いてきました。
自然と台帳の使い方にも詳しくなりますし、自然と愛着も湧いてきます。
そうなると、これはどうやって動いてるんだろう? 作ってる人すごいな? 裏側が知りたい、私もこれを作りたい! という気持ちになることも自然なはず(?)です。
今エンジニアになって実際のコードを触るようになって、当時は知らなかった仕組みなんかを知って日々感動しています。

知っている人たちの中で新しいことに挑戦する

緩い考え方かもしれないですが、新しい環境で新しいことに挑戦する、ってとてもハードルが高いと思うんですよね。
部署が変わるとはいえ、同じ社内なので顔見知りは多い環境で新しいことにチャレンジさせてもらえたのは、私にとってとても良いことでした。
また、独学ではじめた勉強をサポートしてくれる頼れる先輩エンジニアがいたり、分からないところがあればすぐに質問できるあたたかい環境であることも、とてもありがたいと思っています。

困ったこと

Swiftしかわからない(けどSwiftもわからない)

私は去年からSwiftを勉強しはじめました。他の言語? わかりません。
Swiftも勉強中の私ですが、実際のプロダクトのコードはObj-Cで書かれている部分もかなり多く、「読めない…」が最初のつまずきでした。
なので異動当初にObj-CのコードをSwiftに書き換えるタスクをもらって大苦戦…
「Obj-Cの通りにSwiftを書いてるはずなのに、違うclassが返ってきてしまって動かないんです」と先輩に泣きついて、
「これはObj-Cだから動いてただけだね。Obj-Cは型キャストしたときに違うclassが返ってきてても、同じプロパティがあれば動いちゃうんだよ」と聞いてポカーン。なんだそりゃ…ゆるふわ…
なんとか苦戦しながらSwiftに書き換えた、今となってはとても貴重な経験です(あれでObj-Cがだいぶ読めるようになりました)。

ユーザーの声が聞こえにくなった

あんなに毎日電話でユーザーと話してたのに、当たり前ですが開発に移ってきたら電話をしなくなります。途端に使っている人の現状が分からなくなりました。
今までなら黙ってても情報が入ってきたのに、積極的にとりに行かないと分からないんだ……当たり前のことですが、思ってたよりわかんない。
今までの約1年分のユーザーの利用状況は知っていますし、大きな変更が加わらない限りその知識も役に立つだろうとは思っていますが、これからもユーザーの現状は把握しながら開発に臨める人でありたいなぁと思っております。

最後に

なんだかただ私の想いをしたためた感じになってしまいましたが、総合すると、CSからエンジニアに移ってきてよかったよ!という話です。
使う人の声を知りながら作ることもできる人になったらすごくない? 万能なの? かっこいい! という雑な気持ちで締めさせていただきます。
未経験でもエンジニア職に興味を持った人はぜひ挑戦してみたらいいと思います! 楽しいよ!
ありがとうございました!

TrelloAPI+GASでTrelloのカード移動をSlackに通知する仕組みを作った話

この記事は トレタ Advent Calendar 2019 の9日目です。

三度の飯より寿司が好き、QAエンジニアの林です。気付けばトレタに入社して半年経っていました。
今回は、入社1ヶ月目くらいのときに作って以来ちまちま改良しているTrelloのカード移動をSlackにメンション付きで通知するスクリプトについて書いていきます。

背景

社内の一部のチームではTrelloを使用し、ボードに以下のようなリストを作成してカードでタスクを管理しています。
よくあるカンバン方式ですね。

開発担当者が Doing にあるタスクを実装し終わったらカードを QA に移動し、QA担当者がテストを実施して再修正が必要な場合は BugFix へ移動させて再び開発者ボールに、問題なければ Close へ…という運用です。

リスト名 ステータス
ToDo 未着手
Doing 実装中
BugFix QA中に手戻りが発生し、修正中
Code Review 実装が完了し、レビュー中
QA QA実施中
Close 完了

公式のTrelloアプリをSlackに追加することでSlackのチャンネルにカードの動きを通知することはできます (下記画像のような通知がチャンネルに投稿されます)。

f:id:tkgnori:20191209174227p:plain:w400

しかし、これだけだと通知を見逃しがちです。
開発担当者からQA担当者へ、またはその逆へボールが渡されたことに気付かないとタスクが停滞してしまいます。

Slack上で「実装完了し、staging環境にデプロイしました」「QA実施し、不具合ありましたので再修正お願いします」など直接メンション付きでリマインドすれば良いかもしれませんが、カード移動のたびに毎回するのは手間ですし、それ自体も忘れる可能性があります。
どうせならその辺を自動化しちゃおう、と考えたのが発端です。

やりたいこと

  • Trello上でQAリストにカードが移動されたらQA担当者にSlack上でメンション付き通知
    • QA担当者は主に1名
    • 仮に担当者が増えた場合も、そのうちの誰かがQA実施という形になるので全員に通知したい
  • Trello上でBugFixリストにカードが移動されたら開発担当者にSlack上でメンション付き通知
    • 開発担当者は複数存在し、各タスクにアサインされる
    • そのタスクを担当している人物だけに通知したい

使ったもの

実装方法

まずはGASプロジェクトを新規に作成し、以下の順で code.gs にガリガリ書いていきます。
各プロパティ (APIキーやボードIDなど) はスクリプトプロパティで扱うこととしました。

1. Incoming WebhookをSlackに追加し、Webhook URLを取得

このページ でアプリを検索し、Incoming Webhookを追加します。
追加後、 インテグレーションの設定 で各設定を実施します。

  • チャンネルへの投稿: 通知をPOSTするチャンネルを選択
  • Webhook URL: スクリプトで使用するのでコピーしておく
  • 説明ラベル: 任意。アプリの用途など説明を書いておく
  • 名前をカスタマイズ: 任意。Slack上で表示されるアプリのユーザー名になる
  • アイコン: 任意。同じくアプリのアイコンになる

2. TrelloのAPIキー・トークンを取得

Trelloにログインしている状態でこちらにアクセスするとAPIキーが表示されます。 トークンは、同ページ内の トークン リンクから遷移したページで 許可 を選択すると表示されます。
どちらもスクリプトで使用するのでコピーしておきます。

3. TrelloのボードID・リストIDの取得

以下を参考に、ボードIDとリストIDを取得します。

各パラメータには以下を当てはめます。

  • id
    • ボード一覧取得APIの場合: Trelloのユーザー名 (プロフィール画面から確認可能)
    • リスト一覧取得APIの場合: ボード一覧取得APIで取得した、監視対象とするボードのID
  • key: 2. で取得したAPIキー
  • token: 2. で取得したトークン

4. Callback URLの取得

GASプロジェクトの 公開 > ウェブアプリケーションとして導入... を選択し、ダイアログを開きます。 以下の設定に変更し、公開 を選択するとURLが発行されるのでコピーしておきます。これがCallback URLとなります。

  • アプリケーションにアクセスできるユーザー: 自分のみ
  • プロジェクトバージョン: New

5. 各プロパティの設定

GASプロジェクトの ファイル > プロジェクトのプロパティ > スクリプトのプロパティ で各プロパティを設定します。
今回は以下のプロパティを作成しました。

key 内容
CALLBACK_URL 4. で発行されたCallback URL
TRELLO_API_KEY 2. で取得したAPIキー
TRELLO_TOKEN 2. で取得したトークン
BOARD_ID 3. で取得したボードID
LIST_ID_QA 3. で取得したリストID (QA)
LIST_ID_BUGFIX 3. で取得したリストID (BugFix)
SLACK_WEBHOOK_URL 1. で取得したWebhook URL

f:id:tkgnori:20191209192450p:plain:w400

6. Webhook登録処理の実装

WebhookAPI(POST)を使用してWebhookを登録します。callBackURL はpayloadの中に詰め込みます。
また、5. で設定したプロパティ群は
PropertiesService.getScriptProperties().getProperties() を使用して参照します。

function createWebhook(){
  var scriptProp =  PropertiesService.getScriptProperties().getProperties();
  var trelloKey = scriptProp.TRELLO_API_KEY;
  var trelloToken = scriptProp.TRELLO_TOKEN;
  var callbackUrl = scriptProp.CALLBACK_URL;
  var boardId = scriptProp.BOARD_ID;

  var requestUrl = 'https://api.trello.com/1/tokens/' + trelloToken + '/webhooks/?key=' + trelloKey;
  var options = {
    'method' : 'post',
    'payload' : {
      'description': 'Webhook of Trello',
      'callbackURL': callbackUrl,
      'idModel': boardId
    }
  }
  Logger.log(UrlFetchApp.fetch(requestUrl, options));
}

7. Webhookの登録

実行 > 関数を実行 > createWebhook を選択し、6. で作成した関数を実行します。
ログに表示されたレスポンスが正常であればOKです。

8. 通知処理の実装

doPost()
Trelloのカードに対し何かしらのアクション (移動、作成、コメントなど) が行われた際に呼び出される doPost 関数を実装していきます。
まず、目的のアクション (QAリストまたはBugFixリストへのカード移動) 以外だった場合はすべてreturnします。

QA担当者は固定なのでそのままです。
開発担当者は getDevMember()を呼び出してTrelloIDを取得し、それをkeyにして DEV_MEMBERS からSlackIDを取得し、Slack上でメンションが飛ぶようにします。
ここでDEV_MEMBERSでIDを紐付けしていないTrelloIDが返ってきた場合は、メンションの代わりに専用のメッセージを出力します。

なお、SlackIDは表示名 (@hogehoge など) をそのまま埋め込んでもテキストとして表示されるだけで、メンションになりません。 こちらを参考にしてSlack上から メンバーID をコピーする必要があります。

getDevMember()
カードオブジェクトにはアクションの履歴が保存されています。
1つのカードにつき1人だけオーナーを設定できるのであればここまでする必要はないのですが、Trelloはカードのメンバーを複数設定できる仕様のため、履歴から開発担当者 (の可能性が高いユーザー) を特定しています。

具体的には、フィルタを利用して履歴の中から「カードを移動した」というアクションのみを取得し、その中で一番最後にQAリストにカードを移動したユーザーを取得 というロジックを組んでいます。
(カードの移動を行うのは、今現在そのカードを担当している人物であることはほぼ確実であるため)

/*
 メイン処理
 Trello上で何かしらの変更が発生した時に毎回実行され、特定の条件下でSlackへ通知する
*/
function doPost(e){
  var contents = JSON.parse(e.postData.contents);
  var actionType = contents.action.type;
  var destinationList = contents.action.data.listAfter;
  
  // カードが目的のリストに移動された場合のみ通知し、それ以外の場合は終了
  if(actionType !== 'updateCard' || !destinationList) { return; }
  
  var scriptProp =  PropertiesService.getScriptProperties().getProperties();
  var qaListId = scriptProp.LIST_ID_QA;
  var bugfixListId = scriptProp.LIST_ID_BUGFIX;
  var movedUser = contents.action.memberCreator.fullName;
  var mentions = '';
  
  // key=TrelloID, value=SlackID
  // dev memberがjoinした際はここにIDを追加する
  var DEV_MEMBERS = {
    '5xxxxxxxxxxxxxxxxxxxxxxxxx': '<@UAAAAAAAA>',   // @hogehoge
    '5yyyyyyyyyyyyyyyyyyyyyyyy': '<@UBBBBBBBB>',    // @fugafuga
    '5zzzzzzzzzzzzzzzzzzzzzzzzz': '<@UCCCCCCCC>'    // @piyopiyo
  };
  // QA担当者のSlackID
  var QA_MEMBERS = '<@UDDDDDDDD>';   // @hayashi
  
  switch (destinationList.id) {
    case qaListId:
      mentions = QA_MEMBERS;
      break;
    case bugfixListId:
      var devMember = getDevMember(contents.action.data.card.id);
      // TrelloとSlackのIDがまだ紐付いていないユーザーが指定された場合に表示するメッセージ
      var msgUserNotFound = '@' + devMember.fullName + ' (TrelloIDとSlackIDを紐付けてください: TrelloID=' + devMember.id + ')\n';
      mentions = !DEV_MEMBERS[devMember.id] ? msgUserNotFound : DEV_MEMBERS[devMember.id];
      break;
    default:
      return;
  }
  
  var postUrl = scriptProp.SLACK_WEBHOOK_URL;
  var cardName = contents.action.data.card.name;
  var listName = destinationList.name;
  var shortLink = 'https://trello.com/c/' + contents.action.data.card.shortLink;
  var message = mentions + ' カード *<' + shortLink + '|' + cardName +'>* が ' + movedUser + ' さんにより *' + listName + '* リストに移動されました。ご確認をお願いします。';
  
  var jsonData = { "text" : message };
  var payload = JSON.stringify(jsonData);
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };

  UrlFetchApp.fetch(postUrl, options);
}

/*
 QAリストからBugFixリストにカードが移動した際、
 Slack上でメンションを飛ばすために開発担当者を特定する
*/
function getDevMember(cardId) {
  var scriptProp = PropertiesService.getScriptProperties().getProperties();
  var trelloKey = scriptProp.TRELLO_API_KEY;
  var trelloToken = scriptProp.TRELLO_TOKEN;
  var qaListId = scriptProp.LIST_ID_QA;
  var requestUrl = "https://api.trello.com/1/cards/" + cardId + "/actions?key=" + trelloKey + "&token=" + trelloToken + "&filter=updateCard:idList";
  var options = {
    'method' : 'get'
  }
  var response = UrlFetchApp.fetch(requestUrl, options);
  var cardActions = JSON.parse(response.getContentText());
  
  // 必ずカードにメンバーとして追加されているとは限らないので、
  // 「最後にQAリストにカードを移動したユーザー」を開発担当者とする
  for (var i = 0; i < cardActions.length; i++) {
    if (cardActions[i].data.listAfter.id === qaListId) {
      Logger.log(cardActions[i].memberCreator);
        return cardActions[i].memberCreator;
    }
  }
  return;
}

9. 公開

4. と同様、再度 公開 > ウェブアプリケーションとして導入... を選択し、ダイアログを開きます。
設定を以下のように変更し、更新 を選択します。

  • アプリケーションにアクセスできるユーザー: 全員(匿名ユーザーを含む)
  • プロジェクトバージョン: New

ここで「アプリケーションにアクセスできるユーザー」を変更しないとうまく動きません。ちょっとハマりました…。

結果

▼ Code Review → QA にカードを移動させた場合の通知
f:id:tkgnori:20191209205459p:plain

▼ QA → BugFix にカードを移動させた場合の通知 (開発担当者のID紐付け済み)
f:id:tkgnori:20191209200240p:plain

▼ QA → BugFix にカードを移動させた場合の通知 (開発担当者のID未紐付け)
 ここで表示されたユーザー名とTrelloIDを参考にし、コード上でSlackIDと紐付けます
f:id:tkgnori:20191209201617p:plain

これでもうカードの移動を見逃さない!

おわりに

開発→QAに転向してから仕事でコードをあまり書かなくなったので、良いリハビリになりました。
GASがES6に対応する時代はまだでしょうか…。
かなり拙いコードとは思いますが、似たような仕組みを作りたい方にとって少しでも参考になれば幸いです。

また、実装・執筆に当たり以下の記事を参考にさせていただきました。ありがとうございます!

© Toreta, Inc.

Powered by Hatena Blog