TDD benzeri Algoritmik problemlere yaklaşım


10

Codility ile algoritmik bir testte başarısız oldum çünkü daha iyi bir çözüm bulmaya çalıştım ve sonunda hiçbir şeyim yoktu.

TDD'ye benzer bir yaklaşım kullanabilirsem bana düşündürdü. Yani genellikle benzer şekilde yavaş yavaş bir çözüm geliştirebilirsem?

Bir sıralama algoritması yazsaydım, standart bir Bubblesort'tan 2 yollu bir bubblesort'a geçebilirdim, ancak Quicksort gibi daha gelişmiş bir şey "kuantum sıçraması" olurdu, ama en azından test verisine sahip olabilirim, kolayca doğrulayabilirim.

Bu testler için başka ipuçları? Bir dahaki sefere yapacağım bir şey, iç döngülerden daha fazla yöntem / işlev kullanmaktır. Örneğin, sıralamada genellikle bir takas gerekir. Bir yöntem olsaydı ben sadece arama kodunu değiştirmek gerekir. Türetilmiş sınıflar olarak daha gelişmiş çözümlere bile sahip olabilirim.

"Algoritmik" ve "normal" problemlerle Zaman karmaşıklığının önemli olduğu problemleri kastediyorum. Bu yüzden TDD'de olduğu gibi daha fazla test yapmak yerine "daha iyi davranmasını" sağlayabilirsiniz.

"TDD'ye benzer" ile kastediyorum:

  1. Manuel testler artışında zamandan kazanmak için nispeten otomatik test yazın.
  2. Artımlı gelişim.
  3. Regresyon testi, kodun kırılıp kırılmadığını veya en azından işlevler artışlar arasında değişip değişmediğini belirleme yeteneği.

Eğer karşılaştırırsanız bunun anlaşılması kolay olması gerektiğini düşünüyorum

  1. Doğrudan bir kabuk sıralama yazma
  2. Bubblesort'tan quicksort'a atlama (Toplam yeniden yazma)
  3. Tek yönlü bir kabarcık-sıralamasından kabuk sıralamasına aşamalı olarak hareket etme (mümkünse).

"TDD'ye benzer" ile ne demek istiyorsun? Bir sıralama işlevi geliştirmek için TDD'yi kullanmaya çalışabilir ve daha sonra sıralama algoritmasını daha verimli bir yöntemle değiştirdiğinizde hala çalıştığını doğrulamak için birim testlerini kullanabilirsiniz, ancak aklınızda farklı bir sorunuz olduğu anlaşılıyor mu?
Doc Brown

"kademeli olarak" :-) - Son cümle bakınız "Bunun yerine ..."
Olav

2
İlk önce çalışan (ancak çok verimli olmayan) bir çözümle birçok sorunu çözmeye çalışabilir, ardından geliştirebilirsiniz. Bu hiçbir şekilde algoritmik veya programlama problemleriyle sınırlı değildir ve TDD ile pek bir ortak noktası yoktur. Bu sorunuza cevap veriyor mu?
Doc Brown

@DocBrown No - Bkz. Bubblesort / Quicksort örneği. TDD iyi çalışıyor çünkü artımlı bir yaklaşım birçok problem için iyi çalışıyor. Algoritmik problemler farklı olabilir.
Olav

Yani "TDD'nin artımlı bir yaklaşım olduğu gibi" algoritma tasarım sorularını artımlı bir şekilde çözmek mümkün "demek istediniz, değil mi? Lütfen açıkla.
Doc Brown

Yanıtlar:


9

Ayrıca bkz TDD ile bir Sudoku çözücü oluşturmak için Ron Jeffries girişimini maalesef iş vermedi.

Algoritma, algoritma tasarım ilkelerinin önemli bir şekilde anlaşılmasını gerektirir. Bu prensiplerle Peter Norvig'in yaptığı gibi bir planla aşamalı olarak ilerlemek gerçekten mümkündür .

Aslında, önemsiz olmayan tasarım çabası gerektiren algoritmalar için, neredeyse her zaman çabanın doğası artmaktadır. Ancak , bir algoritma tasarımcısının gözünde küçük olan her "artış", bu özel algoritma ailesiyle aynı uzmanlığa veya bilgiye sahip olmayan bir kişiye kuantum sıçraması gibi görünür (ifadenizi ödünç almak için).

