<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by ひだしゅん on Medium]]></title>
        <description><![CDATA[Stories by ひだしゅん on Medium]]></description>
        <link>https://medium.com/@hidashun?source=rss-8cd39e8b76de------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*cQXiOzzxpj1WUD4NNzCuRw.png</url>
            <title>Stories by ひだしゅん on Medium</title>
            <link>https://medium.com/@hidashun?source=rss-8cd39e8b76de------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 12:02:44 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@hidashun/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[iOSDC Japan 2023参加しました]]></title>
            <link>https://medium.com/@hidashun/iosdc-japan-2023%E5%8F%82%E5%8A%A0%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F-feef68c26110?source=rss-8cd39e8b76de------2</link>
            <guid isPermaLink="false">https://medium.com/p/feef68c26110</guid>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[conference]]></category>
            <dc:creator><![CDATA[ひだしゅん]]></dc:creator>
            <pubDate>Mon, 04 Sep 2023 16:05:53 GMT</pubDate>
            <atom:updated>2023-09-04T16:05:53.030Z</atom:updated>
            <content:encoded><![CDATA[<p>去年はオンライン参加でしたが、今年はこのためだけにニコ動でプレミアム会員になり、かつ3日ともオフライン参加しました。</p><p>結論からいうとたくさん人がいてオフライン参加楽しいなと思いましたが、まだ見ていないセッションをニコ生で見る日が続きそうなので今のうちに覚えていることを書こうと思います。</p><h3>LTのペンライトが楽しい</h3><p>色んなカンファレンスでたいていはLTの時間があると思いますが、こちらは終了時間が迫ると発表者の推しの色のペンライトを振る、という視聴者参加方のLTで、みんなが振ると綺麗だし、一体感があってよかったです。もちろんLT自体の内容もかなり幅広くおもしろかったです。ピンチヒッターでおなじみのあの方が出てきて結構テンションがあがりました。</p><h3>オフライン参加でもニコ生は使う</h3><p>トラックが最大4つあるので、同じ時間に見たいトークがかぶる、という時が何度かありました。自分は事前にプレミアム会員登録をしておいたので、タイムシフト予約をしなくとも空き時間や帰ってから見たかったやつをすぐ見られてよかったです。まあ最初からYouTubeの方がいい、という説はありますけど、LTの時なんかは特にコメントが結構流れるので元ニコ厨としては懐しさがあってよかったです。</p><h3>久々の無限コーヒーがうれしい</h3><p>カンファレンスといえば永遠におかわりできる無限コーヒーなんですが、久々のオフライン参加でこれに出会えたので初日はトークの度におかわりするくらいの勢いで飲んでいました。朝は個数限定ですがミスドのドーナツもあるので、最高の組み合わせではと思います。</p><h3>サーロインアボカド弁当うまかった</h3><p>最終日のキッチンカーで売ってましたが、野菜も入ってるし量もそこそこあってよかったです。来年も食べたいです</p><h3>懇親会で話してくれた人に感謝&amp;すみません</h3><p>一人で参加したし知り合いもあまりいないので、酒の力で何人かに話しかけましたが相手してくれてありがとうございます。途中ちょっと声がでかくなってたのは覚えていて、すみませんという気持ちです。というかもっと色んな人と話してみたかったし、スタッフさんとも話してみたかったりします。</p><h3>コードレビューの企画、おもしろそうだった</h3><p>ぶっちゃけスポンサーブースに全然行けてないですが、唯一、たしかLINEさんのブースで、書かれているコードにレビューのコメントを付箋で貼る的なのをやっていて、他の人のコメントを読むのが面白いし、いい企画だなと思いました。まああからさまにおかしいものはコメントも限られてきますが、もっと全体を見ないと分からなそうなコメントをしてる人もいて、その辺がおもしろいなと思いました。</p><h3>こまかい気配りがある</h3><p>分厚いパンフレットや大きいノベルティの箱は何歳になってもわくわくするものなのでいいんですが、会場にはぶっちゃけ重くて持ってこないので、毎日その日だけのタイムテーブルが載ったパンフレットを配ったりしてくれるのはちゃんと考えられてていいなと思います。</p><p>あと部屋が混んできた時にもっと人が入れるように詰めてもらうのも「自分の右側が空いていれば詰めて」という分かりやすい指示の出し方でいいなと思います。</p><h3>トーク&amp;ポスターセッション良かった</h3><p>まず自分が本業でiOSをやるようになって、今回は自分の仕事でやっていることに関係のあるものを選んで聞きにいっていたので、以前よりかなり自分ごとが多くてそれだけでどのトークもおもしろかったです。</p><p>今回は事前に時間帯ごとに見るものを決めてタイムテーブルで星をつけておいたので、聞きたかったやつは全部聞けた気がします。</p><p>まあ全部良かったんですが、前夜祭は shimastripe さんのこの発表が分かりやすくてよかったです。まだ UIKit の部分はかなりあるので多分お世話になる気がしています。あと内容関係ないけど声がよくて聞き取りやすいなと思いました。</p><p><a href="https://fortee.jp/iosdc-japan-2023/proposal/e0cf0ad8-5334-49bf-bb13-04286c5e21d7">UIKit ベースの Custom UIContentConfiguration API を用いた複雑なカスタムセルの作り方</a></p><p>1日目は唯一、 Ask the speaker で質問に行ったのでこちらが印象に残っています。一方的に質問して教えてもらいましたが、他社の人に教えてもらっただけでこちらから返せるものはないが大丈夫なのか…?と不安になってきました。とりあえず林さんありがとうございました。</p><p><a href="https://fortee.jp/iosdc-japan-2023/proposal/0d9b9f20-70c7-4d62-bb7a-378aeb1bc18e">SwiftUI + KMM 開発で見えたそれぞれの長所と短所</a></p><p>最終日は、自社アプリではちゃんと Xcode Preview をまだ使えていないので、まつじさんのこの発表のアイデアが普通にすごいなと思ったし、実際に使いたいと思いました。最初からソースコードなども公開された状態で話が始まったので、クローンしたコードを見ながら話を聞けたのがよかったです。</p><p><a href="https://fortee.jp/iosdc-japan-2023/proposal/2bfb2b2e-5e5e-44a7-87c9-e0dc66819a1e">Xcode Previewを気軽に利用するためのDI戦略</a></p><p>ポスターセッションも色々あって全部は書けないんですが 417.72KI さんのブランチ運用の話を聞いてうちも近いかもと思ったり、ひめしさんのUserDefaultsに暗号化していれる話でなるほどーとなったり、去年めちゃくちゃ幕間に見た気がするuhooiさんのコードが読めたりしました。</p><p>他にも色々ありますが全時間分書くのは大変なのでここまでにします。</p><h3>来年も開催してほしい&amp;行きたい</h3><p>とてもいいイベントなので来年もオフラインで参加したいです。そういや全日マスク着用だったので来年はマスクなしでできる状況であってほしい…!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=feef68c26110" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Angular 10 の Date Range Picker の裏側]]></title>
            <link>https://medium.com/nextbeat-engineering/angular-10-%E3%81%AE-date-range-picker-%E3%81%AE%E8%A3%8F%E5%81%B4-5a51a0c8f6fa?source=rss-8cd39e8b76de------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a51a0c8f6fa</guid>
            <category><![CDATA[angular]]></category>
            <category><![CDATA[engineer]]></category>
            <category><![CDATA[angular-material]]></category>
            <dc:creator><![CDATA[ひだしゅん]]></dc:creator>
            <pubDate>Fri, 28 Aug 2020 09:04:22 GMT</pubDate>
            <atom:updated>2020-08-28T09:04:22.722Z</atom:updated>
            <content:encoded><![CDATA[<p>ネクストビートのエンジニアのひだです。早速ですが、弊社ではサービスのフロントエンドの多くに主に Google が開発しているフレームワーク、<a href="https://angular.io/">Angular</a> が使われています。</p><p>そして6月末に、この Angular の最新バージョンである 10 がリリースされました 🎉。今回はその追加要素の1つである Date Range Picker についてとりあげたいと思います。具体的にいうと、裏側を知ろう、ということで愚直にコードリーディングをしてみました。そこで分かったことをまとめたいと思います。</p><h3>Date Range Picker とは</h3><p>Angular の UI ライブラリである <a href="https://material.angular.io/">Angular Material</a> に追加された、日付の範囲(開始日と終了日)の選択ができる UI コンポーネントのことです。</p><p>細かいことをいうと、日付を選択できる Datepicker というコンポーネントが元々あり、それを日付の範囲選択にも対応させたもののことを Date Range Picker と呼んでいます。</p><p>Angular 10 のリリース内容については <a href="https://blog.angular.io/version-10-of-angular-now-available-78960babd41">Version 10 of Angular Now Available</a> にまとまっていますが、最初にこのコンポーネントの説明があります。</p><p>また実際の動作を見たい場合は、上のリンクの記事からも参照されている <a href="https://next.material.angular.io/components/datepicker/overview#date-range-selection">公式ドキュメント</a> でコード例と合わせて動作サンプルを見ることができます。</p><h3>コードリーディングのやり方</h3><p>ここで実際にどうやってコードを読んだのかについて先に説明しておきます。ただ、私が Angular 公式(?)のコードを読んだのは実は今回がほぼ初めてなので、効率的な読み方といった話ではなく、あくまでも実際にやった方法の話になります。方法としては</p><ol><li><a href="https://cs.opensource.google/">Google Open Source</a> の<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/">該当ディレクトリ</a>でまずオンラインで読む<br>(もちろん GitHub でも読めるのですが、こちらの方がある程度読みやすいと思います。<a href="https://www.youtube.com/watch?v=7C6IS2XWLco&amp;list=PLkUrrnO0bbijBRqp7pDsPr-bhV_TKZuSa&amp;index=8">この ng-japan OnAir の放送</a> で知りました)</li><li>あまりにもややこしいので読むのをあきらめる😩。というのは半分冗談で、ソースをダウンロードして、ローカルの開発サーバで実際に動かし、Webブラウザのデバッガでブレークポイントを置くなどしてややこしい部分の挙動を確認する</li></ol><p>2 は具体的にはこのようにやりました:</p><ol><li>Angular 10 のプロジェクト(スタイルはscssを利用)を作成する</li><li>Angular Material をインストールする</li><li><a href="https://github.com/angular/components">Github</a> から同じバージョンの components のソースをダウンロードし、src/material の中の datepicker ディレクトリだけを丸ごとプロジェクト内にコピーする</li></ol><p>これだけだとビルドができないので、更にこちらの修正をしました:</p><ul><li>.ts 内で .css を参照している場所を .scss に書き換える</li><li>.scss 内の @import &#39;../../cdk を @import &#39;~@angular/cdk に書き換える</li><li>.scss 内の@import &#39;../core を@import &#39;~@angular/material/core に書き換える</li></ul><p>最後に AppModule 等でこの datepicker ディレクトリから MatDatepickerModule をインポートしておけば、テンプレート内で Datepicker のコンポーネントを使うことができます(正確には MatNativeDateModule のインポートも必要です)。また当たり前ですが ローカルにソースコードがあると普段使っているエディタで定義ジャンプなどができて読みやすくなります。</p><h3>今回注目して読んだところ</h3><p>上の Google Open Source の<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/">該当ディレクトリのリンク先</a>を見てもらえば分かるのですが、Datepicker に関するファイルは<strong>約 50 ファイル程</strong>あります。なんと私はこれらを全て読みました😤。…というのは嘘で、仮に読んだとしてもこの記事で触れるには量が多過ぎるので、気になるところに注目して読むことにしました。</p><p>具体的にはドキュメントの「<a href="https://next.material.angular.io/components/datepicker/overview#date-range-input-forms-integration">Date range input forms integration</a>」のサンプルをややシンプルにした以下のコードの各要素について、それぞれどういう関係にあり、どのようにデータをやりとりしているのかを見ていきます。</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a34cc02dbce7fd7c39471e292927ee8d/href">https://medium.com/media/a34cc02dbce7fd7c39471e292927ee8d/href</a></iframe><p>ちなみにこのコンポーネントの TS ファイルはこうなっていますが、 rangeという FormGroup を用意している以外に特筆すべきことはありません。</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ed0bdc352d2ced49504c2dd4eaaa0ec6/href">https://medium.com/media/ed0bdc352d2ced49504c2dd4eaaa0ec6/href</a></iframe><h3>Date Range Picker の理解に必要なファイル6選</h3><p>以下にコード例と実際のUIの対応を図にしてみました。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NPjXdNp1EdCRjunfSYTm6Q.png" /></figure><p>基本的な構成として、まず青枠の mat-date-range-picker (以下、ピッカー)が全体を管理するコンポーネントになります。このコンポーネント自体は裏方的な役割で、画面に表示されません。このピッカーが表示する mat-datepicker-content が日付を選択するためのカレンダー式のUIになります。(なお緑枠の mat-datepicker-toggle はカレンダーの表示をトグルするためのコンポーネントです。他に特に説明することがないため今回は取り上げません。)</p><p>赤枠には複数のコンポーネントがありますが、メインは mat-date-range-input で、その下に matStartDate と matEndDate のディレクティブが付加された input があります。アプリケーションの他の部分とデータのやりとりをするのがこのインプット群で、ピッカーで日付を選択すると FormGroup の値に反映され、逆に FormGroup の値が更新されたり、テキストフィールドから直接日付を入力した場合はそれがピッカーに伝えられます。</p><p>そのやりとりに使われているのが MatRangeDateSelectionModel のオブジェクトで、ピッカーで通常は生成され、インプットやカレンダーUIにその参照を渡すことで共有します。</p><p>これが全体像で、対応するファイルは以下のようになっています:</p><ul><li>mat-date-range-picker … <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-picker.ts">date-range-picker.ts</a></li><li>mat-datepicker-content … <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-base.ts">datepicker-base.ts</a></li><li>mat-date-range-input … <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-input.ts">date-range-input.ts</a></li><li>matStartDate と matEndDate … <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-input-parts.ts">date-range-input-parts.ts</a> 、<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-input-base.ts">datepicker-input-base.ts</a> (継承元)</li><li>MatRangeDateSelectionModel … <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-selection-model.ts">date-selection-model.ts</a></li></ul><p>それでは次に一番重要な mat-date-range-picker を見ていきます。</p><h3>MatDateRangePicker とジェネリック型 S、D</h3><p><a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-picker.ts">mat-date-range-picker.ts</a> を開いて mat-date-range-picker のクラスを見てみます。このファイルは執筆時点のバージョンでたったの46行しかありません。なんだかすぐに読めそうで、良かったですね。ただしクラスの最初の行を読めば分かる通り MatDatepickerBase を継承していて、これが定義されている <strong>datepicker-base.ts は最新バージョンで654行あります</strong>。</p><pre>export class MatDateRangePicker&lt;D&gt; extends <strong>MatDatepickerBase</strong>&lt;<strong>MatDateRangePickerInput&lt;D&gt;,</strong> <strong>DateRange&lt;D&gt;,</strong> D&gt;</pre><p>実は MatDateRangePicker の処理は、以前から存在している単一の日付選択用の <strong>MatDatepicker とほぼ処理が共通</strong>で、それらが MatDatepickerBase に書かれています。ちなみに MatDatepicker のクラス定義はこちらです。</p><pre>export class MatDatepicker&lt;D&gt; extends <strong>MatDatepickerBase</strong>&lt;<strong>MatDatepickerControl&lt;D&gt;,</strong> <strong>D | null,</strong> D&gt;</pre><p>D って何だよ! という気持ちになりますが、あとで説明するので先に Base の方を見てみます。</p><pre>export abstract class <strong>MatDatepickerBase</strong>&lt;<strong>C extends MatDatepickerControl&lt;D&gt;</strong>, <strong>S</strong>, D = ExtractDateTypeFromSelection&lt;S&gt;&gt; implements OnDestroy, CanColor, OnChanges</pre><p>さらに C と S が出てきます。 C は上の方で載せた赤枠のエリア、つまりインプットの型になります。 S と D はこの Base の定義にヒントがあり、 ExtractDateTypeFromSelection という条件型から察するに、 S は Selection、 D は Date Type です。Selection って言われても分からんと思われるかもしれませんが、これが<strong>選択されている日付(複数/単一)を表す値の型</strong>になります。範囲選択だと DateRange&lt;D&gt; 、単一だとただの D というように使い分けることで、全く同じ Base で日付の選択処理ができるようにしています。</p><p>最後に D ですが、Date Type といえば普通は JavaScript 標準の Date じゃないのか? と思われるかもしれませんが、実際デフォルトは Date です。「なぜ Date になるのか」を知るためには DateAdapter について知っている必要があります。Datepicker は日付の型を D としておくことで開発者が自由に変更できるようにしてあり、実際に D についての処理をするのが DateAdapter&lt;D&gt; です。 上の方で MatNativeDateModule を説明もなくインポートしていましたが、このモジュールが NativeDateAdapter を提供しており、<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/core/datetime/native-date-adapter.ts;l=71">この定義</a>を見ると DateAdapter&lt;Date&gt; を継承していることが分かります。</p><pre>export class NativeDateAdapter <strong>extends DateAdapter&lt;Date&gt;</strong></pre><p>これが MatDatepickerBase の constructor にインジェクトされると、 D = Date になります。</p><pre><em>constructor</em>( // 一部引数を省略<br>            @Optional() <em>private </em>_dateAdapter: DateAdapter&lt;D&gt;,<br>            <em>private </em>_model: MatDateSelectionModel&lt;S, D&gt;)</pre><p>ちなみに MatMomentDateModule を追加でインストールすると Date の代わりに Moment を使うことができます。</p><h3>ただのデータではない、MatDateSelectionModel</h3><p>上で Selection として出てきた DateRange&lt;D&gt; や、Datepicker で モデルとして使われる MatDateSelectionModel は <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-selection-model.ts">date-selection-model.ts</a> にまとまっています。</p><pre>export abstract class<em> </em>MatDateSelectionModel&lt;S, D = ExtractDateTypeFromSelection&lt;S&gt;&gt;</pre><p>この抽象クラスを継承した以下が実際に範囲選択で使われるモデルです。</p><pre>export class<em> </em>MatRangeDateSelectionModel&lt;D&gt; extends<em> </em>MatDateSelectionModel&lt;DateRange&lt;D&gt;, D&gt;</pre><p>このモデルがどこからやってくるのかというと、MatDateRangePicker のメタデータを見ると分かります。</p><pre>@Component({<br>  // 一部省略<br>  providers: [<strong>MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER</strong>]<br>})</pre><p>providers で MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER を指定しています。この provider はファクトリーメソッドを持っていて、MatDateRangePicker が作られる際にそのファクトリーメソッドを使ってモデルを生成し、constructor に渡します。</p><p>MatDateSelectionModel のコードは割とシンプルですが、ポイントとしては内部に S (Selection、つまり範囲選択の場合はDateDange&lt;D&gt;)を保持していることと、以下のメソッドで外部から値を更新できるようにしていること、</p><pre>updateSelection(value: S, source: unknown)</pre><p>そして以下を公開することで他のコンポーネントが値の変更を検知できるようにしていることが挙げられます。</p><pre>selectionChanged: Observable&lt;DateSelectionModelChange&lt;S&gt;&gt;</pre><p>モデル、というと単なるデータのようなものを想像したのですが、単なるデータを class でラップしてデータの入出力機能をつけたのが MatDateSelectionModel ということになります。</p><h3>コンポーネント間の連携の仕組みその1</h3><p>ここではまず MatDateRangePicker と MatDateRangeInput の連携を見ていきます。上と同じ図を再掲しますが、 mat-date-range-picker と mat-date-range-input を見ると前者が #picker で参照できるようになっていて、それを後者に [rangePicker]=&quot;picker&quot; としてセットしています。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NPjXdNp1EdCRjunfSYTm6Q.png" /></figure><p>結論をいうと正にここで連携をしているのですが、 picker がセットされるとインプットの方で<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-input.ts;l=100">以下のメソッド</a>が呼び出されます。</p><pre><em>set </em>rangePicker(rangePicker: MatDateRangePicker&lt;D&gt;) {<br> // 一部省略<br> <em>this</em>._model = rangePicker._registerInput(this);<br> <em>this</em>._rangePicker = rangePicker;<br> <em>this</em>._registerModel(<em>this</em>._model!);<br>}</pre><p>ピッカーの <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-base.ts;l=420">_registerInput</a> を呼んでいて、その内容はこのようになっています。</p><pre>_registerInput(input: C): MatDateSelectionModel&lt;S, D&gt; {<br>  // 一部省略<br>  <em>this</em>._datepickerInput = input;<br>  return<em> </em>this._model;<br>}</pre><p>要はインプットに対してピッカーがセットされた時に、ピッカーからインプットにモデルの参照を渡すようになっていて、お返しに(?)インプットは自分の参照をピッカーに渡しているイメージです。インプットの _registerModel はさらにその子(具体的には matStartDate と matEndDate)にモデルを渡しています。子の <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-input-base.ts;l=186">_registerModel</a> では以下のようにモデルの selectionChanged を購読していて、こうすることでモデルのデータに変更があったらインプット側にそれを反映させる、ということができています。</p><pre>_registerModel(model: MatDateSelectionModel&lt;S, D&gt;): void {<br>  this._model = model;<br>  this._valueChangesSubscription.unsubscribe();<br><br>  if (this._pendingValue) {<br>    this._assignValue(this._pendingValue);<br>  }<br><br>  this._valueChangesSubscription = <strong>this._model.selectionChanged</strong>.<strong>subscribe</strong>(event =&gt; {<br>    // 省略<br>  });<br>}</pre><p>もう1つ細かいポイントとして _pendingValue が挙げられます。勘のいい方はお気付きかもしれませんが、この _model は最初は undefined です。例えばインプットに初期値がセットされていて、かつモデルがまだセットされていない場合はその初期値の行き場がないので、いったん _pendingValue に入れておき、モデルがきたらそれをモデルに入れて以降はモデルを使う、という仕組みになっています。</p><h3>コンポーネント間の連携の仕組みその2</h3><p>次に MatDateRangePicker と MatDatepickerContent の連携ですが、基本的にはピッカーからカレンダーUIを表示する際に連携をします。ちょっと興味深いのは、<strong>スマホとPCで別の表示の仕方ができるようにしている点</strong>です。 mat-date-range-picker に <a href="https://next.material.angular.io/components/datepicker/overview#touch-ui-mode">touchUi</a> というオプションをセットすることで、カレンダーがパネルではなくダイアログで開くようになります。</p><p>パネルの場合は CDK の <a href="https://next.material.angular.io/cdk/portal/api#ComponentPortal">ComponentPortal</a> を使い、ダイアログの場合は <a href="https://next.material.angular.io/components/dialog/overview">Mat Dialog</a> を使っていますが、どちらも表示する内容は MatDatepickerContent (以下、コンテント)です。</p><p>ピッカーからコンテントを開く時に <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-picker.ts;l=36">_forwardContentValues</a> という以下のようなメソッドを呼んでいて、自分(ピッカー)の参照をコンテント側にセットするなどしています。</p><pre>protected _forwardContentValues(instance: MatDatepickerContent&lt;DateRange&lt;D&gt;, D&gt;) {<br>  <strong>instance.datepicker = this</strong>;  // 継承元の処理<br>  instance.color = this.color;  // 継承元の処理<br><br>  const input = this._datepickerInput;<br><br>  if (input) {<br>    instance.comparisonStart = input.comparisonStart;<br>    instance.comparisonEnd = input.comparisonEnd;<br>  }<br>}</pre><p>ここでのポイントは、このメソッドで<strong>モデルを渡していないこと</strong>です。では、一体どこでモデルを渡しているのでしょうか? 🤔</p><p>例えば MatDialog を普段使うときは、<a href="https://next.material.angular.io/components/dialog/overview#sharing-data-with-the-dialog-component">ダイアログを開くメソッドの引数に data を渡す方法</a>でデータを渡すことがあると思います。では<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-base.ts;l=494">その部分</a>を見てみましょう 👀</p><pre>this._dialogRef = <strong>this._dialog.open</strong>&lt;MatDatepickerContent&lt;S, D&gt;&gt;<strong>(MatDatepickerContent</strong>, <strong>{</strong><br>  <strong>direction:</strong> this._dir ? this._dir.value : &#39;ltr&#39;,<br>  <strong>viewContainerRef:</strong> this._viewContainerRef,<br>  <strong>panelClass:</strong> &#39;mat-datepicker-dialog&#39;,<br>  // 一部省略<br><strong>})</strong>;</pre><p>実際にソースコードを見てもらえば分かりますが、data は出てきません。謎は深まるばかりです…といったところでネタバラしをすると、ポイントはコードのこの部分です:</p><pre><strong>viewContainerRef</strong>: this._viewContainerRef,</pre><p>詳しくは <a href="https://next.material.angular.io/components/dialog/api#MatDialogConfig">MatDialogConfig</a> の viewContainerRef オプションの説明を読んでいただくとして、<strong>ピッカーからコンテントへモデルを渡す方法はインジェクション</strong>です。ピッカーから viewContainerRef を指定してダイアログを表示すると、そのダイアログがピッカーの子になります。そして <a href="https://angular.io/guide/hierarchical-dependency-injection#elementinjector">ElementInjector</a> の機能により、子はインジェクトが必要なものがある場合、親までさかのぼってそれを探します。結果、親であるピッカーにインジェクトされたモデルが子であるコンテントにもインジェクトされる、というのが真相です。</p><h3>モデルを外から操作するには?</h3><p>ここまで、モデルがコンポーネント間でどう受け渡しされているのかを見てきましたが、これらを使っている親コンポーネントからモデルを操作したい場合はどうすればいいでしょうか。</p><p>最初の方に見た通り、<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-base.ts;l=373">MatDatepickerBase の constructor</a> にモデルがインジェクトされるのですが、private であるため外からモデルを触ることはできません。また protected ではないため継承して中から操作することもできません。</p><pre><em>constructor</em>(// 一部省略<br>            <strong><em>private</em></strong><em> </em>_model: MatDateSelectionModel&lt;S, D&gt;)</pre><p>万策尽きた 😩と言いたいところですが、その方法はここまでの説明で既に出てきています。そう、<strong>インジェクション</strong>です。以下は MatDateRangePicker を使っているコンポーネントでそれをやってみた場合の例です:</p><pre>@Component({<br>  selector: &#39;app-date-range-picker-form&#39;,<br>  templateUrl: &#39;./date-range-picker-form.component.html&#39;,<br>  <strong>providers: [MAT_RANGE_DATE_SELECTION_MODEL_PROVIDER],</strong><br>})<br>export class DateRangePickerFormComponent&lt;D&gt; {<br>  constructor(<br>    <strong>private model: MatDateSelectionModel&lt;DateRange&lt;D&gt;, D&gt;</strong><br>  ) {<br>  }</pre><pre>  // 省略<br>}</pre><p>親コンポーネントにモデルをインジェクトしてしまえば、後は何もしなくても ElementInjector が子の MatDateRangePicker に同じものをインジェクトしてくれます。これにより、親コンポーネントも含めて各コンポーネントが同じモデルを参照することになり、親側でもモデルに対して updateSelection を実行したり、 selectionChanged で変更検知をしたりすることができます。</p><h3>落穂拾い</h3><p>最後に何点か、コードを読んでいて気付いたことを挙げておきます。</p><ul><li>日付のフィールドにカーソルを置いて Alt (Mac の場合は Option) + ↓ (下矢印)を押すとカレンダーUIが開きます。実際に処理が定義されているのは<a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/datepicker-input-base.ts;l=290">こちら</a>です。</li><li>コンポーネントの共通処理をまとめる場合、 @Directive をつけたabstract class として定義して、各@Component の class でそれを継承するのが王道パターンのようです。</li><li>パフォーマンス対策として <a href="https://cs.opensource.google/angular/components/+/10.0.x:src/material/datepicker/date-range-picker.ts;l=30">changeDetection: ChangeDetectionStrategy.OnPush</a> はおそらく必須です。</li></ul><h3>まとめ</h3><p>という訳で初めて公式のコードを読んでみたのですが、最初はジェネリック型が何で、どこから出てくるのかよく分からなかったり、やたらとアンダースコアで始まる命名が多かったり、datepicker-base.ts に重要なクラスが複数書かれていて「なぜファイルを分割しないのか…」と思ったり、date / range / picker / input / base のような単語が色々な組み合わせで出てきてどれがどれだか分からなくなったりしましたが、だんだん把握できてくるとおもしろくなってきました。特にインジェクションについては雰囲気でやっているところがあるので、今回改めて調べたことで以前より理解できるようになった気がします。</p><p>今後こういったコードを読む時も、ジェネリックな型、 @Component/@Directive とproviders、constructor、viewContainerRef 辺りにまず注目すれば読みやすそう、ということも分かりました。</p><p>一方で今回分かったことを普段の開発でも活用できるかというと、ここまできっちりインターフェースを使って疎結合にしたり、ジェネリック型で型を取り替えられるようにしたり、というのはあまりやらないかもしれない、と思います。ただそういうことをしたくなった時のために知っておくのは悪くないのでは、と思います。</p><p>それではここまで読んでいただき、ありがとうございました 🙇</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a51a0c8f6fa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/nextbeat-engineering/angular-10-%E3%81%AE-date-range-picker-%E3%81%AE%E8%A3%8F%E5%81%B4-5a51a0c8f6fa">Angular 10 の Date Range Picker の裏側</a> was originally published in <a href="https://medium.com/nextbeat-engineering">nextbeat-engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AWS Lambda で S3 の動画のサムネイルを作る]]></title>
            <link>https://medium.com/castalia-blog/aws-lambda-%E3%81%A7-s3-%E3%81%AE%E5%8B%95%E7%94%BB%E3%81%AE%E3%82%B5%E3%83%A0%E3%83%8D%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E3%82%8B-d0c130cef793?source=rss-8cd39e8b76de------2</link>
            <guid isPermaLink="false">https://medium.com/p/d0c130cef793</guid>
            <category><![CDATA[aws-lambda]]></category>
            <category><![CDATA[japanese]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[ひだしゅん]]></dc:creator>
            <pubDate>Mon, 20 Jun 2016 01:29:27 GMT</pubDate>
            <atom:updated>2016-06-20T01:29:27.983Z</atom:updated>
            <content:encoded><![CDATA[<p>Castalia のエンジニアの飛田です。ちょっと時間が経ってしまいましたが、今月の頭に AWS Summit Tokyo 2016 が開催されたので行ってきました。自分は Day2 の Developers Conference だけ参加したのですが、こちらのイベントの複数のセッションでとりあげられていたのが今回のテーマの「AWS Lambda(以下、Lambda)」でした。</p><p>自分は普段は Lambda をほとんどさわっていないのですが、せっかくイベントでも話を聞いたので、動画のサムネイル作成をやってみました。といっても、またしても(?)自分でコードを書いた訳ではなく、github にあがっている <a href="https://github.com/binoculars/aws-lambda-ffmpeg">https://github.com/binoculars/aws-lambda-ffmpeg</a> を使ってみました。あ、ふだんはちゃんとコードを書いています…汗</p><h4>binoculars/aws-lambda-ffmpeg で何ができるのか</h4><p>この Lambda は 2 つの S3 バケットを使うのですが、片方の入力用に設定した S3 バケットに特定の拡張子 (mp4など) の動画をアップロードすると、それがトリガーになって Lambda が実行されて、少し待つともう1つの S3 バケットにリサイズされた動画とサムネイルの2つが作られます。</p><p>変換後の動画やサムネイル画像の形式、最大幅は設定ファイルで指定できますが、例えば1つのバケットで完結させたいとか、今回の記事のようにサムネイル画像だけ生成したい場合は少しコードの方をいじる必要があります。それはこの記事の後半で触れることにして、まずはそのまま使う方法を説明していきます。</p><h4>リポジトリの具体的な内容</h4><p>このリポジトリの内容ですが、Lambda の言語は node.js が使われています。具体的にはこの node.js を作った Lambda 用のファイル一式をビルドして、AWS 環境にデプロイしてくれる gulp のコマンドが入っています。</p><p>コマンドが具体的にどんなことをやってくれるかというと、まず動画サムネイル作成用の ffmpeg をダウンロードして、それから設定ファイルを元に Lambda 用のビルドを行って、それを S3 にアップロードしてくれます。それから CloudFormation を使って、動画のアップロード先や Lambda の実行ファイルの置き場所に使うなど、目的ごとの S3 バケットを作成したり、権限や Lambda の設定をやってくれます。</p><p>基本的にはコマンドを叩けばすぐに環境ができあがるようになっています。なお一度デプロイしたあとでコードだけ更新する用のコマンドもちゃんとあります。コマンドのコードはルートの gulpfile.js と、platform/aws/gulpfile.js に書かれています。</p><h4>準備</h4><p>基本的にはコマンド 1 発! のはずなのですが、いくつか準備が必要で、やっていなかった自分は何回かやり直すはめになりました…。</p><p><a href="https://github.com/binoculars/aws-lambda-ffmpeg#setup">binoculars/aws-lambda-ffmpeg</a></p><p>セットアップについては上のリンク先に書いてあるのですが、若干分かりづらいので補足すると、 4 で Lambda のファイルを置く用のバケットを指定します。あらかじめ作っておきます。</p><p>5 では config/aws.json の編集をします。変更必須なのはこのへんです。</p><ul><li>functionBucket: 4 のバケット</li><li>sourceBucket: 動画をアップロードするためのバケット。このバケットはあとで CloudFormation で作るので自分で作らない。作ると CloudFormation の実行でエラーになる。</li><li>destinationBucket: リサイズされた動画とサムネイル画像が作られるバケット。CloudFormation で作るので事前に作っちゃだめ。sourceBucket と同じもだめ。なぜかというと sourceBucket でのファイル生成をトリガに Lambda を実行するので、Lambda によって sourceBucket にファイルが生成されたらまた Lambda が呼ばれてしまうため。</li></ul><p>7 の前にもいくつかやることがあって、まずはいつもの環境変数の設定です。ここの export を各自の値にして実行します(nvm 以下はもちろん関係ないのでやらなくていいです)。</p><p><a href="https://github.com/binoculars/aws-lambda-ffmpeg#example-local-testing-script">binoculars/aws-lambda-ffmpeg</a></p><p>7 の前にやらないといけないもう 1 つ大事なことが実行用のユーザに権限ポリシーをちゃんと設定しておくことです。本当は細かく設定すべきだとは思いますが、とりあえずこれを付与しました。</p><ul><li>AWSLambdaFullAccess</li><li>AmazonS3FullAccess</li></ul><p>また CloudFormation の権限は “Create User Policy” の “Policy Generator” から設定する必要があります。以下を設定します。</p><ul><li>CreateStack</li><li>UpdateStack</li><li>DescribeStackResource</li></ul><p>ここまでできたら gulp aws:default を叩けば待っているだけで全ての設定が完了します。コマンドが終わったらマネジメントコンソールで CloudFormation を見にいきます。ここでスタック作成が完了したら実際に Lambda を試せます。</p><p>画像が地味ですが、こんな風に SourceBucket に動画をアップロードすると</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*OY-le93cSJOcCO3ke7qADw.png" /></figure><p>DestinationBucket にリサイズされた動画とサムネイル画像が作られます。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*pXaREBvGXXf4xk04JaHBpA.png" /></figure><h4>改造してみる</h4><p>これで終わるのも何なので、ちょっと改造してみました。やったこととしては、動画の方は作らずに、サムネイル画像だけ作るようにして、かつ動画をあげたバケットと同じ場所に作られるようにしました。<br> 変更が必要なのはこの辺のファイルです:</p><ul><li>config/aws.json</li><li>platform/aws/cloudformation.json</li><li>platform/common.js</li></ul><h4>config/aws.json</h4><p>destinationBucket は sourceBucket と同じ値にします。ちなみに上で既にスタックを作っていた場合は、バケット名は別のものにしないとデプロイ時に「もうあるよ!」と怒られます。どうしても同じにしたければ、バケットの中身を全て消したあとでスタック自体を消します。</p><p>また format の中の video を消しておきます。残しておくとサムネイル画像しか作らないのに動画も S3 にあげようとしてエラーになります。image の方は JPEG にしたかったので extension = jpg、 mimeType=image/jpeg にしました。</p><h4>platform/aws/cloudformation.json</h4><p>Resources の DestinationBucket は不要なので消します。</p><p>Resources &gt; SourceBucket &gt; Properties &gt; NotificationConfiguration &gt; LambdaConfigurations の Event のあとに以下を追加します。同じバケットにサムネイル画像を作るとまた Lambda が実行されるので、ファイル名の後ろに .mp4 がつくものをあげた時だけ実行します。ただこの回避策だと当然 mp4 以外の動画が使えません(汗)が今回はこれでよしとします。</p><pre><br> “Filter”: {“S3Key”: {“Rules”: [{“Name”: “Suffix”, “Value”: “.mp4”}]}},<br></pre><h4>platform/common.js</h4><p>ffmpeg 関数の中をいじれば OK です。description はいらないので消すのと、あとは ffmpeg の動画出力に関わるオプションを消します。</p><h4>デプロイ</h4><p>変更できたら gulp で aws:default を実行します。バケットに動画をあげると今度は同じ場所に画像が作成されます。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*JsCd5yndZLUhrvGwH8R1Lg.png" /></figure><h4>注意</h4><p>間違ってビルドで作られたファイルの方(dist 以下)を変更すると、gulp でコマンドを実行した時に元の内容で上書きされて悲しい気持ちになるので気をつけましょう。。厄介なのはデプロイして初めて気付くことです。</p><p>Lambda が実行されてなさそうだったら、Lambda のページに CloudWatch のログへのリンクがあるのでそこからログを読んで原因を調べます。コードの変更だけなら aws:update で更新できます。</p><p>Lambda についてはリクエスト数など無料で使える範囲があるので、その点で手軽に試せていいなと思いました。CloudFormation に慣れていなかったのでそこで多少つまづきましたが、他人のライブラリを使ってかなり手軽に動画のサムネイル生成ができました。あと ffmpeg は普通にやるとインストールが結構面倒なんですけど、バイナリ配られてたんですね。。こういう小さくまとまった処理を、サーバーなしで使いたい場面でやはり Lambda は向いているなと思いました。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d0c130cef793" width="1" height="1" alt=""><hr><p><a href="https://medium.com/castalia-blog/aws-lambda-%E3%81%A7-s3-%E3%81%AE%E5%8B%95%E7%94%BB%E3%81%AE%E3%82%B5%E3%83%A0%E3%83%8D%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E3%82%8B-d0c130cef793">AWS Lambda で S3 の動画のサムネイルを作る</a> was originally published in <a href="https://medium.com/castalia-blog">Castalian’s Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[話しかけられた内容をそのまま Slack に流す Facebook Bot を Python で動かしてみた]]></title>
            <link>https://medium.com/castalia-blog/%E8%A9%B1%E3%81%97%E3%81%8B%E3%81%91%E3%82%89%E3%82%8C%E3%81%9F%E5%86%85%E5%AE%B9%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE-slack-%E3%81%AB%E6%B5%81%E3%81%99-facebook-bot-%E3%82%92-python-%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F-b00122cd6460?source=rss-8cd39e8b76de------2</link>
            <guid isPermaLink="false">https://medium.com/p/b00122cd6460</guid>
            <category><![CDATA[bots]]></category>
            <category><![CDATA[facebook-messenger]]></category>
            <category><![CDATA[japanese]]></category>
            <dc:creator><![CDATA[ひだしゅん]]></dc:creator>
            <pubDate>Tue, 19 Apr 2016 04:02:57 GMT</pubDate>
            <atom:updated>2016-04-19T04:02:57.580Z</atom:updated>
            <content:encoded><![CDATA[<p>Castaliaのエンジニアの飛田です。</p><p>最近、LINE や Facebook の Bot の API が試せるようになっているので、自分でも Facebook の方を試してみました。なお公式のチュートリアルはこちらです:</p><p><a href="https://developers.facebook.com/docs/messenger-platform/quickstart">Getting Started - Messenger Platform - Documentation - Facebook for Developers</a></p><h4>使ったもの</h4><p>基本的にほとんど自分でコードを書いた訳ではなくて組み合わせて動かしただけなので、タイトルも「動かしてみた」にしています。使ったものはこちらです：</p><ul><li>AWS API Gateway: HTTPS が必要だったので Proxy のためだけに利用</li><li>AWS EC2: Python の Flask アプリを動かすために利用。上のGatewayでこのサーバにプロキシします</li><li>Python の pymessenger ライブラリ: Bot API のラッパー。サンプルにエコー Bot の Flask アプリが入っているのでこれを少し書き換えて使います</li></ul><h4>必要なもの</h4><p>必要なものはこちらです：</p><ul><li>Facebook のアカウント</li><li>AWS のアカウント</li><li>Slack の Custom Integrations の Incoming WebHooks の Webhook URL</li></ul><p>以下、簡単な手順です。</p><h4>1. Facebook のデベロッパーサイトでアプリとページを用意してページアクセストークンを取得</h4><p>Bot を試すためには Facebook アプリの機能の1つとして送受信API を有効にすればいいだけなので、既存のアプリがあればそれを使ってもいいし、なければ普通にアプリを1つ追加します。</p><p>既存のアプリだろうと新規アプリだろうとやらなければいけないのはサイドバーの Messenger から Messengerプラットフォームの「スタート」をクリックすることです。</p><p>その後トークン作成のパネルで Facebook ページを作成してトークンを取得します。</p><p>次に Webhooks のセットアップに進みたいところですが、実際に Bot が動いていなければセットアップできないので、このページでの設定作業はここまでいったん終わりです。</p><h4>2. EC2 のインスタンスを起ち上げて Bot を動かす</h4><p>とりあえず t2.micro あたりのお金のかからないインスタンスを起ち上げます。OS は Amazon Linux にしておきました。Public IPさえあれば特に必要な設定はありません。セキュリティグループは作業用の SSH と API 用のポート(適当なポートでOK)を受け付けていれば問題ないです。</p><p>EC2 インスタンスに SSH でログインしたら Python3 と virtualenv をいれておきます。</p><pre>sudo yum -y install python34 python-virtualenv</pre><p>Bot 用の Python の環境を作って必要なライブラリをインストールします。</p><pre>virtualenv -p python3 myvenv<br>source ./myvenv/bin/activate<br>pip install flask pymessenger slackweb</pre><p>Bot のスクリプトは以下を書き換えて使います。Git を入れて clone してもいいですが、動かすだけならこのファイルだけでかまいません。</p><p><a href="https://github.com/davidchua/pymessenger/blob/master/examples/messengerbot.py">davidchua/pymessenger</a></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9007160b24555afd7a9a5e8a1d5bfd8f/href">https://medium.com/media/9007160b24555afd7a9a5e8a1d5bfd8f/href</a></iframe><p>書き換えた後のスクリプトは左のようになります。</p><p>9行目の TOKEN のところに 1 で取得したトークンを入れます。</p><p>13行目には Slack の Webhook URL を入れます。</p><p>18行目の “0123456789” は自分で好きな文字列をいれます。URLに入れるので半角スペースなどは避けておくのが無難です。あとで Facebook の設定画面等で使うので覚えておきます。</p><p>起動します。</p><pre>nohup python messengerbot.py &gt; $HOME/out.log 2&gt; $HOME/err.log &lt; /dev/null &amp;</pre><p>試しにアクセスしてみます。verify_token は上の18行目に入れたものを使います。”works” が返ってきたら成功です。SSH を抜けて API Gateway の設定に移ります。</p><pre>curl &quot;localhost:5002/webhook?hub.verify_token=0123456789&amp;hub.challenge=works&quot;</pre><h4>3. API Gateway で EC2 にプロキシする</h4><p>Create API で API を追加したら、メソッドを2つ追加します。</p><ul><li>Integration type: HTTP Proxy</li><li>HTTP method: GET と POST (ここだけ違うものをそれぞれ作ります)</li><li>Endpoint URL: http://[EC2 インスタンスの Public IP]:5002/webhook</li></ul><p>GET Method の方は、URL Query String Parameters に以下を追加しておきます。</p><ul><li>hub.verify_token</li><li>hub.challenge</li></ul><p>設定ができたら、Actions から Deploy API でデプロイします。Stage の名前は “beta” にしておきます。</p><p>デプロイがうまくいったら URL が表示されます。ブラウザから試しにアクセスしてみて、”works” が返ってきたら成功です。</p><pre><a href="https://**********.execute-api.**************.amazonaws.com/beta/?hub.verify_token=0123456789&amp;hub.challenge=works">https://**********.execute-api.**************.amazonaws.com/beta/?hub.verify_token=0123456789&amp;hub.challenge=work</a>s</pre><h4>4. FBアプリの送受信API Webhooks の設定</h4><p>手順の 1 のページで Webhooks の設定をします。</p><ul><li>コールバックURL: https://**********.execute-api.**************.amazonaws.com/beta/</li><li>トークンを確認: 0123456789</li><li>フォロー入力欄: とりあえず全部チェック</li></ul><p>設定できたら、公式チュートリアルにある通り以下のコマンドを叩いておきます。</p><pre>curl -ik -X POST &quot;https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=&lt;FBページのトークン&gt;&quot;</pre><h4>5. 動作テスト</h4><p>ここまでできたら、Bot 用に作成した FB ページのメッセージから Bot のテストができます。何かメッセージを書き込むと Slack にそのメッセージが表示されます。他の人も書いていますが、あまり反応の速度は速くないです。</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U8B5mJXEtC3GWLMFYJrJIQ.png" /></figure><p>以上、Messenger の Bot を試してみる簡単な手順でした。お疲れさまでした!</p><p>Amazon API Gateway は LINE Bot API に関するブログ記事で便利そうだったので初めて使ってみましたが、毎回違うIPからプロキシ先にアクセスしてくるあたりは使い方を気をつける必要がありそうです。</p><p>なお今回作成した Bot は特に実用性がないのですが(汗)、Facebook の Bot の機能には他にもユーザーに選択肢を表示するといったものがあるようですので、それらを試してみるとっかかりとしては手軽でいいかなと思いました。(おしまい)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b00122cd6460" width="1" height="1" alt=""><hr><p><a href="https://medium.com/castalia-blog/%E8%A9%B1%E3%81%97%E3%81%8B%E3%81%91%E3%82%89%E3%82%8C%E3%81%9F%E5%86%85%E5%AE%B9%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE-slack-%E3%81%AB%E6%B5%81%E3%81%99-facebook-bot-%E3%82%92-python-%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F-b00122cd6460">話しかけられた内容をそのまま Slack に流す Facebook Bot を Python で動かしてみた</a> was originally published in <a href="https://medium.com/castalia-blog">Castalian’s Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[コードレビューは愛である]]></title>
            <link>https://medium.com/castalia-blog/%E3%82%B3%E3%83%BC%E3%83%89%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AF%E6%84%9B%E3%81%A7%E3%81%82%E3%82%8B-7417363b378f?source=rss-8cd39e8b76de------2</link>
            <guid isPermaLink="false">https://medium.com/p/7417363b378f</guid>
            <category><![CDATA[japanese]]></category>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[ひだしゅん]]></dc:creator>
            <pubDate>Fri, 26 Feb 2016 05:21:54 GMT</pubDate>
            <atom:updated>2016-02-26T05:21:54.479Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*33I8ur4s_cG2sfPx4u_FAA.jpeg" /></figure><p>コードレビューは、正直あまり楽しくない作業です。</p><p>簡単なものや、量が少ないものはそんなに苦ではありませんが、複雑なものや、別のプロセスと連携するものなど、正直コードを読んでもよく分からない、ということがよくあります。</p><p>今回はコードレビューを自分がどう捉えているのか、そしてどんな風にやっているのか、について書きます。</p><h4>どこを見るのか?：自分の場合</h4><p>基本的には、自分は「バグを見つけること」に重点を置いています。</p><p>もちろん「もっと単純に書けるところを探す」「もっと速い処理に書き換えられそうなところを探す」「設計がまずいところを探す」「誤字を見つける」「コメントの間違いを見つける」「何をやっているのか分からないところについて質問する」などコードレビューでできることは色々ありますが、自分は究極的にはバグやエラーになるところをできるだけ探すようにしています。</p><p><em>動かない綺麗なコードより、動く多少汚ないコードの方がまし</em>だと思っているためです。どんなに綺麗なコードを書いたところで、使えなければ意味がないです。</p><h4>コードは読まない</h4><p><em>正直なところ、自分はそんなにちゃんとコードを見ません。</em></p><p>むしろ動かしてまず、今回の機能で新たにできるようにならないといけないことがちゃんとできるか、を確認します(逆にいうと何ができるようになるのか仕様が理解しづらいものほどレビューしにくいものはありません)。</p><p>それから入力等でできるだけおかしい入力や操作をしたり、データをほぼ空の状態にしてエラーになったりしないかを確認します(データが少ない時のチェックは、開発した本人は色んなテストデータを入れた状態で開発している分、忘れがちです)。</p><h4>それコードレビューじゃないのでは</h4><p>確かにそうです。正確にはコードを見つつ動作確認しているだけです。ただこの「コードレビュー」なら、割と誰でもできます。</p><p>本当は設計などのもうちょっとレベルの高いところの話をすべき場なのかもしれないですが、その辺りは自分の担当の範囲でいいと思う設計やいい書き方を心がけて、他の人がレビューした時に参考になることを目指す、という感じでもまあいいんじゃないかと思います。</p><p><em>「なぜこういう作りにすべきなのか」を説明しようとしても、将来その部分を変更することになった時でないと理解しづらいことが多い</em>と思います。</p><h4>全部のバグを見つけられるのか</h4><p>はっきりいって不可能だと思います。</p><p>でも「どうせできないからやらない」よりも、「できなくてもやらないよりはまし」という気持ちでやっています。</p><p>自分がレビューした結果、まずいところを全部見つけられなかったとしても、全くやらなかったよりはましだ、と考えます。大抵のコードは、書いた本人以外が1度見るだけでも、意外と本人が気づいていないことが見つかるものです。</p><p>逆にいえば、そういう理由から必ずコードレビューをすべきです。努力目標ではなく、<strong>必須</strong>です。片手間の時間つぶしではなく、開発と同じくらい重要なタスクです。エンジニア以外の人にもこのことはよく理解してほしいです。</p><h4>こんなスタンスになった訳</h4><p>元々働いていたソーシャルゲームの会社で、毎日、時には1日に数回リリース作業があったためです。</p><p>こんな速いペースでリリースを繰り返していたのでは、コードレビューの時間が十分にとれません。大量の差分を1時間以内に確認しなければいけないこともありました。</p><p>その時に思ったのが、「例え全部確認できなくても、全くやらないよりはやるべきだ」ということでした。余談ですが、1時間以内にレビューした時は普通にバグが出て、結構大変なことになりました。でも、やったことを無駄だとは思っていません。やっていなかったら、もっとひどいことになっていたかもしれないからです。</p><h4>コードをあまり読まずにコードレビューがしたいあなたへ</h4><ul><li>テストカバレッジが手元にあるなら、差分を見ながらカバーされていないところだけ読む、あるいはそこを通るように操作してみる。大抵クリティカルなバグはないけどちょっとしたバグは見つけやすい</li><li>JS がらみの変更は少なくともChromeの開発ツール等でエラーメッセージが出ていないか確認する</li><li>PyCharm などの JetBrains の IDE だったら、レビュー対象のコミットをログの画面から全部選択すると変更のあったファイルのリストが表示されるので、それを全部選択して「Inspect Code…」を実行する。些細なミスを見つけやすい</li><li>HTML を大幅に変更していたらブラウザ上の HTML をHTMLバリデーターにかけて問題ないか確認</li><li>MySQL であれば、DBを大幅に更新するようなバッチコマンドのレビューだったら mysqldbcompare で差分確認</li><li>とりあえず連打 &amp; 同じ操作を連続でやる &amp; バッチコマンドは2回叩く</li><li>とりあえずウインドウリサイズ</li><li>ログアウトして同じURLを叩く</li><li>想定されているフォーマット以外のものを送信 &amp; 入力する</li><li>とりあえず全部空で送信する</li><li>Webのフロントエンドの変更だったら普段使っていないブラウザで見る</li><li>変更された部分と似たような画面や機能を確認。同様に変更しないといけなかったり、あるいは影響してはいけないのにしてしまっていることがある</li><li>名称の変更があったらとりあえず変更前の単語でgrep検索。変更漏れがあるかもしれないので</li><li>とりあえずコメントは疑っておく</li><li>誤字が多い場合、大抵バグがあるのでその周辺をよく見る</li><li>CIで実行されないテストは大体怪しい</li><li>本当に時間がないなら、その機能を使う一番単純なフローを実行して問題ないか確認する</li></ul><h4>最後に：コードレビューは愛である。たぶんね</h4><p>それでもバグが起きてしまった場合、おそらく一番責められるのはそれを書いたプログラマです。</p><p>レビューした人も、できるのにレビューしなかった人も、動作テストした人も、できるのに動作テストしなかった人も、書いたプログラマほどは責められないと思います(ここは異論ありそうですが)。</p><p>なおここで「しなかった人」を挙げているのはもちろん、その人にも責任があると思っているからです。</p><p>そうならないようにするのが、自分にとってのコードレビューです。誰かにバグを出してほしくないからレビューします。バグが出ればもちろんユーザが困るし、本人だけでなく他の人も対応に時間を取られます。だからこそ、バグが出ると思われる箇所はしつこく指摘します。</p><p>一方で、レビューや動作検証で事前に防ぐことができたバグ、生まれる前に消し去られたバグのことは、関わっていない人は誰も知らないし、特に評価もされません。</p><p>まあそういう訳で(?)、プログラマにとって、コードレビューしてくれる人がいるっていうのは結構幸せなことなのです。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7417363b378f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/castalia-blog/%E3%82%B3%E3%83%BC%E3%83%89%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC%E3%81%AF%E6%84%9B%E3%81%A7%E3%81%82%E3%82%8B-7417363b378f">コードレビューは愛である</a> was originally published in <a href="https://medium.com/castalia-blog">Castalian’s Blog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>