もやぶろ

moyashidaisukeのブログだからもやぶろ。フリーランスのエンジニアのダイスケです。QOLあげて色々楽しくチャレンジして良く生きたい。プログラム関連とかギター関連とか旅行関連とか色々。

ありんこオフィスに行ってみた

シェアオフィス、コアワーキングスペースのありんこオフィスに先日行ってみました。

シェアオフィス【東京・渋谷】ありんこオフィス

 

土曜日のお昼すぎでしたが、賑わっていてほぼ満席でした。

 

良い所

  • ドロップインで一日ずっといても¥1000で利用できる
  • フリードリンクがそこそこ豊富
  • 食べ物持ち込みOK

微妙だったところ

  • 椅子と机が長時間作業するにはちょっとつらい→一部良い椅子があったので運がよければ大丈夫

 

Gitのお便利設定

Gitを使い始めたらやっておきたい便利な設定いろいろ : アシアルブログ

 bashのプロンプトにブランチ名を表示する際、上記エントリの情報だと古くてエラーになる。

-bash: __git_ps1: command not found

bash_completionで「-bash: __git_ps1: command not found」となった時の対処法 - くりにっき

こっちも参考にしつつ

git/contrib/completion/git-prompt.sh at master · git/git · GitHub も入れればOK

 

nokogiriとMechanizeでスクレイピングその1

趣味の関係でmixiをたまに使うのですが、(毎日見てないので)特定のコミュの書き込みがあったらメール飛んでくるようにしたいなと思いチャレンジ。

 

とりあえずログインして中の情報をなんとなくとってくるとこまで。

 

文字コードをちゃんと設定してないせいか、\nがたくさん出てる。

 

参考

スクレイピングのためのNokogiri利用メモ - それはそれ。これはこれ。

RubyのMechanizeを解説 for 1.0.0 - きたももんががきたん。

RubyのNokogiriでギコギコスクレイピングだ | メモ帳代わりのブログ

Macでの開発環境構築

参考にしたリンク集

 

Macbook Pro Retinaを買ってからやったことまとめ - kidomahの日記

Mac OS X Lion で Ruby on Rails の開発環境を1から構築 - Qiita [キータ]

Ruby - Mountain Lion環境への「rbenv」のインストール手順 + 設定方法 - Qiita [キータ]

Homebrew で Apache, PHP, MySQL, Composer をインストールして Yii Framework を動かすところまで - Qiita [キータ]

 

 技術関係はここじゃなくてQitaでいい気がしてきた。

エンジニアの給料

エンジニアに最も高給を支払っている企業は意外にも・・・? | THE NEW CLASSIC

うーん、高いですね。

どの企業も世界的企業なので、単純に日本の企業と比較はできないかもしれませんが、やっぱりすごく高いと感じちゃいますね。

 

日本の企業で高そうなイメージだとDeNAGreeでしょうか。

 

DeNA、GREE、サイバーエージェントの平均年収を比較してみた | CyberTimes [シバタイムス]

 

なぜ日本のエンジニアは地位が低いのか?その傾向と対策 - paiza開発日誌

仕事の報酬は仕事

こんな記事がTLに流れてきました。

スタバはなぜ値下げやテレビCMをしない?高いブランド力構築の戦略を元CEOに聞く
http://zasshi.news.yahoo.co.jp/article?a=20131012-00010000-bjournal-bus_all&1381526511


この記事の中で気になったのが、「仕事の報酬は仕事」という言葉。
調べてみたら、昔からある言葉みたいですね。(誰が最初か、というのはよくわかりませんでしたが)


良い言葉だとは思いますが、一歩間違うと社畜一直線にもなってしまうので、使い方には注意が必要だなーと感じました。

http://www.gexeed.co.jp/column/cl018.html
http://bizmakoto.jp/makoto/articles/1106/08/news012.html
http://www.esofken.com/rensai/1011.html

仕事の報酬でより良い仕事を得て、その循環の先に何があるのか。
だから、給料は大事じゃない(低くても良い)って論調になると、違うんじゃないかな、と思います。どっちが大事って事ではなく、どっちも大事。


私は仕事が好きですが、仕事以外にも好きな事がいっぱいあるので、それを実現するためにはお金と時間が必要です。


結局、多くの人にとって人生の大部分を占める仕事において、何を求めるか、という哲学的な話になってくるのでしょうか。。。

InnoDBとREPEATABLE READとSELECT FOR UPDATEと楽観ロックその2

前回の話に排他(行ロック)を絡めてみる。


Versionカラムを使った楽観ロックをしてみます。

■ストーリー
1.セッション1 トランザクション開始
2.セッション2 トランザクション開始
3.セッション1 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
4.セッション2 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback

楽観ロックなので、1行も更新できなかった場合はrollbackする想定です。

長いので1,2は省略しちゃいます。

READ COMMITTED

セッション1

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


通ってしまいます。

REPEATABLE READ

セッション1

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

mysql> select * from Version;
+----+---------------------+---------+
| id | text                | version |
+----+---------------------+---------+
|  1 | updatedFromSession1 |       2 |
+----+---------------------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


こちらも通ってしまいます。


ここでストーリーを少し変えて、

■ストーリー
1.セッション1 トランザクション開始、tempテーブルselect
2.セッション2 トランザクション開始、tempテーブルselect
3.セッション1 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback
4.セッション2 行情報取得→versionカラムを使って楽観ロックをした更新→commit or rollback

tempテーブルのselectを入れただけです。(for updateは無し)


READ COMMITTED

セッション1

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.01 sec)

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

mysql> select * from Version;
+----+---------------------+---------+
| id | text                | version |
+----+---------------------+---------+
|  1 | updatedFromSession1 |       2 |
+----+---------------------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

変更前と同じ。


REPEATABLE READ

セッション1

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)


なんと結果が変わります。
REPEATABLE READの場合、最初のselectのタイミングで取得するデータのスナップショットが決まるらしいです。
http://dev.mysql.com/doc/refman/5.1/ja/innodb-consistent-read.html

今回だと、2でtempをselectした時点でセッション2中でselectの結果として返ってくる値が全テーブルで確定するようです。

というわけで、1,2の処理にinsertやらが入っていても、REPEATABLE READなら排他がばっちり決まります。



またストーリーを少し変えてみます。

■ストーリー
1.セッション1 トランザクション開始、tempテーブルselect
2.セッション2 トランザクション開始、tempテーブルselect
3.セッション1 行情報取得(for update)
4.セッション2 行情報取得(for update)※トランザクション1のコミット待ち
5.セッション1 versionカラムを使って楽観ロックをした更新→commit or rollback
6.セッション2 versionカラムを使って楽観ロックをした更新→commit or rollback


楽観ロックがかかってるのに、for updateで悲観ロックをかけたとします。
で、コミットのタイミングを変えました。


READ COMMITTED

セッション1

mysql> select * from Version where id = 1 for update;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version where id = 1 for update;

ロック開放待ち。

セッション1

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

+----+---------------------+---------+
| id | text                | version |
+----+---------------------+---------+
|  1 | updatedFromSession1 |       2 |
+----+---------------------+---------+
1 row in set (8.33 sec)

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


REPEATABLE READ

セッション1

mysql> select * from Version where id = 1 for update;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version where id = 1 for update;

ロック開放待ち。

セッション1

mysql> update Version set text = 'updatedFromSession1' , version = version + 1 where id = 1 and version = 1; 
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

セッション2

+----+---------------------+---------+
| id | text                | version |
+----+---------------------+---------+
|  1 | updatedFromSession1 |       2 |
+----+---------------------+---------+
1 row in set (7.38 sec)

mysql> update Version set text = 'updatedFromSession2' where id = 1 and version = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

なんと、通ってしまいました。
REPEATABLE READでトランザクション開始後に1度selectしていても、select for update をかけると他トランザクションの影響を受けてしまうようです。

まとめ

REPEATABLE READの場合、READ COMMITTEDに比べて楽観ロックがシビアに効くこと場合がある。
ただし、select for updateで悲観ロックするとREAD COMMITTEDの場合と同じになる。

既存処理で、楽観ロックだけどシビアに排他が効いてる処理を、
何気なく悲観ロック追加すると挙動が変わる場合があるので注意する。


InnoDBのトランザクションは、ネクストキーロックとかもあって、
ハマるポイントが多いですね。。

InnoDBとREPEATABLE READとSELECT FOR UPDATEと楽観ロックその1

現場でちょっとはまった話。

InnoDBのトランザクション分離レベル

http://dev.mysql.com/doc/refman/5.1/ja/innodb-transaction-isolation.html

InnoDBはトランザクション分離レベルが選べますが、
デフォルトは「REPEATABLE READ」です。

Oracleは「READ COMMITTED」に近いとの事。(どこが違うんだろう。。)

じゃあこの2つどう違うかというと、

READ COMMITTED

セッション1

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション2

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション1

mysql> update Version set text = 'updated' , version = version + 1 where id = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション1

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

セッション1がコミットした段階で、セッション2にも更新が反映されました。


REPEATABLE READ

セッション1

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション2

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション1

mysql> update Version set text = 'updated' , version = version + 1 where id = 1; 
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

セッション1

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

セッション2

mysql> select * from Version;
+----+------+---------+
| id | text | version |
+----+------+---------+
|  1 | init |       1 |
+----+------+---------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from Version;
+----+---------+---------+
| id | text    | version |
+----+---------+---------+
|  1 | updated |       2 |
+----+---------+---------+
1 row in set (0.00 sec)

commitしないとセッション1の更新が反映されない!


という感じで、セッション1が更新した内容をセッション2に反映されるのはセッション2がコミットした後(ロールバックでもOK)になります。
自分はOracle脳になっていたので、最初意味がわかりませんでした。。。



長いので次回に続く。

第69回 PHP勉強会に参加してきた #phpstudy

初参加してきました。
http://atnd.org/events/40476

PHP歴半年ほど(そもそも仕事でばりばりプログラム書くようになって半年ですが。。。)の身でちょっと心配でしたが、アットホームな感じで楽しい会でした。

ビールの乾杯から始まるってのが良いですね。


今回は8周年記念という事でした。

他の言語ユーザーからはPHPェ。。。と言われがちなPHPですが、
集まってる方達はガチな感じですごかったです。

とりあえず、発表(LT以外)の感想だけでも。


Vagrant + Chef で作るこれからの開発環境 @yando

全然知りませんでしたが良さそうですね。ローカルと本番で違う環境(MySQLのバージョンとか。。。)で動かしちゃってるんで、実際に検討してみようかと。


php-gd2で画像を弄る話(仮) @yoyapp

gdのコアな話でした。
palletとtrue colorの話からして頂いたので、非常にわかりやすかったです。



また行こう。

select count(distinct user_id)的な

最近Railsをちょいちょいさわる機会があります。

よくある、

select count(distinct user_id) from hoge_users;

みたいなSQLですが、ActiveRecordだと

Hoge_users.count('user_id', :distinct => true)

でいける。簡単でいいですね。

参考
http://stackoverflow.com/questions/36608/how-can-i-count-the-number-of-records-that-have-a-unique-value-in-a-particular-f

複数行レコードを横持ちに変える

GROUP_CONCATが最高に便利。サブクエリとかいらない。


http://d.hatena.ne.jp/kkz_tech/20100803/1280802260
http://blog.asial.co.jp/209

転職してました

随分日が空いてしまいましたが、昨年の9月末から恵比寿でゲーム作ってる会社で働いています。もう4ヶ月位ですね。

所謂ソシャゲーを作っています。最初は若干抵抗もありましたが、作ってみるとなかなか楽しいです。ソシャゲーはすごい儲かるみたいなイメージがありましたが、それだけ苦労もしてるなーという印象です。


言語的にはPHPとjs(とHTML)なので、転職前にぼんやり考えてたのとは違いますが、アジャイルな感じでばりばり仕様考えて即コーディング!で仕事できていて、余計なストレスは少ないです。


仕事にも慣れてきてある程度コントロールできるようになってきたので、ブログ書いたり、勉強会参加したりしたいなと思っています。


とりあえず近況報告まで。

タイトル変えました

タイトル変えました。

変更前:moyashidaisukeの日記
変更後:moyashidaisukeの日記〜プログラマーになりたい〜


SIerから業界チェンジしたがってますが、自分のスキルの無さにへこんでいます。今までの4年半の活躍はなんだったんだ。。。

まあ分かっていた事ではありますが、いざ直面すると大変ですね。

というわけで一から勉強し直して、地に足を付けた実力を身に付けたいと思います。初心に帰ります。

このブログも入門系の記事(主に自分向け)が中心になるかと思います。がんばろー

Akasaka.scala 41 #akskscala

久々に参加しました。


Play20 モジュールを〜との事でしたが、Play20はちょろっとしかやってないので、自分はチュートリアルから。

ここを参考に、プロジェクトを作ってrunしたらいきなりエラー発生。。。

このエラーらしい。。。


原因はWindowsの環境変数でJDKにPATHを通す際、ダブルコーテーションでくくっていた事が原因。。。なんてこったい。


というわけで全然モジュールにたどり着かずに終わったのでした。とほほ。




エラーの詳細は別記事で書きます。

Scala勉強会第83回 in 秋葉原

初参戦。
いきなりですが、少ししゃべってきました。

http://www.slideshare.net/moyashidaisuke/20120718-scala

Slideshare初めて使いましたが、OpenOfficeのファイルだとフォントとか段落とか色々おかしいですね。
後、うまく埋め込みができないです。また仕様変更??


以下、メモ

  • Scala Schoolには@seratchさんの意訳があり、あわせて読むと便利
  • polymorphismにはランクという考え方が有り、Scalaは1までしかサポートしてない。Haskellだと2もサポート?
  • 2.10では「SIP-11 - String Interpolation and formatting」という機能が追加される。結構便利そう
    • @kmizuさんの記事見つけた
  • ジェネリクスの型情報はコンパイル時に消えるはずが、実は色んな方法で取得できるらしい。