📚 참고자료

  • [10분 테코톡] 🌊 바다의 JUnit5 => 링크

 

1️⃣ JUnit이란?

  • 자바 개발자의 93%가 사용하는 단위 테스트 프레임워크
  • JUnit5는 2017년 10월 공개
  • 스프링 부트 2.2버전 이상부터 기본 제공

 

 

  • Platform : 테스트를 실행해주는 런처 제공. TestEngine API 제공
  • Jupiter : JUnit 5를 지원하는 TestEngine API 구현체
  • Vintage : Junit 4와 3을 지원하는 TestEngine 구현체

 

셋 다 JUnit5 세부 모듈이다

 

 

 

2️⃣ JUnit5 시작하기

 

  • 스프링 부트 프로젝트
    => 스프링 부트 2.2버전 이상부터는 기본적으로 JUnit5 의존성이 추가된다.

  • 스프링 부트 프로젝트가 아닐 경우
    => 다음과 같이 의존성을 추가해주면 된다.
 <dependency>
 	<groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.6.2</version>
    <scope>test</scope>
 </dependency>

 

 

 

3️⃣ 어노테이션들(Annotaions)

 

@Test

  • 테스트 메서드라는 것을 나타내는 어노테이션
  • JUnit4와 다르게 어떠한 속성도 선언하지 않는다.
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {
	...
}

// JUnit5
@Test
void create() {
	...
}

 

생명주기(LifeCycle) 어노테이션

  • @BeforeAll : 해당 클래스에 위치한 모든 테스트 메서드 실행 전에 딱 한번 실행되는 메서드
  • @AfterAll : 해당 클래스에 위치한 모든 테스트 메서드 실행 후에 딱 한번 실행되는 메서드
  • JUnit4의 @BeforeClass / @AfterClass 와 유사

  • @BeforeEach : 해당 클래스에 위치한 모든 테스트 메서드 실행 전에 실행되는 메서드
  • @AfterEach : 해당 클래스에 위치한 모든 테스트 메서드 실행 후에 실행되는 메서드
  • JUnit4의 @Before / @After와 유사
  • 매 테스트 메서드마다 새로운 클래스를 생성(new)하여 실행 (비효율적)

 

 

@Disabled

  • 테스트를 하고 싶지 않은 클래스나 메서드에 붙이는 어노테이션
  • JUnit4의 @Ignore 과 유사
class DisabledExample {
	@Test
    @Disabled("문제가 해결될 때까지 테스트 중단")
    void test() {
    	System.out.println("테스트");
    }
    
    @Test
    void test2() {
    	System.out.println("테스트2");
    }
}

 

 

@DisplayName

  • 어떤 테스트인지 쉽게 표현할 수 있도록 해주는 어노테이션
  • 공백, Emoji, 특수문자 등을 모두 지원
@DisplayName("특수 테스트\uD83D\uDE00")
class DisplayNameExample {
	@Test
    @DisplayName("굉장한 테스트입니다.")
    void test() {
    }
}

 

 

 

@RepeatedTest

  • 특정 테스트를 반복시키고 싶을 때 사용하는 어노테이션
  • 반복 횟수와 반복 테스트 이름을 설정가능
@RepeatedTest(10)
@DisplayName("반복 테스트")
void repeatedTest() {
	...
}

