歩いたら休め

なんでこんな模様をしているのですか?

【Python】他サイトの改修頻度をチェックするためにHTMLをYAML(っぽい何か)に変換するためのコマンドラインツールを書きました

上司から「サイトがマメに更新されてると、Google検索エンジンからの評価が上がるらしいんだけどさぁ、 他サイトの更新頻度をチェックしたり簡単に比較する方法ない?」というふんわりした話題がありました。

単純に考えると、サイトのHTMLを定期的にスクレイピングしてdiffを取ればいけそうですが、 商品の入れ替え等で細かい文言が変わってしまうことは容易に考えられます。

そこで、HTML(DOM)の構造のみを取り出して、比較的人が見やすいデータ構造であるyamlに変換することにしました。 調べてみると、既にRubyで似たようなコードを実装した方がいたようです。

uasi.hatenablog.com

これをそのまま使わせて頂いてもよかったのですが、一度Pythonコマンドラインツールを作ってみたかったのと、 USER-AGENTくらいは指定したかったので再実装しました。

うわ!_stdout_yamlの中がザ・糞実装みたいな感じですね!

クラスメソッドさんの記事にあったClickというライブラリが簡単そうだったのでそちらを利用しました。 デコレータをちゃんと使ったのは初めてかもしれません…。

dev.classmethod.jp

# クックパッドのトップページをテキストに書き出す
./honenuki.py --url='http://cookpad.com/' > output

結果はこんな感じです。一応yamlとして読み込めるようにはしたつもりですが、diff取るためだけに出力しているので努力はしてません。

- :name: 'html'
- :children:
  - :name: 'head'
  - :children:
    - :name: 'meta'
      :attributes:
        :charset: 'utf-8'
    - :name: 'meta'
      :attributes:
        :content: 'IE=edge'
        :http-equiv: 'X-UA-Compatible'
    - :name: 'script'
    - :name: 'link'
      :attributes:
        :media: 'handheld'
        :rel:
          - alternate
        :type: 'text/html'
        :href: 'http://m.cookpad.com/'
    - :name: 'link'

あとはgit管理して簡単にdiffを見れるようにすればいいだけですが、実際にうまくいくかどうかはやってみないとわからないですね…。

【Ruby】PythonプログラマーがRubyを触って感じたこと

Pythonプログラマーというか、元々Python(ときどきR、C言語)で数値シミュレーションをしていた学生が、就職してRubyでWeb開発を行うにあたって勉強したことを書き連ねていくだけの記事です。

もし自分と同じような立場の人(これから後輩としてもどんどん増えていくかも!)がいたら、「ここを押さえておけばRubyは問題なく書けるよ」と教えられるように書いておきます。というのも、レビューを行っていた先輩とのプログラミングのスキルとの開きがあり、先輩も私も「どこが分かってないのか説明できない」状態になってしまってお互いに困ってしまった経験があるからです。

RubyPythonはよく似ているのですが、思想や見た目で違う部分が多く、片方を勉強するともう片方の理解も深まります。 たまに2ちゃんねるのオカルト板である「見たことある世界によく似た異世界に迷い込んだ」みたいな感覚で、なかなか面白い経験でした。

Rubyのよかった点

まず、Rubyを使ってみて、「これってイケてるな」「勉強になったな」と思ったことを書いていきます。

1. オブジェクト指向が(Pythonよりも)徹底している

Rubyのプログラミングは、だいたい「オブジェクトからメソッド(+ブロック)を呼び出して、その戻り値を利用する」ということで表現できます。(if文などの制御構文など、若干の例外もありますが)

nums = [1, 2, 3]

# 全ての配列の要素に1を足す
nums.map {|n| n + 1}

# 合計を取る(畳み込み)
nums.inject {|x, y| x + y}
nums.inject(:+) # 省略した記法
nums.sum # Ruby2.4から利用できるようになるそうです

対してPythonでは、高階関数やリスト内包表記、合計にはsum関数など、リスト(Rubyの配列に対応するもの)を操作するにしても、色々なことをしているように見えます。

from functools import reduce
nums = [1, 2, 3]

# 全ての配列の要素に1を足す
list(map(lambda n: n + 1, nums)) # map関数を利用した例
[n + 1 for n in nums] # リスト内包表記を使った例

# 合計を取る
sum(nums)
reduce(lambda x, y: x + y, nums) # Rubyと同じく畳み込みを使った例

実はPythonも内部的には__iter__メソッドや__next__メソッドを呼び出しているそうなのですが、 表面上は関数として定義されているように見せているだけです。

これはほぼ書き方の違いだけなのですが、Rubyのほうが「主語がはっきりしていて、何を操作の対象にしているか分かりやすい」という利点があるように思います。 ただし、ブロックをeachから使い始める人が多い分、ラムダ式高階関数を理解しないままmapinjectを使っている人も多いように感じています。

一方、Pythonで数値の合計値にsumという関数を使えばいいというのは、数式の表現に近く、きちんとプログラミングを学んでいない情報系以外の分野の学生には使いやすいように思います。

(完全に余談ですが、Rubyでも2.4からsumメソッドが使えるようになるらしいです。数学のバックグラウンドがある人が、「合計値出すのにinject(:+)ってなんだよ…」って愚痴っていたのを聞いたことあるので個人的には大歓迎です。)

クラスとイテレータ - Dive Into Python 3 日本語版

RubyのMix-inも便利でした。Pythonで同様の機能を実現するには、多重継承を気をつけて使うか、abcというモジュールを使うかするといいらしいです…がPythonであまり大きなコードを書く機会が無かったので、これから身につけたいです。

www.atmarkit.co.jp

2. 破壊的変更が理解しやすい

前項のように、Pythonを利用している間、「オブジェクトの内側からメソッドを呼び出す」という感覚はあまりなく、 「オブジェクトの外側から関数を適用する」という感覚でプログラミングを行っていました。 そのため、「破壊的変更」「ミュータブル/イミュータブル」という概念がいまいちピンと来ていませんでした。

例えば、リスト(配列)をソートする場合、Pythonでは破壊/非破壊で関数とメソッドを使い分ける必要があります。

ソート HOW TO — Python 3.5.2 ドキュメント

nums = [1, 3, 2, 5]

# 非破壊的変更はsorted関数
ret = sorted(nums)
print(ret)
# => [1, 2, 3, 5] # 戻り値はソートされる
print(nums)
# => [1, 3, 2, 5] # もとのオブジェクトは変更されない

# 破壊的変更はlist型のsortメソッド
ret = nums.sort()
print(ret)
# => None # 戻り値はNone
print(nums)
# => [1, 2, 3, 5] # 破壊的変更が加わっている

一方、Rubyでは配列をソートしたければ、非破壊/破壊的メソッドのsort, sort!メソッドを使い分ければいいだけです。 また、「オブジェクトからメソッドを呼び出す」ことが徹底している分、 破壊的操作も「要するにインスタンスの内部の変数を書き換えているだけでしょ」と理解できました。

ref.xaio.jp

完全に余談ですが、PHPを書いていた(書かされていた)頃は、sort系の関数がいくつも用意されていたり、そのだいたいが破壊的操作だったり、全く理解できませんでした。

3. nilとfalse以外は全てtrue

勉強になったというか、プログラミング言語として分かりやすいのが「nilfalse以外は全てtrue扱いされる」というルールです。

www.rubylife.jp

例えば、正規表現にマッチするかどうかを調べるには、String型のmatchメソッドの戻り値をifに渡すだけです。 matchメソッドはtrue, falseを返すわけではなく、正規表現にマッチしたときはMatchDataオブジェクトを返し、マッチしなかったときはnilを返します

url = 'www.google.com'
if url.match(/google.com/)
  puts 'Google!'
end
# => Google!

Booleanを返すような特別なメソッドを用意することなく、nilを返すメソッドを使うことで、簡潔で分かりやすいコードを書くことができます。

Pythonでは、FalseNoneの他に、空文字や0なども偽として扱われます。

www.pythonweb.jp

Pythonのほうがルールが複雑でイケてないじゃん」と思われるかもしれませんが、 プログラマが持つべき心構え (The Zen of Python)の記事に書かれていた 最大公約数を求めるプログラムを見るとハッとするかもしれません。 (これも、y <= 0みたいに明示的に書いても良い気もしますが)

def gcd(x, y):
    while y:
        x, y = y, x % y
    return x

4. 便利なメソッドや書き方が多い

多様性は善」を一つのスローガン(?)に掲げているだけあり、 Rubyには様々な便利な機能やメソッドが用意されています。 特に、Pythonに無い機能で便利だと思ったのが以下の4つです。

  1. nilガード(||=)
  2. each_with_object
  3. 後置ifによる早期リターン
  4. メソッド名に!や?が使えること

nilガード(||=)

初心者プログラマーRubyに触るとまずググるのに困るアレ(||=)です。 変数が存在しない場合やハッシュのキーが無い場合(nilの場合)に変数を初期化することができます。

Sinatraで、あるGoogleのサービスのAPIを叩く社内用API(Google APIを叩く & DBにログを残す)を作る際、 「id(hogehoge_id)が引数で渡ってこない場合があるため、名前でidを検索する必要がある」ことがありました。

このような場合にnilガードが便利です。

# dataはAPIに渡す情報が入ったハッシュ
data['hogehoge_id'] ||= _search_hogehoge_id(data['hogehoge_name'])
_exec_api(data)

ちなみに、||=の「nilガード」という呼び名はメタプログラミングRubyの記述に倣ったものです。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

呼び名については、Rubyistの中でも意見が分かれているようです。レビューするとき不便ですね。

www.softantenna.com

each_with_object

私が最初にRubyを使っていて最初に感じたのが、「内包表記やジェネレーターの代わりになるもの無いの?」ということです。

もちろんmapselect等のメソッドもあるのですが、戻り値が配列に限られていますし、 簡単なフィルターもできないため、Pythonの〇〇内包表記に比べて使い心地が悪く感じます。

そんなPythonプログラマーの需要を満たすのがeach_with_objectメソッドです。

例えばURLの配列(リスト)を、{URL => ページタイトル}というハッシュテーブル(辞書)に変換したいとします。 同時に、ページのURLにgoogleが含まれているものを除外したいとします。

Pythonであれば、辞書内包表記を使って以下のように書くでしょう。

# get_titleはページタイトルを取得する関数
def create_url_table(urls)
  return {url: get_title(url) for url in urls if 'google' not in url}

Rubyでは同様のメソッドを次のように書けます。

# Rubyでは明示的にreturnを書かなくて良い
# ループした結果をハッシュ(デフォルト値では{})のキーに代入していく
def create_url_table(urls)
  urls.each_with_object({}) do |url, hash|
    hash[url] = get_title(url) unless url.match(/google/)
  end
end

宗教上の理由で破壊的操作を受け入れられない人以外は、便利に使えるメソッドだと思います。

qiita.com

ここからはeach_with_objectとは関係ない話です。

RubyPythonのような遅延評価が行いたいなら、Enumerableモジュールのlazyメソッドを呼び出せば、mapselectに遅延評価を適用することができます。

Rubyist Magazine - 無限リストを map 可能にする Enumerable#lazy

Pythonのジェネレーターみたいなことがしたいなら、Enumerator::Lazy.newからブロックを呼び出せばできなくはないようです。 …なんだかRubyっぽくないですが。

data = [[1], [2, '2'], ['a', 3, 'b'], [4], ['c']]
generator = Enumerator::Lazy.new(data) do |yielder, item|
  item.each do |x|
    yielder << x if x.is_a?(Integer)
  end
end

puts generator
# => #<Enumerator::Lazy:0x0055634bb03200>
puts generator.first
# => 1
puts generator.force
# => [1, 2, 3, 4]

一度取り出された値(1)がもう一度出てきているので、Pythonのジェネレーターとは少し挙動が違うみたいです。

後置ifによる早期リターン

後置ifも、早期リターンしやすいので便利です。

例えば、Twitterで自動リツイートするbotを作るため、ツイートの配列を渡すとリツイートするメソッドを作りたいとします。 そのとき、引数の配列にnilが含まれる可能性がある場合、その場合はreturnして逃してあげると、 eachメソッドを呼び出す際に変数がnilの場合のエラーを気にせずに済みます。

def post_retweets(tweets)
  return if tweets.nil?
  tweets.each do |t|
    # リツイートする処理
    _post_retweet(t[:tweet_id])
  end
end

mugenup-tech.hatenadiary.com

後置ifが素晴らしいのは、else句が無いことを明示的に示していることです(と個人的には思っています)。

例えばPythonで同様の処理を書くと以下のようになりますが、elseの場合の処理は必要ないの?それとも書き忘れているの?」と不安に感じると思います。 かといって明示的にelse句を書いてネストさせるのもちょっと…と感じてしまいます。

