夏休みを使ってGo言語での開発を行いたい

8月は丸々休みという嬉しい自体になった。 この機会にいままで自分自身できちんとした開発をしたことがないという負い目を払拭する為、Go言語での開発を行いたい。

作るものはなんでもいいが、暫定でパスワード管理システムとする。 思いつきなので変えるかもしれないが、別にそれはよしとする。 学習を行うこと自体が目的なのだ。

CI環境を作ってアジャイル開発を行っていきたい。 スモールスタートしてちょっとずつ大きくしていきたい。

テストコードを書きたい

今まで勉強でC++とかPythonとかちょっとだけGoを書いたことはあるが、ユニットテストコードを書いたことがなかった。 プログラムを書いたらすぐに結合試験に取り掛かっていた。

規模の小さいソースコードだったので問題がなかったのだろうが、規模の大きいプロジェクトだったりアジャイル開発だときっと困るのだろう。 実際に困った自体になる前に、ユニットテストコードを書けるようになりたい。

Chefでの環境構築もやりたい

AWSでのEC2インスタンスを開発環境として利用するつもりなので、節約のために開発中以外はインスタンスを削除しておきたい。 そして、開発を再開するタイミングでインスタンス再生成&前回開発終了時点の環境まで再構築を自動で行いたい。 構成管理ツールだとAnsibleなら使用経験あってある程度分かるんだけど、AWSという土壌に合わせてChef(OpsWorks)を使うべきかな、と思ってる。

CI環境を使いたい

アジャイルな感じで同じコードに対して何度もバージョンアップしていく感じのことをやりたい。 それならば自動ビルドとか自動テストとか自動デプロイやるべきですよねやっぱり! ただ、CIサービスって世の中には数多あるんですよね。

CI環境といえば有名なのはJenkins CI環境で私が構築・使用実績があるのはGitlab CI 経験として今後の役に立ちそうなのは前者。導入コストを抑えられるのは後者。

でも前者はGo言語の開発に使えるのかよく知らないし、後者はGitlabって結構CPU使うのでAWS上で利用しようとするとインスタンス代金が怖い・・・

ということでGo開発向きのCIサービスを調べてみたらTravis CIってのがよさそうなのでこれを使ってみようかな?

 
以上。8月中にちゃんとやりたいなあ

emacsでpython開発環境を作る(ほぼ自分用メモ)

melpaとmarmaladeをパッケージリストに追加

$ emacs ~/.emacs.d/init.el

(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/") t)
(package-initialize)

インストールするパッケージ

M-x package-listから探してインストール

  • python-mode
  • py-autopep8
  • flymake-cursor
  • flymake-python-pyflakes

個別にコマンドでインストール
$ sudo pip install pyflakes jedi epc autopep8

~/.emacs.d/init.el に設定を追記していく

$ emacs ~/.emacs.d/init.el

(require 'py-autopep8)
(setq py-autopep8-options '("--max-line-length=200"))
(setq flycheck-flake8-maximum-line-length 200)
(py-autopep8-enable-on-save)

(flymake-mode t)
;;errorやwarningを表示する
(require 'flymake-python-pyflakes)
(flymake-python-pyflakes-load)

emacsのススメ

emacs楽しい!

前に勉強したいリストにemacsをちょこちょこ触ってるんですが、触るたびに楽しくなってきています。
勉強したいリスト - 意識高く生きたいブログ

普通にテキストエディタとして使うのは当然として、PythonやGo言語を書く際のIDE代わりにも使ってますし、最近はコマンドもemacsから実行するようになってきました。
もはやサーバにログインしたらログアウトするまでemacs開きっぱなし状態

個人的によく使うコマンドはこんな感じ

注:一般的な設定,キーボードの場合、C = ctrlキー, M = ESCキー を表す

コマンド 意味
C-x C-s 保存
C-x C-c emacsを閉じる(全windowを閉じる)
C-x 2 windowを横に分割
C-x 3 windowを縦に分割
C-x 0 選択中のwindowを閉じる
C-x o 次のwindowを選択する
C-x C-b バッファ一覧を表示(選択したバッファを開くことも可能)
C-x k バッファを閉じる
C-a 行頭に移動
C-e 行末に移動
M-< 最初の行に移動
M-> 最後の行に移動
M-g 数値 指定した行に移動
C-k 行末までカット
C-space 範囲選択開始
M-w 選択している範囲をコピー
C-y 貼り付け
C-/ undo
C-s 文字列 文字列を検索
C-x d (バッファごとの)カレントディレクトリを移動
C-x C-f 別のファイルを開く
M-x package-list-packages インストール可能なパッケージ一覧表示
M-! コマンド コマンド実行
M-! コマンド & 非同期でコマンド実行。また、対話式コマンドにも対応可能

後は自分で設定しているキーバインドとして

C-x ←キー|左のwindowに移動
C-x →キー|右のwindowに移動
C-x ↑キー|上のwindowに移動
C-x ↓キー|下のwindowに移動

参考に、↑の設定をする為に~/.emacs.d/init.elに書いている内容はこんな感じ

(global-set-key (kbd "C-x <left>")  'windmove-left)
(global-set-key (kbd "C-x <right>") 'windmove-right)
(global-set-key (kbd "C-x <up>")    'windmove-up)
(global-set-key (kbd "C-x <down>")  'windmove-down)

注:emacswikiによるとC-xよりもC-cでバインドする方がおすすめのようですが、私はwindow扱うコマンドはC-xで統一しちゃってます。
  EmacsWiki: Wind Move

で、使用イメージとしてこんな感じのterminal状態になります。 f:id:hosibui:20170331233315p:plain 画面4分割して複数ファイルを同時に開いて編集しながらコマンド実行して、そのコマンド実行結果も他のwindowに出す。みたいな。
コマンド実行結果をwindowに出力する利点としては、emacsを閉じなくてもコマンド実行結果が確認できることと、キー操作だけで実行結果をコピーしたりできるので楽なところです。

また、バッファを切り替えてやれば限られた数のwindowでもどんどん画面を切り替えて使うことができます。
下の画像の4分割されたwindowのうちの左下がC-x C-bでバッファ一覧を開いた画面で、任意のバッファを選択してやることで、このwindowでそのバッファを開くことができます。 f:id:hosibui:20170331233634p:plain

pythonとかgo用の開発環境化してる部分にも触れようかと思ったけど記事書くのに飽きてきたのでここらへんで終わり!

golang(go言語) / python2 / python3 におけるスライス

go言語の勉強をしている際にpython2とpython3ともスライスの挙動が違うことを知ったので備忘録として。

python2

個人的に一番慣れていて挙動としてもしっくりくるpython2から紹介します。

figs=range(10)  # figs==[0,1,2,3,4,5,6,7,8,9]
myslice=figs[1:5]  # myslice==[1,2,3,4]
myslice[0]=99
print(figs)
print(myslice)

実行結果

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[99, 2, 3, 4]

1行目にて、0~9の数値が順番に並んだlistを変数figとして作成。
2行目にて、figsの1~4番目の要素によるlistを変数mysliceとして保存。
3行目にて、mysliceの0番目に99を代入すると、
実行結果にて、mysliceは書き換わるが、figsの値は1行目の時点から変わっていないことが分かります。

golang

package main
import "fmt"
func main() {
    figs:=[10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    myslice:=figs[1:5]
    myslice[0]=99
    fmt.Println(figs)
    fmt.Println(myslice)
}

実行結果

[0 99 2 3 4 5 6 7 8 9]
[99 2 3 4]

一方、golangでも若干文法の書き方は違いますが同じ処理内容のコードに見えますが、実行結果を見るとfigsの1番目要素が99に変わっています。

このpython2との実行結果の違いはpython2とgolangでのスライスの処理の違いによるものです。

python2の場合はスライスを使うと元のlistの一部をコピーするので、myslice変数は新しい変数として作られていました。

一方、goの場合はスライスはデータを持たず、元のlistの一部へのポインタを作成します。なので、myslice変数は実はfigs[1:5]へのポインタを覚えているだけなのです。
つまり、ポインタを作ってmysliceとしてポインタの場所を覚えているだけなので、myslice[0]=99figs[1]=99と同じ意味になる為、figsの1番目要素が変わっていたのです。

試しにmyslice[0]=99figs[1]=99に書き換えても結果は変わりません。 figsの1番目要素は99になりますし、mysliceの0番目要素も99になります。

python3

最後にpython3です。

まずはpython2と同じコードを実行してみましょう。

figs=range(10)  # figs==[0,1,2,3,4,5,6,7,8,9]
myslice=figs[1:5]  # myslice==[1,2,3,4]
myslice[0]=99
print(figs)
print(myslice)

実行結果

Traceback (most recent call last):
  File "Main.py", line 3, in 
    myslice[0]=99
TypeError: 'range' object does not support item assignment

エラーになってしまいました。 これはpython2とpython3のrange関数の処理の違いによるものです。

python2ではrange関数を使用すると戻り値はlist型で戻ってきますが、 python3ではrange関数を使用すると戻り値はrange型で戻ってきます。

range型をスライスでコピーした新たな変数mysliceもやはりrange型なので、0番目要素だけ書き換える、ということはできないのです。

対処策は色々考えられますが、簡単なところだとスライス結果をlist型に変換してしまえばいいかなと思います。 なお、スライスの処理についてはpython2と同じく元の変数のコピーを作っているのでmysliceを書き換えてもfigsには影響が出ません。

以下がその例です。

figs=range(10)
print(type(figs))
print(type(figs[1:5]))
myslice=list(figs[1:5])
print(type(myslice))
myslice[0]=99
print(figs)
print(myslice)

実行結果




range(0, 10)
[99, 2, 3, 4]

おわり

yahoo hack day 2017に出場しました。

2/4,5の2日間でHack day 2017に出場してきました。

hackday.jp

私は2人チームで出場し、oYUHARIというスマホアプリから遠隔操作で自宅のお風呂にお湯を張れるというIoTなシステムを開発しました。

チーム内の分担としては
私がプログラム面での製造を行い、もう一人のお仲間がデモ用の装置を接着剤とかハンダとかカッターとか駆使して作成しました。
つまりはソフト担当とハード担当といったところでしょうか。

システムの動作概要としては以下のような感じ

  1. まず前準備
    • 風呂の蛇口に本システムで動作する電磁弁を取り付けておく。
    • 蛇口を開けておく。電磁弁が閉まっている状態なのでお湯は漏れない
  2. スマホアプリで湯張り完了時間とお湯の量を設定し、お湯張りボタンをタップする
    • rasberry piにお湯張りを要望するhttpリクエストが飛ぶ
  3. rasberry pi内部で湯張り開始時刻と湯張りにかかる時間を計算
  4. 湯張り開始時刻になるとrasberry piのGPIOからリレーモジュールに対して電圧をかけ始める。
    • raspberry piがかけられる電圧は3.5Vであり、電磁弁を動かす為に必要な12Vに足りない為、リレーモジュールとバッテリーを使用する。
  5. リレーモジュールがバッテリーから電流(12V)を取得し、電磁弁に横流しする。
  6. 電磁弁が開き、お湯が風呂桶に入り始める
  7. 湯張りにかかる時間が経過するとrasberry piのGPIOから流れていた電圧(3.5V)が止まる
  8. リレーモジュールがバッテリーから電流(12V)を取得しなくなる

シーケンス図にすると以下のような感じ。

Created with Raphaël 2.1.2スマホアプリスマホアプリraspberry piraspberry piリレーモジュールリレーモジュールバッテリーバッテリー電磁弁電磁弁webサーバ起動webサーバはpythondjangoで構築post(湯張り完了時刻,湯量)200 OK湯張りにかかる時間を計算湯張り開始時刻を計算湯張り開始時刻までスリープ電圧 START湯張りにかかる時間スリープ電圧START電圧START開く湯張り開始電圧 STOP電圧STOP電圧STOP閉じる湯張り終了

結果としては入賞できずに終わってしまいましたが、他のチームの発表を見ることで様々な技術・発想に触れることができとてもよい刺激になりました。 また別のハッカソンにも参加しようかな

勉強したいリスト

  • emacs(テキストエディタ)を試す
    • 試した。中々面白い。気が向いたら記事書きます
  • pandas(pythonのデータ操作ライブラリ)
  • Jupyter Notebook (何がうれしいもの??)
  • データサイエンティストのスキルとは?
  • Grumpy(Pythonで書かれたコードをGo言語に変換・実行できるGoランタイム)

Amazon Machine Learning その② Amazon Machine Learningに触れてみる

早速ですがAWSにログインしてAmazon Machine Learningサービスを開いてみましょう。

と、ここで早速注意点が・・・。
2016年12月4日現在、東京リージョンではAmazon Machine Learningサービスが提供されていません。
なので、EU (アイルランド)か米国東部 (バージニア北部)リージョンを利用しましょう。

f:id:hosibui:20161204232625j:plain

ちなみに、東京リージョンでサービス提供されていないということは、日本語の公式チュートリアルも存在しません。
頑張って英語版読みましょう・・・

Tutorial: Using Amazon ML to Predict Responses to a Marketing Offer - Amazon Machine Learning

さて、気を取り直してリージョンをEU (アイルランド)か米国東部 (バージニア北部)に変更して画面を進めます。

f:id:hosibui:20161204234144j:plain

まずはInput Dataの設定

まずはInput dataとして、学習を行う為のデータを読み込ませます。
データの読み込ませ方には二種類の方法があり、

  • S3上に保存されているcsvファイルを指定
  • RDSかRedshift(共にデータベースサービス)上に保存してあるデータを指定

のどちらかの方法でデータを指定します。

今回は手元にある株情報のcsvファイルをs3にアップロードして使います。
本題じゃないので銘柄はなんでもいいのですが、例として9432のNTT株を使います。
なお、csvファイルは株価データサイト k-db.comさんからダウンロードさせて頂きました。

csvファイルはこんな内容ね。
2015/11/16~2016/12/2の約一年分のデータ。

f:id:hosibui:20161205002157j:plain

verifyボタンを押して先に進めようと思ったらこんな画面が。
Amazon Machine LearningがS3にアクセスしてもいいですか?ってメッセージなのでYESを選択

f:id:hosibui:20161205002709j:plain

と、エラーメッセージが出ました。
UTF-8にしろってメッセージでした。日本語が入ってるからかな?
日本語で改めてファイルをアップロードして再試行

"The validation is successful. To go to the next step, choose Continue " ってメッセージが出たら成功みたいです。

continueを押して次の画面に進むと、各スキーマの設定
それぞれのスキーマの種類が自動で選択されているので、問題がないかをチェックしてcontinueをクリック。
日付はできればTextじゃなくてdate型を指定したいんですが、選択肢にないものは仕方ない。

f:id:hosibui:20161205005445j:plain

次が似たような画面でTargetの設定。
予測させたいスキーマを選択する・・・ってことだと思います。たぶん
高値と安値を予測したいんですが、ひとつしか選択できなさそうなのでひとまず高値で。

f:id:hosibui:20161205005805j:plain

次がID項目の設定。
・・・ID項目って何だ?
説明読んだ感じ、レコードを特定するためのユニークな情報を選択すりゃいいのかな?
今回は日付を選択。

f:id:hosibui:20161205011219j:plain

最後にreviewで設定内容を見直して、問題なければcontinue

f:id:hosibui:20161205011055j:plain

これでInput Dataの設定は完了。
まだ全設定完了までの道のりは遠いですが今回はここまでです。

f:id:hosibui:20161205011744j:plain