個人開発の時間を確保するのは、仕事だらしない人にとって大変であるという話
まあ私のことなんですけどね_(:3」∠)_
今2つくらい個人開発しているプロダクトがあるんですが、 これがまぁ〜、進まない進まない。
いえね、理由は分かってるんですよ。
開発が習慣化していない
これだね。まさしくね。
そもそもなぜ進まないか
本業が比較的忙しい業種のため、帰宅がだいたい23時とかその辺になることが多く、あまり作業時間が取れないということが大きいです。 帰って飯食って風呂はいって…をこなしていくといつの間にか深夜1時。
こんな生活してると、土日を作業に当てようと考えるわけですね。
私こんな感じでも家庭がありまして、家族サービス(この言い方好きじゃないけど)というタスクが遠慮なく時間を奪っていきます。
昼間からデスクに向かっているのがあまり良く思われておらず。そんなことしてる暇あれば子ども遊びに連れていくことを優先せざるを得ない。
あと、親がデスクで作業してるの見ると寄ってきますからね、子ども。やつらのキーボード乱打を阻止するため、なかなか集中できぬ。
結果、今現在は平日の夜中に作業しております。
平日深夜作業の罠
仕事終わってきているので、結局消耗してるんですよね。疲れ果て、帰ってそのまま寝てしまうこともままあります。 次の日も仕事なので長く作業もできず。実質1時間くらいの作業。調べ物が多く、ほぼ進捗無いことが多いです。
進捗がないということは、いつ終わるか見えないことです。 つまり、モチベーションが維持しづらい。
作りたい物があっても、いつしか作業辛くなって、そのうち止まってしまうことになるわけですね。
本業の時間管理をしっかりするべし
そもそもの問題は帰宅が遅いことにあります。
中途半端だから、これやりきって帰る!が常態化しているのは大変イケてない。残業はよほど切羽詰まってないかぎりやるべきではないですしね。 その日やるタスクを決めて、それ終わらせたら帰ることを徹底すること。
早く帰れればその分割ける時間が増やせます。進捗が目に見えて判れば楽しい。
少しずつサイクル変えていって、開発を習慣化できる工夫をしましょう。楽しい個人開発ライフを充実させて行きたいものです( ・`ω・´)
AtomにGoの環境いれるメモ
参考にしたものはこれ。
基本記載されている内容どおりに導入していけばだいたい大丈夫です。ありがたや。
GOPATHは環境変数にぶっこんでやればOK。
最近のGolangではこれを見てgo getの参照先として動いてくれてるみたいですね。
微妙にはまったところ
リンク先に記載されている、godefパッケージの入手先、どうやら変更されている模様。
go get code.google.com/p/rog-go/exp/cmd/godef
現状、上記を実行すると、
package code.google.com/p/rog-go/exp/cmd/godef: unable to detect version control system for code.google.com/ path
とエラー吐かれました。
調べてみると、google codeからgithubへ移動している模様。 https://groups.google.com/forum/#!topic/golang-nuts/zJuzr1DfgP8
godefの入手はこうすればOK
go get github.com/rogpeppe/godef
stackoverflowでも同じような投稿ありました。 stackoverflow.com
Windows用バージョン管理ツール「Chocolatey」
もともとはWindowsを個人用PCにしていたのですが、Linux使う仕事をするようになった関係か、Macが非常に使いやすくそっちばかり使ってました(`・ω・´)
とはいえ、やはり自宅PCで作業したい感があり、Windowsでもまともに作業できるようにしたいなと。
Macだと、ベースがUnixなので、何も考えることなく、Homebrewを使えば動作する環境を楽に整えられます!便利!
しかしWindowsではVirtualBoxとかVmWareとか使って仮想化しないと、Linux的な環境を用意することはできません。
sygwin + spy-cygの組み合わせである程度はカバーできるのですが、あくまでUnixを再現しているのに過ぎないため、ちゃんと動かない言語やツールが稀にあります(´・ω・`)
となれば、一番楽に環境整えられるのは、docker + docker machineという選択肢になるわけですね。
Chocolatey
さて、ここから本題。
この記事書いてる時点でのWindowsにDocker導入する最新の方法は、chocolateyです。たぶん。
Windows版Homebrew + Homebrew-caskみたいなイケてるやつです。
インストール自体はかなり簡単。公式サイトに書かれているコマンドをPowerShellで実行するだけです。
が、おそらくそのまま実行すると、実行ポリシーによって、スクリプトの実行がブロックされます。
解消方法はここを参照
https://support.microsoft.com/ja-jp/kb/2411920
いったんExecutionPolicyをUnrestictedにして、インストール後Restrictedに戻す方法ですね。
それを踏まえて、以下をPowerShellで実行してください。
Set-ExecutionPolicy Unrestricted iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) Set-ExecutionPolicy Restricted
あとは適当にYesとかやってれば入ります。
インストールに成功したかどうかはchoco -v
ですね。バージョン番号出ればOK。
ちなみに、chocolateyの実体はただのexeなので、PowerShellでなくてもcmdやcygwinでも使えます。
dockerのインストール
choco install docker docker-machine
以上。
きっと環境移行にも便利につかえるはず
chocoがサポートしているパッケージはdocker以外にもいろいろあり、以下に対応しているやつが記載されています。
https://chocolatey.org/packages
Pythonとかその辺の環境以外にも、iTunesとかLinqpad、果てはVisual Studioといった、メジャーどころのアプリがあったりします。
もう環境構築これだけでいいんじゃないか(`・ω・´)
chocolateyインストールと、インストールアプリを管理したpsファイル作っておいて、新しい環境で実行するだけでOK。
ようやく、Windowsでもまともにパッケージ管理できるようになりましたね!
ただし、当然ながら日本語とか期待しちゃいけません。基本英語版になります。残念(´・ω・`)
日本語必要としている方は、普通にパッケージダウンロードしてきて入れましょう。
gulpでSlimのビルド環境作る2
以前、こんなことを書きました。
現在、改めてこのへんの整備をしているのですが、もっと簡単に導入する方法があったのでメモがてら書いておきます。
今年3月くらいに、こんなものが作られていたようです。
導入方法は上のリンク先見てもらえば全部書いてるので、特に特筆すべきことはないのですが、簡単な手順をば。
gem install slim
※結局これは必要npm install --save-dev gulp-slim
- gulpfileを作成
これでビルドできる( ・`ω・´)
ただ、これで吐き出したコードは圧縮されるので、改行やインデントが軒並み死にます。
インデント欲しい時は、gulp-slimの引数にこんなふうなやついれるといい感じになります。
gulp.src("./slim/*.slim") .pipe(slim({pretty: true})) //オプション追加 .pipe(gulp.dest('./html/'));
使えるオプション一覧は
https://www.npmjs.com/package/gulp-slim#options
を参照してください。
mysql(mariadb)のテーブルサイズとインデックスを一覧で見る
小ネタ過ぎてエントリに上げるのもアレですが、備忘録兼ねて( ・`ω・´)
テーブルサイズ一覧
SELECT table_name, table_rows AS "rows_count", ROUND(data_length/1024/1024,1) AS "table size(MB)", ROUND(index_length/1024/1024,1) AS "index size(MB)" FROM information_schema.tables ORDER BY data_length DESC
table_name | rows_count | table size(MB) | index size(MB) |
---|---|---|---|
articles | 327540 | 10.5 | 5.5 |
users | 2 | 0.0 | 0.0 |
schema_migrations | 2 | 0.0 | 0.0 |
dummy | 0 | 0.0 | 0.0 |
インデックスのサイズも見れる。まあそこそこ使う。
インデックス情報一覧
SELECT * FROM information_schema.statistics WHERE table_schema = "sandbox" ORDER BY table_name, index_name
TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | NON_UNIQUE | INDEX_SCHEMA | INDEX_NAME | SEQ_IN_INDEX | COLUMN_NAME | COLLATION | CARDINALITY | SUB_PART | PACKED | NULLABLE | INDEX_TYPE | COMMENT | INDEX_COMMENT |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
def | sandbox | articles | 1 | sandbox | ix_user_id | 1 | user_id | A | 2 | NULL | NULL | YES | BTREE | ||
def | sandbox | articles | 0 | sandbox | PRIMARY | 1 | id | A | 327540 | NULL | NULL | BTREE | |||
def | sandbox | dummy | 0 | sandbox | PRIMARY | 1 | id | A | 0 | NULL | NULL | BTREE | |||
def | sandbox | schema_migrations | 0 | sandbox | unique_schema_migrations | 1 | version | A | 2 | NULL | NULL | BTREE | |||
def | sandbox | users | 0 | sandbox | PRIMARY | 1 | id | A | 2 | NULL | NULL | BTREE |
このデータの見方はそのうち
mithril.jsとCORSの話
個人用のツールとして、最近話題になり始めてるmithril.js使ってるんですが、いいですよこれ。 react.jsと同じようにVirtualDomサポートしつつ、その上でAPIが16しかない(ここ重要)という素晴らしいJavascriptMVCフレームワークです。
react.js少し使っていて、JS側にテンプレート書けるJSXはそこそこ気に入っていたんですが、 素のブラウザで普通には動かせないんで大分辛みを感じてました。 このmithrilなら、素のブラウザで動作しつつ、react.jsのいいところも使えて大変便利です。 ちなみに、JSXのようなものを提供する拡張もあるようです。MSXだったかな?
さて、このmithril、こんな感じでAjaxRequestを発行することができます。
var users = m.request({method: "GET", url: "/user"}) .then(log) .then(function(users) { //add one more user to the response return users.concat({name: "Jane"}) })
まあ、これまんま公式から引っ張ってきたやつですが、いわゆるスタンダードなJqueryと比較して、callbackがchainで書けたりできるのでめちゃ使いやすいです。 素晴らしい。
そんなm.requestを使って起こった問題について書いてみます。 ここからが本題。
Access-Control-Allow-Origin
今回ターゲットにしているサービスは、完全に自分と関係ないやつなので、まあ、こいつと遭遇することになるわけです。
"No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access."
最近のブラウザでは標準搭載されているCross-Domainの制限ですね。
今回は自分の作ったJSと、サービスの公開ドメインが異なっているので、このアクセス制限を食らってしまうわけですねー。
詳しい話はこのへん https://developer.mozilla.org/ja/docs/HTTP_access_control http://qiita.com/zaru/items/6e57ab83a8e0e40f2115
当然、mithril限定の問題ではなく、他のライブラリ使っても発生する問題なので、対応方法も豊富に公開されていました。ありがたい限りです( ・`ω・´)
必要な対応としては3つ
- Jsonp使う
- サーバー側でAccess-Control-Allow-Originを返してあげるようにする
- プロキシ経由させて、プロキシ側でサービスにリクエスト送りつつ、Access-Control-Allow-Originをクライアントに返す
今回の接続先は、自分が管理していないサービスなので、1、2では対応できません。当然ですね(´・ω・`) となると必然的に3の選択を取ることになります。
なぜ3が有効かというと、Cross-Origin Resource Sharingは、あくまでクライアントから通信するときの制限であるため、 3で強制的にAccess-Control-Allow-Originをレスポンスとして返して上げることで、この問題を防ぐことができます。
ちなみにjqueryであれば、jquery.xdomainajax.js というものを使えば簡単に解決可能です。やってることも同じかんじ。
とはいえ、Yahooapiを経由してリクエストぶん投げる方法で、Yahooさんの意向一つで使えなくなる怖さはあるので、今回は自力で対応しています。
今回は、ツール開発で使ってるcoffeeScriptをugilifyしてsourcemapをはき出すためにgulpを使っており、node.jsとは切っても切れない関係になっているので、node.jsでプロキシ作成することにしました。
node.jsでの実装はこんな感じ
リクエスト発行するHTMLと、サーバーのドメインが異なると、それだけで弾かれてしまうので、HTMLやjsもnodeで配信するようにしました。
これで、クライアントとサーバーが同一ドメインであることが満たされるので、問題なく動作するようになります。
before_destroy時点でdestroyされてしまう、dependentの罠
まずはこれを見て欲しい
# == Schema Information # # Table name: users # # id :integer not null, primary key # name :string(255) # class User < ActiveRecord::Base has_many :articles, dependent: :destroy after_create do articles.import(%w"1 2 3 4 5".map{|text| Article.new(text:text)}) end before_destroy do p articles.map(&:text) end end
# == Schema Information # # Table name: articles # # id :integer not null, primary key # user_id :integer # text :string(255) # class Article < ActiveRecord::Base belongs_to :user end
よくある1対多の関連を持ったモデルがありますよ、と。
さらに、dependent指定で、userが消えた時、関連するArticlesを消すようにしています。
userの方では、生成時にarticlesに複数の初期データを同時に作成するようにしています。
after_createのところ見てもらえば分かる通り、1〜5の文字を適当に突っ込んで5レコード作っています。
ここまで前準備。
本題。。。。
さて、ここでarticlesを消す前に、他のテーブルに移すとか、ログにはき出すなりをやりたいとします。
当然dependent指定されているため、after_destroyではarticles拾えなくなるため、before_destroyで拾うとします。
user.rbみてもらうばわかる通り、before_destroyで標準出力に出してあげるようにしています。
User.create(id:13, name:1) => #<User id: 13, name: "test"> User.find(13).articles => [#<Article id: 26, user_id: 13, text: "1">, #<Article id: 27, user_id: 13, text: "2">, #<Article id: 28, user_id: 13, text: "3">, #<Article id: 29, user_id: 13, text: "4">, #<Article id: 30, user_id: 13, text: "5">] User.find(13).destroy >> []
ファッ!?
なぜか空配列が帰ってきてしまいます。 pry眺めてると先にarticlesのDeleteが走っていることがわかります。
ちなみに、こう書けば空配列にはなりません。
class User < ActiveRecord::Base before_destroy do # こちらの定義を先にした p articles.map(&:text) end has_many :articles, dependent: :destroy after_create do articles.import(%w"1 2 3 4 5".map{|text| Article.new(text:text)}) end end >> ["1", "2", "3", "4", "5"]
なぜこのような挙動をするのか。
深くまで潜っていけば、has_manyにdependent: :destroyが指定されている場合、
lib/active_record/associations/builder/association.rbで以下のように、before_destroy時に関連するモデルを削除する処理が埋め込まれます。
def self.define_callbacks(model, reflection) add_before_destroy_callbacks(model, reflection) if reflection.options[:dependent] Association.extensions.each do |extension| extension.build model, reflection end end
さて、ここで思い出してもらいたい。
modelに対するcallbackは複数回指定することができます。
さっきのuser.rbにこれ追加します。
before_destroy do p 1 end before_destroy do p 2 end >> [] 1 2
追加したbefore_destroyを逆にして再度実行すると…
[] 2 1
そうです、大体見えてみた。
先にbefore_destroyを定義した順番に実行されていくのです。
最初に記載していたコードを見てください。
has_manyの定義が先に書かれています。そのため、has_many内で追加されていたdependent: :destroyのbefore_destroyが先に実行されていたために、空配列になっていたのです(`・ω・´)
これで地味にハマりました。
でもrubyは上から順番に評価されていくので、原因が分かってさえすれば理屈はだいたいわかりますねー。
おわり。