RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

LINEでTwitter検索する

はじめに

新卒2年目エンジニアのkasuke18と申します。
今回はLINEでメッセージを送信することでTwitter検索を行うLINE Botを作成してみましたので、作成の流れや実際のコードを記載します。使用言語はPHPです。

もくじ

構成

今回はLINEのAPITwitterAPIを利用します。また、LINEで送信されたテキストに対して処理を行うWebhookスクリプトを設置するSSL対応のサーバが必要なため、HEROKUを使用しています。
イメージとしては以下のようになります。
構成イメージ

必要なもの

APIを利用するまでの流れについては、LINE Messaging API公式サイトに詳しい説明が記載されています。
また、Twitter REST APIは公式サイト上のどこに記載されているか発見できませんでしたが、検索すればそのあたりのことが書かれている導入記事が数多くあるので省略します。
HEROKUの使用方法については当ブログに記事がありますので、ぜひそちらをご参照ください。

実装例

メッセージの取得

まずはLINEから送信されたメッセージテキストを受け取る部分です。
LINE Platformから送信されるのはJSONで、以下のような形式となっています。

{
    "events": [
        {
            "type": "message",
            "replyToken": "**********",
            "source": {
                "groupId": "**********",
                "userId": "**********",
                "type": "group"
            },
            "timestamp": 1529822351422,
            "message": {
                "type": "text",
                "id": "**********",
                "text": "送信メッセージ"
            }
        }
    ]
}

上記のJSONをもとにパースして送信されたテキスト情報を取得するコードが以下となります。送信される形式がJSONなので、$_POSTではデータが取得できないことに注意が必要です。

<?php
$json = json_decode(file_get_contents('php://input'), true);
$message = $json['events'][0]['message'];
$messageText = $message['text'];

Twitterで検索

次に受信したテキストをキーワードとして、Twitterで検索します。Twitterの連携については自前でやってしまうのもありですが、面倒なのでTwitter連携パッケージmpyw/cowitterを使用しています。

<?php
$client = new Client([$consumerKey, $consumerSecret, $twitterAccessToken, $twitterAccessTokenSecret]);
$tweetsParams = ['q' => $q . ' -rt' ,'count' => '10', 'result_type' => 'recent', "include_entities" => true];
$tweets = $client->get('search/tweets', $tweetsParams)->statuses;

$tweetsParamsで検索条件を指定します。
qは検索キーワードで、検索演算子も利用できます。今回はリツイートを排除したいので、検索演算子-rtを使用しています。
countはそのまま検索結果の取得件数で今回は10件、result_typeは取得するツイートの種類でrecentとすることで最新のツイートを取得します。
最後のinclude_entitiesは少し特殊で、取得したツイートオブジェクトにentitiesプロパティを含めるかどうかを指定します。entitiesプロパティとはツイート本文を拡張するエンティティで、画像や動画などの本文に付け足すための情報が格納されています。今回はツイートに付随する画像のURLを取得するために使用しています。
他にも設定可能なプロパティがありますが、今回は不要なので省略します。必要に応じてこちらをご参照ください。

検索結果のパース

検索結果から必要な情報を抜き出すときにも、mpyw/cowitterが当然ながら活躍してくれます。
今回必要とする情報はツイート本文ユーザ名ツイートURL画像URLです。それぞれの情報は以下のようにして取得します。

<?php
foreach($tweets as $tweet){
  $text = $tweet->text;
  $name = $tweet->user->name;
  $url = 'https://mobile.twitter.com/' . $tweet->user->screen_name . '/statuses/' . $tweet->id_str;
  $img = $tweet->extended_entities->media[0]->media_url_https;
}

ここで注意する点が2つあります。
まず1つ目はツイートURLです。これはツイートオブジェクトの中に直接記載されていないので、その他の情報を結合して作成する必要があります。
2つ目は画像URLです。画像のURLは2種類あり、media_urlmedia_url_httpsがあります。見ての通りHTTPかHTTPSかが違うだけなのですが、LINEのAPIHTTPSでないとダメなので、media_url_httpsのURLを取得する必要があります。

LINEに送信

最後にLINEに送信します。単に動かすだけならプレーンテキストでもよいのですが、今回は少し見た目にこだわってFlex Messageという形式にしてみます。Flex Messageでは複雑なレイアウトを自由に作成可能です。今回は以下のような見た目にしました。ほかにどのようなレイアウトにできるのかは、サンプルなどもありますので公式ページをご参照ください。
Flex Messageの例

以下が今回の見た目を作成するのに必要な情報を設定した配列です。この配列をjson_encodeして送信します。



そして実際に作成したメッセージを送信する部分のコードが以下となります。
改めて説明するまでもなく、curlをたたいて終わりです。

