チームスピリットデベロッパーブログ

チームスピリット開発者のブログ

Amazon Echo から Salesforce へ繋げてみた

こんにちは。
株式会社チームスピリットの古川(id:furukawa-hisakatsu)です。

Amazonにて発売されましたスマートスピーカー「Amazon Echo」が11月に日本に上陸しました。
私自身も11月末にAmazon Echoが届きましたので試しにSalesforceに繋げてみました。

f:id:furukawa-hisakatsu:20171222194712p:plain

(可愛いやつです)

後、この記事はチームスピリット Advent Calendar 2017の21日目です。(遅刻) adventar.org

概要

今回はAmazon Echoと接続する音声サービス「Amazon Alexa」からAccount Link機能とAPI Gatewayを使用してSalesforceと接続し、
Lambdaから未承認レコードの件数の取得を行うカスタム音声サービス「Alexa Skills Kit」を作成します。
お試しまでとなりますので公開用の設定ではありません。

必要なアカウント

Alexaからのリクエスト処理をLambdaで作成

Alexaからのリクエストを受付し、Salesforceに接続、その後Alexaに件数を発言するレスポンスを返す処理を作成します。 ソースコードは下記URLから参照して下さい。

github.com

  • AWSにログインし、「Lambda」を選択し、関数の作成をクリックします。

f:id:furukawa-hisakatsu:20171222160507p:plain

  • 次に「一から作成」を選択し、名前を適当に入力し、ランタイムは「Node.js 6.10」を選択し、ロールは既存のままで選択して保存します。

f:id:furukawa-hisakatsu:20171222160634p:plain

  • 関数の詳細画面が表示されましたら、「関数コード」の「コード エントリ タイプ」に「.ZIP ファイルをアップロード」を選択し、こちらをダウンロードしてアップロードします。

f:id:furukawa-hisakatsu:20171222162847p:plain

  • 表示している関数がAlexa Skills Kitから呼び出されるトリガーを設定するため、「Designer」のサイドメニューから「Alexa Skills Kit」を選択し、「トリガーの設定」から「追加」をクリックします。

f:id:furukawa-hisakatsu:20171222163241p:plain

  • 最後に右上の「保存」をクリックし、Lambdaの設定は完了です。

f:id:furukawa-hisakatsu:20171222163308p:plain

  • 後のスキル設定で使用するため、右上の「ARN」を何処かに退避します。

f:id:furukawa-hisakatsu:20171222180221p:plain

トークン取得時のレスポンスを工夫するためAPI Gatewayを作成する

Salesforceからのアクセストークン取得を行うためにAPI Gatewayを作成します。

  • AWSにログインし、「API Gateway」を選択し、「APIの作成」をクリックします。

f:id:furukawa-hisakatsu:20171222164535p:plain

  • 「Swagger からインポート」選択し、下記コードを入力して、「インポート」をクリックします。
    (名称変更したい場合は、下記コードの「title」属性の値を変更してください。)
{
  "swagger": "2.0",
  "info": {
    "title": "SalesforceProxy"
  },
  "schemes": [
    "https"
  ],
  "paths": {
    "/": {
      "post": {
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($params = $input.path('$'))\n{\n#foreach($paramName in $params.keySet())\n    #if($paramName == \"access_token\")\n    \"expires_in\": 3600,\n    #end\n    \"$paramName\": \"$params.get($paramName)\"\n    #if($foreach.hasNext)\n    ,\n    #end\n#end\n}\n"
              }
            }
          },
          "requestParameters": {
            "integration.request.header.Accept": "'application/json'",
            "integration.request.header.Content-Type": "method.request.header.Content-Type"
          },
          "uri": "https://login.salesforce.com/services/oauth2/token",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "type": "http"
        }
      }
    }
  },
  "definitions": {
    "Empty": {
      "type": "object",
      "title": "Empty Schema"
    }
  }
}

f:id:furukawa-hisakatsu:20171222170333p:plain

  • これだけではまだ使用できないため、作成に成功しましたら「アクション」をクリックして、「API のデプロイ」をクリックします。

f:id:furukawa-hisakatsu:20171222170441p:plain

  • 「デプロイされるステージ」に「[新しいステージ]」を選択しステージ名等を適当に入力して「デプロイ」をクリックします。

f:id:furukawa-hisakatsu:20171222170509p:plain

  • 成功しますとステージエディタが表示されるので、「URLの呼び出し」を何処かに退避します。(これもスキル設定で使いますよ)

f:id:furukawa-hisakatsu:20171222170914p:plain

余談

OAuth認証処理を行ったことある人は(あれ?)と思われますが、 本来、「https://login.salesforce.com/services/oauth2/token」に通信してアクセストークンを取得するのがSalesforceの認証となりますが、 Amazon AlexaのAccount Link機能でアクセストークンを取得する際、初回時は問題ないのですが、 アクセストークンが時間切れとなり再度取得が必要となった場合、 Amazon Alexaはアクセストークン取得のレスポンスに含まれている「expires_in」(有効時間)が過ぎているかを判定し再度取得する仕組みと思われます。 ですが、Salesforceからのアクセストークン取得時には「expires_in」が含まれていないため、これを含ませるためにAPI Gatewayを作成します。

Salesforceのセッション時間は設定による可変式でありますが、これを検出する手段がないため、今回は固定で1時間を指定しております。

Alexaのスキルを作成しよう

AWS側の設定が終わりました。Alexaスキルを作成しましょう!

  • Amazon Developerにログインし、「Alexa」をクリックし、「Alexa Skills Kit」の「始める」をクリックします。

