See the Elephant

1992生まれのプログラマが書くエンジニアブログ

mac sierra, tmux で '~/.tmux/plugins/tpm/tpm' returned 127 (pluginがうまく動かない)

tmuxのpluginがうまく動かない

これを動かしたかった.

tech.quartetcom.co.jp

僕の.tmux.conf はこんなの

一部抜粋

# tmuxのセッションを保存する
# prefix C-s : セッション保存
# prefix C-r : セッション復元
# see : http://tech.quartetcom.co.jp/2016/01/15/tmux-continuum/
set -g @tpm_plugins 'tmux-plugins/tpm'
set -g @tpm_plugins 'tmux-plugins/tmux-resurrect'
set -g @tpm_plugins 'tmux-plugins/tmux-sensible'

# resurrect
set -g @resurrect-strategy-vim 'session'
set -g @resurrect-processes 'irb pry "~rails server" "~rails console" mysql ssh php'

# continuum
set -g @continuum-restore 'on'

# tmux内でopenコマンドが使えるようにする
# これをやらないとうまく動かない
# brew install reattach-to-user-namespace

set -g default-command "reattach-to-user-namespace -l ${SHELL}"

run-shell '~/.tmux/plugins/tpm/tpm'

<prefix>r でconfファイルをリロードすると以下のエラーが出る

'~/.tmux/plugins/tpm/tpm' returned 127

本家のissue を見るとどうやら ElCapitanあたりで行われたpermission変更の影響を受けているらしい.

I get error 127 when trying to install. · Issue #67 · tmux-plugins/tpm · GitHub

このコメントによると

I get error 127 when trying to install. · Issue #67 · tmux-plugins/tpm · GitHub

システムのプロテクション切ると使えるとのこと. これは辛いのでやめておこう.

入社2ヶ月の新卒Webプログラマが感じた既存コードとの向き合い方 ~うんこの上のうんこを作るべからず~

TL:DR

  • 既存コードはどんなコードでも尊さがある
  • 影響範囲と変更しづらさ
  • 無知な共通化は怖い
  • 現状のコードはBetterでありBestではない

弊社のシステム概要

僕が在籍している会社は2011年に設立しており, その頃に作られたシステムを現在も運用している.
そのため, 既存システムは5~6年間ほど実運用されてきた歴史がある.

ここ2週の僕の働き

ここ2週は, 1つの追加機能をしていた.
そして, リードエンジニアについてもらい3回設計をやり直した.
結果として僕が考えたコード(200行位)が, 最終的には1つの関数になった. その理由は, 既存コードの中に"追加機能に必要なロジックを持つ関数"が揃っていたからである.

そこで, 学んだこと, 感じたことを忘れないよう, 思い出せるようこのエントリに書いていく.

僕の失敗

僕は既存コードの把握が甘く, 自分自身で既存機能を再度開発していた.
加えて, 仕事の範囲とは異なる似た機能を持つ部分に手を出し同じロジックを見るように共通化をしていた.

既存コードとの向き合い方

僕が感じた既存コードが持つ特徴 f:id:namu_r21:20170619000640j:plain

既存コードはどんなコードでも尊さがある

既存のコードは"既に動いている"という点で実績を持っている.
それは"現時点で問題なく動作するもの"と評価を受けていることを意味している.

リファクタリングの際に注意すべきこと | プログラマが知るべき97のこと (以下きのこ本)を引用する.

既存のコードを出来る限り活かすべきです. 
いかに醜悪なコードであっても, そのコードはテストやレビューを通っているものなのです.  
既存のコードを-特に既にリリースされたシステムのコード-をすべて破棄するというのは  
それまでの数ヶ月(何年)という時間を捨ててしまうということを意味します.  
(中略)
仮にコードを新たにゼロから書き直したとすると(中略), 過去の作業で得た知識も無駄になってしまいます.  

自分が1文字でも変えてしまった時点でそのコードは"動作が未知"であるものに変わってしまう. 元のコードにテストコードがない場合は悲惨で, 本当に動作が担保されない"何か"を生み出すことになる.

自分の場合, 既存コードに存在しているロジックを再度自身の手で再開発していた.
既存コードの把握が甘かったという背景はあれど, 非常に無駄な時間を過ごした.

また, あまり良くないと感じた既存コードのロジックを変え, 自分なりの変更を加えていた.
これはまさに,きのこ本の個人の好みやエゴを入れてはいけませんに反していた.

