2023.08.29.TUE

ronglong·2023년 8월 29일

[ 프로그래머스 ]

[ 덧칠하기 ]

class Solution {
    public int solution(int n, int m, int[] section) {
        int answer = 1;
        
        int temp = section[0] + m;
        //작은 번호부터 m까지 1번으로 해결 가능. 
        for(int i=1; i<section.length; i++){
            if(section[i] >= temp){
                answer++;
                temp = section[i] + m;
            }
        }
        
        return answer;
    }
}

[ [1차] 다트 게임 ]

: 어우 핵구림... 내 코드 냄새남.
갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었지만, 나는 입사 못할 듯ㅋㅋㅋ큐ㅠㅠ
처음 짤 때, 10점인 경우를 생각을 못했다.
10점인 경우 고려했더니 코드가 너무 지저분해짐.

import java.util.*;

class Solution {
    public int solution(String dartResult) {
        int answer = 0;
        
        //숫자가 나올때마다 끊어서 리스트에 담기 
        List<String> list = new ArrayList<>();
        
        while(dartResult.length()>0){
            int len = dartResult.length();
            for(int i=2; i<len; i++){
                if(Character.isDigit(dartResult.charAt(i))){
                    list.add(dartResult.substring(0, i));
                    dartResult = dartResult.substring(i);
                    break;
                }
            }
            if(dartResult.length()==2 || dartResult.length()==3 || (dartResult.startsWith("10") && dartResult.length()==4)){
                list.add(dartResult);
                break;
            }
        }
        
        //각 회차의 계산된 점수를 담을 배열
        int[] points = new int[3];
        
        //점수 계산하기 
        for(int i=0; i<3; i++){
            String str = list.get(i);
            
            String[] arr;
            if(str.startsWith("10") && str.length()==3){
                arr = new String[2];
                arr[0] = "10";
                arr[1] = str.substring(2);
            } else if(str.startsWith("10") && str.length()==4){
                arr = new String[2];
                arr[0] = "10";
                arr[1] = str.substring(2,3);
                arr[2] = str.substring(3);
            } else {
                arr = str.split("");
            }
            int temp = Integer.parseInt(arr[0]);
            
            if(arr[1].equals("D")){
                temp *= temp;
            } else if(arr[1].equals("T")){
                temp = temp * temp * temp;
            }
            
            if(arr.length==3){
                if(arr[2].equals("*")){
                    if(i!=0){
                        points[i-1] *= 2;
                    } 
                    temp *= 2;
                } else if(arr[2].equals("#")){
                    temp *= -1;
                }
            }
            points[i] = temp;
        }
        
        return points[0]+points[1]+points[2];
    }
}

[ 주식가격 ]

: 스택/큐 문제라고 써있었지만, 그냥 이중 for문으로 해결 가능.

class Solution {
    public int[] solution(int[] prices) {
        int[] answer = new int[prices.length];
        
        for(int i=0; i<prices.length; i++){
            int temp = 0;
            for(int j=i+1; j<prices.length; j++){
                if(prices[i]<=prices[j]){
                    temp++;
                } else {
                    temp++;
                    break;
                }
            }
            answer[i] = temp;
        }
        
        return answer;
    }
}

[ 클린 코드 ]

[ 15장 JUnit 들여다보기 ]

[ 16장 SerialDate 리팩터링 ]

  • 보이스카우트 규칙 : 머문 자리는 이전보다 더 깨끗하게.
    체크아웃한 코드보다 더 깨끗한 코드를 체크인하기
  • 1) 프로그램 (소스 코드 및 테스트) 돌려보기
    • 클로버 : 코드 커버리지 분석 도구
  • 2) 고쳐보기
    • 고칠 때마다 단위 테스트 실행하기
    • enum 활용
    • 일관성 있는 패턴으로 수정하기
    • 너무 사소한 코드는 테스트하지 않음