def post_retweets(tweets):
  if tweets is None:
    return
  for t in tweets:
    # リツイートする処理
    _post_retweet(t['tweet_id'])

メソッド名に!や?が使えること

?は真偽値を返すメソッドに、!は破壊的な(または注意すべき)メソッドに付けることが多いです。

Rubyで使われる記号の意味(正規表現の複雑な記号は除く) (Ruby 2.3.0)

ただし、!は破壊的メソッドだけに限らず、例えばハッシュのmergeメソッドupdateメソッドも破壊的であることに注意しましょう。

Rubyの微妙な点

Pythonに比べてプログラミングの自由度が大きい分、微妙だと感じるものも多いです。

ただし、これはプログラミング言語どうこうというより、言語ユーザーの文化的な違いの面が大きいのかもしれません。

1. Rubyオブジェクト指向にこだわりすぎている

Rubyでは、「そんなのいちいちクラス分けなくていいじゃん」と思うようなことでも、Rubyではクラスを分けたりします。例えば、標準ライブラリのnet/http等がそうです。Web APIを叩くときによく使います。

Rubyist Magazine - 標準添付ライブラリ紹介 【第 7 回】 net/http

Class: Net::HTTP (Ruby 2.3.1)

例えば、チャットワークのAPIを利用して、POSTでメッセージを投稿するようなものを想像しましょう。

curl -X POST -H "X-ChatWorkToken: xxxxx" -d "body=チャットワークに投稿" "https://api.chatwork.com/v1/rooms/*****/messages"

上の例を、Rubynet/httpを使ったコードに直すとこんな感じになります。(ただし、curl-to-rubyというサイトで作ったため、もっと簡単な書き方があるかもしれません)

require 'net/http'
require 'uri'

uri = URI.parse("https://api.chatwork.com/v1/rooms/*****/messages")
request = Net::HTTP::Post.new(uri)
request["X-Chatworktoken"] = "xxxxx"
request.set_form_data(
  "body" => "チャットワークに投稿",
)

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

URI専用の型を作って、それをもとにNet::HTTP::Postインスタンスを作って、パラメータをつけ加えて実行するような形です。

同じ操作をPythonrequestsライブラリで行うと、必要なパラメータを辞書(ハッシュテーブル)で引数に与える形で実現しています。標準ではないものの、net/httpと似た用途でよく使われます。(標準のurllibopen-uriに対応するようなシンプルな用途で使われます。)

import requests

headers = {'X-ChatWorkToken': 'xxxxx'}
params = {'body': 'チャットワークに投稿'}
requets.post('https://api.chatwork.com/v1/rooms/*****/messages', headers=headers, params=params)

私はPythonの書き方のほうがシンプルで分かりやすいと思っています。

同じように、色々なgem(ライブラリ)を使う際に、引数や戻り値がいちいち専用の型のインスタンスで操作することが多く、「これって文字列型でいいじゃん…」と感じることが度々あります。

こちらの記事の後に、

qiita.com

同じリファクタリングPythonで行った記事を見ると、Ruby/Pythonでの文化の違いが分かると思います。

qiita.com

2. 変な記号がいっぱいある

Rubyに慣れていない間、既存のコードを読み解く際、変な記号がいっぱいあって困りました。例えばclass << selfという記述があり、ようやくググると特異クラスという単語が現れ(特異クラスってなんだ?)…みたいな感じに、ちょっとした記述が分からずにハマることが案外多かったです。

Rubyist Magazine - Ruby 初級者のための class << self の話 (または特異クラスとメタクラス)

これを友人のRubyプログラマーに愚痴ったら「Perlにはもっと意味不明な記号があるよ」と言われました。ひとまず下のページをブックマークしておくといいでしょう。

Rubyで使われる記号の意味(正規表現の複雑な記号は除く) (Ruby 2.3.0)

また、文字列型('string')とシンボル型(:symbol)が別々に存在することも、おそらく、ハッシュのキーや言語自体の機能を操作するために、イミュータブルな(破壊的変更ができない)文字列型のようなものが必要だったんじゃないかと思います。 ただし、別に文字列型だけでも対応できたんじゃないかなと思います。

togetter.com

ちなみにPythonでは通常の文字列型が破壊的変更不可能なので、Rubyのシンボル型のような役割も兼ねています。代わりに、ハッシュテーブルのキーにミュータブルなオブジェクトが使えないようになっており、イミュータブルな配列型(タプル型)が用意されている点がちょっと不自然かもしれません。

www.yoheim.net

3. ブロック(ラムダ式)が強力すぎる

Rubyのブロック(メソッドからラムダ式を呼び出す機能)が強力すぎる分、気をつけないとすぐにごちゃごちゃしたコードになる印象があります。

Pythonではラムダ式の表現力を意図的に落としていて、「これ以上複雑にするなら関数分けてね」と制限しているのですが、 Rubyでは「プログラマーよ、望むままを行え」ということを戒律にしているようです。ベルセルクの使徒みたいです。

Rubyist Magazine - Rubyist のための他言語探訪 【第 1 回】 Python

こちらの記事に書かれていますが、

しかし、この文法では、ブロックを含む構文は値を持つ式として用いることができませんから、Rubyで頻繁に使われるブロック付きメソッド呼び出しのようなことはできません。 Python には名前のない関数を作る lambda という文法がありますが、関数本体部分には式ひとつしかかけないという大きな制限があるため、条件分岐ひとつ使うことができません。 そのような場合、Python では名前を付けた関数を定義し、その関数を引数として使うのが一般的のようです。 Ruby では

ary.map {|x| x**2}

となるものが、Python では

map(lambda x: x**2, ary)

となり、lambda の本体が1つの式では表現しきれなくなると

def mapper(x): .....

map(mapper, ary)

と書き換える必要があります。ブロックによるうれしさとのトレードオフの関係と言っても良いかもしれません。

Pythonでは「リストの要素一つを操作する小さい関数を作る」 → 「その関数をmapやリスト内包表記でリスト全体に適用する」という順序で考えていたので、 Rubymapのブロックの中にごちゃごちゃ書くのに違和感があります。

先輩から「if文の無いeach文はmapに書き換えられるよ!」と説明を受けたことがあるのですが、 私はmapは配列を数学の写像として操作する関数やメソッドで、 eachとは違うニュアンスで捉えていた(実行する順序が関係ないとか)のでちょっとビックリしました。

ただし、強力なメソッドを適切に使うことで、意図の伝わりやすいコードになるとも思うので、注意すれば問題ないかなと思っています。

まとめ & おすすめの書籍

意外と長くなってしまいました。

プログラミング初心者の後輩が入ってきたとして、↑のような説明してもあんまり伝わらない(少なくともPython知ってないと分からない)し、 私自身まだ糞みたいなプログラマーなので、どこかに認識違い等があると思います。

Ruby勉強したい人は次の2冊をおすすめします。めっちゃ無難な取り合わせです。

初めてのRuby

初めてのRuby

Effective Ruby

Effective Ruby

逆に、RubyプログラマーPythonを勉強したいなら、以下の3点を押さえておけば、ちゃんとしたプログラムが書けると思います。

  1. リスト内包表記
  2. ジェネレーター(遅延評価)
  3. ふつうに定義した関数がオブジェクトであること

その他の困る点は、先人が素晴らしい記事を書いてくださっているのでそちらを参考にしましょう。

qiita.com

「2と3のどちらのバージョンを身につければいいの?」という人もいると思いますが、 3系で困る(例えば使いたいライブラリが2系のみ)ことは全くといいほど無くなりました。 3系を勉強しましょう。

入門 Python 3

入門 Python 3

【本】『ウェブマーケティングという茶番』『やりなおし!地理の教科書』など読みました

技術書っぽくないやつですが、昨日2冊読みました。

ウェブマーケティングという茶番

タイトルに惹かれて買いました。リスティング広告SEOなどの広告代理店の話です。

胡散臭いと思われているこの業界を変えるため、同業者を敵に回す覚悟で、業界の実態を暴き、本当の魅力を伝えようと本書の執筆を決意!

弊社代表、後藤晴伸が執筆した本経営者新書 「ウェブマーケティングという茶番」幻冬舎より出版されました。 │後藤ブランド株式会社 真のWEBマーケティングをプロデュース | 後藤ブランド

  • GDN(Google Display Network)等を利用する際は、きちんとターゲティングしなきゃ無駄に広告費かかるから代理店にも圧をかけなきゃダメ
    • 例えばスマホアプリに出す広告は間違ってクリックするユーザーも多いので除外すべき
    • 同業他社が狙っておらず、自分たちの顧客セグメントに合ったブルーオーシャンのセグメントを狙うべき
  • 制作やSEO、広告まで総合的に運用できる担当者はかなり貴重
    • ダメな会社や担当者の見極め方
  • 「ここは大きな会社と取引があるから大丈夫」 → 中小の優先度が低く後回しにされる

