Slide 1

Slide 1 text

マーケティングに強いCTOが語る技術未来とElixir 第2回 プログラミング未経験でも ExcelできればElixirマスターできる ~ITのパラダイムシフトで、従来の知識・経験が邪魔になる時~ 2018/04/15 ver 0.5作成 2018/04/19 ver 0.9作成

Slide 2

Slide 2 text

1 1. プログラミングを始めるなら今がチャンス 2. 事前準備:Elixirのインストール 3. 入門:Excelの操作と同じElixir 4. 事前準備:PhoenixでPJ作成 5. 初級:DBデータをWeb表示 6. Excelから関数型言語へ行った理由 目次

Slide 3

Slide 3 text

2 1.プログラミングを始めるなら今がチャンス

Slide 4

Slide 4 text

3 1.プログラミングを始めるなら今がチャンス 現在、プログラミング言語は、JavaやPHP等の「オブジェクト指向 言語」と呼ばれるものが主流で、大半のエンジニアに利用されて いますが、本シリーズ第1回でお伝えした、「人手不足」と「データ 量爆発」に対しては、性能面・運用面においては、不充分です 一方、Elixirを始めとする「関数型言語」は、新しい言語のように 見えますが、実は「オブジェクト指向言語」より歴史は古く、そして、 「オブジェクト指向言語」習得者ほど、移行できず苦しんでいます そこで、Elixirは、「Excel使う位、簡単」だと知ってもらおうという のが趣旨で、これまでプログラミングが得意で無い、とか、知らない 方でも、Excelを使うレベルでElixirができる実感を伝えます つまり、プログラミングを本格的に始めるなら、今がチャンスです

Slide 5

Slide 5 text

4 2.事前準備:Elixirのインストール

Slide 6

Slide 6 text

5 2.事前準備:Elixirのインストール まず、Elixirを使い始めるのに、3種類の方法があります ① インストーラやyum/apt/Homebrewを使う ② ソースコードからビルドする ③ DockerでElixirイメージをインスト―ル (pull) する Windows/macOSは①、Linux含むUNIX系は②、普段 Dockerを使い慣れている方は③がオススメです 以降で、①~③の手順をそれぞれ解説します

Slide 7

Slide 7 text

6 2.事前準備:Elixirのインストール ①は、下記URLの手順に沿って、Elixirをインストールします (なお、Linux含むUNIX系の手順も記載されていますが、手順 通りにすると、古いバージョンがインストールされるため、②が良い) https://elixir-lang.org/install.html

Slide 8

Slide 8 text

7 2.事前準備:Elixirのインストール ②は、以下の手順通り、まずErlangをソースコードからビルドして、 インストールします 次に、Elixirをソースコードからビルドして、インストールします > wget http://erlang.org/download/otp_src_20.3.tar.gz > tar vzfx otp_src_20.3.tar.gz > cd otp_src_20.3/ >./configure --enable-hipe > make && make install > git clone https://github.com/elixir-lang/elixir/ > cd elixir > git checkout v1.6 > git pull > export PATH="${PATH}:/usr/local/bin" > make && make install > elixir -v 実施するタイミング次第では、新しいものがリリース されているかも知れないので、気になる方は、下記 URLをチェックして、適宜、変更してください http://erlang.org/download Elixirのメジャーバージョンが新しくなっている場合は 適宜、バージョンを変更してください

Slide 9

Slide 9 text

8 2.事前準備:Elixirのインストール ③は、下記URLを、「Docker Community Edition (CE)」 までスクロールし、利用OS毎のDockerをインストールします https://www.docker.com/get-docker . その後、以下コマンドでElixirイメージを入れます (要ネット接続) 以下コマンドで、Elixirイメージのコンテナを起動します > docker pull trenpixster/elixir > docker run -p 4000:4000 -i -t trenpixster/elixir /bin/bash

Slide 10

Slide 10 text

9 3.入門①:Excelの操作と同じElixir

Slide 11

Slide 11 text

