CodeGym /Java Blogu /Rastgele /Java'da yeniden düzenleme nasıl çalışır?
John Squirrels
Seviye
San Francisco

Java'da yeniden düzenleme nasıl çalışır?

grupta yayınlandı
Programlamayı öğrenirken, kod yazmaya çok zaman harcarsınız. Yeni başlayan geliştiricilerin çoğu, gelecekte yapacaklarının bu olduğuna inanıyor. Bu kısmen doğrudur, ancak bir programcının işi aynı zamanda kodu korumayı ve yeniden düzenlemeyi de içerir. Bugün yeniden düzenleme hakkında konuşacağız. Java'da yeniden düzenleme nasıl çalışır - 1

CodeGym'de yeniden düzenleme

Yeniden düzenleme, CodeGym kursunda iki kez işlenir: Büyük görev, uygulama yoluyla gerçek yeniden düzenleme ile tanışma fırsatı sağlar ve IDEA'daki yeniden düzenleme dersi, hayatınızı inanılmaz derecede kolaylaştıracak otomatik araçlara dalmanıza yardımcı olur.

Yeniden düzenleme nedir?

İşlevselliğini değiştirmeden kodun yapısını değiştiriyor. Örneğin, 2 sayıyı karşılaştıran ve ilki daha büyükse doğru , aksi takdirde yanlış döndüren bir yöntemimiz olduğunu varsayalım :

    public boolean max(int a, int b) {
        if(a > b) {
            return true;
        } else if (a == b) {
            return false;
        } else {
            return false;
        }
    }
Bu oldukça hantal bir koddur. Yeni başlayanlar bile nadiren böyle bir şey yazardı, ancak bir şans var. if-else6 satırlık yöntemi daha kısa ve öz bir şekilde yazabiliyorsanız neden bir blok kullanasınız ?

 public boolean max(int a, int b) {
      return a > b;
 }
Şimdi yukarıdaki örnekle aynı işlemi gerçekleştiren basit ve zarif bir yöntemimiz var. Yeniden düzenleme şu şekilde çalışır: Özünü etkilemeden kodun yapısını değiştirirsiniz. Daha yakından inceleyeceğimiz birçok yeniden düzenleme yöntemi ve tekniği vardır.

Neden yeniden düzenlemeye ihtiyacınız var?

Birkaç sebep var. Örneğin, kodda basitlik ve kısalık elde etmek için. Bu teorinin savunucuları, kodu anlamak için birkaç düzine yorum satırına ihtiyaç duyulsa bile kodun olabildiğince kısa olması gerektiğine inanırlar. Diğer geliştiriciler, kodun minimum sayıda yorumla anlaşılır olması için yeniden düzenlenmesi gerektiğine inanıyor. Her takım kendi pozisyonunu benimser, ancak yeniden düzenlemenin azaltma anlamına gelmediğini unutmayın . Temel amacı kodun yapısını iyileştirmektir. Bu genel amaca birkaç görev dahil edilebilir:
  1. Yeniden düzenleme, diğer geliştiriciler tarafından yazılan kodun anlaşılmasını geliştirir.
  2. Hataların bulunmasına ve düzeltilmesine yardımcı olur.
  3. Yazılım geliştirme hızını hızlandırabilir.
  4. Genel olarak, yazılım tasarımını geliştirir.
Yeniden düzenleme uzun süre yapılmazsa, geliştirme, işin tamamen durması da dahil olmak üzere zorluklarla karşılaşabilir.

"Kod kokuyor"

Kod yeniden düzenleme gerektirdiğinde, bir "kokusu" olduğu söylenir. Elbette kelimenin tam anlamıyla değil, ancak böyle bir kod gerçekten çok çekici görünmüyor. Aşağıda, ilk aşama için temel yeniden düzenleme tekniklerini keşfedeceğiz.

Mantıksız derecede büyük sınıflar ve yöntemler

Sınıflar ve yöntemler, tam olarak büyük boyutlarından dolayı, hantal ve etkili bir şekilde çalışmak imkansız olabilir.