みたいな具体的で、どこかで聞いたような話も多く、 多少なりともウェブマーケティングに関わった人なら、学ぶところがあると思います。 代理店側の都合や事情を知るのに役に立つかもしれません。

(最後にちゃっかり自分の会社の宣伝も行っています!)

ウェブマーケティングという茶番 (経営者新書)

ウェブマーケティングという茶番 (経営者新書)

やりなおし!地理の教科書

「え〜!○○県出身なの!?〇〇県は××が特産なんだよね!」みたいな話や、不動産関連のデータを各地域ごとに分析した、みたいな話に全くついていけないので読みました。

古代から現代まで、いろいろな時代に関わる話が載っていました。「古代にナントカっていう令が出されて漢字二文字の地名が多いんだよ!その際に沖→隠岐など二文字地名が増えたらしい」などなど。

個人的に印象に残った話題をメモしておきます。

  • 本来は同名の市町村名はNGだが、法律の施工のタイミングや、合併を推し進めるための緩和策(既存の市町村がOK出せばOK)のために重複している地名がある
    • エンジニア的には勘弁してほしいです。制約のないデータベースみたい…
  • 今はドーナツ化現象は緩和し、通勤が楽な都心に回帰して来ている
  • 全市町村の46%以上が限界集落、そのうち1/3程度が65歳以上しか住人のいない超限界集落
  • 中核市特例市の要件は備えているのに、住人の経済的な負担増を嫌って申請しない地域もある

なんというか、今の市区町村といった区分って、「きちんとデータにもとづいて整理されたもの」というより、「それぞれの地域やそこの住人が、自分の利やメンツに則って行動した結果が今の地域」と考えたほうがいいなあと思いました。その分歴史を勉強するのは楽しそうですが。

会社に残っているようなデータもこんな感じですよね。

やりなおし! 地理の教科書

やりなおし! 地理の教科書

【本】仕様化やレビューについて勉強しています

最近、2つ理由からレビューの仕方や、仕様化のプロセスについて勉強しています。

  1. 自分自身がプログラムを書いている間、ドメイン知識が足りず、手が止まっている時間や周囲に確認することが多い。
  2. (半ば非公式に)分析用のRプログラムのコードをレビューするようになったが、「どうすればお互い勉強できるレビューができるか」に困っている。

1つ目について話すと、私はWEBマーケッター向けの社内ツールを作成しているのですが、 マーケッター側の企画者のまとめた「仕様」を理解できておらず、 「全データを使うめちゃめちゃ時間がかかるので、ここのチェック変えても大丈夫ですか? あ、変えちゃダメなんですね。…じゃあなんとか別の方法を考えてみます」 みたいな細かい手戻りも多いように感じています。

2つ目は、分析者(いわゆるデータサイエンティストと呼ばれるような立場)の人のコードをレビューするようになったということ。 分析者は、コードを書くことが専門ではないため、定期分析用のコードが必要以上に煩雑で扱いづらいものになってしまっていました。 そのため、先輩からの引き継ぎやモデルの改良に異様に時間がかかってしまっていました(と傍から感じていました)。

開発ではレビューが行われていたものの、 分析サイドでは「自分のやった分析を、一生自分で面倒見なければならない」みたいな風潮になってしまっていて、 分析者の立場では「優秀な人ががんばればがんばるほど自由に動けなくなる」という闇のスパイラルに入る傾向にあったように思います。

また、「レビュー=品質の悪いコードを外に出さないためのチェック」という役割が強くなってしまっているように感じていて、 「この機能を実現するのにAPIとして機能を切り出す場合と切り出さない場合の2つ選択肢があるんだけど、 どっちが総合的に楽なんだっけ?」と悩むような場合に、 相談とかレビューというか、そういう役割のものが欲しいと思っていたこともあります。

チームでコードを書き始めた後、「どうやらレビューってやつをした方が良いらしい」くらいの若手に向けた資料です。 · GitHub

というわけで、こちらの記事で紹介されている本2冊を読んでみています。どちらの本も、上のような悩みにフィットするものだったので、 もうちょっとうまく開発フローを回せるようになったら文章でまとめてみようと思います。

