점진적인 개선(2)

책너두 5기 29일차 로버트 C. 마틴의 클린코드 p. 255~ p.272 내용정리 14. 점진적인 개선 초안 작성 Args.java (Boolean만 지원하는 버전) 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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 package com.objectmentor.utilities.getopts; import java.util.*; public class Args { private String schema; private String[] args; private boolean valid; private Set<Character> unexpectedArguments = new TreeSet<Character>(); private Map<Character, Boolean> booleanArgs = new HashMap<Character, Boolean>(); private int numberOfArguments = 0; public Args(String schema, String[] args) { this.schema = schema; this.args = args; valid = parse(); } public boolean isValid() { return valid; } private boolean parse() { if (schema.length() == 0 && args.length == 0) return true; parseSchema(); parseArguments(); return unexpectedArguments.size() == 0; } private boolean parseSchema() { for (String element : schema.split(”,”)) { parseSchemaElement(element); } return true; } private void parseSchemaElement(String element) { if (element.length() == 1) { parseBooleanSchemaElement(element); } } private void parseBooleanSchemaElement(String element) { char c = element.charAt(0); if (Character.isLetter(c)) { booleanArgs.put(c, false); } } private boolean parseArguments() { for (String arg : args) parseArgument(arg); return true; } private void parseArgument(String arg) { if (arg.startsWith(”-”)) parseElements(arg); } private void parseElements(String arg) { for (int i = 1; i < arg.length(); i++) parseElement(arg.charAt(i)); } private void parseElement(char argChar) { if (isBoolean(argChar)) { numberOfArguments++; setBooleanArg(argChar, true); } else unexpectedArguments.add(argChar); } private void setBooleanArg(char argChar, boolean value) { booleanArgs.put(argChar, value); } private boolean isBoolean(char argChar) { return booleanArgs.containsKey(argChar); } public int cardinality() { return numberOfArguments; } public String usage() { if (schema.length() > 0) return ”-[“+schema+”]”; else return ””; } public String errorMessage() { if (unexpectedArguments.size() > 0) { return unexpectedArgumentMessage(); } else return ””; } private String unexpectedArgumentMessage() { StringBuffer message = new StringBuffer(“Argument(s) -”); for (char c : unexpectedArguments) { message.append(c); } message.append(“ unexpected.”); return message.toString(); } public boolean getBoolean(char arg) { return booleanArgs.get(arg); } } 가장 초기의 코드. 우선 String 인수 유형을 추가하여 아래 코드가 된다. ...

2023년 9월 8일 · 8 분 · 배준수

점진적인 개선(1)

책너두 5기 28일차 로버트 C. 마틴의 클린코드 p. 246~ p.254 내용정리 14. 점진적인 개선 출발은 좋았으나 확장성이 부족했던 모듈을 소개하고, 이를 개선하고 정리하는 단계를 살펴본다. 프로그램을 짜다 보면 내 사정에 딱 맞는 유틸리티가 없어서 직접 짜게 된다. 이를 Args라고 부르겠다. 이 유틸리티는 명령행 인수의 구문을 분석하기 위해 main함수로 넘어오는 문자열 배열을 직접 분석하는 유틸리티다. Args 생성자에 (입력으로 들어온) 인수 문자열과 형식 문자열을 넘겨 Args 인스턴스를 생성한 후 Args 인스턴스에다 인수 값을 질의한다. 다음을 살펴보자 ...

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

동시성(3)

