JUnit 들여다보기(1)

책너두 5기 35일차 로버트 C. 마틴의 클린코드 p. 324~ p.332 34일차는 없습니다. 내용정리 15. JUnit 들여다보기 JUnit : 가장 유명한 자바 프레임워크 JUnit 프레임워크 과거의 모듈을 리팩토링해보자. ComparisonCompactor 모듈은 문자열 비교 오류를 파악할 때 쓴다. 원본은 다음과 같다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package junit.framework; public class ComparisonCompactor { private static final String ELLIPSIS = "..."; private static final String DELTA_END = "]"; private static final String DELTA_START = "["; private int fContextLength; private String fExpected; private String fActual; private int fPrefix; private int fSuffix; public ComparisonCompactor(int contextLength, String expected, String actual) { fContextLength = contextLength; fExpected = expected; fActual = actual; } public String compact(String message) { if (fExpected == null || fActual == null || areStringsEqual()) { return Assert.format(message, fExpected, fActual); } findCommonPrefix(); findCommonSuffix(); String expected = compactString(fExpected); String actual = compactString(fActual); return Assert.format(message, expected, actual); } private String compactString(String source) { String result = DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END; if (fPrefix > 0) { result = computeCommonPrefix() + result; } if (fSuffix > 0) { result = result + computeCommonSuffix(); } return result; } private void findCommonPrefix() { fPrefix = 0; int end = Math.min(fExpected.length(), fActual.length()); for (; fPrefix < end; fPrefix++) { if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) { break; } } } private void findCommonSuffix() { int expectedSuffix = fExpected.length() - 1; int actualSuffix = fActual.length() - 1; for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) { if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) { break; } } fSuffix = fExpected.length() - expectedSuffix; } private String computeCommonPrefix() { return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix); } private String computeCommonSuffix() { int end = Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length()); return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : ""); } private boolean areStringsEqual() { return fExpected.equals(fActual); } } 가장 먼저 멤버 변수 앞에 붙인 접두어 f를 삭제하자. 과거의 습관이다. 이후 compact 함수 시작부에 캡슐화되지 않은 조건문을 메서드로 뽑아내 적절한 이름을 붙인다. f를 빼면서 생긴 비슷한 이름들을 다시 명명한다. if 부정문을 긍정문으로 바꾸어 가독성을 높인다. ...

2023년 9월 15일 · 3 분 · 배준수

언두로그

책너두 6기 11일차 백은빈, 이성욱의 Real MySQL8.0 1권 p.120 ~ p.129 내용정리 04 아키텍처 4.2.8 Double Write Buffer InnoDB 스토리지 엔진의 리두 로그는 리두 로그 공간의 낭비를 막기 위해 페이지의 변경된 내용만 기록한다. 이로 인해 스토리지 엔진에서 더티 페이지를 디스크 파일로 플러시할 때 일부만 기록되는 문제가 발생하면 그 페이지의 내용은 복구할 수 없을 수도 있다. 이렇게 페이지가 일부만 기록되는 현상을 파셜 페이지(Partial-page) 또는 톤 페이지(Torn-page)라고 한다. 데이터의 무결성이 매우 중요한 서비스에서는 고려할만하다. ...

2023년 9월 15일 · 2 분 · 배준수

자료구조(5) 연결리스트

11일차 게일 라크만 맥도웰의 코딩 인터뷰 완전 분석 2.3~ 2.8 내용 정리 9 면접 문제 2.3 중간 노드 삭제 단방향 연결리스트가 주어졌을 때 중간(정확히 가운데 노드일 필요는 없고 처음과 끝 노드만 아니면 된다)에 있는 노드 하나를 삭제하는 알고리즘을 구현하라. 단, 삭제할 노드에만 접근할 수 있다. 예제 입력 : 연결리스트 a->b->c->d->e 에서 노드 c 결과 : 아무것도 반환할 필요는 없지만, 결과로 연결리스트 a->b->d->e가 되어 있어야 한다. 답 : 예제에서 삭제할 노드인 c의 다음 노드 d를 복사해서 c에 붙여 넣는다. d(c였으나 복사하여서 d가 된)를 d(원래 d)의 다음 노드인 e에 연결한 후 d를 삭제한다. ...

2023년 9월 15일 · 4 분 · 배준수

파이썬 알고리즘 : 동전 0, 잃어버린 괄호, 외판원 순회

2023년 9월 15일 알고리즘 문제풀이 문제 1 백준 11047 문제 링크 1차 시도 나의 생각 최소한의 동전을 사용하기 위해선 최대한 가치가 큰 동전을 많이 사용해야 한다. 이를 위해 입력받은 동전을 큐에 저장해 최대 힙을 사용하였다. 가장 큰 동전부터 가능한 갯수만큼 사용했다. 기존에는 이중 반복문을 사용해서 가장 큰 동전을 여러번 쓰도록 구현했지만 시간초과가 문제가 되었다. 따라서 몫과 나머지를 이용해서 한번만 실행되도록 바꾸었더니 통과되었다. 결과 정답 코드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import sys from heapq import heappush, heappop n, k = map(int, sys.stdin.readline().split()) coins = [] for _ in range(n): heappush(coins, -1*int(sys.stdin.readline())) cnt = 0 while k > 0 and coins: val = -1*coins[0] if k >= val: tmp = k//val cnt += tmp k %= val heappop(coins) print(cnt) 문제 2 백준 1541 문제 링크 ...

2023년 9월 15일 · 6 분 · 배준수

InnoDB 버퍼 풀

책너두 6기 10일차 백은빈, 이성욱의 Real MySQL8.0 1권 p.108 ~ p.119 내용정리 04 아키텍처 4.2.7 InnoDB 버퍼 풀 InnoDB 스토리지 엔진에서 가장 핵심적인 부분 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간 쓰기 작업을 지연시켜 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할 4.2.7.1 버퍼 풀의 크기 설정 운영체제와 각 클라이언트 스레드가 사용할 메모리도 충분히 고려해서 설정 시스템 변수 innodb_buffer_pool_size로 동적 설정 가능 운영체제의 전체 메모리 공간이 8GB 미만이라면 50% 정도만 InnoDB 버퍼 풀로 설정 나머지 메모리 공간은 MySQL 서버와 운영체제, 그리고 다른 프로그램을 위한 공간으로 설정 권장 전체 메모리가 그 이상이면 버퍼 풀의 크기를 점차 증가시키며 최적점을 찾을 것 4.2.7.2 버퍼 풀의 구조 버퍼 풀이라는 거대한 메모리 공간을 페이지 크기(innodb_page_size시스템 변수로 설정)의 조각으로 쪼갠다 InnoDB 스토리지 엔진이 데이터를 필요로 할 때 해당 페이지를 읽어 각 조각에 저장한다 페이지 크기 조각 관리를 위한 LRU 리스트, 플러시 리스트, 프리 리스트라는 3개 자료구조를 관리한다. LRU(Least Recently Used) : 디스크로부터 한 번 읽어온 페이지를 최대한 오랫동안 메모리에 유지해서 읽기를 최소화 플러시(Flush) : 디스크로 동기화되지 않은 데이터를 가진 데이터 페이지(더티 페이지)의 목록 관리 프리(Free) : InnoDB 버퍼 풀에서 실제 사용자 데이터로 채워지지 않은 비어 있는 페이지들의 목록 4.2.7.3 버퍼 풀과 리두 로그 InnoDB의 버퍼 풀은 디스크에서 읽은 상태로 전혀 변경되지 않은 클린 페이지(Clean Page)와 함께 insert,update,delete 명령으로 변경된 데이터를 가진 더티 페이지(Dirty Page)도 가지고 있다. 더티 페이지는 언젠가 디스크로 기록되야 하며 버퍼 풀에 무한정 머무를 수 있지 않다. ...

2023년 9월 14일 · 3 분 · 배준수

자료구조(4) 연결리스트

10일차 게일 라크만 맥도웰의 코딩 인터뷰 완전 분석 p.139 ~ p.141, 2.1, 2.2 내용 정리 9 면접 문제 02 연결리스트 연결리스트는 차례로 연결된 노드를 표현해주는 자료구조이다. 단방향 연결리스트에서 각 노드는 다음 노드를 가리킨다. 양방향 연결리스트에서 각 노드는 다음 노드와 이전 노드를 함께 가리킨다. 배열과는 달리 연결리스트에서는 특정 인덱스를 상수 시간에 접근할 수 없다. K번째 원소를 찾고 싶다면 처음부터 K번 루프를 돌아야 한다. 연결리스트의 장점은 리스트의 시작 지점에서 아이템을 추가하거나 삭제하는 연산을 상수 시간에 할 수 있다는 점이다. 연결리스트 만들기 LinkedList 자료구조를 사용할 수 있다. ...