[改訂第2版] [入門+実践]要求を仕様化する技術・表現する技術 -仕様が書けていますか?

[改訂第2版] [入門+実践]要求を仕様化する技術・表現する技術 -仕様が書けていますか?

ピアレビュー

ピアレビュー

【MySQL】DBに入れた検索クエリテーブルから、キーワードの順序に関係なく抽出する

MySQLのデータベースに検索クエリが保存されており、その中から検索クエリを取得したいとします。

具体的には「検索連動広告にガンガン新規キーワードの組み合わせを登録したい」「葉隠れ構造を崩したくないから、同じキーワードの組み合わせを別のキャンペーンに登録したくないからチェックしたい」という要件がありました。

日本語で説明すると、「指定のキーワードをどちらも含んでおり、スペースの数が1つ(キーワードが2つ)のものを抽出する」という処理を走らせています。

こちらのクエリで、「アニメ 配信」または「配信 アニメ」のクエリ(keyword_text)を抽出することができます。

SELECT
  keyword_text,
  LENGTH(keyword_text) - LENGTH(REPLACE(keyword_text, ' ', '')) AS spaces
FROM
  keyword_master_table
HAVING
  keyword_text REGEXP '(^| )(\\+?)アニメ($| )' AND
  keyword_text REGEXP '(^| )(\\+?)配信($| )' AND
  spaces = 1;

正規表現のでAND条件を指定することもできますが、MySQL正規表現が先読みの機能に対応していないらしく、利用できませんでした。(正規表現の先読み・後読みの機能が良く分かってないので勉強しなきゃ…)

qiita.com

(\\+?)として+の文字がが先頭に付いている場合も含めているのは、絞り込み部分一致の場合、対象の文字列の先頭に+がつくからです。

また、WHEREではなくHAVINGを使っているのは、本来はもう少しクエリの組み合わせをORで絞り込んでおり、そのたびにLENGTH(keyword_text) - LENGTH(REPLACE(keyword_text, ' ', ''))と書くのが面倒だったためです。

MySQLであれば、カラムの型を文字列でなくSET(集合)型で入れておけば、自然で、もう少し高速なクエリになっていた気がします。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.4.5 SET 型

ちなみにGoogleBigQueryでは、SPLITという関数が用意されており、文字列を分割して列に展開するようなこともできます。その際のキーはJOINする際のキーには使えませんが、FLATTENでカラムを指定することで結合キーとして使えるようになるはずです。

SELECT
  master.keyword_text AS keyword_text,
  master.one_keyword