この手の変更は, 動作を未知にしているだけで殆どの場合は悪影響しか及ぼさない.
できるだけ仕事と関係ないコードには手を入れない, ということが現時点の技術力では大切だと感じた.

影響範囲と変更しづらさ

変更箇所のコードがどの程度の影響範囲を持つのかを気にすることはとても大切である.

例えば…

関数のインタフェースが変わる => 関数を利用している全ての呼び出し元に修正が必要
引数の型が変わる =>  呼び出し元や関数内部の処理に修正が必要
関数内部の処理を変える => 意図しない挙動を生み出す  
変数名を変える => タイポや修正忘れによるバグが生まれる(controller -> viewへの変数渡しで起きがち)  
関数を消す => どこかで機能そのものを失う可能性がある

このように既に動いているものに対する変更は思いもよらぬ変更範囲を伴う.
変更範囲の大きいコードは, “変更しづらい"コードである.

特に"インタフェースの変更"や"関数の削除"はとても影響範囲が広い. 途端にバグを広めることになるため, 変更部分がどれだけの範囲で影響をおよぼすのか把握することは大切である.
これの対策として, リファクタリング前に対象関数のテストを書くことでプログラムの挙動を担保することができる.

外部委託でいらっしゃっている@t_wadaさんとペアプロさせていただいたときにおっしゃっていた言葉を引用する.
(思い出しながら書いているので表現は本人の意図とずれているかもしれません. あくまでも僕の解釈です)

自分が既存関数を変更するときは変更前に必ずテストを書く.  
そうすると関数の挙動が担保できる.  
そして, 変更前にどの程度この関数が"有名人"なのかを調べる.  
あまりにも多い場所で利用されているようであればできるだけ変更は加えたくない.  
あまり有名人でない, または全然無名なときは変えてしまってもいい.  
ただし動作は変わらないようにしたい.  

テストファーストでなくてもいいのでできるだけテストは書いた方がいいしリファクタリングの際はテストが必要ですという言葉は今後のプログラマ人生の中でずっと活かしていきたいと思う.

無知な共通化は怖い

上記したように, 今回の仕事で仕事の範囲とは異なる似た機能を持つ部分に手を出し同じロジックを見るように共通化を行っていた.

似たようなロジックの共通化は慎重に行うべきである, と指摘を受けた.
それは, 使用される場面や背景が異なるほど慎重にやらなければいけない.

例えば, controllerとbatch処理を行うコマンドで呼び出されるロジックを共通化したとしよう.

これを行うと, その時点で"たまたま似ている"コードかもしれないのに, 共通化することで依存を生むことになる. どちらかの背景や使われ方を反映させると, どちらかも引きづられるように変更が必要になる.

つまり, “変更しづらい & 変更に弱いコード"を生んでしまい後の運用に手間がかかるようになる. このため, 背景の異なる共通化は慎重に行わなければならない.

共有は慎重に | プログラマが知るべき97のこと

現状のコードはBetterでありBestではない

こちらに関しては, エンジニアの先輩方の言葉を借りる.

既存コードは, "作られた時点でとり得る時間, 状態, 事業内容における最適解"でしかない.  
それが"現状の最適解"とは限らない. だけど僕たちはそれを使って物を作っていかなければならない.  

例えば, 今あるコードがクソコードだったとして, うんこの上にうんこを乗せてもそれはうんこにしかならない.  
だから今の状況に合うように少しずつ変えていかなければならないし, 
同じようにクソを生み出してはいけない. 今あるコードが"理想的"であると思ってはいけないよ. 

あとは, 自分が書いたコードも書いた瞬間から陳腐化が始まることはしっていなきゃいけない.  
どのコードも'road of the うんこ' だって知りながら書くのも1つ意識を置かなければいけない, 

酒の席で聞いた話も混じっているのでご了承ください…mm

実際, 新卒の僕ですら驚いて声が出るようなコードがあったりする.
直そうとすると影響範囲が広く結構大変な上に, テストも無かったりする.

既存のシステムはきっとそういう"過去"を持つものだし, それをあるべき姿にしていくことも自分の仕事なんだろうと考えている.

まとめ

  • 既存コードはどんなコードでも尊さがある
  • 影響範囲と変更しづらさ
  • 無知な共通化は怖い
  • 現状のコードはBetterでありBestではない