10 データの「並べ替え」は、Elixirでは、Enum.sort()を使います パイプ「|>」により「データ→並べ替え」という流れの順で書けます 3.入門①:Excelの操作と同じElixir iex> Enum.sort( [ 323, 999, 54 ] ) [54, 323, 999] iex> [ 323, 999, 54 ] |> Enum.sort [54, 323, 999]

Slide 12

Slide 12 text

11 データの「フィルタ」は、Elixirでは、Enum.filter()を使います 3.入門①:Excelの操作と同じElixir iex> [ 323, 999, 54 ] |> Enum.filter( fn( n ) -> n != 999 end ) [323, 54]

Slide 13

Slide 13 text

12 Enum.filter()内のfn( n )は、データの1つ1つの値を変数n※ として、後ろの処理 (青枠) に渡す、という意味で、青枠の処理 では、1つ1つの値が「999」で無いことをチェックしています ※この「n」は、fn()で指定した変数と、後ろの処理で同一であれば、どんな変数名でも構いません なお「fn」は、関数 (function) を意味しており、その後の「->」 から「end」までの間が、関数の処理を意味しています つまり、データの1つ1つの値が、「999で無いことをチェック」すると いう関数に順に渡され、 「999で無い値」だけが残るようフィルタ されている、というのが、Enum.filter()で行われている処理です 3.入門①:Excelの操作と同じElixir iex> [ 323, 999, 54 ] |> Enum.filter( fn( n ) -> n != 999 end ) [323, 54] iex> [ 323, 999, 54 ] |> Enum.filter( fn( n ) -> n != 999 end ) [323, 54]

Slide 14

Slide 14 text

13 3.入門①:Excelの操作と同じElixir データの「変換」は、Elixirでは、Enum.map()を使います Enum.map()内のfn()は、前のEnum.filter()と同じように、 1つ1つの値に対する処理を書きます iex> [ 323, 999, 54 ] |> Enum.map( fn( n ) -> n * 2 end ) [646, 1998, 108]

Slide 15

Slide 15 text

14 「fn( n )」のカッコは、省略できます 更に、「fn」から「end」の書き方は、fnの代わりに「&(~)」と囲む ことができ、変数も「&1」と省略できます これらの省略した書き方は、Enum.filter()等でも同じように、 使うことができます 3.入門①:Excelの操作と同じElixir iex> [ 323, 999, 54 ] |> Enum.map( &( &1 * 2 ) ) [646, 1998, 108] iex> [ 323, 999, 54 ] |> Enum.map( fn n -> n * 2 end ) [646, 1998, 108]

Slide 16

Slide 16 text

15 文字列でも、Enum.sort()は、Excelと同じ結果になります Enum.Filter()や、Enum.map()も同様です 3.入門①:Excelの操作と同じElixir iex> [ "ゆじかわ", "つちろー", "enぺだーし", "ざっきー" ] |> Enum.sort ["enぺだーし", "ざっきー", "つちろー", "ゆじかわ"] iex> [ "ゆじかわ", "つちろー", "enぺだーし", "ざっきー" ] |> Enum.map( &( &1 <> "さん" ) ) ["ゆじかわさん", "つちろーさん", "enぺだーしさん", "ざっきーさん"] iex> [ "ゆじかわ", "つちろー", "enぺだーし", "ざっきー" ] |> Enum.filter( &( &1 != "つちろー" ) ) ["ゆじかわ", "enぺだーし", "ざっきー"]

Slide 17

Slide 17 text

16 複数の操作をパイプで繋げることもできます このデータの値を並べている「 [~] 」を、「リスト」と呼びます 3.入門①:Excelの操作と同じElixir iex> [ "ゆじかわ", "つちろー", "enぺだーし", "ざっきー" ] ¥ ...> |> Enum.sort ...> |> Enum.filter( &( &1 != "つちろー" ) ) ...> |> Enum.map( &( &1 <> "さん" ) ) ["enぺだーしさん", "ざっきーさん", "ゆじかわさん"]

Slide 18

Slide 18 text