f:id:furukawa-hisakatsu:20171222171221p:plain

  • Alexa スキル一覧の画面が表示されましたら、「新しいスキルを追加する」をクリックします。

f:id:furukawa-hisakatsu:20171222171812p:plain

  • スキル情報を設定する画面が表示されるため、下記設定を行い、「保存」をクリックします。
    • スキルの種別:カスタム対話モデル
    • 言語:Japanese
    • スキル名:適当に入力して下さい
    • 呼び出し名:こちらも適当に入力してください。

f:id:furukawa-hisakatsu:20171222172057p:plain

  • 「対話モデル」を選択し、「インテントスキーマ」及び「サンプル発話」に下記コードを入力し、「保存」をクリックします。

    インテントスキーマ

{
  "intents": [
    {
      "intent": "SalesforceIntent"
    }
  ]
}

f:id:furukawa-hisakatsu:20171222173646p:plain

サンプル発話

SalesforceIntent 未承認個数を教えて

f:id:furukawa-hisakatsu:20171222173708p:plain

  • 次のSalesforceの設定のため、「設定」をクリックし、「アカウントリンク」の「ユーザーにアカウントの作成や既存のアカウントへのリンクを許可しますか?」に「はい」を選択して、
    「リダイレクトURL」を何処かに退避しておきます。

f:id:furukawa-hisakatsu:20171222174755p:plain

(まだ設定しますので画面はそのまま)

Salesforceに繋ぐための設定をする

スキルの設定を一旦中断し、AlexaからSalesforceに接続するための設定をしましょう!

  • Salesforceにログインし、右上の歯車をクリックし、「設定」をクリックします。

f:id:furukawa-hisakatsu:20171222174320p:plain

  • 設定画面が開きましたら「アプリケーション」から「アプリケーションマネージャ」をクリックし、「新規接続アプリケーション」をクリックします。

f:id:furukawa-hisakatsu:20171222174500p:plain

  • 「接続アプリケーション名」や「API 参照名」、「取引先責任者 メール」を適当に設定しましょう。

f:id:furukawa-hisakatsu:20171222174914p:plain

  • 「OAuth 設定の有効化」にチェックを入れ、下記設定を行い、「保存」をクリックします。
    • コールバックURL:先程退避したリダイレクトURLを貼り付けましょう
    • 選択したOAuth範囲:「データへのアクセスと管理(api)」、「ユーザに代わっていつでも要求を実行(refresh_token, offline_access)」、「基本設定へのアクセス(id, profile, email ,address, phone)」を右に追加します。

f:id:furukawa-hisakatsu:20171222175245p:plain

  • 「次へ」をクリックし、設定完了!

f:id:furukawa-hisakatsu:20171222175319p:plain

  • 画面が切り替わりましたら「コンシューマ鍵」と「コンシューマの秘密」を退避しておきましょう。次に使いますよ!

f:id:furukawa-hisakatsu:20171222175618p:plain

AlexaとSalesforceが繋がる時です

Alexaのスキル設定を再開し、Salesforceの接続設定をしましょう!

  • Amazon Developerのスキル設定画面に戻って「設定」をクリックします。(もう開いているかもしれません)

f:id:furukawa-hisakatsu:20171222180045p:plain

  • 「サービスエンドポイントのタイプ」に「AWS Lambda の ARN (Amazonリソースネーム)」を選択し、「デフォルト」に先程退避したLambdaの「ARN」を貼り付けます。

f:id:furukawa-hisakatsu:20171222180722p:plain

  • 「アカウントリンク」から「ユーザーにアカウントの作成や既存のアカウントへのリンクを許可しますか?」に「はい」を入れ(もう入れてるかもしれません)、下記設定を行います。
    • 認証 URL:「https://login.salesforce.com/https://login.salesforce.com/services/oauth2/authorize
    • クライアント ID:退避したSalesforceの「コンシューマ鍵」
    • 認可の承諾タイプ:「Auth Code Grant」
    • アクセストークンURL:退避したAPI Gatewayの「URLの呼び出し」
    • クライアントシークレット:退避したSalesforceの「コンシューマの秘密」
    • クライアント認証スキーム:「リクエストボディの資格情報」

f:id:furukawa-hisakatsu:20171222181415p:plain

  • 最後の「プライバシーポリシー URL」は適当に入力しましょう。(本当は個人情報の取扱が記載されているURLが必要ですよ)

f:id:furukawa-hisakatsu:20171222181654p:plain

  • 「保存」をクリックして「次へ」をクリックします。
    (このあたりでエラーが起きやすいですね、エラーが起きたら手順を再確認してみましょう)

さぁテストの時間だ!

面倒な設定作業を終え、ついにAlexaの言葉を聞く時が来ました。

Amazon Echo等を持っていない方向け

なんとAmazon Echoのシミュレータがあるのでログインして許可してみましょう。

echosim.io

Salesforceの認証が必要です

まだ声を聴くのは早かったですね、Salesforceの認証をしましょう

  • お手持ちのスマートフォンにAmazon Alexaをインストールするか、もしくは http://https:/alexa.amazon.co.jp からログインします。
    (スキル開発したアカウントでログインしてください)

  • 「スキル」を選択して「有効なスキル」をクリックします。(Amazon Echo等が設定済みか上のシミュレータ連携されていないと開けないかもしれません)

f:id:furukawa-hisakatsu:20171222183300p:plain

  • 先程登録したスキルが表示されているのでクリックします。
    (表示されていなかったらログインするユーザが異なっているか、スキルの設定が途中かもしれません)