といくつも書いてきたがきっとまた同じように間違えるのだろうな, と予感している.
ここ2週間でいかに設計が難しいか, いかに物を作らずに問題を解決するかが 容易でないかを知れた気がするし, まだまだ能力として身についていないと思う.

ではどのように自分は進んでいけばいいのだろうか.
ここについては先輩の言葉をお借りしてしめたい.

迷ったときは, 聞けばいい. できるだけ早く.  
だけど, ただ聞いただけでは自分のものにならない. 
できるだけ自分で考えてみる. 設計を自分で紙でもテストでも書いてみる.  
そして, 聞いた時の意見と自分の意見の差分を見てみる.  

それを繰り返していけば自分の中に落とし込んでいける. 

この2週間はまさにそれを経験させていただいた日々だったと思う.
忘れずに今週も頑張ろう.

t_wadaさんから講演を受けた "新卒に向けたエンジニアの生存戦略"

新卒に向けたエンジニアの生存戦略

TL;DR

プログラマとして生き続けていくということは学び続ける姿勢が必要
自分の学び方をカスタマイズして学び方をハックしていく

このエントリを書くに至った理由

弊社で@t_wadaさんが"新卒エンジニアに向けた生存戦略"と題して講演会を行っていただいた. (@t_wadaさんは弊社の技術アドバイザーとして出社している)
https://twitter.com/t_wada

t_wadaさんの遍歴

大学在学中から設定とプログラミングのアルバイトを始める
卒業後プログラマとしてキャリアを開始
電子政府住基ネットのサブプロジェクトでリードエンジニア
色々あって流しのペアプロ業をやる
プログラマが知るべき97のこと」, 「SQLアンチパターン」の監訳者

はじめに

プログラマが知るべき97のこと, 達人プログラマを背骨にして話していく

一番伝えたいこと : 学び続ける姿勢

  • 常にあなたの知識ポートフォリオに投資すること
  • 技術を学ぶのではなく、技術の学び方を学ぶ
  • 歳をとるとやることが多くなっていくので、技術を早く学ぶ技術が必要になってくる

1. 四半期ごとに技術書を読むこと

  • はじめのうちは簡単に思える
  • 読むべき本は最初のうちはいっぱいあるように感じる
    • 段々と同じような内容の本になり読む本を選ぶことが難しくなっていく
  • 最初の1,2冊はオススメされた本を読む
  • 次はその本が参考にした書籍を読む

学びの仕組み

  • 感覚記憶 0.5~2.0sec
  • 短期記憶 15~30sec
  • 長期記憶 死ぬまで? storeされているが到達できないのでないと同等になる

脳内インデックスを作る(長期記憶に紐づけるために)

  • なんども引き出すこと
  • 他のものとくっつける(連想記憶)

例えば読んだ本を時系列に並べて考えてみる

  • リファクタリング, TDD, migrationという変遷を経てrailsが登場した

    • リファクタリングの概念を元にTDDという思想が生まれた
    • DBの管理をmigrationというバージョン管理のような仕組みで行う考え方が生まれた
    • それらを実際に実装したWeb FWがRuby on Rails
  • 何らかの技術を説明する際に, その技術が元にしている書籍がある.

  • 時系列に並べる, 読むことで, 技術の流れや成り立ちが体系的に理解出来る
  • 時系列に並べる, 読むことで, 「この本が発刊された時点で今考えられている〇〇という思想, 技術は知る由がない」ということがわかる.
  • そうすると本が出版された時点では存在しない概念を差っ引いて考えることができる

2.手を動かしてやってみる

  • “やる-> できる -> 好きになる"のサイクルを生み出してく
  • 上達の鍵はとにかくまず始める

デールの円錐 http://www.hi-ho.ne.jp/tgoto/medic3/cone%20of%20learning.jpg

発話して手で実際にやる, と9割を記憶できる 写経 : 技術書に書いてあるサンプルコードを写して実行する

  • 写経はかなり深い本の読み方
  • 実際に試しながら読むことで身につく

3. 毎年少なくとも1つの言語を学習する

  • はじめは仕事に必要な技術,言語の勉強
  • オブジェクト志向言語のみを扱っているならば関数型を
  • 動的型付きのみを扱っているならば静的型付き言語を

というふうに慣れているパラダイムと異なるパラダイムを触って見る.
こうすることで自分のポートフォリオを広くしていくことが出来る

