Yorumlanan kısa süslü kod ile karşılaştırılmamış daha uzun anlaşılması kolay kod - hangisi tercih edilir?


18

Bazen bir algoritma iki şekilde yazılabilir:

  • Kısa, süslü bir yol; veya
  • Daha uzun, anlaşılması kolay yol.

Örneğin, burada bir dize kopyalama daha uzun, daha kolay bir yoldur sourceiçin destC:

*dest = *source;
while (*source != '\0') {
    source++;
    dest++;
    *dest = *source;
} (true);

Ve işte kısa, süslü bir yol.

// Copy string source to dest
while (*dest++ = *source++);

Ben her zaman duydum ve fantezi kodu kaçınılması gerektiğini okudum ve kabul etme eğilimindedir. Peki ya yorumları dikkate alırsak? Yukarıdaki örneklerde olduğu gibi, kabul edilmemiş, daha uzun ve sözde anlaşılması daha kolay bir kodumuz ve iyi yorumlanmış, kısa, süslü bir kodumuz olduğunu varsayın? Süslü olmayan kod hala tercih ediliyor mu?

EDIT: Birçok değişken adları yorumladı, bu yüzden diğer bir tercih tercih ederken bir faktör yapmak değil örnek kod değiştirdim. İlk örnekte çift atamayı kaldırmaya çalıştım, ancak bu yalnızca kodu daha az okunabilir hale getirdi.

Belki de bu en iyi örnek değildi çünkü çoğu 'fantezi' kodu daha uzun koddan daha okunabilir ve anlaşılır buluyor. Fikir, anlaşılması çok kısa ama karmaşık bir koddan çok daha kolay olan daha uzun bir koda sahip olmaktı.

EDIT2: İşte aldığım yeni Examle var SO :

Yorumlanan fantezi sürüm:

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Yorum yapılmamış uzun versiyon:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}

2
@gablin: "iyi" bir kelimedir, ancak "iyi" den biraz farklı bir anlama sahip bir sıfattır ve artık yaygın olarak kullanılmamaktadır (en azından ABD'de) "İyi" nin zarf biçimi "iyi" dir. "iyi yorumlanmış kod" da olduğu gibi.
John M Gant

@John: Ah evet, elbette. Soruyu buna göre güncelledim. Teşekkürler.
gablin

2
Kısa yol ne şekilde 'süslü'? Bu, C'yi bildiğini iddia eden herkesin herhangi bir sorun yaşamadan okuyabileceği bir C kodu metin kitabıdır. Terseness 'fantezi' anlamına gelmez.
JBRWilkinson

@JBRWilkinson: Sorunun değiştirilmiş bölümünde söylediğim gibi, bu örnek iyi değil çünkü "süslü" sürüm o kadar da süslü değil. Amaç kısa ve anlaşılır olmayan bir yorum ve daha uzun ama daha okunaksız bir yorum yapmaktı.
gablin

@gablin: Düzenlemeniz mevcut yanıtlardan ödün veriyor.
Maniero

Yanıtlar:


28

Ben genellikle kendi yöntemine fantezi kodu çıkarmayı tercih ederim ..

Süslü kodu yorumlamak yerine, yöntem adı, işleri netleştirmek için ihtiyaç duyduğu tek şey olmalıdır.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}

3
Harika bir nokta. Bağımsız kodun dışlanması, yorumlardan çok daha iyidir. Derleyici, gerektiğinde nasıl satır içi olacağını bilir.
dbkk

Ah evet, bu yorumu geçersiz kılmanın harika bir yolu. Ama buna rağmen, fantezi kodu her zaman daha uzun kod yerine tercih eder misiniz?
gablin

Genel olarak, evet. Kısa, iyi adlandırılmış yöntemlerin kodun okunmasını ve bakımını kolaylaştırdığını hissediyorum. Kendi yöntemlerine dahil edilen karmaşıklık, yeniden kullanımı daha erişilebilir ve belirgin hale getirir. Her zaman istisnalar vardır, sonuçta her zaman koda bağlıdır.
Mongus Pong

Elbette fonksiyonunuz 'strcpy' olarak adlandırılmalıdır?
JBRWilkinson

Bu kodda bir hata var. Ne döndürülür? Neyin iade edilmesi gerekiyordu? Sadece geçersiz bir yöntem haline getirin ve onunla yapın;)
Christian Mann