Bu nedenle, CS teorisindeki temel eğitimin birçok algoritma programlama uygulaması ile birleşmesi de aynı derecede önemlidir. Belirli bir "tekniğin" (algoritmaların küçük yapı taşları) var olduğunu bilmek, bu artımlı kuantum sıçramaları yapmak için uzun bir yoldur.


Yine de algoritmalarda artımlı ilerleme ve TDD arasında bazı önemli farklılıklar vardır.

Farklardan biri JeffO tarafından belirtilmiştir : Çıktı verilerinin doğruluğunu doğrulayan bir test , aynı algoritmanın farklı uygulanması (veya aynı çözümü vermek için yarışan farklı algoritmalar) arasındaki performansı destekleyen bir testten ayrıdır .

TDD'de kişi test şeklinde yeni bir gereklilik ekler ve bu test başlangıçta geçmeyecektir (kırmızı). Sonra gereksinim karşılanır (yeşil). Son olarak kod yeniden düzenlenir.

Algoritma geliştirmede, gereksinim genellikle değişmez. Sonuç doğruluğu doğrulama testi ya ilk olarak ya da algoritmanın taslak (son derece kendinden emin ama yavaş) uygulaması tamamlandıktan kısa bir süre sonra yazılır. Bu veri doğruluğu testi nadiren değiştirilir; biri TDD ayininin bir parçası olarak başarısız (kırmızı) olarak değiştirmez.

Bununla birlikte, bu açıdan, veri analizi algoritma geliştirmeden belirgin şekilde farklıdır, çünkü veri analizi gereklilikleri (hem girdi kümeleri hem de beklenen sonuçlar) sadece insan anlayışında gevşek bir şekilde tanımlanmıştır. Böylece gereksinimler teknik düzeyde sık sık değişir. Bu hızlı değişim, algoritma geliştirme ile genel yazılım uygulaması geliştirme arasında veri analizini bir yere koyuyor - yine de algoritma ağırlıklı olsa da, gereksinimler de herhangi bir programcının zevkine göre "çok hızlı" değişiyor.

Gereksinim değişirse, genellikle farklı bir algoritma gerektirir.

Algoritma geliştirmede, performans karşılaştırma testinin başarısız (kırmızı) olarak değiştirilmesi (sıkılması) saçmadır - algoritmanızda performansı artıracak olası değişiklikler hakkında herhangi bir fikir vermez.

Bu nedenle, algoritma geliştirmede, hem doğruluk testi hem de performans testi TDD testleri değildir. Bunun yerine, her ikisi de regresyon testleridir . Özellikle, doğruluk regresyon testi algoritmada doğruluğunu bozacak değişiklikler yapmanızı engeller; performans testi algoritmada daha yavaş çalışmasını sağlayacak değişiklikler yapmanızı engeller.

TDD'yi kişisel çalışma tarzı olarak da dahil edebilirsiniz, ancak "kırmızı - yeşil - refaktör" ritüelinin algoritma geliştirmenin düşünce sürecinde kesin olarak gerekli olmaması veya özellikle yararlı olmaması gerekir .

Algoritma geliştirmelerinin gerçekte mevcut algoritmanın veri akış diyagramlarına rasgele (gerekli olmayan) permütasyonlar yapmasından veya bunları önceden bilinen uygulamalar arasında karıştırıp eşleştirmesinden kaynaklandığını iddia ediyorum.


TDD, test setinize aşamalı olarak eklenebilecek birden fazla gereksinim olduğunda kullanılır .

Alternatif olarak, algoritmanız veriye dayalıysa, her bir test verisi / test durumu parçası aşamalı olarak eklenebilir. TDD de faydalı olacaktır. Bu nedenle, yeni test verileri ekleme - bu verileri doğru bir şekilde işlemek için kodu geliştirin - refactor "" TDD benzeri "yaklaşımı, algoritmaların hedeflerinin insanlarda tanımlandığı açık uçlu veri analizi çalışması için de çalışacaktır. merkezli kelimeler ve başarı ölçüsü de insan tanımlı terimlerle değerlendirilir.

Tek bir denemede tüm (düzinelerce veya yüzlerce) gereksinimi karşılamaya çalışmaktan daha az ezici bir yol öğretmeyi amaçlıyor . Başka bir deyişle, çözümünüzün bazı erken taslaklarını uygularken belirli gereksinimlerin veya esneme hedeflerinin geçici olarak göz ardı edilebileceğini dikte edebildiğinizde TDD etkinleştirilir .

TDD, bilgisayar biliminin yerini tutmaz. Programcıların aynı anda birçok gereksinimi karşılama şokunun üstesinden gelmesine yardımcı olan psikolojik bir koltuk değneği .

Ancak, doğru sonucu veren bir uygulamanız varsa, TDD hedefinin yerine getirildiğini ve kodun (yeniden düzenleme veya başka bir programcı kullanıcı için) dağıtılmaya hazır olduğunu düşünür. Bir anlamda, objektif olarak size kodun "yeterince iyi" olduğuna dair bir sinyal vererek (tüm doğruluk testlerini geçmek için) kodunuzu erken optimize etmemenizi teşvik eder.


TDD'de "mikro gereksinimlere" (veya gizli niteliklere) de odaklanılmaktadır. Örneğin, parametre doğrulamaları, iddialar, istisna atma ve işleme, vb. TDD, yazılım yürütmenin normal seyrinde sık kullanılmayan yürütme yollarının doğruluğunun sağlanmasına yardımcı olur.

Bazı algoritma kodu türleri de bunları içerir; bunlar TDD'ye uygundur. Ancak, algoritmanın genel iş akışı TDD olmadığı için, bu tür testler (parametre doğrulamaları, iddialar ve istisna atma ve işleme), uygulama kodu zaten (en azından kısmen) yazıldıktan sonra yazma eğilimindedir.


Gönderinizdeki alıntı yapılan ilk iki kelime ("Bob Amca") ne anlama geliyor?
Robert Harvey

@RobertHarvey Bob Amca'ya göre, TDD algoritma keşfi için kullanılabilir. Başka bir armatüre göre, işe yaramıyor. Her ikisinden de bahsedilmesi gerektiğini düşündüm (yani birisi bir örnekten bahsettiğinde, biri de diğer örnekten bahsetmek zorundadır), böylece insanlar olumlu ve olumsuz örnekler hakkında dengeli bilgi edinirler.
rwong

TAMAM. Ama kafa karışıklığımı anlıyor musun? İlk paragrafınız "Bob Amca" kelimelerini kullanan birinden alıntı yapıyor gibi görünüyor. Bunu kim söylüyor?
Robert Harvey

@RobertHarvey siparişi yerine getirildi.
rwong

2

Sorununuz için iki testiniz olacaktır:

  1. Algoritmanın hala doğru olduğundan emin olmak için bir test. Örneğin, doğru bir şekilde sıralanmış mı?
  2. Performans karşılaştırma testi - performans iyileştirildi. Bu zor olabilir, bu nedenle testi aynı makinede, aynı verilerde çalıştırmaya ve diğer kaynakların kullanımını sınırlamaya yardımcı olur. Özel bir makine yardımcı olur.

Ne test veya tam test kapsamı tartışmalıdır, ancak uygulamanızın ince ayar yapılması gereken karmaşık kısımlarının (çok fazla değişti) otomatik test için mükemmel adaylar olduğunu düşünüyorum. Başvurunun bu bölümleri genellikle çok erken teşhis edilir. Bu parça ile bir TDD yaklaşımı kullanmak mantıklı olacaktır.

Karmaşık problemleri çözebilmek, çeşitli yaklaşımları denemek konusunda bir isteksizlikle engellenmemelidir. Otomatik test yaptırmak bu alanda yardımcı olacaktır. En azından onu daha da kötüleştirmediğini bileceksin.


1

Bu yüzden TDD'de olduğu gibi daha fazla test yapmak yerine "daha iyi davranmasını" sağlayabilirsiniz.

Bir çeşit.

Çalışma süresi ve karmaşıklığı test edebilirsiniz. Çalışma zamanı testlerinin, sistem kaynaklarında çekişmeye izin vermek için biraz bağışlayıcı olması gerekecektir. Ancak, birçok dilde, yöntemleri geçersiz kılabilir veya enjekte edebilir ve gerçek işlev çağrılarını sayabilirsiniz. Mevcut algoritmanızın en düşük düzeyde olduğundan eminseniz , saf uygulamadan daha az kez sort()çağırılmasını talep eden bir test compare()uygulayabilirsiniz.

Ya da, sort()iki kümeyi karşılaştırabilir ve compare()aramalarda hedef karmaşıklığınıza göre ölçeklendirilmesini sağlayabilirsiniz (veya tutarsızlık beklerseniz yaklaşık olarak).

Eğer Ve eğer, teorik boyutta bir dizi olduğunu kanıtlamak Nfazla sıkı gerektiren gerektiğini N*log(N)karşılaştırmalar, olabilir senin zaten çalışan kısıtlamak için makul sort()için N*log(N)halinin çağrıları compare()...

Ancak ...

Bir performans veya karmaşıklık gereksinimini karşılamak, temeldeki uygulamanın {AlgorithmX} olmasını sağlamaz . Ve bunun normalde sorun olmadığını iddia ediyorum. Uygulamanızın önemli karmaşıklık, performans veya kaynak gereksinimleri dahil olmak üzere gereksinimlerinizi karşılaması koşuluyla hangi algoritmanın kullanıldığı önemli değildir.

Ancak, belirli bir algoritmanın kullanıldığından emin olmak istiyorsanız, daha sıkıcı olmanız ve daha derinlemesine öğrenmeniz gerekir. Gibi şeyler..

  • Sağlamak aynen çağrı beklenen sayısını compare()ve swap()(veya ne olursa olsun) yapılır
  • Tüm önemli işlevleri / yöntemleri kaydırma ve tahmin edilebilir bir veri seti ile çağrıların tam olarak beklenen sırada yapılmasını sağlama
  • Tam olarak beklendiği gibi değiştiğinden emin olmak için her N adımından sonra çalışma durumunu inceleme

Ama yine de, özellikle {AlgorithmX} ' in kullanılmasını sağlamaya çalışıyorsanız , muhtemelen {AlgorithmX}' in test ettiğiniz {AlgorithmX} ' in sonunda kullanılıp kullanılmadığından daha önemli olan özellikleri vardır ...


Ayrıca, TDD'nin yazılım geliştirmede araştırma, düşünme veya planlama gereğini ortadan kaldırmaz . Ayrıca, otomatik test paketinizde Google'ınızı ve beyaz tahtanızı kolayca iddia edemeseniz bile, beyin fırtınası ve deneme ihtiyacını ortadan kaldırmaz .


Operasyon sayısına sınır koyma olasılığı konusunda mükemmel bir nokta. TDD'de kullanılabilecek bir şeyin (alaylar, taslaklar ve casuslar) gücü olduğunu ve diğer testlerde de kullanılabileceğini iddia ediyorum.
rwong

Bir test senaryosunda koddan önce test yazarken fazla bir nokta görmüyorum. Genellikle fonksiyonel kriterler karşılandıktan sonra son bir kriterdir. Bazen ilk önce rasgele sayılar ve sonra en kötü durumda olabilirsiniz, ancak yine de yazma testi bazı akıllı çıktılara kıyasla uzun zaman alabilir. (Bazı istatistiklerle muhtemelen bir genel kod yazabilirsiniz, ancak bir test sırasında yazamazsınız) Gerçek dünyada, bazı durumlarda performansın aniden düşüp düşmediğini bilmek isteyeceğinizi düşünüyorum.
Olav

Eğer codility.com/programmers/task/stone_wall adresine bakarsanız, örneğin çok uzun süreler boyunca çalışmanız gereken özel durumlar haricinde N'den fazla karmaşıklığa sahip olup olmadığınızı bilirsiniz.
Olav

@Olav "yazma testi bazı akıllı çıktılara göre uzun zaman alacaktır" ... bir kez yapmak ... ah ... belki , ama aynı zamanda çok tartışmalı. Her derlemede tekrar tekrar yapmak? ... Kesinlikle hayır.
svidgen

@Olav "Gerçek dünyada, belirli durumlarda performansın aniden düşüp düşmediğini bilmek isteyeceğinizi düşünüyorum." Canlı hizmetlerde, yalnızca belirli yöntemlerin değil genel performansın izlenmesi için Yeni Kalıntı gibi bazılarını kullanırsınız . İdeal olarak, testleriniz performans açısından kritik olan modüllerin ve yöntemlerin konuşlandırmadan önce beklentileri karşılamadığını gösterir .
svidgen
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.