「基本的に」とか、「原則として」が、会議の中で出てくる事が多いが、(経験を積んだエンジニアは良く知っている事ですが)放置しておくと間違いなく危ない場合が多い。
基本的に~であるという事は、裏を返せば基本的に~ではないケースが存在するという事。
例1) 原則的には、そこの関係は、1:1です!
答え) 最低でも、1:nで考えておかないと後で不味い事に。。ヒアリング必須
例2) 基本的に、その資料は担当者に返します。
答え) 担当者以外に誰が受け取るかヒアリングする
ITシステムでは、ロジックで処理をしなければいけない為、処理がMECEになっている必要があります。「基本的に」とかではぐらかしてきたら、逆に突っ込んで聞きましょう!
2010年12月29日水曜日
distinctってそんなに使うのか?
SQLのdistinctは使い所によっては、必要なキーワードだが、訳も分からず使われている事も多い。「膨らんだから書いとけ!」見たいな感じで。
若者のSQLを見ていると、同じ使い方が多いことに気づいた。例えば
foo: id, name
bar: id, foo_id, flag
というテーブル構成で、「barでflagがたっているfooの行を取得」が課題だった場合
select
f.id, f.name
from
foo f inner join bar b on b.foo_id = f.id
where
b.flag = true
と書いてしまったが為に、最終的にselect句にdistinctをつけるはめに。。
これは「fooからデータを取得する際の抽出条件」と認識すれば
select
f.id, f.name
from
foo f
where
exists (select 'x' from bar b where b.foo_id = f.id and b.flag = true)
と書けるはずで、distinct は不要だ。
selectは、縦*横の新しい表を取得する物で、「1行が意味する概念」は何かを、はっきり意識できていないからではと思う。
若者のSQLを見ていると、同じ使い方が多いことに気づいた。例えば
foo: id, name
bar: id, foo_id, flag
というテーブル構成で、「barでflagがたっているfooの行を取得」が課題だった場合
select
f.id, f.name
from
foo f inner join bar b on b.foo_id = f.id
where
b.flag = true
と書いてしまったが為に、最終的にselect句にdistinctをつけるはめに。。
これは「fooからデータを取得する際の抽出条件」と認識すれば
select
f.id, f.name
from
foo f
where
exists (select 'x' from bar b where b.foo_id = f.id and b.flag = true)
と書けるはずで、distinct は不要だ。
selectは、縦*横の新しい表を取得する物で、「1行が意味する概念」は何かを、はっきり意識できていないからではと思う。
2010年12月28日火曜日
CSVというフォーマット
データ交換の検討で、「ここはCSVで」とかで会議終わらせちゃう人もいますが、アフォかと思います。
"CSV"だけでは、フォーマットがあるようでないのと同じです。細かい事が詰まってないので、下記は最低決めちゃいましょう。
"CSV"だけでは、フォーマットがあるようでないのと同じです。細かい事が詰まってないので、下記は最低決めちゃいましょう。
- 文字列エンコーディング(例 Windows-31J)
- 改行コード (例 CRLF)
- "の使い方。業務上EXCELで作業される方が多いので、私は下記で話する事が多いです。
- セル内に , がある場合は、"で囲む
- セル内に " がある場合は、"で囲み、"は""とエスケープする
- セル内に改行がある場合は、"で囲む
ラベル:
design
rails2.3.5のマルチパート解析ではまった
概要
rails2.3.5、正確にはrack1.0.1のマルチパート解析処理に問題があり、データの欠落する可能性があります。
問題
「チェックボックスがおかしな状態になる」という問い合わせがあり調査開始しました。ほどなく"ごくまれ"にチェックボックスの入力状態が正しく反映されないケースがある事に気付きました。
切り分けの為、問題箇所を確認した所
そこで、Rack::Utils::Multipart.parse_multipartメソッドにログを仕込んで確認した所
上手くいかない場合は、変数の動きをみていると、buf変数に一度読み込まれるだけで、後続のデータが処理されていません。
解決
buf変数に読み込んだデータを逐次処理していきますが、バウンダリ+EOL(\r\n)で丁度処理が終了した場合、buf.empty?が真となり、bufに読み込まれていないデータがあっても処理終了になっているようです。よって上記をrack1.1.xで修正されているように
break if (buf.empty? && $1 != EOL) || content_length == -1
とする必要があるようです($1 != EOLを追加)。
しかしrack1.1とrails2.3.5は相性が悪いみたいなので、モンキーパッチで対処する必要がありますね。
下記のような内容をconfig/initializers/rack_patch.rbとかで配置して下さい。
rails2.3.5、正確にはrack1.0.1のマルチパート解析処理に問題があり、データの欠落する可能性があります。
問題
「チェックボックスがおかしな状態になる」という問い合わせがあり調査開始しました。ほどなく"ごくまれ"にチェックボックスの入力状態が正しく反映されないケースがある事に気付きました。
切り分けの為、問題箇所を確認した所
- パケットダンパーでデータを確認すると、socket通信上は想定値が確認できた。
- 例外メール上の記録から、railsでのparamsには、おかしな値が入っている。
- 上記メールから、rackより引き継いだ段階でも、おかしな値が入っている。
そこで、Rack::Utils::Multipart.parse_multipartメソッドにログを仕込んで確認した所
- content_lengthは想定どおりの値が確認できた。
- io上入ってきた内容も想定どおり確認できた。
- 処理ループが想定よりもかなり早い段階で抜けている。但し例外は発生していない。
上手くいかない場合は、変数の動きをみていると、buf変数に一度読み込まれるだけで、後続のデータが処理されていません。
解決
buf変数に読み込んだデータを逐次処理していきますが、バウンダリ+EOL(\r\n)で丁度処理が終了した場合、buf.empty?が真となり、bufに読み込まれていないデータがあっても処理終了になっているようです。よって上記をrack1.1.xで修正されているように
break if (buf.empty? && $1 != EOL) || content_length == -1
とする必要があるようです($1 != EOLを追加)。
しかしrack1.1とrails2.3.5は相性が悪いみたいなので、モンキーパッチで対処する必要がありますね。
下記のような内容をconfig/initializers/rack_patch.rbとかで配置して下さい。
module Rack module Utils module Multipart def self.parse_multipart(env) unless env['CONTENT_TYPE'] =~ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n nil else boundary = "--#{$1}" params = {} buf = "" content_length = env['CONTENT_LENGTH'].to_i input = env['rack.input'] input.rewind boundary_size = Utils.bytesize(boundary) + EOL.size bufsize = 16384 content_length -= boundary_size read_buffer = '' status = input.read(boundary_size, read_buffer) raise EOFError, "bad content body" unless status == boundary + EOL rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n loop { head = nil body = '' filename = content_type = name = nil until head && buf =~ rx if !head && i = buf.index(EOL+EOL) head = buf.slice!(0, i+2) # First \r\n buf.slice!(0, 2) # Second \r\n filename = head[/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni, 1] content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] if content_type || filename body = Tempfile.new("RackMultipart") body.binmode if body.respond_to?(:binmode) end next end # Save the read body part. if head && (boundary_size+4 < buf.size) body << buf.slice!(0, buf.size - (boundary_size+4)) end c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer) raise EOFError, "bad content body" if c.nil? || c.empty? buf << c content_length -= c.size end # Save the rest. if i = buf.index(rx) body << buf.slice!(0, i) buf.slice!(0, boundary_size+2) content_length = -1 if $1 == "--" end if filename == "" # filename is blank which means no file has been selected data = nil elsif filename body.rewind # Take the basename of the upload's original filename. # This handles the full Windows paths given by Internet Explorer # (and perhaps other broken user agents) without affecting # those which give the lone filename. filename =~ /^(?:.*[:\\\/])?(.*)/m filename = $1 data = {:filename => filename, :type => content_type, :name => name, :tempfile => body, :head => head} elsif !filename && content_type body.rewind # Generic multipart cases, not coming from a form data = {:type => content_type, :name => name, :tempfile => body, :head => head} else data = body end Utils.normalize_params(params, name, data) unless data.nil? # break if buf.empty? || content_length == -1 break if (buf.empty? && $1 != EOL) || content_length == -1 } input.rewind params end end end end end
登録:
投稿 (Atom)