[ 17장 냄새와 휴리스틱 ]

  • 주석

    • 부적절한 정보
    • 쓸모 없는 주석
    • 중복된 주석 (코드만으로 충분한 경우)
    • 성의 없는 주석 (주석은 간단명료하게)
    • 주석처리된 코드 (안 쓰면 지워라)
  • 환경

    • 하나의 명령어로 한 번에 빌드될 수 있게 만들기 (한 번에 빌드)
    • IDE에서 버튼 하나로 모든 테스트를 돌릴 수 있게 만들기 (한 번에 테스트)
  • 함수

    • 너무 많은 인수
    • 출력 인수 피하기
    • 플래그 인수 (boolean 인수. 함수가 여러 기능을 수행한다는 증거)
    • 죽은 함수 (미사용 함수 제거하기)
  • 일반

    • 한 소스 파일에 가능한 적은 수의 언어 사용하기
    • 당연한 동작도 구현할 것 (가독성 높이기. 최소 놀람의 원칙)
    • 테스트 케이스 작성을 통한 올바른 경계 조건 처리
    • 손쉬운 빌드를 위해 컴파일러 경고 무시하지 말기
    • 중복 제거! (using 추상화, 다형성, 클래스 분리, 메서드 추출 등)
    • 올바른 추상화 수준 (고차원 기초 클래스, 저차원 파생 클래스)
    • 기초 클래스가 파생 클래스에 의존하지 않도록 하기
      • 일반적으로 기초 클래스와 파생 클래스는 다른 JAR 파일로 배포
        -> 독립적인 개별 컴포넌트 단위로 시스템 배치 가능
    • 변수, 함수, 클래스 최소화. 캡슐화. 낮은 결합도.
    • 실행되지 않는 코드 제거
    • 정의와 사용 위치를 가깝게. 수직 위치.
    • 일관성. 유사 개념 같은 방식으로 구현. (최소 놀람의 원칙)
    • 일반적으로 static 함수보다 인스턴스 함수가 더 낫다.
    • 서술적인 변수명
    • 테스트 케이스를 통과할 뿐만 아니라, 개발자가 알고리즘을 정확히 이해하고 있어야 함.
    • 논리적 의존성이 있다면 물리적 의존성으로도 드러낼 것
    • 매직 숫자, 문자열 대신 상수 이용
    • (부울 논리) 조건을 캡슐화하기
    • 부정 조건보다는 긍정 조건 사용
    • 함수는 추상화 수준을 한 단계만 내려가야한다.
    • 설정 관련 상수는 위에 두기
    • 디미터의 법칙, Writing Shy Code : A가 B를, B가 C를 사용할 때, A가 C를 모르게.
  • 자바

    • 긴 import 목록을 피하고 와일드 카드 사용하기 (결합성 낮아짐)
    • 상수는 상속하지 않기
    • 상수보다 enum 활용
  • 이름

    • 서술적인 이름
    • 명확한 이름
    • 범위 길이와 비례하는 이름 길이 (for문 같은 것에서는 반복자로 i 쓰는 등)
    • 이름으로 부수 효과까지 모두 정확하게 설명하기
  • 테스트

    • 잠재적으로 깨질만한 부분들을 모두 테스트하기(불충분한 테스트 피하기)
    • 커버리지 도구 활용
    • 사소한 테스트 건너뛰지 말기
    • 경계 조건은 신경 써서 테스트하기
    • 버그 주변은 철저히 테스트하기 (버그는 모이는 경향이 있다.)
    • 테스트 케이스 실패 패턴을 확인
    • 테스트 커버리지 패턴 확인
    • 테스트는 빨라야한다.

[ 느낀 점 ]

프로그래머스 코테 문제는 특수 자료구조/알고리즘(DP, DFS, BFS, 그래프 등) 공부하기 싫어서 일반 구현 문제만 푸는 중,,,ㅎ
내일부터는 도전해봐야겠다. 성장해야지~!

책 <클린 코드> 15,16장은 리팩토링하는 과정을 보여주는 것이 대부분이었다.
17장은 어떤 코드가 냄새가 나는지 정리해서 보여줌.
이제 부록에 나온 코드를 보면 책이 끝난다.
처음부터 끝까지 일관된 주장을 해서 생각보다 어렵지는 않았다.
물론 직접 구현하려고 하면 어렵겠지만.

테스트가 너무 중요해서 개인 프로젝트에서는 이 부분을 꼭 신경써야겠다고 생각하고 있다.

0개의 댓글