@RepeatedTest(value = 10, name = "{displayName} 중 {currentRepetition} of {totalRepetitions})
@DisplayName("반복 테스트")
void repeatedTest2() {
	...
}

 

 

@ParameterizedTest

  • 테스트에 여러 다른 매개변수를 대입해가며 반복 실행할 때 사용하는 어노테이션
@ParameterizedTest
@CsvSource(value = {"ACE,ACE:12", "ACE,ACE,ACE:13", "ACE,ACE,TEN:12"}, delimiter = ':')
@DisplayName("에이스 카드가 여러 개일 때 합 구하기")
void calculateCardSumWhenAceIsTwo(final String input, final int expected) {
	final String[] inputs = input.split(",");
    for (final String number : inputs) {
    	final CardNumber cardNumber = CardNumber.valueOf(number);
        dealer.receiveOneCard(new Card(cardNumber, CardType.CLOVER));
    }
    assertThat(dealer.calculateScore()).isEqualTo(expected);
}

 

 

 

 

@Nested

  • 테스트 클래스 안에서 내부 클래스 정의해 테스트를 계층화 할 때 사용
  • 내부클래스는 부모클래스의 멤버 필드에 접근가능
  • Before / After와 같은 테스트 생명주기에 관계된 메소드들도 계층에 맞춰 동작

 

 

Assertions

  • 사전적 의미: 주장, 행사, 단정문
  • 테스트 케이스의 수행 결과를 판별하는 메서드
  • 모든 Junit Jupiter Assertions는 static 메서드

 

 

Assertions - assertAll(executables...)

  • 매개변수로 받는 모든 테스트코드를 한 번에 실행
  • 오류가 나도 끝까지 샐행한 뒤 한 번에 모아서 출력
@Test
public void create_study() {
	Study study = new Study();
    assertNotNull(study);
    assertEquals(Status.STARTED, study.getStatus(), "처음 상태값이 DRAFT");
    assertTrue(study.getLimit() > 0, () -> "최대 인원은 0보다 커야한다.");
}

@Test
public void create_study() {
	Study study = new Study();
    assertAll(
    	() -> assertNotNull(study),
		() -> assertEquals(Status.STARTED, study.getStatus(), "처음 상태값 DRAFT"),
        () -> assertTrue(study.getLimit() > 0, "최대 인원은 0보다 커야한다.")
    );
}

 

 

 

Assertions - assertThrows(expectedType, executable)

  • 예외 발생을 확인하는 테스트
  • executable의 로직이 실행하는 도중 expectedType의 에러를 발생시키는지 확인
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {
	...
}

// JUnit5
@Test
void exceptionThrow() {
	Exception e = assertThrows(Exception.class, () -> new Test(-10));
    assertDoesNotThrow(() -> System.out.println("Do Something"));
}

 

 

Assertions - assertTimeout(duration, executable)

  • 특정 시간 안에 실행이 완료되는지 확인
  • Duration : 원하는 시간
  • Executable : 테스트할 로직
@Rule
public Timeout timeout = Timeout.seconds(5);

class TimeoutExample {
	@Test
    @DisplayName("타임아웃 준수")
    void timeoutNotExceeded() {
    	assertTimeout(ofMinutes(2), () -> Thread.sleep(10));
	}

	@Test
	@DisplayName("타임아웃 초과")
	void timeoutExceeded() {
		assertTimeout(ofMillis(10), () -> Thread.sleep(100));
	}
}

 

 

Assumption

  • 전제문이 true라면 실행, false라면 종료
  • assumeTrue : false일 때 이후 테스트 전체가 실행되지 않음
  • assumingThat : 파라미터로 전달된 코드블럭만 실행되지 않음
void dev_env_only() {
	assumeTrue("DEV".equals(System.getenv("ENV")), () -> "개발 환경이 아닙니다.");
    assertEquals("A", "A");	 // 단정문이 실행되지 않음
}

void some_test() {
	assumingThat("DEV".equals(System.getenv("ENV")),
    	() -> {
        	assertEquals("A", "B");  // 단정문이 실행되지 않음
        });
	assertEquals("A", "A");  // 단정문이 실행됨
}

 


느낀 점

  • 어노테이션을 단순히 적용하는 것이 아닌 좀 더 깊게 파고 들어가 공부 할 수 있도록 진행
  • 이론만 공부하면 확실히 해당 내용을 익힐 수 없다는 느낌을 받았습니다.
    => 정리를 하고 다음에 JUnit5를 사용할 때 이 글을 참고하면서 공부
반응형

📚 참고자료

  • [10분 테코톡] 샐리의 트랜잭션 => 링크

0️⃣ 트랜잭션 개념 공부를 하게 된 계기

스프링을 사용하면서 @Transactional 이라는 어노테이션을 적용해본 적이 있습니다.

메서드 위에 해당 어노테이션을 적용하면 메서드 안에 있는 쿼리들이 하나의 단위로 묶인다는 대략적인 용도만 고 있습니다. 그래서 @Transactional 어노테이션의 정확한 개념을 모르고 사용했기 때문에 의문점이 많이 들었습니다.

  • 트랜잭션이란?
  • 트랜잭션을 사용해야 하는 상황은?
  • 스프링에서는 트랜잭션을 어떻게 지원하는지?

 

 

 

 

1️⃣ 트랜잭션이란?

  • 더이상 나눌 수 없는 가장 작은 하나의 단위를 의미
  • 데이터베이스에서는 트랜잭션을 조작함으로써 사용자가 데이터베이스에 대한 완전성을 신뢰할 수 있도록 함
  • 모든 데이터베이스는 자체적으로 트랜잭션을 지원
  • 하나의 명령을 실행했을 때 데이터베이스가 온전히 그 명령을 실행해주는 것
    => 성공하면 커밋(Commit)
    => 실패하면 롤백(Rollback)
  • 데이터베이스는 기본적으로 트랜잭션을 관리하기 위한 설정을 갖고 있습니다.
    • 명령을 끝마칠 때까지 수행 내역을 로그에 저장해둡니다.
      - 데이터베이스에 반영된 내용을 재반영하기 위한 redo log
      - 수행을 실패해 이전의 상태로 되돌리는 undo log
      * 두 개의 log를 이용해 트랜잭션을 지원합니다.

 

 

 

2️⃣ 트랜잭션을 사용하는 상황(예시)과 성질

트랜잭션에서 가장 흔히 볼 수 있는 입출금을 예시로 들어보겠습니다.

 

  1. A가 B에게 만원을 송금하려고 합니다.
  2. A의 계좌에 만원보다 많은 금액이 있는지 확인합니다.
  3. A의 계좌에 만원보다 많은 금액이 있다면 만원을 차감합니다.
  4. 차감한 만원의 금액을 B의 계좌에 더해줍니다.

 

위 업무는 순서를 나눠놨지만 절대로 분리되거나 일부만 실행되면 안 되는 하나의 작업입니다.

이렇게 절대로 깨져서는 안되는 하나의 작업을 트랜잭션이라고 합니다.

 

 

트랜잭션의 네가지 성질

  • 원자성(Atomicity)
    - A가 B에게 송금을 하는데 A의 계좌에서 만원이 차감만 되고 작업이 종료되면 문제가 발생합니다.
    - 이렇듯 일부만 실행되는 경우는 없다는 원자성을 지닙니다.
    - [롤백]1번부터 4번까지 연결된 하나의 작업에서 어느 하나의 명령이라도 실패하면 롤백을 하게 됩니다.
    - [트랜잭션 커밋]반대로 1번부터 4번까지 작업이 성공적으로 수행하면 수정된 내용 데이터베이스에 반영
    - 롤백이나 커밋이 실행되어야 트랜잭션이 종료됩니다.

  • 일관성(Consistency)
    - 데이터베이스 내의 상태 혹은 계층 관계
    - 컬럼의 속성이 항상 일관되게 유지되어야 함
    - 컬럼의 속성이 수정되었다면 trigger를 통해 일괄적으로 모든 데이터베이스에 적용해야 합니다.
  • 지속성(Durability)
    - 트랜잭션이 성공적으로 수행되어 커밋되었다면 어떠한 문제가 발생하더라도 데이터베이스에 그 내용이
    영원히 지속되어야한다는 지속성이 있습니다.
    - 이를 위해 모든 트랜잭션은 로그로 남겨져 어떠한 장애에도 대비할 수 있도록 합니다.

  • 독립성(Isolation)
    - 트랜잭션 수행 시 다른 트랜잭션이 끼어들 수 없고 각각 독립적으로 실행된다는 성질
    DB 독립성의 문제점(더보기 클릭)
    더보기
    하지만 데이터베이스에 작업이 들어왔을 때 모든 작업의 독립성을 보장해 하나씩 순차적으로 진행하게 된다면, CPU는 DBMS보다 인풋, 아웃풋이 빈번히 수행되기 때문에 트랜잭션을 순차적으로 시행하면 CPU는 점점
    응답을 기다리는 시간이 길어지게 됩니다. 그 결과 프로그램이 비효율적으로 동작하는 문제가 발생합니다.

 

이처럼 데이터베이스에 저장된 데이터의 무결성과 동시성의 성능을 지키기 위해 트랜잭션의 설정이 중요한 것입니다.

여러 명령을 하나의 트랜잭션으로 묶고 싶은 경우 개발자가 직접 트랜잭션의 경계설정을 통해 트랜잭션 명시

 

 

 

 

3️⃣ 스프링에서 지원하는 트랜잭션

 

public interface PlatformTransactionManager extends TransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition);
    void commit(TransactionStatus status);
    void rollback(TransactionStatus status);
}

 

  • 트랜잭션 추상화 인터페이스인 PlatformTransactionManager를 제공
    • getTransaction 메서드
      - 파라미터로 전달되는 TransactionDefinition에 따라 트랜잭션을 시작
      - 트랜잭션을 문제없이 마치면 commit을, 문제가 발생하면 Rollback을 호출
    • getTransaction부터 commit이나 rollback을 하는 부분까지가 트랜잭션의 경계설정입니다.
  • 다양한 DataSource에 맞게 트랜잭션을 관리

 

 

스프링이 제공하는 다양한 트랜잭션 매니저 구현체

 

  1. DataSourceTransactionManager
    - JDBC에 사용되는 매니저
    - 하나의 데이터베이스를 사용하거나 각각의 데이터를 독립적으로 사용하는 로컬 트랜잭션에 사용

  2. JpaTransactionManager
    - JPA에 사용되는 매니저
    - 하나의 데이터베이스를 사용하거나 각각의 데이터를 독립적으로 사용하는 로컬 트랜잭션에 사용

  3. JtaTransactionManager
    - 하나 이상의 데이터베이스가 참여하는 경우 글로벌 트랜잭션에 사용되는 JtaTransactionManager 사용
    - 여러 개의 데이터베이스에 대한 작업을 하나의 트랜잭션에 묶을 수 있고, 다른 서버에 분산된 것도 묶을 수 있음

 

 

🍃 어노테이션을 기반으로 트랜잭션을 설정하는 방법

 

  @Transactional
    public void addRestaurantFoods(
            Long restaurantId,
            List<FoodRequestDto> requestDtoList
    ) {
        Optional<Restaurant> foundRestaurant = restaurantRepository.findById(restaurantId);

        checkRestaurant(foundRestaurant);
        Restaurant restaurant = foundRestaurant.get();

        for (FoodRequestDto requestDto : requestDtoList) {
            String foodName = requestDto.getName();
            int foodPrice = requestDto.getPrice();

            checkDuplicateRestaurantFood(restaurant, foodName);

            checkFoodPrice(foodPrice);

            Food food = Food.builder()
                    .name(foodName)
                    .price(foodPrice)
                    .restaurant(restaurant)
                    .build();

            foodRepository.save(food);
        }
    }

 

  • 어노테이션이 적용된 메서드는 메서드 시작부터 트랜잭션이 시작
    => 메서드를 성공적으로 끝마치면 트랜잭션 커밋
    => 도중에 문제가 발생하면 롤백
  • 어노테이션은 데이터베이스에 여러번 접근하면서 하나의 작업을 수행하는 서비스 계층 메서드에 붙인다.

 

 

 

