オルトプラスエンジニアの日常をお伝えします!

ブロックチェーン記事の執筆について

みなさんこんにちは。オルトプラスラボの竹田(id:mitsutaka-takeda)です。

今回、技術評論社が出版しているSoftware Designにブロックチェーンの記事を書く機会を頂いたので、その時の経験を書こうと思います。

ブロックチェーンってなに?

ぜひ、Software Design 2017年5月号をご購入して、「いまから学ぶブロックチェーンのしくみ」をご覧ください。まだブロックチェーンに触れたことがない方向けの内容になっております。ブロックチェーンに関する重要なコンセプト、技術的な概要、応用面が書かれた記事です。

http://gihyo.jp/magazine/SD/archive/2017/201705

執筆の流れ

執筆が決まったのは2月頭ぐらいでした。そして2月末には目次を提示して3月の中頃に原稿の提出。その後2週間ほどかけて原稿の訂正を行いました。

今回の記事では、弊社嶋田(id:cimadai)と2人での共同執筆でした。章ごとに分担を決め、各自担当の章を書き、お互いにレビューを行うという形で作業を進めていきました。

執筆作業について

今回の記事では、1ページ1000文字で10ページ、約1万文字を目安に執筆を行いました。私は雑誌記事への投稿は初めてで、執筆がどのくらいの大変さになるか想像できませんでした。共同執筆者の嶋田は過去に技術書を執筆した経験があり、彼から「大変だよ」と聞いていたので、書き始める前はかなり不安でした。実際は、1度書き始めると逆に文量が想定より多すぎて最終的には削ることになりました。2人で10000文字という少なめのボリュームのおかげかもしれません。

執筆を行う上で気を付けたことは、なるべく読者に前提知識を要求しないことです。普段の開発チームでのコミュニケーションでは、同じ知識を共有しているものとして専門用語でも何気なく使ってしまいます。導入向けの記事では、何気ない専門用語でも(全体から見れば重要ではない用語であっても)、理解の妨げになる可能性があります。専門用語を多用しない、または、使用する専門用語は初出時に適切な説明を付けるようにしました。難しかったのは何を専門知識や用語とするかです。1度知ってしまうと何が難しくて理解しづらかったのか忘れてしまい、自分たちだけでレビューしてもなかなか理解しづらいことに気づけません。今回はブロックチェーンに関しては聞いたことがあるが中身は知らないエンジニアの方にレビューをお願いしました。

共同執筆について。技術書執筆の経験者がおり、執筆作業の流れについて知っていたため、スムーズに作業を進めることが出来ました。原稿の共有、バージョン管理はgitです。構成や書くことに詰まった時、相談できる相手がいるのは心強かったです。

最後に

今回は2か月ほどで10ページという余裕のある(?)スケジュールでしたが、連載を持たれてるエンジニアの方は、どのように連載をこなしているのか頭が下がる思いです。

共同執筆は執筆の敷居を下げてくれる大きな要因でした。書く機会はあるけど1人ではなかなか始めることができないという方は共同執筆できそうな人を探してみるのはいかがでしょうか。

Software Designの記事を通じて、ブロックチェーンについてより多くのエンジニアに興味を持ってもらえることを願っています。

いろはハッカソンに参加してきました。

みなさんこんにちは。 しぶやちほーで働くオルトプラスラボの嶋田(id:cimadai)です。

f:id:d-shimada:20170314001714p:plain

ブロックチェーンしてますか?

以前以下のようなセミナーを開いたのですが、それ以来ブロックチェーンの虜になっている今日このごろです。

techblog.altplus.co.jp

そんな中、東京大学で情報社会基盤卓越講義の一貫で「ブロックチェーン・ハッカソン〜irohaで作る新たな未来〜」 というハッカソンが開かれましたので参加してきました。

irohaって?

irohaとは、ソラミツ株式会社が作成したブロックチェーンで、昨年10月にIBMのFabric、IntelのSawtooth Lakeに 続いて3番目にHyperledgerプロジェクトに受諾されたプロジェクトです。

ソースコードはすべてGitHubで公開されており、誰でも利用可能なものになっています。

github.com

プロジェクト名も和風ですが、コード中の命名も「鳥居(torii)」「皇(sumeragi)」「天地(ametsuchi)」など 中二心をくすぐられるものになっているのも特徴です。

irohaハッカソン

第8回 情報社会基盤卓越講義 (2017/3/11-12) - 情報社会基盤卓越講義

東京大学の大学院情報学環・情報社会基盤卓越講義シリーズの第8回として開催されたもので、 「irohaを活用して社会的課題解決につながるサービスを提供できるようなアプリを開発する」 というお題のものでした。

なにを作ったか