17 3.入門①:Excelの操作と同じElixir 今度は、複数列のデータを扱ってみましょう これをElixirで表現すると、以下のような感じになります iex> data = [ %{ "名前" => "enぺだーし", "年齢" => 49, "所属" => "有限会社デライトシステムズ", "ポジション" => "代表取締役, 性能探求者" }, %{"名前" => "ざっきー", "年齢" => 45, "所属" => "公立大学法人 北九州市立大学", "ポジション" => "准教授, カーネルハッカー" }, %{"名前" => "つちろー", "年齢" => 34, "所属" => "カラビナテクノロジー株式会社", "ポジション" => "リードエンジニア, アプリマイスター" }, %{"名前" => "ゆじかわ", "年齢" => 30, "所属" => "カラビナテクノロジー株式会社", "ポジション" => "リードエンジニア, グロースハッカー" }, %{"名前" => "piacere", "年齢" => 43, "所属" => "株式会社TechJIN", "ポジション" => "CTO, 福岡Elixirプログラマ, 重力プログラマ, 技術顧問" } ]

Slide 19

Slide 19 text

18 3.入門①:Excelの操作と同じElixir 列名を日本語にすると、後で扱いにくくなるので、英語に変えます この複数列をまとめる「%{~}」を、「マップ」と呼びます (Enum.map()の「マップ」と紛らわしいですね…) 複数列データは、この「マップ」を「リスト」で包んでいるので「マップ リスト」と呼んだりします dataの中身は、次ページのように格納されます iex> data = [ %{ "name" => "enぺだーし", "age" => 49, "team" => "有限会社デライトシステム ズ", "position" => "代表取締役, 性能探求者" }, %{"name" => "ざっきー", "age" => 45, "team" => "公立大学法人 北九州市立大学", "position" => "准教授, カーネルハッカー" }, %{"name" => "つちろー", "age" => 34, "team" => "カラビナテクノロジー株式会社", "position" => "リードエンジニア, アプリマイスター" }, %{"name" => "ゆじかわ", "age" => 30, "team" => "カラビナテクノロジー株式会社", "position" => "リードエンジニア, グロースハッカー" }, %{"name" => "piacere", "age" => 43, "team" => "株式会社TechJIN", "position" => "CTO, 福岡Elixirプログラマ, 重力プログラマ, 技術顧問" } ]

Slide 20

Slide 20 text

19 3.入門①:Excelの操作と同じElixir [ %{ "age" => 49, "name" => "enぺだーし", "position" => "代表取締役, 性能探求者", "team" => "有限会社デライトシステムズ" }, %{ "age" => 45, "name" => "ざっきー", "position" => "准教授, カーネルハッカー", "team" => "公立大学法人 北九州市立大学" }, %{ "age" => 34, "name" => "つちろー", "position" => "リードエンジニア, アプリマイスター", "team" => "カラビナテクノロジー株式会社" }, %{ "age" => 30, "name" => "ゆじかわ", "position" => "リードエンジニア, グロースハッカー", "team" => "カラビナテクノロジー株式会社" }, %{ "age" => 43, "name" => "piacere", "position" => "CTO, 福岡Elixirプログラマ, 重力プログラマ, 技術顧問", "team" => "株式会社TechJIN" } ]

Slide 21

Slide 21 text

20 3.入門①:Excelの操作と同じElixir List.firstを使うと、先頭行のみ取得できます 取得した行から、特定の列の値を取り出すには、[ "【列名】" ] で行います iex> first_line = data |> List.first %{ "age" => 49, "name" => "enぺだーし", "position" => "代表取締役, 性能探求者", "team" => "有限会社デライトシステムズ" } iex> first_line[ "name" ] "enぺだーし" iex> first_line[ "age" ] 49

Slide 22

Slide 22 text

21 「年齢」列でフィルタするには、Enum.filter()にて、「年齢」列の 値の条件判断により、フィルタをかけます 3.入門①:Excelの操作と同じElixir iex> data |> Enum.filter( &( &1[ "年齢" ] > 40 ) ) [ %{ "ポジション" => "代表取締役, 性能探求者", "名前" => "enぺだーし", "年齢" => 49, "所属" => "有限会社デライトシステムズ" }, %{ "ポジション" => "准教授, カーネルハッカー", "名前" => "ざっきー", "年齢" => 45, "所属" => "公立大学法人 北九州市立大学" }, %{ "ポジション" => "CTO, 福岡Elixirプログラマ, 重力プログラマ, 技術顧問", "名前" => "piacere", "年齢" => 43, "所属" => "株式会社TechJIN" } ]