技術者と英語について

"英語ができるようになるというのは、「大きな図書館の鍵」を渡されるようなものです。1人ひとりの人生にいろんな可能性を与えてくれます” 高松珠子 kwsk : http://lite.blogos.com/article/85541/

プログラマとして生きていくためには少なくともあと数年は英語に触れると諦めること

4. 身の回りをプログラミング対象にする

  • 段々と勉強する, プログラミングの対象とするものが減っていく
  • 子供が生まれてからwebカムと携帯を使った遠隔カメラソフトを作っている

そこでプログラマらしく本を書いた(プログラマが知るべき97のこと)

  • 怠惰、傲慢、短気を美徳とする
  • プレーンテキストを好む
  • すべてをバージョン管理する
  • すべてを自動化する
  • 変化を抱擁する
  • 原稿はmarkdown形式
    • 当時はあまりやられていなかった
  • 原文はスクレイピングして取得
    • 書籍界はpdfから原文をコピーすることが多い
    • 制御文字や欠損が多いので不便
    • 原文がwebに公開されているため
  • git を使いバージョン管理
  • 編集者とのやり取りは全て自作サイト上で管理
  • herokuにpushしてサイトに反映
  • 監修差分はdocdiffで表示

結果として手戻りがとても減った

5. アウトプットを行う

量は質に転化する

ある有名な論文を紹介していた.

 * 陶芸クラスの評価を2つ用意.  
 * 質のみで評価する/量のみで評価するグループを作った
 * 結果, 量が多いグループから質が良いものが生み出されていた
 * アウトプットの量を行うことでフィードバックサイクルを早くする
 * 結果として量が質に転化する

量をこなしている人の方が, 一世一代で1つを生み出す人よりも良いものが出せる

アウトプットのチャネル

twitter, blog, 雑誌記事, 書籍, 講演, ライブコーディング, github

blogを書くことがプログラマとしての基本姿勢になる ストック型なので蓄積されていく

新人のよくある質問

Q: 先人が書いているのに僕が書く必要があるのか "情報発信、blog, 発表, 公開などは, 数学の未解決問題の証明ではなく料理のようなものである"

A: 5年前の著名なブログエントリよりも昨日書かれたブログエントリの方が信頼性が高い, と判断される場合もたかい(いつ動いたのかという状態のエントリも価値がある)

紙媒体 執筆する まずは雑誌から初めて見る

何らかの文章のアウトプット(ブログ, 講演)を見て編集者がアクセスしてくる そして, 執筆依頼が来る

雑誌と書籍は全然違う 雑誌は短距離走. 書籍はマラソンなのでモチベーション, タイムマネジメントが必要になって来る

現役プログラマでいるために

1. 生活習慣を変える

あの Jon Resig(jQuery作者)でもうまくいかないこと

週末に自分のプロダクト開発を頑張ろうとしたが失敗 平時と同じ馬力で書けない

  1. 毎日コードを書くこと
  2. 意味のあるコードを書くこと(リファクタリングもカウントしない)
  3. 深夜24時前に終わらせること
  4. 書いたコードをgithubで全てOSSにすること

起こった変化

  • 必要最小限のコードへの集中
  • 30分~1時間で意味のあるコードをかくことが強いられる
  • プログラミングの習慣化
  • githubに草を生やすのが目的ではない. 自分で自分のために生活習慣を帰る
  • 不安との戦い
  • 進んでいる感覚がプロダクトの進捗と同等に大切だと知った

  • 週末の過ごし方

  • 週末はそれほど重要でなくなりリアルライフを充実できるようになった バックグラウンド処理 散歩中やシャワー中に常にコードのことを考えるようになった

  • ワークライフバランス 仕事/生活/自分のプロジェクトのバランスの取り方がわかったのが最大の収穫だった

  • まわりからの理解 毎日コードを書くという習慣を公言したことでパートナーからの理解も得られるようになった

  • どれだけコードを書いたか この習慣を続けると書くコードやアウトプットは自分でも覚えられないくらい生まれる

t_wadaさんが上に追加して行っていること

住む場所を工夫する

  • 始発駅の近くにする
  • 通勤時間は累積で考えると膨大な時間になる

意図的にオフラインの環境を作る -> 捗る

2. 年下から学ぶ