10

Ben daha uzun versiyonum. Kodun kısa versiyonuyla ilgili sorun, bazı programcıların okumasının daha zor olmasının yanı sıra, çoğu zaman sadece ona bakarak hataları tespit etmenin daha zor olmasıdır.

Gerçek bir hayat örneğim var. Ürünümüzde aşağıdaki kod snippet'imiz vardı:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

Bu kod ilk bakışta mükemmel makul görünüyor, ancak uzun bir süre sonra bu sayaç taşar ve durumu ihlal eder (gerçek yaşam senaryosunda müşterinin üretim sistemini bir OOM ile ezdik). Bu kod biraz daha az "sofistike", ancak yapılması gerekeni yaptığı açıktır:

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

Ve bu kodu yazan geliştiricinin yeterince iyi olmadığını söyleyebilirsin (bu doğru değil, oldukça parlak bir adamdı), ancak kodlama tekniğiniz süper süper yetenekli programlama ALLAH olmanızı gerektirdiğini düşünüyorum. kodunuzu doğru yapmak için yanlış bir şey yapıyorsunuz. Kodunuz, sizin iyiliğiniz ve sizden sonra bu kodu kimin korumak zorunda olduğu (olabildiğince akıllı olmayabilir) için mümkün olduğunca kusursuz olmalıdır.

Yani - ben basitlik ve açıklık için.

Edit: Oh, ve yorumlarla ilgili olarak - önemli değil. Birçok kişi zaten yorumları okumaz ( http://www.javaspecialists.co.za/archive/Issue039.html ) ve kodunuzu yorum yapmadan anlamayanlar, onlarla yeterince iyi anlayamayacaklar, bunu koruyabilir. Amaç, insanların belirli kodların "doğru" olduğunu görmelerine yardımcı olmaktır , yorumlar bu konuda yardımcı olamaz.


1
"müşterinin üretim sistemini ezdi" - bu oldukça kötü: -S

"Bazı programcıların okuması daha zor olmasının yanı sıra, kodun kısa versiyonu ile ilgili sorun" - herhangi bir kod parçası "bazı programcılar için" zor olabilir. Sadece yeterince aptalca programcı bulmalısın. Kodu en düşük paydaya batırmayın.
quant_dev

@quant_dev: tersine, "Hata ayıklama ilk etapta kodu yazmaktan iki kat daha zordur. Bu nedenle, kodu olabildiğince akıllıca yazarsanız, tanım olarak, hata ayıklamak için yeterince akıllı değilsiniz." - Brian W. Kernighan
Michael Borgwardt

@MichaelBorgwardt Kernighan'ın dictumunu olası her duruma körü körüne uygulamam. OPs örneği, "olabildiğince akıllıca" (veya buna yakın) yazılmış bir işlevdir ve yine de herhangi bir hata ayıklama gerekiyorsa hata ayıklamak oldukça kolay olmalıdır. Öte yandan, karmaşık bit döndürücü onelinerler çok akıllı olabilir, ancak hata ayıklamak kesinlikle daha zor olacaktır. (Ayrıca: Kernighan kodlama becerileri = hata ayıklama becerileri olduğunu varsayar. Durum böyle olmak zorunda değil. Ben başarılı bir şekilde yazmak mümkün olmaz kod hata
ayıkladım

6

Genellikle daha uzun versiyonu tercih ederim. Akla gelen iki ana sebep:

  • Daha fazla insanın daha az çaba ile anlaması muhtemeldir (bu dize kopyası gibi "standart" bir örnek olmadığı varsayılır).
  • Bireysel ifadelere kesme noktaları koymak ve bir hata ayıklayıcı ile adım atmak mümkündür.

Her iki dünyanın en iyisi için, kodu sizin için yorum yapan bir işlev içine sarın:

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '\0') {
        t++;
        s++;
        *s = *t;
    }
}

Bunu yapmamanın tek nedeni, performansın bir sorun olması ve profil oluşturma işleminin gerçekten ek yükün önemli olduğunu göstermesidir.


1
Satır içi bunun için değil mi?
Antsan

Gerçekten de, satır içi, işlev gövdesini başlık dosyalarında göstermek zorunda gibi kendi sorun paylaşımıyla birlikte gelir. Modern derleyiciler zaten mantıklı yerlerde sizin için otomatik olarak satır içi şeyler değil mi?
Paul Stephenson

