C++幼女先輩

プログラミング成分多め

Elixir Phoenix 試食

はじめに

ここ1か月にたくさんの言語仕事で触っている
PHP(なぜか今まで触ったことなかった)、GolangPython、Elixir、RailsScala、node(5年ぶり2回目) など
1か月程度なので知見がほとんどないけど、知識をまとめていく

作るもの

APIサーバのサンプル(評価)プロジェクト
Redis、MySQL、MongoDBなどのCRUDテスト
言語の評価
Docker構築

Docker構築

最初は OSから自分で入れた
とりあえずUbuntu

FROM ubuntu:17.04

RUN apt-get update

RUN apt-get install -y sudo wget
RUN apt-get install -y language-pack-ja
RUN wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && dpkg -i erlang-solutions_1.0_all.deb
RUN apt-get update
RUN apt-get install -y esl-erlang
RUN apt-get install -y elixir

ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8

# Set app env
ENV HOME /root

WORKDIR /usr/local/src
RUN apt-get install -y libssl-dev ncurses-dev
RUN apt-get install -y sudo wget git tar bzip2 incron vim nodejs npm
RUN apt-get install -y inotify-tools


RUN yes | mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez


#RUN mkdir /runnet
#WORKDIR /runnet

ENV PHOENIX_APP_NAME runnet
ENV PHOENIX_APP_PORT 4000
ENV PHOENIX_APP_ROOT /${PHOENIX_APP_NAME}

WORKDIR /$PHOENIX_APP_ROOT

EXPOSE ${PHOENIX_APP_PORT}
COPY . $PHOENIX_APP_ROOT
WORKDIR /runnet/$PHOENIX_APP_ROOT

# Compile phoenix(FOR dev)
RUN yes | mix local.hex && yes | mix local.rebar && mix do deps.get, compile

RUN mix deps.get
RUN mix ecto.create
RUN mix ecto.migrate

# npm install
#RUN npm install
#RUN npm install -g brunch

# Run Phoenix
CMD ["/bin/bash", "-c", "mix phoenix.server"]

色々無駄なものがあるけど、とりあえず Erlang、Elixir、Phoenix と必要なものをセットアップ
結構めんどくさいね。イメージも大きいし
時間あったら Alpineにしようと思っていた

docker-composeも下記のかんじで

version: '2'
services:
  app:
    build: .
    environment:
      MYSQL_ROOT_USERNAME: 'root'
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_HOSTNAME: 'mysql'
      MYSQL_PORT: '3306'
    ports:
      - '4000:4000'
    volumes:
      - .:/runnet
    links:
      - mysql
  mysql:
    image: mysql:5.7.10
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
    ports:
      - '3306:3306'
    volumes:
      - mysql-data:/var/lib/mysql
volumes:
  mysql-data:
    driver: local

PhoenixはデフォがPostgresだけど MySQLを入れた

router

  scope "/", Runnet do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/users", UserController
  end

controller

defmodule Runnet.UserController do
  use Runnet.Web, :controller

  alias Runnet.User

  def index(conn, _params) do
    users = Repo.all(User)
    render(conn, "index.html", users: users)
  end

  def new(conn, _params) do
    changeset = User.changeset(%User{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    changeset = User.changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, _user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: user_path(conn, :index))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    user = Repo.get!(User, id)
    render(conn, "show.html", user: user)
  end

  def edit(conn, %{"id" => id}) do
    user = Repo.get!(User, id)
    changeset = User.changeset(user)
    render(conn, "edit.html", user: user, changeset: changeset)
  end

  def update(conn, %{"id" => id, "user" => user_params}) do
    user = Repo.get!(User, id)
    changeset = User.changeset(user, user_params)

    case Repo.update(changeset) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User updated successfully.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, changeset} ->
        render(conn, "edit.html", user: user, changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    user = Repo.get!(User, id)

    # Here we use delete! (with a bang) because we expect
    # it to always work (and if it does not, it will raise).
    Repo.delete!(user)

    conn
    |> put_flash(:info, "User deleted successfully.")
    |> redirect(to: user_path(conn, :index))
  end
end

model

defmodule Runnet.User do
  use Runnet.Web, :model

  schema "users" do
    field :name, :string
    field :email, :string
    field :encrypted_password, :string

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :email, :encrypted_password])
    |> validate_required([:name, :email, :encrypted_password])
  end
end

migrateファイル

defmodule Runnet.Repo.Migrations.CreateUser do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :name, :string
      add :email, :string
      add :encrypted_password, :string

      timestamps()
    end

  end
