こまどブログ

技術のこととか仕事のこととか。

WebページからDynamoDBにアクセスしてみる〜はじめてのAjax通信とDOM操作〜

前回のLINE Bot作成に引き続き、AWS関連です。Webアプリ側に寄せています。

ky-yk-d.hatenablog.com

前回やったこと

今回やること

  • Lambdaの裏側にDynamoDBを置く(前回はLambda側に全て記載されていた)
  • WebページからJavaScriptAPI GatewayAPIを叩く
  • 新たなデータを作成する/取得した結果を表示する

LINEボットを作成して、 API GatewayからLambda関数を呼び出す流れはわかりました。 前回は、API Gatewayの呼び出しはLINE側で用意されていましたが、今回はWebページからJavaScriptで呼び出してみます。また、 フレームワークを使ったWebアプリを作成した(編集した)経験はあるのですが、クライアントサイドJavaScriptを書いた経験はほぼゼロです。自分でWebアプリを作れるようになるには、クライアントサイドJSは避けて通れませんので、今回はその初歩をやってみました。

図示するほどのものではないのですが、憧れがあったので構成図を。素材は以下から。 ちなみに、PowerPointでペタペタ貼り付けてスクショ撮ったんですけど、色々間違っている気がします。

f:id:ky_yk_d:20180520201851p:plain
アーキテクチャ構成図(書いてみたかった)

API Gateway〜DynamoDBの設定は下記の書籍(198頁以下)を参照しました。

Amazon Dynamo DB の設定

テーブルを作成します。以上!

・・・

というわけには流石にいきませんが、リレーショナルデータベースと異なりスキーマを設定する必要がないので、確実に設定しなければならないのはテーブル名とプライマリーキーくらいです。

テーブル名はSAMPLE_TASKS、プライマリーキーはIDとしました。普段(リレーショナルDBでの)テーブル名やカラム名は大文字表記の場合が多いので、書籍の指示を無視して大文字にしたのですが、画面との連携を考えると小文字の方が良かったと思います(そして見返して思いましたがtasknameは小文字にしてますね・・・)

f:id:ky_yk_d:20180520233151p:plain
DynamoDB(データを入れた後の状態)

AWS Lambda の設定

Lambdaで設定する内容は以下の2点です。

  • DynamoDBFullAccessを付与したロールを割り当てる
  • 関数を記載する

今回は、LambdaからDynamoDBにアクセスするので、DynamoDBに対する読み書きの権限を有するロールをLambda関数に割り当てる必要があります。そこで、Lambda関数の作成の前にIAMロールを作成します。ロール作成画面で、「信頼されたエンティティの種類」でLambdaを、次の画面の「アクセス権限ポリシー」でDynamoDBFullAccessを選択しましょう。

f:id:ky_yk_d:20180520201842p:plainf:id:ky_yk_d:20180520201846p:plain

上記の手順でIAMロールを作成できたら、Lambda関数の作成です。「一から作成」を選択し、先程のロールを割り当てて作成します。今回は、ランタイムにはNode.js 8.10を選択しました。

Lambda関数の中身は今回はこのファイルひとつです。GETとPUTの両方をこの関数で受け付けます。

index.js

const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    const operation = event.method;  // API Gatewayのマッピングテンプレートで指定した"method"要素
    let params;
    switch (operation) {  // いずれのリクエストかによって分岐させる
        case 'GET':
            params = {
                TableName: "SAMPLE_TASKS", 
            };
            dynamo.scan(params, callback);
            break;
        case 'PUT':
            params = {
                TableName: "SAMPLE_TASKS",
                Item: {
                    "ID": event.body.Item.id,  //  "ID"はDynamoDBのカラム(?)名、"Item.id"は送信するJSON内の要素名
                    "taskname": event.body.Item.taskname
                }
            };
            dynamo.put(params, callback);
            break;
        default:
            callback('Unknown operation: ${operation}');
    }
};

Amazon API Gateway の設定

API Gatewayでは以下の手順で作業を行います。

  • APIの作成(sample_crud_tasks
  • リソースの作成(sample_tasks
  • GETメソッドとPUTメソッドを作成し、Lambda関数と紐づける
  • GETメソッドとPUTメソッドの双方の「統合リクエスト」に本文マッピングテンプレートを指定
  • ステージにデプロイ

f:id:ky_yk_d:20180520205451p:plainf:id:ky_yk_d:20180520220121p:plain
作成したAPI(GETメソッド) ※OPTIONはのちの過程で自動的に作成される

本文マッピングテンプレートを設定するところについては説明が必要と思われます。「統合リクエスト」をクリックして開く画面の最下部に「本文マッピングテンプレート」という項目があるので、Content-Typeの欄にはapplication/jsonと記載して追加します。上記の2番目のような画面になります。

本文マッピング・テンプレート(GET, PUT共通)

{
    "method": "$context.httpMethod",
    "body": $input.json('$')
}

送られてきたHTTPリクエストの内容を、受け手側のデータにマッピングして渡すもののようです。 $context.httpMethod は一見してわかるように使用されたHTTPメソッド名で、画面側のJavaScriptxhr.open()の第一引数で指定しているものです。Lambda側ではevent.methodとして参照されています。どのメソッドを使用したかによってLambda側で処理を変えるためのものですね。

$input.json('$')は入力されたxhr.send()の引数で渡した内容(=リクエスト本文)をJSON形式で読み取っています。こちらも、Lambda側でevent.bodyとして参照され、DynamoDBに登録するデータの取り出しに使われています。

API Gatewayマッピングテンプレートのリファレンスはこちら

API Gateway のマッピングテンプレートリファレンス - Amazon API Gateway

ここまでで、DynamoDBのためのAPIは完成です。

Webページ(HTML & JavaScript)の作成

さて、ここまでは専らAWSのお話(『実践AWS Lambda』に記載の内容)でした。ここからは作成したAPIをWebページから呼び出します。呼び出しただけではしょうがないので、以下の2つを実装します。

  • 簡単な入力フォームを用いたデータの追加(PUTなので同じIDなら更新になる)
  • DynamoDBのデータのリスト表示

使用する技術としては、以下のようなものです。

僕は「DOMってなに?モビルスーツ?」というレベルなので、極めて初歩的な内容となっています。また、jQueryなどを用いればAjaxはもっと簡潔に実装できるのだと思うのですが、色々なところから「jQueryはもう・・・」という声が聞こえてきています(例:You-Dont-Need-jQuery)。研修のときにjQueryがモダンなのだという話を聴いた気がしたのですが。

今後の開発のなかでjQueryを使いたくなるようなことがあれば学ぶことはやぶさかではないのですが、今回はJavaScriptの勉強をするという観点からも、ピュアJSで記述しました。また、HTMLファイルとJSファイルを別に作成すべきところなのでしょうが、今回はHTMLファイルに<script>タグで埋め込んでしまいました。どこかのタイミングで切り離します。ソースコードに重複も多いですし、リファクタをちゃんと考えてみたいです。

f:id:ky_yk_d:20180520233428p:plainf:id:ky_yk_d:20180520233431p:plainf:id:ky_yk_d:20180520233434p:plainf:id:ky_yk_d:20180520233436p:plain
こんな感じになる(大きさバラバラ・・・)

なお、今回のコードを実装するにあたっては、下記を参照しました。

tomosoft.jp

それでは実際のコードです。

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <form>
        <input id="ID" type="text" placeholder="IDを入力">
        <input id="taskname" type="text" placeholder="タスク名を入力">
        <input id="submit" type="button" value="送信">
    </form>
    <hr/>
    <div id="status"></div>
    <form>
        <input id="btn" type="button" value="取得">
    </form>
    <hr/>
    <div id="result"></div>
    <script>
        document.addEventListener('DOMContentLoaded', function(){
            document.getElementById('submit').addEventListener('click',function(){
                var status = document.getElementById('status');
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function(){
                    if (xhr.readyState === 4){ // 通信完了
                        if (xhr.status === 200) { // 通信成功
                            status.textContent = '送信しました';
                        } else {
                            status.textContent = 'サーバーエラーが発生しました';
                        }
                    } else {
                        status.textContent = '送信中';
                    }
                };
                var obj = {
                    Item : {
                        id: document.getElementById('ID').value,
                        taskname: document.getElementById('taskname').value
                    }
                };
                var json = JSON.stringify(obj);
                xhr.open('PUT', 'https://l3uk6hufcf.execute-api.ap-northeast-1.amazonaws.com/prod/sample-tasks', true);
                xhr.setRequestHeader('Content-Type', 'application/json');
                console.log(json);
                xhr.send(json);
            })
        })
    </script>

    <script>
        document.addEventListener('DOMContentLoaded', function(){
            // 取得ボタンクリック時に実行される
            document.getElementById('btn').addEventListener('click', function(){
                var result = document.getElementById('result');
                var xhr = new XMLHttpRequest();
                // 非同期通信時の処理
                xhr.onreadystatechange = function(){
                    if (xhr.readyState === 4){ // 通信完了
                        if (xhr.status === 200) { // 通信成功
                            //var data = JSON.parse(xhr.responseText);
                            var data = xhr.response;
                            // 結果からキーにアクセス
                            if (data === null) {
                                // ない場合はメッセージ
                                result.textContent = 'データが存在しません';
                            } else {
                                // 取得できた場合
                                console.log(typeof(data));
                                console.log(data)
                                var items = data.Items;
                                var ul = document.createElement('ul');
                                for (var i = 0; i < items.length; i++){
                                    var li = document.createElement('li');
                                    var text = document.createTextNode(items[i].ID + ' ' + items[i].taskname);
                                    // 組み立て
                                    li.appendChild(text);
                                    ul.appendChild(li);
                                }
                                // <div id="result">の配下を置き換える
                                result.replaceChild(ul, result.firstChild);
                            }
                        } else {
                            result.textContent = 'サーバエラーが発生';
                        }
                    } else { // 通信中
                        result.textContent = '通信中'
                    }
                };
                // 非同期通信を開始
                xhr.responseType = 'json';
                xhr.open('GET', 'https://l3uk6hufcf.execute-api.ap-northeast-1.amazonaws.com/prod/sample-tasks', true);
                xhr.send(null);
            }, false );
        } ,false);
    </script>
</body>
</html>

HTMLの部分はまぁいいとして、JSの部分を丁寧にみてみようと思います。

送信ボタンの処理

document.addEventListener('DOMContentLoaded', function(){
        / * 中略 */
        })

ページロード時に実行されるイベントリスナーを登録しています。/* 中略 */の部分に記載した内容が初期化処理になります。次は中身をみてみます。

document.getElementById('submit').addEventListener('click',function(){
        /* 中略 */
            })

submitボタンにイベントリスナーを登録しています。さきほどDOMContentLoadedを渡していた第一引数は、今回はclickとなっています。イベントリスナーの種類を指定しているのですね。クリックしたときに、第二引数で渡している関数オブジェクトが実行されるわけです。さらに括弧の中をみていきます。

var status = document.getElementById('status');     // HTMLのid="status"の要素を取得
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){                       // 通信の状態が変化したときに呼び出されるイベントハンドラ
    if (xhr.readyState === 4){ // 通信完了
        if (xhr.status === 200) { // 通信成功
            status.textContent = '送信しました';
        } else {
            status.textContent = 'サーバーエラーが発生しました';
        }
    } else {
        status.textContent = '送信中';
    }
};
var obj = {
    Item : {
        id: document.getElementById('ID').value,
        taskname: document.getElementById('taskname').value
    }
};
var json = JSON.stringify(obj);
xhr.open('PUT', 'https://l3uk6hufcf.execute-api.ap-northeast-1.amazonaws.com/prod/sample-tasks', true);
xhr.setRequestHeader('Content-Type', 'application/json');
console.log(json);
xhr.send(json);

非同期通信を管理するXMLHttpRequestが登場しています。onreadystatechangeプロパティには、通信の状態が変化したときに呼び出されるイベントハンドラを格納します。この例の場合、HTTP通信の状態(readyState)とHTTPステータスコードstatus)によって通信の状態を判断し、status.textContentにメッセージを代入することで通信状態を画面に表示しています。

後半では、PUTリクエストでJSONを送付する処理を記述しています。まず、送信したいJSONデータの元となるJavaScriptのオブジェクトをobjに代入し、それをJSON.stringify()で文字列形式に変換しています。次に、XMLHttpRequestオブジェクトのopen()メソッドで、HTTPリクエストの初期化を行います。第一引数がHTTPメソッド、第二引数がアクセス先URLです。第三引数以降はオプションで、ここでは第三引数にtrueを渡すことで非同期通信であることを明示しています(第三引数はデフォルトがtrueなので書いても書かなくても変わらないはずですが)。

重要なのは、xhr.setRequestHeader('Content-Type', 'application/json');の部分です。リクエストヘッダーを指定しています。API Gatewayで本文マッピングテンプレートを設定した際、「Content-Typeの欄にはapplication/jsonと記載して〜〜」と書いたことに対応しています。この処理の記述を省いてしまうと、リクエストは拒否されます(ステータスコード415)。この点については下記の記事が参考になるかと思います。

dev.classmethod.jp

リクエストヘッダーを指定したら、最後にJSON文字列をリクエストの本文としてsend()メソッドに渡して送信します。ここまでの処理が、すべて`「送信」ボタンをクリックした際に実行されます。

取得ボタンの処理

リクエスト送信時のJSON関係の処理がないこと以外、基本は送信ボタンの処理と同じです。ただ、こちらでは取得したデータをHTML側に埋め込むための処理が加わっています。

var data = xhr.response;
// 結果からキーにアクセス
if (data === null) {
    // ない場合はメッセージ
    result.textContent = 'データが存在しません';
} else {
    // 取得できた場合
    console.log(typeof(data));
    console.log(data)
    var items = data.Items;
    var ul = document.createElement('ul');
    for (var i = 0; i < items.length; i++){
        var li = document.createElement('li');
        var text = document.createTextNode(items[i].ID + ' ' + items[i].taskname);
        // 組み立て
        li.appendChild(text);
        ul.appendChild(li);
    }
// <div id="result">の配下を置き換える
result.replaceChild(ul, result.firstChild);

API Gateway(の背後にいるLambda)からはオブジェクト形式でデータが送られてきます。responseプロパティがレスポンスの本体です。それは下記のような形のデータです(ブラウザでAPIのエンドポイントに直接アクセスすると見られます)。

{
    "Items":[
        {"taskname":"test2","ID":"secondData"},
        {"taskname":"test","ID":"firstData"},
        {"taskname":"変更後!!!","ID":"aaa"}
    ],
    "Count":3,
    "ScannedCount":3
}

(参考)AWS-SDKのscanの仕様(英語)

取得されたデータの個数(Count)やスキャン対象となったデータの個数(ScannedCount※今回はフィルター適用していないのでCountと等しい)も一緒に送られてきていることがわかります。今回欲しいのはそれぞれのデータなので、Itemsを順に扱えば足ります。

ローカル変数itemsItemsの内容を代入したあとは、forループを使いながらid="result"の箇所に挿入する要素を作成しています。古典的なfor文で記載していますが、たぶんもっと近代的な書き方があるのだと思います。

仕上げ(CORSの有効化)

liul要素を順に作成したあと、最後にresult.replaceChild()で置き換えて、この無事表示ができました。めでたしめでたし。

と思いきや、この状態でindex.htmlにアクセスして、送信ボタンや取得ボタンを押すとエラーになります。クロスオリジン通信を可能にする必要があります。ブラウザのコンソールに、Access-Control-Allow-Originがなんちゃらかんちゃらと出るはずなので、これをコピーしてAPI GatewayAPIのアクションで「CORSの有効化」を選択し、Access-Control-Allow-Headersのところに上記のAccess-Control-Allow-Originを加えます。この設定をすることで、ようやくAPIをWebページから叩くことができます。

f:id:ky_yk_d:20180521001112p:plain

API Gateway リソースの CORS を有効にする - Amazon API Gateway

※XDR(Cross-Domain Request)は、元来セキュリティ上の必要性から制限されたもので、対応手段はCORS(Cross-Origin Resource Sharing)以外にも存在するようです。どの手段が適切であるかは、実践レベルでは要検討でしょう。

dev.classmethod.jp

JavaScript のクロス ドメイン (Cross-Domain) 問題の回避と諸注意tsmatz.wordpress.com

終わりに

はい。短くまとめるはずだったのに、今回も長くなってしまいました。個々の技術要素については入門的な記事や書籍がいくらでも存在しているので、あえて記事にするとすれば「実現したことベース」にして繋ぎ方を意識したものがいいかなと思ってるのですが、それゆえにこそ色々な要素を詰め込んでしまい、長くなってしまう傾向がありますね。これだけ長くなるとどこに何書いたかも忘れますし、構成や文章もグダグダになりがちです。なんとかしたいですね。技術的には、次はVue.jsとDynamoDBでも繋げてみようかと思っています。乞うご期待。

ソースコードについてはツッコミどころ満載であることは自覚しており、発展させながら直していこうと思っていますが、幾分初心者であるがために気づかないミスや改善点などあると思いますので、pull request・Issue等なげていただけるととても嬉しいです。

github.com

JS初心者がAWS Lambdaで実装するLINE Bot〜「オウム返し」の一歩先〜

先日まで、Vue.jsの勉強をしてきました。ところが、vue-cliがわけわからなすぎて「Node.jsも勉強しなきゃ」となっています。JavaScript自体にも理解が不足していることを実感してきました。

そこで、今回はNode.jsの勉強を兼ねてLINEのボット開発に挑戦です。以前、ネット上の記事をそのまま写す形で、Lambdaを用いてNode.jsでLINEのボット(オウム返しするだけ)作成していたので、今回はそちらを一歩先へ進めてみようと思います。

この記事が提供するもの

あらかじめお伝えしますが、この記事で紹介するのは、 LINEのMessaging APIを用いて簡単な会話を作成する方法 です。以下のようなことには触れません。

この記事で作成したコードのGitHubリポジトリ

ソースコードの全量および変更履歴はこちらをご参照ください。

github.com

今回の出発点:「オウム返し」

この記事の内容を概ねコピペした形となっています(最初のものを作ったのが少し前なので、そのときにどの記事をみて作成したのかは定かではありません)。

AWS、LINEの設定についてはこちらの記事の方が詳しいです。

今回の到達点

入力された文字列やボタンの選択に応じて、簡単なやりとりが成り立つようにしました。あらかじめ用意したJSON形式のメッセージを渡しているだけなので、チャットボットと言えるようなものではあいりません。あしからず。実際の画面は以下のような感じです。

f:id:ky_yk_d:20180517212449j:plain

修正後のコード(一部省略)

まずは、修正(機能追加+簡単なリファクタリング)後のコードを提示しておきます。大きな変更のなかった箇所については省略していますので、細かい修正履歴はGitHubをご覧ください(改善提案もお待ちしています)。

index.js

let https = require('https');

/**
 * Lambda実行時に呼び出されるハンドラ
 * @param {} event イベント
 * @param {} context コンテキスト
 * @param {} callback コールバック関数(正体は未確認)
 */
exports.handler = (event, context, callback) => {
    let messageObj;
    let replyToken;
    let jsonFile;
    let opts;
    let req;
    let data;
    let replyData;
    data = event.events[0];
    replyToken = data.replyToken;
// LINEでユーザから送られたテキストを取得
// メッセージオブジェクトを記述したJSONファイルを読み込む
// https://developers.line.me/ja/docs/messaging-api/reference/#anchor-e65d8a1fb213489f6475b06ad10f66b7b30b0072
    jsonFile = require("./dialogue.json");
// 入力に応じたメッサージの選択
    console.log(data);
    messageObj = getMessageObj(data, jsonFile);
// 返すデータを作成する
    console.log('データ作成');
    console.log(messageObj);
    replyData = JSON.stringify({
       replyToken: replyToken,
       messages: [
           messageObj
        ] 
    });
    console.log(replyData);
/* 〜共通部分中略〜 */
};

/**
 * 入力されたデータに応じて、返すメッセージを生成する関数
 * @param {} data 入力されたデータ
 * @param {} jsonFile 外部ファイルから読み込んだJSON形式のデータ
 * @return メッセージオブジェクト
 */
let getMessageObj = (data, jsonFile)=> {
    switch (data.type){
        case 'message':
            console.log('メッセージの場合');
            if (data.message.type != 'text'){
                // テキストメッセージ以外の場合
                console.log('テキスト以外のメッセージが入力された');
                return jsonFile.otherType;
            } else {
                // テキストメッセージの場合、入力された文字列に応じて分岐
                if (data.message.text == '住所') {
                    return jsonFile.dialogue2;
                } else {
                    return jsonFile.dialogue1;
                }
            }
        case 'postback':
            console.log('postbackの場合');
            return jsonFile[data.postback.data];
        default :
            console.log('それ以外の場合');
            console.log(data);
            return jsonFile.otherType;
    }
};

dialogue.json

{
    "dialogue1": {
        "type": "template",
        "altText": "テストメッセージ",
        "template": {
            "type": "buttons",
            "text": "メッセージありがとうございます!どんなことに興味がありますか?",
            "defaultAction": {
                "type": "uri",
                "label": "Twitterをみる",
                "uri": "https://twitter.com/ky_yk_d"
            },
            "actions": [
                {
                    "type": "uri",
                    "label": "ブログを読む",
                    "uri": "https://ky-yk-d.hatenablog.com/"
                },
                {
                    "type": "uri",
                    "label": "GitHubをみる",
                    "uri": "https://github.com/ky-yk-d"
                },
                {
                    "type": "postback",
                    "label": "次の質問に行く",
                    "data": "dialogue3",
                    "displayText": "別の質問がいい!"
                }
            ]
        }
   },
   "dialogue2": {
        "type": "location",
        "title": "東京スカイツリー",
        "address": "〒131-0045 東京都墨田区押上1丁目1−2",
        "latitude": 35.710139,
        "longitude": 139.810833
   },
   "dialogue3": {
        "type": "template",
        "altText": "メッセージ",
        "template": {
            "type": "buttons",
            "thumbnailImageUrl": "https://cdn-ak.f.st-hatena.com/images/fotolife/k/ky_yk_d/20180513/20180513094057.png",
            "imageAspectRatio": "rectangle",
            "imageSize": "cover",
            "imageBackgroundColor": "#000000",
            "text": "別の質問へを押しましたね?",
            "actions": [
                {
                    "type": "postback",
                    "label": "おわり",
                    "data": "end",
                    "displayText": "おわりにする"
                },
                {
                    "type": "uri",
                    "label": "やっぱりTwitter",
                    "uri": "https://twitter.com/ky_yk_d"
                }
            ]
        }
   },
   "otherType": {
       "type": "text",
       "text": "ごめんなさい!文章での入力をお願いします!"
   },
   "end": {
       "type": "text",
       "text": "お疲れ様でした!"
   }
}

メッセージオブジェクトを返却する

JSONファイル(dialogue.json)を新たに作成し、以下の部分で読み込んでいます。

jsonFile = require("./dialogue.json");

ここで読み込んだファイルには、複数のメッセージオブジェクトの内容が記載されています。下記の部分が一つのメッセージオブジェクトで、これを返却したものが上記のスクリーンショットの上部で表示されているものです。

"dialogue1": {
    "type": "template",
    "altText": "テストメッセージ",
    "template": {
        "type": "buttons",
        "text": "メッセージありがとうございます!どんなことに興味がありますか?",
        "defaultAction": {
            "type": "uri",
            "label": "Twitterをみる",
            "uri": "https://twitter.com/ky_yk_d"
        },
        "actions": [
            {
                "type": "uri",
                "label": "ブログを読む",
                "uri": "https://ky-yk-d.hatenablog.com/"
            },
            {
                "type": "uri",
                "label": "GitHubをみる",
                 "uri": "https://github.com/ky-yk-d"
            },
            {
                "type": "postback",
                "label": "次の質問に行く",
                "data": "dialogue3",
                "displayText": "別の質問がいい!" 
            }
        ]
    }
},

上記の例では、ボタンを表示するテンプレートメッセージを使用しており、それぞれのボタンには、リンクやpostback(後述)のアクションを持たせています。入力に応じて返すメッセージオブジェクトを切り替えることで、様々な機能を持ったボットを作成することができます。

様々なメッセージオブジェクト

他にも、メッセージオブジェクトには、以下のような種類があります。

  • テキストメッセージ
  • スタンプメッセージ
  • 画像メッセージ
  • 動画メッセージ
  • 音声メッセージ
  • 位置情報メッセージ
  • イメージマップメッセージ

以下は位置情報メッセージの例です。 f:id:ky_yk_d:20180517230336j:plain

"dialogue2": {
     "type": "location",
     "title": "東京スカイツリー",
     "address": "〒131-0045 東京都墨田区押上1丁目1−2",
     "latitude": 35.710139,
     "longitude": 139.810833
},

それぞれの細かい仕様については、LINEのMessaging APIリファレンスをご覧ください。

postbackイベントを使ってみる

さて、ここまででも色々なメッセージを応答として返すことができますが、まだ「決められた入力-決められた出力」しか実現できていません。Lambdaはあくまで関数なので、前回どのような入力があったかを保持することができず、流れのあるやりとりにはなりません。

流れのあるやりとりを実現するための方法として、postbackイベントが用意されています。冒頭の画像で、「別の質問がいい!」というテキストを送っているように見えますが、これは「次の質問へ行く」というボタンを押したときに表示されるテキストです。ソースコードでいうとこの部分。

{
    "type": "postback",
    "label": "次の質問に行く",
    "data": "dialogue3",
    "displayText": "別の質問がいい!"
}

label要素がボタンの文言で、displayTextが送信され(ているように見え)るテキストです。ユーザ側からはテキストメッセージを送っているようにしか見えないのですが、内部的には異なります。postbackイベントの場合、data要素を含めて送信されます。postbackイベントは、templateメッセージの選択肢に対応して送信されるイベントです。

今回の例では、postbackイベントの場合に、data要素で送られた文字列に対応するメッセージオブジェクトをJSONファイルから取得して返すようにしています。画像の例では、data要素でdialogue3という文字列を渡すようにすることで、JSONファイル内の"dialogue3"に対応するメッセージオブジェクトが返されるようになっています。

case 'postback':
    console.log('postbackの場合');
    return jsonFile[data.postback.data];

これを用いることで、流れある会話を実現することができるわけです。JSONファイルさえ用意できれば、何回もやりとりが続く応答も可能になります。ただ、やりとりが増えればその分だけJSONファイルの内容はカオスになっていくので、その辺りをどのように管理するかは今後の課題です。

おわりに

いかがでしたでしょうか。オウム返しだけではつまらなかったLINEボットも、やりとりが成立するようになると随分楽しくなりますね。多くの公式アカウントが存在していますが、一方的に情報を投げつけてくるだけで、こちらからメッセージを送っても「個別のメッセージにはお答えできません」と返ってくるだけのものも多いです。もちろん、今回の方法では、「りんな」のような対話ができるボットは作ることができませんが、一人で作って遊んだり仲間内で遊ぶ程度なら楽しいものが作れるのではないでしょうか。

また、今回条件分岐や関数のくくりだしなどを行ったことで、JavaScript的にもやや考えることがありました(下記におまけとして少し記載しておきます)。まだまだ、オブジェクト指向とは程遠いコードですが、機能追加をしながらJavaScriptのコードとしてもより良くしていけたらなと思っています。

エンジニアのためのJavadoc再入門講座 現場で使えるAPI仕様書の作り方

エンジニアのためのJavadoc再入門講座 現場で使えるAPI仕様書の作り方


おまけ:JavaScriptの変数がつらい話

今回条件分岐を追加したり、変数を新たに作成したりするなかで、若干リファクタリング的なことを行いながら進めました。そのうち大きな変更点としては、当初のソースコードで、var命令を用いていた箇所を、全てlet命令に変更し、また宣言の箇所もブロックの先頭に移動しました。
let命令はES6(ECMAScript2015)から使えるようになったものです。アロー関数も同じタイミングでの採用ということなので、アロー関数が使われていればletも使えるはずということで使ってみることにしました。varletでは、例えば以下のような違いがあるようです。

  • 同じ名称の変数宣言を許さない
  • ブロックスコープに対応している

(参考)

qiita.com

写経した段階のコードでは、ハンドラの冒頭でdata変数が明示的に宣言されずに使われていました。var命令がない場合、変数は(関数の中で初めて使用される場合でも)グローバル変数として宣言される(山田祥寛『JavaScript本格入門』188頁)とのことですが、今回の場合はさらに厄介だったようです。

というのも、関数内の後続する箇所でvar data = ...と宣言されているために、冒頭で利用されているdataもこのローカル変数と解釈されていたみたいです。「変数の巻き上げ」(山田189頁)と呼ばれるこの現象、var命令によって宣言されるローカル変数のスコープが関数全体(宣言箇所から関数の終わりまでではない!)であることによるものらしいのですが、極めて分かりにくいですね。

この点に限らず、ES6以前はブロックスコープ変数が存在しなかったり、Javaにもっとも親しんでいるプログラマとしてはJavaScriptは複雑怪奇です。JavaJavaScriptは全然似ていないというネタをよくみますが、ようやく実感できてきた気がします(とはいえ、JSDocはJavaDocと記法がほぼ一緒なので馴染みやすいです)。学びがいがありますね。

フロントエンド初心者が学ぶ「リンクが展開されるあれ」とVue.js

前回の記事の続きです。
ky-yk-d.hatenablog.com

前回、簡単なwebサイトを作成し、GitHub Pagesで公開するというところまで行いました。今回は、Vue.jsをもう少しちゃんと学んでみようと思います。また、「リンクが展開されるあれ」について学んだことも書いておきます。 今回主に編集したのはこちらのページです。 ky-yk-d.github.io

og:imageとTwitterカードを設定する

前回のブログを公開してTwitterにリンクを貼った際に、カカカカックさん(@kakakakakku)さんから、

ノンデザイナーズ本が og:image になってるのですが,今回の記事の本題ではないので,実際に作った GitHub Page のキャプチャにするか,1番関連する本にするべきかもしれませんねー

というご指摘をいただきました。

「og:image?なにそれ美味しいの?」という第一印象でしたが、調べてみるとあれですね。リンクが展開されるあれ。あれって選択できるんですね。勝手に選ばれるもんだと思ってました

ブログの方は、記事をHTML編集モードで開いて記載しましたが、せっかくなのでGitHub Pagesで公開している方のページにもmetaタグを仕込んでみることにしました。そこで関連情報を調べていると、Twitterカードというものがあるという記事を見つけました。

saruwakakun.com

Twitterカードというのは、Twitterでのリンク付きツイートに画像やその他の情報が添付されるあれですね。URLが貼られているのに画像が展開されたりされなかったりしているのは、Twitterカードの設定の有無に起因していたということを知りました。

実際に作成したサイトの記載は以下の通りです。画像については、ブログでも用いているはてなのアップロード機能を利用しました。

<!DOCTYPE html>
<html>
<head>
〜〜中略〜〜
    <meta name="twitter:card" content="summary_large_image"/>
    <meta name="twitter:site" content="@ky_yk_d"/>
    <meta property="og:url" content="https://ky-yk-d.github.io/github-pages-practice/vue/practice.html"/>
    <meta property="og:title" content="こまどのVue.js練習場"/>
    <meta property="og:description" content="Vue.jsになれるための練習場です。" />
    <meta property="og:image" content="https://cdn-ak.f.st-hatena.com/images/fotolife/k/ky_yk_d/20180504/20180504185225.png"/>
〜〜中略〜〜
</head>

以上の設定をしたページのURLを貼り付けたツイートは、以下のようになります。

ちゃんと画像や説明等が表示されていますね。ベタがきでURLが書かれているだけのツイートとは見栄えが全く違います。せっかく書いた記事や作ったページを多くの人に見てもらうには、こういう工夫は不可欠ですね。勉強になりました!

(補足)og:imageが反映されない場合の対処法

ブログの方で設定を変えたときに、「変わったかなー」と改めてリンクを貼ったツイートをしてみたところ、変更が反映されていませんでした。しばらくしないと反映されないのかなーと思っていましたが、即時反映させる方法がありました。下記のページでURLを入力して「検証」することで、Twitter側から情報を収集しなおされ、即座に反映されるようです。

Twitter Card validator

※今回はTwitterでしたが、facebookにも同等のページがあります。

デバッガー - 開発者向けFacebook

Vue.jsの勉強の続き:基本文法

前回、ネット上の記事を写経してタスク管理画面を作成しました。使い方もわからずただ写経しただけだったので、今回は、体型的に初歩から学んでみます。

公式のチュートリアルなど、教材は複数の選択肢があったのですが、今回は山田祥寛さんの『速習Vue.js』を写経して見た感想を書き留めておきます。

速習Vue.js 速習シリーズ

速習Vue.js 速習シリーズ

Part 1〜7では、Vue.jsの基本文法が丁寧に解説されていますし、写経もしやすかったです。脆弱性対策を考慮した仕様についての説明など、何も言われなければ通り過ぎてしまうところにも説明があったのがよかったと思います(他を知らないのであくまで感想ですが・・・)。

具体的な内容については、内容を用いて作成したページ(あるいはGitHubリポジトリ)を参照いただくとして、印象に残っている箇所をご紹介します。下記の例は、算出プロパティとメソッドの違いについてです。

<div>
    <p>↓クリックを押すとメソッドの方だけ更新されて算出プロパティは更新されない</p>
    <form>
        <input type="button" v-on:click="onclick" value="クリック"/>
    </form>
    <p>算出プロパティ:{{randomc}}</p>
    <p>メソッド:{{randomm()}}</p>
    <p>現在日時:{{current}}</p>
    <p>メソッドは再描画時に常に評価されるが、算出プロパティはそれが依存するプロパティが変更されたときのみ評価される。</p>
</div>
var app = new Vue({
    // このVueを有効にする要素の指定
    el: '#app',
    // 上記で指定した範囲で利用するデータ
    data: {
        current: new Date().toLocaleString()
    },
    computed: {
        // 算出プロパティ経由で乱数を取得
        randomc: function(){
            return Math.random();
        }
    },
    methods: {
        // クリック時に処理を実行する
        onclick: function(){
            this.current = new Date().toLocaleString();
        },
        // メソッド経由で乱数を取得
        randomm: function(){
            return Math.random();
        }
    }
});

この箇所の手前で、同じ機能を算出プロパティとメソッドの両方で実装してみるという箇所があったのですが、そこで当然浮かぶ「じゃあこの二つは何が違うの?」という疑問に答える説明がなされています。違いをただ文章で説明するだけではなく、サンプルコードで実際の動きによって納得させてくれるのも「こまど的にポイント高い(cv:悠木碧)」ですね。

Vue.jsの勉強の続き:コンポーネント、ディレクティブ、フィルター、プラグイン

Part 7 ではコンポーネントを、Part 8 ではディレクティブ以下の部品化技術を説明しています。たくさんの機能を単一のVueインスタンスで作成するのではなく、再利用可能な部品として切り出して利用するという発想ですね。これをうまく使うことが、Vue.js(に限らないのでしょうが)の真骨頂ということになりそうです。フロントエンド初心者にはハードルが高い部分でもあります。

詳しい内容については再度実際のページないしGitHubの参照を乞うことにして、ここでも印象に残った箇所を挙げて一言コメントを。パラメータ付きコンポーネントを利用する方法についての箇所です(サンプルコードそのままではありません。念のため)。

<p>パラメータ付きコンポーネント</p>
<!-- 属性名はケバブケース-->
<my-param-hello your-name="瀧くん"></my-param-hello>
<!-- v-bindを使う場合はシングルクオートでも囲む(数値として渡すなら不要)-->
<my-param-hello v-bind:your-name="'三葉'"></my-param-hello>
Vue.component('my-param-hello', {
    props: ['yourName'], // プロパティはキャメルケース
    template: '<div>{{yourName}}!</div>'
});

他のJSフレームワークを知らないので実感をもっては言えないのですが、先日公開された soussune.fmの40で「VueはReactに比べて書き方に自由度が高い」という話が出ていました。

soussune.com

上記の例でも、略式の書き方とv−bindを使った書き方との両方で書いています。v-bindで文字列を渡す場合はシングルクオートも必要というのは、目が悪いのでソースコードを見ても気づきにくいポイントだと思います。複数の記法が混在するソースコードは避けなければなりませんが、「他の書き方の場合はどうなるのだろう」ということを知っておくことは必要ですね。

Vue.jsの勉強の続き:vue-cli & ルーティング

Part 9では、コマンドラインツールであるvue-cliが紹介されています。インストールと起動にnpmを使うことからも明らかであるように、Node.jsを利用したツールとなります。プロジェクトの雛形の作成(rails newみたいなもの)とビルド&実行も自動化できるとのことで、Vue.jsで本格的にアプリを作成するには欠かせないようです。導入から基本の立ち上げまでは以下のように行います。

npm install -g vue-cli
cd  vue-cli-practice[=プロジェクトを作成するディレクトリ]
vue init webpack[=テンプレート名] my-app[=プロジェクト名]

上記を実行すると、? Project name my-app から始まる割とたくさんの質問が次々と表示されます。書籍はデフォルトで進めていました。すべての質問に答えると、 最初に指定したディレクトリ配下にプロジェクトのフォルダが作成され、その中に必要なフォルダ・ファイルが自動的に作成されます。上述の通り、rails newと同じような感じですね。 自動生成された段階で、動くようになっているので、下記を入力して実行してみます。

cd my-app 
npm start

実行中のメッセージが色々と表示された末尾に、Your application is running here: http://localhost:8080などと表示されれば、起動は成功です。ここで表示されたlocalhostの8080番にブラウザでアクセスするとVueのロゴを含むデフォルトのページが表示されます。

f:id:ky_yk_d:20180513094057p:plain

なるほどー(棒)簡単すぎて初学者にはよろしくないですね。npm startによって何が行われたのかもよくわかりません。vue-cliについては、著者の山田さんも、

初学者が最初から vue-cli を利用するのはお勧めしません。特に Node.js による開発に精通していない場合には、導入のハードルを上げるだけです。

と述べています。また、このあと、Part 10ではルーティングについて記載されており、その部分も写経をしたのですが、紙幅の都合かこの部分は書籍でも説明が薄く、こちらについても正直いってあまりよく理解できていません。あとは自分なりのものを作りながら試行錯誤の中で学ぶべきなのでしょう。基本的なVue.jsの道具立ては獲得したので、公式のレファレンスに当たることもできるでしょうし、ネット上の記事も少しは読めるようになっていると信じます。

HTML & CSS の勉強もやり直し始めています。まだ、こちらも写経以上のことはできていないのですが、これからVue.jsも使いながらまずはある程度整った(目的のある)静的Webサイトを作成し、ゆくゆくはNode.jsなどでサーバーサイドも構築して公開・・・といったところまで行ければと思っています。「フロントエンド初心者」という肩書きが取れるのはいつになるのでしょうか?ではでは。

フロントエンドの勉強としてGitHub PagesでダメWebサイトを公開してみました

はじめに

記念すべき最初の「実装してみた」記事です。
GitHub & フロントエンド初心者がこんなもの↓を作りました、という話です。

f:id:ky_yk_d:20180504185225p:plain

目次

はじめての「実装してみた」

技術の勉強が捗らない!

技術ブログのつもりで始めたこのブログですが、これまでの投稿で何一つとして実装していないことに気づきました。仕事でプログラムを書くのは好きなのですが、どうもプライベートの技術の勉強は捗らないんですよね。勉強に時間を割くことは吝かではなく、書籍やネットの記事などを見て勉強することも少なくないのですが、

  • 内容がエモい話に偏ってしまう(仕事術とか組織論とか開発手法とか)
  • Hello World的なもの単一の機能の写経までで途絶してしまう

というのが自分の傾向としてあるな、と感じています。課題解決の手段としてエモい話が有効である場合も多く、自社の状況からするとこちらの方にまず手が着けやすそうだったので、その方面に力が入るのはある程度は意図的ではあります。

ただ一方で、技術で解決されるべき問題をエモい話で解決しようとしてしまったり、業務で与えられた技術的課題を自分の技術力の不足によって解決できなかったりするという怖れがある以上、技術の勉強をすることは不可欠だなと考えています。

「おそらく自分のやりたいことがマネジメント方面にあるのだろうな」、「新卒でエンジニアになったからといっても技術にこだわる必要はないんじゃないか?」などと思うこともあり、考えをまとめておきたいと思っているのですが、「いいから実装しろ」という天のお告げが聴こえたので、とにかく何か実装してみることにしました。

フロントエンドの勉強をしよう

さて、学ばねば、と思っている技術はいくらだってあるわけですが、今回JavaScriptを勉強したいなと思いました。JavaScriptは、

  • 業務で使うことがある
  • Webとかbot作成とかいろんな場面で使える
  • AngularとかReactとかNodeとか聴こえてくる

といった理由で、学ぶ必要性は感じています。ただ、JavaScriptをそれ自体として学ぶのはイメージが湧かず、またWebサイト制作でもすれば、JSは当然学ぶことになるのでしょうが、新人研修でWeb技術を少しだけ学んだときに興味が持てず、業務でもビジネスロジック側を触ることがほとんどになったので、これまで放置してきました。

Web系に転職したり、フリーランスになったりする予定も今のところないし、趣味で何かサイトで公開したいという気持ちもないし、Webサイト作ってもなぁ、というのが正直なところです。しかし、 「いいから実装しろ」 という天のお告げが再び聴こえたので、Webサイトを制作してみることにしました。

はじめてのGitHub Pages

GitHub Pagesがあるじゃん」と思った

さて、Webサイトを作るなら、どのように作っていくのがよいのでしょうか。やはり、公開した方がいいだろうな、と思ったとき、GitHub Pages で公開すればいいのでは??」 と思いつきました。ちょうど先日、『わかばちゃんと学ぶGit使い方入門』を読みまして、

GitHubには【GitHub Pages】という静的Webサイトの無料ホスティングサービスがある

ということを知識として得ていました(手元に今ないのですが、確かこの本で知ったはず)。

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

【2018.05.07追記】 やはりわかばちゃん本でした。Section 29です。

ゆくゆくはDB接続をするようなアプリケーションを作れればと思っていますが、さしあたりのWebサイト制作という目的にはGitHub Pagesで足りると考えました。また、GitHub Pagesを使用することには、

  • Git, GitHubを使う練習になる
  • 勉強・試行錯誤の過程が残る
  • フィードバックをもらいやすい

などのメリットもあると感じ、よし、GitHub Pagesでやってみよう! と決めました。

GitHub Pagesに公開してみた

GitHub Pagesでのページ公開の方法は下記のサイトを参照しました。

大昔、中学生のとき色々と苦しみながらホームページを公開していた記憶があるのですが、簡単なもんですね。 手順は、

  1. GitHubにレポジトリ作って、
  2. ローカルにクローンして、
  3. ローカルで編集して、
  4. コミットして、
  5. プッシュして、
  6. Settingsから公開

これで公開は完了です。

はじめてじゃないJavaScriptとHTML & CSS

JavaScriptを書いてみた

さて、いよいよ中身です。とはいえ、<h1>タグとかは流石にわかる一方で、実践的に「こういうサイトが作りたい」というものがあるわけでもなかったので、書籍のサンプルコードのなかでJavaScriptを使っている風のところを選んで実装してみることにしました。今回は、こちらの書籍に載っているストップウォッチにしました。

これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん

これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん

下に今回書いた(写経した)コードの一部を示しています。秒を60で割って分にして、それを更に60で割って時間に……、という流れ、懐かしいですね。

// タイマーの処理
var goTimer = function(){
    var now = new Date();
    var milli = now.getTime() - start.getTime();
    var seconds = Math.floor(milli / 1000);
    var minutes = Math.floor(seconds / 60);
    var hours = Math.floor(minutes / 60);

    seconds = seconds - minutes * 60; 
    minutes = minutes - hours * 60;
    // 0補完
    hours = addZero(hours);
    minutes = addZero(minutes);
    seconds = addZero(seconds);
    document.getElementById('timer').innerHTML = hours + ':' + minutes + ':' + seconds;
}

function(){...}というのがJSだなぁという印象です。もっとも、ES2015からはアロー関数で書けるようになっていて、僕の思うJavaScript像は既に時代送れになりつつあるようですし、僕が知っているJavaが7以前でラムダ式がなかったりするので、Java像もJavaScript像も同程度に歪んだものであることを痛感しました。モダンな書き方ができるようにならないといけませんね。

HTML & CSSも(久しぶりに)書いてみた

見た目にはあまり興味がなく、目的としてもJavaScriptを学ぶことが第一だったので、CSSは特にこだわる必要を感じていませんでした。しかし、友人に「Bootstrapは見た目的に欲しいよね」と言われ、敢えて使わないというようなこだわりもないので導入することにしました。下記のサイトを参考にしました。

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>

これでボタンやテーブルに対して簡単にスタイルを適用できるようになりました。めでたしめでたし。サンプルコードの写経だけではあんまりですから、下記の2つを参考にして実装することで、申し訳程度の「オリジナル感」を出しておきました。

はじめてのJSフレームワーク

Vue.jsをやってみることにした

せっかくなので、JSついでにVue.jsも試してみました。

他のJSフレームワークも考えたのですが、しがないラジオでの言及や友人の話から、Reactなどに比べてとっつきやすいらしいという印象を持っていたためVue.jsに。JSの勉強が進んだらNode.jsでサーバーサイドも書いてみたいと思っています。

Vue.jsを使ってみるのに、何かサンプルを探していたところ、下記のページが見つかったので、こちらのタスク管理アプリを実装することにしました。 また、日本語版の公式ガイドも参照しています。

jp.vuejs.org

Vue.jsを使ってみた

当初は、「JSフレームワークって大変なのでは?」と思っていたのですが、Vue.jsの導入は簡単でした。Bootstrapと同じくCDNで提供されているので、下記のコードを公式からコピーして貼り付ければ使えるようになります。今回は開発バージョンの方にしました。

<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

こちらを貼り付けたあとは、HTMLに{{ }}で囲まれたプレースホルダー」を記述し、js側からそれを指定してデータを入れてやればVue.jsのHello Worldは完了です(?)。今回は触りの部分だけで、Vue.jsの何が優れているのか等を理解できるところまではやっていないので、公式ガイドを読みながら勉強してみようと思います。

はじめてのGitHub Issue

写経したはずなのにバグが出た

「さーて、写経して動くようになったっぽいしGitHubにプッシュだー」と公開し、満足した気分でポチポチしていると「ん?」と気づくことがありました。最初から存在しているタスクは正常に【Done!】で削除できるのに、画面から新しく追加したタスクは削除されるタイミングがおかしいではありませんか。 これバグじゃん。

Issueを書いてみた

写経元のサイトから見られるサンプルは正常に動いていましたので、自分のコードに問題がありそうです。しかし、コードを見直してみても、原因がパッと見ではわかりません。そこで、Issueを書いてみることにしました。GitHubの練習です。そこで上げた記念すべき第1号のIssueがこちら。

Issueのコメントを書くにあたっては、ネット上の情報を参考に書いてみました。書いてみて感じたのは、他の人に伝わりやすいIssueを書くためには、形式・内容の両面の洗練が必要ということです。バグの報告は業務でもする機会があったのですが、口頭で、かつ画面を一緒に見ながら報告することが多かったので、言語でわかりやすく書くのは難しいなーと思いました。

ちなみに、こちらのバグ、JSの中にタイプミスがあった(1箇所だけ isDeleted じゃなくて idDeleted になっていた)というオチでした。自分で修正してクローズ。次はどなたかにissue上げてもらったりプルリク出してもらったりできると、GitHubらしくなってきますね。

おわりに

「フロントエンド技術を勉強するぞ!うぉー!」と走り始め、雑ではありますがWebサイトらしきものを公開するところまでやってみました。思ったことをまとめておきます。

  • ネットの情報だけでも色々作れることが実感できた
  • 勉強する足がかりを作ることができた
  • やっぱりデザイン大事なのである程度気を使うべきだと思った
  • 「こういうページが作ろう」というゴールを設定すべきだと思った

最後のものが重要ですね。今回の目的は、とにかく実装してみることだったので、仕方がないのですが、やはり「こういうものを作ろう」というゴールは持たなければならないなと実感しました。言語やツールが手段でしかない以上、目的がなければそれらの勉強が捗るはずがありません。

「プログラミングは嫌いじゃないけど作りたいものがないから勉強できない」という、エンジニアの一部の層には確実に存在しているであろう悩みを僕も持っていますし、一朝一夕で「こんなものが作りたい!!」となることは多分ないと思います。

しかし、今回何もないまま実装してみて目的設定の重要性を痛感しましたので、目的設定に労力を割くのも勉強の一環だと思って、一度ちゃんと考えてみようと思います。一方で、設定できないことを勉強しないことの言い訳にしては元も子もないので、これから週に1回は何かしら実装して記事を書いていきます! 頑張ります。頑張ります。

最後にお願いをいくつか。

  • オススメの書籍や記事、勉強方法などあれば教えてください!
  • サイトにツッコミどころがあったらGitHubでIssue or プルリクお願いします!

わかばちゃんと学ぶ Webサイト制作の基本

わかばちゃんと学ぶ Webサイト制作の基本

ノンデザイナーズ・デザインブック [第4版]

ノンデザイナーズ・デザインブック [第4版]

Tech系ポッドキャストについて(2):しがないラジオについて

イベントレポートが間に入ったので、前回更新から少し空いてしまいました。ポッドキャストについての記事の続きです。

(前回の記事)

ky-yk-d.hatenablog.com

しがないラジオとの出会い

Tech系ポッドキャストの存在を昨年末に認知したものの、それから特に聴くようになったわけではなかった僕ですが、この4月に「しがないラジオ」に出会ってから、音楽を聴くことが減ってポッドキャストを聴くようになっています。

shiganai.org

正式名称(?)は「SIerのSEからWeb系エンジニアに転職したんだが楽くて仕方がないラジオ」。パーソナリティはzuckey(@zuckey_17)さんとgami(@jumpei_ikegami)さんのお二人。もともと富士通の新卒入社の同期で、現在はそれぞれ転職をして別々の会社で働かれているということです。

聴くようになった経緯は、たまたまTwitterのTLに流れてきたツイートを見て、「面白そうだし聴いてみるかー」という程度のノリで聴いてみた、というものです。聴き始めてみると、これがなかなか面白く、過去回に遡って消化をしはじめてしまいました。

僕にとって「しがないラジオを聴くこと」の何が良かったのか

Tech系ポッドキャストを聴くのが初めてだった訳ではないにも関わらず、何故僕はしがないラジオに(それこそブログを書くほどの)エンゲージメントを持ったのでしょうか。思いつく理由を書いてみようと思います。

パーソナリティのお二人への親近感

パーソナリティのお二人と僕との間には色々と共通点があり、話を聴いていて親近感を覚えています。

まず、年齢が近い。年齢は僕がたぶん1~2個下ということになると思うのですが、ほぼ同じ世代で、社会人になったのもお二人が2年早いだけなので、お話を聴いていて共感できることが多くあります。

また、文化的にも近しさを感じます。gamiさんとは大学が同じで、在学期間も被っていることもあってか、語り口に馴染みがあるというか、同じものを見てきたな感があります。zuckeyさんは別の大学ですが、僕にもアニオタ声オタ声優ラジオリスナーの時期があったので、非常に親近感を持っています。ヨルナイト×ヨルナイトいいっすよね。  

話のとっつきやすさ

話がとっつきやすいので、気軽に聴くことができています。

一応、Web系の技術の話が割合としては多いと感じていますが、特定の技術について語り続けているという印象はなく、様々な話題を取り上げています。そして、ゲスト回ではWeb系以外の業界の方々を招き、それぞれの分野のお話を上手く聴き出していますので、興味のある回をピックアップして聴いているだけでも面白いです。

また、たびたび登場するReact.jsやVue.jsの話も、聴いていてしんどいということにはなりません。僕はJSを業務で使うことがあまりなく、そのあたりの知識は乏しいので、滔々とこの分野の話をされると退屈に感じてしまうと思うのですが、なんででしょうか、不思議と聴いていて辛くないんですよね。説明の仕方がいいんですかね?とにかく聴いていて辛くないです(もっと分かるようになると楽しいのでしょうが)。

他のポッドキャストなどの情報源を知るきっかけになった

お二人がRebuild.fmに憧れてポッドキャストを始めたという経緯もあり、他のポッドキャストへの言及が度々あります。情報収集源・エンタメとしてのポッドキャストの面白さを知るきっかけを担っているのではないかと思います。

ゲスト回の多さもしがないラジオの特徴だと思います。上でも触れましたが、様々なバックグラウンドからゲストを招いているので、その人のTwitterをフォローするなどを通じて新たな分野の情報源を獲得する入り口としての効果がありました。

勝手に選ぶ「しがないラジオ十選」

過去回全部聴いた訳ではないのですが、印象に残っている回を挙げてみようと思います。

①ep.1 楽しいラジオ

初回ですね。初回の高揚感、Web系に転職して楽しくて仕方がない感じがキラキラと出ています。 

②ep.6 楽しいエンジニアの哲学

gamiさんが哲学の話をし続ける回です。学生時代、曲がりなりにも哲学に近い分野にいた人間ですので、楽しく聴きました(東浩紀は真面目に読んだことがないのですが)。個人的には、下記の部分がツボでした。

③ep.7 楽しい雑談

あまり聴かれていない回として言及されていた記憶がありますが、コミュニケーションについて悩んでいるzuckeyさんが本を読んで得た知見をgamiさんが日頃から実践していたというスリリングな(?)回です。

④sp.7a 楽しい!スキルの組み合わせで仕事を作る話

わかばちゃん』シリーズの作者・湊川あい(@llminatoll)さんのゲスト回です。前向きさというか、直向きさというか、なんというか勇気をもらえる回です。後編の「学習コストを下げる話」も面白い。

⑤sp.8a 楽しくない7次受けSIer

てぃーびー(@tbpgr)さんゲスト回。ひどいブラック企業でも向上心を忘れず、自分のできる範囲で業務改善に取り組み続けたてぃーびーさんのお話は、駆け出しの社会人としてとても勉強になるお話でした。

⑥sp.11b 楽しいドイツでの研究生活

石丸翔也@shoya140)さんゲスト回。ドイツと日本の労働の文化の違いについては色々なところで言及されていると思いますが、改めて考えさせられた回でした。

⑦sp.13a 楽しいエンジニアが職種を超えて業務が効率化された話

ぷぽ(@pupupopo88)さんゲスト回。人にものを教えるということについては、僕も学生時代から色々と考えてきました。それについてはどこかで記事にします。たぶん。

⑧sp.14a 楽しい積ん読カンバン術

るっか(@lucca0show)さんゲスト回。この回を聴いてTrelloを使い始めました。Trello積ん読カンバン、やばいです。見たくないものを見えるようにしてしまった。頑張ります。

⑨sp.19a 楽しい!?PL/Iでレガシー銀行システム開発

はっせー(@Dear_you_cry)さんゲスト回。聴き始めて最初の方に聴き、衝撃を受けた記憶があります。レガシー技術の話は必聴です。自分の会社のレガシーさは生温いな、と思えるほどです。

⑩sp.22b 楽しい超スクラムと驚異の1 Hour Sprint

きょん(@kyon_mm)さんゲスト回。アジャイルスクラムの実践について非常に刺激的なお話をされています。スクラム関係者のなかにはスクラムの形式を重んじる人もいますが、自分なりに消化し、より良い実践方法を探ろうとされています。

今後の展開?

これだけのゲストを呼びながら、また一回一回も1時間を超えているにも拘らず、高い更新頻度を維持しているというのもしがないラジオのすごいところだと思います。僕がいうのも変ですが、若いお二人が配信されているポッドキャストということで若い世代のエンジニアにとっては貴重なのではないでしょうか。下記のようなイベントも開かれるということですので、今後の展開にも期待したいですね。 

shiganai.connpass.com

 

(↓ポッドキャストの中で言及されていた書籍)

動物化するポストモダン オタクから見た日本社会 (講談社現代新書)

動物化するポストモダン オタクから見た日本社会 (講談社現代新書)

 
ザ・コーチ

ザ・コーチ

 
ファシリテーション入門 (日経文庫)

ファシリテーション入門 (日経文庫)

 
わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

 

 

4/26「エンジニアリング組織論への招待 ☓ カイゼン・ジャーニー」 に参加しました

概要

イベントに参加してきました。内容はこの2月に相次いで出版された2冊の書籍、

のコラボ企画です。著者の方々は以下の三名です。

会場はajitofmでおなじみのVOYAGE GROUPさん。

「エンジニアリング組織論への招待 ☓ カイゼン・ジャーニー」 devlove.doorkeeper.jp

書籍について

開催が発表された時点で既に両方の書籍も読んでいました。順番としては、『エンジニアリング組織論への招待』の方が先で、 発売日前に手に入れていました。原理っぽい話が好きで、うっかり文系大学院まで行ってしまった人間には非常に好印象でした。

カイゼン・ジャーニー』については、ずいぶん遅れまして、読み始めたのは3月末でした。物語仕立てだと思って、買うまでもないと最初は思っていたんですね。すみません。本日の広木さんのお話にもあったように、物語仕立てであることには意義があるのだと、読んでからは思いました。

どちらの書籍も非常に楽しく読み、比べて読みたい、もっと知りたいと思っていた本だったので、このイベントが発表されたときは久しぶりに、

キタ━━━━━━(゚∀゚)━━━━━━ !!!!!

となりました。

イベントの中身

本来はきちんとまとめて、内容を消化して公開すべきものと思いますが、鮮度が命、ということでメモ書きをそのまま公開させていただきます。後日、自分なりに消化して別途投稿するかも・・・?

前説

出席者の集まりが悪く、少し開始が遅れたので、広木さんが前でお話をされました。

エゴサーチして「エンジニアリング組織論よかった、カイゼンジャーニーよりいい」と言っている人がいて、問題と思った。自身もカイゼンジャーニーを読んでいて、同じテーマを違う形で扱っているだけの、いい本だと思っていたので、Twitterにその旨を書いたところ、同じくエゴサーチをしている新井さんに発見された(笑)一度会ってみて(主にアルコールが)盛り上がったので、今回こういうイベントをする運びとなった。

1.それぞれの書籍について語る(LT)

こちらについては、実際は、池田さん→原田さん→西村さん→小賀さん、の順番だったと思います。doorkeeperに書かれていた順番で下書きを用意していたので、そのままになっています。
また、開始の遅れによって40分取っていた時間が20分しか取れなくなったため、当初10分間だったと思しき持ち時間は5分に短縮され、みなさま苦労していらっしゃいました。

『エンジニアリング組織論への招待』①:池田秀行さん

発表タイトル:「(未定)」

何を話そうか迷ってタイトルを出していなかったら「未定」となっていた。不確実性の話をしている本なのでこのままでいいや、となった。

技術者と経営者の両方を経験されてきた立場からのお話でした。

  • 不確実性の扱いについて一貫した書籍
    • 思考方法
    • メンタリング
    • チーム運営
    • 組織運営
  • 感じたこと
    • 自分自身は不確実なことに対する耐性は強い(なんとかなるだろ、感)
    • その分、他人やチームの不確実性というものに、これまではキチンと向き合えていなかった
  • 自らを振り返るには最良の本
  • 組織リファクタリングのその先にあるもの
    • 技術・ビジネスモデルがコモディティになると組織力が武器になる
    • 組織もシステムもアーキテクチャが重要
    • 人には能力が眠っていて誰にでも創造性を発揮できるポテンシャルがある

「招待」②:小賀昌法(@makoga)さん

発表タイトル:「経営者が読みたくなる『エンジニアリング組織論への招待』の薦め方」

経営者と技術責任者の対話のベースとなる本。経営者に読んでほしい。

想定パターン

①本を薦める
②読む
③第1章で挫折する

なぜなのか

  • 目次を見てもテンションが上がらない
    リファクタリング」とか、「メンタリング」とか・・・。経営者はプライドが高いので「メンタリング」などと言われても「できてるわ!」となってしまいがち。
  • 序盤でエントロピーとか数式が出てくる。

対策:経営者が抱えていそうな課題からアプローチする

  • 抽象的な指示でもうまくいく、のが経営者にとっても嬉しいはず!
    →デリゲーションポーカーを使おう!
  • 「なんで最初は早かったのに後になると・・・?」
    →技術的負債の話。見えるようにしよう!
  • アーキテクチャの複雑性と将来要件の不確実性
    →エンジニアが知っていて、経営者が知らないこともあれば、経営者が知っていて、エンジニアが知らないこともある。それを解決するには、一緒に読むしかない!

カイゼン・ジャーニー』①:西村直人(@nawoto)さん

発表タイトル:「わいが西方でおま!」
遅れていらっしゃったので、原田さんに

チームに時間守れと言っているアジャイルコーチが時間通りに来ない

と皮肉られていました。 慌てていたのかLTもかなり苦しい形になってしまい、ご本人も下記のようにツイートされていました。

アジャイルチームを支える会」からきた。「元・流しのスクラムマスター」。

読書感想文

  • 「なぜこれをやるのか」
    これからの人のための理由、順序、そうそうあるある物語、共感が軸
  • ソフトウェアの難しさ
    広さ、難しさ、前提知識のアップデート、知識の再編集、オールインワンRailsみたいな感じ 昔あった話を、これからの人たちに向けて、今なりのやり方を整理する
  • 巻き込み力
    これから求められるHR、人材スキル

巻き込みエピソード

(※用意されていたようですが、時間短縮のため略されました)

カイゼン・ジャーニー』②:原田騎郎(@haradakiro)さん

発表タイトル:「カイゼン・ジャーニー」に何が書いていないのか

著者二人が下手くそで、しかし重要なことが書かれていない。

「助けて」

登場人物がみな、自分でなんとかしようとしすぎ。「マネージャー助けて」と言ってあげること。マネージャーからしてみれば、何をしているかよくわからないエンジニアには声をかけづらい。

「ゆっくり」

あのプロジェクトは急ぎすぎ。カイゼンをしていくには安定しておく必要がある。カイゼン・変化の間に、何スプリントか、何も起きない、ユーザーも平和な時期が必要。

アジャイルコーチは?」

外からくる傭兵はあんなに優秀ではない。アジャイルコーチは来てからしばらくは観察しなければならない。コーチの役割は、チームが見逃していることを気づかせること。

「逸脱しよう」

市谷さんと最初に話した時は「越境」ではなく「逸脱」だった。今までの自分のやり方を少し外れてみる。そうするとどう変わるかわかる。境界もわかる。

2.著者陣による対談

テーマ0:お互いの本を紹介する

『エンジニアリング組織論への招待』について(新井さん)

  • 多岐にわたる内容で、書くの大変だったんじゃないか。
  • 幅の広さと深掘りを両立できているすごい本。
  • 飲み会の時にかかった時間や章立てについて聞いた。
  • 認知心理学については自分も興味を持っていたので、学び直すチャンスだと思った。
  • 教科書のような感じ。

カイゼン・ジャーニー』について(広木さん)

伝えたいことがあった時に、納得する回路は人によって違うから使い分ける。自分は原理でしっかり説明されているといいタイプ。今回は、共感を伴った伝え方をするために必要な、ナラティブ性を入れたいとは思ったが、無理だと思った。そうしたら、自分の本と同時期にそのアプローチで書かれた本が出て衝撃を受けた。因果だなと思っているので、一緒に読んでほしい本。

テーマ1:2つの本に共通することは何か。なぜ、共通部分が生まれたのか。

市谷さん

ある難しさに向き合っていくためにどうするか?どうにもならないんじゃないかと諦めてしまいがちな問題に直面することはよくある。それに対して、『招待』はその構造を明らかにすること、『カイゼン・ジャーニー』は動的なアプローチ。

広木さん

共通部分だと思っているのは、「問いを持ちなさい、その問いはあなた自身に向かっています」ということが再帰的に、常に書かれていること。フレームワークや考え方の断片は様々な媒体に書かれている知識。これらの本に書かれているのは知恵。「この状況どうしよう」を問いかけること。なぜその問いを持ち続けられるかというと、良くしたいから。良くしたいという気持ちは、周りに振り回されて失ってしまいがちだが、問いを持ち直すことが必要。それをくどくど言っている本が2冊同時に出てしまったのは大変なこと。大変なので、多くの人で分かち合うと良い。バイラル性を出していきたい。。巻き込んだ方が楽だし、問いを捨てずにいられる。単なるノウハウとしてではなく、輸入物、舶来品ではなくて、色々な人の営みを自分たちのものとして捉え直そうとしたのが2018年2月という時期だった。

テーマ2:それぞれの本で異なる考え方、表現は何か。

新井さん

カイゼン・ジャーニー』は「物語、解説、物語、解説、、、」と進んでいく。個人からチーム、自社開発から受託開発、という展開。展開に合わせてプラクティスを紹介していく本になっている。『招待』は「Theory」であって、物語ではない。ページ数も多いので、深く解説ができている。『ジャーニー』の初稿にはダブルループ学習の話なども出ていたが、紙面の都合でカットしてしまった。『ジャーニー』を読んでよくわからなかったところを『招待』を読んでもらうといい。それと、キャラクターがいる。

広木さん

「いきなりエントロピーとか言っちゃう感じ」の理屈っぽさ。シンプルな理屈が説明されないでアジャイルスクラム、マイクロサービスが唐突に出てきて、若い人が飛びついて失敗することをよく見る。ちゃんとベースとなる理屈から出発するものを書こうと思った。情報科学という分野、そもそも科学とは、というところを飛ばしがち。経験主義にせよ、仮説法にせよ、大学の情報系の教養ではやるが、実務に触れていないので重要性がわからずに過ぎてしまう。実務に触れてからだとわかる話、サイバネティクスエントロピー科学史が『招待』に書かれている。
カイゼン・ジャーニー』も『エンジニアリング組織論への招待』も、「なぜ自分のところの事情がこんなに書かれているんだ!?」と言われるが、人類がずっとそうだったから。そういう部分に触れたいなら、『招待』。青春時代、大学時代の取り戻しができるかもしれない。

現場でそれぞれの本をどんな風に使っていけばいいか。著者が気をつけていることは?

市谷さん

「ぼっち」の人向けにこの本は書いた。「なんか変だな」「なんでこんなことしてるんだろ」と思っても、周りは全然感じていない、という境遇にある人に、ぼっちでも次の一歩を踏み出せると思ってほしい。原田さんが「助けて」という話をしていたが、「助けて」と言っても助けてもらえないことも多い。そのときに傍らに置いておいてほしい。

広木さん

何人かで読んで思ったことを言いあった方がいい。ちょっと気になる、ちょっとむかつく、ちょっと話が通じないかもしれないあいつと、これをきっかけに話をする、アルコールを飲む。色んなチームを見ていても、大人は嘘をつく。大したことのない諍いが大きなものになり、あとから理屈や正しさを持ち出される。問いを自分に向けること。ちょっとコミュニケーションをとる。ちゃんと話をしなければならないと気付きながらも、なんか嫌だなと思ってコミュニケーションを怠った結果に起きる問題。コンティンジェンシー理論に関して。お互いにどっちが先にするかというのを監視しているとだめ。それを突き崩す社会の仕組みを作らなければならない。「あいつと話したくないなー」と思い浮かべているあいつと話をしてみよう。ソーシャルメディアを作っていた経験からすると、最強のソーシャルメディアはアルコールだが、アルコールに匹敵するバイラル性、話したくなるようなものを作ったつもり。ビールがライバル。

新井さん

「ファイブフィンガー」などのプラクティスをやってみると、チームが変わっていくんじゃないか。そういう使い方をしてもいいと思う。

お互いに聞いて見たいこと。

Q. 新井さん

表紙の色や英語タイトルの決め方?

A. 広木さん

かっこよさめの本のタイトルをつけたかった。アルファベットの英単語二つ(『Joy, Inc』とか)をつけようと思ったが、技術評論社が「そういうのは違う」という雰囲気があった。洋物に見えては、という感じだったので、わもので、「招待」とついている本があったのでつけた。装丁を考えているときに、デザイナーから現在の英題が出されていたのでいいなと思ってつけた。色については、『ティール組織』が日本で出る前だったが、原書で流行りそうな雰囲気を見ていたので、近いもので少し差別化した。

Q. 広木さん

モデルと思しき人から何か言われたか。

A1. 市谷さん

直接言われなくても、肖像権とか色々あることがわかった。今日の司会の方もモデル。ギルドワークスの同僚だが、こだわりが強い。細かいすぎて色んな人が逃げていく。そんな人。

(司会の方「最初は本名で登場していたんですが今は違います」)

A2. 新井さん

僕も出ています。最初の方に出てくる。

Q. 広木さん

見る人が見れば実際の出来事そのままじゃんという人がいるのでは?

A. 市谷さん&新井さん

実体験に基づいている確かに出している。1章の終わりの、勉強会をやった後に声をかけてくれた人がいた、というのはそう。

会場からの質問

Q

技術的負債の返却は、ビジネスインパクトに中々跳ね返ってこず、経営層やステークホルダーの協力を継続的に得ることが難しいと感じています。特に長期プロジェクトで中々成果が出ないような状況を乗り越えるコツやエピソードがあれば聞きたいです

A1. 広木さん

自社サービスをやっている組織がどうするかというのが『招待』で、最初は受託なのが『ジャーニー』。自分たちでビジネスをやるとなると、技術力・エンジニアリングリソースという最も調達が難しくなっているリソース、ボトルネックになるリソースの効率化に投資できない会社が生きていけるはずがない。そういったことをきちんと伝えれば、経営層にも伝わるはず。伝え方が悪いのではないか?お互いの認識をすり合わせようと思って、コミュニケーション取ろうとおもって、経営層やステークホルダーにもアプローチするべき。「いつもなんか文句を言っているやつ」と思われたらだめ。あと、「作り直し幻想(作り直せば負債がなくなるという幻想)」は危険。

A2. 市谷さん

「できなくなることがこれだけあります」ということをちゃんとコミュニケートする。エンジニアが逃げてしまう、一緒に働いていた仲間が居なくなってしまうということを目の当たりにすれば、やばいことはわかるはず。

Q

『エンジニアリング組織論への招待』への質問です。 「不確実性に向き合う」というテーマに少しでも関連する理論やプラクティスが全部ブッ込まれてるように感じるほどの情報量だと感じました。これらは広木さん自身、全部実際に実践してきた経験を通して書かれたのでしょうか。どの辺りが理論で、どの辺りが実践なのかに興味ありました。

A. 広木さん

全部やったことのあること。実践したことのないものは理論として書いていない。理屈が切断されているよりは、実践が飛んでしまう方がマシだと思ってこうなった。

Q

経営者へ本を薦めるお話がありましたが、マネジメントされている側の立場として、同僚やマネージャーなどに広げていく方法など何かありませんか??

A1. 新井さん

勝手にぼんぼんアップする。「実は読んでいるんですよ」という人は出てくる。想いは伝わる人には伝わる。レスがなくても続ける。あと、問題駆動。その人、そのチームが抱えている問題に 関係する形で伝えよう。

A2. 広木さん

とりあえず買っておいておく。UX的な話にはなるが、自分で見つけておもしろいと思うと勧めたくなるが、色んな人に勧められると斜に構える人が出てくる。「自分で見つけた」と、斜に構えるタイプの人に感じさせることは重要なのではないか。「社内Slackでシェアする限りでは写真を貼ってもオッケー!!」ユニコーン企業数社で全社チャンネル(#general)に@channel で投稿されている。ユニコーンになりたければ投稿しよう!

最後に一言

新井さん

「夜中のラブレター」。ちょっとテンションが上がって考えたこと、妄想をやってみる。甚大な損失を負うことはたぶんない。やってみると自分ごとになってきて楽しい。そんなジャーニーを。

広木さん

セルフマネジメントができることを示すために45キロやせ、禁煙もした。この本を読めばできる!

市谷さん

誰かと一緒に仕事をする、何かを作るのは難しい。協働作業はなかなかうまくいかない。なんとかしていくやり方を広めていくことを読者と一緒にやっていきたい。全部は同意できなくても、少しでもやってみよう。

3.懇談会

「じゃんけんぽん(本)」という書籍のプレゼント企画がありました。広木さんは「デリゲーション・ポーカー」を付けて贈呈という大盤振る舞いでした。僕はゲットできませんでした(が、サインは広木さん新井さんからいただけました!)。

その後の立食形式の懇談会では、広木さんが独演会をしていました。その内容も非常に面白かったのですが、メモをとるという感じではなかったので、印象に残ったお話だけ。

電車の都合で市谷さんが早く帰られるタイミングで、みなさんで写真撮影。最後は、広木さんの号令で一本締めとなりました。懇談会の時間がたっぷりあったので、著者のみなさんや他の方々とお話できたのはとてもよかったと思います。

おわりに

素晴らしいイベントだったと思います。著者のお三方、LT登壇者の方々、スタッフのみなさま、本当にありがとうございました。新井さんが最後に仰っていましたが、これから日本のソフトウェア業界がもっと楽しく、よいところになるといいですね。

※書籍の読書体験と今回のイベント体験の両方を元に考えた記事を別途書くかもしれません。乞うご期待。。

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

SCRUM BOOT CAMP THE BOOK

SCRUM BOOT CAMP THE BOOK

アジャイルサムライ−達人開発者への道−

アジャイルサムライ−達人開発者への道−

Tech系ポッドキャストについて(1):t_wadaさんとajitofm

初回に予告していたポッドキャストの話を書こうと思います。

ポッドキャストとの関係

昔からiPodユーザーで、ポッドキャストという媒体の存在は知っていましたが、学生時代まではニュースや外国語学習の番組を聴いてはやめ、聴いてはやめの繰り返しでした(飽きっぽい)。学生時代は主たる関心が研究の方にあり、ニュースも語学番組も直接研究に活かせるものではなかった(語学は読解が研究のためには圧倒的に重要でした)ですし、常にガラガラの電車で移動し、書籍を主な情報源とする暇人学生にとってはポッドキャストという媒体はあまり重要ではなかったのです。

就職し、通勤電車で満足に本を広げられない時間ができてからも、しばらくは音楽を聴いて過ごしていました。エンジニアとしての情報収集という点においても、技術書をパラパラと読んでみる程度で、勉強会に行ったり、Twitterで業界の人をフォローしたりといったことはしていませんでした。

t_wadaさんとの出会い

2017年9月くらいから、情報収集をしようと思い立ってTwitterを再開し、またconnpassに登録して勉強会に参加するようになりました。そして、2017年12月5日に開催された下記勉強会での、和田卓人(@t_wada)さんのお話の際に、Tech系ポッドキャストという存在を初めて認識しました。 

connpass.com

確か、この講演のなかで、「ajitofmというポッドキャストに出演して、テスト駆動開発について話した」、というようなことを聴いたのだったと思います。自宅PCのポッドキャストのデータの日付が、12月6日になっていますので、翌日すぐに聴いたんですね。ミーハーですね(笑)それがこちら。 

ajito.fm勉強会の際の和田さんのお話がとても面白く、またテスト駆動開発というものが自社における極めてアクチュアルな問題に関わるものであったことで、しばらく和田さんの書かれた記事や講演資料を読み漁っていました(笑)そのなかで、ajitofmの和田さんゲスト回(6: Worth is Betterを含めて)を聴いたわけです。思えば、この時にTDDを通じて初めてXP、アジャイルというものに接したのではないかと思います。そう考えると、僕にとっては大きな転機だったかもしれません。

ajitofmと、しがないラジオ以前 

閑話休題。このとき、ajitofmについては、和田さんゲスト回以外もいくつか聴きましたが、自分にはわからない技術の話が多く、生活に密着したものにはなりませんでした。ただ、今もフォローはしていて、2018年3月に『エンジニアリング組織論への招待』の著者:広木大地(@hiroki_daichi)さんがゲスト出演された回は拝聴しました。 

ajito.fm

こうして、2017年12月にTech系のポッドキャストというものの存在を認識したわけですが、それからしばらくはまた音楽を聴く日々に戻りました。ポッドキャストが生活に溶け込みはじめたのは、つい先日、しがないラジオに出会ってからです。まだ、聴き始めてから3週間程度しか経っていませんので、すっかり定着したとは言えないのですが、確かなマイブームになっていますので、この気分の盛り上がりを記事にしておきたいと思います。

あんまり一回に長く書くと、すぐにネタがなくなりそうなので、続きは次回。。

テスト駆動開発

テスト駆動開発

 
エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング