Dış davranışını değiştirmeden yeniden yapılanmayı ne kadar zorlayabilirim?


27

Martin Fowler’a göre , kod yeniden düzenleme işlemi şu şekildedir:

Yeniden düzenleme, mevcut davranış kodunu yeniden yapılandırmak , dış yapısını değiştirmeksizin iç yapısını değiştiren disiplinli bir tekniktir . Kalbi, dönüşümleri koruyan bir dizi küçük davranış. Her dönüşüm (“yeniden düzenleme” olarak adlandırılır) çok az şey yapar, ancak bir dizi dönüşüm önemli bir yeniden yapılanma sağlayabilir. Her yeniden düzenleme küçük olduğundan, yanlış gitme olasılığı daha düşüktür. Sistem ayrıca her küçük yeniden yapılandırma işleminden sonra tamamen çalışır durumda tutulur ve yeniden yapılandırma sırasında bir sistemin ciddi şekilde kırılma ihtimalini azaltır.

Bu bağlamda "dış davranış" nedir? Örneğin, taşıma yöntemini refactoring olarak uygularsam ve bazı yöntemleri diğer sınıfa taşırsam, dış davranışı değiştiriyormuşum gibi görünüyor, değil mi?

Bu nedenle, bir değişimin refaktör olmayı bırakıp, daha fazlası haline gelmesinin ne noktada olduğunu bulmakla ilgileniyorum. "Yeniden düzenleme" terimi daha büyük değişiklikler için kötüye kullanılabilir: bunun için farklı bir kelime var mı?

Güncelleştirme. Arayüzle ilgili ilginç cevapların birçoğu var ancak harekete geçmeyen metodun arayüzü değiştirmesine neden olmaz mı?


Mevcut davranış berbatsa veya eksikse, düzeltin, silin / yeniden yazın. Öyleyse yeniden faktoring yapmıyor olabilirsiniz, ancak bunun sonucu olarak sistemin daha iyi hale gelmesi durumunda adın ne olduğu kimin umrunda.
İş

2
Süpervizörünüze refactor'a izin vermeniz ve bir yeniden yazma yapmanız gerekebilir.
JeffO

2
Yeniden yapılanmanın sınırı birim testleridir. Onlar tarafından çizilen bir şartnameniz varsa, testleri bozmayan değiştirdiğiniz herhangi bir şey yeniden yönlendiriyor mu?
George Silva


Daha fazla bilgi edinmek istiyorsanız, bu konu aynı zamanda aktif bir araştırma alanıdır. Bu konuda birçok bilimsel yayın var, örneğin, informatik.uni-trier.de/~ley/db/indices/a-tree/s/…
Skarab

Yanıtlar:


25

Bu bağlamda "Dış", "kullanıcılara gözlemlenebilir" anlamına gelir. Kullanıcılar bir uygulama durumunda insan olabilir veya genel bir API durumunda başka programlar olabilir.

Bu nedenle, M yöntemini A sınıfından B sınıfına taşırsanız ve her iki sınıf da bir uygulamanın derinindeyse ve uygulamanın davranışındaki herhangi bir değişikliği, değişiklik nedeniyle gözlemleyemezseniz, o zaman doğrulamayı refactoring olarak adlandırabilirsiniz.

OTOH ise, bazı daha üst düzey bir alt sistem / bileşen, davranışını değiştirir veya değişiklik nedeniyle kırılır, bu gerçekten de (genellikle) kullanıcılar (veya en azından günlükleri kontrol eden sysadmins kontrolleri) görülebilir. Veya sınıflarınız ortak bir API’nin parçasıysa, B’nin değil, A sınıfının bir parçası olmasına bağlı olan 3. parti kod olabilir. Bu nedenle, bu davaların hiçbiri katı anlamda yeniden yönlenmiyor.

Herhangi bir kod çalışmasını yeniden yapılandırma olarak adlandırma eğilimi var, sanırım yanlış.

Gerçekten de, yeniden yapılanmanın modaya kavuşması üzücü ancak beklenen bir sonucudur. Geliştiriciler, uzun süredir geçici olarak kod çalışması yapıyorlar ve yeni bir bilmeceyi öğrenmek, köklü alışkanlıkları analiz etmek ve değiştirmek yerine kesinlikle daha kolay.

Öyleyse dış davranışları değiştiren reworks'ler için doğru kelime nedir?

Ben buna yeniden dizayn derim .

Güncelleştirme

Arayüzle ilgili ilginç cevapların birçoğu var ancak harekete geçmeyen metodun arayüzü değiştirmesine neden olmaz mı?

Neyin? Belirli sınıflar, evet. Fakat bu sınıflar herhangi bir şekilde doğrudan dış dünyaya görünür durumda mı? Onlar dış arabirimi (API / GUI) bölümü program içerisine, ve çünkü - Değilse programı - değişiklik yapılmış dış taraflarca gözlenebilir yoktur (elbette değişim sonları şey, sürece).

Bunun ötesinde daha derin bir soru olduğunu hissediyorum: belirli bir sınıf kendi başına bağımsız bir varlık olarak var mı? Çoğu durumda, cevap hayırdır : sınıf sadece daha büyük bir bileşenin parçası, sınıflar ve nesnelerden oluşan bir ekosistemdir, bunlar olmadan başlatılamaz ve / veya kullanılamaz. Bu ekosistem sadece (dolaylı / dolaylı) bağımlılıklarını değil, aynı zamanda ona bağlı diğer sınıfları / nesneleri de içerir. Bunun nedeni, bu yüksek seviyeli sınıflar olmadan, sınıfımızla ilişkili sorumluluğun sistem kullanıcıları için anlamsız / yararsız olabileceğidir.

Örneğin, araç kiralama ile uğraşan projemizde Chargesınıf. Bu sınıf, sistemin kullanıcılarını kendi başına kullanmaz, çünkü kiralık istasyon acenteleri ve müşteriler bireysel bir ücretlendirme ile fazla bir şey yapamazlar: bir bütün olarak kira sözleşmesi sözleşmeleri ile uğraşırlar (bir sürü farklı ücret içerir) . Kullanıcılar çoğunlukla, sonunda ödemeleri gereken bu ücretlerin toplamına; Temsilci seçilen farklı sözleşme seçenekleriyle, kiralama süresinin, araç grubunun, sigorta paketinin, ekstra kalemlerin vb. ile ilgilenir, bunlar (karmaşık iş kuralları aracılığıyla) hangi ücretlerin mevcut olduğunu ve kesin ödemenin nasıl hesaplandığını yönetir. bunlar disinda. Ülke temsilcileri / iş analistleri, belirli iş kurallarına, sinerji ve etkilerine (şirketin gelirine vb.) Dikkat eder.

Son zamanlarda, bu sınıfı yeniden etkiledim, alanlarının ve yöntemlerinin çoğunu yeniden adlandırdım (öncekiler tarafından tamamen ihmal edilen standart Java adlandırma kurallarına uymak için). Ayrıca daha uygun ve tipe sahip alanları Stringve charalanları değiştirmek için başka refactoringler planlıyorum . Bütün bunlar kesinlikle sınıfın arayüzünü değiştirecek, ancak (eğer işimi doğru yaparsam) hiçbiri uygulamamızın kullanıcıları tarafından görülmeyecek. Hiçbiri, bireysel olarak ücretlendirmenin nasıl temsil edildiğini umursamıyor, kesinlikle ücret kavramını bilmelerine rağmenenumboolean. Herhangi bir alan kavramını temsil etmeyen yüzlerce sınıf daha seçebilirdim, bu yüzden son kullanıcılar için kavramsal olarak görünmez bile, ancak kavram düzeyinde en azından bir görünürlüğün olduğu bir örnek seçmenin daha ilginç olduğunu düşündüm. Bu, güzel bir şekilde sınıf arayüzlerinin gerçek etkiyi değil, yalnızca etki alanı kavramlarının (en iyi ihtimalle) temsilleri olduğunu gösterir. Temsil kavramı etkilenmeden değiştirilebilir. Ve kullanıcılar sadece kavramı var ve anlıyorlar; kavram ve temsil arasındaki eşlemeyi yapmak bizim görevimizdir.

* Ve kolayca sınıfımızın temsil ettiği alan modelinin kendisi sadece bazı "gerçek şeylerin" sadece bir temsili olduğunu ekleyebilir ...


3
Nitpicking, yeniden tasarım değil, 'tasarım değişikliği' derim. yeniden tasarımı çok önemli geliyor.
user606723

4
ilginç - senin örneğin sınıf A 'kod varolan beden" olduğunu ve yöntem M kamu ise o zaman A'nın dış davranış değiştiriliyor muhtemelen bu sınıf Yeniden tasarlanmış olan söyleyebiliriz Yani, genel sistem refactored oysa..
saus

Kullanıcılara gözlemlenebilirliği severim. Bu yüzden, birim testlerinin kırılmasının bir işaret olduğunu söyleyemem, fakat baştan sona veya entegrasyon testlerinin bir işareti olacağını söyleyemem.
Andy Wiesendanger,

8

Dış basitçe gerçek dil anlamında arayüz demektir. Bu örnek için bir inek düşünün. Bazı sebzeleri beslediğiniz ve geri dönüş değeri olarak süt aldığınız sürece, iç organlarının nasıl çalıştığını umursamazsınız. Şimdi, eğer Tanrı değiştirirse, iç organları besler, böylece kanı mavi renkte olur, giriş noktası ve çıkış noktası (ağız ve süt) değişmediği sürece, yeniden yakma olarak kabul edilebilir.


1
Bunun iyi bir cevap olduğunu sanmıyorum. Yeniden düzenleme, API değişikliklerini ima edebilir. Ancak, son kullanıcıyı veya giriş / dosyaların okunma / üretilme şeklini etkilememelidir.
RDS

3

Bana göre, sınırlamalar testler ve / veya resmi şartnameler ile belirlendiğinde refactoring en verimli / rahat oldu.

  • Bu sınırlar, zaman zaman geçersem, yakında düzeltilecek bir çok değişikliği geri almak zorunda kalmayacağımı bildiğim için kendimi güvende hissetmem için yeterince katı. Öte yandan, bunlar ilgisiz davranışları değiştirmekten endişe duymadan kodu geliştirmek için yeterli yer sağlar.

  • Özellikle sevdiğim şey, bu tür sınırların konuşması için uyarlanabilir olmasıdır . Yani, 1) Değişikliği yapıyorum ve şartname / testlere uygun olduğunu doğrularım. Daha sonra, 2) QA veya kullanıcı testine geçirilir - burada not edin, teknik özelliklerde / testlerde bir şey eksik olduğundan hala başarısız olabilir. Tamam, eğer 3a) testi geçerse, tamam, tamam. Aksi takdirde, 3b) testi başarısız olursa, o zaman I 4) değişikliği geri alır ve 5) testler ekler veya bir sonraki seferde bu hatanın tekrarlanmaması için spesifikasyonu netleştirir. Geçer test ederken veya başarısız olursa olursa olsun, o Not kazanmak şey - Ya kodu / testlerin / spec geliştirilmiş olur - çabalarım toplam atığın içine açmazlar.

Diğer tür sınırlara gelince - şu ana kadar çok şansım yoktu.

"Kullanıcılar için gözlemlenebilir" birinin izleyeceği bir disipline sahip olması durumunda güvenli bir bahis - bu da bir şekilde bana her zaman varolan analizleri yapmak / yeni testler oluşturmak için çok çaba sarf etti - belki de çok fazla çaba. Bu yaklaşımdan hoşlanmadığım bir diğer şey, kör bir şekilde takip etmenin çok kısıtlayıcı olabileceği yönünde. - Bu değişiklik yasaktır, çünkü veri yükleme 2 yerine 3 saniye sürecektir. - Uhm peki bununla ilgili olup olmadığını kullanıcı / UX uzmanıyla kontrol etmeye ne dersiniz? - Hiçbir şekilde, gözlemlenebilir davranışlarda herhangi bir değişiklik yapılması yasaktır. Kasa? emin ol! üretken? pek sayılmaz.

Çalıştığım bir diğeri de kod mantığını korumak (okurken bunu anladığım gibi). En temel (ve genellikle çok verimli olmayan) değişiklikler dışında, bu her zaman bir kurtçuk kutusuydu ... yoksa bir kutu böcek mi demeliyim? Regresyon hatalarını kastediyorum. Spagetti koduyla çalışırken önemli bir şeyi kırmak çok kolaydır.