一生プログラマーでいられるかどうかは言い換えれば年下から学べるか否か 年関係なく若い人たちと競える場にいく

できる->好きになる(好きすぎる世界から逃れられない)というサイクルは過剰適用とタコツボ化を生み出す. ベテランはやってきたこと/得意なことにとらわれてロックインされてしまうことがある

タコツボ化の対策として….

ベンチマークとアンラーニング

  • 定期的に自分のスキルを棚卸する
  • 積極的に外部に出て自分のスキルを相対化する
  • 使う道具を定期的に帰る
  • 道のコミュニティに参加する
  • 若者から学ぶ
  • 若者と同じ土俵で戦う

10年前に戦えていた道具が今も使えるとは言えない 意識的に使わないようにしていく

過去から未来を知る

技術は「振り子」と言われるが「螺旋」に似た構造.
同じようなパラダイムが繰り返されている.
10,15年の歴史を伴って同じようなパラダイムが改善されていっている

  • 同じように見えて実はメリットが増えている
  • 同じものとして「わしらもそれで失敗した」と言い始めると老害

ベテランはこの周期を知っている. これが 若手との絶対的な違い

ベテランは前の技術との差分を見ることで限界(未来)を見据えることができる

エンジニアとして価値を下げないために

T字型のスキルではなく複数の柱を作る

  • 他の人に負けないスキルを持つ(尖った技術)
    • これはキャリアの初期には大切なこと
  • 20年くらいやっていると地殻変動が起きる
    • そもそも無意味になってしまうことがある
    • 技術的な柱を持つにも, 枯れ具合が違ったものを持っておく

人の作る渦を見る

githubによってソフト開発は組織->個人へ 個が多く集まると何かが起こる - 大量のゴミを集めることで中から金が見つかることもある

