Soyutlama: Sorunu çözme ile genel bir çözüm arasındaki savaş [kapalı]


33

Bir programcı olarak, kendimi programımı mümkün olduğunca soyut ve genel yapmak isteyen ikilemde buluyorum.

Bunu yapmak genellikle kodumu tekrar kullanmama ve tekrar ortaya çıkacak (veya çıkmayacak) bir sorun için daha genel bir çözüme sahip olmamı sağlayacaktır.

Sonra kafamdaki bu ses der ki, problemi çöz o kadar kolay! Neden yapmak zorunda olduğundan daha fazla zaman harcıyorsun?

Gerçekten de, Soyutlama'nın sağ omzunuzda olduğu ve Aptalca Sol'un solda olduğu bu soruyla karşı karşıya kaldık.

Hangisini dinlemek ve ne sıklıkla? Bunun için stratejiniz nedir? Her şeyi soyutlamalı mısın?


1
"Özet ve genel olarak" genellikle programcının kocaları olarak bilinir :) Ancak, Murphy yasası nedeniyle, bir sonraki görevde çalışırken ihtiyaç duyacağınız bir derece uyum sağlamadığınızdan olacaktır.
Matthieu M.

1
Şimdiye kadar en iyi sorulardan biri!
explorest

1
Her zaman yanlış tahmin edersiniz, bu yüzden basit görün. Basit vakaları "yeterince defa" genişlettiğinizde, bir model görmeye başlarsınız. O zamana kadar yapma.

Yanıtlar:


27

Hangisini dinlemek ve ne sıklıkla?

Yapmanız gereken kadar asla soyut.

Örneğin Java'da arayüzleri kullanmanız gerekir. Onlar bir soyutlama.

Python'da arayüzlere sahip değilsiniz, Ördek Typing'iniz var ve yüksek seviyelerde soyutlamaya ihtiyacınız yok. Yani yapmıyorsun.

Bunun için stratejiniz nedir?

Üç kere yazana kadar soyutlama.

Bir kere - iyi - bir kere. Sadece çöz ve devam et.

Burada iki kez bir kalıp olabileceğini gösteren gösterge var. Ya da olmayabilir. Sadece tesadüf olabilir.

Üç kere örüntü başlangıcıdır. Şimdi tesadüfleri aşıyor. Şimdi başarıyla soyutlayabilirsiniz.

Her şeyi soyutlamalı mısın?

Yok hayır.

Gerçekten de, doğru bir soyutlama yaptığınıza dair kesin bir kanıt olana kadar hiçbir şeyi soyutlamamalısınız. "Üç Tekrar Kuralı" olmadan, işe yaramaz bir şekilde işe yaramaz şekilde soyutlanmış şeyler yazacaksınız.

Bunu yapmak genellikle kodumu yeniden kullanmama izin verir

Bu, genellikle yanlış olan bir varsayımdır. Soyutlama hiç yardımcı olmayabilir. Kötü yapılabilir. Bu nedenle, yapana kadar yapmayın.


1
"Yapmanız gerekene kadar asla soyut değil." - Anladığım kadarıyla sınıfları, yöntemleri, döngüleri veya if ifadelerini kullanmaktan kaçınırsınız. Bunların hepsi soyutlamalar. Eğer düşünürseniz, üst düzeyde dilde yazılmış olan kod, ister ister ister istemeseniz çok soyut. Soru soyut olup olmadığı değil. Kullanılacak soyutlamalar.
Jason Baker,

9
@ Jason Baker: "Anladığım kadarıyla sınıfları, yöntemleri, döngüleri veya if ifadelerini kullanmaktan kaçının" Sorunun konusu bu gibi görünmüyor. Tasarımlarımızı fazla soyutlamaktan kaçınırsak neden saçmalamayı bütün programlamanın mümkün olmadığını iddia ediyor?
S.Lott,

1
Bir erkeğin bir kadına onunla birlikte bir milyon dolara yatıp yatmayacağını sorduğu eski şakayı hatırlatırım. Evet dediğinde beş dolar için onunla birlikte mi uyuyacağını soruyor. "Ne tür bir kadın için beni alıyorsun?" Dediğinde Cevap: "Pekala, zaten seks için birisiyle yatacağınızı belirledik. Şimdi sadece fiyatın üzerinde duruyoruz." Demek istediğim, asla soyut ya da değil kararıyla ilgili değil. Ne kadar soyutlanacağı ve hangi soyutlamaları seçeceği ile ilgili. Saf derleme yazmadan soyutlamayı uzak tutmayı seçemezsiniz.
Jason Baker,

9
@Jason Baker: "Saf montaj yazmadan soyutlamayı uzak tutmayı seçemezsin" Bu çok yanlış. Montaj, makine dili üzerinde bir soyutlamadır. Bu donanım devresi üzerinde bir soyutlamadır. Lütfen ilk başta söz konusu olmayan cevaba fazlaca okumayı bırakın. Soru, bir kavram veya entelektüel bir araç olarak "Soyutlama" ile ilgili değildi. OO tasarım tekniği olarak soyutlama ile ilgiliydi - yanlış uygulandı - çok sık. Cevabım bu soyutlamanın imkansız olmadığıydı. Ama bu "aşırı soyutlama" kötüdür.
S.Lott

1
@JasonBaker biriyle uyumak için duyulmamış bir sebep değil. Belki de "para" mı düşünüyorsun?

19

Ah, YAGNI. En kötüye kullanılan programlama kavramı.

Kodunuzu genel hale getirmek ve fazladan iş yapmak arasında bir fark vardır. Kodunuzu gevşek bir şekilde birleştirmek ve başka şeylere kolayca adapte olmak için fazladan zaman harcamalı mıydınız? Kesinlikle. Gereksiz işlevselliği uygulamak için zaman harcamanız gerekiyor mu? Hayır. Kodunuzu henüz zorlanmayan başka bir kodla çalışmak için zaman harcamanız gerekiyor mu? Yok hayır.

Söylediği gibi "İşe yarayabilecek en basit şeyi yapın". Mesele şu ki, insanlar her zaman basit ile kolay karıştırırlar . Sadelik işe alır. Ancak bu çabaya değer.

Denize gidebilir misin? Tabii ki. Ancak benim deneyimim, az sayıdaki şirketin zaten sahip olduklarından daha “şimdi halletmek” tutumuna ihtiyaç duymasıdır. Çoğu şirket, işleri önceden düşünecek daha fazla insana ihtiyaç duyar. Aksi halde, hiç kimsenin bir şey için vakti olmadığı, herkesin her zaman telaşa girdiği ve hiç kimsenin bir şey yapamadığı kendi kendine devam eden bir problemi vardır.

Bunu bu şekilde düşünün: Şayet kodunuzun bir şekilde tekrar kullanılması ihtimali yüksektir. Ama bu şekilde doğru bir şekilde tahmin etmeyeceksin. Bu yüzden kodunuzu temiz, soyut ve gevşek bir şekilde birleştirin. Ancak, kodunuzun henüz bulunmayan belirli bir işlevsellik parçasıyla çalışmasını sağlamaya çalışmayın. Gelecekte var olacağını bilsen bile.


Arasındaki Güzel ayrım simpleve easy!
Matthieu M.


"Ama benim deneyimim az sayıda şirket" - ilginç bir şekilde, bunun tersi akademi'de doğru olabilir.
Steve Bennett

12

Bir syllogism:

  1. Genellik pahalıdır.

  2. Başkalarının parasını harcıyorsun.

  3. Bu nedenle, genelliğin gideri paydaşlara haklı gösterilmelidir.

Eğer varsa kendinize sorun gerçekten sadece bunu gereksiz derecede genel bir çözüm yapmak için entelektüel bir meydan okuma bulursanız daha sonra paydaşlar tasarruf veya amacıyla daha genel problem çözme.

Genelliğin istendiği belirlenirse, diğer özellikler gibi tasarlanmalı ve test edilmelidir . Uyguladığınız genelliğin şartnamenin gerektirdiği bir sorunu nasıl çözdüğünü gösteren testler yazamıyorsanız, bunu yapmaktan zahmet etmeyin! Tasarım kriterlerine uymayan ve test edilemeyen bir özellik, kimsenin güvenemeyeceği bir özelliktir.

Ve son olarak, "mümkün olduğunca genel" diye bir şey yoktur. Sadece tartışma uğruna, C # ile yazılım yazdığınızı varsayalım. Her sınıfın bir arayüz oluşturmasını sağlayacak mısın? Her sınıf, her yöntemle soyut bir yöntemle soyut bir temel sınıf mıdır? Bu oldukça genel, ancak "mümkün olduğunca genel" hiçbir yerde bulunmuyor. Bu sadece insanların alt sınıflandırma yoluyla herhangi bir yöntemin uygulamasını değiştirmesine izin verir. Ya bir yöntemin uygulamasını alt sınıflandırmadan değiştirmek isterlerse? Her metodu aslında delege tipi bir mülk haline getirebilir, bir ayarlayıcı kullanarak insanların her metodu başka bir şeye değiştirmesini sağlayabilirsiniz. Peki ya birisi daha fazla yöntem eklemek isterse? Şimdi her nesne genişletilebilir olmak zorunda.

Bu noktada C # 'yı terk etmeli ve JavaScript'i kullanmalısınız. Ama hala yeterince generale yakın bir yere ulaşmadın; Birisi üye aramasının bu belirli nesne için çalışma şeklini değiştirmek isterse? Belki de her şeyi Python'da yazmalısın.

Genelliğin arttırılması, genellikle, uygulanan genelliğin gerçekten gerçek bir kullanıcı ihtiyacını karşılamada başarılı olmasını sağlamak için öngörülebilirliği bırakmak ve test maliyetlerini büyük ölçüde artırmak anlamına gelir . Bu maliyetler, yararları için para ödeyen paydaşlara doğrulanıyor mu? Belki onlar; Bu paydaşlarla tartışmak size kalmış. Tamamen gereksiz ve son derece pahalı bir genellik seviyesinin peşinde olan statik yazımdan vazgeçmek benim için tüm paydaşlarım değil, belki de sizin.


2
Yararlı ilkeler için +1, her şeyi para kazanmak için -1.
Mason Wheeler

4
@Mason: Bu parayla ilgili değil , çaba ile ilgili . Para, çabanın pratik bir ölçüsüdür . Verimlilik, üretilen efor başına tahakkuk eden faydadır; Yine, para karı tahakkuk eden faydaların pratik bir ölçüsüdür . Paranın soyutlamasını tartışmak, çaba, maliyet ve faydayı ölçmek için bir yol bulmaktan daha kolaydır. Çaba, maliyet ve faydayı başka bir şekilde ölçmeyi mi tercih edersiniz? Daha iyi bir yolla öneride bulunmaktan çekinmeyin.
Eric Lippert

2
@Mason Wheeler'ın amacına katılıyorum. Buradaki çözümün, paydaşları projenin bu seviyesine dahil etmemesi olduğunu düşünüyorum. Belli ki endüstriye bağlı, ancak müşteriler genellikle kodu göremiyorlar. Ayrıca, tüm bu cevaplar çaba karşıtı görünmektedir, tembel görünmektedir.
Orbling

2
@Orbling: Kaynakları değerli ve önemli projelerden uzaklaştıran gereksiz, pahalı, israf çabalarına şiddetle karşıyım. Bunun beni tembelleştirdiğini öne sürüyorsanız, o zaman "tembel" kelimesini alışılmadık bir şekilde kullandığınızı söylerim.
Eric Lippert

1
Tecrübelerime göre, diğer projeler uzaklaşma eğiliminde değil, bu yüzden genellikle devam etmeden önce mevcut projede ihtiyaç duyulduğu kadar zaman harcanmaya değer.
Orbling

5

Sadece açık olmak gerekirse, genel bir şeyler yapmak ve bir soyutlamayı uygulamak tamamen iki farklı şeydir.

Örneğin, hafızayı kopyalayan bir işlevi düşünün.

İşlev, 4 baytın nasıl kopyalandığını gizleyen bir soyutlamadır.

int copy4Bytes (char * pSrc, char * pDest)

Bir genelleme bu işlevin herhangi bir sayıda baytı kopyalamasını sağlıyor olabilir.

int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)

Soyutlama, yeniden kullanım için kendini ödünç verirken, genelleme, soyutlamayı sadece daha fazla durumda kullanışlı kılar.

Daha spesifik olarak sorunuzla ilgili olan Soyutlama, yalnızca kod yeniden kullanımı açısından yararlı değildir. Çoğu zaman doğru şekilde yapılırsa, kodunuzu daha okunaklı ve bakım yapılabilir hale getirir. Yukarıdaki örneği kullanarak, her seferinde bir dizini hareket ettiren bir dizi veriyi yineleyen bir dizi döngüsü yineleyerek copyBytes () veya a kodunu gözden geçiriyorsanız okunması ve anlaşılması daha kolay olan ne olabilir? Soyutlama, bence kodun çalışmasını kolaylaştıran bir tür kişisel dokümantasyon sağlayabilir.

Kendi genel kuralım olarak, bir kod parçasını tam olarak neyi planladığımı açıklayan iyi bir işlev adı bulabilirsem, tekrar kullanacağımı düşünüp kullanmamamdan bağımsız olarak bir işlev yazarım.


Soyutlama ve genelleme arasındaki farkı yaratmak için +1.
Joris Meys

4

Bu tür bir şey için iyi bir genel kural Sıfır, Bir, Sonsuzluktur. Diğer bir deyişle, bir kereden fazla yazdığınız şeye ihtiyacınız olursa, daha fazla zamana ihtiyacınız olduğunu ve genelleştireceğinizi varsayabilirsiniz. Bu kural, ilk defa bir şey yazarken soyutlama ile uğraşmadığınız anlamına gelir.

Bu kuralın bir başka iyi nedeni de, kodu ilk yazışınızda, neyi soyutlayacağınızı bilemeyeceğinizdir, çünkü sadece bir örneğiniz vardır. Murphy Kanunu, ilk defa soyut kod yazarsanız, ikinci örneğin beklemeyeceğiniz farklılıklar olacağı anlamına gelir.


1
Bu, Refactoring Kuralının versiyonuna çok benziyor: iki vuruş! refactor!
Frank Shearar

@Frank: Muhtemelen Refactoring Kural, ancak ikinci paragraf kişisel deneyimden eklendi.
Larry Coleman,

+1: Bunun Pragmatik Programcı'da neredeyse IIRC'de yazılı olarak oldukça erken olduğuna dikkat çekiliyor .
Steven Evers,

oh kesinlikle. Sadece bir örnekle soyutlanacak hiçbir şey yoktur: ikinci bir örneğiniz olduğu anda, neyin ortak (paylaşılan) ve neyin olmadığını görebilirsiniz ve soyutlayabilirsiniz!
Frank Shearar

İki örnek, bence sonsuzluk için genelleştirmek için çok küçük. Başka bir deyişle, çok erken.

2

Eric Lippert, gelecekteki bir tasarımı kanıtlayan makalesinde uygulanabileceğini düşündüğüm üç şeyi işaret ediyor . Bence onu takip edersen iyi durumda olacaksın.

Birincisi: Erken genelliği pahalıdır.

İkincisi: Modelinizde yalnızca daima problem alanında olan ve sınıf ilişkileri değişmeyen şeyleri temsil edin.

Üçüncüsü: Politikalarınızı mekanizmalarınızdan uzak tutun.


1

Neden kodladığınıza, projenizin amacına bağlı. Eğer kodunuzun değeri bu ise somut bir sorunu çözüyorsa, bunu yapmak ve bir sonraki soruna geçmek istersiniz. Kodun gelecekteki kullanıcıları (kendiniz dahil) için işleri kolaylaştırmak için yapabileceğiniz hızlı ve kolay şeyler varsa, o zaman elbette makul bir şekilde konaklama yapın.

Öte yandan, yazdığınız kodun daha genel bir amaca hizmet ettiği durumlar vardır. Örneğin, diğer programcılar için bir kütüphane yazarken, onu çok çeşitli uygulamalarda kullanacak. Potansiyel kullanıcılar bilinmiyor ve tam olarak ne istediklerini onlara soramazsınız. Ancak kütüphanenizi geniş ölçüde kullanışlı hale getirmek istiyorsunuz. Bu gibi durumlarda, genel çözümü desteklemek için daha fazla zaman harcıyorum.


0

Ben KISS prensibinin büyük bir hayranıyım.

Yapmam istendiği şeyi sağlamaya odaklanıyorum, en iyi çözümün ne olduğuna değil. Mükemmeliyetçilikten (ve OKB) kurtulmam gerekti, çünkü beni mutsuz etti.


Mükemmeliyetçilikten hoşlanmama neden? (Bu arada sana oy vermedim)
Orbling

Mükemmelliği hedeflememek benim için çalışıyor. Niye ya? Çünkü programlarımın asla mükemmel olmayacağını biliyorum. Standart mükemmellik tanımı yoktur, bu yüzden sadece işe yarayacak bir şey sağlamayı tercih ederim.
Pablo

-1

Soyutlama sağ omzunda ve Sol -it-aptal nerede solda oturuyor.

"Aptalca çöz" ile aynı fikirde değilim , daha "akıllıca çöz" olabileceğini düşünüyorum .

Akıllı olan ne:

  • Birden fazla vakayı destekleyebilecek karmaşık bir genelleştirilmiş çözüm yazmak
  • Çözer söz konusu sorun ve bakımı kolay olduğunu kısa ve verimli kod yazma ve hangi edebilirsiniz edilecek genişletilmiş gelecekte EĞER o gerekmektedir.

Varsayılan seçenek ikinci seçenek olmalıdır. Kuşaklara duyulan ihtiyacı göstermediğiniz sürece.

Genelleştirilmiş çözüm, yalnızca birden fazla projede / davada kullanılacak bir şey olduğunu bildiğiniz zaman olmalıdır.

Genellikle genelleştirilmiş çözümlerin en iyi "Çekirdek Kütüphane Kodu" olarak sunulduğunu düşünüyorum


Buradaki tüm varsayımları yapabilseydin, bir problemin olmazdı. Kısa ve bakımı kolay, birbirinden ayrı. Bir şeyin yeniden kullanılacağını biliyorsanız, genel çözüm buna değinecektir.
JeffO

@Jeff Yorumunuzu anladığımdan emin değilim ..
Darknight

"Aptalca Çöz" ü bağlamdan çıkardın.
Bryan Harrington
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.