Büyük sınıf

Böyle bir sınıf, çok sayıda kod satırına ve birçok farklı yönteme sahiptir. Bir geliştirici için yeni bir sınıf oluşturmak yerine mevcut bir sınıfa özellik eklemek genellikle daha kolaydır, bu nedenle sınıf büyür. Kural olarak, böyle bir sınıfa çok fazla işlevsellik sığdırılır. Bu durumda, işlevselliğin bir kısmını ayrı bir sınıfa taşımak yardımcı olur. Yeniden düzenleme teknikleri bölümünde bundan daha ayrıntılı olarak bahsedeceğiz.

Uzun yöntem

Bu "koku", bir geliştirici bir yönteme yeni işlevsellik eklediğinde ortaya çıkar: "Kodu buraya yazabiliyorsam neden ayrı bir yönteme parametre denetimi koymalıyım?", "Maksimum değeri bulmak için neden ayrı bir arama yöntemine ihtiyacım var? dizideki bir eleman mı? Burada tutalım. Kod bu şekilde daha anlaşılır olacaktır" ve bunun gibi diğer kavram yanılgıları.

Uzun bir yöntemi yeniden düzenlemenin iki kuralı vardır:

  1. Yöntem yazarken yorum eklemek istiyorsanız, işlevi ayrı bir yönteme koymalısınız.
  2. Bir metot 10-15 satırdan fazla kod alıyorsa, gerçekleştirdiği görevleri ve alt görevleri belirlemeli ve alt görevleri ayrı bir metot içine koymaya çalışmalısınız.

Uzun bir yöntemi ortadan kaldırmanın birkaç yolu vardır:

  • Yöntemin işlevselliğinin bir kısmını ayrı bir yönteme taşıyın
  • Yerel değişkenler, işlevselliğin bir kısmını taşımanızı engelliyorsa, tüm nesneyi başka bir yönteme taşıyabilirsiniz.

Çok sayıda ilkel veri türü kullanmak

Bu sorun genellikle bir sınıftaki alanların sayısı zamanla arttığında ortaya çıkar. Örneğin, her şeyi (para birimi, tarih, telefon numaraları vb.) küçük nesneler yerine ilkel türlerde veya sabitlerde saklarsanız. Bu durumda, mantıksal bir alan gruplamasını ayrı bir sınıfa (çıkarma sınıfı) taşımak iyi bir uygulama olacaktır. Verileri işlemek için sınıfa yöntemler de ekleyebilirsiniz.

Çok fazla parametre

Bu, özellikle uzun bir yöntemle birlikte oldukça yaygın bir hatadır. Genellikle, bir yöntemin çok fazla işlevi varsa veya bir yöntem birden fazla algoritma uygularsa oluşur. Uzun parametre listelerinin anlaşılması çok zordur ve bu tür listelerle yöntemlerin kullanılması elverişsizdir. Sonuç olarak, tüm bir nesneyi geçmek daha iyidir. Bir nesnede yeterli veri yoksa, daha genel bir nesne kullanmalı veya yöntemin işlevselliğini bölerek her yöntemin mantıksal olarak ilişkili verileri işlemesini sağlamalısınız.

veri grupları

Mantıksal olarak ilişkili veri grupları genellikle kodda görünür. Örneğin, veritabanı bağlantı parametreleri (URL, kullanıcı adı, şifre, şema adı vb.). Bir alan listesinden tek bir alan çıkarılamıyorsa, bu alanlar ayrı bir sınıfa (çıkarma sınıfı) taşınmalıdır.

OOP ilkelerini ihlal eden çözümler

Bu "kokular", bir geliştirici uygun OOP tasarımını ihlal ettiğinde ortaya çıkar. Bu, kişi OOP yeteneklerini tam olarak anlamadığında ve bunları tam olarak veya doğru şekilde kullanamadığında olur.

Mirasın kullanılamaması

Bir alt sınıf, üst sınıfın işlevlerinin yalnızca küçük bir alt kümesini kullanıyorsa, yanlış hiyerarşi kokuyor demektir. Bu olduğunda, genellikle gereksiz yöntemler basitçe geçersiz kılınmaz veya istisnalar oluştururlar. Bir sınıfın diğerini devralması, alt sınıfın üst sınıfın neredeyse tüm işlevlerini kullandığı anlamına gelir. Doğru bir hiyerarşi örneği: Java'da yeniden düzenleme nasıl çalışır - 2Yanlış bir hiyerarşi örneği: Java'da yeniden düzenleme nasıl çalışır - 3

Anahtar bildirimi

Bir açıklamada yanlış olan ne olabilir switch? Çok karmaşık hale geldiğinde kötüdür. İlgili bir sorun, çok sayıda iç içe ififadedir.

Farklı arayüzlere sahip alternatif sınıflar

Birden çok sınıf aynı şeyi yapar, ancak yöntemlerinin adları farklıdır.

geçici alan

Bir sınıfın, bir nesnenin değeri ayarlandığında yalnızca ara sıra ihtiyaç duyduğu geçici bir alanı varsa ve boşsa veya nullgeri kalan zamanlarda Tanrı korusun, o zaman kod kokar. Bu şüpheli bir tasarım kararıdır.

Modifikasyonu zorlaştıran kokular

Bu kokular daha ciddidir. Diğer kokular esas olarak kodu anlamayı zorlaştırır, ancak bunlar onu değiştirmenizi engeller. Herhangi bir yeni özellik sunmaya çalıştığınızda, geliştiricilerin yarısı işi bırakıyor ve yarısı çıldırıyor.

Paralel kalıtım hiyerarşileri

Bu sorun, bir sınıfı alt sınıflamak, farklı bir sınıf için başka bir alt sınıf oluşturmanızı gerektirdiğinde kendini gösterir.

Düzgün dağıtılmış bağımlılıklar

Herhangi bir değişiklik, bir sınıfın tüm kullanımlarını (bağımlılıkları) aramanızı ve birçok küçük değişiklik yapmanızı gerektirir. Bir değişiklik — birçok sınıfta düzenleme yapar.

Karmaşık modifikasyon ağacı

Bu koku bir öncekinin tersidir: değişiklikler bir sınıftaki çok sayıda yöntemi etkiler. Kural olarak, bu tür bir kodun basamaklı bağımlılığı vardır: bir yöntemi değiştirmek, bir şeyi diğerinde düzeltmenizi ve ardından üçüncüsünde vb. Bir sınıf - birçok değişiklik.

"Çöp kokuyor"

Baş ağrısına neden olan oldukça hoş olmayan bir koku kategorisi. Yararsız, gereksiz, eski kod. Neyse ki, modern IDE'ler ve linterler bu tür kokulara karşı uyarı vermeyi öğrendi.

Bir yöntemde çok sayıda yorum

Bir yöntemin hemen hemen her satırında çok sayıda açıklayıcı yorum vardır. Bu genellikle karmaşık bir algoritmadan kaynaklanır, bu nedenle kodu birkaç küçük yönteme bölmek ve onlara açıklayıcı adlar vermek daha iyidir.

Yinelenen kod

Farklı sınıflar veya yöntemler aynı kod bloklarını kullanır.

Tembel sınıf

Bir sınıf, büyük olması planlanmış olmasına rağmen çok az işlevsellik alır.

kullanılmayan kod

Kodda bir sınıf, yöntem veya değişken kullanılmaz ve ölü ağırlıktır.

aşırı bağlantı

Bu koku kategorisi, kodda çok sayıda gerekçesiz ilişki ile karakterize edilir.

Dış yöntemler

Bir yöntem, başka bir nesneden gelen verileri kendi verilerinden çok daha sık kullanır.

uygunsuz yakınlık

Bir sınıf, başka bir sınıfın uygulama ayrıntılarına bağlıdır.

Uzun sınıf görüşmeleri

Bir sınıf, üçüncüden veri isteyen, dördüncüden veri alan diğerini çağırır, vb. Bu kadar uzun bir çağrı zinciri, mevcut sınıf yapısına yüksek bağımlılık anlamına gelir.

Görev dağıtıcı sınıfı

Bir sınıf, yalnızca başka bir sınıfa görev göndermek için gereklidir. Belki de kaldırılmalıdır?

Yeniden düzenleme teknikleri

Aşağıda, açıklanan kod kokularını ortadan kaldırmaya yardımcı olabilecek temel yeniden düzenleme tekniklerini tartışacağız.

Bir sınıfı ayıklayın

Bir sınıf çok fazla işlev gerçekleştirir. Bazıları başka bir sınıfa taşınmalıdır. Örneğin, Humanbir ev adresi de depolayan ve tam adresi döndüren bir yöntemi olan bir sınıfımız olduğunu varsayalım:

class Human {
    private String name;
    private String age;
    private String country;
    private String city;
    private String street;
    private String house;
    private String quarter;
 
    public String getFullAddress() {
        StringBuilder result = new StringBuilder();
        return result
                        .append(country)
                        .append(", ")
                        .append(city)
                        .append(", ")
                        .append(street)
                        .append(", ")
                        .append(house)
                        .append(" ")
                        .append(quarter).toString();
    }
 }
Adres bilgilerini ve ilişkili yöntemi (veri işleme davranışı) ayrı bir sınıfa koymak iyi bir uygulamadır:

 class Human {
    private String name;
    private String age;
    private Address address;
 
    private String getFullAddress() {
        return address.getFullAddress();
    }
 }
 class Address {
    private String country;
    private String city;
    private String street;
    private String house;
    private String quarter;
 
    public String getFullAddress() {
        StringBuilder result = new StringBuilder();
        return result
                        .append(country)
                        .append(", ")
                        .append(city)
                        .append(", ")
                        .append(street)
                        .append(", ")
                        .append(house)
                        .append(" ")
                        .append(quarter).toString();
    }
 }

Bir yöntemi ayıklayın

Bir yöntemin izole edilebilecek bazı işlevleri varsa, onu ayrı bir yönteme yerleştirmelisiniz. Örneğin, ikinci dereceden bir denklemin köklerini hesaplayan bir yöntem:

    public void calcQuadraticEq(double a, double b, double c) {
        double D = b * b - 4 * a * c;
        if (D > 0) {
            double x1, x2;
            x1 = (-b - Math.sqrt(D)) / (2 * a);
            x2 = (-b + Math.sqrt(D)) / (2 * a);
            System.out.println("x1 = " + x1 + ", x2 = " + x2);
        }
        else if (D == 0) {
            double x;
            x = -b / (2 * a);
            System.out.println("x = " + x);
        }
        else {
            System.out.println("Equation has no roots");
        }
    }
Üç olası seçeneğin her birini ayrı yöntemlerle hesaplıyoruz:

    public void calcQuadraticEq(double a, double b, double c) {
        double D = b * b - 4 * a * c;
        if (D > 0) {
            dGreaterThanZero(a, b, D);
        }
        else if (D == 0) {
            dEqualsZero(a, b);
        }
        else {
            dLessThanZero();
        }
    }
 
    public void dGreaterThanZero(double a, double b, double D) {
        double x1, x2;
        x1 = (-b - Math.sqrt(D)) / (2 * a);
        x2 = (-b + Math.sqrt(D)) / (2 * a);
        System.out.println("x1 = " + x1 + ", x2 = " + x2);
    }
 
    public void dEqualsZero(double a, double b) {
        double x;
        x = -b / (2 * a);
        System.out.println("x = " + x);
    }
 
    public void dLessThanZero() {
        System.out.println("Equation has no roots");
    }
Her yöntemin kodu çok daha kısa ve anlaşılması kolay hale geldi.

Bütün bir nesneyi geçirme

