nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

メールアドレスとウェブサイトを Google のサービスのみを使って用意する

はじめに

  • アプリを公開するため問い合わせ用のメールアドレスとウェブサイトを用意することにした
  • メールアドレスの用意のためにメールサーバーは管理したくないので Gmail が使えて独自ドメインが使える G suites を使う
  • ウェブサイトは GAE/Go を最近使っていて慣れているので静的ページのみだが GAE を使ってみる

独自ドメインのメールアドレスをつくる

  • Gmail などが独自ドメインで利用できる G suites に契約する
  • 1 アカウントで最安プランで月 600 円、1 年まとめ払いで月 500 円
  • ドメインも一緒に購入できて “.com” で年 1000 円
    • 実際のドメイン管理者は Google ではなく eNom
    • 値段はお名前.comと同じくらいで eNom で直接買うより何故か安い
    • 購入後に eNom 側の管理画面を使って DNS のカスタム設定もできる
  • 購入後にアカウントの設定からメールのエイリアスも登録できる

独自ドメインのウェブサイトをつくる準備をする

  • 作成したメールアドレスで Google Cloud Platform に登録する
    • いまだと新規契約で 300 ドルまでの無料枠が使えた
  • GCP でウェブサイト用のプロジェクトを作成する
  • Google App Engine をつかってウェブサイトをつくる
    • 静的ページのみでも GAE を使うと独自ドメインでの公開が楽
    • 静的ページのみならインスタンスの起動時間あたりの使用料は発生しない
    • GAE の設定ファイルだけで簡単なルーティングをしてくれるので Google Cloud Storage とかに直接静的ファイルを置くよりも便利
  • Google Site Repositories でウェブサイトのソースコードを管理する
    • ウェブサイト用のプロジェクトで GSR のレポジトリをつくる

ウェブサイトを作る

設定ファイルを用意する

  • “/” で “index.html” を表示
  • それ以外は “404.html” を表示
  • それだけだとデプロイ時にエラーになるので参照されない go ファイルの実行パスを追加
runtime: go
api_version: go1

handlers:
- url: /
  static_files: index.html
  upload: index.html
- url: /.*
  static_files: 404.html
  upload: 404.html
- url: /.*
  script: _go_app

HTML ファイルの用意

  • 任意で

Go ファイルの用意

  • 参照されないが置いておかないとデプロイできないので何もしないファイルを置いておく
package main

import "net/http"

func init() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // no op
    })
}

デプロイ

gcloud app deploy app.yaml --project [PROJECT_ID] -v [VERSION]

さいごに

  • 独自ドメインとメールアドレスの方は探せばもっと安いものはありそうな気がするがとりあえず慣れているので Gmail 便利。
  • ウェブサイトの方は使わない Go ファイルを置いたりするのがいけてないが、よっぽどのことがない限り無料枠で収まってれると思うので悪くない気がする。

Unity の UnityEditor.BuildPipeline:BuildAssetBundles で出たエラーと対策

前提条件

  • Unity 5.6.1f
  • UnityEditor.BuildPipeline:BuildAssetBundles で Asset Bundle をビルドしたらエラーが発生した

エラー内容

  • ポップアップで “Build failure Internal error: Target platform mismatch”
  • コンソールに “Menu Edit/Graphics Emulation/OpenGL ES 3.0 can’t be checked because it doesn’t exist” とエラー表示

対策

  • Unity 5.6.1f から最新の Unity 5.6.2f にアップグレードしたらエラーにならずに正常に Asset Bundle のビルドができるようになった

参考URL

https://forum.unity3d.com/threads/got-an-error-when-building-assetbundles-target-platform-mismatch.476663/

ユースケース駆動開発実践ガイドまとめと感想

はじめに

感想

  • ウォーターフォール的なちゃんと設計ドキュメントを作ってから実装する、みたいな流れで開発をしたことがなかったので勉強になったし、ユースケースの作り方なんかはためになった
  • これをそのまま実践するかというとしないと思うが、選択肢として堅いやり方を知っておきながら柔らかいやり方と使い分けていけるようになれればいいかなと思う

簡単なまとめ

  • 全体を通して ICONIX(アイコニクス)プロセスという手法を使ったソフトウェア開発について書かれている
  • ざっくりまとめると、要求を、ドメインモデル、ユースケースロバストネス図、シーケンス図、コード、と変換していくことで、要求漏れがなく手戻りが少ない開発ができる、みたいなことだと理解
  • 以下各章ごとに順にまとめ

第1章 ICONIXプロセス

  • 全体の大まかなまとめ
  • 全部読んでからならここだけ読めばなんとなく復習できるかも

第2章 ドメインモデリング

  • 静的モデルを一番初めに定義しておき、後の工程で曖昧さのない用語を利用する

感想

  • エリック・エヴァンス本で言うユビキタス言語のことか
  • エリック・エヴァンス本でドメインモデルというと図のことではなく振る舞いなども含めた概念を指すと思うので同じ言葉だが別のものを指しているはず

第3章 ユースケースモデリング

  • 要求からユースケースを作っていく
  • ユースケースとは「AはBをする、次にCはDをする」という叙述的なものになる
    • ユーザーがログインする場合のユースケースの例は「システムはログイン画面を表示する。ユーザーはユーザー名とパスワードを入力してログインボタンを押す。システムはユーザー名とパスワードをチェックする。ユーザーはシステムにログインする。」といったもの
  • ユースケースは基本コース(正常系)と代替コース(異常系)すべてを網羅すること
  • ユビキタス言語を使用して記述されていること
  • 「ログイン画面を表示する」というようにGUIの具体的なパーツ名を使用して記述されていること
  • 必要であればドメインモデルを更新する

3つの魔法の質問

  • ユースケースを書くときには、「何が起きるか?」「そして何が起きるか?」「他にどのようなことが起きそうか?」という質問を繰り返して正常系異常系すべてのケースをあぶり出していく

第4章 要求レビュー

  • ドメインモデルとユースケースが要求を満たしているか顧客と共にレビューを行う
  • 必要なら紙芝居やモックやプロトタイプを作って説明を行う

第5章 ロバストネス分析

感想

  • ロバストネス図を作ることで予備的な設計が行われ、UIやドメインや処理の不足や用語のブレなどがあらかじめ浮き彫りになってくる
  • 最近 twitter で流れてきた、先の工程に進むと前の工程のアラが見えてくる法則を逆に利用してはやめに先の工程に進んでミスを潰していくという戦術なのかも
  • オブジェクトでもコントローラでもない、間の線に書かれた文字の意味がわからない
    • なんとなくユーザーの振る舞いは線上に書いている気がする
    • ユーザーの振る舞いでもコントローラになっているものもある
    • 粒度の問題?
    • たぶん説明がないのでロバストネス図について理解が曖昧になっている

第6章 予備設計レビュー

第7章 テクニカルアーキテクチャ

第8章 シーケンス図

  • ロバストネス図をシーケンス図に変換する
  • 正常系も異常系も同じシーケンス図上に記述する
  • ロバストネス図上では各コントローラについて誰が主体になって行っているかが記述されていないので、シーケンス図を使って処理の主体をはっきりさせてオブジェクトとメソッドを定義していく
  • 活性区間(線上の長方形、オブジェクトのライフタイムを表す)は利用しない
  • 必要であればロバストネス図を更新する

第9章 詳細設計レビュー

  • シーケンス図を開発者のみでレビューする
  • シーケンス図とユースケースの割り当てができてるかや、適切な属性と操作が割り当てられているかなどを確認する

第10章 実装

  • ここから具体的に Spring Framework を使って具体的に実装していく
  • 汎用的に使えそうな内容としては、設計をそのまま実装しなさい、コーディング中につまったら設計から見直しなさい、設計とコードを常に動悸させなさい、コメントを書きすぎてはいけません、正常系だけでなく異常系も書くのです

感想

  • ここから先は Spring Framework についての具体的な話になっており流し読みしたくらいなので省略

GAE/Go 環境で echo が実行できない問題

