Published on

고급컴퓨터그래픽스 | Clean Coding

Refactoring

refactoring에 대해 들어가기 전에 저번 시간에 배운, 좋은 설계에 대해 짚고 넘어가자.

  • 변경(추가,삭제)에 유연하게 대응(버그 발생이 최소화)할 수 있는 코드
  • 낮은 결합도(관계), 높은 응집도(모듈 자체), 중복 제거, 유의미한 이름
  • 건물 블루프린트가 아니다! 좋은 설계는.. 항상 설계해야하는 것이다.

이 정도 알았으면 리팩토링(refactoring)에 대해 넘어가보자.

리팩토링은 클린 코드화라고 보아도 무방하다. 함수를 분리하고 변수의 이름를 바꾸고 등등 여러 가지 방법이 있다.

  • 메서드명 변경: 직관적이게
  • 메서드 추출: 그룹화를 명료하게
  • 메서드를 메서드 객체로: 지역변수를 객체의 필드화 후 메서드 객체 안의 여러 메서드로 분할하자
  • 조건문을 재정의로: 조건에 따라 분할하기 보다는 하위클래스 내 메서드로 재정의하자
  • Null 검사를 객체에 위임: null 검사하기 보다는 null 객체를 하나 따로 만들자

리팩토링을 하면서 주의할 점이 있다.

  1. 새로운 기능을 추가와 동시에 리팩토링을 하지 말 것
  2. 자주 테스트해본다
  3. 단계를 작게 나누고, 한 단계가 끝날 때 마다 테스트를 돌린다. ➡ 이를 단위테스트라고 한다.

여담이지만.. TDD를 Do-it 파이썬 프레임워크 장고? 책인가 거기서 TDD를 그 때 제대로 해봤던 것 같다. 포스트를 임의로 만들고 네비바가 포스트에도 들어갔을 때 작동이 되는지 이런 식으로 진행이 되는데, 기능 하나 만들 때마다 해서 굉장히 피곤..했었다. 아직도 unittest? 안한다.. 필요성을 딱히 못느낌..ㅠㅠ

다시 본 내용으로 넘어오면, 단위 테스트의 겨우 자체적으로 함수를 불러와서 자의적으로 테스트를 할 수 있으나, 세상에는 참 똑똑한 개발자들이 많은 것 같다. 번거롭게 하지 않고도 단위 테스트 프레임워크를 사용하면 된다!

pip intall pytest

사용방법은 보통 어떤 값이 일치하는지, 값을 넣었을 때 그 값이 안에 있는지 assert를 사용한다. 따로 test_*, *_test 이런식으로 파이썬 파일을 만든후 pytest로 호출하면 된다.😄 경로의 경우 패키지 폴더, 테스트 폴더 분리해서 작성하는 것이 좋음.

Unit test

단위 테스트의 기본적인 속성에 대해 알아보자.

단위 테스트에서의 단위

동작의 단위, 메서드라고 볼 수 있다. 개별의 메서드를 테스트한다기보단 전체적인 동작에 포커스를 두어야 한다.

단위 테스트는 빠르게 수행되어야

아래는 단위테스트라고 말할 수 없음! 하드웨어 자체 테스트는 아니기 때문.

  • 데이터가 연동
  • 네트워크를 통해 통신
  • 파일시스템을 건드린다
  • 특별한 작업이 별도로 필요(편집)

단위 테스트는 서로 격리되어야..

테스트 시에는 의존성을 제거해야 한다. 데이터 베이스 호출, 파일 시스템 호출이 그 예.

Test Double(테스트 대역)

만약 의존성이 포함이 된다면? 테스트 대상 동작이 네트워크 통신이 불가피하다면? 실제 객체를 대체하는 test double을 이용하여 테스트를 작성한다

단위 테스트의 장점

  • 강력한 버그 감지 도구: 오류가 난곳을 쉽게 찾을 수 있음
  • 설계 품질 향상: 테스트를 작성하면 구현부가 아닌 인터페이스에 집중하게 됨. 높은 결합도는 테스트 케이스를 작성하기 어렵기 때문에 필연적으로 결합도를 낮춘다. 결과적으로는 설계 품질이 높아짐.
  • 소프트웨어 안전망: 변경에 따른 문제가 발생해도 나머지 코드에 미치는 영향을 최소화함.
  • 예제로 보여주는 문서: 클래스 기능이 한눈에!

단위 테스트 구조

  • AAA 패턴: Arrange,Act,Assert
  • 안티 패턴: 한번에 검증은 피하기, 테스트 내 if 문 피하기
  • 테스트 당 assert 갯수: 최대한 줄이자
  • 의미 있는 네이밍: test naming conventions - methodName_stateUnderTest_ExpectedBehavior, should_expectedBehavior_when_stateUndetTest, when_stateUndetTest_expect_expectedBehavior, FeatureToBeTested, 등등

단위 테스트 Tip

  • OpenGL/GUI의 경우 렌더링보단 객체의 상태에 포커스를 맞추자.
  • 실수 계산에 있어서 오차 고려 ex.numpy.testing.assert_allclose
  • 테스트 루틴이 없을 때는? 변경하는 곳보다 새로운 기능을 추가할 때 테스트 루틴을 배치한다.

테스트를 따로 작성해서 돌리는 건 시간이 많이 소요된다.. 이럴 때 있는 방법이 바로 테스트 주도 개발(Test-Driven Develoopment, TDD)이다. 내 아킬레스건

Test-Driven Development

위에서 말한 장고 프레임워크 책에서 TDD를 이용하여 개발을 했는데, 실제로 기능 구현 전에 테스트를 하면서 점차 개발을 하였다.

따라서 실제 코드를 작성하기 전에 단위 테스트부터 작성하였다.

사실 이부분에 관해서라면, 이 책에서 실제로 적용하고 개발해보는 시간을 가질 수 있다. 수업 PPT 내용은 지금 봐도 뭔 말인지 모르겠다..ㅠ

테스트 주도 개발의 본질은 항상 먼저 어떻게 코드를 테스트할지 고민하는데 있다. 작성할 코드를 묘사하는 테스트를 설계하면서 실코드를 작성해나가는 것이 특징이다.

Design Patterns

소프트웨어 설계에서 반복적으로 발생하는 문제에 대해 반복적으로 적용할 수 있는 해결 방법이다. 좋은 설계를 위한 원칙이 잘 지켜지고 리팩토링의 목표가 될 수 있다.

Wrapup & Conclusion

  • 좋은 설계를 위한 원칙 - 낮은 결합도, 높은 응집도, 코드의 중복제거, 의미있는 이름
  • 인터페이스 상속과 코드 재사용을 위해 합성관계 사용. ※ 참고
  • Code smells: 원칙 깨짐의 전조 증상
  • Refactoring: 원칙을 유지하기 위해 개선하는 항상 설계하기의 과정
  • Unit testing: 변경 작업에 있어서 수월한 리팩토링과 코드의 인터페이스를 집중함으로서 좋은 설계를 유지
  • TDD: 테스트 코드를 먼저 작성함으로써 버그없는, 빠른 기능의 추가/변경이 가능하고 충실한 단위 테스트 집합을 가질 수 있게 함
  • Design patterns: 원칙이 잘 지켜진 설계에 대한 훌륭한 예제

강의 끝으로는 이렇게 적혀 있었다.

맹목적으로 따르진 말것! 수학의 정석과 같은 것이 아니라 경험에서 나온 조언이다. 적재적소에게 알잘딱깔센하게 사용하는 것이 이상적이다. 하지만 좋은 설계에 관한 원칙은 반드시 기억할 것!

Authors