Bir yöntem parametrelerle çağrıldığında, bazen şöyle bir kod görebilirsiniz:

 public void employeeMethod(Employee employee) {
     // Some actions
     double yearlySalary = employee.getYearlySalary();
     double awards = employee.getAwards();
     double monthlySalary = getMonthlySalary(yearlySalary, awards);
     // Continue processing
 }
 
 public double getMonthlySalary(double yearlySalary, double awards) {
      return (yearlySalary + awards)/12;
 }
employeeMethodDeğerleri almaya ve bunları ilkel değişkenlerde depolamaya ayrılmış 2 tam satıra sahiptir . Bazen bu tür yapılar 10 satıra kadar sürebilir. Nesnenin kendisini iletmek ve onu gerekli verileri çıkarmak için kullanmak çok daha kolaydır:

 public void employeeMethod(Employee employee) {
     // Some actions
     double monthlySalary = getMonthlySalary(employee);
     // Continue processing
 }
 
 public double getMonthlySalary(Employee employee) {
     return (employee.getYearlySalary() + employee.getAwards())/12;
 }

Basit, kısa ve öz.

Alanları mantıksal olarak gruplandırmak ve parçalara ayırmak, classDespiteyukarıdaki örneklerin çok basit olduğu ve bunlara baktığınızda birçoğunuzun "Bunu kim yapıyor?" kodu yeniden düzenleme isteksizliği veya basitçe "bu yeterince iyi" tavrı.

Yeniden düzenleme neden etkilidir?

İyi bir yeniden düzenlemenin sonucu olarak, bir programın kodu okunması kolay olur, mantığını değiştirme olasılığı korkutucu değildir ve yeni özellikler getirmek kod analizi cehennemi haline gelmez, bunun yerine birkaç gün için hoş bir deneyim olur. . Sıfırdan bir program yazmak daha kolay olacaksa yeniden düzenleme yapmamalısınız. Örneğin, ekibinizin kodu anlamak, analiz etmek ve yeniden düzenlemek için gereken emeğin, aynı işlevi sıfırdan uygulamaktan daha fazla olacağını tahmin ettiğini varsayalım. Veya yeniden düzenlenecek kodda hata ayıklamanın zor olduğu çok sayıda sorun varsa. Bir programcının çalışmasında kodun yapısının nasıl iyileştirileceğini bilmek çok önemlidir. Ve Java'da programlamayı öğrenmek en iyi, pratiği vurgulayan çevrimiçi kurs olan CodeGym'de yapılır. Anında doğrulama ile 1200'den fazla görev, yaklaşık 20 mini proje, oyun görevleri — tüm bunlar kodlama konusunda kendinize güvenmenize yardımcı olacaktır. Başlamak için en iyi zaman şimdi :)

Kendinizi yeniden düzenlemeye daha fazla kaptırmanızı sağlayacak kaynaklar

Yeniden düzenlemeyle ilgili en ünlü kitap, Martin Fowler'ın "Yeniden Düzenleme. Mevcut Kodun Tasarımını Geliştirme" kitabıdır. Yeniden düzenleme hakkında, önceki bir kitaba dayanan ilginç bir yayın da var: Joshua Kerievsky'nin "Kalıpları Kullanarak Yeniden Düzenleme". Kalıplardan bahsetmişken... Yeniden düzenleme yaparken, temel tasarım kalıplarını bilmek her zaman çok faydalıdır. Bu mükemmel kitaplar bu konuda yardımcı olacaktır: Kalıplardan bahsetmişken... Yeniden düzenleme yaparken, temel tasarım kalıplarını bilmek her zaman çok faydalıdır. Bu mükemmel kitaplar bu konuda yardımcı olacaktır:
  1. Head First serisinden Eric Freeman, Elizabeth Robson, Kathy Sierra ve Bert Bates tarafından yazılan "Design Patterns"
  2. Dustin Boswell ve Trevor Foucher tarafından yazılan "Okunabilir Kod Sanatı"
  3. Güzel ve zarif kodun ilkelerini belirleyen Steve McConnell tarafından yazılan "Code Complete".
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION