ついつい使ってしまうプログラミングの悪いテクニックは? 188
ストーリー by headless
悪癖 部門より
悪癖 部門より
プログラミングの際に、さまざまな理由でコーディングのルールを破ってしまうことがある。これらは誰もが「悪い」プログラミングテクニックであると認めるようなものだが、結果としてコードがクリーンになり、高速かつシンプルになることもある。InfoWorldの記事では、愛される悪いプログラミングテクニックを9つ選んでいる。
InfoWorldが選んだ悪いプログラミングテクニックは以下の通り。
InfoWorldが選んだ悪いプログラミングテクニックは以下の通り。
- gotoを使う
- 関数名だけで内容がわかるようにしてドキュメンテーションを避ける
- 1行に大量のコードを詰め込む
- 型宣言をしない
- 値の型を繰り返し変換する「ヨーヨーコード」
- 独自のデータ構造を書く
- ループの半ばでループを抜ける
- 短い変数名を使う
- 演算子や関数を再定義する
プログラミング言語や環境によっては使用できないものもあるが、皆さんがよく使うものはあるだろうか。また、リストに追加するとしたらどのようなものがあるだろう。
コピペ (スコア:3)
コーディングのルールなのでちょっと違うか…
Re:コピペ (スコア:2)
あるある。
共通処理考えるのめんどくさいから、まるっとコピペして一部書き換えた程度のものを作ってしまうときあるわ。
Re:コピペ (スコア:1)
>まるっとコピペして一部書き換え
共通処理にとどまらない発展形を実現しようとがんばれば、例えばMDISの図書館システムパッケージのようなしろものが花開くそうです…4年前の旧聞ですけどね。
もっと新しいものがあったら知りたい。
オブジェクト指向的な書き方と、手続き型的な書き方の混在 (スコア:3)
手続き型プログラミングとオブジェクト指向プログラミングの両方が可能な言語の場合、作法が混在してしまうことがよくあります。
大きな実害は無いですが、気分が悪いです。
nullの多用 (スコア:2)
空の値、確定する前の値、適用不能なもの、域外値、例外で返す値、その全てを null で表してしまう。
アレゲなニュースと雑談サイト
Re:nullの多用 (スコア:2)
文語訳舊約聖書傳道之書1:2 [wikisource.org]
傳道者言く 空の空 空の空なる哉 都て空なり
っぽいですね。
大体はやってないけど (スコア:1)
> 6.独自のデータ構造を書く
> 7.ループの半ばでループを抜ける
これって駄目だったんだ?
普通にやってしまってるけど……。
6番のデータ構造を書くっていうのが漠然とし過ぎて、具体的にどんなデータ構造を書いてどのように使ったらどう悪いのかわかんないなぁ。
メソッドを持たないクラスを書いたらそれもデータ構造だと思うけど、それも駄目って事?
構造体だけを言ってるんなら、何故に構造体だけ駄目なのか? ……うーん、わからない。
原文も読んでみたけど、どうも……要約すると
「大体のデータ構造は既に用意されてるからそれ使えや」
って事かな。英語苦手なので解釈おかしいかも知れないけど。
でも、用意されてないデータ構造なんていくらでもあるし……。
もっと原始的な話でリスト構造とかの再実装をするなって言うならわかるし、それは僕も稀にしかやってない。
(標準の連想配列が要件を満たさなくて、色々ごちゃごちゃといじった事がある程度)
あと、ループを途中で抜けるのも。
そんなにコードの可読性下げてるとは思えないけど……。
そう思ってるのは僕だけで、みんな読み辛いのかなぁ?
Re:大体はやってないけど (スコア:3)
単に、既存のライブラリで使える構造体を独自に実装するなってだけかと。
で、余計な機能が付いてる駄目ライブラリなら無視して良いって、原文には書いてる。
あと、ループを抜ける件については、「ループを抜ける理由を書け」って事らしい。
で、フラグ命名に抜ける理由を付けると可読性が上がるよって事だって。
でも個人的には、フラグ乱立の方がよっぽど危険だと思う。ま、この辺はケースバイケースだが。
-- Buy It When You Found It --
Re:大体はやってないけど (スコア:2)
コメントは嘘を書けるから信用に値しないと思う。
で、関数名だけでドキュメントを付けないのは、頻繁にリファクタリングされる場合に、関数名を変えられると何も残らないから駄目らしい。
でも、嘘のコメントはもっと有害だから、上手く使い分けろって事らしい。
-- Buy It When You Found It --
Re:大体はやってないけど (スコア:2)
だから、関数名だけでドキュメントを付けないのは良くないって話なんじゃ。
で、ドキュメント部分を更新せずに機能だけ付加するような改造はするなって事でしょう。
//でも、多くの現場では実行コードしか修正しないからメンテ不能になる
-- Buy It When You Found It --
Re:大体はやってないけど (スコア:2)
プログラミング技法に唯一の正解なんて無い。
改変を多数受けて、更にリファクタリングするものも在れば、そのまま使われ続けるコードもある。
半年後に自分がメンテする場合もあれば、他人が弄り回す場合もある。
つまりはケースバイケース。
で、今書いてるプログラムが何れに該当するかを見極めて最善の手法をとるのが優れたプログラマってだけ。
ま、将来を予測出来る人間なんて滅多に居ないけどね。
-- Buy It When You Found It --
Re:大体はやってないけど (スコア:1)
オレは、まずコメントでプログラム書いて、それを実行するように作るなー。
the.ACount
Re:大体はやってないけど (スコア:2)
6はもしかすると、
「この関数に渡す時だけに適用されるルールがある謎文字列」とか「オレオレJSONモドキ」とかのような、負の遺産まっしぐらなヤツを言っているのかもしれない。。。
7は私もよく使う。
もちろん1ループ単位で綺麗に終了条件が定まるフローを作るのが基本だけど、
「これ以降は処理しないでねフラグ」みたいなのを使うより、途中でぬける方がよほど好ましいと思う。
Re:大体はやってないけど (スコア:1)
冒頭の内容からも、それぞれのルールにたいするコメントからも、「XXXというルールがあるけど、破ったほうが良いときもあるよな!?破っても良いけど上司には黙っとけよ!」っていう記事に読めます。
たとえば、6については、要件を満たす上で標準ライブラリや広く知られているライブラリでは十分でない時に限って、データ構造を当たらしく作っても良いと書いてありますね。
7も同様で、ループの不変条件だけで制御しようとするとgoto禁止と同様な冗長な表現になるので問題だと有ります。
Re:大体はやってないけど (スコア:2)
悪い一例として、
否定な名前を使う。
#defineがあれば、何でも出来る (スコア:1)
#define private public
#include "hoge/hoge.h"
これで秘匿関数呼びたいホーダイ。
Re:#defineがあれば、何でも出来る (スコア:3, 参考になる)
ちなみに、少し前からVisual C++には#define private public対策が入っています。
これをコンパイルすると、このようにコンパイルエラーとなります。
まあ、ヘッダーでの対処なので、インクルードよりあとに#define private publicすると回避できるのですが。
Re:#defineがあれば、何でも出来る (スコア:2)
マクロなら、OKだけど、関数は無理。 (C/C++)
リンク時に相手がいない。
Re:#defineがあれば、何でも出来る (スコア:1)
まあ、それも善し悪しではありますが。
-- To be sincere...
optionalでこっそり引数を増やす (スコア:1, おもしろおかしい)
ごめんなさい
既存の機能を使わない (スコア:1)
「既存の機能を使わない」、いわゆる車輪の再発明。
・日時や時刻の計算を自作ルーチンで行なう
「n日前」だとか「指定日の午前0時ジャストをUNIX秒で」とか「UNIX秒→YYYY/MM/DD hh:mm:ss」とか。
よくみれば、1か月を31日決め打ち(他との兼ね合いでこれでも動く)とか、うるう年を考えていないとか。
・配列やリストやセット(データ構造)の全体の処理をループでやっちゃう
処理順が関係ないものも、mapやfindを使わない。まあ動きますがね。
・SQLで集約せずに、呼び出した言語側で集約する
(上の2つとはカテゴリが違うかも)
何も考えていません (スコア:1)
ググってコピペ。
Re:何も考えていません (スコア:1)
Yahoo質問箱とかokwebとかに質問する。
http://okwave.jp/qa/q2122395.html [okwave.jp]
「上記のようなプログラムを途中まで書いたところなのですが、コードの行数が長く、どうも効率が悪いような気がしています。
このままでは納期に間に合うか不安です。
効率のよいアルゴリズムをご存知の方、教えてください。」
#じ、自分のことじゃないんだからねッ
ところで、最近流行の質問サイトってどこだろう?
Re:何も考えていません (スコア:1)
考えるとコピペしたコードが居なくなるんだよなぁ(ぉぃ
プログラミングの処方箋 (スコア:1)
ストーリーにあるような、効果はあるけど乱用すると害を引き起こすテクニックを
うちでは薬になぞらえて処方箋と呼びます。
処方箋はとある課題に対して目に見える効果があります。同時に、取るに足らない(と感じる)副作用が付随します。
乱用するなどして条件が揃うと、害をなします。複数同時にかけあわせると、思わぬ副作用を引き起こすこともあります。
継続して使うと麻痺して、問題とも思わなくなります。
本物の薬は、医者が症状を判断して病人に処方します。
プログラミングでは、病人が自分自身に処方します。
その結果、症状に合わない処方を使っていることもあれば、逆に、規約などで一律に禁じられ、症状が出ても放置するしかないこともあります。
どちらも不健全です。
プログラミングの世界に医者はいません。
病気があれば自分で調べて治療することが求められます。
悪だが使わざるを得ないテクニックのリストがもっと広まると、苦しむ人が減ると思います。
処方を守って、必要な時に必要なだけ使うのが正しい使い方です。
Re:とりあえずグローバル変数 (スコア:3, おもしろおかしい)
ある新人プログラマー
「変数 i がたくさん定義されていたので
グローバル変数にしておきました。」
余計なことすんな。
Re:とりあえずグローバル変数 (スコア:2)
> 「単純なループ変数をグローバル変数で定義するんじゃねぇ!!」
あ、あった。
どこで定義してる? -- 別ファイルでグローバル定義。
他で使ってる? -- 他では使ってない。
マジックナンバーを書くな --> その都度、定数を定義して使用。
ま、人のあら探しは簡単。
Re:とりあえずグローバル変数 (スコア:2)
#define 機能名_SixTeen 16
...と。
Re:とりあえずグローバル変数 (スコア:1)
#define 本人名_ForeverSevenTeen 17
Re:とりあえずグローバル変数 (スコア:1)
#define daitetsujin 17
#ちゃんと「じゅーなな」でわなく「わんせぶん」と読むように!
Re:とりあえずグローバル変数 (スコア:1)
モーニング娘。'15(ワンファイブ)
って読むんでしたよね。
ということであと2年(何がだ)
-- To be sincere...
Re:書き散らかし (スコア:3)
if (true) { ... }
も忘れないで。
// これはテストコード。リリース時には消す事
なんてのもリリースコードにあった。
最終リリースは何時だったろうか。
do~while(0)でbreak (スコア:2)
goto文やtry-catchの代わりに
do~while(0)でbreak
させると何これって言う人が必ずいる
Re:do~while(0)でbreak (スコア:2)
Re:do~while(0)でbreak (スコア:2)
私も同意見ですが、
CORBAでは例外以外も例外で扱うんですよね。
初めてソース見たときはびっくりしましたが、
タイムアウトでも例外が発生します。
Re:do~while(0)でbreak (スコア:1)
continue くらいになると存在自体を忘れてたり...f(^^;
for文ばっかり使いすぎてて、do - while()が咄嗟に思いつかないことも。
Re:goto文は使い方 (スコア:1)
同意
いまだにgotoは悪だというけど、C言語だと仕様上
goto使ったほうがシンプルでわかりやすくなる箇所は必ずある。
Re:goto文は使い方 (スコア:3, すばらしい洞察)
goto文は(そう書いた方がよい場面というのはあるのだけど、一概に示せるものでもないし、説明したとてもお前は正しく理解して活用出来そうにないから)使うな
Re:goto文は使い方 (スコア:2)
try-catch的に使うとか、ラベル付きbreak的に使うとか、ですね。
try-catch的に末尾に飛ばすのは、リソースの解放忘れを防げるし、常用してる。
Re:goto文は使い方 (スコア:2)
ないから、goto文で代用する;という話ですが、なにかおかしなことを言っています?
try-catch的に (エラー時にretにエラーコードを入れて、関数末尾に飛ぶgotoを) 使う;
ラベル付きbreak的に (多重のfor/switchの中から、外側にラベルを張って そこに飛ぶgotoを) 使う;
とか。
Re:goto文は使い方 (スコア:1)
gotoを使ったほうが良い具合に見やすくなるケースをいくつか見た。
上手く使えばわかりやすくなるけど、考えなく使われるとひどい事にもなるから
内規のコーディングルール上は原則禁止にしときたくもなる
Re:goto文は使い方 (スコア:1)
「gotoをつかってはいけません」に加えて「関数の途中でreturnで抜けるの禁止、というか1関数にreturnは1つだけな」みたいな変な制約つけるところあるけどね。
構造化プログラミングの名の下に。
Re:goto文は使い方 (スコア:1)
そうだと思う。
なぜ、そういう複雑なループ終了条件になるのか、ロジックから見直すことを、まず考えたほうがよいと思われる。
後で何か改変が入った時、ロジックが入り組んでいると、その改変が可能かどうかさえわからなくなる。
Re:カンマ式、3項演算子の乱用 (スコア:1)
たいていは左辺の変数や関数のパラーメタとなる値を計算するために使われるものだから、変数を書き換えたり手続きを呼び出すようなコードは書かない。
文法的には文も書けるけど式しか書いちゃダメって原則を守ればかなりマシになるかと
うじゃうじゃ
Re:カンマ式、3項演算子の乱用 (スコア:1)
で、「b()がエラー返すとなぜかc()も実行される!」と大騒ぎ…。
A「"なんで素直に3項演算子を使わないんですか", a() ? b() : c();」
B「 "elseが要らない時もあるから…";」
A「a() ? b() : (void)0, "で良いでしょうが";」
B「"それなら", a() && (b(), true) || c(), "の方が素直かなー";」
# Lispが俺にもっとカッコ付けろと囁いている
Re:見たくないけどあるあるなコード (スコア:1)
こういうのって, 最近は直接
typedef int16_t hogehoge
みたいに, 名前にサイズを含めた形にすることが多いんじゃないでしょうかね.
20年以上前だと, 周辺機器やCPUのリファレンスマニュアルで “WORD” とかの記述が多かったので, それに合わせてdefineすることが多かったとは思いますが.
Re:テクニック以前の問題 (スコア:1)
分野によって「悪い」が違うので言語を選ぶのはよいけど、問題外と決めつけている内容は場合によると思うよ。
Re:正確にはプログラミングしないテクニック (スコア:1)
なら見たこともやったこともある。
Re:変数とかプロセス名にアニメのキャラクターを入れる (スコア:1)
-- To be sincere...
Re:DBのカラムがんがん増やす人 (スコア:1)
ちゃんと java.util.List の実装クラスを使えってことでしょ。
普通普通。