3

Refactoring kitap ki onun mesajında oldukça güçlü yalnızca birim test kapsama alanına girdiğinizde üstlenmeden gerçekleştirmek .

Böylece, herhangi bir ünite testinizi kırmadığınız sürece, yeniden canlandırdığınızı söyleyebilirsiniz . Testleri çiğnediğin zaman, artık refactoring yapmıyorsun.

Ancak: sınıfların veya üyelerin adlarını değiştirmek gibi basit yeniden yapılandırmalara ne dersiniz? Testleri geçmiyorlar mı?

Evet yaparlar ve her durumda bu molanın önemli olup olmadığını düşünmeniz gerekir. Eğer SUT’niz herkese açık bir API / SDK ise, bir yeniden adlandırma gerçekten de bir değişikliktir. Değilse, muhtemelen tamamdır.

Ancak, sık sık, testlerin gerçekten önem verdiğiniz davranışı değiştirdiğiniz için değil, testlerin Kırılgan Testleri olduğu için kırıldığını düşünün .


3

Bu bağlamda "dış davranışı" tanımlamanın en iyi yolu, "test durumları" olabilir.

Kodu yeniden düzenlerseniz ve test senaryolarını geçmeye devam ederse (yeniden düzenleme öncesinde tanımlanmış), yeniden düzenleme harici davranışı değiştirmedi. Bir veya daha fazla test durumları başarısız olursa, o zaman var harici davranışı değişti.

