C# 코드 재구성 - 소개

당신은 코드를 얼마나 자주 청소하고, 얼마나 자주 코드 재구성을 진행합니까?코드 재구성이 무엇인지 모르면, 기존 기능을 바꾸지 않고, 기존 코드를 더욱 읽기, 유연성, 유지보수성, 확장성으로 바꾸는 과정입니다.

왜 코드 재구성을 진행합니까?


하나의 예를 제시함으로써 왜 우리가 코드 재구성을 필요로 하는지 쉽게 설명할 수 있다.다음 예는 Animal 클래스를 보여 줍니다. 이 클래스는 AnimalType를 매개 변수로 하는 함수를 가지고 있습니다.만약 네가 AnimalType.Cat를 통과한다면, 그것은 너Miao와 같은 물건을 개에게 돌려줄 것이다.
public class Animal {
    public string Sound(AnimalType animalType) {
        if (animalType == AnimalType.Cat) {
            return "Miao";
        } else if (animalType == AnimalType.Dog) {
            return "Woof";
        }
        return "";
    }
}
그럼 이거class는 뭐가 문제예요?
만약 내가 이 종류에 10개의 동물의 소리를 첨가해야 한다면, 나는 10개의 If 문장을 써야 한다.예컨대 아래의 예.
public class Animal {
    public string Sound(AnimalType animalType) {
        if (animalType == AnimalType.Cat) {
            return "Miao";
        } else if (animalType == AnimalType.Dog) {
            return "Woof";
        } else if (animalType == AnimalType.Bird) {
            return "Chick";
        } // else if () x 7 more...
        return "";
    }
}
너는 이 함수가 비대해지거나 누군가가 그것을 afat function라고 부르는 것을 발견할 수 있다.너는 아마도 생각할 것이다. 그래, 이것은 단지 함수일 뿐, 나는 그것을 확장하는 문제를 발견하지 못했다.나는 끊임없이 else-if 문장을 추가하기만 하면, 그것은 매력적일 것이다.
이 함수가 매우 작을 때, 너는 아마 맞을 것이다.함수에 100여 개의 소리를 추가한 후에 Fly 라는 함수를 실현하려면 어떻게 해야 합니까?당신은 이 새로운 기능을 어떻게 처리할 계획입니까?if 성명을 한 부 더 쓰시겠어요?당신은 어떻게 당신이 동물 유형을 놓치지 않고, 동물마다 다른 비행 방식의 정확한 실시를 확보합니까?
public class Animal {
    public string Sound(AnimalType animalType) {
        // sound implementation
    }

    public void Fly(AnimalType animalType) {
        if (animalType == AnimalType.Cat || animalType == AnimalType.Dog) { 
            // this if statement might go wrong, because not every animal can fly.
            throw new InvalidOperationException("This animal cannot fly!!");
        } else if (animalType == AnimalType.Bird) {
            // fly implementation
        } 
    }
}
따라서 상술한 실시는 지속가능하지 않다.우선 위의 실현은 이해하기 어렵다.만약 내가 동물 유형을 찾아서 그 방식을 바꾸려고 한다면, 나는 너무 많은 sound 문장이 있기 때문에 검색하는 데 더 많은 시간을 들여야 한다.새로운 동물 유형을 제거하거나 추가하는 것도 마찬가지다.
위의 실현에 대해 추상적인 if 클래스와 다시 써야 하는 animal 함수를 만들어서 더 잘 할 수 있습니다.클래스에 Sound를 추가하여 abstract클래스가 실례화되는 것을 방지한다.또한 실현Animal 함수를 통해 동물류를 만들 수 있으나 실현되지 않은 Sound 함수의 동물 유형을 놓치지 않는다.이렇게 하면 당신의 수업은 더욱 유창하고 날씬하며 읽기 쉬워 보일 것이다.
public abstract class Animal {
    public abstract string Sound();
}

public class Cat: Animal {
    public override string Sound() {
        return "Miao";
    }
}

public class Dog: Animal {
    public override string Sound() {
        return "Woof";
    }
}

// same for the rest of the animals

너는 이런 문제가 있을 수 있다. 그러나 나는 동물 유형을 사용해서 동물의 소리를 얻고 싶다.그렇지 않으면, 나는 다시 Sound 문장을 사용하여 애니메이션 클래스를 실례화할 것이며, 코드는 모든 곳으로 복사될 것이다.
맞아, 우리는 여전히 if 문구를 사용하여 이 종류를 실례화해야 한다.그러나 우리는 simple factory design pattern를 사용하여 봉인하여 실현할 것이다.
public class AnimalFactory {
    public static Create(AnimalType animalType) {
        if (animalType = AnimalType.Cat) return new Cat();
        if (animalType = AnimalType.Dog) return new Dog();
        // implementation for other animals...
        throw new InvalidOperationException("Invalid animal type!");
    }
}

// usage
Animal cat = AnimalFactory.Create(AnimalType.Cat);
cat.Sound(); // Miao
너는 if 함수가 어떠냐고 물어볼 수도 있다.모든 동물이 날 수 있는 것은 아니지, 그렇지?
네가 옳다. 모든 동물이 날 수 있는 것은 아니기 때문에 모든 동물에게 Fly 기능을 실시하는 것은 좋은 생각이 아니다.그렇지 않으면, 만약 당신이 100종의 동물을 가지고 있다면, 당신은 반드시 100개의 기능을 실현해야 한다.Fly 인터페이스를 만들 수 있습니다.이 생각은 SOLID principle - Interface Segregation Principle에서 나온 것이다.다음 예제를 참조하십시오.
public interface IFlyableAnimal {
    void Fly();
}

public class Bird: Animal, IFlyableAnimal {
    public override string Sound() {
        return "Chick";
    }

    public void Fly() {
        // some fly implementation
    }
}

// usage
Animal bird = AnimalFactory.Create(AnimalType.Bird);
bird.Sound(); // Chick
if (bird is IFlyableAnimal) {
    bird.Fly();
}
위의 예를 본 후에 이 종류는 더욱 얇고 확장이 가능하게 변했다.우리가 IFlyableAnimal을 만들어야 할 때마다 추상AnimalType류를 확장하고 동물이 비행할 수 있다면 우리는 Animal인터페이스만 실현할 수 있다.컴파일러는 개발자가 함수를 실현하지 않으면 컴파일러가 오류를 표시하기 때문에 처리를 도와줍니다.이런 디자인은 SOLID principle - open-close concept의 요구에 부합된다.

코드는 언제 재구성합니까?


코드를 재구성하는 가장 좋은 시기는 당신이 하나의 특성을 완성한 후에 있을 수 있습니다.너는 너의 동업자와 코드 심사 회의를 열어 코드를 구축하는 가장 좋은 방법을 토론할 것이다.
그러나 실현된 후에 코드 재구성을 할 기회가 항상 있는 것은 아닙니다.QA는 사용자의 실현을 기다리고 있습니다. 제품 소유자는 코드를 재구성할 수 있는 추가 시간을 얻지 못합니다. 정해진 시간 안에 전달해야 하기 때문입니다.
근데 괜찮아요.같은 코드의 특성을 다시 강화할 수 있다는 것을 알았을 때, 코드 재구성을 할 수 있습니다.그 이후로 제품 담당자에게 현재의 코드 라이브러리에 코드 재구성이 필요하기 때문에 더 많은 시간이 필요하다고 요구할 수 있다.

결론


코드 재구성을 연습하는 것은 너나 너의 팀에 약간의 이익을 가져다 줄 것이다.그중 하나는 코드가 더 깨끗해 보이고 읽기 쉽다는 것이다.현재 개발자가 같은 코드에서 뛰어난 기능을 강화한다는 소식을 들었을 때, 개발은 확장할 수 있기 때문에 더욱 쉬워질 것이다.동시에 발전 속도가 훨씬 빨라질 것이다.
다른 한편, 코드가 필요할 때 재구성되지 않으면 다음 개발자는 코드를 읽어야 하기 때문에 간단한 강화를 읽고 강화하는 데 더 많은 시간이 필요하다.상황이 더 나빠졌을 때, 코드가 지속가능하지 않기 때문에 곳곳에 오류가 있다는 것을 발견할 수 있을 것이다.

속담에 이르기를

The true professional knows that delivering function at the expense of structure is a fool’s errand. It is the structure of your code that allows it to be flexible.

If you compromise the structure, you compromise the future.
The fundamental assumption underlying all software projects is that software is easy to change. If you violate this assumption by creating inflexible structures, then you undercut the economic model that the entire industry is based on.

In short: You must be able to make changes without exorbitant costs.

~ The clean coder by Robert C. Martin


마지막으로 가장 중요하지 않은 점은 즐거움의 인코딩과 즐거움의 학습😆

좋은 웹페이지 즐겨찾기