サクサク読めて、アプリ限定の機能も多数!
トップへ戻る
2024年ランキング
fj.hatenablog.jp
間違いを減らす方法を考えていて、ある程度以上はどうしようもないという役に立たない結論を得たのだったのだが、過激だったのか、意図せずアクセスが増えてしまった。単に苦労していますだけの内容を多く読まれても困るなと、一回取り下げて書き足しました。 間違いの減らし方を こちら に書きました。 仕事をしていると、必ず間違いを提出してくる人に出会ったことはないでしょうか?私は何度も悲しい思いをしており、そういう人にはもう仕事は頼めないと、非情ですが早々に判断するようにしています。 少なくともソフトウェア開発の世界では、正確さに大きな価値が置かれています。この業界だけでなく、一般的に、間違いは欠陥か事故であり、基本的に許されないものです。仕事は、紙の試験ではないため、百点満点が当たり前です。タクシーに乗ったら、事故せずに必ずつくことを期待する。手術で手が滑ることや、車を運転して信号を見間違えることは許さ
語っていることの辻褄があっているとか、矛盾がないとか、整合性が取れている状態を論理的と言います。意思決定や問題を解きたいときなど、正しさに重きが置かれる場面では、論理的であることを求められます。論理的整合性が取れていないものは誤っている可能性が高く、根拠が弱かったり話の辻褄があっていない意見は、正しいことを求めるところではだいたい無視されるでしょう。ただし偉い人が言ったら別ですけど。 議論が論理的か非論理的かは、話を聞く人が判断しますが、われわれはどうやって話の筋が通っているかどうかを判断しているんでしょうか。現実にはもっと大雑把にやっていますけど、理想的な場面を仮定して、数学の証明のように推論規則を守っているかをひとつずつ確認しているとしましょう。ひとつの文が論理的に妥当化どうかって、わたしたちはどうやって判断していますかね。見たら分かるとしか答えようがないと思うんですよね。 例えば「A
仕事の出来栄えは、どのような順番でサブタスクをこなしていくか、考えていくかで大きく変わってくるように思います。もちろん、やる順番が唯一の説明変数ではありませんが、安定した仕事ができる経験豊かな人と、そうでない未熟な人、この二者の間では、明らかに手をつけていく順に違いがあります。 一般的に経験の浅い人たちは、どうやるのか想像がつきやすくて、簡単に手をつけやすいところから始める傾向があります。そして、手をつけ始めたところに夢中になってしまい、考慮していないところに大きな落とし穴があることに気づきません。後々になって問題が明らかになって、手戻りをしたり、いびつな状態で無理やり終わらぜなるを得なくなったりします。この結果、仕上がりは悪くなるのはよくあることです。 例えば、経験のない人が、設計をしてみたら、全体的には穴だらけなのに、一部はやたらと細かくなります。決まって、どこまで細かくしていいか分か
オブジェクト指向プログラミングは失敗だった――以前から思っていました。 okuranagaimo.blogspot.com オブジェクト指向プログラミング (OOP) が人類にとって早すぎたか、人類には OOP が向いていなかった。世の中の Java で作られたプログラムのほとんどは、Java に付属する OOP っぽい機能を使うことで余計に複雑になっているように思います。ここでいう複雑さとは、頭が整理されていない状態、頭が構造化されていない状態のことです。例えば、インスタンスなんて作らずに全部 static メソッドでベタ書きされた方がよっぽどわかりやすいのに、それができてしまうからという理由で要らぬ副作用、すなわちオブジェクトの状態の変化が入りこんで、おかしなことになっている様子に出会ったことは何度となくあります。 おそらく原始的で単純な OOP で作られたプログラムはそこまで問題では
static おじさんと呼ばれる人がいたそうだ、あるいはいるそうです。インスタンスの生成を嫌がって、何でも static メソッド にしてしまう人のことです。static メソッドと呼ぶよりも関数と呼んだ方がよいかもしれません。 インスタンスの生成を嫌がるのは、気持ちはわかります。メモリ管理が GC 任せで、速度にどう影響するかわからないのが嫌なのでしょう。現在では、細かいメモリ管理が本当に必要な場合はほとんどないので、ほとんどの場合インスタンスの生成なんて無視してよいでしょう。しかし、ひとつひとつの処理に対してコスト感覚を持つこと自体はよいことです。問題があるとすれば、その感覚が誤っていることでしょう。 ただ、おそらく static おじさんと嘲笑されたのは、コスト感覚の誤りからよりも、未知のものがわからない、覚える気がない態度からでしょう。いつか私も Java おじさんとか Linux
モジュールが疎結合になっているとか密結合になっているとか、業界にいますとよく聞きます。モジュール間の結合度の定義を発見したのでメモしておきます。 モジュール の モジュール に対する結合度 は以下の式で定義できます。 ここで、 は が に対して持つ仮定の集合、 は仮定 が成立しなくなる確率です。 要するに、これは情報エントロピーを用いて結合度を定義しようとしていまして、 は0以上の値を取り、結合度の値が大きいほどモジュール間の結合が密となります。 そもそも、モジュール間の結合度というものが定義されていなかったので、その定義を発見したことに意味があります。 さらに、この定義が便利なのは有名な設計原則を説明できてしまうことです。以下のようなものを聞いたことがあると思います。 デルメル原則 リスコフの置換原則 ハリウッド原則 驚き最小の原則 これらはだいたい同じことを言っています。依存する側が持
仕様とはわかりくい概念です。辞書には次のようにあります: 製品や注文にあたって、あらかじめ定める仕上がり品の構造やデザイン。 仕様は発注者が定めて、受注者がそれに従うもののようです。仕様書を固めて、そのとおりに製造し、仕様書と照らし合せて完成品を検品する。一度つくっておしまいという工程であれば、これが全てでしょう。作って動いてで全てであれば仕様書なんて納品されたら燃やしてしまっても問題ないはずです。実際そういうスタンスのいい加減なところだと、仕様書は適当に共有フォルダに放り込まれて、管理もされていないでしょう。 しかし、仕様は実装を行う人や検査を行う人だけが参照するものではありません。仕様は、作る人だけでなく、使う人も従わなければならないものです。仕様として定められていることが満足されることを期待してよい――という約束事が仕様です。つまり、仕様とは利用者と提供者の「契約」です。契約とは双方
Bloom Filter を実装してみた。簡単な実装なので、速度や空間効率は悪いです。 Bloom Filter というのは、確率的データ構造の一つで、ある要素が集合に含まれるかどうかを試験するものです。空間効率が非常に良いのが利点で、偽陽性、つまり集合に含まれない要素もあるとしてしまう場合があるという欠点があります。偽陰性はありません。 以下が実装例です。 import hashlib import math class BloomFilter: def __init__(self, num_item, false_positive): assert 0 <= false_positive <= 1 # Optimal number of bit array size and hash function # https://en.wikipedia.org/wiki/Bloom_filt
プログラムにはレイヤーというものがあります。レベルとも呼びます。プログラムというのは人間の理解を超えて複雑なものなので、全容を知るということは人間には出来ません。理解できない複雑なものを理解するために、人間には便利な思考法が備わっています:抽象化という思考法です。抽象思考がどういうものなのかは、説明が長くなるので、ここでは省きますが、プログラムの世界もレイヤー化という一種の抽象思考によって驚くほど複雑なものが作られてきました。一般に、カーネルなど生の機械を触るプログラムを低レイヤー(低レベル)と言い、アプリケーションの画面など人間に近いプログラムを高レイヤー(高レベル)と言います。 ソフトウェアエンジニアとざっくり呼ばれますが、レイヤーごとに仕事をしている人が異なります。高レイヤーのエンジニアはアプリケーションエンジニアと募集されていることが多いですし、比較的低レイヤーのプログラミングは最
歴史は繰り返しでアナロジーがあるから面白い。ソフトウェアのアーキテクチャの流行りを調べてみると同じようなことを言葉を変えて繰り返している。切り口はいろいろあると思うが、今日はアーキテクチャという切り口から見てみる。 ソフトウェアのアーキテクチャはコンポーネントとかモジュールが疎結合になったり密結合になったりを繰り返している。 一般にソフトウェアの部品は疎結合な方が保守性が高い。理解しやすいし、テストもしやすいから品質も高い。再利用性も高いので、生産性も高まる。それに、美しい。人間の頭に合わせて行くと、ソフトウェアは疎な方向に向かっていく。小さく分割されて整理されていなければ人間は理解できない。ソフトウェアは保守にとにかくコストがかかるということは経験として知られている。ソフトウェアを人間が理解できなければ保守できないが、人間の理解というものは非常にコストがかかることだ。コストを抑えたいとい
前回に続いてBashネタで、Bashで排他ロックを取る方法について。 並行プログラミングをしようとするならば、排他は必要となる。シェルスクリプトでも並行性について考慮しなければならない場面があるが、アトミックにロックを取る手段はシェルスクリプトだけでは無理で、OSの機能に頼らなければならない。 3つのやり方を見つけたので、メモしておく lockfileコマンド flockコマンド 自前のコマンド lockfileコマンド lockfileというコマンドがある。ただし、必ずしもどの環境にあるとは限らない。 LOCKFILE="/tmp/example.lock" lockfile "${LOCKFILE}" # 排他したい処理 rm -f "${LOCKFILE}" 上のようにLOCKFILEというファイルをlockfileコマンドでつくって、排他したい処理を行い、最後にLOCKFILEを削
CAP定理という分散ストレージシステムの設計において非常に重要な定理がある。まだ、以下の元の論文を読んでいないので、正確な理解かどうかは保証できないが、理解している範囲で考えることを記す。 https://www.comp.nus.edu.sg/~gilbert/pubs/BrewersConjecture-SigAct.pdf CAP定理によると、分散システムでは以下の3つを同時に満たすことはできない: Consistency 一貫性、 Availability 可用性、 Partition tolerance 分断耐性。 それぞれ、 all nodes see the same data at the same time, every request receives a response about whether it succeeded or failed, the system
ncatという超便利コマンドを恥ずかしながらいままで知らなかった。HTTPプロトコルを学ぶには最適なおもちゃだ。 www.example.com の 80番ポートに、 / を GET するという HTTP リクエストを投げてみる。 fjk@x240:~$ ncat www.example.com 80 << END GET / HTTP/1.1 Host: www.example.com END すると、以下のような HTTP レスポンスが返ってくる。200番のステータスコードが帰ってきているので、リクエストはうまいこといったようだ。いろいろヘッダーフィールドについているが、こう見ると HTTP プロトコルはテキストを送って返すだけという非常に単純なプロトコルなことが分かる。 HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: max-a
他の人が書いていたら読めるけれども、知らなければ書けない定型的なソースコードの型を集めているので気が向いたら書いていく。ダジャレが好きなので、コード型ログと呼ぶ。今回は1回目。 無限ループを持つスレッドはinterrupt()で止められるようにする。 package org.example.katalog; public class InterruptSample { public static void main(String[] args) { Thread t = new Thread() { @Override public void run() { // interruptされるまで、"Hello world"を出力し続ける。 // なお、isInterrupted()は呼ぶとフラグがクリアされてfalseになる。 while (!isInterrupted()) { Syste
新しいソフトウェアメトリクスを思いつきました。 ソフトウェアメトリクスとは、ソフトウェアの特性を推定するための定量値のことです。バグの数とかレビューの時間とか開発の過程で得られる値もありますし、テストの数だとかカバレージといったテストを評価する値もあります。ソースコード自体から測定されるものとしては、LOC (Line Of Code)やCyclomatic Complexityがよく知られています。それぞれ、ソースコードの規模・複雑さを示すものです。*1 近年では、ソフトウェアの特性としてソースコードの可読性が重要視されるようになっています。ソースコードは書く時間よりも読まれる時間の方が長い。読むための労力が少ないソースコードは、生産性を向上させ、バグも少なくなります。 可読性を高めるためには、適切な名付けやコメント、明快な処理のフローが必要です。名付けやコメントについては、数値化するこ
オブジェクト指向でプログラムを作れば再利用性が高くなるというのは誤りだったと思う。オブジェクト指向プログラミング(OOP)についての本を呼んでいるとOOPは再利用性が高いというようなことが書いてある。すでに結論が出ている話な気もするが、これは必ずしも正しくないと思う。 正確には、OOPは結果として再利用性は高くすることもあるかもしれないが、それを目的にするものではないと思う。素直に作れば良いものを変に欲出して再利用性とか言って作ったら、そのプログラム内でも使いづらいし、他のプログラムになんか流用したくないものが出来てしまうだろう。 クラスの意味・役割は、プログラムの目的――ドメインって言うのか?――によって異なる。十得ナイフなんて作ろうとしたら、鉛筆削りにすら使えないものができるのでやめたほうがいい。特定のドメインのためのプログラムが他のプログラムに使いまわせることってあんまりないと思う。
興味深い記事を見つけた。 Cyclomatic Complexity and Lines of Code: Empirical Evidence of a Stable Linear Relationship http://dx.doi.org/10.4236/jsea.2009.23020 コードの行数(LOC)と循環的複雑度には強い相関があるとのことだ。 循環的複雑度とは、プログラム内のif, for, whileといった制御構文の数に1を足した数である。つまり、プログラム内の分岐の数を示している。分岐の多いプログラムは複雑度が高く、分岐の少ないプログラムは複雑度が低い。サブルーチンの循環的複雑度は10ぐらいにしておくのが、最も障害が少ないとのことだ。*1 また、循環的複雑度はプログラム内の分岐の数であるので、C1カバレージを100%にするテストの数と一致している。したがって、単体テス
デザインパターンはオブジェクト指向言語だけのものではない。シェルスクリプトにもデザインパターンの概念は適用可能です。 Strategyパターンとは、アルゴリズムを動的に付け替えることができるデザインパターンです。 この概念は決してオブジェクト指向だけのものではありません。Cでもコールバック関数という形で実現することができます。 シェルスクリプトであっても、処理を動的に付け替えるコマンドを作ることができます。例えば、 exec nohup chroot time strace などのコマンドは引数に指定されたコマンドで動きが変わります。Strategyパターンと同じ発想と言えると思います。 こういうコマンドを引数に取るようなコマンドを作ると便利なことが多い。例えば、前処理と後処理を共通化したいときに有効かと思われる。 以下は例。 function do_between_before_afte
コードの品質のスカウターをどうにか作れないかと考えていて、ソフトウェアメトリクスについて調べている。 古い記事ですが、読んだのでメモ書きする。 Robert Martin, OO Design Quality Metrics. An Analysis of Dependencies https://linux.ime.usp.br/~joaomm/mac499/arquivos/referencias/oodmetrics.pdf Instability パッケージ*1の不安定性 (Instability) I は I = Ce / (Ca + Ce) で定義される。ここで、Ca は被依存数 (Afferent Couplings) でパッケージ内のクラス*2に依存しているパッケージ外のクラスの数である。また、Ce は依存数 (Efferent Couplings) でパッケージ内のクラス
最近Bashで凝ったものを作ろうとして、Bashについて結構しらべた。ネット上の情報は散らばっていたので、不完全ながら仕入れたネタをまとめようかと思う。特にカッコについて。 Bashのカッコには以下の種類がある。 { } ${ } ( ) $( ) <( ) >( ) (( )) $(( )) [ ] [[ ]] { } : 複数のコマンドをまとめる 波括弧{ }で複数のコマンドをまとめて1つのコマンドとして扱うことができる。{ }に対して標準入出力をパイプでつないだりリダイレクトして利用する。 例1: fjk@x240:~$ echo "world" | { echo "hello"; cat - ; } hello world 例2: fjk@x240:~$ { for i in {1..3}; do echo ${i}; done; } > 123.txt fjk@x240:~$ c
ちょっと前からモヤモヤしていたこと――HiveやPrestoのようなSQLでHadoop上のデータを集計できるというようなものを使うのだったら、昔からあるデータウェアハウス(DWH)でよくないか? データを扱うにはSQLが、なんやかんやで向いているということが再確認されている。ビッグデータは大量の非構造データのことだとしばし前はいわれていたが、非構造データなんてゴミデータなわけで意味のあるデータは何かしらの構造がある。データがどういう構造をもっていたら整理しやすいかというのは、長年――人類が文字をもったときから――研究されてきた。その結果人類は関係モデルというものにたどり着いた。他にもKey-ValueだとかXMLだとかデータの持ち方は色々あるけれど、やっぱり関係モデルが未だ最強のデータモデルだと私は思う。慣れている人が多いという点と扱いやすいように整理されているという点で関係モデルに帰着
ローマ字入力の効率を向上させる入力法AZIKというものがあります。これを改良したAZITというローマ字入力法を作っています。 Google日本語入力用のローマ字テーブル: mozc_azit.txt 入力方法: README.md 今回は、AZIKのどこをよいと思ったのか、どこが気に食わなかったのか、AZIKに比べAZITは何が優れているのかを記したいと思います。 QWERTYキーボードとローマ字入力 ほとんどの人はPCで日本語を入力する際、QWERTY配列キーボードとローマ字入力を使用していると思います。これらは、いわゆるデファクトスタンダードと呼ばれるものです。当然、Dvorak配列や親指シフトの方が効率は良いのでしょう。しかし、それを下手に採用すると人のコンピュータは触れないし、逆にこちらのコンピュータも人に触れなくなります。QWERTY配列キーボードとローマ字入力が使えなければ、非
テストばっかり書いている。テストコードなんかの綺麗さを追求しても仕方ないかなと思っていたのだけれど、適当に書いていると重複が多くて大変で、シンプルに楽に書くコツみたいなのを掴んできたのでメモしておく。JUnitを対象にする。 テストクラスの単位 ユニットテストは機能要件をテストするものだ。非機能要件(性能、保守性、etc)などはテストできない。ユニットテストを書けるようなコードは保守性も上がるし、テストがあるコードは壊せないのでチューニングもしやすいというのは事実だろうが、これらをユニットテストで確認することはできない。 機能をテストするのだから、JUnitのクラスは機能(function)ごとに分けるのが自然だ。基本的にはクラス・メソッドごとになるかと思う。普通は機能ごとにクラスがあって、そのサブ機能がメソッドになっているものでしょう。したがって、クラスとそのテストのクラスは1対多にする
まだまだオブジェクト指向を極めたわけではないのですが、最近気になったこと。 オブジェクト指向の継承はメソッドを使いまわすためにあるのではないということです。 Fooというクラスがあって、BarというクラスがFooを継承(inherit)しているとする。つまり、Bar is a Fooとなっている。 このとき、Barに求められるのは、Fooと同じメソッドを持つということだけではない。メソッドの動作は変えても良いが、意味は変えてはならない。プログラム内でFooクラスを使っているところをBarに置き換えても、Fooを使っているつもりで動作しなければならない。 これを守ろうと思ったら、継承はむやみにできなくなると思うです。 ただメソッドを使いまわしたいだけなら継承ではなくて、委譲(delegate)をするべきなのです。例えば、Fooを継承したBarというクラスがあったとして、他にFooを継承したク
「Jupyter」という主にPythonのためのWebベースのシェルに感動した。 インストールと起動 Ubuntu14.04なら、 $ sudo apt-get install build-essential python3-dev $ sudo pip3 install jupyter でインストールできるはずです。 $ jupyter notebook と打つとブラウザが開きます。 Pythonパッケージが足りなくて起動できないときは、 $ sudo pip3 install で適宜追加します。 Notebook 右上のNewボタン → Python3で「Notebook」というシェルが開きます。 %matplotlib inline と入力してShift + Enterを押すとmatplotlibのグラフがブラウザ上に表示されるようになります。こんな感じ SympyというMathem
Paxosという分散システムでconsensusを取得するアルゴリズムがある。複数台のマシンから構成されるシステムで、単一のproposalが共有されることを保証するものである。ネットワークが不安定だったりシステムを構成するマシンが落ちたりするので、複数台のマシンが情報を共有するというのは難しいものなのだ。 Leslie Lamport*1の『Paxos Made Simple』を読んで勉強中です。 証明は非常に難しいらしいが、アルゴリズム自体は単純です*2。以下に、記事からPaxosアルゴリズムの流れを引用します。 Phase 1. A proposer selects a proposal number n and sends a prepare request with number n to a majority of acceptors. If an acceptor recei
プログラミングにはレベルの低い・高いがある。ここでいうレベルとはCPUとかストレージデバイスといった生のハードウェアに近いかという意味である。レベルが低いほど生のハードウェアを意識しなければならない。カーネルは低レベルなソフトウェアの代表である。高尚かどうかと混同されることを嫌ってか、低レイヤ・高レイヤという言い方も良くする。私はあえて混同させたくてレベルという単語を使用している。 私は元々低レベルのプログラミングの方が計算機を操ってる感があって好きだった。しかし、しばらく離れてJavaとかPythonとか高レベルなことをやっていたが、ふと低レベルのところを再び触りたくなったので、 ハッカーのたのしみ Binary Hacks Cプログラミング高速化研究班 等を読み返しながら勉強している。低レベルはちょこちょこっとチューニングするだけで演算が高速化していき、ハッカー感が得られるので楽しい。
「Infrastructure as Code」という言葉を良く聞く。基本的にはバズワードは好まない。馬鹿だと思われるからだ。 ビッグデータという言葉は嫌い - 超ウィザード級ハッカーのたのしみ しかし、Infrastructure as Codeは好きだ。言葉というより、コンセプトに同意する。 機器の設定なんて機械にやらせた方がいい。SIという業種がある。計算機システムを構築する仕事だ。設計書や手順書を作るところは人しかできない。しかし、設計書や手順書は人に読ませるために書かれる。機械が読めるように設計書や手順書を書いて、機械に機器の設定をやらせるべきだ。 機器の設定なんて人がすべきことではない。その手間を省いた方が人類は幸せになれる。人間にやらせたら不正確だし、遅いし、手間賃もかかる。やる人もつまらない。つまらない仕事はfeeも少ない。*1 機械が読めるように設計書・手順書を書いて、機
ソフトウェア開発はリリースごとに差分を積み上げていくのが一般的なスタイルです。最初に動くものを組んで、リリースしたあとは触らずに放置されるべきものではない。周囲の環境の変化に合わせて要望があるので、ほとんどの場合は動くものをベースにして、新しい機能なりを追加してというのを繰り返します。 既存のコードベースに差分を積み上げる改良開発は、新規開発と比べて、難しいというか厳格なものです。最初はやっぱりワーっと統制のない状態で作られても完成までは何とかたどり着けます。超人的なエンジニアが独力で作り上げたって伝説が残ってたりしますね。完成までたどり着けない場合もありますが、それは今回議論したいことではありません。一方で、そのような新規開発と比べると、追加の開発は既存のものと整合性をとったり、既存のものを壊さないように気をつけたりする必要があるので、それなりに厳格な変更管理のプロセスが必要になります。
次のページ
このページを最初にブックマークしてみませんか?
『超ウィザード級ハッカーのたのしみ』の新着エントリーを見る
j次のブックマーク
k前のブックマーク
lあとで読む
eコメント一覧を開く
oページを開く