Slide 23

Slide 23 text

22 複数列の「年齢」列でソートをかけるには、Enum.sort()にて、 &1 (現在行)と&2 (次行) の「年齢」列を、昇順なら「<」、 降順なら「>」で比較することでソートします 難しかったですかね?もし難しければ、ここは覚えなくて良いです 3.入門①:Excelの操作と同じElixir iex> data |> Enum.sort( &( &1[ "age" ] < &2[ "age" ] ) ) [ %{ "ポジション" => "リードエンジニア, グロースハッカー", "名前" => "ゆじかわ", "年齢" => 30, "所属" => "カラビナテクノロジー株式会社" }, … %{ "ポジション" => "代表取締役, 性能探求者", "名前" => "enぺだーし", "年齢" => 49, "所属" => "有限会社デライトシステムズ" } ]

Slide 24

Slide 24 text

23 「年齢」列のみを「変換」するには、Enum.map()にて、「年齢」 列の値の処理により、変換をかけます 「名前」列のみの変換もできます 特に処理を書かなかったら、何も変換されず、出力されます 3.入門①:Excelの操作と同じElixir iex> data |> Enum.map( &( &1[ "年齢" ] + 100 ) ) [149, 145, 134, 130, 143] iex> data |> Enum.map( &( &1[ "年齢" ] ) ) [49, 45, 34, 30, 43] iex> data |> Enum.map( &( &1[ "名前" ] <> "さん" ) ) ["enぺだーしさん", "ざっきーさん", "つちろーさん", "ゆじかわさん", "piacereさん"]

Slide 25

Slide 25 text

24 前ページの上記は、以下のように、「fn~end」と関数を使い、 以下のように書き直すことができます やや難しく思えたかも知れませんが、P47で行った「fn~end」と 関数での書き方と同じ、と聞けば、fnの後の書き方が違うだけ、 と理解しやすくなるかも知れません 3.入門①:Excelの操作と同じElixir iex> data |> Enum.map( fn %{ "age" => n } -> n end ) ) [49, 45, 34, 30, 43] iex> [ 323, 999, 54 ] |> Enum.map( fn n -> n * 2 end ) [646, 1998, 108] iex> data |> Enum.map( &( &1[ "年齢" ] ) ) [49, 45, 34, 30, 43]

Slide 26

Slide 26 text

25 「fn~end」と関数を使った書き方で、複数列を、別の複数列に 変換せずに移すことも、Enum.map()でできます (結果的にこれは、特定の列を抜き出す処理になります) 3.入門①:Excelの操作と同じElixir iex> data |> Enum.map( fn %{ "name" => name, "age" => age } -> %{ "name" => name, "age" => age } end ) [ %{"age" => 49, "name" => "enぺだーし"}, %{"age" => 45, "name" => "ざっきー"}, %{"age" => 34, "name" => "つちろー"}, %{"age" => 30, "name" => "ゆじかわ"}, %{"age" => 43, "name" => "piacere"} ]

Slide 27

Slide 27 text

26 前ページの上記は、Enum.map()内を列毎に並べて書き直す と以下の通りです ちなみに、fnを使わないと、以下になります (どちらが簡単?) 3.入門①:Excelの操作と同じElixir iex> data |> Enum.map( &( %{ "name" => &1[ "name" ], "age" => &1[ "age" ] } ) ) iex> data |> Enum.map( fn %{ "name" => name, "age" => age } -> %{ "name" => name, "age" => age } end ) iex> data |> Enum.map( fn %{ "name" => name, "age" => age } -> %{ "name" => name, "age" => age } end )

Slide 28

Slide 28 text

