この記事を読む: 15分
テクニックの理解: 10分
有形の結果: 30分
だから
なんで?
悪いコードはどうですか?
- 何も明確ではありません
- あいまいな変数
- 巨大な方法
- 非自明なアルゴリズム
- カーキのカプセル化違反
- 高度な複雑さと複雑さ
- 変更は驚きにつながる
- 何も明確ではありません
同じ瞬間を二度指摘したのも不思議ではありません。 実際、ほとんどすべては、プログラマーがコードを理解できないという事実に帰着します。

悪いコードはゆっくりと修正され、変更は驚きをもたらします。 これは理解できることです。プログラマーはコードが何をしているのかわからないので、何か新しいものを作成する代わりにそれを把握する必要があります。 実際、作者だけが実際にプログラムを修正できることがよくあります。
したがって、優れたコードの最も重要な兆候の1つは、そのわかりやすさです。 明快さは純粋に人間の概念です。 コンパイラは何と呼ばれるかを気にしません;本質を掘り下げません; コードを読むのは人だけです。 メソッドの名前からメソッドが何をするのかを想像できるのは人だけです。 変数の名前を読んだ人だけが、変数に保存されたデータの本質をすぐに見ることができます。
コードのわかりやすさは名前により依存していると確信しています。 クラス、メソッド、変数の名前から。 名前が明確に定式化されていればいるほど、コードが読みやすくなります。
たとえば、モバイルデバイスに通知を送信するためのコードは次のとおりです。
function locator($device) {
// Can we locate the device?
if ($device->token != "" && $device->expire <= $now) {
return false;
}
$modelNotifier = new ModelNotifier($device);
return $modelNotifier->go();
}
, - . .
-
$device?
-
$device->expire
$now
? ? -
$modelNotifier->go()
?
. , ,
$device->expire
, .
ModelNotifier->go()
, . , , token . , .
, :
token!=""
, . , , .
, . — . , ; , . , .
.
?
, — .
, , , . , — — .
:
function locator($device) {
// Can we locate the device?
if ($device->token != "" && $device->expire <= $now) {
return false;
}
$modelNotifier = new ModelNotifier($device);
return $modelNotifier->go();
}
, , : “ ?”
:
function ModelDevice::isLocatable() {
return ($this->token != "" && $this->expire <= $now);
}
…
function locateAndNotifyDevice(ModelDevice $device) {
if (!$device->isLocatable()) {
return false;
}
$modelNotifier = new ModelNotifier($device);
return $modelNotifier->go();
}
, , - , .
. isLocatable(). : , :
- ?
- ?
: , .
:
function isDeviceExpired() {
return ($this->expireAtUnixtime >= $now);
}
function isOurTokenValid() {
return ($this->token != "");
}
function isLocatable() {
return ($this->isOurTokenValid() && !$this->isDeviceExpired());
}
. :
isLocatable()
, . isDeviceExpired(), , .
— .
, , , token . , : .
, : . Instant win!
?
, . ! , .
-, . , , . , : . , , . . , ? :)
-, - (“ ?”) (“ ?”) .
isLocatable()
, : , . — , . “”
locateDevice()
, ; , , . — , .
-, , CPU, . , — 1/3 *. , , . , . , , . , .
*300ms — .
:
function getConfig() {
if ($this->hasOption('configs')) {
$configs = $this->getOption('configs');
} else if ($this->hasOption('config')) {
$configs = [ $this->getOption('config') ];
}
if (isset($configs)) {
$root = $this->getOption('root', null);
if (!$root) {
if (isset($_SERVER['PWD'])) {
$root = $_SERVER['PWD'];
} else if (isset($_SERVER['DOCUMENT_ROOT'])) {
$root = $_SERVER['DOCUMENT_ROOT'];
}
}
$configs->root = $root;
}
return $configs;
}
: ( ), . :
function grabConfiguration() {
if ($this->hasOption('configs')) {
return $this->getOption('configs');
} else if ($this->hasOption('config')) {
return [ $this->getOption('config') ];
}
}
function figureOutRootFolder() {
$root = $this->getOption('root', null);
if (!$root) {
$root = $_SERVER['PWD'];
}
if (!$root) {
$root = $_SERVER['DOCUMENT_ROOT'];
}
return $root;
}
function getConfigs() {
$configs = $this->grabConfiguration();
if (!is_null($configs)) {
$configs->rootFolder = $this->figureOutRootFolder();
}
return $configs;
}
iOS:
if ([imageEntry objectForKey:@"fullscreenUrl"]==nil) {
NSString *kind = [imageEntry objectForKey:@"kind"];
if ([kind isEqualToString:@"pdf"]) {
UIImage *i = [UIImage imageNamed:@"galleryPdfIcon"];
[self.uiImagesCache setObject:i forKey:@(photoIndex)];
*photoSize = NIPhotoScrollViewPhotoSizeOriginal;
return i;
} else if ([kind isEqualToString:@"video"]) {
UIImage *i = [UIImage imageNamed:@"galleryVideoIcon"];
[self.uiImagesCache setObject:i forKey:@(photoIndex)];
*photoSize = NIPhotoScrollViewPhotoSizeOriginal;
return i;
} else {
UIImage *i = [UIImage imageNamed:@"galleryBrokenImage"];
[self.uiImagesCache setObject:i forKey:@(photoIndex)];
*photoSize = NIPhotoScrollViewPhotoSizeOriginal;
return i;
}
}
, . . :
- (UIImage *) genericImageForKind:(NSString *) imageKind {
UIImage *candidate = nil;
if ([kind isEqualToString:@"pdf"]) {
candidate = [UIImage imageNamed:@"galleryPdfIcon"];
} else if ([kind isEqualToString:@"video"]) {
candidate = [UIImage imageNamed:@"galleryVideoIcon"];
} else {
candidate = [UIImage imageNamed:@"galleryBrokenImage"];
}
return candidate;
}
…
if ([imageEntry objectForKey:@"fullscreenUrl"]==nil) {
NSString *kind = [imageEntry objectForKey:@"kind"];
UIImage *genericImage = [self genericImageForKind:kind];
if (genericImage) {
[self.uiImagesCache setObject:genericImage forKey:@(photoIndex)];
*photoSize = NIPhotoScrollViewPhotoSizeOriginal;
}
return nil;
}
SQL . , , , , .
function(err, dResults) {
if (err) {
console.log(err);
callback(err);
return;
}
var i=0, lastDownloaded = null;
var unixtimes = Object.keys(dResults);
for(i=0;i<unixtimes.length;i++) {
if (dResults[unixtimes[i]].isDownloaded) {
lastDownloaded = unixtimes[i];
}
}
for(i=0;i<unixtimes.length;i++) {
if (unixtimes[i]>lastDownloaded) {
delete dResults[unixtimes[i]];
}
}
self.getOpenPrice(symbol, function(err, openPrice) {
callback(err, dResults, openPrice);
});
}
:
function getLastDownloadedUnixtime(entries) {
var lastDownloadedUnixtime = null;
var unixtimes = Object.keys(entries);
unixtimes.forEach(function(unixtime) {
if (entries[unixtime].isDownloaded) {
lastDownloadedUnixtime = unixtime;
}
});
return lastDownloadedUnixtime;
}
function cleanupEntriesNewerThanLastDownloadedUnixtime(entries, lastDownloadedUnixtime) {
var unixtimes = Object.keys(entries);
for(var i=0;i<unixtimes.length;i++) {
if (unixtimes[i]>lastDownloadedUnixtime) {
delete entries[unixtimes[i]];
}
}
}
…
function(err, dResults) {
if (err) {
console.log(err);
callback(err);
return;
}
var lastDownloadedUnixtime = getLastDownloadedUnixtime(dResults);
cleanupEntriesNewerThanLastDownloadedUnixtime(dResults, lastDownloadedUnixtime);
self.getOpenPrice(symbol, function(err, openPrice) {
callback(err, dResults, openPrice);
});
}
XML Amazon S3. , , XML :
strcat(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
strcat(xml, "<Delete>\n");
strcat(xml, "<Quiet>true</Quiet>\n");
for (uint32_t i=0;i<batchCount;i++) {
char *escapedPath=Deleter::xmlEscape(batch[i]);
strcat(xml, "\t<Object><Key>");
strcat(xml, escapedPath);
free(escapedPath);
strcat(xml, "</Key></Object>\n");
LOG(LOG_DBG, "[Delete] %s", batch[i]);
}
strcat(xml, "</Delete>\n");
, :
void addPathToDeleteXml(char *xml, char *path) {
char *escapedPath=Deleter::xmlEscape(path);
strcat(xml, "\t<Object><Key>");
strcat(xml, escapedPath);
strcat(xml, "</Key></Object>\n");
free(escapedPath);
}
void addBatchOfPathsToXml(char *xml, char **batch, uint32_t batchCount) {
for (uint32_t i=0;i<batchCount;i++) {
addPathToDeleteXml(xml, batch[i]);
LOG(LOG_DBG, "[Delete] %s", batch[i]);
}
}
…
strcat(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
strcat(xml, "<Delete>\n");
strcat(xml, "<Quiet>true</Quiet>\n");
addBatchOfPathsToXml(xml, batch, batchCount);
strcat(xml, "</Delete>\n");
, — . : , - . , - , - , , .
, . , . , , , .
. , . , . , .
— . , : , , .
. — , - .
. , , , autocomplete.
Update: «if (true) return true» , .. , .