2023년 9월 14일 · 2 분 · 배준수

InnoDB 스토리지 엔진 아키텍처

책너두 6기 9일차 백은빈, 이성욱의 Real MySQL8.0 1권 p.98 ~ p.107 내용정리 04 아키텍처 4.2 InnoDB 스토리지 엔진 아키텍처 InnoDB는 MySQL에서 사용할 수 있는 스토리지 엔진 중 거의 유일하게 리코드 기반의 잠금을 제공하며, 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어나다. 4.2.1 프라이머리 키에 의한 클러스터링 InnoDB의 모든 테이블은 기본적으로 프라이머리 키를 기준으로 클러스터링되어 저장된다. 프라이머리 키 값의 순서대로 디스크에 저장된다는 뜻이며 모든 세컨더리 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용한다. ...

2023년 9월 13일 · 3 분 · 배준수

자료구조(3) 배열과 문자열

9일차 게일 라크만 맥도웰의 코딩 인터뷰 완전 분석 예제 1.4~1.9 내용 정리 9 면접 문제 1.4 회문 순열 주어진 문자열이 회문(palindrome)의 순열인지 아닌지 확인하는 함수를 작성하라. 회문이란 앞으로 읽으나 뒤로 읽으나 같은 단어 혹은 구절을 의미하며, 순열이란 문자열을 재배치하는 것을 뜻한다. 회문이 꼭 사전에 등장하는 단어로 제한될 필요는 없다. 예제 입력 : Tact Coa 출력 : True (순열: “taco cat”, “atco cta” 등) 1 2 3 4 5 6 7 def main(s): arr = list(s) new_arr = set(arr) if 2*len(new_arr) - len(arr) <= 1: return True else: return False 1.5 하나 빼기 문자열을 편집하는 방법에는 세 가지 종류가 있다. 문자 삽입, 문자 삭제, 문자 교체. 문자열 두 개가 주어졌을 때, 문자열을 같게 만들기 위한 편집 횟수가 1회 이내인지 확인하는 함수를 작성하라. ...

2023년 9월 13일 · 3 분 · 배준수

점진적인 개선(5)

책너두 5기 33일차 로버트 C. 마틴의 클린코드 p. 305~ p.321 내용정리 14. 점진적인 개선 지금까지의 리팩터링 결과 인수 유형을 추가하는 것이 매우 쉬워졌다. 이를 확인하기 위해 우선 시스템이 double 인수 유형을 제대로 받아들이는지 확인할 테스트 케이스를 추가한다. 1 2 3 4 5 6 7 public void testSimpleDoublePresent() throws Exception { Args args = new Args("x##", new String[]{"-x", "42.3"}); assertTrue(args.isValid()); assertEquals(1, args.cardinality()); assertTrue(args.has('x')); assertEquals(42.3, args.getDouble('x'), .001); } 스키마 구문분석 코드를 정리하고 ## 감지 코드를 추가한다. ##는 double 인수 유형을 뜻한다. ...

2023년 9월 13일 · 12 분 · 배준수

5. 확률적 분석과 랜덤화된 알고리즘

5. 확률적 분석과 랜덤화된 알고리즘 통계에 관한 기초 용어 설명 확률함수 어떤 사건 X가 일어날 확률을 Pr(X)라고 표현한다. 주사위를 던져서 1이 나오는 사건을 A, 짝수가 나오는 사건을 B라 하면 $$ Pr(A) = \frac16 , \ \ Pr(B) = \frac12 $$ 라고 표현할 수 있다. 기댓값 각 사건이 벌어졌을 때의 이득과 그 사건이 벌어질 확률을 곱한 것을 전체 사건에 대해 합한 값이다. 예를 들어 500원 동전을 던져서 앞면이 나오면 500원을 얻는다고 해보자. 앞면이 나올 확률 X는 2분의 1, 즉 50%이다. 따라서 ...

2023년 9월 12일 · 3 분 · 배준수