ロードマップ志向からエコシステム志向へ

  • これまでは大きいベンダが技術の道筋を立てていた
  • appleがやってるのは明らかにロードマップ志向プラットフォーム(これは社員の呟き

今の技術の世界は「エコシステム」の時代 熱帯雨林のように食い合いつつ矯正し合う様々なタイプのプレイヤーが自分のためだけの個別の意思決定をしてその相互作用で技術が発展していく

エコシステムの中心部がレッドオーシャンで周辺ぶんんい生き残りが容易なブルーオーシャンがある

普通の人は,ロードマップでは真ん中, エコシステムの中では真ん中で避けるべき

まとめ

プログラマとして生き続けていくということは学び続ける姿勢が必要 自分の学び方をカスタマイズして学び方をハックしていく

誇りあるプロになってください

本当に恥ずかしくて言えないけど, 入社2ヶ月の新卒が今更データベースについて勉強したので新卒向けに書いてみた

お願い

勉強中なので間違えていることが書いてあるかもしれません.
気づいた方はコメントで指摘していただけると嬉しいです

TL;DR (too long, don’t read)

新卒向け. データベース, 特にトランザクション, ACID特性についてまとめた.

トランザクションはDBに対する一連の処理のまとまり.

ACID特性について適当にまとめると,こんなやーつ.

DBに対する
A: 中途半端な操作は許さないし,   
C: 正しい操作は通すし違法な操作は通さないし,  
I: 並列で行われている操作同士は一切関与しないし,  
D: どんな操作も必ず動作を保証する.   

入社と無知の知

入社して2ヶ月が経った.
ちょっとずつ生活も落ち着いてきたし, DBについて勉強したことをまとめたいと思う.
特にACID特性については, 図を入れて簡単に説明したい(したつもり).

学生時代にサークルでRailsでゆるふわWebサービスを作っていたので, Webプログラマ気取りをしていたら今とても痛い目にあっている. 修士卒とは思えないほど知識なさすぎてまじでやばい.
この記事が言っていることが身にしみる.
今すぐ辞めて欲しい、「Ruby on Rails勉強してます」「CakePHP勉強してます」

ActiveRecord & Rails consoleが強力しすぎてSQLを書いてこなかったので全然SQLがかけない.

痛い目を見ているので, ここ2,3週は自分の弱点であるDB, SQLあたりを勉強していた.

勉強に使っている本はこれ.

マンガでわかるデータベース

SQL 第2版 ゼロからはじめるデータベース操作 ミック

マンガでわかるデータベースはドチャクソわかりやすいので是非読んでみてほしい.
小難しい正規化あたりを妖精が教えてくれますლ(´ڡ`ლ)

ここ2週くらいで ゼロから始めるデータベース 第4章 トランザクションまで勉強した.

概念的なのでおそらく一番覚えにくいであろうACID特性についてまとめる.
トランザクションについて触れる必要があるのでそこも触れる.

基本的なSQLの操作(CRUD)についてはdotinstall MySQLを見て欲しい.
課金すると女性ボイスで聞けるので勉強に気が向かない人は課金オススメ.

ココらへんも分かりやすかった.

[SQL] データベース | TECHSCORE(テックスコア)

postd.cc

トランザクション

トランザクションとは, 1つ以上の更新処理をひとまとまりにまとめたものである.

つまり, insert, update, deleteのうちどれか1つを1回実行してもトランザクション, それぞれを複数回実行してもトランザクションと呼ぶ.

トランザクションとはあくまでも, データベースに対する1つ以上の更新処理の名称 である.

トランザクションの開始と終了

start transaction と commit

トランザクションを作るためには開始文と終了文を書く必要がある.

これは標準規格によって決まっているわけではないためRDBMSによって違う.

僕が使ってるmysqlではこう書く.

start transaction - - トランザクション開始

insertupdate …
処理 ….

commit; // 処理の確定(トランザクション終了)
  

このように, start transactionからcommitまでが一連の処理としてみなされる.

rollback

何らかの原因でトランザクションを途中でやめたい場合は, rollbackを行う.

これは, トランザクションを中断しトランザクション前のDBと同じ状態に戻ることを意味する.

start transaction -- トランザクション開始

insertupdate …
処理 ….

rollback; -- 処理の破棄(トランザクション終了)
  

トランザクションcommitが行われるまでDBに変更を加えないため, rollbackしたとしてもDBには何の影響も与えない.

トランザクションの開始と終了タイミング

これはRDBMSに拠って違うので注意が必要.

oracleに関しては, 自動でstart transactionを行うらしくcommitのみ明示的に書くようだ.

ACID特性

標準規格ではACID特性を守ることが取り決められている.
ACID特性はトランザクションを利用したDBが最低限担保すべき特性である.
つまり, どのRDBMSを使ってもこれだけは守られているルール である.

個人的な意見としてはこういう標準化されたものほど覚えるべきだと思ってるけど, 使わないからすぐ忘れるんだなぁ…

では一個ずつやっていこう.

A: Atomicity 原子性

f:id:namu_r21:20170529205133p:plain:w500

DBに対する操作はcommit(全て実行) か rollback(全て破棄)のどちらかが必ず適用されることを保証すること. つまり, トランザクション途中の中途半端な変更は適用されないことを指す. DBに対する変更はやるかやらないかどちらかだということ.

C : Consistency 一貫性

f:id:namu_r21:20170529205456p:plain:w500

データベースには予め制約を持たせることができる. この制約を違反するトランザクションは絶対にrollbackすることを保証すること. つまり, 制約がDBにデータを追加する際のフィルタ(validator)として動作する.

I : Isolation 独立性

f:id:namu_r21:20170529205143p:plain:w500

並列で処理されているトランザクションは, お互いの処理内容に干渉を受けないことを保証すること. commitされるまで別のトランザクションの内容は反映されず, また, 他のトランザクションからは見えない, 独立していることを保証すること.

D : Durability 永続性

f:id:namu_r21:20170529205147p:plain:w500

終了したトランザクションの動作は喩えDBが障害時であってもデータ変更の動作を担保すること. 最もポピュラーな方法は, トランザクションログをとっておき障害時のDBに対する操作を復元することで実現される.

まとめ

今回はACID特性についてまとめた. ここまで読むと, TL;DRに書いたことが分かっていただけたと思う.

  
トランザクションはDBに対する一連の処理のまとまり.    

ACID特性について適当にまとめると,こんなやーつ.  

DBに対する
A: 中途半端な操作は許さないし,   
C: 正しい操作は通すし違法な操作は通さないし,  
I: 並列で行われている操作同士は一切関与しないし,  
D: どんな操作も必ず動作を保証する.   

実際業務でもガッツリSQL触ることが多くなってきたので, 早く身につけないとなぁ…

curry化と部分適用の違いについて

今日は, rubycurryを勉強していた.

ruby 2.4.0の日本語リファレンスMethod#curryによるとこう書かれている.

self を元にカリー化した Proc を返します。カリー化した Proc はいくつかの引数をとります。十分な数の引数が与えられると、元の Proc に引数を渡して実行し、結果を返します。引数 の個数が足りないときは、部分適用したカリー化 Proc を返します

か, カリー化ってなんだ….?

wikiによるとカリー化とはこういう意味らしい.

カリー化 (currying, カリー化された=curried) とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(あるいはその関数のこと)である。

ふーん. なるほど.

ということは,

div  = lambda {|x, y| x.to_f/y.to_f}.curry # ラムダ式をカリー化
div1 = add.(1) # xを1に束縛, 
div1.(4) # yを4に束縛, このタイミングでprocが実行される

#=> 5

これで俺もカレー職人や!!!

と思っていたらこれはどうやら部分適用と呼ぶらしい.

カリー化と部分適用の違い

curry化と部分適用を混同してる人が多いと書かれたブログを見つけた. 部分適用をカリー化と呼ばないで - kmizuの日記

いまいちピンと来なかったので, 調べてみると こんな書き込みを見つけた(Shingo Omura @everpeace)

x,y,z -> V をx -> (y->(z->V)) に変換するのがカリー化。x,y,z-> Vのyに値を束縛して結果的にx,z->Vという関数になるのが部分適用。どこが同じなんだろうか。

なるほど. 階層化することが大切なんだね. でもいまいちピンと来ていない.

見落としていたけど, wikiの下の方にこんなことが書いてあった.


カリー化は部分適用と混同されやすい。

部分適用とは、

複数引数ある関数の引数の一部だけに実引数を適用する操作

のことで、div->invを導出する操作を指す。

一方、カリー化は

div->cdivを導出する操作であり、引数への値の適用までは行わない.

div = lambda {|x, y| x.to_f/y.to_f}
cdiv = lambda {|x| lambda{|y| div.(x,y)}}
inv = cdiv.(1)
p inv.(2) #=> 0.5

つまり, 値を入れた時点で「部分適用」になるんですね.

wikiによると, カリー化は以下のように表現されていた.

...Haskellでは関数は常に一つの引数のみを取り、複数の引数を取る関数とは、単にネストされた複数の一引数関数の糖衣構文(syntax suger)にすぎない

なるほど.

今読み返すと@everpeaceさんの表現がとてもわかり易い.

x,y,z -> V をx -> (y->(z->V)) に変換するのがカリー化。x,y,z-> Vのyに値を束縛して結果的にx,z->Vという関数になるのが部分適用。どこが同じなんだろうか。

調べてみて, 僕の中での「カリー化」の理解は, 以下のような感じでまとまった.

カリー化 = 複数の引数を取る関数を, 常に1つの引数を取る関数が多層化された関数に変換すること

gmailでラベル付きのメールを自動アーカイブする, の続き

1年前に書いた記事の続き. 基本的なやり方はこの記事に書いてある.

namu-r21.hatenablog.com

参照元はこちら -> うちのGMailはこうなっている(2014年完全版) - Qiita

最近, ラベル付きメールの自動アーカイブ機能がうまく動かずエラーを吐いていたので修正した.

これは本当に便利なのでオススメ.

// exclude multi-message conversations where I sent the last message?
var SINGLE_MESSAGE_ONLY = false;
// string for regular expression check
var EMAIL_REGEX = /[a-zA-Z0-9\._\-]+@[a-zA-Z0-9\.\-]+\.[a-z\.A-Z]+/g;
// look only in sent messages from last 7 days, otherwise script takes a while
var DAYS_TO_SEARCH = 7;
// set your email address.
var YOUR_EMAIL_ADDRESS = "your gmail address";

function getEmailAddress() {
  // return Session.getEffectiveUser().getEmail();
  return YOUR_EMAIL_ADDRESS;
}

function archiveReadMail() {
  var query = 'in:inbox is:read has:userlabels';
  var threadAll = 0;
  var offset = 0;
  var limit = 5;
  var mailAddress = getEmailAddress();
  var AddressList = {};
  var hasMore = true;
  while (hasMore) {
    var threads = GmailApp.search(query, offset, limit);
    Logger.log(threads.length);
    for (var i = 0; i < threads.length; i++) {
      var thread = threads[i];
      thread.moveToArchive() 
    }
    hasMore = false;
  } 
}