반응형

 

 

회사에 입사하고 야근에 대해 많은 생각을 하게 되었습니다.

아무래도 야근을 좋아하는 분은 거의 없을 것이라고 생각합니다.

 

주변에서도 야근을 자주 하는 회사는 최대한 피하라는 얘기를 많이 들었을 것입니다.

 

그 근본적인 이유가 무엇일까 신입 개발자가 보고 느끼면서 생각해봤습니다.

 

* 이 글은 SI업체에 다니는 신입 개발자의 관점으로 작성한 것입니다.

 

 

🤔 근본적인 문제가 무엇일까?

 

위의 문제에 대해 생각하기 전에  우선 '야근을왜 할까?' 라는 의문을 먼저 가졌습니다.

 

그 결과 나온 것은

 

  1. 해당 개발자의 역량을 넘어서는 업무 할당
    ex) 신입 개발자에게 자바로 배치 프로그램을 만들라고 시킴

  2. 회사가 소화할 수 없는 수준의 일을 받은 경우
    ex) 회사에 개발팀이 제대로 꾸려져 있지 않은데 무리하게 금융권 대규모 프로젝트를 받음

  3. 개발 외적인 업무를 개발자에게 할당
    ex) 개발보다 문서화가 너무 많아서 시간을 소비

 

위 세 가지는 제가 직접 경험한 것들도 포함되어 있습니다.

 

저는 위 세 가지를 하나하나 좀 더 깊게 생각해봤습니다.

어떻게 하면 극복 혹은 개선해 나갈지 말입니다.

 

 

 

 

1️⃣ 해당 개발자의 역량을 넘어서는 업무 할당

  • 무능한 사수가 자신이 할 일을 부사수에게 넘기는 경우
  • 개발자의 경력을 뻥튀기해서 파견을 보내는 경우
    • 클라이언트는 해당 개발자가 n년차이기 때문에 충분히 가능할 것이라 생각하고 업무 부여
    • 대부분 이 경우에는 사수라고 할 만한 사람이 제대로 없고 팀도 잘 안 굴러가는 상황인 것 같습니다.
      (팀이 있다고 해도 서로 소통을 잘 안 하는 경우가 많음)
  • 회사에 개발팀이 제대로 안 꾸려진 경우
    • 이런 경우에는 사수도 없다는 걸 입사 후 알게 되었습니다.
    • 만약에 사수가 있다고 해도 무늬만 사수인 경우

 

  • 군대식 마인드로 어떻게든 하면 가능하다고 생각하는 경우
    • 이 경우는 데드라인을 정해주고 PM이 계속 개발자를 닦달하는 경우를 봤습니다.
      * PM이 계속 개발자를 쪼는 업무가 주 업무인지 고민

 

 

 

2️⃣ 회사가 소화할 수 없는 수준의 일을 받은 경우

  • 1번과 동일하게 회사에 개발팀이 제대로 안 꾸려진 경우
  • PM 혹은 기획자가 해당 업무를 소화할 만한 개발자와 기간을 제대로 정하지 못한 경우
    • 회사에 개발자가 없더라도 외주 개발자로 채워서 진행할 수 있지만 못한 경우
    • 해당 프로젝트를 맡게 될 개발자가 너무 자만해서 역량 이상의 일 혹은 기간을 선정한 경우

 

 

 

3️⃣ 개발 외적인 업무를 개발자에게 할당

  • 개발을 진행해야 하는데 계속 문서화 업무를 시켜 주객전도가 된 경우
  • PM 혹은 기획자가 개발자의 업무의 경계에 대해 아예 모르는 경우
    • 이 경우는 개발자에 대해 대우가 상당히 안 좋은 회사 일 것이라고 생각합니다.
  • PM 혹은 기획자조차 없고 있다고 해도 분업화가 제대로 이뤄지지 않은 경우
  • 개발자가 자만하고 모든 걸 다 할 수 있다고 얘기하고 업무를 받은 경우

 

 

 

 

 

 

 

🤔 극복할 방법 혹은 해야 할 것

  • 금전적, 시간적으로 여유가 있다면 바로 퇴사를 하는 것도 좋다고 생각했습니다.
    • 퇴사 후에 교육기관에 들어가서 다시 포트폴리오를 만들면서 공부
    • 교육기관을 들어간다면 시험을 보고 들어가는 곳으로 지원
  • 금전적, 시간적 여유가 안된다면 배민 출신 개발자 이동욱님처럼 1년 정도 다니면서 이직 준비
    • 이동욱님의 이직 준비 방법에 대해 정리한 글 => 링크
    • 회사를 다니면서 생기는 돈으로 현업 개발자를 대상으로 진행하는 교육과정 듣기
      => 고스펙의 개발자에게 코드 리뷰를 받아볼 수 있음
      => 대부분 가격대가 비싸기 때문에 잘 찾아서 진행
      => 찾아본 교육과정 들
      1. 코드숨 => 우아한 형제들, 마켓 컬리 출신의 개발자에게 배울 수 있음
      2. NEXTSTEP => 우아한 테크코스(우테코)라는 유명한 교육기관의 커리큘럼을 배울 수 있음
      3. POCU  => 개발의 기초적인 지식을 유튜브 채널 포프TV를 운영하는 개발자에게 배울 수 있음
    • 만약에 회사에서 교육에 대한 지원을 한다면 놓치지 않고 진행

 

 

😀 느낀 점

  • 이런 회사는 개발자의 성장을 통해 이득을 얻으려고 하는 게 아니고, 당장 써먹기 바쁘다는 느낌을 받았습니다.
  • 야근을 하는 경우는 대부분 안 좋은 상황일 때 많이 한다는 것을 느꼈습니다.
  • 개발자에게 야근은 당연하다고 생각하는 회사는 정말 위험하다고 느꼈습니다.
    • 이런 경우 회사에서 개발자에 대한 대우도 안 좋은 다는 것을 느꼈습니다.
  • 야근을 한다고 하면 어떻게 시간을 관리해야 할까 고민하게 되었습니다.
    • 지금 당장 답은 안 나오지만 회사를 다니면서 계속 고민해야 할 것
  • 개발자 이동욱님의 영상을 보고 우선 회사를 다니면서 이직을 준비해야겠다고 생각했습니다.
    • 근본적인 문제는 돈이 없으면 내가 원하는 좋은 교육을 들을 수 없음
    • 대우가 안좋은 회사라도 배울점은 당연히 있다고 생각
  • 성공적인 이직 화이팅!!

 

 

 

반응형

 

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

  • 알고리즘을 이해하라(383p)
    • 알고리즘을 안다고 생각하지만 실제는 코드가 '돌아갈' 때까지 이리저리 찔러보고 굴려본다.
    • '돌아간다'는 사실은 어떻게 아느냐고? 생각할 수 있는 테스트 케이스를 모두 통과하니까.
      * 이 방식이 틀렸다는 말이 아니다.
    • 구현이 끝났다고 선언하기 전에 함수가 돌아가는 방식을 확실히 이해하는지 확인하라.
      =>  테스트 케이스를 모두 통과한다는 사실만으로 부족하다.
    • 알고리즘이 올바르다는 사실을 확인하고 이해하려면 기능이 뻔히 보일 정도로 함수를
      깔끔하고 명확하게 재구성하는 방법이 최고다.

  • if/Else 혹은 Switch/Case 문보다 다형성을 사용하라(385p)
    1. 대다수 개발자가 switch 문을 사용하는 이유는 그 상황에서 가장 올바른 선택이기보다는
      당장 손쉬운 선택이기 때문이다.
      => switch를 선택하기 전에 다형성을 먼저 고려하라는 의미다.
    2. 유형보다 함수가 더 쉽게 변하는 경우는 극히 드물다. 그러므로 모든 swtich 문을 의심해야 한다.

// 변경 전
if (shouldBeDeleted(timer))

// 변경 후
if (timer.hasExpired() && !timer.isRecurrent())
  • 조건을 캡슐화하라(388p)
    • 부울 논리는 이해하기 어렵다.
    • 조건의 의도를 분명히 밝히는 함수로 표현하라.
  • 부정 조건은 피하라(389p)
    • 부정 조건은 긍정 조건보다 이해하기 어렵다.
    • 가능하면 긍정 조건으로 표현한다.

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. Switch/Case 문은 잘 사용하지 않았지만 if/else로 도배된 코드는 많이 봤습니다.
    • 우선적으로 가독성이 상당히 안 좋았습니다.
    • if에 해당하는 조건을 전부 거치기 때문에 상당히 비효율적이라고 느껴졌습니다.
  2. 제가 추상화에 대한 개념이 아직 덜 정립되어 있는 것 같습니다.
    • 우선 책을 읽어야겠다는 생각 때문에 '대략적인 이런 거구나?'라는 생각으로 넘어가고 있습니다.
      추상화의 개념과 예시를 좀 더 찾아보고 고민해봐야 할 것 같습니다.

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 추상화란?
    • 컴퓨터 과학에서 추상화는 복잡한 자료, 모듈, 시스템 등으로부터
      핵심적인 개념 또는 기능을 간추려 내는 것을 말한다.
    • 결국 핵심은 불필요한 코드를 제거하고 중요한 부분을 살리는 것입니다.
  • 다형성이란?
    • 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미합니다.
    • 자바에서는 이러한 다형성을 부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를
      참조할 수 있도록 하여 구현하고 있습니다.

 

 

 

👀 소감 3줄 요약

  • 알고리즘을 이해하지 않고 우선 코드부터 했던 적이 많은데, 책을 읽고  반성하게 되었습니다.
  • 객체지향의 개념이 중요하다는 걸 이번 챕터를 읽고 더욱 강하게 느꼈습니다.
  • 클린코드를 읽었나 보다 그걸 바탕으로 코드에 적용해 봤나 가 중요하다고 생각했습니다.

 

 

 

 

 
반응형

 

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

  • 주석(368p)
    • 부적절한 정보
      => 일반적으로 작성자, 최종 수정일, SPR(Software Problem Report)번호 등과 같은 메타 정보만 주석 사용
      => 주석은 코드와 설계에 기술적인 설명을 부연하는 수단이다.
    • 주석 처리된 코드
      => 누군가에게 필요하거나 다른 사람이 사용할 코드라 생각해 아무도 삭제하지 않는다.
      => 주석으로 남겨진 코드는 그 자리에 남아 매일매일 낡아간다.
      => 주석으로 처리된 코드를 발견하면 즉각 지워버려라!

  • 일반(371p)
    • 한 소스 파일에 여러 언어를 사용한다.
      => 이상적으로는 소스 파일 하나에 언어 하나만 사용하는 방식이 가장 좋다.
      * 혼란스럽고 조잡하다.

    • 경계를 올바로 처리하지 않는다.
      => 스스로의 직관에 의존하지 마라.
      => 모든 경계 조건을 찾아내고, 모든 경계 조건을 테스트하는 테스트 케이스를 작성하라.

    • 중복
      => 코드에서 중복을 발견할 때마다 추상화할 기회로 간주하라.
      => 중복된 코드를 하위 루틴이나 다른 클래스로 분리하라.
      => 이렇듯 추상화로 중복을 정리하면 설계 언어의 어휘가 늘어난다.
      => 추상화 수준을 높였으므로 구현이 빨라지고 오류가 적어진다.

    • 과도한 정보
      => 잘 정의된 모듈은 인테페이스가 아주 작다.
      => 하지만 작은 인터페이스로도 많은 동작이 가능하다.
      => 우수한 소프트웨어 개발자는 클래스나 모듈 인터페이스에 노출할 함수를 제한할 줄 알아야 한다.
      => 클래스가 제공하는 메서드 수는 적을수록 좋다.
      => 정보를 제한해 결합도를 낮춰라.

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 지금까지 읽은 내용이 정말 많은 내용이 담겨 있다는 걸 느꼈습니다.
    => 단순히 읽고 끝내는 것이 아닌 그 이론에 해당하는 코드를 보고 직접 타이핑

  2. 클린 코드를 하나의 방향성 같다는 느낌을 받았습니다.
    => 클린코드의 내용과 내가 작성한 코드를 보면서 한번 더 생각하게 만들어 줬습니다.
    => 하나의 방향성을 보여주는 것이지 꼭 지켜야 하는 룰은 아닌 것 같다고 생각했습니다.
    => 우선 클린코드 저자가 절대로 하지 말아야 한다는 규칙은 지키도록 노력해야겠습니다.

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 디자인 패턴은 어떻게 공부 할지?
    • 클린코드를 읽으면서, 해당 디자인 패턴을 사용해야 하는 상황을 직접 보고 공부해야 한다는걸 알게되었습니다.
    • 당연하겠지만 단순히 암기를 하는 식의 공부는 휘발성이 심하다는걸 다른 책을 읽고 느꼈습니다.
      => 다른 책은 개념을 알려주고 코드를 보여주고 요약본을 보여주는 형태였습니다.

 

 

 

👀 소감 3줄 요약

  • 친절한 저자의 책에 대한 복습 챕터를 만들어 놔서 복습을 편하게 할 수 있었습니다.
  • 요약본을 통한 읽은 부분을 정확히 이해했는지 확인 할 수 있어서 좋았습니다.
  • 클린코드는 두고두고 읽을 명저라고 느꼈습니다.

 

 

 

 

 