f:id:furukawa-hisakatsu:20171222183656p:plain

  • 「設定」をクリックし、「アカウントのリンク」をクリックしてSalesforceにログインします。
    (Salesforceのログイン時にこのアプリケーション許可するとウィンドウが出ると思いますが、「許可」するをクリックして下さい)

f:id:furukawa-hisakatsu:20171222183756p:plain

  • アカウントのリンクに成功しているはずです!
    (成功していなかったらスキル設定やSalesforceの設定を再確認!)

f:id:furukawa-hisakatsu:20171222184202p:plain

声を聞きましょう

youtu.be

(なかなか通じない場合は単語分割していってみるのもいいかもしれません)

締め

今回Alexaにてスキルを実装してみましたが、アカウント管理や認証処理をAlexa側に一任できるのは大きく、
わざわざユーザを特定したり、データベースを用意したりする必要もないのは魅力的であり、
開発自体もsdkが用意されていたりと特に詳しく勉強しなくても開発できるのはいいですね。

皆様も是非仕事役に立つような、あるいはちょっと役に立つような、はたまた面白いようなスキルを開発してみて下さい!

公式でのSalesforceとの接続はAlexa for Businessでなにか来るみたいですけど日本にくるのでしょうか?

入社して10ヶ月がたったので入社エントリ書く

どうも、こんにちは
腹筋しろよ(ブログ出張バージョン)

チームスピリットでデザイナーをやっていますid:ts-yokouchiです。

本記事はチームスピリット Advent Calendar 2017の14日目および転職 Advent Calendar 2017の21日目です。日付とはなんだったのか。

弊社に入社してちょうど10カ月ほどたった今、入社エントリーを書こうと思います。

自由な働き方

弊社では働き方にフォーカスしたサービスを提供しているので、もちろん働くわれわれも比較的柔軟な働き方ができます。

フレックスタイム制

弊社では11時から16時がコアタイムのフレックスタイム制が開発チームに導入されています。
8時間/1日 労働を基準に日によっては長く、またある日は短く、自由に時間を決めながら働くことができます。

入社してしばらくは8時出社の17時退社をするなどをしていました。みんなが必死に働いてる中帰宅するのは楽しいか?、めっちゃ楽しい!
ただ、今ではすっかり11時ギリギリ出社です。オフトゥンやっぱすっきやで。

日によっては10時くらいまで働くこともあれば、勉強会のお手伝いなどで17時に退社したり勤務時間はバラバラです。
コアタイム外にミーティングが組まれるようなことをもあまりないためスケジュールが組みやすいと感じています。

スタンディングデスク

f:id:ts-yokouchi:20171221131519j:plain ※僕ではなく同僚氏です。

入社してしばらくダンボールによるスタンディングを行っていた私ですが、偉い人が哀れんでくれたらしくちょっと前からフリーアドレスの席にスタンディングデスクが設置されています。

※ダンボールデスクについてはこちらの記事にまとめております。 teamspirit.hatenablog.com

オカムラ製のSwiftが全部で8脚もあります。
これは非常に良いデスクで、天板面積も広い上に昇降が電動式となっています。
疲れた座り、座り疲れたら立つという運用を行っています。

「は?スタンディングで座ったら意味なくない?」
と突っ込まれることもしばしばですが、
「勘違いしないで欲しい、私はやがて立つために座っている、意識高いシッティグをしている。
などのやりとりを行っています。

スタンディング、腰への負担も少ない上に眠気もおさえられるため本当に良きです。

リモート

だいたい週1でのリモートが推奨されていますし、時短勤務でほぼほぼフルリモートで働いてる社員の方もいます。 MTGもハングアウトを使ってリモート参加が当たり前にできる環境になってて良いと思います。

私も入社するにあたり10万くらいの椅子を買って自宅に設置し、自宅勤務への高まりを自宅に表現して、自宅への愛を深めていたのですが、最近は全くやっていません。

  • 役割的に人とのコミュケーションが重要
    • すぐ気になったことを相談しがち
  • 自宅だと昼寝する

が主な理由です。

リモートが推奨されていると言っても、前述のとおりスタンディングデスクが導入されているなどオフィスでの働きやすさもちゃんと考えてくれる会社です。 リモートが可能であっても、使うかどうかは当人達に任せられており、かつ両方の場合で働きやすいのは素晴らしいことだと思います。

チームについて

エモいことを頑張って書こうと思ったのですが、面倒になったのでやめます。恥ずかしいし。
大体チームについて感じてることはこんな感じです。

  • 常に前を向いているチーム
  • 技術が好き
  • 垣根なく意見のやり取りができる

3つ目は良いです。風通しが良い。 最初はフロントエンドエンジニアで採用された私も、いろいろあってデザイナーになりました私は今日も元気です。

まとめ(まとめない)

弊社について良い所を書き連ねるエントリーになりました。(検閲が入るので)
個人ブログなどでもうちょっとエグ味があることを裏で書きたい、会社の人は目をつぶってください。

総括するとスタンディングデスク最高なんでスタンディングデスクを信じろ。信じる人募集という感じです。
今のところ高級なスタンディングデスクがある良い会社に入ったなと思ってます!

ちなみに入社の決め手は最初に受かったからです。
勢いって大事ですよね!

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

QAエンジニアが参画する時の7つの確認リスト

この投稿はチームスピリット Advent Calendar 2017 - Adventarの20日目の記事です。

adventar.org

こんにちは、QAチームの生井(id:riririusei99)です。
今年も残すところあと少しになりましたね。

はじめに