問題

  • GAE/Go 環境で echo を使ったアプリケーションを goapp serve で実行しようとすると以下のエラーが発生して実行できない
2017/01/16 16:08:42 go-app-builder: Failed parsing input: parser: bad import "unsafe" in github.com/valyala/fasttemplate/template.go from GOPATH

原因

  • echo が依存している fasttemplate でエラーが出ている
  • Issuesは出ている
  • 修正パッチのPull requestも出ている

対策

  • Pull request がマージされるのを待つ
  • 待てない場合は変更内容をローカルの fasttemplate のソースコードに適用する。手元では動いた。

Go 言語のアプリを heroku にデプロイするときは vender を .gitignore にいれるとだめ

  • ビルドエラーになる
  • godep 使わせている意味なくない?
  • デプロイ用のブランチ作って .gitignore から外すとかするのかな?
$ git push heroku master
Counting objects: 280, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (260/260), done.
Writing objects: 100% (280/280), 36.31 KiB | 0 bytes/s, done.
Total 280 (delta 123), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Go app detected
remote: -----> Checking Godeps/Godeps.json file.
remote: -----> Installing go1.6... done
remote: -----> Running: godep go install -tags heroku ./...
remote: my_go_file.go:5:2: cannot find package "any/dep/package" in any of:
... 略 ...
remote: godep: go exit status 1
remote:  !     Push rejected, failed to compile Go app.
remote:
remote:  !     Push failed
remote: Verifying deploy...
remote:
remote: !       Push rejected to myapp.
remote:
To https://git.heroku.com/myapp.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/myapp.git'

Rubyのリファクタリングでイケてないコードをなんとかするやつをやってみた

はじめに

リファクタリングできそうな点

  • initialize で start_date, end_date を渡しているのが不自然。
    • OrdersReport という汎用的なクラス名なので期間以外の条件で絞り込みたくなった時に応用が効かない
    • クラス名が OrdersDailyReport だったり、仕様として集計時には必ず期間が指定されると決まっていたりしたら気にしなくていいかも
  • total_sales_within_date_range で orders の絞り込みと集計を同時にやっている
    • ここも他の条件で絞り込みたくなった時に応用が効かないので絞り込み処理と集計処理を分けたい

リファクタリング結果

変更後

  • 呼び出し方は変わって OrdersReport.new(orders).select_within_date_range(start_date, end_date).total_amount となった
  • 行数が削減された
  • 複数の責務を持つ一つの大きなメソッドから単一の責務を持つ複数の小さなメソッドに分割された
  • 絞り込み処理と集計処理をメソッドチェーンで繋げるようにしたので、新しい絞り込み条件が入ってきても拡張しやすくなった
require 'ostruct'

class OrdersReport
  def initialize(orders)
    @orders = orders
  end

  def select_within_date_range(start_date, end_date)
    select { |o| start_date <= o.placed_at && o.placed_at <= end_date }
  end

  def select(&block)
    self.class.new(@orders.select(&block))
  end

  def total_amount
    @orders.map(&:amount).inject(:+)
  end
end

class Order < OpenStruct
end

変更前

require 'ostruct'

class OrdersReport
  def initialize(orders, start_date, end_date)
    @orders = orders
    @start_date = start_date
    @end_date = end_date
  end

  def total_sales_within_date_range
    orders_within_range = []
    @orders.each do |order|
      if order.placed_at >= @start_date && order.placed_at <= @end_date
        orders_within_range << order
      end
    end

    sum = 0
    orders_within_range.each do |order|
      sum += order.amount
    end
    sum
  end
end

class Order < OpenStruct
end

Go 言語でソリティアを作った

termbox-go を知ったので、息抜きに Go 言語でソリティアを作りました。
https://github.com/nirasan/go-solitaire

f:id:nirasan:20160610081329p:plain

仕事中にやりやすいように ls っぽいモードも搭載してあります。

f:id:nirasan:20160610081347p:plain

mac 用だけサンプルがあります。操作は README で。
https://github.com/nirasan/go-solitaire/blob/master/sample/solitaire?raw=true