En azından, bu konuda yayınlanan çeşitli kitapları anladım (örneğin, Fowler's).


2

Sınır, projeyi kimin geliştirdiğini, sürdürdüğünü, desteklediğini ve destekçileri, geliştiricileri, geliştiricileri dışındaki kullanıcıları kim olduğunu söyleyen çizgi olacaktır. Böylece, dış dünyaya davranış aynı gözükürken davranışın arkasındaki iç yapılar değişmiştir.

Bu nedenle, kullanıcıların gördüğü işlevler olmadığı sürece, işlevler sınıflar arasında taşınmalıdır.

Kod çalışması, harici davranışları değiştirmediği, yeni işlevler eklediği veya mevcut işlevleri kaldırdığı sürece, yeniden işleme bir yeniden düzenleme işlemi demenin uygun olduğunu düşünüyorum.


Katılmıyorum. Veri erişim kodunuzun tamamını nHibernate ile değiştirirseniz, harici davranışı değiştirmez ancak Fowler'in "disiplinli tekniklerini" izlemez. Bu yeniden yapılanma olur ve buna refactoring diyoruz, içerdiği risk faktörünü gizler.
pdr,

1

Tüm saygımla, bir sınıfın kullanıcılarının sınıfla yapılan uygulamaların son kullanıcıları olmadığını, aksine, refactor yapılan sınıfın çağrılması veya miras alınması yoluyla kullanılmasıyla uygulanan sınıfların olduğunu hatırlamalıyız. .

"Dış davranış değişmemelidir" derken, kullanıcılar söz konusu olduğunda sınıfın aynen daha önce olduğu gibi davrandığını kastediyorsunuz. Orijinal (yeniden düzenlenmemiş) uygulamanın tek bir sınıf olduğu ve yeni (yeniden yapılanmış) uygulamanın, sınıfın üzerine kurulduğu bir veya daha fazla süper sınıfa sahip olabileceği, ancak kullanıcılar asla içlerinde (uygulama) göremedikleri olabilir. sadece arayüzü görün.

Bu nedenle, eğer bir sınıf "doSomethingAmazing" adında bir yönteme sahipse, bu, başvurdukları sınıf tarafından veya o sınıfın üzerine inşa edilmiş bir üst sınıf tarafından uygulandığında, kullanıcı için önemli değildir. Kullanıcı için önemli olan şey, yeni (yeniden yapılanmış) "doSomethingAmazing" in eski (etkilenmemiş) "doSomethingAmazing" ile aynı sonucu olmasıdır.

Ancak, çoğu durumda refactoring denilen şey gerçek refactoring değil, belki de yeni bir özellik eklemek için kodu değiştirmeyi kolaylaştırmak için yapılmış bir yeniden yorumlamadır. Dolayısıyla bu daha sonraki (sözde) yeniden düzenleme durumunda, yeni (yeniden düzenlenmiş) kod aslında eskisinden farklı bir şey veya belki de eski bir şey yapar.


Bir pencere formu bir iletişim kutusu açmak için kullanılırsa "Tamam düğmesine basmak istediğinizden emin misiniz?" ve kaldırmaya karar verdim çünkü çok az başarıya ulaşıyor ve kullanıcıları kızdırıyor, sonra kodu yeniden belirledim, yeniden tasarladım, değiştirdim, çıkardım, başka?
İş

@job: Programı yeni özelliklere uygun olarak değiştirdiniz.
jmoreno

IMHO burada farklı kriterleri karıştırıyor olabilirsiniz. Sıfırdan kod yeniden yazmak gerçekten canlandırıcı değildir, ancak dış davranışını değiştirip değiştirmemesine bakılmaksızın bu böyledir. Ayrıca, bir sınıf arayüzünü değiştirmek, yeniden yapılanma yapmadıysa, nasıl Taşıma Yöntemi ve ark. refactorings kataloğunda var mı?
Péter Török

@ Péter Török - Tamamen "sınıf arayüzünü değiştirerek" ne demek istediğine bağlı. Çünkü kalıtım uygulayan bir OOP dilinde, sınıfın arayüzü sadece sınıfın kendisi tarafından tüm ataları tarafından uygulananları içermiyor. Bir sınıf arayüzünü değiştirmek, arayüze bir metodu kaldırmak / eklemek (veya bir metodun imzasını değiştirmek - yani geçen bir parametre tipi) anlamına gelir. Yeniden düzenleme, yönteme, sınıfa veya bir üst sınıfa kimin yanıt verdiği anlamına gelir.
Zeke Hansell

IMHO - bu sorunun tamamı programcılar için faydalı bir değeri olmayacak kadar ezoterik olabilir.
Zeke Hansell

1

Öncelikle "dış davranış" ile halka açık arayüzden bahsediyor, ancak bu aynı zamanda sistemin çıktılarını / eserlerini de kapsıyor. (yani bir dosya üreten bir yönteminiz var, dosyanın biçimini değiştirmek dış davranışı değiştirir)

e: "move yöntemini" dışsal davranışta bir değişiklik olarak düşünürdüm. Fowler'ın vahşi doğada var olan mevcut kod tabanları hakkında konuştuğunu aklınızda bulundurun. Durumunuza bağlı olarak, yaptığınız değişikliğin herhangi bir harici müşteriyi bozmadığını ve mutlu bir şekilde ilerlemenizi doğrulayabilirsiniz.

e2: "Dış davranışları değiştiren reworks'ler için doğru kelime nedir?" - API Refactoring, Change Breaking, vb ... hala yeniden canlandırıyor, müşterileri ile zaten vahşi olan ortak bir arayüzün yeniden yapılandırılması için en iyi uygulamaları izlemiyor.


Ama eğer halka açık bir arayüzden bahsediyorsa, "Yeniden taşıma yöntemi" refactoring'den ne haber?
SiberianGuy

@ Idsa Sorunuzu yanıtlamak için cevabımı düzenledik.

@kekela, ama hala bu "refactoring" olayının bittiği yer bana hala net değil
SiberianGuy

@ idsa Gönderdiğiniz tanıma göre, genel bir arayüzü değiştirdiğiniz anda yeniden canlandırıcı davranmakla sonuçlanır. (Bu örnek olacak bir sınıftan gelen genel bir yöntem hareketli)

0

"Move method", bir yeniden düzenleme tekniğidir, kendi başına bir yeniden düzenleme işlemi değildir. Bir yeniden düzenleme, birkaç yeniden düzenleme tekniğini sınıflara uygulama işlemidir. Orada, bir sınıfa "taşıma yöntemi" uyguladığımı söylediğinizde, aslında "Ben yeniden sınıflandıracağım (sınıf)" anlamına gelmez, aslında "Ben bu sınıfa yeni bir yeniden uygulama tekniği uyguladım" anlamına gelir. Yeniden düzenleme, en saf anlamıyla tasarıma veya daha spesifik olarak, kara kutu olarak görülebilen uygulama tasarımının bir kısmına uygulanır.

Sınıflar bağlamında kullanılan "yeniden düzenleme" nin "yeniden düzenleme tekniği" anlamına geldiğini, böylece "hareket yönteminin" yeniden yapılandırma sürecinin tanımını bozmadığını söyleyebilirsiniz. Aynı sayfada, tasarım bağlamında "yeniden düzenleme", koddaki mevcut özellikleri bozmaz, yalnızca tasarımı ("yine de amacıdır") bozar.

Sonuç olarak, soruda belirtilen "sınır", refactoring tekniğini refactoring işlemi ile karıştırırsanız (karışım: D).

Not: İyi soru, btw.


Birkaç kez okuyun, ancak yine de alamadım
SiberianGuy

hangi kısmını anlamadın (tanımınızın uygulandığı süreçte yeniden düzenleme işlemi var veya örneğin yeniden uygulama tekniği, örneğin uygulamanın uygulanmadığı hareket yöntemi; bunun için hareket yöntemi yeniden yapılandırma tanımını bozmuyor ne olursa olsun, işlemez veya sınırları aşmaz). Örneğin, kaygılarınız için var olmamanız gereken endişeyi söylüyorum. Yeniden yapılanmanın sınırı, bulanık bir şey değildir. sen sadece başka bir şeye bir şeyin tanımını uyguluyorsun.
Belun

0

Faktoring sayıları hakkında konuşursanız, birlikte çarpıldığında başlangıç ​​sayısına eşit olan tam sayı grubunu tanımlarsınız. Eğer faktörü tanımlamak için bu tanımı alırsak ve bunu programlama refactor programına uygularsak, yeniden düzenleme bir program olarak en küçük mantıksal birimlere bölünür, öyle ki bir program olarak çalıştırıldıklarında aynı çıktıyı verir (aynı girdi verilir) ) orijinal program olarak.