FROM
  (
    FLATTEN(
      (
        SELECT
          keyword_text,
          SPLIT(keyword_text, ' ') AS one_keyword
        FROM
          [project.keyword_master_table]
      ),
      one_keyword
    ) AS master
INNER JOIN
  (
    SELECT
      one_keyword
    FROM
      [project.new_keywords] -- 新しく登録したいキーワードテーブル
  ) new_keyword
ON
  master.one_keyword = new_keyword.one_keyword

ここから、NULLを含まないkeyword_textを抽出すればイケるはずですが、眠くなってきたし、手元にBigQueryが無くて確認できないので寝ます…。また、もっとエレガントな解法があるような気もしています。

【シェルスクリプト】git管理下のファイルの行末のスペースを消す

あまりに「末尾に空白がある」ってレビューで返されてしまうので、今のディレクトリ配下の行末のスペースを消すようにした。 vimでファイル閉じるときにできるのかもしれんけどまあいいや。

git ls-files | xargs sed -i -e 's/ *$//'

【本】『人』も『プログラム』も両方動かさなくっちゃあならないってのがエンジニアのつらいところだな

最近いろいろ読みました。

人を動かす

有名なやつですね。SOFT SKILLSで薦められていたのと、同期の優秀なマーケッター(仕事の進め方がうまい)がコレ系の本が好きなので読みました。

「相手に重要感をもたせることが大事」「相手の自尊心を傷つけると、反発させてしまうから逆効果」という考え方と、その具体的なTips集みたいな感じです。特にSOFT SKILLSでも触れられている「議論で勝っても相手の感情的な反発は残るから、出来る限り避けろ」というノウハウは目からウロコです。

同期の優秀なマーケッターも、(上司に唆されたこともあって)最近RやSQLを覚え始め、プログラマーやエンジニアの立場を尊重してくれているように見せてくれます。彼のおかげもあり、逆に自分もマーケティングやツールの話を理解しなきゃと思っているため、いいフィードバックを生み出してるように思います。

人を動かす 文庫版

人を動かす 文庫版

はじめてでも集客&売上アップ! Google AdWords完全攻略

Google Adwords関連の仕事があったのですが、「結局Adwordsってどこまでできんねん」というところが分からなかったので、本屋で良さそうな本を買って読みました。

はじめてでも集客&売上アップ! Google AdWords完全攻略

はじめてでも集客&売上アップ! Google AdWords完全攻略

間違いだらけのソフトウェア・アーキテクチャ

読み物として面白かったです。「アーキテクチャ」という抽象的な言葉の定義について、

そうそう,抽象化されたヤツで最近僕のお気に入りの定義は,「人間の個性を無視して奴隷化する権力」ってヤツだ。 これは,ローレンツレッシグが『CODE』で論じたことに端を発したニューアカデミズムの人達が言っていることだ。 権力って言うのは実にうまくアーキテクチャの一面を表現していると思うよ。

と述べていた点が印象に残っています。あとはコンピュータとか、オブジェクト指向アーキテクチャの関わりの歴史とか。

自分の普段の仕事でも、先輩の作ったアーキテクチャの上で行っているため、目の前にあるコードをプログラミングするだけじゃなく、全体の設計を理解する能力も必要だなと思っています。

間違いだらけのソフトウェア・アーキテクチャ―非機能要件の開発と評価 (Software Design plus)

間違いだらけのソフトウェア・アーキテクチャ―非機能要件の開発と評価 (Software Design plus)

プログラマのためのサバイバルマニュアル

これ系(SOFT SKILLSとか達人プログラマーとか)の本は内容かぶってることが多いので、そろそろ読まなくてもいいかなと思ってます。

Macが壊れたり、電源が壊れていて本しか読めなかったのですが、今度は家でもプロダクト作ったり、普段使っているツール(embulkとかかな?)のコード読んだりするようにします。

プログラマのためのサバイバルマニュアル

プログラマのためのサバイバルマニュアル

サーバ/インフラを支える技術

研修で全然うまくいかず無能だったので泣きながら読んでいます。

kiito.hatenablog.com

[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)

[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)

なぜ財務を知っている社員は出世するのか

営業出身の方のちょっとしたセミナーで「損益分岐点が〜」とか出てきて「わかんねえよ…」って思ったので読みました。 会社で出世したいというか、せめてもう少しちやほやされたいとも思っています。

主に営業の目線で書かれている本で、「黒字の会社でも在庫が増え、負債になってあぼーんすることがある」とか「そのため早く現金化できるものがありがたがられる」とか、ところどころ印象に残っているワードが残っています。

ただ、後半のキャッシュフローとかのアレはさらっと読んでしまいました…。

なぜ財務を知っている社員は出世するのか

なぜ財務を知っている社員は出世するのか

A/Bテストの教科書

社内で統計の勉強会をやることになったのですが、ニーズがバラバラで(「ツールを使いこなせるようになりたい」という人もいれば、「今自部署でやってる分析って意味あるの?」と悩んでいる人もいる)何をすればいいのか困っています。

「RやPythonで分析するスキルはそこそこあるけど、分析の設計の話とかって全然分かんないよね」って悩んでいたときに、WEBディレクターの方がTwitterで薦めてたので買いました。

結局言ってることはシンプルで、「仮説を持ってサイトの製作をして、検証して、(失敗したとしても)ノウハウ残して学んでいくことが大事だよね」「効果が大きくて、仮説検証しやすいところから手をつけようね」「そのために必要な組織やツールってこういうものだね」って言ってる感じでした。

シンプルなことをちゃんとできれば、ちゃんと効果出せると思うんですが、それが難しいんですよね…。

A/Bテストの教科書

A/Bテストの教科書

日本を動かす「100の行動」

社長さんが薦めてたのでパラパラ読んでみましたが、私はあまりおもしろく感じませんでした。

世代が違うのかもしれませんが、自分と持っている世界観が違うように思い、あまり肌に合いませんでした。ただ、扱っている話題の網羅性は高いと思います。

日本を動かす「100の行動」

日本を動かす「100の行動」