책너두 5기 27일차 로버트 C. 마틴의 클린코드 p. 237~ p.244 내용정리 13.동시성 스레드 코드 테스트하기 지금까지 공부한 것은 스레드가 하나인 프로그램은 지금까지 한 말이 모두 옳다. 하지만 같은 코드와 같은 자원을 사용하는 스레드가 둘 이상으로 늘어나면 다르다. 권장사항: 문제를 노출하는 테스트 케이스를 작성하라. 프로그램 설정과 시스템 설정과 부하를 바꿔가며 자주 돌려라. 실패하면 원인을 추적하라. 스레드가 둘 이상일 때 지침은 다음과 같다. 말이 안 되는 실패는 잠정적인 스레드 문제로 취급하라. 다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자. 다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워 넣을 수 있도록 스레드 코드를 구현하라. 다중 스레드를 쓰는 코드 부분을 상황에 맞춰 조정할 수 있게 작성하라. 프로세서 수보다 많은 스레드를 돌려보라. 다른 플랫폼에서 돌려보라. 코드에 보조 코드(instrument)를 넣어 돌려라. 강제로 실패를 일으키게 해보라. 말이 안되는 실패는 잠정적인 스레드 문제로 취급하라 다중 스레드 코드는 아주 드물게 한번씩 나타나서 실패를 재현하기 아주 어렵고 그로 인해 일회성 문제로 치부한다. 그렇게 되면 잘못된 코드위에 코드가 계속 쌓인다. ...

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

동시성(2)

책너두 5기 26일차 로버트 C. 마틴의 클린코드 p. 230~ p.237 내용정리 13.동시성 난관 동시성을 구현하기 어려운 이유? 예시 1 2 3 4 5 6 7 public class X { private int lastIdUsed; public int getNextId() { return ++lastIdUsed; } } 인스턴스 X를 생성하고, lastIdUsed 필드를 42로 설정한 다음, 두 스레드가 해당 인스턴스를 공유한다. 두 스레드가 getNextId();를 호출한다고 가정헀을때 결과는? ...

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

MySQL 공부 시작

책너두 6기 1일차 책 : Real MySQL 1권 주제 MySQL에 관한 모든 것. 독서 방법 읽고 ‘그렇구나’가 아니라, 적용해보고 따라해보고 손으로 익히자. 책너두에 임하는 다짐 그동안 내가 사용한 데이터베이스는 MongoDB 뿐이었다. 취준을 하다보면 느끼겠지만 SQL 관련하여 코딩테스트를 진행하기도 하고, 기술스택으로도 많이 요구한다. 진작에 공부했어야 했지만 미루다가 책너두를 통해 할 수 있는 원동력을 얻었다. 꼭 완주하자.

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

동시성(1)

책너두 5기 25일차 로버트 C. 마틴의 클린코드 p. 226~ p.229 내용 정리 13. 동시성 동시성과 깔끔한 코드는 양립하기 어렵다. 동시성이 필요한 이유? 동시성은 결합(coupling)을 없애는 전략이다. **무엇(what)**과 **언제(when)**을 분리하는 전략이다. 스레드가 하나인 프로그램은 무엇과 언제가 밀접하다. **무엇(what)**과 **언제(when)**를 분리하면 애플리케이션 구조와 효율이 극적으로 나아진다. 따라서 시스템을 이해하기 쉽고 문제를 분리하기도 쉽다. 예시: 서블릿(Servlet) 서블릿은 웹 혹은 EJB 컨테이너 아래서 돌아가는데 컨테이너는 동시성을 부분적으로 관리한다. 웹 요청이 들어올 때마다 웹 서버는 비동기식으로 서블릿을 실행한다. 원칙적으로 각 서블릿 스레드는 다른 서블릿 스레드와 무관하게 자신만의 세상에서 돌아간다. 서블릿 프로그래머는 동시성을 정확히 구현하도록 각별한 주의와 노력을 기울여야 한다. 그럼에도 서블릿 모델이 제공하는 구조적 이점은 아주 크다. ...

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

창발성

책너두 5기 24일차 로버트 C. 마틴의 클린코드 p. 216~ p.223 내용 정리 12. 창발성 창발적 설계로 깔끔한 코드를 구현하자 켄트 백이 제시한 단순한 설계 규칙 네 가지가 소프트웨어 설계 품질을 크게 높여준다. 다음은 중요도 순이다. 모든 테스트를 실행한다. 중복을 없앤다. 프로그래머 의도를 표현한다. 클래스와 메서드 수를 최소로 줄인다. 단순한 설계 규칙 1: 모든 테스트를 실행하라 테스트가 불가능한 시스템은 검증도 불가능하고, 출시되어선 안된다. 테스트 케이스가 많을수록 개발자는 테스트가 쉽게 코드를 작성한다. 따라서 철저한 테스트가 가능한 시스템을 만들면 더 나은 설계가 얻어진다. ...

