はてなキーワード: grepとは
ここ一ヶ月間私は気になって仕方がない。
もう一度言おう。sendとreciveだ。
誰かをお忘れではないですか。
(゚∀゚)ラヴィ!!
reciveから逃亡していたのだった。
ところで、私はSEだ。IT業界の雑用係として名を馳せている。エクセルシートでレポートを書き、エクセルで調査表を作成し、excelで仕様書を修正し、Excelでソースコードを打ち込んでいる。エクセルでチャットに励むのも、エクセルに目覚まし時計を頼むこともエクセルでコーヒーを沸かすことも、、、できる。そんなエクセル戦士たる我が日々戦っているものはなんであろうか。難解なシステムか?不毛なレビュー会議か?睡眠時間か?……いや、どれもそうであるが、どれもそうではない。一番は誤字脱字、二番目は文言の不統一だ。レビューで誤字脱字が一つ見つかると平均して五分時間が伸びる。たった六つで三十分だ。鬼の首でも取った勢いで指摘する人もいれば、淡々と告げる人もいる。だが、これだけは共通している。間違えれば、確実に時間が伸びる。
そこは本質ではない、そこはレビューで確認してほしい点ではないんだ。内心でどう喚こうと、口に出していかに取り繕うと、誤字脱字の指摘にレビュアーは時間を最大限に割く。どいつもこいつもだ。修正は終わるところを知らない。
今いる場所もまぁ似たようなところだ。どこも一緒。だが、IFなんつー物騒なところにアホくさいスペルミス。これはどういうことだ?使用箇所は軽くgrep検索しただけで200行以上。ソースコードのタイムスタンプを見るに八年前はすでにこのフォルダ…ディレクトリ名を使用していた。
これだけ省略形?
今気づいた。
聞いていて、こっちが間違っているような気がした。何でたかが一ディレクトリの名前が違うことに義憤とも私怨ともつかぬものを燃やせばならんのだ。アホらし、アホらし。
その数時間後、仕様変更の連絡違いで30ファイルのエラーログを修正しなければいけないことをレビューで告げられて、闇の炎は再燃することになる。何の因果から、レビュー議事録を送ろうと開いたメールボックスには、TOEIC団体申し込みの最終案内が入っていた。
少なくとも八年前、ディレクトリ名にreciveと名付け、魔のレビュアーの監視を全て逃れて、見事システムに組み込むことに成功した名も無きエンジニアよ。私が今、敬意さえ込めた眼差しで見つめていることをあなた様は知る由もないだろう。人が多ければ多いほどいい。そうすれば、猫は犬に変わり、日本語はJanglishになる。あなた様は確かに、間違いを正しさへ変えたのだ。工数、信用、評価、どれも欠けることなく。
凄いよ、くそったれ。
幼稚で愚かな底辺SEの一人より。
http://anond.hatelabo.jp/20130325172822 の続き
言語はJava7を想定。(Java8が迫っていますが、Lambdaなど関数型は、まだ早いと言うことで)
選定理由は、C++と比較して学べるところが大きく、安全でシンプルな言語だから。
※いきなりJavascriptはやめとけ、PHPは論外。
Ruby・Scalaでないのは、筆者が初心者には適切には教えられないから。
おもちゃ・ToyとしてjQueryで遊ぶのは、悪くは無いと思う。
これ以降は名著の紹介や学習方法の紹介が主体となります。名著のコンポジションという形が時間的限界ですね。
量については「初級になるなら、専門書を計3,000ページは修得することは覚悟してね」なんて言ったりしています。
Javaで初級のわかりやすい指標ですと、[amazon:Effective Java]とGoFまでの修得。
初級になるまでに登竜門への挑戦期間を含めて、3~4年はかかっても仕方が無いとも思います。
※逆に「一山いくらのコーダー」というのは、Effctive JavaやGoFが達成している技術も知らずに「自分がJavaプログラマー」だと誤解してしまっているような人達です。
そういったコーダーは何年経とうとも初級プログラマーにすら敵いません。
初級を目指して、プログラミングを楽しんでください。
ただ、学ぶべきことはべらぼうですが、「各分野毎に、エレガントな方法がある。だから探して修得する」ということが大切です。
※「一を聞いて十を知る」ような優秀な人に、50冊くらいドーンと本を置いてあげて、各本の目次を読ませるだけで、
底の見え無さを悟ってくれたりすると、嬉しくなってしまいます。
※余談ですが、その底の見え無さは数学という学問そのものですね。例えば、関数型言語の底流に「圏論」というここ100年の最新の数学があります。
また中級くらいで、Liskovの置換原則などが載っている本を紹介しますが、
そのLiskovの置換原則の周辺で出てくるcovariant(共変)って、圏論という数学の概念だったりします。
数学畑出身としては、数学が現実に活かされている嬉しい事例です。
「速く正確に大量の出力」という能力は、プログラミングをする上でも、ドキュメントを書く上でも、何より「つまらん仕事」の時間圧縮ができるようになるため、重要です。
スローガンとしては「思考のスピードで出力することを目指そう」です。
紹介するエディターはemacsやvimやExcelです。ついでにIMEとしてATOKを使用しているため、ATOKの操作をEmacsライクにする話も紹介します。
ExcelはWindows環境でMeadowすら入れさせてくれない場合の最後の砦という扱いです。
コマンドラインは、「コマンドラインというものがある」「時として非常に強力である」程度の紹介です。
※筆者はzshは全然使えません。使いこなしている方々と接する度に「勉強しなきゃな~、でも、あっちの方を先にやりたい・・・」とグズグズして、はや何年・・・
正規表現は置換を用いて、テキストの一括編集が重要です。後、遭遇したくない事態ですが、スパゲッティコードの解析をする上での最後の砦です。
※遭遇したくない例
ん?何か変なところで副作用のある処理があるようだなぁ(消沈)、SQLのInsertかUpdateか一応Mergeも使っているところから逆算して原因箇所を探すか・・・(諦念)
この糞コードがっ!!こんなところに書くんじゃねぇ!!(憤怒激高)
(ここで、他にやらかしていそうな似たようなコードを正規表現でgrep検索。改行コード込みにすれば複数文検索も可能)
わはは、予想通り共通化すべきロジックのメソッドがそこら中にある・・・
入門編で一つLinkedListというアルゴリズムを学びました。
少なくとも一つ本を読みながら自力でアルゴリズムを学べる人なら、大成できる可能性があります。
前に紹介した[amazon:C++実践プログラミング]には、LikedListやStackなど基本的なアルゴリズムが載っておりますが、
これに加えて、初級になるためにはこれくらいは知っておいて欲しいというものを紹介します。
※後、最初から必ずしも手を出さなくても良い上限も紹介いたします。
プログラムは、データを入力して、加工して出力・保存する処理の繰り返しです。
つまり、各一連の繰り返し毎に、「正しい入力」「正しい出力」を定式化する必要があります。
それを人間の手では無くコンピューターにやらせられるように、つまり自動テストできるようにテストをプログラミングします。
そこで処理の進捗を確認するためにロギングし、処理が想定通りであるかをアサーションでチェックし、
不正な入力・不正な出力=例外が起きたら、対処策をプログラミングします。
(ex 途中で処理を中断して、入力者に適切な入力のメッセージを伝えてあげる。入力の自動補正などもあり得る)
で、ここら辺をまとめてどうあるべきかとして「契約プログラミング」があります。
※余談。定式化・テストに際して、数学畑の人間としては、Javaだとequalsのオーバーライドでも必要になるし、同値関係・同値分割だけでなく、集合論・群論から学んで欲しい・・・(ここいらは数学科の学部1~2年の学習内容)
名著は英語で読みましょう。名著が名著たる由縁は、度々引用されることにあります。
つまり最新の技術書を読むときに、引用された名著のフレーズが、新旧のリンクをなし、理解の助けになります。
壁打ちといって、独り言で思考補助をするよりも遙かに有益です。
※素晴らしい師匠を探すなら、大学行くのが一番ですが、見聞を広げていく中で出会いを待つしかないとも思います。
マルチスレッドが難しいのは「バグを起こしにくいプログラミング」を求められるから。
つまりTry and Errorからの決別が求められ、今後の仕様変更・拡張も踏まえて慎重に慎重にデザインする必要があります。
できる限りステータス変数を持たずに安全に、でもマルチスレッドにするのだから、効率を追求しなければ本末転倒。
でも効率のためにはメモ化に代表されるキャッシングは必須と、アンビバレンツな要素のバランス取りが難しい。
このために、リエントラントな実装・抽象と実装の分離など様々なエッセンスを駆使することが必要です。
というよりも孔子曰く、知っているよりも好きであること。好きであることよりも楽しめることのほうが強く、
気づいたら日々時間が許す限りプログラミングをしてしまうのが理想です。
※仕事として嫌々スキルを磨かなきゃということが、これほど不幸な職業も無いですね。
学習の達成度を測るには、簡単すぎる不適切な問題ですね。
写経は数学の証明問題を、教科書のテンプレ通りに、数値や名称だけ変えて記述することしか出来ない人の発想。
つまり「矛盾無く一貫した論理モデル」の構築が自由に出来ず、テンプレの微修正しか出来ない人の発想。
また、外部の「矛盾無く一貫した論理モデル」の吸収が不自由で、アルゴリズムを「手順」としてしか捉えられないように見受けられる。
「連続」であること確かめるための「ε-Δ論法」(数学科の学部1年の学習内容)
事前知識無く、このモデルを理解できる人は、十分に「矛盾無く一貫した論理モデル」を構築できる人。
数百行、果ては数千行もある関数やメソッドが何故生まれるのか、どうしても理解できない。それ仕様の通りに動かそうと思ったら、テストもデバッグもライフワークになるよね?それとも未完成でも納品するってこと?もしかしたら「勝手に関数/メソッド作るな」司令が出てるのかもしれないけど、だったら「できません」と断ったほうが絶対楽だと思うぞ。あ、楽といえばこういうコードのレビューは楽だよ、「長すぎて読めない、書き直し」で終わるから。
条件分岐やループを何重にもネストしたコード。スクロールさせるとうねって見える。それさ、正常系の処理だとして一番最後の行の直前はどこ通るの?即答できないなら書き直せ。即答できても「こういう複雑なコードを書けるのがプロ」とか誇らしげな表情しちゃう人はただの勘違いバカだから、その姿勢改めるまで可愛がられるかサクッと見捨てられるかでしょう。
ANDやORが入り組みまくった条件式だけどさ、お前一体何がしたいの?それ多分お前しか理解できないから、システムがEOLになるまで面倒見てあげてね。
「1からnまでの総和」とか、公式がありそうなものをロクに調べもせず、n回ループする方法しか思いつきませんでした的に書いたコード。そんなバカ丸出しの実装で恥ずかしくないの?バカはプログラマに向いてません。それは前述の勘違いバカもそうだけど、頭を捻るセンスが無いのも致命的。
閏年を始めとする日付の計算アルゴリズムとか、標準提供されていそうなものまで手で実装したコード。お前それ辛くないか?てかマニュアルやヘルプはちゃんと読もう、な?
なんで同じコードをコピペするの?共通ルーチン作らなくてもgrepで直して回れば修正漏れも起きないって魂胆?同じ処理が出てくるたびに読んでてうんざりしてくる人も少なからずいることを理解して仕事してください。頼むよ。
DBのテーブルから全レコード取得して、必要なデータか判定して処理するコード。WHERE句って知ってる?データが数億件とかあってもそれでいいと思ってる?
その処理は本当にコードで書かないとダメなの?書かないで済みそうなことまで何故書くの?書かなきゃいけないとして、どうやって短く書くか工夫しないの?コードが増えただけバグも増えることを、もっと深刻に受け止めて欲しい。
最後にコードじゃないけど、巨大なディスプレイに高解像度で極小フォントという環境で開発ってどうなのよ。そこまでしてコード全部表示しないと書けないんだ?今まさに書いている部分なんて、変数もアルゴリズムも自分の頭の中にあるんだから画面に表示する必要なくね?確かに開発用のディスプレイは大きいものが複数あったほうがいいけど、それらはそういう使い方をするためにあるものじゃないと思うぞ。
問3をgrepでやるならせめて ^server4, とすべき。server40があるかもしれないし、URLにserver4って文字が存在する可能性がある。
# cat a.log
# cat a.log |awk -F"," '{print $1","$4}'
# grep server4 a.log
# cat a.log |wc -l
# sort -t"," -k1,1 -k3,3n a.log | head -5
# sort a.log |uniq |wc -l
# cat a.log |awk -F"," '{print $3}' |sort |uniq |wc -l
追記
他の人の回答見ました。
http://anond.hatelabo.jp/20120727180525
パイプでつながなくてもawkでファイル指定できるのとIFができるのとuniq -cは知らなかった。
今度使ってみよう。
【お知らせ】2011/09/07
http://d.hatena.ne.jp/uniqueweb/20110906/1315285545
プログラムは全く得意じゃないけれど最近よく見かけるようになったエロ動画検索を自分でも作ってみたくて頑張ってみました。
近年、インターネットの普及によりエロ動画が自宅で簡単に見れるという素晴らしい時代になりました。
自分が若い頃はインターネットなんてものはなくエロビデオが主流でドキドキしながらレンタルビデオ屋に行き、可愛い女の子がレジにいない隙を見計らってお兄さんにパッケージを伏せて空箱を渡しビデオを借りたものでした。
お兄さんにビデオの空箱を渡そうとした時に可愛い子がレジに戻ってきて焦って渡すのをやめてものすごく変な動きをしながらエロビコーナーに引き返していくなんてことも多々ありましたw
僕のお気に入りといえば「白石ひとみ」や「あいだもも」といった女優でよく借りてました。エロビを借りるということがものすごく恥ずかしい時代?年頃?でカモフラージュに普通のビデオと一緒に借りるということもしていました。それはそれは大変な思いでオナニーしてたんです!
しかも、ビデオデッキ自体が貴重な時代でリビングに一台しかないのが当たり前でした。
深夜家族が寝静まってからヘッドフォンとビデオを抱えリビングに行き暗がりの中でヘッドフォンをテレビに差し込んでビデオの再生ボタンを期待に胸をふくらませながら押したものです。いいシーンを何回も見るためにビデオを巻き戻すんですが、ビデオを巻き戻すガチャンガチャンという機械音で家族が起きてこないか?とかそれはそれはドキドキしながら見てました。一仕事終えたあとヘッドフォンを外したらジャックが外れていて大音量で喘ぎ声が響き渡っていたなんてこともありました。誰も起きてこなかったのは優しさなんでしょうか?w
さて、大分前置きが長くなりましたがエロというものはものすごい技術発展させるものだと思います。エロのおかげで日本でビデオは普及しエロのおかげで日本でインターネットはものすごく普及したと言っていいと思います。自分もエロを通して技術の発展に貢献し自分自身のスキルアップになれば。という高い志を持ってこのサイトを制作しました。決して自らのオナニーライフの充実と性癖を充たすため作ったわけではありません・・・w
※2011.08.07 利用中のサーバーに障害が発生しているようで現在サーバーに接続できない状態となっています・・・
サイト名の由来は抜きネタからきています。抜きネーター、ヌキネーターという感じですw
エロサイトの制作工程を日記にしてみたんで良かったら読んで下さい。そしてこのサイトを使って夜いろいろと励んでくれたら嬉しいです。
まず前提条件としてお金をほとんどかけたくない。アダルトサイトであるということから
月の予算は5000円以内で考えていたのでけっこう探すのが大変でした。
日本でアダルトサイトを許可している所はかなり限られていてさらにやりたいことができるのは
専用サーバーかVPSしかないのでそうなると専用サーバーは予算オーバーなので
VPSで探すことになり検索しまくってはじめに見つけたVPSはKAGOYAのVPSだったのですがβ版で募集を締め切っていて泣く泣く諦めました。
KAGOYAはかなり評判がいいみたいなので使ってみたかった。
次に見つけたのが○○○VPS。海外サーバーで日本語サポートがあり転送量の制限なしディスク容量100G
月1300円程度で借りれるということで初期設定費用に5000円程度かかりましたが借りてみました。
結果、ここは最悪でした。
あまりの酷さに1ヶ月で解約。
よく調べてみたら評判がものすごく悪い某VPSの再販らしいです。
もう失敗したくないと思い今度は比較的有名な海外サーバーLINODE。
iptablesの設定でどうしてもうまくいかなくて拙い英語でメールしてみたら
10分しないうちに返信がきました!
メールに書かれているとおりにコマンドを入力したらあっさり解決。
担当のブライアンはなぜか分からないけどとてもフレンドリーで親切に感じましたw
LINODEは複数のディストリビューションから好きなものを選択できるので
とりあえず、64bit版を選択。
一番面倒だけど重要だということで
Tripwire
ほんとに面倒でした。
はじめはmysqlにストレージエンジンgroongaを使おうと思ったのですが
初めに借りた最悪なVPSはOSが32bit版だったのでgroongaがのソースが見つからずなぜかと思っていたら
どこかで見つけた記事で32bit版ではgroongaの性能を発揮しきれないということで32bit版の提供をやめてしまったらしいと書いてたので
じゃあ、sennaにするかということで最悪VPSでsennaをインストール。
その後LINODEに変更したのでOSに64bit版を選択し念願のgroongaをインストール。
しかし、調べてみると
プログラムもそれに合わせてその都度書き換えたので2度手間どころか3度手間4度手間でした・・・
まず
そして下記の順番でインストール
rpm -ivh mecab-0.98-tritonn.1.0.12a.x86_64.rpm
rpm -ivh mecab-ipadic-2.7.0.20070801-tritonn.1.0.12a.x86_64.rpm
rpm -ivh senna-1.1.4-tritonn.1.0.12a.x86_64.rpm
rpm -ivh MySQL-shared-5.0.87-tritonn.1.0.12a.x86_64.rpm
rpm -ivh MySQL-client-5.0.87-tritonn.1.0.12a.x86_64.rpm
rpm -ivh MySQL-server-5.0.87-tritonn.1.0.12a.x86_64.rpm
rpm -ivh MySQL-devel-5.0.87-tritonn.1.0.12a.x86_64.rpm
my.cnfの設定をして終了
で肝心の全文検索ですがデータ件数が5万件程度で少ないせいなのか、あいまい検索と比べてそれほど速さを実感できなかったです・・・
でもきっとすごく速くなったはず!
ちなみに「麻美ゆま おっぱい」で検索した場合、0.01 secで結果が返ってきました。
さて、動画データの作成ですがいくつかのエロサイト等制作記事でもあるようにスクレイピングということをします。
スクレイピングとはWEBサイトから特定の情報だけを取得することでネット上にあるサイトをクロールして必要なデータだけを拾ってデータを作るといった感じでしょうか。
スクレイピングのプログラム自体は以前にTidy関数を使って為替データを10分おきに取得するような物を作ったことがあったのでそれほど時間はかからないかなと思ったのですがけっこう時間かかりました。
スクレイピングにはTidyとhtmlSQL、それにPHP Simple HTML DOM Parserを使いました。
SQL みたいな文法で HTML を抽出する PHP のライブラリ
htmlSQLよりアツい!?jQueryみたいにセレクタでHTMLをparse(解析)する「PHP Simple HTML DOM Parser」
3つの中で抜群に使えるのはPHP Simple HTML DOM Parserだったんですが
ループ処理させるとメモリがすごいことになって今回のようなスクレイピングに向いてないみたいで
結局、htmlSQLとTidyの両方を使ってスクレイピングしました。
両方ともPHP Simple HTML DOM Parserに比べるとうまくデータの取得ができないことが多く残念な感じなんですが他に選択肢がないので・・・
使える順に並べると
といった感じかもしれません。
おおまかにデータを取得して正規表現で特定データを抜き出しました。
http://affiliate.dmm.com/link.html
利用可能な物はパッケージ画像、サンプル画像(縮小)と書かれていたのでそれに従い画像を利用。
注記に※ユーザーレビューは引用いただけません。とだけ書かれているのでそれ以外は引用ありと判断して説明文とタイトルなどを利用
女優データとジャンルデータ、DVDデータ、を紐付けたデータベースを作成し検索ワードに応じて検索結果に関連する商品を表示させるようにしました。
現状、売り上げ0で意味があるのか分かりませんけどw
エロサイトということで多少はチューニングとか設定とかしないとまずいかもと思い色々調べて設定しました。
やったこと
KeepAlive On MaxKeepAliveRequests 60 KeepAliveTimeout 3 <IfModule prefork.c> StartServers 7 MinSpareServers 5 MaxSpareServers 10 ServerLimit 30 MaxClients 30 MaxRequestsPerChild 4000 </IfModule>
様子見ということで2日間で設定してみました。
query_cache_limit=1M
query_cache_min_res_unit=4k
query_cache_size=16M
query_cache_type=1
とりあえずこんなところを設定してみましたが、爆発的なアクセスがあるわけでもないので有効なのか今のところ分かりません(-_-;)
Apache Benchでテストはしてみましたけど問題はない感じですが実際にチューニングができているか分かりません。
プログラマーとして有名なゆうすけさんのサイトとgoogleを参考にしました。
シンプルで使いやすいようにしようと思いこのデザインにしました。
クロスブラウザはIE7、firefox3、chromeで行いました。
可変ものって作ったことなかったんですがけっこう面倒なんですね。
ブックマーク機能とメニューの折りたたみ機能、検索結果の表示方法切替を作りました。
まず、ブックマーク機能ですがログインなしで気に入った動画をブックマークできるようにしました。
ブックマークに追加した動画はブックマークページで確認できるようにしました。
cookie機能を利用したらいけると思い色々調べてjquery.cookie.jsを利用。
保存したクッキー情報を呼び出してphpに渡して処理し指定要素にブックマーク一覧をloadメソッドで表示させるという感じです。
$(function(){ $("#youso").load("xxx.php"); });
メニューの折りたたみ機能は人気AV女優やAV女優別、人気タグなどをそのまま表示させるとずらっと長くなって邪魔だったのでつけました。
これには同じくjquery.cookie.jsを利用しました。
参考サイト:http://blog.caraldo.net/2009/03/newjqqookiemenu.php
検索結果の表示方法切替にはZoomer Galleryを利用しました。
参考URL:http://phpjavascriptroom.com/?t=ajax&p=jquery_plugin_zoom#a_zoomergallery
検索結果ページで表示される
[ここの画像]
××× の検索結果
44件中 1~10件目を表示
ここの画像の部分をクリックするとgoogleイメージ検索みたいに一覧でイメージ表示できるようにしてみました。
基本的に動画の埋め込みを許可しているサイトのみプレイヤー表示をしそれ以外は画像を表示し動画データへリンクするようにしました。
埋め込み部分はあらかじめそれぞれのサイトに対応したプレーヤー部分のコードを記述しVIDEOIDの部分に置き換えるような形にしました。
XVIDEOSを例にすると
XVIDEOSの場合かならず動画のurlがhttp://www.xvideos.com/videoXXXXXX/のようになりますのでXXXXXXの部分を
VIDEOID部分に置き換えるようにプログラムを組みました、
埋め込み部のソース
>||<object width="510" height="400" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" ><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="allowScriptAccess" value="always" /><param name="movie" value="http://static.xvideos.com/swf/flv_player_site_v4.swf" /><param name="allowFullScreen" value="true" /><param name="flashvars" value="id_video=VIDEOID" /><embed src="http://static.xvideos.com/swf/flv_player_site_v4.swf" allowscriptaccess="always" width="510" height="400" menu="false" quality="high" bgcolor="#000000" allowfullscreen="true" flashvars="id_video=VIDEOID" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>
||<
その他の動画サイトもURLの一部分のデータを使っているので同様の処理をしました。
実際の作業は2、3週間ですが色々調べる時間が多くて制作に2ヶ月くらいかかりました。
自分でエロ動画検索を作ってみて有名プログラマーさん達がいかに優秀なのか思い知らされました。
全くWEBの知識がない人で4、5ヶ月ですごいの作っちゃう人とかもいるみたいですし世の中広いな~と思います。
大分、色んな知識を得ることができました。
これからプラグラムを勉強しようと思う人はぜひエロサイトから入ってみて下さい。
そんなこんなで?頑張って作ってみたエロ動画検索、良かったら使ってみて下さい。
これで少しは技術の発展に役立てたでしょうか?w
P.S エロサイトを作っていてはじめは楽しくて興奮しながら作ってたのですが最後の方はエロい物を見ても全く反応しなくなりましたw
不能ではないんですけど・・・今現在も性欲が著しく減退しております・・・
そしてスーパーpre記法がうまういかないのはなぜ?はてな匿名ダイアリー初投稿で全然分からない・・・
そしてそしてプログラマーさんとかデザイナーさんとかエロい人とかお気軽にお声をおかけ下さい。
【お知らせ】2011/09/07
まぁ、タイトルの「レガシープログラマ」とは私の事なんですけどね。
if( foo == TRUE ){
という判定文をよく見かける(fooはいろんなオブジェクトだと思ってほしい)。
個人的には、この書き方、嫌いなんだよね。
if( foo ){
か
if( foo != FALSE ){
と書いて欲しいわけよ。とにかく「TRUEか?」という判定にはして欲しくないわけです。
で、なんでこう書くの?と外注や若い連中に聞いたら、「TUREは1ですから」と必ず答える(断言する)。
あ、あれ???自分は「TRUEはFALSEでは無い。確定しているのはFALSE=0という事だけ」だとずっと思っていたんですわ。
古いC言語風に書けばこんな感じ。
#define FALSE 0 #define TRUE (!FALSE)
確かに、実際に値を表示させてみると、昔のVC6だと「1」という結果が出てくるし、VB6だと「-1」という結果が出てくる。これ、当時混乱の元だったんだよね。
新しいC++や規格ではBOOL型というのがきちんと定義されたと思うけど、製品寿命が20年とかいう私の職場では、DOSやC(K&R)、アセンブラは現役だし、プラットフォームもなにもWindowsに限らない。組み込みマイコンも使う(うちのところはVxWOKSだが)し、UNIXやLINUXも使う。
もちろん、マネージドC++(.netFramework)やC#、JAVA、Parlも私は使うし。でも、どのプラットフォームでどの言語になっても「TRUEか?」という判定文は使ってこなかった。
で、試しに、VC2008のincludeフォルダをgrepしてみたら、
#define TRUE 1
あ、ほんとに「1」だ。
typedef bool int
なんて見かけるから、やろうと思えば「5」でも何でも数字が入ってしまうわけですよ。そこで「== TRUE」なんてやられたら、絶対に成立しないわけで。バグの温床になるんじゃないかなー、と思ってかたくなに前述の姿勢を持っていたわけです。
今(最近の)言語はきちんと「BOOL」型(またはboolという名のクラス)を定義されていて、コンパイルエラーになるか、自動的に補正してもらえるのかもしれないけど、ちょっと気持ち悪い。
最近、ちょくちょく外注や若い連中と意見や話が合わず、「ああ、俺ってレガシープログラマなんだな」と思う事が多くなった今日この頃。ネットワークに平気でリトルエンディアンのデータを流すとか、勘弁して欲しい。LANアナライザでデータが見にくくてしょうが無い。
5年以上ぐらい前にPerlのレガシーコードで書かれたcgiって駄目なプログラムのお手本だな。
1ファイル何千行もあるcgiで、一生懸命条件分岐や関数呼び出ししながらprintしてHTML作っていくやつ。
後から他人がレイアウト変更とか不可能に近い。
同じような処理(例えば掲示板だと新規書き込み、書き込み確認、書き込み修正など)があちこちに分散してて、全部探し出さないと変更できないとか。
俺が今作ってるWebアプリではSmartyなどのテンプレ使ってロジックとデザインの分離が当たり前なのに(ちなみにSmartyは分離がイマイチ、最近は他のを使ってる)、この時代にはそんな考え毛頭なかったんだね。
拡張子もcgiだったりplだったり。*.cgiでgrepしても出てこない処理のせいで半日つぶした。
それは、使ったほうが分かりやすい例ではあるけど、わかんない人も多いかと思うよ。
それよりも、関数を引数にするアルゴリズム関連は 正直 やめてほしい。
長めの関数の中盤ぐらいに書いてあって、その中の値がおかしいのか、デバッグするときに、関数本体がどこにあるのか、
わざわざgrepしなきゃいけないとか、時間がもったいない。IDEでジャンプでもいいけど、IDEサポートあってもめんどうだ。無いことだってあるんだよ。
その関数が随所で使いまわされているなら、まだわかるけどね。
かいている人間は、それでいいのかも知れないけど引き継いでデバッグする方の事も考えて書いて欲しい。
巨大なシステムやってると、書く方は量が少ないが、デバッグする方は、システム全部デバッグしてるんだぞと。
そうならないように、モジュール化してくれるのが一番だが、どんなにモジュール化してあっても、どこで起きてるかわからないから、全部見なきゃいけないバグなんて余裕で起きるんだよ。orz
100時間ぐらい、高負荷テストしてると落ちるとかね。当て推量はするけどさ、たのむ、みんな、分かりやすく他人がデバッグしやすく書こうぜ!
元ネタ http://phpspot.org/blog/archives/2009/12/phpjavascriptph_1.html
面白そうだと思ったので僕もやってみた。モジュールはPerl5.8系の標準モジュールのみ利用可という制限。
全部はキツイので関数処理関係の関数(http://php.benscom.com/manual/ja/ref.funchand.php)だけ実装してみた。
use strict; use warnings; =head2 call_user_func $ret = call_user_func($function,@param); $ret = call_user_func([$class,$method],@param); example1 sub plus { $_[0] + $_[1] } print call_user_func('plus',10,20); # 30 example2 package Foo; sub plus { $_[1] + $_[2] } package main; print call_user_func(['Foo','plus'],10,20); # 30 =cut sub call_user_func { my $proto = shift; if ( ref $proto eq 'ARRAY' ) { return $$proto[0]->${\$$proto[1]}(@_); } else { require Pod::Functions; if ( $Pod::Functions::Flavor{$proto} ) { return eval qq{$proto(\@_)}; } else { no strict 'refs'; return $proto->(@_); } } } =head2 call_user_func_array $ret = call_user_func_array($function,\@param); $ret = call_user_func_array([$class,$method],\@param); example sub plus { $_[0] + $_[1] } print call_user_func_array('plus',[10,20]); # 30 =cut sub call_user_func_array { return call_user_func(shift,@{+shift}); } =head2 create_function $code = create_function($args_str,$code_str); example $code = create_function('$c,$d=1','print $c+$d'); $code->(10); # 11 =cut sub create_function { my $args = shift; my $code = shift; my $default = 0; my @args = split /,/,$args; my $code_str = 'sub {'; for my $arg (@args) { if ( $arg =~ /^\s*(\$[a-zA-Z][\w]*)\s*(?:=\s*(.+))?\s*$/ ) { my $val = $1; my $def = $2; if ( defined $def ) { $default = 1; $code_str .= qq{my $val = \@_ ? shift : $def;\n}; } else { die 'parse error' if $default; $code_str .= qq{my $val = shift;\n}; } } } $code_str .= $code . '}'; my $sub = eval $code_str; die $@ if $@; return $sub; } =head2 forward_static_call $ret = forward_static_call($function,@param); $ret = forward_static_call([$class,$method],@param); =cut sub forward_static_call { call_user_func(@_); } =head2 forward_static_call_array $ret = forward_static_call_array($function,\@param); $ret = forward_static_call_array([$class,$method],\@param); =cut sub forward_static_call_array { call_user_func_array(@_); } =head2 func_get_arg $arg = func_get_arg($no) example sub foo { print func_get_arg(1) } foo(100,200); # 200 =cut sub func_get_arg { my $n = shift; package DB; @DB::args = (); () = caller(1); return defined $DB::args[$n] ? $DB::args[$n] : undef; } =head2 func_get_args @args = func_get_args() example sub foo { print join ':', func_get_args() } foo(11,22,33); # 11:22:33 =cut sub func_get_args { my $n = shift; package DB; @DB::args = (); () = caller(1); return @DB::args; } =head2 func_num_args $arg_count = func_num_args() example sub foo { print func_num_args() } foo(11,22,33); # 3 =cut sub func_num_args { my $n = shift; package DB; @DB::args = (); () = caller(1); return scalar @DB::args; } =head2 function_exists $bool = function_exists($func) example sub foo {} print function_exists('foo'); # 1 print function_exists('bar'); # 0 print function_exists('rand'); # 1 =cut sub function_exists { my $func = shift; return 1 if exists &$func; require Pod::Functions; return $Pod::Functions::Flavor{$func} ? 1 : 0; } =head2 get_defined_functions $funcs = get_defined_functions() =cut sub get_defined_functions { require Pod::Functions; return { internal => [ keys %Pod::Functions::Flavor ], user => [ grep { exists &$_ } keys %:: ], }; } =head2 register_shutdown_function register_shutdown_function($func,@param); register_shutdown_function([$class,$method],@param); =cut { my $REGISTER_SHUTDOWN_FUNCTION = []; sub register_shutdown_function { my $proto = shift; push @$REGISTER_SHUTDOWN_FUNCTION, [ do { if ( ref $proto eq 'ARRAY' ) { $$proto[0]->can($$proto[1]); } else { require Pod::Functions; if ( $Pod::Functions::Flavor{$proto} ) { sub { eval qq{$proto(\@_)} }; } else { no strict 'refs'; \&$proto; } } }, [@_] ] } END { $_->[0]->(@{$_->[1]}) for @$REGISTER_SHUTDOWN_FUNCTION; } }
思ったよりも難しかった。標準関数一覧を取る手段がなかったので標準モジュールを利用して標準関数の一覧を取得した。
あと文字列から標準関数を呼び出すスマートな手段が思いつかなかったのでeval便りに。
create_functionはかなりゴリ押し。myを勝手に付けたりデフォルト引数にも対応してたり細かい芸が光る(自分で言うな)
forward_static_callはぶっちゃけPerl的にcall_user_funcと殆ど処理が変わらないのでそのまま利用。
func_get_arg系は結構クリティカルだなー。@DB::argsをリアルに使ったの初めてだよ。
register_shutdown_functionはちょっとねー。ENDブロックを利用してるわけなんだけど当然mod_perlとかではうまく動かない。あとシグナルとか使った方が良いのかもしれない。
ヒマがあったら他の関数とかも実装してみたいかも。
http://anond.hatelabo.jp/20090914132607 の増田です。
こんな話きいても面白いと思ってくれる人いるわけねーだろ、みたいなテーマで調べものをしてます(本業はというと不景気で自席待機中、次の派遣先は決まらないかもしれない)。自分が首になって家内ともども路頭に迷うかもしれないのに、不思議と危機感がなくて。
CiNii のサイトにいくと、とある学会誌の創刊号から何年かが全部無料公開されてて、創刊号にはなんと当時の科学技術庁長官、中曽根康弘氏が祝辞を寄せてるわけです(さてどこの雑誌でしょう)。とある単語をさがしてその検索のきかない pdf を延々延々「目 grep」してます。で、二段組みなので狭い画面で見ると
と2passかかる。疲れ目がひどくてブルーベリーのサプリがありがたい。
あと JIS の規格票とかも検索するのですがこの検索がまた動きが微妙なんだ。
資料の探索範囲はストーリーが見えてくるに従って広がっているのですが、なんか自分の知識には主に理論面であちこち欠落があって、定番的教科書に何が書いてあるのか知らないままやっているもので、あちこち致命的ではないもののぼろが見えてきて、それを全部繕ってるといつまでも終わりそうになくて、しょうがないから切り捨てたりごまかしたりして、まあ本に書いてないような新事実もちょっとだけ確認はしたものの。
結局やってることはといえば、安楽椅子、もしくはマトリックス内歴史家で、pdf になってないものにはほとんど手が届いてない。
要するに、キーパーソンにアポとるのが怖いんです。勉強不足を pgr れて瞬殺されるのが怖いんです。自分が持って行った新事実を喜ぶどころか不機嫌な顔で、おまえうざい、って言われてすべてが終わりになる恐怖がいつまでも去りません。円満退社したとはいえ古巣の元上司に「いまは職を転々としながらこんな金にならないことにまで手を出してます」と自己紹介するのもこわいし、要するにすべてが怖いです。
私ごときが全てを知ろうなんておこがましいんですが、何の権利があって、自分の先生でもない人に質問をするのか、その根拠が見えません。
まあ恥を晒し大失敗するしかないんだろうけど。
% diff host.old host.txt | grep '[<>]' | sort > 16x16.hatelabo.jp > b.st-hatena.com > copie.hatelabo.jp > maintenance.hatena.ne.jp > uicon.st-hatena.com
それと、はてラボ新サービス、漏れていた maintenance も加え調べる。
% diff resolve.old resolve.txt | grep '[<>]' | sort > 59.106.108.101: maintenance.hatena.ne.jp. > 59.106.108.72: b.st-hatena.com. > 59.106.108.72: uicon.st-hatena.com. > 59.106.108.93: 16x16.hatelabo.jp. > 59.106.108.93: copie.hatelabo.jp.
http://anond.hatelabo.jp/20090408100019
ベンチを取ってみると、ハッシュの方が速かったです。
UPSERT処理SQL生成処理の汎用化に使用中だったのですが、プロファイルすると結構時間をくっていたので、key設定時まで遡って再構築したいと思います。
#!/usr/bin/perl use strict; use warnings; use Benchmark; my $item = { date => undef, type => undef, value => undef, title => undef, views => undef }; my @key = ('date', 'type'); my %key; my @update; timethese(1000000, { use_grep => sub { @update = grep { my $a = 1; foreach my $b (@key) { $a = 0 if $_ eq $b; } $a; } keys %{$item}; }, use_hash => sub { %key = map { $_ => 1 } @key; @update = grep { not exists $key{$_} } keys %{$item}; }, } );
実行結果
Benchmark: timing 1000000 iterations of use_grep, use_hash... use_grep: 10 wallclock secs ( 9.84 usr + 0.00 sys = 9.84 CPU) @ 101595.04/s (n=1000000) use_hash: 5 wallclock secs ( 6.43 usr + 0.00 sys = 6.43 CPU) @ 155593.59/s (n=1000000)
http://anond.hatelabo.jp/20090408034449
リスト内の有無を複数回調べるときの定石は、事前にハッシュに突っ込んでおく方法です。
元のコードはgrep内でリニアサーチをやっているわけですから、ここにハッシュテーブルを使うわけです。
my %key = map { $_ => 1 } @key; my @update = grep { not exists $key{$_} } @items;
ベンチは取っていないですが、多分早いです。
ただ、その分メモリを食いますし、@itemsに対し@keyの方が長大だと、あまり効率が良くないかも知れません。
その場合、ソート済みならバイナリサーチでやってみるとか、そもそもkeyをハッシュで管理するとか、GDBMやsqlite等を使って永続化するとか、keyの入手段階から検討したほうが良いかもしれません。
忘れないうちに調べてみた。
% diff host.old host.txt | grep '[<>]' | sort > d2.hatena.ne.jp > ugomemo.hatena.ne.jp > url.hatena.ne.jp
新サービスうごメモと、漏れていた d2, url を加えた。
% diff resolve.old resolve.txt | grep '[<>]' | sort > 59.106.108.80: d2.hatena.ne.jp. > 59.106.108.91: url.hatena.ne.jp. > 59.106.108.94: ugomemo.hatena.ne.jp.
今回は 59.106.108.64/27 だった。59.106.108.96/27 との使い分けに何か法則があるのだろうか。
はてなキーワード、はてなブックマークのリニューアルに加え、はてラボ新サービスも始まったので、ここ半年近くの変化を調べてみた。
% diff host.old host.txt | grep '[<>]' | sort > bbeta.hatena.ne.jp > bottle.hatelabo.jp > counting.hatelabo.jp > favicon.hatena.ne.jp > img.b.hatena.ne.jp > img.f.hatena.ne.jp > k.hatena.ne.jp > news.hatelabo.jp
対象に、新サービスによるものと、漏れていた img.f.hatena.ne.jp を加えた。
% diff resolve.old resolve.txt | grep '[<>]' | sort < 221.186.146.26: mail.hatena.ne.jp. < 221.186.146.26: ns.hatena.ne.jp. < 221.186.146.26: sv.hatena.ne.jp. < 221.186.146.27: hatena.ne.jp. > 59.106.108.101: ns.hatena.ne.jp. > 59.106.108.101: sv.hatena.ne.jp. > 59.106.108.102: k.hatena.ne.jp. > 59.106.108.103: favicon.hatena.ne.jp. > 59.106.108.105: img.b.hatena.ne.jp. > 59.106.108.106: bbeta.hatena.ne.jp. > 59.106.108.69: img.f.hatena.ne.jp. > 59.106.108.86: hatena.ne.jp. > 59.106.108.93: bottle.hatelabo.jp. > 59.106.108.93: counting.hatelabo.jp. > 59.106.108.93: mail.hatena.ne.jp. > 59.106.108.93: news.hatelabo.jp.
221.186.146.24/29も消え、外向けサーバは完全にサクラのみでの運用に切り替わったようだ。
img.f.hatena.ne.jp と f.hatena.ne.jp、hatena.ne.jp と www.hatena.ne.jp は同じゲートウェイとなっている。
おれはもうMooseしかつかわねぇ。後にも先にもMooseMooseMooseMooseMoose!!!!!!!!!!!1111111
ってな人の為にいつでもどこでもMooseする。automooseを実装しますた。
package automoose; use strict; use warnings; sub import { strict->import; warnings->import; } package automoose::before; use Moose; no Moose; package automoose::after; use Moose; my @before = keys %automoose::before::; my @after = keys %automoose::after::; my @exports = do { my %u; @u{@before} = (); grep { !exists $u{$_} } @after }; package UNIVERSAL; use Moose; for my $func (@exports) { __PACKAGE__->meta->remove_method($func); __PACKAGE__->meta->add_method($func,sub { my $class = shift; my $auto = $class.'::__auto__'; no warnings 'redefine'; local *Moose::_get_caller = sub { return $class }; Moose->import( { into => $auto } ); my $code = $auto->can($func); $class->meta->add_method($func,sub { shift; goto $code; }); goto $code; }); } 1;
使い方はいたって簡単。useするだけ。
use automoose; my $obj = Foo->new;
いきなりnewが呼べちゃう。
他にも
use automoose; Foo->has( hoge => is => 'rw' ,default => 9999 ); Foo->has( muge => is => 'rw' ,default => 7777 ); print Foo->new->hoge; print Foo->new->muge; Bar->extends('Foo'); print Bar->new->hoge;
ょーかんたん。げーべんり。
しっかしこれ、automooseだけど実装するの結構めんどかったのよ。Moose-0.44をベースに作ったんだけどさ。
Moose内部で使用している$CALLERって変数がレキシカルなもんだから、どうやってそれを外から制御すればいいのかすんごい苦労したわけさね。
で結局importの引数にinto渡してさらにMoose::_get_caller関数を上書き無理矢理ハックしたってわけさ。
でもね。でもね。でもね。ちょっと聞いてよ。
ふと最新のMoose-0.50見てみたらさ、Moose::__CURRY_EXPORTS_FOR_CLASS__なんて関数が定義されてるわけよ。
外から明示的に$CLASSを変更できるインターフェイスなわけよ。おいおいおいおい、勘弁してくれよ。こっちゃ折角苦労してハックしたのにあっさり公式対応するなってばよ。メゲルヨ?ぼく。
まぢめげるよ。めげる。ってかもうめげたよ。もうMooseなんてつかわんね!つかわんね!
Mooseなんて大嫌いだー!
俺はMooooooooooseをやめるぞぉおおおおおおおおお、JOJOぉぉぉおおおおお!!!!11
今回、洩れていたauth,gw,mail,nsを加えている。
% diff resolve.old resolve.txt | grep '[<>]' | sort < 125.206.202.66: graph.hatena.ne.jp. < 125.206.202.66: i.hatena.ne.jp. < 125.206.202.66: map.hatena.ne.jp. < 125.206.202.66: q.hatena.ne.jp. < 221.186.146.26: mail.hatelabo.jp. < 221.186.146.27: www.hatena.ne.jp. < 221.186.146.28: anond.hatelabo.jp. < 221.186.146.28: hatelabo.jp. < 221.186.146.28: music.hatelabo.jp. < 221.186.146.28: searchplus.hatelabo.jp. < 221.186.146.28: serif.hatelabo.jp. < 221.186.146.28: sns.hatelabo.jp. < 221.186.146.28: sv.hatelabo.jp. < 221.186.146.28: wordlink.hatelabo.jp. < 221.186.146.28: world.hatelabo.jp. < 61.196.246.68: screenshot.hatena.ne.jp. < sv.hatelabo.jp.: www.hatelabo.jp. > 221.186.146.26: mail.hatena.ne.jp. > 221.186.146.26: ns.hatena.ne.jp. > 59.106.108.66: gw.hatena.ne.jp. > 59.106.108.86: www.hatena.ne.jp. > 59.106.108.87: screenshot.hatena.ne.jp. > 59.106.108.88: map.hatena.ne.jp. > 59.106.108.89: i.hatena.ne.jp. > 59.106.108.90: auth.hatena.ne.jp. > 59.106.108.92: graph.hatena.ne.jp. > 59.106.108.93: anond.hatelabo.jp. > 59.106.108.93: hatelabo.jp. > 59.106.108.93: mail.hatelabo.jp. > 59.106.108.93: music.hatelabo.jp. > 59.106.108.93: rokuro.hatelabo.jp. > 59.106.108.93: searchplus.hatelabo.jp. > 59.106.108.93: serif.hatelabo.jp. > 59.106.108.93: sns.hatelabo.jp. > 59.106.108.93: sv.hatelabo.jp. > 59.106.108.93: wordlink.hatelabo.jp. > 59.106.108.93: world.hatelabo.jp. > 59.106.108.93: www.hatelabo.jp. > 59.106.108.99: q.hatena.ne.jp.
気がつくと、61.196.246.64/29と125.206.202.64/29が消え221.186.146.24/29が残るのみとなった。
おそらくこれで移転完了だろう。そこで、改めてサーバ一覧を示す。
inetnum: 221.184.0.0/13 (221.184.0.0 -221.191.255.255) netname: OCN-JPNIC-JP inetnum: 221.186.146.24/29 (221.186.146.24 - 221.186.146.31) netname: HATENA 221.186.146.26: mail.hatena.ne.jp. 221.186.146.26: ns.hatena.ne.jp. 221.186.146.26: sv.hatena.ne.jp. 221.186.146.27: hatena.ne.jp. inetnum: 59.106.0.0/16 (59.106.0.0 - 59.106.255.255) netname: SAKURA inetnum: 59.106.108.64/26 (59.106.108.64 - 59.106.108.127) netname: HATENA 59.106.108.66: gw.hatena.ne.jp. 59.106.108.67: red.hatena.ne.jp. 59.106.108.67: red3.hatena.ne.jp. 59.106.108.68: mobile.hatena.ne.jp. 59.106.108.69: f.hatena.ne.jp. 59.106.108.70: rimo.tv. 59.106.108.71: mgw.hatena.ne.jp. 59.106.108.72: b.hatena.ne.jp. 59.106.108.73: g.hatena.ne.jp. 59.106.108.74: a.hatena.ne.jp. 59.106.108.75: r.hatena.ne.jp. 59.106.108.76: ring.hatena.ne.jp. 59.106.108.77: d.hatena.ne.jp. 59.106.108.78: w.hatena.ne.jp. 59.106.108.81: counter.hatena.ne.jp. 59.106.108.82: search.hatena.ne.jp. 59.106.108.84: h.hatena.com. 59.106.108.84: h.hatena.ne.jp. 59.106.108.86: www.hatena.ne.jp. 59.106.108.87: screenshot.hatena.ne.jp. 59.106.108.88: map.hatena.ne.jp. 59.106.108.89: i.hatena.ne.jp. 59.106.108.90: auth.hatena.ne.jp. 59.106.108.92: graph.hatena.ne.jp. 59.106.108.93: anond.hatelabo.jp. 59.106.108.93: hatelabo.jp. 59.106.108.93: mail.hatelabo.jp. 59.106.108.93: music.hatelabo.jp. 59.106.108.93: rokuro.hatelabo.jp. 59.106.108.93: searchplus.hatelabo.jp. 59.106.108.93: serif.hatelabo.jp. 59.106.108.93: sns.hatelabo.jp. 59.106.108.93: sv.hatelabo.jp. 59.106.108.93: wordlink.hatelabo.jp. 59.106.108.93: world.hatelabo.jp. 59.106.108.93: www.hatelabo.jp. 59.106.108.97: d.hatena.com. 59.106.108.97: hatena.com. 59.106.108.97: m.hatena.com. 59.106.108.97: m.hatena.ne.jp. 59.106.108.97: s.hatena.com. 59.106.108.97: s.hatena.ne.jp. 59.106.108.98: w.hatena.com. 59.106.108.99: q.hatena.ne.jp.