QAエンジニアは「テスト」や「品質保証」といった幅が広いテーマに対してリードするエンジニアです。
テストの自動化、テスト設計&テストマネジメント、開発チームのテストを改善していく役割など仕事内容は会社・チームによって異なるかと思います。 そんな中でどういった働き方を期待されているのかは認識にズレがないように把握している必要がありますよね。

今回のテーマはそんなQAエンジニアがチームに参加する前に確認しておくべき項目について、 ソフトウェアテストドキュメントの国際標準であるIEEE829-2008を参考に作ってみましたという内容です。

7つの確認リスト

  1. 目的
  2. テストアイテム&スコープ
  3. アプローチ
  4. アウトプット
  5. 参加するまでのタスク
  6. 役割
  7. あってはならないこと

1.目的

ここではなぜQAエンジニアが必要なのかを思い切って確認します。
プロダクトへの課題感、期待されていることが聞けるはずです。
目的を聞くことで目指すべき品質目標や今後のテスト計画が立てやすくなります。
どんなことを聞けばいいかわからない場合は、QAエンジニアやソフトウェア品質を大枠で捉えて分解して考えてみると良いかもしれません。

2.プロダクト&スコープ

携わるプロダクトについて現段階でわかっていることを確認します。
具体的にテストして欲しいバージョンや環境、開発フェーズといったことを聞くことで必要なものが見えてきます。 その他、既に十分テストしている機能がある場合など、テストするもの/しないものをわかっている範囲で確認しておきましょう。

3.アプローチ

目的を達成するためにどのような手を打つのかスケジュール、テスト体制などをすり合わせます。
開発スプリントとテストスプリントを別々に用意しテストする場合や、スプリント期間内にテスト期間に設けるなど参加するチームによってそれぞれ変わっていく部分だと考えています。
余裕があれば目的を達成したあとの話も確認できると良いです。(現在はテストの設計がメインだが、テストの自動化にも注力したい。など)

4.アウトプット

テストなどの活動の結果として何をアウトプットとするかあらかじめ決めておきます。
具体的な内容としてテストレポートやインシデントチケットなどが挙げられます。
同時にインプットとして提供してもらえる資料などを確認することも重要です。
テスト計画書やインシデントチケットの項目など、弊社では作成した成果物をなるべく使いまわせることを意識しながら作成しています。

5.参加するまでのタスク

参加するまでに準備しなければいけないタスクを洗い出します。
テストデータの準備や環境準備など、QAエンジニアだけで解決できないものがないか確認しましょう。

6.役割

QAエンジニアしかできない仕事や、開発メンバーに協力してもらう部分を明らかにします。
具体的な例で言うと「インシデントチケットの起票はQAが行い、原因調査などは開発メンバーが行う」ことや、 「大容量テストに向けた設計をQAが行い、データの作成と実施を開発者メンバーに担当する」
といった想定される仕事の中でどの部分でだれが役割を分担するか確認しておきましょう。

7.あってはならないこと

プロダクトにおける「あってはならないこと」などは聞いておくとテストの優先順位や、品質目標を決める助けになります。
今後リスクになりそうな部分について事前に聞いておきましょう。
ここで聞いた内容は当たり前品質における観点材料やリスクベースドテストの分析材料など、様々な場所で再利用ができます。

まとめ

開発チームに参加した時によく聞かれそうな、聞いておけばよかったと思った内容をまとめてみました。
IEEE829はテスト計画書の作成に使われ、テストにおける共通認識を用意するには有用です。また今回確認したチェック項目は時間の経過とともに変わっていくこともあるので定期的に見返してみることも重要だと思います。
QAエンジニアといっても自動化が得意な人、テストのプロセス改善が得意な人などいろんなタイプがいますので、アサインした人、された人の双方の理解が深まる手助けになればうれしいです。

プロダクトディベロップメントチーム解体新書!(技術・開発環境編)

みなさんこんにちは。松田(id:a-matsuda)でございます。
今回は、仲間も増えてきたプロダクトディベロップメントチーム(以下、PDチーム)を解体したらどうなる?という企画で、計2回の連載でお届けします♪ 今回は、技術・開発環境編!
PDチームメンバーに、マクロミル社のセルフアンケートシステムQuestantでアンケートを行い、その結果をまとめました。

あなたの役割を教えて!

PDチームでは、弊社で提供している働き方改革プラットフォーム”TeamSpirit”や"TeamSpirit HR"を始めとしたファミリー製品の開発を行っています。
チームには、開発エンジニアだけでなく、プロダクト開発に関わるさまざまな役割のメンバーがおり、一人二役という場合もありますので(たとえばフロントエンドもサーバサイドも両方担当しているメンバーがいる、スクラムマスターは兼任など)、延べ数での割合はこのようになりました!

f:id:teamspiritinc:20171219161931p:plain