2023년 8월 26일 · 2 분 · 배준수

시스템(2)

책너두 5기 23일차 로버트 C. 마틴의 클린코드 p. 206 ~ p.215 내용 정리 11. 시스템 순수 자바 AOP 프레임워크 순수자바 관점을 구현하는 스프링 AOP, JBoss AOP 등과 같은 여러 자바 프레임워크는 내부적으로 프록시를 사용한다. 스프링은 비즈니스 논리를 POJO(Plain Old Java Object)로 구현한다. POJO는 도메인에 초점을 맞춰서 테스트가 쉽고 간단하며, 상대적으로 단순하기 때문에 사용자 스토리를 올바로 구현하기 쉽고 미래 스토리에 맞춰 코드를 보수하고 개선하기 편하다. AspectJ 관점 관심사를 관점으로 분리하는 가장 강력한 도구는 AspectJ 언어이다. 이것은 언어 차원에서 과넞ㅁ을 모듈화 구성으로 지원하는 자바 언어 확장이다. 관점을 분리하기 좋지만 새 도구를 사용하고 새 언어 문법과 사용법을 익혀야 하는 단점이 있다. 하지만 ‘애너테이션 폼’은 이 부담을 어느정도 완화한다. ...

2023년 8월 25일 · 2 분 · 배준수

시스템(1)

책너두 5기 22일차 로버트 C. 마틴의 클린코드 p.198 ~ p.205 내용 정리 11. 시스템 시스템 제작과 시스템 사용을 분리하라 Main 분리 시스템 생성과 시스템 사용을 분리하는 방법 중 하나는, 생성과 관련한 코드는 모두 main이나 main이 호출하는ㄴ 모듈로 옮기고, 나머지 시스템은 모든 객체가 생성되었고 모든 의존성이 연결되었다고 가정하는 것이다. 팩토리 때로는 객체가 생성되는 시점을 애플리케이션이 결정할 필요도 생긴다. 의존성 주입 의존성 주입(Dependency Injection)은 제어 역전(Inversion of Control, IoC) 기법을 의존성 관리에 적용한 메커니즘이다. 제어 역전에서는 한 객체가 맡은 보조 책임을 새로운 객체에레 전적으로 떠넘긴다. 새로운 객체는 넘겨받은 책임만 맡으므로 단일 책임의 원칙을 지키게 된다. 초기 설정은 시스템전체에서 필요하므로 대개 ‘책임질’ 메커니즘으로 ‘main’ 루틴이나 특수 컨테이너를 사용한다. ...

2023년 8월 24일 · 2 분 · 배준수

클래스(3)

책너두 5기 21일차 로버트 C. 마틴의 클린코드 p.189 ~ p.197 내용 정리 10. 클래스 변경하기 쉬운 클래스 변경으로부터 격리 객체 지향 프로그래밍에는 구체적인(concrete) 클래스와 추상(abstract) 클래스가 있다. 상세한 구현(코드)을 포함하는 것과 개념만 포함하는 것의 차이이다. 상세한 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험하므로 인터페이스와 추상 클래스를 사용해 구현이 미치는 영향을 격리한다. 시스템의 결합도를 낮추면 유연성과 재사용성도 더욱 높아진다. 이는 각 시스템 요소가 다른 요소로부터, 변경으로부터 잘 격리되어 있다는 의미다. 11. 시스템 도시를 세운다면? 도시에는 큰 그림을 그리는 사람들도 있으며 작은 사항에 집중하는 사람들도 있다. 한 사람의 힘으로는 직접 관리할 수 없다. 도시가 돌아가는 이유는 적절한 추상화와 모듈화 때문이다. 시스템도 마찬가지다. ...

2023년 8월 23일 · 1 분 · 배준수