「ちょいサポ」というアプリで、地域の課題・依頼を地域(にいる人)で解決するという 課題・依頼の地産地消を目指したアプリです。

f:id:d-shimada:20170314105544j:plain

チームは本当にいろいろなフレンズがいて、アイデアを出してくれたりパワポをまとめてくれたり発表の準備をしたりというエンジニアじゃ無い方々と、 フロントエンドやインフラ、サーバサイドとそれぞれ分担できるエンジニアがいてとてもバランスのいいチームでした。

その中で私の担当部分としては、PlayFrameworkを使ったサーバサイドと、irohaのビルド、Scalaからirohaを利用するコードを書いて実際にirohaとのつなぎこみを行いました。

今回のハッカソンのお題と、作ったアプリのコンセプトがマッチしていることと 実際にirohaと連携ができているという点が評価されて最優秀賞を頂くことができました! f:id:d-shimada:20170314105745j:plain

最終的な構成としてはこんな感じです。 f:id:d-shimada:20170314105553j:plain インフラは僕のAWSがあるから、と言ってくれたチームリーダーには驚きましたが、とても感謝しています。

なお、Scalaからirohaを利用するコードは、後日切り出してライブラリとしてGitHubに公開しています。

github.com

さらに光栄なことにirohaプロジェクトのメンテナにもなりましたので、これからはirohaに積極的に取り組んでいこうと思います。

おわりに

個人的には、実は初めてのハッカソンでしたので、立ち居振る舞いがよくわからずとにかく開発してた感じですが、とても楽しい経験でした。

オルトプラスラボはブロックチェーンが得意なフレンズを募集しています! 一緒に開発をしたいフレンズさんは是非オルトプラスにご応募ください。

ブロックチェーン、たーのしー!

C++17で基本統計量を計算してみる

こんにちは id:mitsutaka-takada です。

今日はC++17で導入されるRanges TS(Technical Specification)ライブラリの紹介をしたいと思います。

http://en.cppreference.com/w/cpp/experimental/ranges

Rangesライブラリが導入されると、C++のプログラミングにどのような影響があるか数式をプログラミングしてみることで確認していきたいと思います。

プログラミングのお題は以下のエントリで紹介されているものを使い、Rangesライブラリ以前と以降で書き方の違いが明確になれば良いかと思います。

qiita.com

qiita.com

最大・最小値

以下が0から19までの整数から最大値(19)と最小値(0)を求めるプログラムです。

ranges::view::iotaで0から19までの整数の列をlazyに生成して、ranges::minmaxで最大値と最小値を取り出します。

#include <range/v3/view/iota.hpp>
#include <range/v3/algorithm/minmax.hpp>

#include <cassert>

int main(int argc, char *argv[])
{
    // [0,20) の整数。
    auto const intFrom0To20 = ranges::view::iota(0, 20);
    auto const minMax = ranges::minmax(intFrom0To20);

    assert(minMax.first == 0 && minMax.second == 19);
    return 0;
}

総和

ranges::view::iotaはlazyな列なので、終点を指定せずに無限長の列(iota(1))を表現することができます。

無限長の列の総和はとれないので、列の長さを制限する必要があります。LINQやHaskellのようにtakeで列の長さを指定すると有限長の列になります。

#include <range/v3/view/iota.hpp>
#include <range/v3/view/take.hpp>
#include <range/v3/numeric/accumulate.hpp>

#include <cassert>

int main(int argc, char *argv[])
{
    // 1 .. 100 までの整数。
    auto const intsFrom1To100 = ranges::view::iota(1) | ranges::view::take(100);
    // 0は合計の初期値。
    assert(ranges::accumulate(intsFrom1To100, 0)  == (1 + 100)*100/2);
    return 0;
}

平均

平均を計算する際は従来のSTLと同じようにaccumurateを使用します。

#include <range/v3/view/iota.hpp>
#include <range/v3/numeric/accumulate.hpp>

#include <cassert>

int main(int argc, char *argv[])
{
    // 1 .. 100 までの整数。
    auto const intsFrom1To100 = ranges::view::iota(1, 101);
    assert(ranges::accumulate(intsFrom1To100, 0.0)/ranges::size(intsFrom1To100)  == 50.5);
    return 0;
}

分散

平均と内積から分散を求めます。内積はranges::inner_productで計算できます。

今回の計算では整数では浮動小数点を使用しています。ranges::view::iotaは整数しかサポートしていないのでranges::view::generate_nを使用して1から100までの浮動小数点を生成してranges::to_vectorでstd::vectorに変換します。

#include <range/v3/view/generate_n.hpp>
#include <range/v3/numeric/accumulate.hpp>
#include <range/v3/numeric/inner_product.hpp>

#include <iostream>
#include <vector>