<?php
$ch = curl_init("https://api.line.me/v2/bot/message/push");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  'Content-Type: application/json; charser=UTF-8',
  'Authorization: Bearer ' . $accessToken
  ));
$result = curl_exec($ch);
curl_close($ch);

おわりに

特に需要はないでしょうが、今回はLINEからTwitter検索をしてみました。単にAPIをたたくだけで多くのことができます。今回はテキストメッセージを検索するということしかしていませんが、もっと面白いものがあれば機能拡張という形で取り込んで行きたいです。
最後までご覧いただきありがとうございます。

参考文献

大阪開発部のビアバッシュを開催しました ~技術ネタ~

MasaKuです。
ラクスでは月1回のペースで開発メンバーの交流会としてビアバッシュを開催しています。

ビアバッシュとはビールなどのアルコールを片手に(+軽食)フランクに技術内容について発表したり語り合う交流会です。
ラクスで行っているビアバッシュについては以下の記事が参考になるかと思いますので、よろしければご確認下さい。

tech-blog.rakus.co.jp tech-blog.rakus.co.jp

大阪開発部では毎月何らかのテーマを決めてビアバッシュを行っています。
今月、大阪の開発部で開催されたビアバッシュのテーマは「技術ネタ」です。
技術ネタといっても、硬い雰囲気は全くなく、業務に直接関係しないような内容について発表されている人がほとんどでした。
また、テーマに縛られないLT枠も毎回開催されており、こちらも毎回数名の方が発表しています。

簡単ではありますが、今月のビアバッシュの雰囲気をお伝えできればと思い、発表内容についてまとめさせていただきました。

f:id:MasaKu:20180617220021j:plain

ビアバッシュの様子。ちなみに、今回のケータリングは「サンドイッチ」でした。

テーマ枠(技術ネタ)

PHPのマジックメソッドについて

マジックメソッドとは、クラスに設定しておけば、明示的にメソッドを呼び出さなくても特定条件で自動的に発動するメソッドのことです。
__construct()は業務の中でもよく目にしますが、それ以外のマジックメソッドについては、PHPの学習初期に利用していた参考書に紹介されていたものを少し読んだくらいで、ほとんど知りませんでした。
マジックメソッドはフレームワークやライブラリの中で利用されていることが多いようで__call()__get()CakePHPでも利用されているようです。
発表は__callStatic()を中心とした内容でしたが、機能の説明だけでなく、どのように実装するかということを、書籍管理を例にして説明していただきました。
発表の時間内でライブコーディングするというテクニックも披露していただき、大変見ごたえのある発表でした。

これまでのPWAとこれからのPWAについて

Progressive Web Appsについては、Webアプリでありながら、ネイティブアプリのように振る舞うことができるもの、くらいの認識でした。
また、どこでもネットに繋がる現代において、オフライン環境でも利用できることのメリットはそこまで大きくないのではないかと考えていました。
しかし、データを端末にキャッシュすることで、アプリのレスポンスが早くなるという点もPWAの特徴であるということについてご指摘いただき、オンラインで通信する必要のある箇所を切り分けるという観点を見落としていました。
様々なフレームワークでPWAのテンプレートが利用できるようになってきている(React.js / Vue.js / Angular.js)ことから、PWAの開発が加速化することが期待されます。
Microsoftが今年中にPWAをWebアプリストアに追加することを発表したこともあり、今後のPWAのニュースにも注目しておかなければなりません。

www.itmedia.co.jp

Haskellの参照透過性について

Haskellの参照透過性のメリットについての発表内容でした。
なお、本発表は発表者とは異なる方が作成された資料を参照しながらの発表でした。(下記のslideshare
関数を実装する際に気をつけなければならないこととして、その関数がどのような値を受け取ってどのような値を返すのか、ということを明確に意識しておくことが挙げられます。
Haskellは静的型付き言語の中でも、制約が強いプログラミング言語に分類されるようです。
そのため、実装した関数が正しい型で設定されていない場合は、コンパイル時に失敗するが、裏を返せば、コンパイルで落ちなければ、関数の型が正しく設定できていることが保証されるということでもあります。
発表者の方は、Haskellのような強い静的型付き言語でプログラミングを行うことによって、PHPなどの制約の優しいプログラミング言語でプログラミングをする際にも型を意識する癖がついたとおっしゃっていました。
実装する際の心構えだけでなく、体に癖をつけておくことは大切だなと思いました。

Haskell Day2012 - 参照透過性とは何だったのか

LT枠(自由発表)

使い続けているツールについて

業務で使っているツールを2つ紹介してくださいました。

Wireshark
ネットワークに流れるパケット情報をリアルタイムで調査できるツールです。
Linuxのコマンドも利用できることに利便性を感じて、今でも利用されているようです。

knowledge.sakura.ad.jp

Vimium
ブラウザ操作をキーボードで行うためのツールです。
マウスを操作しなくてもブラウジングができることから、キーボードから手を離したくないような場合に便利で、体感的にはすごく楽とおっしゃっていました。
なお、以前のビアバッシュでこちらのツールと同様のcVimというGoogle Chrome拡張機能の発表をしている方もいらっしゃいました。
マウス無しでブラウジングすることの需要は一定存在するようですね。

Googleのデータセンターについて

Googleのサーバは、サーバを構成するビス1つからGoogleが自社で作成しているようです。
なんでも、利用している製品に脆弱性が発覚した際に攻撃されるリスクを回避するためなんだとか。
また、本発表で面白いと思ったのが、サーバの維持管理で一番コストがかかる箇所が、空調管理のための電力だそうです。
PUE(Power Usage Effectiveness)という、データセンターのエネルギー効率を表す一つの指標がありますが、GoogleではこのPUEが1.12~1.19程度らしいです。(業界標準は1.5程度)
以前耳にした話ですが、さくらインターネットでは北海道の冷涼な外気をサーバルーム内に取り込むことで、一般的な都市型データセンターと比較して約4割の消費電力を削減しているそうです。
サーバの維持管理のコストをいかに抑えるか、という話を聞くことで、Google検索を行う度にGoogleの電気が一部利用されているということをちゃんと意識できるようになりました。
提供されているサービスとはいえ、無駄なクエリ発行はできる限り抑えなければなりませんね。

www.sakura.ad.jp

Android Studio で作ったアプリについて

業務で行った内容の復習として取り組まれた、cURLで外部サーバにアクセスして情報を取得するAndroidアプリの開発について発表していただきました。
アプリの内容はWather HacksというWebサービスAPIを用いて、その日の天気情報を取得するといったものでした。
本アプリを開発する上での苦労話として、AndroidはOSのバージョンアップによって仕様が変わることから、参考にしている記事がどのバージョンのAndroidを対象とした記事なのかをしっかりと確認しなければ、うまく動作しなかった、ということを話されていました。
これは、自分が情報を収集する際のポイントとして、気をつけなければならないことでもあります。
しかし、新たに情報を発信する際も、環境依存となる情報は明確に提示しておくことで、記事の価値を高めることに繋がることを認識することができました。

tech-blog.rakus.co.jp

おわりに

いかがでしたでしょうか。
今月も様々なタイプの発表が聞くことができて、大変充実したビアバッシュになりました。
次回のテーマは「使用しているツール特集」ということで、次回も魅力あふれる発表が聞けるのではないかと今から楽しみです。

参考サイト

チーム力を高めるためのテストを書いてみよう

id:radiocat です。スクラムマスターの修行中です。

今回はチーム力を高めるために私たちが取り組んでいる手法を紹介します。アジャイルのプラクティスとして紹介されている手法ですが、アジャイルではない開発の現場でも活用できるのでぜひ参考にしてみてください。

学びにフォーカスしてチームで試験問題を作る

この手法は「スクラム現場ガイド」という書籍の第20章で、新しいメンバーを受け入れる手法として紹介されています。

この書籍を翻訳されている安井さんが同様のテーマのスライドも公開されています。

www.slideshare.net

目的

チームが大事にしている文化や技術について繰り返しテストをすることで新しいメンバーにそれらを理解してもらいます。また、テストをすることで新メンバーの理解が足りていないことを既存メンバーも含めてお互いに認識することができます。

やりかた

  • チームが問題を作る
  • 新しいメンバーは毎週必ずテストを受ける

問題の例

チームに取り入れよう

私たちのチームも新しいメンバーを迎えることになったので、早速この手法を取り入れようと考えました。しかし、ここでいくつか疑問が浮かびました。

テストするのは新しいメンバーだけ?

テストは新しいメンバーだけに必要なものでしょうか?我々エンジニアは新しく作った機能を必ずテストしますが、そのテストを日々回帰的に利用する手法を取り入れています。同様にスクラムチームも定期的にテストすればよりチーム力を高められるのではないかと考えました。

テストという言葉のハードルが高い

新しく入ってきたメンバーに対して「これからテストしますよ」と言うのは少し仰々しく、これから一緒にやっていこうというのに逆に心理的な壁ができてしまいそうな気がしました。そもそもこのテストは「チームが大事にしている文化や技術について理解する」ことが目的であり「テストする」のは手段でしかありません。無理にテストという言葉を使う必要もないので余計な心理的障壁を作らないように「クイズ」という呼び方にしてはどうかと考えました。その名も「Scrum Quiz」です。

Scrum Quizとは

私たちはScrum Quizを以下のように定義しました。

  • スクラムチームを前進させるための質問集です
  • 以下のような内容について質問に回答することで相互理解を図ります
    • 文化
    • 価値観
    • 必須スキル・理論
  • クイズはみんなのものなのでチームの誰でも追加・更新できます

クイズの内容を考える

あとは問題を作るだけです。インセプションデッキにまとめた内容やチームで決めている品質の基準などを質問するようにします。また、ふりかえりで決めたルールなども質問に加えました。ふりかえりの時にチームで決めたルールがいつの間にか形骸化してしまうことが時々あります。クイズの問題にしておけばチームでそのルールを意識することができて、定着につなげることができます。

また、理解や定着が目的なので一言で答えられるようなクローズドな質問ではなく、あえてやや曖昧でオープンな質問にしてみました。

f:id:radiocat:20180608192057p:plain:w500

Scrum Quizの完成

そして私たちのチームのScrum Quizが完成しました。

f:id:radiocat:20180608191955p:plain:w500

チームの朝会(デイリースクラム)後に数分ほど時間をとってメンバーの誰か1人がクイズを引いて答えてもらうようにしました。正しく答えられることも大事ですが、チームで「ああ、そういうルールだったよね」という理解が共有されることも大事です。「補足すると、ふりかえりでこういう意見がでたのでこういうルールにしました」というような話が出ればさらに理解が深まって良いと思います。また、もしクイズに答えられなかったら、次の日のまでに答えをみつけて朝会で共有してもらいます。

チームを継続的にインテグレートする

Scrum Quizはチーム力を高めるためのテストです。これを日々実行することで継続的にチームの大事にしている文化をより強化することができます。エンジニア的な言葉で言い換えるとチーム力を高めるためのCIツールなのです。

アジャイルな現場に限らずどんなチームでも大事にしている文化やルールはあると思います。チームでテストを作っておけば、それらを確認し合ってチーム力を高めることができます。

VagrantとDockerで「環境に縛られない」開発環境を構築しよう

f:id:rs_tukki:20180509170211p:plain

はじめに

こんにちは。@rs_tukkiです。

先日、このエンジニアブログでY-KanohさんがDockerでの開発環境構築について説明されていましたね。
tech-blog.rakus.co.jp
また、mickey-STRANGEさんはHerokuを使った開発環境の構築を行っていました。
tech-blog.rakus.co.jp

恥ずかしながら、一エンジニアとしてもう1年以上が経過している私ですが、業務以外でガッツリ開発することがあまりありません... 環境の構築についても色々手法があるなー程度で見ていたのですが、
先日Vagrantというツールを使って、「どの」、「誰の」、「どんな」環境でも手軽に開発環境を構築できる手順を学びましたので、今回はそちらについて簡単に記事にしたいと思います。

Vagrant?Docker?

f:id:rs_tukki:20180615103526p:plain

まず初めにVagrantとDockerで開発環境を構築するにあたっては、当然ですがVagrantとDockerがどのようなツールなのか、ということを理解しなければなりません。
正直自分も違いがよくわからないまま触っていたのですが...調べていると面白い例えを見つけました。

Vagrant : 家の内装、全体的な設計 - どんな室内構造か、部屋は何があるのか~その他
Docker : 部屋or(キッチンも可) - 様々な種類がある、場合によってば独特な空間を持ち合わせている

Vagrantは、設計図を基に自分のPCに仮想環境という「家」を作成するためのツールです。
普通に環境を作ろうとした場合は、どういう階層構造にするか、どんなOSを使うのか…等々、都度細かく設定しなければなりませんが、それらの設定をVagrantfileとしてテキスト形式で保存しておけば、それを元にどんなPCからでも同じような仮想環境を作成できるのです。

Dockerに関してはこのブログでも何度か説明されていますが、今回の場合では、Vagrantから作成された「家」の中に作られた部屋*1というイメージで説明します。
それぞれ作られたコンテナの中にはそれぞれ単独で機能する仕組みがあり、例えばそれがWebサーバならWebにアクセスできる仕組みがありますし、DBであればデータを保存する仕組みがあります。また、それぞれのコンテナの間にネットワークという通路を作っておけば、複数のサーバを用いるようなWebアプリケーションも簡単に作成できるというわけです。
そして最も便利なのは、このコンテナ自体もVagrantと同じくDockerfileを作成しておくことによって、細かい設定なしにいきなりコンテナを配置することが出来るという点です。

VagrantとDockerで誰でも使える開発環境を構築してみる

では、VargrantとDockerを用いて、実際に開発環境を作成してみましょう。

必要なツールのインストール

まずは必要なソフトとしてVagrantと、仮想環境を作成する際に必要となるVirtualBoxをインストールします。
Dockerは? となるかもしれませんが、DockerをインストールするのはあくまでVagrantで作った仮想環境に対してなので、現時点でのインストールは不要です。

Vagrant by HashiCorp f:id:rs_tukki:20180615104032p:plain

Oracle VM VirtualBox f:id:rs_tukki:20180615104051p:plain

特にこだわりがなければ、最新版でOKです。
画面の指示に従ってインストールしてください。

Vagrantfileの作成、VMの起動

インストールが完了したら、早速仮想環境の元となるVagrantfileを作ってみましょう。
ちなみに今回の手順は、windowsでの操作を前提にしています。予めご了承くださいm(__)m。

まずはコマンドプロンプトを開き、 適当な作業用フォルダを作成します。

mkdir vm\test
cd vm\test

作成したこのフォルダの中にVagratfileを作成していきます。
本来であればvagrant initコマンドでテンプレートをダウンロードするのですが、今回は手軽に環境構築をお試しするためのVagrantfileをサクッと作っておきました。

Vagrant.configure("2") do |config|
 config.vm.box = "CentOS/7"
 config.vm.network :private_network, ip: "192.168.33.10"
 config.vm.provision "docker"
end

Vagrant.configure("2") do |config|...endで囲まれた範囲が、細かい設定を記述する箇所になります。

  • config.vm.box は仮想環境のOSを表します。今回はCentOSを使用します。
  • config.vm.networkは仮想環境のIPアドレスの指定に使用します。実はこれがかなり重要で、これが設定されていないと仮に仮想環境上でWebサーバを立ち上げても、IPアドレスがないのでPC上からアクセスできません。考えてみれば当然のことなのですが…こんな単純なことに3,4日も気づかずつまづいてしまいました…
  • config.vm.provisionで、環境の作成時にインストールするソフトを指定します。今回は前述の通りdockerを使用するので、今のうちに記述しておきます。

これだけ書いて保存したら、あとは仮想環境を作成して接続するだけです。

vagrant up
vagrant ssh

vagrant upでVagratfileを元に仮想環境を起動し、その環境にvagrant sshで接続します。初回はdockerのインストール等もあるので多少時間がかかりますが、気長に待ちましょう。
しかし、気長といってもここに第二のつまづきポイントがあり、何故かVagrantfileは問題なく作成できているはずなのですが、10分経っても20分経っても起動が完了せず、タイムアウトしてしまうことがあります。
調べたところ、どうやらBIOSの設定が邪魔をしているらしく、この設定をこちょこちょして何とか解決。

Dockerイメージの取得

接続が完了すると、ごく一般的なCentOS上でLinuxコマンドを叩けるようになります。
この環境上に、Dockerを使ってコンテナを作っていくわけですが、それには主に2つの方法があります。

  1. Vagrantfileを作成したのと同じフォルダ内に「Dockerfile」を作成してビルドする
  2. dockerHubという、公式で提供されるコンテナの「カタログ」からDockerfileを借りてくる

細かく設定を行いたい場合は1.で行うのもいいですが、今回はとっかかりなので2.の方法で行きましょう。
プロジェクト管理OSSである「redmine」と、そのデータを格納するための「MySQL」を作成してみます。

docker pull sameersbn/redmine:3.3.1
docker pull sameersbn/mysql:latest

dockerHubからイメージを借りてくる際は、docker pullコマンドを使用します。特に細かい設定は必要なく、dockerHubで提供されているイメージ名とバージョンを指定するだけで落とせるので便利。
こちらも時間がかかるので、気長に待ちましょう。

mkdir -p /srv/docker/redmine/mysql
mkdir -p /srv/docker/redmine/redmine

続いて、MySQLredmineのデータを格納するフォルダを作ります。
本来データはコンテナの中に格納されていますが、このフォルダと紐づけを行う(後述)ことで両者を共有することが出来ます。四次元ポケット

これで、コンテナを動かす準備が完了しました。

実行

少し長いですが、以下2つのコマンドを実行してみてください。

docker run --name=mysql-redmine -d --env='DB_NAME=redmine_production' --env='DB_USER=redmine' --env='DB_PASS=redpass' -v /srv/docker/redmine/mysql:/var/lib/mysql sameersbn/mysql:latest  
docker run --name=redmine -d -p 8080:80 --link=mysql-redmine:mysql -v /srv/docker/redmine/redmine:/home/redmine/data sameersbn/redmine:3.3.1

docker runコマンドでコンテナを動かしています。以下、コマンドのオプションについて解説。

  • --name : 起動するコンテナの名前を定義しています。
  • -d : バックグラウンドで動かします。これがないと、一つ動かしている間は何も操作できなくなってしまいます。
  • --env : コンテナで扱う環境変数を設定します。
  • -v : コンテナの中にあるデータ配置のためのフォルダを、仮想環境の特定のフォルダと紐づけます。
  • -p : 起動したコンテナのポート番号と、自分のPC上で操作する時に指定するポート番号を紐づけます。
  • --link : 他のコンテナを指定することで、そのコンテナと連携することが出来ます。

これでPC側からアクセスができるはずなので、http://192.168.33.10:8080にアクセスします。

f:id:rs_tukki:20180615132038p:plain

Redmine使用者には見慣れたTOPページが表示されました!

おわりに

VagrantとDockerを使って環境を構築するやり方を説明いたしました。
正直なところ、結構噛み砕いて説明したつもりでしたがそれでも大分難しいと思います。なんとたったこれだけのことを調べ始めてから記事にするまで約一ヶ月
ただ、当然若手エンジニアにとっては勉強になりますし、何よりどんな環境でも、同じように環境を構築できるのはとても便利だと思います。ぜひ皆さんも試してみてはいかがでしょうか。

参考

acchi-muite-hoi.hatenablog.com

https://qiita.com/hidekuro/items/fc12344d36d996198e96qiita.com

weblabo.oscasierra.net

qiita.com

www.risewill.co.jp


  • エンジニア中途採用サイト
    ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
    ご興味ありましたら是非ご確認をお願いします。
    20210916153018
    https://career-recruit.rakus.co.jp/career_engineer/

  • カジュアル面談お申込みフォーム
    どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
    以下フォームよりお申込みください。
    forms.gle

  • イベント情報
    会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com

*1:以下、これを「コンテナ」と呼びます

PHP カンファレンス関西 2018 に登壇します&協賛します

はじめまして!普段業務では Java や Swift を書いていますが、本当は(?) PHP が大好きな @kawanamiyuu です。

今日は PHPer な私にとって嬉しいお知らせです!

お知らせ

関西での PHP の一大イベント、PHP カンファレンス関西に弊社のエンジニアが登壇します。

また、株式会社ラクスはシルバースポンサーとしてイベントに協賛します。

2018.kphpug.jp

登壇内容

タイトル

チャットディーラーの高速開発を支える Laravel

概要

チャットディーラー」は株式会社ラクスが提供する、チャットを活用した Web 接客ツール (SaaS) です。

10 年以上 PHP でノンフレームワークで開発・運用されてきた主力サービス(メールディーラー)の開発チームが、新規に姉妹サービス(チャットディーラー)を立ち上げる際に Laravel を選択をしました。

開発期間半年というスピードが求められる中で、チームが Laravel に抱いた理想と現実、また、Laravel (Blade) と Vue.js の組み合わせにより発生した脆弱性への対応など、Laravel での新規サービス立ち上げの経験を具体的にお伝えします。

最後に

当日は弊社のエンジニア数名もイベント本編および懇親会に参加します。セッションや懇親会を通して、弊社のサービス開発やエンジニアリングについてぜひたくさんお話できればと思います!

PostgreSQL10についてまとめてみた

こんにちは。開発エンジニアのd_shr(id:d_shr)です。
前回はNode.jsのことを書いていましたが、今回はPostgreSQLのことを書きます。

前回投稿した記事 tech-blog.rakus.co.jp

はじめに

最近、PostgreSQLについて調査する機会がありました。
主にPostgreSQL9系やPostgreSQL10の変更点を調査しましたが、その中でも最新のPostgreSQL10について書きます。
PostgreSQL10はリリースから半年以上経っており今更ですが、新機能や変更点で気になったものをピックアップしてまとめようと思います。

PostgreSQL10 変更点

  • ロジカルレプリケーション
  • 宣言的テーブルパーティショニング
  • 改善された並列問い合わせ
  • その他

ロジカルレプリケーション

PostgreSQL10でPublish/Subscribeによる論理レプリケーションが実装されました。

PostgreSQL9.6までのレプリケーション

マスタからスタンバイにトランザクションログを転送し適用することでデータの複製を実現していました。
対象はデータベース全体。完全な複製でスタンバイには物理的な変更はできないものでした。

PostgreSQL10 ロジカルレプリケーション

レプリケーション先に対して変更したレプリケーション情報を送付できるようになります。
トランザクションログを「テーブルに〇〇を挿入しました」のように論理的な変更内容として転送することができます。
データベース全体をレプリケーションするのではなく、特定のテーブルの情報やinsertだけをレプリケーションすることが可能です。
レプリケーション情報のやりとりにPublish/Subscribe(出版/購読型)モデルのメッセージ送信を用いています。
複製元でPUBLICATIONを作成し、複製先でSUBSCRIPTIONを作成することでテーブルの同期とレプリケーションが行われます。
INSERT, DELETE, UPDATEには対応していますが、CREATE TABLEなどには対応してません。

所感

柔軟にレプリケーションできるようになったという印象を受けました。
学生の頃にPub/Subモデルのメッセージングを用いた開発をしていたので興味深い内容でした。

パーティショニング

パーティショニングとは、巨大な親テーブルを複数の子テーブルに分割することです。
今までパーティショニングの手順がめんどうだったのですが、CREATE TABLE文でパーティショニングが構築可能になりました。

これまでのパーティショニング

  1. 親テーブルを作成
  2. 親テーブルを継承する子テーブルを作成
  3. CHECK制約を作成
  4. 親テーブルにINSERTトリガを作成 ......

宣言的テーブルパーティショニング

CREATE TABLE文で構築可能 1. 親テーブル作成 PARTITION BY構文 2. 子テーブル作成 PARTITION OF構文

所感

PostgreSQL9.5でもUPSERTが追加されていましたが便利な構文が増えたということで使ってみようかなと思いました。

パラレルクエリの強化

パラレルクエリとは、PostgreSQL9.6で追加された大きなテーブルに対するクエリを並列問合せで実行することです。
パフォーマンスの向上が期待できます。
PostgreSQL9.6で追加されたパラレルクエリ(並列問い合せ)がPostgreSQL10で強化されています。

PostgreSQL9.6で対応していたもの

  • シーケンシャルスキャン
  • 結合(nested loop, hash join)
  • 集約

PostgreSQL10で追加されたもの

  • インデックススキャン(B-tree, index only scan, bitmap heap scan)
  • 結合(merge)
  • 非相関副問合せ

所感

パラレルクエリ自体、バージョンアップで既存のシステムに取り入れるのは難しいのかなという印象を持っています。
これからも並列化はどんどん強化されそうな流れなので、パフォーマンス向上に繋がるなら考慮するべきなのかなと思います。
正しく理解しておきたい機能だと思いました。

その他

PostgreSQL10.3の修正で
他ユーザからの search_path を使った「トロイの木馬」攻撃を防御する PostgreSQL とアプリケーションの設定方法がドキュメントに記載されました。
pg_dump や他のクライアントプログラムで安全でない search_path 設定の使用が回避されました。 *1

PostgreSQLのpublicスキーマの仕様によるもので、悪意あるユーザがpublicスキーマに不正な挙動を行うユーザー関数を仕込んでおくことができます。
他のユーザがその不正なユーザ関数を一般のユーザ関数として実行させることで攻撃(漏えい、改ざんなど)ができてしまう問題がありました。
pg_dump」「pg_upgrade」「vacuumdb」などの管理者ユーザで実行されるアプリケーション関してはsearch_pathからpublicスキーマが取り除かれました。

PostgreSQLの仕様が原因になっていることなのでpublicスキーマの設定を見直す必要もあり 既存のシステムで問題に直面しそうな場合は、運用面のことを考えるのなかなか辛いなという印象を受けました。

まとめ

PostgreSQL10についてまとめました。
個人的に興味深い技術が使われていたものや、構文が追加され便利になったものなどありました。
また、パフォーマンスの向上に繋がることや脆弱性に関連した修正もあり、正しく理解しておかないといけないこともあるなと思いました。

参考

Android Studioで天気情報を表示するアプリを作ってみた

はじめに

kuwa_38です。以前Android Studioを使ってみたので、その続きとして天気情報を表示するアプリを実装してみました。簡単に実装できるかと思いきや、AndroidではAPI接続に非同期処理(AsyncTask)を用いる必要があるらしく苦戦しました。この記事では今回苦戦した非同期処理も含め、天気情報を表示するアプリについて、実装に必要なこと、実装したコードを記載します。

前回実装した処理

今回は下記の実装に付け加える形で実装したため記載しておきます。

Android Studioを使ってHello Worldをやってみた

  • 初期画面の表示
  • ボタンを押すとテキストが変わる

今回実装した処理

  • ボタンを押すとその日の大阪の天気が表示される

利用したAPI

Weather Hacksを利用させて頂きました。GETでエンドポイントにアクセスすることで、パラメータcityで設定した都市の天気をJSONで返してくれます(因みに270000は大阪です)。

補足:jqを活用してAPIレスポンス等から欲しい情報だけを抽出する【初級編】

$ curl -s http://weather.livedoor.com/forecast/webservice/json/v1\?city\=270000 | jq -r

# 結果
{
  "pinpointLocations": [
    {
      "link": "http://weather.livedoor.com/area/forecast/2710000",
      "name": "大阪市"
    },
# ...(中略)
 "link": "http://weather.livedoor.com/area/forecast/270000",
  "forecasts": [
    {
      "dateLabel": "今日",
      "telop": "晴れ",
      "date": "2018-05-27",
      "temperature": {
        "min": null,
        "max": {
          "celsius": "29",
          "fahrenheit": "84.2"
        }
      },

Androidのバージョンに伴う注意点

それでは実装、といきたいところですが、先に私がハマった注意点について述べておきます。

実装概要

コードなどは次の節に記述します。この節では実装すべきことについて大まかに述べます。

※ 今回は実機デバックを対象とします(エミュレータを使用する場合は、エミュレータwifi設定などが必要です)。

ネット接続を許可する

  • AndroidManifest.xmlに下記を追記
<!-- ネット接続を許可する -->
<uses-permission android:name="android.permission.INTERNET" />

ボタンを押すと特定の処理を実行する

  • 前回の記事を参照ください

APIサーバに接続する

  • 注意で述べたようにメインスレッドでは接続できませんので、実行用のクラスを作成してあげます

    • 参考:AsyncTaskを使った非同期処理のきほん

      1. AsyncTaskを継承するクラス(今回はAsyncHttpRequestというクラス名にしました)を作成する
      2. 作成したクラス内にdoInBackground(非同期で行いたい処理を記述する)メソッドを実装する
      3. メインスレッド(MainActivity.java)で1のクラスをインスタンス化し、executeメソッドを呼び出す
        doInBackgroundが呼び出される

受け取ったJSONを加工する

  • 受け取った文字列をJSONObjectでパースし、天気情報を取り出します

天気情報を表示する

  • AsyncTaskを継承するクラスでonPostExecute(非同期処理が終わった後に実行される)メソッドを実装し、メインスレッドのラベルを変更する

実装例

下記にMainActivity.javaAsyncHttpRequest.java(AsyncTaskを継承するクラス)を載せますので、実装してみたい方は参考にして下さい。

AndroidManifest.xmlは1行追記したのみですので載せていません

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * トップ画面を制御するActivityクラス.
 */
public class MainActivity extends AppCompatActivity {

    /**
     * 画面を表示する.
     *  note:デフォルトで実装されている
     * @param savedInstanceState savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    }

    /**
     * テキストラベルを変更する.
     * @param view view
     */
    public void changeTextView(View view) {
        // 非同期処理(AsyncHttpRequest#doInBackground())を呼び出す
        try {
            new AsyncHttpRequest(this).execute(new URL("http://weather.livedoor.com/forecast/webservice/json/v1?city=270000"));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

AsyncHttpRequest

import android.app.Activity;
import android.os.AsyncTask;
import android.widget.TextView;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 非同期処理を行うクラス.
 */
public final class AsyncHttpRequest extends AsyncTask<URL, Void, String> {
    private int TODAY_FORCAST_INDEX = 0;
    private Activity mainActivity;

    public AsyncHttpRequest(Activity activity) {
        // 呼び出し元のアクティビティ
        this.mainActivity = activity;
    }

    /**
     * 非同期処理で天気情報を取得する.
     * @param urls 接続先のURL
     * @return 取得した天気情報
     */
    @Override
    protected String doInBackground(URL... urls) {

        final URL url = urls[0];
        HttpURLConnection con = null;

        try {
            con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            // リダイレクトを自動で許可しない設定
            con.setInstanceFollowRedirects(false);
            con.connect();

            final int statusCode = con.getResponseCode();
            if (statusCode != HttpURLConnection.HTTP_OK) {
                System.err.println("正常に接続できていません。statusCode:" + statusCode);
                return null;
            }

            // レスポンス(JSON文字列)を読み込む準備
            final InputStream in = con.getInputStream();
            String encoding = con.getContentEncoding();
            if(null == encoding){
                encoding = "UTF-8";
            }
            final InputStreamReader inReader = new InputStreamReader(in, encoding);
            final BufferedReader bufReader = new BufferedReader(inReader);
            StringBuilder response = new StringBuilder();
            String line = null;
            // 1行ずつ読み込む
            while((line = bufReader.readLine()) != null) {
                response.append(line);
            }
            bufReader.close();
            inReader.close();
            in.close();

            // 受け取ったJSON文字列をパース
            JSONObject jsonObject = new JSONObject(response.toString());
            JSONObject todayForcasts = jsonObject.getJSONArray("forecasts").getJSONObject(TODAY_FORCAST_INDEX);

            return todayForcasts.getString("dateLabel") + "の天気は " + todayForcasts.getString("telop");
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
    }

    /**
     * 非同期処理が終わった後の処理.
     * @param result 非同期処理の結果得られる文字列
     */
    @Override
    protected void onPostExecute(String result) {
        TextView tv = mainActivity.findViewById(R.id.messageTextView);
        tv.setText(result);
    }
}

おわりに

本記事ではAndroid Studioを使い、天気情報を表示するAndroidアプリの実装方法を紹介しました。まだまだ実用には遠いクオリティですが、非同期処理やjqコマンドなど知らなかったことを学ぶいい機会になりました。自分の学習目的で始めた部分が大きいですが、Androidアプリ開発の初心者や非同期処理の実装で困っている方の手助けになれば幸いです。


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.