4

En açık olan her neyse. Genellikle, yorum gerektirmeyen, anlaşılması kolay, küçük bir kod snippet'i ... ikinci örneğiniz gibi.

Genellikle daha kısa kod snippet'lerini anlamak daha kolaydır, çünkü okuyucunun bir anda kafasında kalması için daha az şey vardır. Açıkçası, kod aşırı şaşkınlaştığında bir sınır var ve beyaz alanı arttıran netliğin kesilmesi gerektiği anlamına gelmiyorum.

Yorumlar hiçbir zaman koddan belirgin olan hiçbir şeyi söylememelidir, bu da okuyucunun aynı şeyi iki kez okumasını sağlar. Bana göre ilk pasaj açıklama gerektiriyor. Geliştirici do...while, *s = *t;ödevin kopyasını kaldırmak için neden bir döngü kullanmadı ? Bir dize kopyasını uygulamak için daha fazla kod ayrıştırmak zorunda. Bir yorum, bu daha uzun koda daha kısa koda göre daha yararlı olacaktır.

İkinci pasajdaki yorum neredeyse döngüseldir, çünkü döngü pratik olarak deyimseldir, ancak kodun daha yüksek bir seviyede ne yaptığını söyler, bu da kodun kendisini yararlı bir yorum yapar.


Geliştirici (ben) do ... whilesadece soruyu yazdığımda düşünmediğim için kullanmıyordu . Bunu işaret ettiğiniz için teşekkürler. ^^ İkinci pasaj sizin için açık olabilir, ama kesinlikle benim için değil.
gablin

4

Sorun, short fancy codeprogramcı seviyesine çok bağlı olduğu için açık bir tanımı olmamasıdır . Bazı insanlar bir while(*s++ = *t++);ifadeyi anlamada sorun yaşamazken, diğerleri bunu yapacak.

Şahsen while(*s++ = *t++);mükemmel okunabilir ve daha uzun olanı okumak daha zor buluyorum . Diğerleri de aynı fikirde olmayabilir.

Ne olursa olsun, bu sadece sağduyu kullanma meselesidir. Okunabilirlik kesinlikle bir öncelik olmalıdır, ancak daha uzun kodlar daha uzun olduğunda daha az okunabilir hale gelir. Ayrıntı düzeyi genellikle deneyimimden okunabilirliği azaltır.


Bu cevapların çoğunun bir temasının "geliştiriciler C'de strcpy () yazmanın standart yolunu tanımayabilir" şeklinde
üzülüyor

Bu - daha iyi programcıların olmadığı anlamına gelmez, bunun yerine a) C'ye daha fazla öğretmiyoruz ve b) C'nin gücünün de zayıflığı olduğunu - bu döngüde C de oldukça gizli ve aynı zamanda C
Murph

Bu yüzden kendimizi günlük görevlerimize başka bir meydan okuma ile buluyoruz. Doğrudan akranlarımızın dil anlama düzeyinin genel düzeyini tahmin etmek gerekir, böylece kod incelemelerimiz yapıcı kalacaktır. Savaşın içine girmemek niyetin "doğru", daha temiz bir ifadesidir.
frogstarr78

2

Buradaki diğer cevapların çoğuna katılmıyorum - sanırım (en azından bu durumda) daha kısa kod daha iyi. Senin iddiasının aksine, uzun kodudur değil , en azından bir okuyucu için daha "daha kolay" . Bir şey varsa, kodun anlaşılmasını ve / veya doğru çalıştığından emin olmanızı zorlaştırsa da, daha uzun yapmak istemenizden çıkmış gibi görünüyorsunuz.

Özellikle, dizenin ilk baytının döngü dışında, diğer baytların atamasından ayrı olarak atanması , tüm baytların doğru kopyalandığından emin olmak için okumada çok daha dikkatli olması gerektiği anlamına gelir . Kısa versiyondaki temel işlem sırasının doğrulanması çok daha kolaydır. Tek gerçek sorunu biçimlendirmedir - kasıtlı olarak boş bir döngü gövdesine sahip olduğunuzda, bunu açıklığa kavuşturmak en iyisidir:

while (*dest++ = *source++)
    ;

ya da:

while (*dest++ = *source++)
    ; /* no body */

Bazı insanlar bunun yerine diş telleri kullanmayı tercih eder:

while (*dest++ = *source++)
    {}

Tam olarak hangi biçimlendirmeyi tercih ederseniz edin, aşağıdakiler gibi konularda yeterli hatalar yapıldı:

if (x>y);
     x = z;

... emin olmak önemlidir 1) herhangi bir akış kontrolü tarafından gerçekte neyin kontrol edildiğinin açık olduğu ve 2) kodun neyin kontrol edildiğini bilerek yazıldığı açıktır , bu yüzden okuyan biri denemek için zaman kaybetmez sadece bir hata bulup bulmadıklarını anlamak için.


Evet, bu özel örneğin geçmişinde, 'süslü' sürüm muhtemelen daha uzun sürümden daha okunabilir. Daha iyi bir örnek düşünebilseydim, ama şu anda yapamam. Ama ben daha uzun yapmak için "benim yolumdan gitmedi" - en azından başlangıçta, bir dize kopyasını bu şekilde yazmak istiyorum. En iyi yaklaşım olmayabilir, ancak niyet gereği gereğinden fazla yapılmamıştır.
gablin

2
Keep it simple, stupid!

Başka bir programcının kodunuzun ne yaptığını anlayabildiğinden ve bir bakışta daha da iyi olduğundan emin olun (iyi isimlerin ve yorumların kendi haline geldiği yer).

Süslü bit twiddling kung-fu ve inline montaj (belki de gereksiz ve erken) optimizasyon adına harika, ancak iki ay sonra bir hatayla karşılaştığınızda yazdığınız kodu anlayamadığınızda bile .. Amaç neydi? Kendinize zaman ve çaba harcayacaksınız.

Bu durumlarda genellikle Python'un Zen'inden söz ediyorum . Özellikle:

Explicit is better than implicit.
Simple is better than complex.

1

Üretim yazılımında fantezi kod yazmayın. Bunu gerçekten yazmanın iyi hissettirdiğini biliyorum ve bu daha kısa. Fantezi kod yazmak "WTF / dakika" değerini önemli ölçüde artırır, başka bir deyişle kaliteyi düşürür.

alternatif metin


1

Tabii ki tamamen koşullara bağlı. ama genel olarak, bunu iyi bir kural olarak görüyorum:

Hata ayıklama, kodu ilk etapta yazmaktan iki kat daha zordur. Bu nedenle, kodu olabildiğince akıllıca yazarsanız, tanımı gereği, hata ayıklamak için yeterince akıllı değilsinizdir.

~ Brian Kernighan


daha kompakt ama daha anlamlı, zarif , daha kompakt KISS kısaltmasından daha ~ umarım ironi kaybolmaz; p
violet313 17:12

0

Deneyimlerime göre, kısa fantezi kod açısından en büyük kazanç, yineleme yerine özyineleme kullanma eğilimindedir. Ayrıca, her şeyin yine de özyinelemeli olduğu bir dilde çalışmadığınız sürece, kodun bir bakışta anlaşılması en zor şeylerden biridir. Yine de sunduğu zarafet ve gelişme hızı için onu tercih ederim, ancak gelecekteki koruyucular veya gelecekteki kendime opak olacak gibi görünüyorsa ayrıntılı yorumlara sahip olduğundan emin olmaya çalışıyorum.


0

Yorumlara asla güvenmemeye başlıyorum. Çoğu zaman, kod güncellendiğinde yorumlar güncellenmez ve çok güncel değildir veya artık ilgili olmayan müşterilerden / yönetimden gelen kuralları temsil eder.

Bazı durumlarda yorumların artık tanımladıkları kodla bile eşleşmediği noktaya geldi.

Kısa / süslü ve daha uzun / anlaşılması daha kolay arasında seçim yapmam gerekiyorsa, gerçekten iyi bir neden olmadığı sürece ikincisini seçerim .


0

Okunabilirlik ve sürdürülebilirlik çok önemlidir ve ikinci örneğiniz (yani daha uzun olanı) her ikisinden de çok daha fazladır. Ama neden kendinizi iki seçenekle sınırlandırıyorsunuz? Uzun kod bile çok karmaşık olmamalıdır (IMHO). Uygun Javadoc (veya her neyse) ve uygun bir yöntem adı ile kendi başına bir yöntem koymak istiyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.