それぞれの役割や、開発プロセスについては、きっと近々、チームリーダーやプロダクトマネージャーが記事にしてくれることと思います!(id:dackdive id:a-kura

仕事で使っているキーボードを教えて!

続いて、みんなどんな環境で仕事しているんでしょうか? PCは、MacBook Proが9割、一部のメンバーがWindowsマシンを利用しています。
そんななか、キーボードには、みんなの個性が滲み出ているような・・・気がしたので、聞いてみました!

f:id:teamspiritinc:20171219144659p:plain

キーボードこだわりのあるメンバーは1/3程度でしたね。
その中でも、プログラマーから人気が高いそうですが、使うのに少し気がひけるという意見もある Happy Hacking Keyboard を利用しているメンバーに聞いてみました。

  • 打ち心地が気持ちいい!最高!
  • 俺って、できるエンジニアなんじゃないか?という気分になる!

あ”ーなるほどね。その様子をご覧ください。※●ラセではありません。 f:id:teamspiritinc:20171219162952j:plain

仕事で主に使っているエディタを教えて!

開発で利用するエディタも、エンジニアのこだわりが出る部分ですよね!

f:id:teamspiritinc:20171219143845p:plain

サーバサイドエンジニアから根強い人気のある「Eclipse」に続いて、2015年にリリースされたマイクロソフトのソースコードエディタ「Visual Studio Code」が台頭しています。その後に「Atom」や「Vim」が続き・・・。
なぜ「Visual Studio Code」なのか、利用しているメンバーに聞いてみました。

  • とにかく、軽くで動きが早い!
  • VSCodeの拡張機能でSalesforceと繋げることができるんです、これじゃなきゃ。

あなたの好きな言語を教えて!

TeamSpiritでは、サーバサイド:Salesforce Force.com Apex(Javaライクな言語)、フロントエンド:JavaScript(いろいろライブラリも使いつつ)で開発をしています。
開発メンバーは、仕事だけでなく趣味でも開発を楽しんでいるメンバーが多いので、どんな言語が出てくるのがワクワク!

f:id:teamspiritinc:20171219151606p:plain

やはり、Java/JS強し!!
少し古いデータではありますが、GitHubの総プロジェクト数ランキング(2016/2時点)では、上位から、JS、Java、Python、Ruby の順なので、この辺りはエンジニアに好まれる言語ということかもしれませんね!
(ちなみに、私はオブジェクト指向Javaが好きです)

最近興味のある技術分野を教えて!

たくさん出てきました。ええ、たくさん出てきました。 まとめられません。無理やりまとめますと・・

  • 機械学習・AI系
    TeamSpiritにも取り入れていきたい機械学習やAI。みんなで勉強しましょう。
  • 自分の業務の幅を広げたい系
    フロントエンドのメンバーはバックエンドの知識、バックエンドのメンバーはフロントエンドの知識、QAエンジニアは自動テストのスキルを身に付けたいなど
  • チーム開発・リーン開発系
    開発におけるアジャイル開発(現在もやっていますがさらに深めたいのでしょう)、ビジネスにおけるリーン開発とは・・のようなこと。
  • その他
    アクセシビリティ、ドメイン駆動設計など、今の業務で直面しているものから、コンテナー技術(Docker、Kubernetesなど)、ブロックチェーン、VRなど・・・うーん、みんな興味の幅が広いなぁ。。
  • 番外編
    プログラミングパラダイム(手続き型, オブジェクト指向型、関数型etc)とソフトウェアの設計って、なんか壮大だぞ。君の興味は、一体どこへ向かうのか。。。

まとめ

最後に何かまとめたいと思ったのですが、「最近興味のある技術分野」のところで、無理にまとめてはいけない(まとめられない)ことに気づきました。
個性あふれるメンバーが、それぞれの力が発揮できる環境で、パワフルに仕事をしています。次回の「人・趣味編」は、もう少しはっちゃけますので、お楽しみに!

最後に

この投稿は チームスピリット Advent Calendar 2017 - Adventar 第19日目の投稿になります。 毎日面白い投稿が行われていますので、ぜひ最後までチェックしてください! adventar.org

Platform EventとElectronでChatter Desktop的なものを作る

この記事は弊社アドベントカレンダーの 11 日目の記事です。
投稿日と一致しないのはお察しください。

エンジニアの山﨑( id:dackdive )です。
少し前から役割がフロントエンドエンジニアからプロダクトマネージャーに変わり、現在はプロダクトの仕様検討をメインで行っています。日々精進です。

さて、最近は Einstein、Big Object、Salesforce DX などなど、開発者の興味を引く新機能が続々登場していますが
今回はその中でも個人的に興味のあった Platform Event を試してみようと思います。

Platform Event の特徴

Platform Event は Summer'17 で正式リリースされた 機能です。機能の概要は webinar や公式ドキュメントに譲るとして、個人的には以下のような点が特徴として挙げられるかと思います。

  • イベントを「イベントオブジェクト」という形で、カスタムオブジェクトと同じように定義できる
  • Salesforce イベントを送受信するための方法として、複数の選択肢がある(Apex やプロセスビルダーなど)
  • Salesforce 内だけでなく、Salesforce と外部のアプリケーションとの間でイベントを送受信できる
    • 一例として、webinar のデモ では Heroku アプリケーションと通信しています

機能の概要を聞いたとき、「あれ、これって Electron でアプリ作ったらローカルでも受信できるんだろうか?そしたらもうすぐ廃止される Chatter Desktop の代替アプリみたいなもの作れないかな〜(Chatter Desktop はポーリングだったし)」という気持ちになったので試してみた次第です。

なお、Platform Event についての基本的な知識は以下の Trailhead モジュールで学ぶことができます。

特に後者は、Salesforce 内ではありますがイベントを Lightning Component で受信する簡単なアプリケーションを作ってみることで Publisher 側、Subscriber 側両方のイメージがつかめるのでオススメです。
(この記事を書いた時点ではまだ英語ですが。。。)

コード

今回作成したサンプルはこちらに置いてあります。

実装:Publisher 編

ここからは実装の話です。まずは Publisher 側から。

イベントオブジェクトを定義する

まずはイベントオブジェクトを定義します。
クイック検索で「プラットフォームイベント」と検索すると該当の項目が見つかります。

イベントオブジェクトの登録手順の詳細は Trailhead で説明されているため省きますが、カスタムオブジェクトとほぼ同様の手順で定義できます。
カスタム項目については、今回は Chatter のフィードに相当する FeedItem オブジェクトのデータ定義 を眺めつつ、必要になりそうなものを適当にピックアップしました。
(結局メッセージ本文に相当する Body しか使わなかった)

f:id:dackdive:20171215034808p:plain

イベントの Publisher を定義する(プロセスビルダー)

イベントオブジェクトを定義したので、次はこれを Publish するしくみを作ります。
Salesforce から Publish するための手段はトリガ、プロセスビルダー、フローなどいくつかありますが、今回はさくっと試すためプロセスビルダーを使用します。
プロセスビルダーはイベントの Publisher 側にも Subscriber 側にもなれます。

f:id:dackdive:20171215035428p:plain

Publisher 側として定義する場合、はじめにイベント発火のトリガーとなるオブジェクトを選び(今回は「フィード項目」)、ルール適用時のアクション種別として「レコードを作成」を選びます。
対象のオブジェクトを選択するプルダウンで、カスタムオブジェクトに混じって先ほど定義したイベントオブジェクトも候補に表示されます。

最後に、イベントオブジェクトの各カスタム項目とフィード項目オブジェクトの各項目をマッピングしてあげれば完成です。

実装:Subscriber 編

続いて、イベントを Subscribe する Electron アプリの方に移ります。
Electron アプリ開発の経験はほとんどないので環境構築で消耗しないよう、また JS のライブラリは React&Redux しか書けないので、今回は「electron react redux boilerplate」などのキーワードで検索してヒットした jschr/electron-react-redux-boilerplate からスタートします。

※ 余談ですが、今思うと chentsulin/electron-react-boilerplate の方がいいかもしれません...

$ git clone https://github.com/jschr/electron-react-redux-boilerplate chatter-desktop
$ cd chatter-desktop

$ yarn
# または npm install

# yarn run develop で起動

jsforce と CometD をインストール

認証およびアクセストークンの取得に jsforce を使います。
また外部アプリケーションで Platform Event を受信するためには CometD が必要です。npm 経由でインストールできるパッケージ があるので、それを使います。

$ yarn add jsforce cometd

Subscriber の実装

最後に、イベントを Subscribe する部分の実装です。

// app/containers/Root.js
import { connect } from 'react-redux';
import Root from '../components/Root';
import { addFeedItem } from '../actions/feedItems';

import jsforce from 'jsforce';
import lib from 'cometd';
const cometd = new lib.CometD();

const mapStateToProps = (state) => {
  return state;
};

// NOTE: ここを自分の環境に置き換え
const USERNAME = 'username';
const PASSWORD = 'password';

const mapDispatchToProps = (dispatch) => {
  return {
    initialize: () => {
      // (1) 認証・アクセストークン取得
      const conn = new jsforce.Connection();
      conn.login(USERNAME, PASSWORD, (err, userInfo) => {
        // (2) CometD の設定
        cometd.configure({
          url: `${conn.instanceUrl}/cometd/41.0`,
          requestHeaders: { Authorization: `OAuth ${conn.accessToken}` },
          appendMessageTypeToURL: false,
        });
        cometd.websocketEnabled = false;

        // (3) 接続&イベントの Subscribe
        cometd.handshake((handshakeReply) => {
          if (handshakeReply.successful) {
            console.log('Connected to CometD.');
            const newSubscription = cometd.subscribe('/event/FeedItemPosted__e',
              (platformEvent) => {
                console.log('Platform event received: '+ (platformEvent.data.payload));
                dispatch(addFeedItem(platformEvent.data.payload));
              }
            );
          } else {
            console.error('Failed to connected to CometD.');
          }
        });
      });
    },
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Root);

アプリケーションを Redux で作っているので多少関係ないところも含まれていますが、 initialize 関数の中身がメインです。
initialize はアプリケーションのルートコンポーネントがマウントされたタイミングで呼び出されるイメージです)

(1) 〜 (4) まで軽く補足します。

(1) 認証・アクセストークン取得

jsforce を使って認証している部分です。本来ユーザ名・パスワードはログイン画面のような形でユーザに入力させたものを使うべきですが端折ってしまってます。
認証に成功すると Connection オブジェクトからアクセストークンを取得できるようになります。

(2) CometD の設定

ここについては正直まだ設定内容を完全には理解しておらず、Trailhead のコード をそのまま流用しました。

CometD のエンドポイントは https://<インスタンス URL>/cometd/<API バージョン> となり、インスタンス URL は Connection オブジェクトから取得しています。
appendMessageTypeToURLwebsocketEnabled についてはなぜ false に設定する必要があるのかわかってませんが、これを指定しないとエラーになることは確認できました。

(3) 接続&イベントの Subscribe

接続部分については同様に Trailhead のコードをそのまま使っています。Subscribe するチャンネル名は

/event/<イベントオブジェクト名>__e

となります。
最後に、新しいイベントを受信するたび Redux の action を dispatch し、画面に描画しています。action, reducer および描画コンポーネントについては リポジトリ をご参照ください。

できたもの

f:id:dackdive:20171215045733g:plain

(左)Electron アプリ、(右)ブラウザ

UI まで手が回らなかったので、Chatter Desktop ぽさは一切ないですね。。。
あと <p> タグとか表示されてるのはリッチテキストなのを考慮していないからですね。

それでも期待通り near realtime なフィード表示は実現でき、Platform Event が Electron アプリでも受信できることを確認できました。よかった。

TODO

よくよく考えると、全ての投稿が流れてきてしまうので自分のフィードの内容とは違ってしまいます。。。
Chatter まわりのデータ構造を勉強せねばという気持ちになりました。

余談:Chatter Desktop の現状と今後

Chatter Desktop は Spring'17 で廃止され、これ以降に作成した組織では利用できなくなっていました。
参考:Spring'16 リリースノート
Spring'17 以前に作成した組織については引き続き利用が可能で、現在も動いています。

また、
Chatter デスクトップの廃止
によると、

Summer '18 リリース* をもって、Chatter デスクトップは廃止され、Salesforce によるサポートが終了します。その時点でこの機能は使用不可になり、Salesforce によるサポートの提供も終了します。

とあるので、これまで使えていた組織も 2018 年夏をもって使えなくなるんでしょうか。知らなかった。

気になる代替手段についてですが、Windows については Microsoft から 新しいデスクトップアプリ がリリースされていますが、Mac は今のところありません。果たして。。。

Google Homeから音声で出退社を記録する

家庭用のスマートスピーカー、まだ使いみちが思い当たらずに購入見送りのケースがほとんどでしょうか。ただ、これから家電と本格的に繋がってくると一気に普及していきそうで、市場規模としても2025年度に今年度比で9.2倍の成長が予測されていたりします。1

一方、オフィスにおいては、音声UIで業務が効率化できる分野も広がりつつあり、別の時間軸で導入が進みそうです。コミュニケーションロボットとして捉えると、こちらの市場規模は同期間で33.8倍!の成長予測です。

そんな折、Google Home Miniが各所で半額(税込3,240円)で買えるようでしたので、用途もあまり考えないまま入手。せっかくなので、音声によりTeamSpiritに対して出退社の打刻をする世界観を体感してみました。次のような会話で処理が行われます。

「OK, Google. 出社」
「TeamSpiritに出社を打刻します」

まずはデモ(動画)

こちらをご覧ください。


Google HomeからTeamSpiritに出社時刻を打刻する

どんな印象を持ちましたか?職場で使うイメージが湧きますでしょうか?

勤務表に記録されますので、企業に必要な36協定安全管理上の労働時間の把握がいつでも可能です。

実現方法(のポイントのみ)

今回はクイックに、ノンコーディング、TeamSpiritの標準機能で実現しています。処理の流れは次の様な感じです。

f:id:hwakabay:20171211192739p:plain

Google Assistant → IFTTT → GMail → Chatter → TeamSpirit

やったことは細かくは省きますが、以下の内容について設定しています。

1.Chatterの設定

メールでSalesforceのChatterに投稿する設定をします。

  • 勤怠投稿用のChatterグループを作成 ・・・①
  • グループへの投稿用メールアドレスを取得 ・・・②

2.TeamSpiritの設定

Chatterグループへの投稿により出退社を打刻する設定を行います。

  • Chatter打刻機能を有効化(システム設定の「Chatter 打刻を利用しない」をオフに)
  • 発言グループを設定(部署の発言グループに①のChatter グループを選択)
  • SalesforceユーザーのEmailにGMailアドレスを設定

3.IFTTTの設定

Google Assistantで音声で出退社を検知したら、GMailでChatterグループのメールアドレス充に投稿メールを送信させます。

  • ”This”に”Google Assistant”を指定(フレーズや回答を設定)
  • ”That”に”GMail”を指定(メール宛先に②のChatter投稿用メールアドレス、本文に”出社>”または”退社>”を設定)

以上、これだけでデモ動画の通りに動きました。

結びに

簡易的な設定による動作デモですので、本番運用で利用するにはいろいろ課題もあります。例えば以下のような点など。

  • 確実性の観点。打刻結果を受け取らないため、メール不着や二重打刻などにより打刻されないケースでも通知されません
  • 正確性の観点。打刻時刻はChatter投稿時刻となるため、メール遅延の場合は打刻も遅延となります
  • 端末制限への影響。スマホのGoogle Assistantから実行可能となり、IP制限している場合でも無力化されます
  • ユーザー認証への対応、メール運用ポリシー、その他、、。

このような前提ですので、本内容に関しての正式なユーザーサポートは致しかねますが、PCやスマホを使わずに自分の声で勤怠時刻を記録するこの世界観を試してみたい方は、ご参考にして頂ければと思います。

まだTeamSpiritをお使いでない企業様は、是非こちらからTeamSpiritが多くのユーザーに選ばれる理由をご覧ください!

この記事は「チームスピリット Advent Calendar 2017」の13日目です。
以上、若林(id:hwakabay)が執筆しました。

Slack×GAS 契約自動更新サービスの稟議忘れを防ぎたい!

こんにちは。開発チームで社内利用ツールの管理もしている松田(id:a-matsuda)です。
みなさん、開発に際して、いろんなクラウドサービスを利用しているのではないかと思います。

弊社でも

  • JIRA
  • Confluence
  • Cacoo
  • CirecleCI  などなど・・

様々なツールを利用して、開発プロジェクトやドキュメントの管理、開発工程の効率化などを行っています。 が、今回のテーマは、使っている開発ツールの便利な使い方、とかではありません!

こういったツールって、だいたいが契約自動更新ですよね?
再契約しなくて済むので、その点は非常に楽なのですが、反面、気づいたら社内の稟議期限が切れてしまいそうだった(しまっていた・・・汗!)なんてこと、ありませんか?

今回は、そんな危ない稟議漏れを防ぐ仕組みをSlack×GAS(Google Apps Script)で作ろうという内容です。

これまではどうしてた?

月初に1回、当月に更新切れになるものがないかをプロアクティブにチェックしていました。

困っていたこと

  • 管理するツールが20件を超えた時点で、自身の目が節穴になる。
  • 1ヶ月の無償期間を経て有償になるツールを利用したいというニーズが出てきた。
    この場合、2weeks検証したあとに、解約または契約(のあと、稟議)となるので、
    1ヶ月に1回じゃ間に合わない。

目的

自動更新されてしまう前に、漏れなく社内稟議、承認までを完了できるようにしたい。

実現したいこと

毎週月曜日10時に、契約しているクラウドサービスのうち、契約見直日(※)の14日前をきっているサービスがあったら、Slackに契約更新通知を行いたい。
(※解約通知が3ヶ月前というサービスもあります。弊社の場合は、解約通知日=契約見直日として、契約見直日の前に契約継続でいいかを判断したうえで、継続の場合は社内稟議をあげるルールとしています。)

使う技術要素

  • SlackのIncoming WebHooks
    Slackが発行するURLへPOSTするとSlackにメッセージが投稿される機能 api.slack.com
  • Google Apps Script
    Googleが提供するサーバーサイド・スクリプト環境

おおまかな流れ

1. スプレッドシートで契約一覧を作ろう
契約サービス名と契約見直日は、最低限管理をしておきましょう。 f:id:a-matsuda:20171212013126j:plain

2. SlackのIncoming WebHooksの登録しよう

  • https://(Slackドメイン名).slack.com/apps にアクセスします。
  • 上部に検索ボックスが表示されるので、そこで「Incoming WebHooks」という検索をすると、Incoming WebHooksの設定ページへと飛ぶことができます。
  • 「Add Configuration」をクリック後、投稿したいチャンネルを選択し、作成ボタンをクリックします。
  • 作成完了後、Webhook URLの項目に表示されるURLを次の章で使用します。

3. GASを作成しよう

function alertContract() {
    var mySheet = SpreadsheetApp.openById('シートID').getSheetByName('契約サービス一覧_sample'); //スプレッドシートを取得
    var lastRow = mySheet.getLastRow(); //スプレッドシートの最終行を取得
    var today = new Date(); //今日の日付を取得
  
    /* 契約見直日まで14日切っていたらSlack投稿 */
    for (var i = 2; i <= lastRow; i++) {
        var Di = mySheet.getRange(i, 4).getValue(); //サービス名(Di列)を取得
        var dateHi = new Date(mySheet.getRange(i, 8).getValue()); //契約見直日(Hi列)を取得
        var period = dateHi.getDate() - today.getDate(); //今日から契約見直日までの期間を取得
        if (period <= 14) { //2週間前に告知
          //通知文を作成
          var strText = "@matsuda.akiko " + Di + "の契約更新期限が迫っています。稟議を上げてください。期限:" + dateHi;
          //Slackへ投稿
          postSlack(strText);
        }
    }
}

function postSlack(strText) {
 
  //payload
  var payload  = { 
    'username'  : "Contract Notification",
    'text'      : strText,
    'link_names' : "1", //
  };
  var options = {
    'method'      : 'post'                 ,
    'contentType' : 'application/json'     ,
    'payload'     : JSON.stringify(payload),
  };
 
  // Webhook URL へPOSTする
  var url = 'https://hooks.slack.com/services/XXXX/XXXX/XXXX';  //「2.SlackのIncoming WebHooksの登録しよう」で払い出したURLを指定
  UrlFetchApp.fetch(url, options);
}

4. トリガーを登録しよう
「現在のプロジェクトのトリガー」アイコンをクリックし、トリガーの予定を登録して保存します。

f:id:a-matsuda:20171212014925p:plain

5. 無事Slackに投稿されました!
f:id:a-matsuda:20171212024256p:plain

つまづいたところ

  • チャネルに投稿するときに自分にメンションをしたかったのですが、最初はテキストにしか認識されませんでした。
    payloadの設定で、'link_names' : "1" に追加することで無事メンション認識されました!

こんなことにも応用してみた!

  • 私、採用も担当しております。googleカレンダーと連携し、翌日に面接に関連する予定が入っていたら、「ちゃんと面接の準備できてる?」とSlackで通知してくれる機能も作ってみました。 基本的な流れは一緒で、GASだけ下記ような感じで書いてみました。
function alertInterview() {
  //IDを指定してカレンダーを取得
  var calendar = CalendarApp.getCalendarById('カレンダーID');

  //翌日のイベントを取得
  var date = new Date();
 date.setDate(date.getDate() + 1);
  var events = calendar.getEventsForDay(date);

  //面談の予定があったらSlack投稿
  for (var i=0; i < events.length; i++) {
    var title = events[i].getTitle();
    var startTime = events[i].getStartTime()     
    var endTime = events[i].getEndTime()
    
    //面談の種類によりメッセージを振り分ける(実際はもう少し複雑・・)
    if(title.indexOf("面談") !== -1) {
      //通知文を作成
      strText = "@matsuda.akiko " + title + "面接の準備できてる?";
      //Slackへ投稿
      postSlack(strText);
    }  
  }
}

まとめ

大変簡単な技術ではありますが、Slack中心の生活を送っておられるエンジニアやチームマネージャー、私と同様に忘れっぽい方、忙しい方にも、Slackでのアラート通知は心強い味方になるでしょう。

おまけ

最後になりましたが、この投稿は チームスピリット Advent Calendar 2017 - Adventar 第12日目の投稿になります。 毎日面白い投稿が行われていますので、ぜひ継続してチェックしてください! adventar.org