0

Bir yeniden düzenlemenin sınırları, belirli bir yeniden düzenlemeye özgüdür. Sadece bir cevap olamaz ve her şeyi kapsar. Bunun bir nedeni, yeniden düzenleme teriminin kendisinin belirli olmamasıdır.

Refactor yapabilirsiniz:

  • Kaynak kodu
  • Program Mimarisi
  • UI Tasarım / Kullanıcı Etkileşimi

ve başka pek çok şeyden eminim.

Belki de refactor olarak tanımlanabilir

"belirli bir sistemdeki entropiyi azaltan bir eylem veya eylemler dizisi"


0

Kesinlikle ne kadar refaktör olabileceğine dair bazı sınırlar var. Bakınız: İki Algoritma Ne Zaman Aynıdır?

İnsanlar genellikle algoritmaları, bunları uygulayan programlardan daha soyut görürler. Bu fikri biçimlendirmenin doğal yolu, algoritmaların uygun bir denklik ilişkisine göre denklik program sınıfları olmasıdır. Böyle bir denklik ilişkisinin olmadığını iddia ediyoruz.

Yani, fazla ileri gitmeyin, yoksa sonuçta hiçbir güveniniz olmaz. Öte yandan, deneyim, bir algoritmayı sıklıkla diğeriyle değiştirebileceğiniz ve aynı cevapları, bazen daha hızlı alabileceğinizi belirtir. Onun güzelliği bu mu?


0

“Dış” anlamını düşünebilirsiniz.

Günlük ayağa kalkmadan dışarıda.

Bu nedenle, sistemde hiçbir domuzu etkilemeyen herhangi bir değişiklik, yeniden yapılanma olarak kabul edilebilir.

Sınıf arayüzünü değiştirmek, eğer sınıf sadece ekibiniz tarafından oluşturulan ve bakımı yapılan tek bir sistem tarafından kullanılıyorsa, hiç sorun değildir. Ancak, sınıf, her .net programcısı tarafından kullanılan .net çerçevesindeki bir genel sınıf ise, çok farklı bir konudur.

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.