int main(int argc, char *argv[])
{
    auto const from1To100 = ranges::view::generate_n(
            [v = 1.0]() mutable { 
                auto const tmp = v;
                ++v;
                return tmp;
            },
            100) | ranges::to_vector;

    auto const avg = ranges::accumulate(from1To100, 0.0)/from1To100.size();
    auto const variance = ranges::inner_product(from1To100, from1To100, 0)/from1To100.size()- avg*avg;
    std::cout << "variance = " << variance << std::endl;
    return 0;
}

中央値

中央値はranges::n_th_elementで求めます。n_th_elementは、対象の範囲をソートした時、指定したn番目の位置にn番目の値が来るように範囲をソートするアルゴリズムです。n番目より前の要素はn番目の要素より小さいことが保証されているだけでソートはされていません。例えば、1から5までの整数がランダムに配置された範囲をn_th_elementにn=3を指定してソートするとn番目の位置には3が来ますが、1番目と2番目の要素はどちらが1でどちらが2かは保証されていません。[1, 2, 3, X, Y]かもしれませんし、[2, 1, 3, X, Y]かもしれません。STLの中でも使われる機会が少ないアルゴリズムでしょうか。

また中央値を求める前にranges::action::shuffleで範囲をランダムにしています。action下のアルゴリズムはコンテナの要素をinplaceで処理するアルゴリズムです。この場合from1To100というvectorの要素を並べかえるのでactionとなります。一方view下のアルゴリズムはコンテナ中の要素を変更しません。

#include <range/v3/view/generate_n.hpp>
#include <range/v3/iterator_range.hpp>
#include <range/v3/numeric/accumulate.hpp>
#include <range/v3/numeric/inner_product.hpp>
#include <range/v3/algorithm/nth_element.hpp>
#include <range/v3/action/shuffle.hpp>

#include <random>
#include <iostream>
#include <vector>

int main(int argc, char *argv[])
{
    auto from1To100 = ranges::view::generate_n(
            [v = 1.0]() mutable { 
                auto const tmp = v;
                ++v;
                return tmp;
            },
            100) | ranges::to_vector;
    std::mt19937 rbg;
    from1To100 = std::move(from1To100) | ranges::action::shuffle(rbg);

    double median = 0.0;
    if(from1To100.size()%2 == 0){ 
        auto const middlePoint = from1To100.begin() + from1To100.size()/2 - 1;
        ranges::nth_element(from1To100, middlePoint);
        ranges::nth_element(middlePoint + 1, middlePoint + 1, from1To100.end());
        median = (*middlePoint + *(middlePoint + 1))/2;
    } else {
        auto const middlePoint = from1To100.begin() + from1To100.size()/2;
        ranges::nth_element(from1To100, middlePoint);
        median = *middlePoint;
    }

    std::cout << " median = " << median << std::endl;
    return 0;
}

最頻値

最頻値は、まず範囲をソート(ranges::action::sort)します。その後、値が同じ者同士を1つのグループにします(ranges::view::group_by)。
同値グループをグループの長さとそのグループの値の組に変換して(ranges::view::transform)、最後にグループの長さが最大(ranges::max)のグループを選択します。

#include <range/v3/action/sort.hpp>
#include <range/v3/algorithm/max.hpp>
#include <range/v3/view/group_by.hpp>
#include <range/v3/view/transform.hpp>

#include <iostream>
#include <vector>

int main(int argc, char *argv[])
{
    struct valAndCount{
        int value;
        long count;
    };

    auto const sorted = std::vector<int>{0, 0, 1, 10, 2, 5, 1, 1} | ranges::action::sort;
    auto mode = ranges::max(
        sorted
        | ranges::view::group_by([](auto x, auto y){ return x == y;})
        | ranges::view::transform(
            [](auto const& vs){ return valAndCount{ *vs.begin(), ranges::distance(vs)}; }),
        [](auto const& lvc, auto const& rvc){
             return lvc.count < rvc.count;
         }
        );
    std::cout << mode.value << std::endl;

    return 0;
}

最後に

Range TSを利用したプログラミングはいかがでしたでしょうか。従来のSTLで見慣れた名前が多かったかと思います。

Range TSは従来のイテレータ・ベースのアルゴリズムをRangeというコンセプト(例えば、イテレータのペアもRangeです)に拡張したもの+αなライブラリです。アルゴリズムを使う際、イテレータのペアを自分で管理しなくてよかったり、パイプ(|演算子)で複数の処理を合成していくことが可能な便利なライブラリです。

Range TSの理論的な部分は以下の本を

www.amazon.co.jp

Range TSのポテンシャルの高さについて知りたい人は、CPPCON 2015のRange TSライブラリ作者の発表がオススメです。

www.youtube.com