27 「for」を使うと、Enum.map()と同じようなリスト操作ができます これを最初に出さなかったのは、以下3つの理由からです ① 既存のオブジェクト指向言語の「for」と同じで無いから ② Enum.map()のように、パイプを繋いで使えないから ③ 馴染みあるせいで使いたくなる、という思考が罠だから 3.入門①:Excelの操作と同じElixir iex> for record <- data do ...> %{ "name" => record[ "name" ], "age" => record[ "age" ] } ...> end [ %{"age" => 49, "name" => "enぺだーし"}, %{"age" => 45, "name" => "ざっきー"}, %{"age" => 34, "name" => "つちろー"}, %{"age" => 30, "name" => "ゆじかわ"}, %{"age" => 43, "name" => "piacere"} ]

Slide 29

Slide 29 text

28 4.事前準備:PhoenixでPJ作成

Slide 30

Slide 30 text

29 4.事前準備:PhoenixでPJ作成 ExcelのようなElixirの書き方を使って、DBデータをWebに表示 するPJを作る前準備として、PostgreSQLをインストールします PostgreSQLのインストール手順は割愛しますが、パスワードは 「postgres」で設定しておいてください (以下、Windows版のインストール中設定画面)

Slide 31

Slide 31 text

30 4.事前準備:PhoenixでPJ作成 次に、ElixirのWebアプリケーションフレームワーク「Phoenix」を インストールします(要ネット接続) Phoenixプロジェクトを作成します (要ネット接続) DBを作成します ※作成しないとiex内でエラー連発となります Phoenixサーバーを起動します # mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez # mix phx.new sample_db --no-brunch # iex -S mix phx.server 掲載スペースの関係で2行になっていますが、 2行目URLも続けて1行で入力してください PJ名には、英小文字と「_」を指定しないと エラーないしはビルド途中でコケることがあります # cd sample_db # mix ecto.crete

Slide 32

Slide 32 text

31 4.事前準備:PhoenixでPJ作成 ブラウザで「http://localhost:4000」にアクセスすると、 Phoenixで作られたWebページが見れます

Slide 33

Slide 33 text

32 5.初級:DBデータをWeb表示

Slide 34

Slide 34 text

33 5.初級:DBデータをWeb表示 DBの準備をするため、psqlを起動し、既に「mix ecto.crete」 で作成したデータベースに接続します 以下SQLで、Webに表示する元データのテーブルを作成します create table members ( id integer, name varchar(255), age integer, team varchar(255), position varchar(255) ) postgres-# ¥c sample_db_dev データベース "sample_db_dev" にユーザ "postgres" として接続しました。 postgres-# ¥d members テーブル "public.members" 列 | 型 | 照合順序 | Null 値を許容 | デフォルト ----------+------------------------+----------+---------------+------------ id | integer | | | name | character varying(255) | | | age | integer | | | team | character varying(255) | | | position | character varying(255) | | |

Slide 35

Slide 35 text

34 5.初級:DBデータをWeb表示 以下SQLで、Webに表示する元データを追加します insert into members( id, name, age, team, position) values ( 1, 'enぺだーし', 49, '有限会社デライトシステムズ', '代表取締役, 性能探求者' ); insert into members( id, name, age, team, position) values ( 2, 'ざっきー', 45, '公立大学法人 北九州市立大学', '准教授, カーネルハッカー' ); insert into members( id, name, age, team, position) values ( 3, 'つちろー', 34, 'カラビナテクノロジー株式会社', 'リードエンジニア, アプリマイスター' ) insert into members( id, name, age, team, position) values ( 4, 'ゆじかわ', 30, 'カラビナテクノロジー株式会社', 'リードエンジニア, グロースハッカー' ); insert into members( id, name, age, team, position) values ( 5, 'piacere', 43, '株式会社TechJIN', 'CTO, 福岡Elixirプログラマ, 重力プログラマ, 技術顧問' );

Slide 36

Slide 36 text

35 5.初級:DBデータをWeb表示 selectを直接発行するために、以下のモジュールを用意します ※実は、性能重視のSQLを書く場合に、このモジュール重宝します defmodule Db do def query( sql ) when sql != "" do { :ok, result } = Ecto.Adapters.SQL.query( SampleDb.Repo, sql, [] ) result end def columns( %{ columns: columns } = _result ), do: columns def rows( %{ rows: rows } = _result ), do: rows def columns_rows( result ) do result |> rows |> Enum.map( &( Enum.into( List.zip( [columns( result ), &1 ] ), %{} ) ) ) end end lib/util/db.ex

Slide 37

Slide 37 text

36 5.初級:DBデータをWeb表示 selectでDBデータを取得して、HTMLを出力します 最初のfor (3行目) は、各行毎のデータを「record」に渡し、 行数分だけループします 1つ内側のfor (5行目) は、列名を「column」に渡し、6行目 の「record[ column ]」で、各行各列の出力に使います <% data = Db.query( "select * from members" ) %> <%= for record <- Db.columns_rows( data ) do %> <%= for column <- Db.columns( data ) do %> <%= record[ column ] %> <% end %> <% end %> lib/sample_db_web/templates/page/index.htm

Slide 38

Slide 38 text

37 5.初級:DBデータをWeb表示 DBデータがWeb表示されました

Slide 39

Slide 39 text

38 5.初級:DBデータをWeb表示 列名もHTML出力してみます lib/sample_db_web/templates/page/index.htm <% data = Db.query( "select * from members" ) %> <%= for column <- Db.columns( data ) do %> <%= column %> <% end %> <%= for record <- Db.columns_rows( data ) do %> <%= for column <- Db.columns( data ) do %> <%= record[ column ] %> <% end %> <% end %>

Slide 40

Slide 40 text

39 5.初級:DBデータをWeb表示 列名もWeb表示できるようになりました

Slide 41

Slide 41 text

40 5.初級:DBデータをWeb表示 この作り方の延長で、こんなデータサイエンスアプリも開発できます Excelからスタートして、ここまで来れるのは、ワクワクしませんか?

Slide 42

Slide 42 text

41 5.初級:DBデータをWeb表示 DBからだけで無く、外部APIから取得して、Web表示するのも、 ほぼ同じ要領で作れます…次回解説しますが、ワクワクですね!! (Backlog/Zendeskという2種類の問合せ管理ツールをAPI 呼出でWeb表示したものが以下)

Slide 43

Slide 43 text

42 6.Excelから関数型言語に行った理由

Slide 44

Slide 44 text

43 6.Excelから関数型言語に行った理由 途中にあったforが、「罠」だと言ったのを、思い出してください 恐らくforを最初に出していたら、既存のプログラミング言語を思い 出しながら、Elixirを覚えていったのでは無いでしょうか? 今回、ExcelからElixir、という流れにした一番の理由は、既存 のプログラミング言語から離れた方が、Elixirや関数型言語は、 習得しやすい、ということを実感してもらうことが裏の目的でした 「関数型言語」のコンセプトは、非常にシンプルで強力であるが 故に、複雑な「オブジェクト指向言語」に慣れた人にとっては、 逆に難しく感じる…という妙な心理作用が発生し、これが関数 型言語の習得を邪魔しているのです 「Excel」という、誰もが使えるもので、この思い込みを脱しました

Slide 45

Slide 45 text

44 6.Excelから関数型言語に行った理由 「オブジェクト指向言語」と比較した「関数型言語」には、以下の ような大きな違いがあります ① メンバー変数やグローバル変数のような「状態」を持てない ② 一度、代入した変数は、変更できない (≒イミュータブル) ③ Elixir以外の関数型言語には、オブジェクト指向言語では、 一切出ない、「カリー化」 「部分適用」「クロージャ」「モナド」 等の摩訶不思議なキーワードが幾つも出てくる ※関数型の習得に必須に見えるが、上記は必須では無い こうした違いは、とても有用な一方、真正面から受けると、プログ ラミング経験が幾らあっても、隔たりが大き過ぎて、辛いのです こうした罠を回避するための「Excelで覚えるElixir」だったのです

Slide 46

Slide 46 text

45 ご清聴ありがとうございます