はてなキーワード: 名前空間とは
プログラミング言語側に組み込まれている「型」だけでなく、プログラマーが独自に「型」を定義する方法も用意されています。
struct、class、interface、type, enumなどを使って独自の「型」を定義します。
開発しているソフトウェア独自の「型」は、ドメインモデルの要素になります。
多数の「型」を分類し、組織化するために名前空間を利用します。
近年「クラス」が「型」の定義であるという基本概念を理解していないエンジニアが増えているので、エンジニアを採用する際には注意しましょう。
ソフトウェアを起動すると、メモリ上には、たくさんのデータを読み込まれます。各データには、データの種類を表す「型」が割り当てられています。
例えば、ゲームならばCartという大分類の「型」を用意し、その要素としてMarioCart, LuigiCartという「型」を用意します。
業務システムならば、Reportという大分類の「型」を用意し、その要素としてCostReport, SalesReportのような「型」を用意することになります。
これらの大分類の「型」と、要素の「型」は、is-a関係にある、といいます。
CPUは機械語しか理解できません。一方で人間は機械語でプログラミングすることは困難です。
人間が「1ドル」のつもりで、メモリに「1」と記憶させても、CPUは「ドル」だとは扱ってくれません。
CPUは、「円」のつもりで記憶させた「1」と、ドルの「1」を区別出来ないので、そのまま足し算などの演算を実行してしまいます。
そこで、人間にとってプログラムを読みやすくすることと、CPUに意図しない演算をさせないために、データの種類を表す「型」という概念がプログラミング言語に用意されるようになりました。
金融やECサイトなどのお金の計算間違いが致命的なシステムでは、1ドル、1円を整数型などで扱うのではなく、予期せぬ演算が実行されないように「ドル型」、「円型」という「型」を定義します。
メモリ上のデータがどの「型」に属しているのか、という集合論の話でもあります。
例えば、猫型のデータは、動物型という大分類に属する、という集合の話です。
オブジェクト指向プログラミングの「is-a関係」は、集合論に由来するメモリ上のデータ(オブジェクト)の分類の話です。
プライベートなメソッドや関数をテストする必要は無いと考えています。プライベートなメソッドは、実装の詳細であるからです。
ほとんどの場合、プライベート メソッドをテストする必要はありません。 プライベート メソッドは実装の詳細です。
「プライベートメソッドはテストするな」と強く主張されるのは、ケント・ベックの影響もあるかもしれない。
例えばtwitterで、パブリックメソッドにだけテストを書き、テストが必要なほどプライベートメソッドが複雑ならそれを別のオブジェクトに切り出す必要があると発言している(twitter/kentbeck)ように、プライベートメソッドのテストに強く反対している。
またベックの書いたSUnit(xUnitの源流にあたる)には「ひとつのテストをひとつのオブジェクトで表し、それによってテストの独立性を高める」というアイディアが使われている(そのアイディアを実現するためにとても複雑な設計をしている Simple Smalltalk Testing: With Patterns)。テスト自身がひとつのオブジェクトとして独立しているなら、テスト対象となるオブジェクトのプライベートメソッドがテストできないのは当然のことになる。
が問題になる。
テストファーストで開発するなら手を動かしながら軽い気持ちで書きたい。
privateなルーチンの自動テストは面倒だ。実際にコーディングするときは最初publicにしておいてテストしてうまく動いていそうならprivateにするのだけど、この「いそう」がくせ者。いっそのことすべてpublicにしたくなる。
私は元々メソッドはprivateにしない主義なのでメソッドの場合は問題ないのだけれど、ファイル内の「関数」が問題になる。和了点計算だと和了形判定とか符計算とか和了役判定とか単体でテストしたい内部関数が山ほどある。(twitter/koba0367)
private メソッドをテストすべきか問題、原則論だけだと袋小路に入りがちだから、private メソッドをテストしたくなる具体的な場面について議論したほうがいいと思う。
自分がレビューでよく見る例としては、複数の public メソッドの重複部分を private メソッドに抽出した結果、濃い private メソッドと薄い public メソッドが一対多関係になる場合が挙げられる。設計としては間違っていないし、わざわざ public メソッド経由でテストする意義があるかというと微妙。(twitter/ts7i)
きれいなインターフェースを作ろうとすればするほどpublicメソッドじゃない部分に複雑性を追いやることになり、壊れた時に手戻りが大きすぎると思ったら、プライベートにバックドア開けてでもテスト書くようにしてます (twitter/mizchi)
しかしプライベートメソッドに対するテストを書こうとすると大概リフレクションなどで可視性の制限をすり抜けるとかメソッドの可視性を変更するといった回りくどさやコストの導入が必要になるので、じゃあプライベートに対するテストはそうしたコストに見合うのかが問題になる。
伊藤さんの答えは「原則書かないほうがいいという大前提のうえで、どうしてもというときは、"これはテストのためにpublic"にしているというコメントの上でpublicにする」だった。
自分は「テスタビリティのためにメソッドをpublicにする」っていう"実プログラムの挙動を変えること"の方が、「privateなメソッドをテストコードのみsendで叩く」よりも怖いって思ってることに気がついた。(twitter/highwide)
単体テストがホワイトボックステストだとするなら、publicかprivateかでテストの有無が変わるのは明らかにおかしいだろ。ややこしいロジックはprivateに隠蔽すべきだが、そこがテストできないなんて。 (twitter/kmaebashi)
private メソッドをテストするかどうか? まず最初に言っておきたいのは public/private は抽象の設計の問題であって、テストすべきかどうかとは当然無関係だろうということ。(twitter/qeigoi)
特定の言語の貧弱な機能に思考が制限を受けて誤った結論を出している典型的な例。
https://b.hatena.ne.jp/entry/4684049296462116226/comment/megumin1
テストの粒度とメソッドのアクセス権は独立したものなので、「プライベートメソッドをテストすべきか否か」という切り方自体がナンセンスではあるのだが、現実問題としてはアクセス権がテストに影響するので難しい。(twitter/AoiMoe)
private メソッドのテストはすべきかどうかというより、「できるべき」であって、それができないというのも、ある種、言語機能とテストのインピーダンスミスマッチと言えるのではないだろうか、と思っている。(twitter/aetos382)
RustやGoではプライベートメソッドに対するテストが簡単にできる。
そのためかプライベートメソッドをテストすることに対して拒否反応があまりないようだ。
Rustのテストはファイル内とtests/以下の2箇所に書ける。
テストには開発用のホワイトボックステストと仕様確認用のブラックボックステストがあり、前者をファイル内に、後者をtests/に書けば良い。
例えば度々議論になるプライベート関数のテストについてはもちろんホワイトボックステスト。(twitter/blackenedgold)
Rustではプライベートに対して何の手間もなくテストが書ける。
Rustでprivateなメソッドのテストを書きたいなら、そのメソッドのすぐ隣に書けば内部アクセスになるから普通に書けるよ、ってのは目からウロコだった。できるだけ近いところにテストを書こうっていう文化と相まって最高。(twitter/kuy)
Rust のようにユニットテストをプロダクションに混ぜる方式はおれもいいと思ってて、テストとプロダクションを分離することで private 関数のテストができない問題があるけど(テストしたければクラスを分けよ/メソッドを公開せよ/テスト必要なし、に分かれるよね)、そもそもこの議論が不要になるよね (twitter/nunulk)
昨日「private method の単体テストは書くか否か」という話題がちょいとあったのだが、わしは当然書く感じの昨今を送ってきたもんで何で書かんのやくらいに思ってたんだけど、Go だと private なやつのテストが書きやすいってのがデカそう。(twitter/pankona)
golangのテスト書いてたけど、テストプログラムの名前空間(パッケージ)が、対象のプログラムと一緒で、そのためプライベートメソッドでもテストできるの良い感じ (twitter/74th)
Goのテストコード、テスト対象と同じパッケージにすればエクスポートしてない関数でもなんでもテストコードから参照できるんだけど、これってプライベートメソッドはテストすべきか議論するよりテスト書けと言われているようで好き。(twitter/plan9user)
「プライベートメソッドをテストするか?」とは別に「ドキュメントをソースコードと同じファイルに書いていい(文芸的プログラミング)なら、単体テストをテスト対象と同じファイルに書いてもいいのでは?」というのも論点になるかもしれない。
プログラミングできる気になった自称中級者は、ソースコードに共通のパターンが現れると決まって、その処理を関数などに共通化したがる。
たしかに、そうすることでソースコードは短くなるし、一見して保守性が上がったような気になるのだが、それは間違った作法だから止めろ。
細かいこと言っても伝わらない自称プログラマが読んでることを想定して、先に結論を簡単に書いておく。
なぜコードを共通化するのがいけないのか。理由は簡単だ。要するに、コードが似ているのは単なる偶然であって、それらは別の処理だからだ。
別の処理だから共通化するのはおかしいし、もし共通化した処理の一方のみ仕様が変わった場合、その修正は他方にも影響してしまう。つまり、保守性が下がっている。
たとえば、同じプロジェクトの中に、10%の消費税を加える処理と、10%の金利を加える処理があったとする。この2つの処理はともに元の金額を1.1倍する処理であり、全く同じ処理であるが、共通化してはいけない。
これらを共通化してしまうと、たとえば金利が8%に変更になったとき、金利計算の処理だけではなく、消費税を計算している箇所すべてを変更しなければならなくなる。
実際のアプリケーションでやりがちなのは、複数の処理の「事前処理」「事後処理」などを1つの関数にして、呼び出し毎に細かい挙動を引数で制御するようなパターンだ。
これは結局、改修を重ねる度に「事前処理」「事後処理」の内容が使用箇所によって全く異なるものとなり、それに対応するために
他にも、GUIアプリでユーザーの応答を待つDialogクラスなんてものを作って、使用箇所ごとにメッセージやボタンに割り当てる処理などを切り替えることがある。
これも間違いなく、プログラムが成長するにつれて破綻する。たとえば、ある場所のダイアログは、表示するメッセージがテキスト形式のみではなくなり、脇に画像を表示するかどうかのフラグをコンストラクタに渡したり、Dialogを継承させて表組みを表示するTableDialogサブクラスを作ったりすることになる。ボタンが「OK」と「キャンセル」の2種類の場合じゃなくなって、表示するボタンの数をコンストラクタに渡したり、ボタンに割り当てる処理をリスト形式で渡したりし出す。
こうして、最初は良い設計に見えたDialogクラスはどんどん複雑になる。こうなった原因は明らかで、本来は異なるものを共通化したからだ。おかしな色気を出さずに、素直に別々に実装しておけばよかったのである。
プログラミングをする上で「コードを共通化する」なんてことは意識しなくていい。それよりもプログラマがすべきことは、処理に適切な名前をつけることだ。そのプログラムにおいて「単なる変数の操作」を超えた意味のある処理には名前をつけろ。そして、同じ意味の処理なら同じ関数を使うし、違う処理なら違う関数を使う。それだけだ。コードが共通化できるかどうかなんて全く関係ない。
変数、関数、クラス、名前空間等が再利用のための機構だという先入観は一旦捨てろ。それらの真の意義は、「関心の分離」にある。つまり、実装を隠蔽し、その意図を抽象するために存在する。たまに勘違いしてる奴がいるが、別に1回しか使われない関数とか、1行しかない関数はあってもいい。というか、この原則にしたがって設計すると、ほとんどの関数(or メソッド)は数行になる。
上の消費税の例で言えば、「消費税を加える」「金利を加える」処理は、明らかに単なる算術演算以上の意味のある操作だから、関数化する。そして、それぞれの実装は当初の仕様では奇しくも全く同じになる。消費税を加える箇所では前者の関数を呼ぶし、金利を加える箇所では後者の関数を呼ぶ。
これはこう言い換えることもできる。消費税を加える関数を変更するのは、消費税の計算処理が変わったときのみであり、金利を加える関数を変更するのは、金利の計算処理が変わったときのみである。つまり、すべての関数は、それを変更する理由がただ1つになるように設計しろということだ。
こういうアプローチでプログラムを書くと、ソースコードはあたかもそのアプリケーションのドメイン特化言語で書かれたかのような見た目になる。
また、一つ一つの関数は小さく、理解しやすく、テストやデバッグも容易になる。そして、結果として再利用もしやすくなるし、プログラムの変更も容易になる。
今日Container Runtime Meetupという勉強会に参加させていただいたのだが、KubernetesにContainerに詳しい第一人者による神々の集いに目がくらみそうになった。
ここにいる人たちを除いたら、日本でどなたがContainerに詳しいといえるのかわからない感じの人たちが一堂に揃っている。技術書典で池袋ジュンク堂でGitHubのissueで名前を見たことがある人たちがいる。
Organizerにいらしゃったので来るかもしれないと期待していたgVisorの中の人たちがいないのが寂しいくらい。
そんな人たちによる登壇者の話がrunc runのから始まったのはまだいい。予告があったり、自分は途中でinit処理にわけわからなくなった下地があったので。少なくともその後について腑に落ちたのだ。
だが、そこからいきなりnsexec.cに行ったのは突き放された感じがしてひたすらうなづくしかなかった。
Kushwahaさん。goのimportで定義されることにより本文が呼ばれる前にプリ実行されるCライブラリで名前空間を作成している、そのライブラリの処理の解説が行われた。
https://github.com/opencontainers/runc/blob/master/libcontainer/nsenter/nsexec.c
もうここで、unshare?unshare what?という気持ちになって、あー空のnamespaceを作成できるコマンドかと腑に落ちる暇もなくSudaさん。
ライブラリの実装と呼び出し方法について実際に処理を書いた人が、直直にケースごとのnamespace()の使い方の解説をするのだ。
こんなの後にも先にも一生聞けないだろう。聞き逃すまいと望んだが、MountNSの話は正直セキュリティ懸念があるのね、だから実装=サポートも積極的にされてないということしかわからなかった。
ファイル、ディレクトリ一つ一つのアクセス権限の付与をプロセスIDごと振り返る必要があって、それを高速にできるfsがsysfsという認識であってるのだろうか...自分でも何を言っているのかメモを見返しても呪文にしか読めない。
その後もsd_notifyをruncから呼んでいることに端を発したコンテナ起動待ち処理をどう実装するかという議論やら、某ベンダーさんによるruncをガチ運用している環境下でftraceを使ったデバッグの実演やらもうこの夜ここでしか聞けないような話ばかりで。
祭りが終わった後、ほとんどの人が帰らずに、会場となった台所みたいな食卓を囲んでフリートークを交わしていた。
Cloud Controller Managerを自社内向けに実装する話の相談をしていたり、先ほどの登壇者が同じPCの画面を前に肩を並べてruncのソースコードリーディングを始めたり好き勝手にしてる。
それは正直自分みたいに浅い知識を持った人には、RHTechExchangeで聞いた英語の雑談よりも遥かに遠い世界だった。
名前空間とは何でしょう?
広義の「名前空間」とは、項目をカプセル化するもののことです。
たとえば、たいていの OS はディレクトリでファイルをグループ化します。
この場合、ディレクトリがその中のファイルの名前空間として機能しています。
具体的に言うと、foo.txt というファイルは /home/greg と /home/other の両方に存在することが可能ですが、それらふたつの foo.txt を同じディレクトリに配置することはできません。
さらに、/home/greg ディレクトリの外から foo.txt にアクセスするには、ディレクトリ名をファイル名の前につけて /home/greg/foo.txt としなければなりません。
プログラミングの世界における名前空間も、この延長線上にあります。
名前空間を定義するには、namespaceキーワードの後に任意の空間名を記述します。
namespace 名前空間名;
VisualStudioでローカルで動作するアプリを作ろうと思ってるんだけど
本当に初歩的なことかもしれないことが分からない。
「class」というやつについてだ。
そいつの中には複数のclassさんが存在してもいいのか?SAVACLASSとLOADCLASSが存在しても良いのか?
public class Person { public string name { get; set; } public int age { get; set; } } public class Office { public string name; public ObservableCollection<Person> persons; } private Office office; private void init() { office = new Office(); office.name = "オフィス"; office.persons = new ObservableCollection<Person>(); office.persons.Add(new Person { name = "001", age = 11 }); office.persons.Add(new Person { name = "002", age = 22 }); office.persons.Add(new Person { name = "003", age = 33 }); }
OFFICEという属性にはPARSONというものが集まってて、そのPARSONの情報にはNAMEとAGEがありますよ!というのは分かるんだけど
シリアライズも、デシリアライズも、「圧縮⇔解凍」みたいなイメージしかないし
うーん。難しい。
クラスって何なんだ。VBA風に説明できる人いない?(VBAでもClassは使わずにFunctionとSUBだけ使い回してた)
プログラミングを教えててよく分かるのは、ちゃんと論理的な思考が出来ているかどうかを計る道具として非常に有用だということ
口先だけで乗り切ってきた人はプログラミングを教えてもちゃんと理解してくれない
知識化するときに表面上だけを理解することに慣れきってしまっていて
だからプログラミングを教えて新しい物を作らせようとすると全然作れない
例えば
def hoge(a, b): c = a + b return c def gaga(a, b): print("Hello ", a, b)
っていうソースがあったとして、gagaっていうメソッドをhogeの演算結果が表示されるように変更してみよう、っていうことをさせると
def gaga(a, b): print("Hello ", a, b, c)
って答える。
もちろんスコープとか名前空間とか、そもそもそれが生まれてきた経緯とかメソッドの意味とかはちゃんと教えてるんだけど
それでも理解してくれない
この問題に関して正解を教えると、この問題は解けるようになるが、しばらくすると似たようなミスを連発する
一方で論理的な思考が出来る子は全然分野違いから来てる子でもそんな間違いはしない
頭の中を整理して理解しているからなのか、とんでもない間違いはほぼない
入試とか面接だと両者の区別は付かないし、下手したら普段の業務でも顕在化しなかったりするんだけど
しばらく一緒に仕事をしたりすると
「あ、なんかそもそもを分かってない」
っていう子はプログラミングができない
PlayStation JapanのYouTube動画「『 ゴッド・オブ・ウォー』 究極のアクションアドベンチャーの創造3 アトレウスができあがるまで」
https://youtu.be/vxUbSuKRs5c?t=1m4s
の1:04あたりでは
const char* stance const dc::tAIStance if (!pStance || return luaL_error(L, "Stance %s RequestQueue* pActiveRequest = L AISwitchStanceRequest* request = pAc request->SetStance(pAI, pStance); return 0;
というコードの断片が映る.(ただ,上から分かる通り,ほとんどの行は途中までしか映っていない.)
コードにあるluaL_errorはLuaのC APIにある関数である.pStanceがnullptrだった場合などに,この関数を呼ぶのだろう.
.NET Framework の System.Media.Imaging、PresentationCore.dll やらを参照設定に加えたけど、インテリセンスに出てこないぜ。
ついでに MSDN Library
http://msdn.microsoft.com/ja-jp/library/system.windows.media.imaging.tiffbitmapdecoder.aspx