반응형

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

  • 불필요한 주석은 거짓말과 잘못된 정보가 쌓이기 좋은 곳이다.
  • 일반적으로 기반 클래스(base class, 부모 클래스)는 파생 클래스(derivative, 자식 클래스)를 몰라야 바람직하다.
    • ABSTRACT FACTORY 패턴을 적용
    • 추상 메서드로 위임하는 정적 메서드는 SINGLETON, DECORATOR, ABSTRACT FACTORY 패턴 조합을 사용한다.
  • 보이스카우트 규칙
  • 다음 사람은 우리보다 코드를 좀 더 쉽게 이해하리라.
    그래서 보다 코드를  좀 더 쉽게 개선하리라.

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 너무 사소한 코드는 테스트할 필요가 없다.
    • 이전 프로젝트에서 코드 커버리지를 채우는 데에만 급급했었던 경험이 있습니다.
      => 중요한 메서드에 테스트를 집중 하고 사소한 건 테스트할 필요 없다는 걸 알게 되었습니다.

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 싱글톤이란?
    • 소프트웨어 디자인 패턴에서 싱글턴 패턴을 따르는 클래스는,
      생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에
      호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.

 

 

 

👀 소감 3줄 요약

  • 예전에도 나왔지만 불필요한 주석을 다는 위험을 강조하고 있습니다.
  • 테스트 커버리지 도구를 통해 지표를 확인하면서 테스트 코드를 작성해야 한다는 걸 알게 되었습니다.
  • 리팩터링을 통해 나중에 해당 코드를 개선할 사람까지 생각하는 것이 인상 깊었습니다.

 

 

 

 

반응형

노마드코더

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

  • 코드를 리팩터링 하다 보면 원래 했던 변경을 되돌리는 경우가 흔하다.
    => 리팩터링은 코드가 어느 수준에 이를 때까지 수많은 시행착오를 반복하는 작업이기 때문이다.

  • 세상에 개선이 불필요한 모듈은 없다.

  • 코드를 처음보다 조금 더 깨끗하게 만드는 책임은 우리 모두에게 있다.

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 처음 장에서 저자가 얘기했던 지켜야 할 규칙들을 바탕으로 리팩터링 하는 파트였습니다.
    => 이미 깨끗한 코드도 리팩터링할 것이 있다는 것을 알게 되었습니다.
    => 코드를 더욱 깨끗하게 만들어가는 과정은 진짜 장인들의 모습과도 같다고 느꼈습니다.

  2. 클린코드를 읽으면서 매번 느끼지만 내가 작성한 코드를 꼭 둘러보면서 리팩터링 해야겠다고 느꼈습니다.
    => 기능을 만들고 그냥 놔버리는 경우가 많았었습니다.
    => 리팩터링을 아주 조금하면서 많은 성장을 이뤄냈습니다.
    => 테스트코드가 없는 코드는 리팩터링 하는게 힘들다는 것을 느꼈습니다.

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 테스트코드 리팩터링은 어떻게 할까?
    • 중복되는 코드는 @Before 어노테이션으로 옮긴다.
    • 하나의 assert 문으로도 충분히 테스트할 수있는 케이스로 리팩터링
      => 너무 많은 assert(단언문)을 가진다면 테스트 케이스가 두 개 이상 포함되어 있는지 의심해본다.
    • 참고한 블로그 -> 링크

 

 

 

👀 소감 3줄 요약

  • 코드를 리팩터링 하다가 예전 코드로 돌리는 경우는 흔한 일이다.
  • 세상에 개선이 불필요한 모듈은 없다.
  • 코드를 처음보다 조금 더 깨끗하게 만드는 장인정신

 

 

 

 

반응형

노마드코더

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

 

public String compact(String message) {
	if (shouldNotCompact())
    	return Assert.format(message, expected, actual);
        
    findCommonPrefix();
    ...
}

private boolean shouldNotCompact() {
	return expected == null || actual == null || areStringsEqual();
}
  • 의도를 명확히 표현하려면 조건문을 캡슐화해야 한다.
    • 조건문을 메서드로 뽑아내 적잘한 이름을 붙인다.

 

public String compact(String message) {
	if (canBeCompacted()) {
    	findCommonPrefix();
        ...
    } else {
    	return Assert.format(message, expected, actual);
    }
}

private boolean canBeCompacted() {
	return expected != null &&  actual != null && !areStringsEqual();
}
  • 부정문은 긍정문보다 이해하기 약간 더 어렵다.
    그러므로 첫 문장 if를 긍정으로 만들어 조건문을 반전한다.

 

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 책을 통해 캡슐화를 하는 과정을 직접적으로 보게 되면서 이해를 할 수 있었습니다.
    => 하나의 과정을 보여주면서 더 클린한 코드가 되가는 모습
    => 클린한 코드와 객체지향적 설계 코드가 비슷하다는 것을 느꼈습니다.

 

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 보이스카우트 규칙이란?
    • 클린코드 18쪽에 나오는 내용이다. 
    • 잘 짠 코드가 전부는 아니다.
      시간이 지나도 언제나 깨끗하게 유지해야 한다.
    • 지속적인 개선이야말로 전문가 정신의 본질
  • 캡슐화란?
    • 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고,
      실제 구현 내용 일부를 외부에 감추어 은닉한다.
    • 캡슐화를 private이라고 단순하게 이야기하면 안된다는 이유를 알게 되었습니다.

 

 

 

👀 소감 3줄 요약

  • 객체지향 설계의 캡슐화가 클린한 코드를 만드는 과정
  • 부정문은 긍정문보다 이해하기 약간 더 어렵다
  • 코드를 직접 보면서 이론을 설명해줘서 이해하기 수월했습니다.

 

 

 

 

반응형

 

노마드코더

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

  • 소프트웨어 설계는 분할만 잘해도 품질이 크게 높아진다.
    • 적절한 장소를 만들어 코드만 분리해도 설계가 좋아진다.
    • 관심사를 분리하면 코드를 이해하고 보수하기 훨씬 더 쉬워진다.
  • 그저 돌아가는 코드만으로는 부족하다.
    • 돌아가는 코드가 심하게 망가지는 사례는 흔하다.
    • 단순히 돌아가는 코드에 만족하는 프로그래머는 전문가 정신이 부족하다.
    • 나쁜 코드는 썩어 문드러진다.
  • 나쁜 코드도 깨끗한 코드로 개선할 수 있지만 비용이 엄청나게 많이 든다.
    • 모듈은 서로서로 얽히고설켜 뒤엉키고 숨겨진 의존성이 수도 없이 생긴다.

 

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 프로젝트를 하면서 분할에 대한 것을 팀원분에게 배웠습니다.
    => 작동하는데 문제가 없었던 코드였지만 분할을 하면서 중복되는 코드가 확연하게 줄어들었습니다.
    => 다른 사람의 습관과 코드를 통해 배울게 많다는 것을 느꼈습니다.

 

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 관심사란?
    • 컴퓨터 프로그램의 코드에 영향을 미치는 특정한 정보 집합이다.
    • 프로그래밍 관점에서 보면 하나의 기능이나 모듈이라고 이해하면 쉽다.
  • 의존성이란?
    • 코드에서 두 모듈간의 연결.
    • 객체지향언어에서는 두 클래스 간의 관계라고도 말함.
    • 일반적으로 둘 중 하나가 다른 하나를 어떤 용도를 위해 사용함.

 

 

 

👀 소감 3줄 요약

  • 소프트웨어 설계는 분할만 잘해도 품질이 크게 높아진다.
  • 나쁜 코드는 썩어 문드러진다.
  • 코드는 언제나 최대한 깔끔하고 단순하게 정리하자.

 

 

 

 

반응형

 

 

😀 책에서 기억하고 싶은 내용을 써보세요.

private void setBooleanArg(ArgumentMarshaler m) {
	try {
    	m.set("true"); // 이전 코드: booleanArgs.get(argChar).set("true");
    } catch (ArgsException e) {
    }
}
  • 변경 전 booleanArgs.get(argChar).set("true");  코드
    • 위 코드는 클린코드 6장에 나왔던 기차 충돌 코드 사례와 비슷하게 생겼습니다.
    • 변경 후 코드가 훨씬 간결해졌습니다.

  • 리팩터링을 하다보면 코드를 넣었다 뺐다 하는 사례가 아주 흔하다.
    • 단계적으로 조금씩 변경하며 매번 테스트를 돌려야 하므로 코드를 여기저기 옮길 일이 많아진다.
      => 리팩터링은 루빅 큐브 맞추기와 비슷하다.
      => 큰 목표 하나를 이루기 위해 자잘한 단계를 수없이 거친다.
      => 각 단계를 거쳐야 다음 단계가 가능하다.

 

 

 

 

🤔 오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

  1. 이 챕터를 읽고 저자는 한번에 완벽한 코드를 작성할 수 없다는 것을 보여주는 것 같았습니다.
    => 챕터 제목 그대로 점진적인 개선을 보여주고 있습니다.

  2. 모든 코드를 다 리팩터링 하고 테스트를 돌려보는 방식이 아녔습니다.
    => 한 부분을 리팩터링 하고 테스트를 돌리는 과정이 많았습니다.

  3. 이전 장에서 배웠던 내용을 코드에 적용해 하나씩 리팩터링 하는 게 인상 깊었습니다.

 

 

 

 

🔎 궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요. 

  • 코드가 엄청 방대해서 전체를 다 이해하기는 힘들다고 느꼈습니다.
    => 눈으로만 읽고 생각해서 그런지 가독성이 안 좋았습니다.

 

 

 

👀 소감 3줄 요약

  • 큰 목표 하나를 이루기 위해 자잘한 단계를 수없이 거친다.
  • 점진적인 개선과 리팩터링
  • 저자도 계속해서 리팩터링 과정을 거치면서 깨끗한 코드를 만들어가는 과정이 인상 깊었습니다.

 

 

 

반응형

+ Recent posts