end

ユーザ名、メールアドレス、パスワードを保存する、よくあるログイン認証まわり
細かく追ってないけど Routerでresources を指定すると、複数のメソッドに対応してくれるっぽい
そのあたりが自動的に controllerの index、new、create、show、update、delete等に対応される

MySQLとの連携もばっちりだし、そこまで言語的にも覚えにくくないと思う

Postgresで再構築

いちおうPostgresにて構築してみる。Redisも使う
同じようにDockerイメージ作る

docker-compose.yml

version: '3'
services:
  db:
    image: postgres
    ports:
      - 5432:5432
  redis:
    image: redis:latest
    ports:
      - 6379:6379
  web:
    build: .
    container_name: "ages_app"
    volumes:
      - $PWD:/ages
    ports:
      - "4000:4000"
    links:
      - db
      - redis
    environment:
      DATABASE_USER: postgres
      DATABASE_PASSWORD:
      DATABASE_PORT: 5432
      DATABASE_HOST: db
      REDIS_URL: redis://redis:6379
    depends_on:
      - db
      - redis

今回はゲームサンプルを見据えて DB定義もそれっぽくする

router

  scope "/", AgesApp do
    pipe_through :browser # Use the default browser stack

    get "/users", UserController, :index
    get "/user/:id", UserController, :show
    get "/", PageController, :index
  end

コントローラーのソース消失!

model

defmodule AgesApp.User do
  use AgesApp.Web, :model

  schema "users" do
    field :name, :string
    field :os_type, :string
    field :device_id, :string
    field :device_name, :string
    field :os_version, :string
    field :game_money, :integer
    field :ios_charge, :integer
    field :android_charge, :integer
    field :max_hp, :integer
    field :level, :integer
    field :exp, :integer
    field :max_deck_count, :integer
    field :max_deck_point, :integer
    field :max_friend, :integer
    field :tutorial_progress, :integer
    field :last_login_at, :naive_datetime

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :os_type, :device_id, :device_name, :os_version, :game_money, :ios_charge, :android_charge, :max_hp, :level, :exp, :max_deck_count, :max_deck_point, :max_friend, :tutorial_progress, :last_login_at])
    |> validate_required([:name, :os_type, :device_id, :device_name, :os_version, :game_money, :ios_charge, :android_charge, :max_hp, :level, :exp, :max_deck_count, :max_deck_point, :max_friend, :tutorial_progress, :last_login_at])
  end
end

Migrate、Seedのコードも消失!

Postgresは上手くいったが、その後 Redisにセッション保存をしようと思い、Redis用のライブラリを探す
exredisが有名らしいので調べたところ、キー取得時にエラーがわからないという酷い実装のため変更

exredis を使ってみなかった - Qiita

redixをパッケージに追加するとDependencyエラー
色々なバージョンを試してみたが、簡単にはいかない

その後、うちのメンバーに新人の参入可能性が高まったため、一度JavaScript覚えさせたいのと
最近のnodeは、ES6に対応したり、以前よりも複数人開発がしやすくなっているので
nodeの調査に変更した

Docker for windows 快適に使う

色々書いていたが Qiitaに投稿したので そっちのリンクを

qiita.com

とりあえず、私は6年前まではWindowsで開発
Linuxサーバ関連はVM使ったり、SSHログインしたり、Windowsネイティブで など色々だけど
基本的に面倒
5年前に iOS開発のためMac買ってからは、しばらくMac上で開発して快適だった

ところが、ここ数年 Dockerが便利で、Vagrant等も併用すると、WindowsでもMacでもほぼ同じに VM上で開発できる

そして、Windows10では Dockerがネイティブで動くようになった! Docker for Windowsの登場である
それに WindowsSubsystem for Linux ( WSL、 Bash on Windows) もかなり良くなり
また Dockerのファイルアクセスが、Windowsだけ10倍~のオーダーで爆速のため
最近は 完全にWindowsでサーバ開発している

今までの VM上でDockerを建てる方式は、何も困ることがなく、爆速になるのだが
おそらく Docker for Windowsのほうが 1~2割ほど速くなるはずなので、そちらを利用している
その場合は パスの問題やWindows固有問題で躓くことがあったが
今のところ全部回避できている

問題がおこるたびに 解決法を探していきます。私は人柱

Docker向け DB設定まとめ

DockerでDB使うたびに調べるの疲れたのでまとめる

だいたい、ゲームサーバやWebで使われるDBは下記だ
MySQL 、postgres、Redis、Mongo
それらの設定をまとめる

DB port mount command ENV
MySQL 3306 /var/lib/mysql MYSQL_ROOT_PASSWORD={pass}
postgres 5432 //var/lib/postgresql/data
redis 6379 /data redis-server --appendonly yes
mongo 27017 /data/db

年末~年始の開発 Elixir phoenix、node express、ruby rails 調査

あけましておめでとうございます

年末~年始にかけて、自分で作るゲーム用にサーバ開発の調査をしていた
色々な選択肢があり C++で作る:経験あるし可能だが、初心者のメンバーがいるので今回は却下
JavaPlayframework:前に作って経験があるし Java8等も使ってみたいが飽きたので
Ruby on RailsPythonPHP・・: サーバ運用コスト考えると遅いサーバは費用が辛いので却下
ErlangHaskellClojure:趣味に走りすぎか
Scala:ビルド長い
C#:まだMicrosoftロックインははやい
Go:言語的にちょっと・・

で、結局
Rails: ほとんどのフレームワークRailsライクなので基礎としていつか勉強させるべきだ
Elixir:そこそこ速いらしい。堅牢性は十分。これからのWeb言語の候補
node:そもそもC10Kはnodeが解決すべきであった。言語の堅牢性が悪いが ES6 Babelを使えばかなり回避可能である

の3本に絞った

Rails

一応最初に Railsを調べた。というのは最も日本語情報もありコミュニティが発達していたからだ
あっさりDockerを作り簡単なAPIを作った
一旦中断

Elixir

Alpine Linuxから Elixir環境をビルドしてくるDockerを作ってみた。とりあえず上手くいった
ところが、mixパッケージの依存関係なので、本体バージョンなどの制約があり
色々なバージョンを選べるよう、他人のイメージを使っている
バージョンFixできたらAlphineで1から作りたいところ

現在は、やはりmixパッケージの依存関係で mongodbのライブラリがうまくビルド出来ず
いろんなバージョンを試したり、情報をあさっているところ
正直辛い・・ nodeでいいや という気持ちになってきている

また、最も有名なmongoライブラリ exredisは、findやsave時にエラーか成功かを取れない
という問題もあり redixを使おうと思っている
まだビルドエラーなんだけどね・・

node

ここ数年のJavaScript業界はカオスで情報収集怠っていたが、ふと名案を思い付いた
node+express に対し ES6で記述しBabelすることは必須と思っているが
Webpack等でワンソースにして minifyかけると、実行速度も上がり 素晴らしいはず
そして 通常開発Dockerと ビルド済Dockerを別にすれば Dockerイメージも極小になるし最強ではないかと

方針はなんとなくたった
Builderイメージとrunnerイメージを作り
Builderイメージは 普通に expressで新規プロジェクト作り lebabでES6に変換し開発をする
そして 自動的にBabelしてWebpackしてminifyし Runnerイメージで実行
ただし 色々と躓きポイントがあるので、1個ずつ検証中だ

とりあえず今は普通の Expressでmongodbの設定を試している
データベース指定でconnectすると固まるので 原因をさぐっているところ

あとは オートリロードが出来ていないので不便

そして最大の問題が BuildとRunを別Dockerにして実行させるやつ
ES6対応ともいう
はやくES6使いたい

来年の抱負みたいなもの

来年の抱負みたいなものを

今から来年の事を言うと
あっせんなよ トランキーロ って言われそうだけど一応

仕事について

メインはやはりプログラム。下記で細かく書くけど、ゲームを中心としたのはかわらない
釣りと音楽はそろそろ事業化したい
ゲーム実況的なものを趣味で始める。Youtuberになるとかではなく ライフログ的に
楽しい会社目指したいね

ブログ SNSについて

Facebookは仕事の話題率を高くし、それ以外は極力話さない事にしノイズ減らす
Twitterで仕事以外のつぶやきをし、Twitter率を増やす
はてなブログは基本コードを書くところだが、それ以外も試験的に増やす。現在平均でDailyが25-30 下降気味なので50目指す
C++の記事を増やしたいが当分は色々な技術を書く
Qiitaには はてぶろであるていどまとまってから情報として残す

IT事業

セカンドハウス借りて時々人を呼べる環境は作ったけど、事務所 欲しいね。ちゃんと探そう
ゲームを1本まるっと請け負える体制を1年で作れるかが勝負だ
まずはサーバを〇請けできるよう、サンプルのゲームとサーバインフラ一式の開発を行い営業に使う
Elixirをサーバに使う予定だが、C++技術ももっと勉強する
ゲーム以外はいろいろな新規に誘われているが、C++人工知能を中心として手伝えれば・・
スタートアップ関連にかんしては どれに集約するか・・だけど 頑張る
インドオフショアも目指す

音楽

セカンドハウスが出来たので、ちゃんと練習する
スラ研、セッパ もっと参加して、Alwaysはミストーンゼロ目指す
その他 アニソンバンド2個もちゃんと練習して再開うながす
大西さんのレッスン受ける体制作る

釣り

セカンドハウスに釣り道具置けるようになった
原付も置けるようになったので、東京湾攻めれる
管釣りでは、普段使ってないルアー練習しパーフェクト目指す
釣り動画作って事業化
釣りゲームも

運動

最近ジム行けてないので毎日行く事にしよう。有酸素無理でもマシンだけでも
とりあえずは1日5キロを目指す。欲いえば1日10キロ1時間
マラソン大会出よう。とりあえずハーフから

Windowsと Bash on WindowsでGolangはじめる

はじめに

以外と困ったのでメモ
まず結果からいえば、現在のGoはWindowsではプラグイン(ダイナミックリンク)が出来ない
ので、出来るだけLinuxで開発しましょう

Windows

インストールは簡単だ
Windowsのばあいはmsiでインストールできるのでそれで問題が無い
バージョンも現在の最新 1.9.2 である
環境変数 GOROOTも設定してくれる(デフォルトで C:\go)
すばらしい!

一応 GOBINに対して、%GOROOT%\bin を設定してみた。

> go get
> go build

OK 簡単

ただし、Windowsではプラグインを使えない

Bash on Ubuntu on Windows

$ apt-get install golang  

で簡単におわりそうだが、落とし穴がある

$ go version
go version go1.2.1 linux/amd64

古すぎる・・・
ので 最新をwgetしてくる

$ apt-get remove golang
$ wget https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz
$ tar xvfz go1.9.2.linux-amd64.tar.gz
$ sudo mv go /usr/local
$ vim ~/.bashrc
環境変数設定
$ source ~/.bashrc
$ go version
go version go1.9.2 linux/amd64

環境変数は下記のように設定してみた

export GOROOT=/usr/local/go
export GOPATH=/home/yuki/go
export PATH=$GOROOT/bin:$PATH
export GOBIN=$GOROOT/bin

近況:PHP Laravel触ってます

なぜか今までPHPの仕事をしたことがなく
C++Java等のコンパイル言語ばっかだったし

今更PHP入門ですが、こいつがまた わかりやすい言語でして
表記がCやJavaに似てるから 慣れがある

ただし 何個か気を付けることがある

文字列の連結

+ではなく.
Perlですね

ラムダ、クロージャ

ラムダが使えるんだけど驚くことにC++でいうキャプチャがあるってこと
use() 内にキャプチャする変数を指定

変数

すべて頭に$が必要
メンバ変数やメソッドを呼ぶにも $this->method() とかく必要がある
メンバ変数を参照するときは メンバ変数名の前に$はいらない $this->menber
メンバ変数名を変数で呼ぶことができる。その時は変数名の前にも$をつける $idx = 'member'; $this->$idx; // $this->idxではなく $this->member が参照される

&

なんとPHPでは参照というのがある
関数の引数や foreachの変数は、コピーなのでそこに対して変更しても反映されないが
&をつけてやると、C++でいう参照となり値を変更することができる

===

JavaScriptなどにあるやつ
===だと型も見て(暗黙型変換をせず)比較してくれる
特に必要なのは null時チェックかな

isset、empty、is_null

細かい違いはおいておいて、コンパイル言語とは違い未定義という状態もあり得る
その時に falseを返したりする
ただしラムダのキャプチャ(use)なり、関数の引数にするときは Undefinedエラーが出るので定義しておかないとだめ
可変長引数も使えるけど・・・ねぇ・・・

Array

ちょいめんどう
配列はない。全部連想配列である
省略すると intのKey 自動インクリメントで保存されるので実質配列のように扱うことができるが
stringのKeyと同居することも出来る
また 初期化及び値を代入する際も hoge( 'key' => 'value') のように書く
ここは 慣れるしかない

Laravel

Railsライクなライブラリなので、なんとなーくRailsを知ってれば扱いやすいんじゃないかな?
Railsとの比較はほかの人に任せます。私は比較できるほどの知識はない

総括

Railsライク
文法はJava
所々 CやC++の知識があると楽なところが多い
C++Javaの人にはわかりやすい