2021-10-31

1031 궁금했던 것들

 1. 왜 파일을 업로드 할때 바로 inputStream으로 처리하지 않고, transferTo같은 메소드를 통해서 한번 임시파일로 저장해둔 후에 다시 해당 파일을 처리로직을 짜야 하는지 궁금했다. 

-> 이유: 

곧바로 웹 애플리케이션이 동작하고있는 중인 JVM메모리상에 곧바로 파일을 로드해버리면, 대용량파일일 경우 굉장한 부담이 될수있기 때문이다. 그렇기 때문에 일단 임시파일로서 업로드하고 처리한다!


2. system.out.println을 통해 로그를 찍으면 안좋은 이유

1) 로그에 필요한 필수적인 추적정보들이 누락되며 개발자가 어떤식으로 작성하느냐에 따라서 형식이 무분별하게 된다( ex, 어떤클래스?몇시 ? 등등)

2) log파일에 쓰여지지 않고 콘솔에 출력되기 때문에 통합적인 관리가 어렵다

3) native I/O로서 synchronized키워드를 사용한다. 성능면에서 훨씬 안좋다고 한다. 


2021-10-30

1030 싱글톤 스코프 테스트!

 빈을 가져오는 방법

1. ApplicationContext에서 직접 getBean하기 -> 로우레벨의 기술(나는 스프링을 사용중이다!~) 라는 것을 들켜버리므로 좋지 않다. 

2. Factory클래스를 만들기

ObjectFactoryCreatingFactoryBean을 @Bean으로 올린다.

인터페이스가 있고 - 이 인터페이스를 구현한 ObjectFactoryCreatingFactoryBean이 있음. 해당 클래스의 메소드 setTargetName 이름을 넣어주고 빈으로 등록해서 올린다. 사용할때는 인터페이스 타입으로 @Autowired받으면 됨. 다만 스프링이 정의해둔 인터페이스를 가져다 쓴다는 것이 찜찜할 수 있다. 

어쨌든 그래도 로우레벨을( 어플리케이션콘텍스트) 한번감싸서 팩토리 빈으로 빈을 생성해 주기때문에- 1번보다는 낫다. 빈이 어떤식으로 생성되는지는 몰라도 되기 땜에.

3. Provider<T> 인터페이스 이용하기

해당 인터페이스를 구현한 클래스를 @Bean으로 올리면 됨. Provider<돌려줄 빈타입> 으로 @Autowired받아서사용.


- 재미있었던점!!




첨에 @Configuration으로 안올리고 일반 @Component로 한뒤에 new SingletonScopeBean으로 되돌려주도록 메소드 만들었더니 해당 빈또한 @Component로 돌렸음에도 불구하고 새로운 빈이 또 생겨나서 싱글톤이 아니게되었다!!

그래서 @Autowired로 바꾼뒤에 돌려주게 만들었더니 이제 싱글톤빈으로 돌려줌. 그래서 @보통은 @Configuration으로 붙인담에 그런식으루 쓰는구나 싶었다.. 헷갈리니까?

2021-10-28

1028 불필요한 객체생성을 피하라! 편~~

 

일반적인 스트링의 정규식 비교방법. 편하게 matches를 사용하면 되지만.. 사실 String의 mathces 메소드 안의 Pattern은 매번 비교할때마다 사용되고 버려진다. 그래서 불필요하게 메모리에 올라가고 그때마다 가비지컬렉터가 돌기때문에 훨씬 성능이 느리다.


대신에 사용할수있는 방법은 - static final로 클래스가 로딩될때 미리 메모리에 올려두고 공유하게 하는 것이다. Pattern.compile을 사용하면 된다!


같은 조건에서 100번 돌린결과

일반적인 matches를 사용했을때 : 173 ms,
static final 한 메소드를 사용했을때 : 26 ms로 압도적인 빠름을 확인할수있었다.... 무려 7배정도나 차이가 난다. 불필요한 객체생성을 막음으로써 성능향상을 꾀할수있다!!!


2021-10-26

1026 스프링 @Configuration 싱글톤 테스트

 

Configuration어노테이션의 독특한 점을 발견할수있다.

설령 해당 메소드로 직접불렀다고 하더라도!! 싱글톤임을 보장해준다. @Configuraiton자체도 그자체로 빈이 된다.




신기한결과 - @Configuration어노테이션을 지우고 실험해보았더니.
hello()메소드로 직접부른 hello1 = hello2객체는 같았다.
그러나 getBean에서 hello를 불러올수는 없었다
?!! 뭐지!! 신기한결과...예상치 못했다

내가 예상한 것은 메소드마다 새로운 hello빈이 생성되는 것이었는데,
해당 클래스(TestConfiguration클래스)안에서의 싱글톤만 보장해주고
@Configuraiton이 아니기때문에 - 스프링 컨텍스트에는 올려주지 않는것!!인듯!!


2021-10-25

1025 톰캣, 스레드, 스프링, 커넥션객체

[스프링]

- 메타 정보 파일 + 클래스 => 스프링 어플리케이션

1. 메타정보파일 : xml, 자바 config , db데이터 등등 다양. resourceLoader만 필요적절하게 있다면뭐든 형식오케이

- 스프링 빈 등록방법

1. 형식 : xml또는 java config

2. 방법 : 

1) 직접 bean id일일이 등록

2) component scan해서 베이스 패키지 등록 - 아래에 있는 애들 다 등록하기 . 빈스캐너 등록

3) 스테레오 타입 어노테이션 이용 (위에랑 합쳐서,할수있음)

4) 빈스캐너 : 직접 등록하기 or 해당 빈스캐너를 이미 디폴트로 들고있는 applicationcontext사용하기(우리는 보통 이쪾을 사용하니까 걍 스테레오 타입어노테이션 막붙여버리고 ㅇㅇ 아무렇지않게 쓰고있었다)


3. 반드시 필요한것 : id , class 보통 어노테이션 방식쓰면 - id는 class명에서 앞에만 소문자로 따서 ㅇㅇ만들어짐 

4. 빈 스코프설정  : 디폴트 싱글톤. 특별한 경우 prototype으로 계속 생성도 가능

5. @configuration : 이거 이용해서 여러빈을 한번에 등록. 얘 자체도 하나의 빈이기때문에 싱글톤. 설령 얘의 메소드를 직접부른다고 하더라도1!! 반환된 객체는 싱글톤이다 (오묘~~~@!)

6. 같은 타입의빈이 여러개 있을떄 ? -.> @qualified같이 이름으로 구분하거나 / 아니면 배열로 주고 파라메터 받아서 적절하게 반환한다는 전략도 있음. HashMap으로 해서 이름/ 객체로 받을수도 있음!!! 개쩐당


- DI하기

1. 전략 : setter / 생성자 / 필드 / 일반 메소드 주입

2 . 만약에 테스트 환경같이 갈아끼울필요있으면 setter주입고려해보고.

3. 생성자주입쓰면 한번에 할수있으니까 편하다-

-스테레오타입어노테이션 

: 해당 어노테이션으로 빈등록하면 - aop쓸때 걸러낸다던지. 좀더 명확하게 클래스에 이런애입니다!! 라고 정보를 모아서 볼수있으니 편함. 이용하자. @Repository, @Controller, @Service 그외에 애매한 애들은 @Component라고 등록. 

- @Configuration에 등록하는 애들 : 개발자가 작성한 클래스가 아니라 기술적으로 필요한 애들등록할때도 사용@Bean으로. 


- 다양한 종류의 ApplicationContext가 있다. 여기는 빈들이 생성(초기화) 되고 . 한번 호출해준다!! 그러면- 이제 타고타고 유저요청에따라 main메소드가 실행되고. 







2021-10-24

1024 스프링, 스레드, 톰캣에 대한 의문들

 1. 스프링은 빈 객체를 싱글톤전략으로 (기본적으로는) 사용한다.

2. 왜냐? 유저 요청이 들어올때마다 컨트롤러 서비스 각각 개별적으로 띄우면- 금방 메모리가 바닥날것이기 때문에 같은 빈을 공유하는 것이 효율적이다. 

3. 여기서 의문!! 그럼 아니 어떻게 하나의 컨트롤러가 유저요청을 다받아내??

4. 톰캣은 기본적으로 max스레드 수가 200으로 되어있으니까 최대 동시에 200요청을 하나의 컨트롤러가 받아낸다고 ?!! 하는 의문이 들어서 찾아보았다---

https://jeong-pro.tistory.com/204

<< 여기 글을 보고 의문을 해결할수있었다!!!

5. 결론 - 객체 주소(heap영역_)는 공유하지만, 메소드(stack영역)는 개개별 스레드마다 생성되므로- 동기화 우려가 없다. 그래서 빈 객체는 무상태로 유지해야하는 것이 중요하다! 그래야 동기화 이슈가 없다-. 그리고 메소드는stack별로 유저마다 다른 값을 가질것이므로 - 컨트롤러라는 객체를 '공유'한다는 것이 가능하다.

6. '공유'라는 개념을 헷갈리고 있었던것이당.

7. 커넥션풀과 톰캣스레드 수는다르다!!

-> 톰캣스레드별로 커넥션을 물고간다? 뭐 그런 식의 표현을 읽은적이 있다... 근데 커넥션 수 100개만 넘어가도 뻑 죽던데 왜지... 하는 의문이 있었는데그것도 해결!!

스레드를 공유하는게 아니라 객체의 수를 공유한다는 것이었땅.

2021-10-23

1023 리눅스 명령어 정리

# 리눅스 명령어 정리

## su

switch user

- su: root로 변경

- su [유저명] : 해당 유저로 변경

## sudo

- superuser do

- etc/sudoers파일에서 sudo 명령어실행가능한 유저들 수정가능

- 루트 권한으로 명령어 실행

## dmesg

- 부팅하는 동안의 로그메시지 출력 명령어

- etc/log/dmesg에 쌓인다고함

## service, systemctl

- 서비스 제어 명령어

systemctl 옵션 서비스명.service~ (.service는 생략가능)

- 예시

$ systemctl start iptables

CentOS 6이전 버전은 service~구문으로,

CentOS 7이후 버전은 systemctl~ 구문으로 제어한다.

systemctl을 사용해달라는 친절한 메시지를 확인할수있음

- 원래는 /etc/init.d에 등록된 서비스들을 제어하는명령어이나 현재는 


systemctl list-unit-files명령어를 통해서 확인가능하다.

## shutdown

- 시스템 종료명령어. 아주 큰일나니까(맘대로 서버 종료!ㅎ..) 쓰지말고 로그아웃을 합시다.

## reboot

- 시스템 재시작명령어.

shutdown -r을 통해서도 할수있음

1023 Java Web Application

 1. 웹 서버와 클라이언트 

- 웹서버: 아파치 서버 등등. 자원을 가지고 서비스를 제공하는 쪽

- 클라이언트: 자원을 요청하거나 자원을 스스로 만들어서 서비스를 제공받는쪽

1) HTML & HTTP

- HTML : 웹서버와 클라이언트의 언어

- HTTP : 웹서버와 클라이언트의 통신규약

2) 요청(리퀘스트) 3대요소 : URL, METHOD, 파라메터


-> restTemplate을 사용해서 getForEntity를 보낼때를 생각해보자 -

// 사용시 주의사항 : 타임아웃설정!!

일반 new RestTemplate()해서 부르면 - 타임아웃없이 그냥 설정됨!

restTemplate이란 - 스프링에서 HTTP통신을 좀더 깔끔하게 할수있도록 제공해주는 클래스이다. 추상화된 객체. 따라서 우리는 좀더 이쁘게 코딩할수있게 된다.

 getForEntity에 사용하는 요소가 무엇인가? 바로 url과, get이라는 메소드, 그리고 파라메터들이다. get을 사용하기 때문에 파라메터들은 쿼리스트링으로 url에 포함되어서 날아가게 된다 .

그럼 exchange()메소드를 사용해서 보낼때도 생각해보자. 

HttpEntity클래스안에 보낼 파라메터들을 모아서 넣을 수 있다.

HttpEntity란, 헤더와 바디를 함께 담을수있는 클래스이다.

org.springframework.http

Class HttpEntity<T>

  • Type Parameters:
    T - the body type
    Direct Known Subclasses:
    RequestEntityResponseEntity


    public class HttpEntity<T>
    extends Object
    Represents an HTTP request or response entity, consisting of headers and body.

    Typically used in combination with the RestTemplate, like so:

     HttpHeaders headers = new HttpHeaders();
     headers.setContentType(MediaType.TEXT_PLAIN);
     HttpEntity<String> entity = new HttpEntity<String>(helloWorld, headers);
     URI location = template.postForLocation("https://example.com", entity);
     

header에 넣을 부가정보 있으면 넣어주고 (이를테면, 콘텐츠타입 지정)

URL당연히 넣어주어야 하고

파라메터 넣을 거있으면 바디에 넣어주고 해서 -> REST요청 보내기!!

이 클라이언트 - 서버 관계는 상대적이다.

요새는 MSA구조를 많이들쓰니까.. 자원을 요청하는 쪽이 누구냐? 에 따라서 - 웹서버가 클라이언트가 되어서 다른 웹서버에게 요청을 하기도 하는것이다.

3) response 3대요소: status code, content type , content 

-> 마찬가지로 똑같이 restTemplate상상하면 쉽다!!

restTemplate에서 getStatusCode()해서 부를수있고, getBody()해서 콘텐츠 꺼내오는 거!!


- 참고: mime type = content type동의어이다.

4) url

통신규약 :// 호스트의주소:포트번호/자원의 위치


2. JSP & Servlet

- 사용이유 : 동적콘텐츠 생성.

어떤 콘텐츠들은 자주 변경된다. 이런 콘텐츠를 서버에다 전부 넣어두면- 넘 비효율적이고 비대하다. 따라서 이러한 콘텐츠들은 동적으로 생성해서 요청시마다 반영한다. 

3. 웹 컨테이너 

1) 톰캣은 웹 컨테이너이다.

2) 웹 컨테이너란 ? 간단하게 말하자면, 사용자의 요청을 받아 response를 주는 스레드이다. 톰캣도 결국엔 하나의 스레드이고- 웹 요청 이라는 작업!! 을 처리하는 녀석인 것이다.

3) 요청을 처리하는 순서 : request받음 -> servlet찾음 -> 서블릿이 작업처리하면 그것을 response로 보냄

4. 웹 컨테이너의 장점

1) 효율적인 비지니스 로직 처리 : socket을 자바단에서 만들어서 포트생성하고.. 요청계속 기달리고.. 요청끊기면 막 그거 따라서 close떄려주고.. 이런 low레벨의 코딩을 안해도 된다. 톰캣이 알아서 요청 받아서 샥샥 처리해준다. 

2) 서블릿 스레드 생성 처리 : 톰캣이 유저요청에 따라서 알아서 서블릿 스레드를 생성해준다. 우리가 스레드를 일일이 유저별로 안만들어줘도 된다!!

3) 멀티스레드 지원 

4) pool관리: 기본적으로 톰캣 max pool은 200. 하지만 여기에 비동기처리를 한다면? 톰캣스레드 1명이서 웹 요청 처리하고 return하고, 워커스레드 슉슉슉 만들어서 더 효율적으로 처리할수있음!! 이런 풀관리를 컨테이너 차원에서 할수있으니까 개발자는 넘 편해진다. 


2021-10-12

1012 FactoryBean 만들기

 

스프링이 bean을 등록하는 방식

1. 자바 리플렉션

2. FactoryBean이용.

직접 factorybean클래스를 상속하여 나만의 helloFactoryBean을 만든다. 

hello 오브젝트를 interface만든후 impl클래스 하나 만들고. @Autowired로 받아둔다.

hello factory bean은, 일종의 프록시로 작동한다. hello의 메소드에 invocationHandler를 붙여서- 부가기능을 첨가해줄것이다. 



재미있는 점은. helloFactoryBean을 bean으로 가져왔을때 던져주는 클래스가 helloFactorybean이 아니라, hello클래스라는 점이다. 

확장한다면 hello뿐만이아니라- 다양한 Object클래스를 받을 수 있을 것이다. 

해당 target 클래스의 toString이 불리는 것을 확인할 수있다.

2021-10-11

1011 implements 하는 타입의 빈이 여러개 등록된경우

 

스프링은 싱글톤으로 빈등록을 한다.그래서 여러개 implements하는 빈이 있으면 어느쪽을 주어야할지몰라서 에러가 발생하곤 한다. 해결방법은

1 ) @qualified사용하거나

2) 이름을 지정해준다

스프링은 일단 타입으로 찾고 -> 그다음에 이름으로 찾기때문에.. 특정 이름으로 인스턴스변수를 넣어주면 그 객체로 @Autowired해준다. 



Tx의 메소드가 호출된 것을 확인할 수 있다. 

이런식으로 한겹 감싸서 - (프록시 패턴. 혹은 데코레이터 패턴) 부가기능을 제공해줄 수 있다. 

1011 spring boot test


 @RunWith 

@SpringBootTest

로 했을 때의 차이??

이상하게 - @Runwith(SpringBoot4TestRunner.class)로 돌리면 ApplicationContext가 찾아지는데

단순히 @SpringbootTest로 붙이면 못찾더라. 왜지?

테스트 쉽게하라고 만들어준 어노테이션이 아니었던 건가?!!



-----

확인결과

 @Runwith(SpringBoot4TestRunner.class)로 돌리면, 단위테스트. 정말로 test에 필요한 최소한의 클래스만 올려줌. 만약에 @Component등.. bean으로 등록한 애들 가져오고 싶은거면

1. @ContextConfiguration으로 지정해서 - 테스트하고 싶은 클래스들만 가져온다

2.

@BootstrapWith(SpringBootTestContextBootstrapper.class)


이용해서 . 빈들 다 띄울수도 있다.

특히 저 둘 어노테이션들은 @SpringBootTest어노테이션안에 들어가 있음. 그래서 @SpringBootTest를 붙이면 모든 클래스를 올려주는 통합테스트가 된다. 

스프링부트가 만들어주는 각종 AutoConfig하는 클래스들과 내가 만든 모든 빈들 전부 등록해준다. 안으로 들어가보면.. mvc (web일경우.) 부터시작해서 각종 autoconfigure클래스들이 들어오는 걸 확인할 수 있다.


3. @ExtendWith 어노테이션 : JUnit4 -> 5로 확장해줌. 

2021-10-09

1009 TDD

# 각종 테스트 지원 라이브러리

## DBUnit 

1. DBUnit 의 데이터셋을 활용하여 손쉽게 DB테스트를 할 수 있다.

2. xml파일을 읽어들여서 테스트 데이터를 만들고 원하는 로직을 검증한다.

3. Assertion 을 제공한다.

4. but 이러한 설정파일을 만들고 테스트하는데 걸리는 시간이 필요하므로, 반드시 DBUnit과 같은 라이브러리를 사용해야만하는지에 대해서 생각해보자. 

## Unitils

1. 리플렉션 단정문을 이용해서 동등성비교가 가능하다.

    - 동일성과 동등성

    - 동일성 : ==로 비교하는것. 수학적 연산. 

    - 동등성: 논리적인 같음을 포함한다. equals 비교. 객체를 비교할 때는 기본적으로 동등성이 보장되지 않음. 동등성비교해서 같게나오게 하고싶으면. equalsAndHashcode를 같게 만들어주어야 한다. 같은 객체는 같은 메모리 주소를 가져야 한다. 

    - 참고: 해쉬코드 연산시 : set등에 저장할때 이것을 같게 만들어주지 않으면 겉보기 내용물은 같아도 두개의 객체가 저장된다.

    - Hash알고리즘을 구현하는 컬렉션은 - 어떠한 그들만의 해쉬함수연산을 돌려서 저장한다. set이 데이터의 순서를 보장하지 않는 것은 맞지만, 뭔가 비슷비슷한 순서로 저장되는 것은 이때문이다. 같은 해시함수를 사용하기 때문에 일정 기준의 객체는 비슷비슷한 위치에 저장되는 것이다. 


2. assertPropertyLenientEquals를 사용해서 자바리플렉션 사용하는 효과 비슷한 것을 누릴 수 있다. 아니면 그냥 reflection 써서 컨스트럭터 만들고 프로퍼티 불러와도 된다.

3. Transaction phase 를 지정할 수 있다. 

4.@Runwith으로 테스트 러너를 확장할 수 있다.

5. @Before에서 관련 라이브러리 및 데이터셋을 셋팅하고, @After에서 tearDown으로 데이터 커넥션을 close하는 메소드를 부를 수 있다.


# TDD 작성 패턴

## 일반적인 어플리케이션

- 생성자 작성패턴 : 잘 사용하지 않지만 db커넥션등을 확인하거나 할때 사용하기도 함.

- dto스타일의 객체 테스트 : 불변객체를 테스트 할때 사용하기도 함.

    - 불변객체란 ?  : 한번 값이 정해지면, 변하지 않는 클래스. 대표적으로 String클래스가 있다. String은 부를 때마다 new String("김마리"); 같이 새로 메모리가 할당된다. 

이러한 객체를 만들어줄 필요성이 있을떄가 있다.. 멀티스레드 프로그래밍 할때라든지. 

- 닭과 달걀 : a 메소드를 테스트하기 위해 b 메소드가 필요한 경우

    - 때에 따라서는 .getDeclaredField 같은 메소드 (리플렉션) 사용해서 가져오기도 하지만. 보기에 코드가 길어지고 그다지 좋지않은 방법. 굳이굳이 해당 접근제한자 바꾸면서 - (setAccessible(true))접근하는것은 권장되지 않는다.

- 배열테스트 : assertArrayEquals사용

- Collection테스트 : 굳이 equals and hashcode를 구현하기 싫다면(?) toString을 비교하는 방식으로 우회할 수 있다. 정렬할경우 sort같은 메소드 사용하거나. 아니면 소트없이 그냥 비교하는 방식사용.

## 웹 어플리케이션

- 각 계층별 테스트가 필요할 수 있다. 

- 프레젠테이션 영역, 어플리케이션 영역, 도메인로직 영역, 인프라스트럭쳐 영역으로 각각 단위 테스트 및 통합테스트가 필요할 수 있다.

- 특히 도메인 로직을 담당하는 부분은 반드시 테스트가 필요하다고 볼 수 있을 것이다.

- 프레젠테이션 영역: 사용자와의 인터렉션. 상호작용 담당. 파라메터를 받는다. 흔히 생각하는 컨트롤러.

- 어플리케이션 영역: 수행해야하는 로직의 뼈대를 잡는다. 말하자면 지휘관. 

- 도메인로직 영역 : 어플리케이션의 핵심로직이 들어가는 부분. 변경의 생명주기에 따라 쪼개어질수있다.

- 인프라스트럭쳐 영역 : 로직을 구현하기 위한 구체적인 구현 객체들이 들어가게 된다. 변경사항에 따라서 얼마든지 바뀔 수있어야함.

### 뷰 테스트

- 반드시 해야하는가? 고민해볼 수 있다.

- 셀레늄과 같은 라이브러리를 이용할 수 있다.

- 사용자 화면(클라이언트) 를 테스트한다는 것인지, 서버 화면을 테스트한다는 것인지 명확해야한다.

### 컨트롤러 테스트

- 스프링 프레임워크의 목객체를 이용해서 MockMVC를 만들고 파라메터를 검증할수있다.

### 서비스 테스트

- 모델에 대한 TDD는 최대한으로 적용한다.

## DB테스트

- 트랜잭션 처리 : 끝나면 롤백한다.

- before, after이용해서 delete 및 insert 한다.

- sql스크립트 파일을 하나 작성해서. 자동적으로 수행되게끔한다

## 테스트 코드의 리팩토링

### 테스트 코드의 원칙

- 테스트 코드는 각각이 독립적으로 수행되어야 한다. 하나의 테스트코드가 다른 테스트 코드에 영향을 미치면 안된다. 이를테면 a테스트코드가 먼저 수행되어야만 성공하는 b테스트코드는 잘못된것이다(하지만 물론 절대적인것은 아니고, 문맥에 따라서는 이러한 테스트코드가 필요한 상황이 있을수있다.)

- 일관된 시나리오를 가지고 있어야한다. 1번과 이어진다. 하나의 테스트코드는 독립적이기 때문에, 한개 테스트코드 내부의 시나리오에 완결성이 있어야한다. -> but 이것역시 절대적인 것은 아니다. 중복을 제거하기 위해서 다른 메소드를 만들어 호출할 수 도 있는것이다.

# TDD에 대한 다양한 시각

## 높은 응집도, 낮은 결합도

- 테스트코드를 작성하다보면, 의존성이 많으면 많을수록 테스트가 어렵다는 것을 깨닫게 된다. 자연스럽게 결합도가 낮은 클래스를 만들수있게 된다.


## 계약에 의한 프로그래밍

- 계약이란(Contract) : 고객의 요구사항, 업무 규칙, 제한조건 등 모든것을 포함한다.

- 테스트주도개발은 방어형 코딩을 주도해준다. 좀더 오류를 줄일 수 있는 것이다.


## TDD유의사항

- 테스트 케이스는 이름이 중요하다. 자신만 알아볼 수 있는 테스트 케이스는 효용성이 떨어진다. 다른 동료에게 읽혀도 명확하도록 작성해야 한다. 

- 제대로 동작하지않는 테스트 케이스는 과감하게 제거한다. 우리에게는 버젼관리 툴이 있으니까 지운다고 해서 문제될것은 없을 것이다.

- 현재 필요한 기능에 대한 테스트케이스만 만든다. 모든 상황을 가정하고 예상하면서 테스트 케이스를 만들면 지쳐 떨어져나가게 될것이다. 

- 테스트 케이스 독립성을 유지한다. 목객체를 이용해서 최대한 의존성을 낮추는 것을 고려해본다. db연결등.

## 행위주도개발 (BDD)

- 어플리케이션의 행위 . 서비스 중에서. 가치있는 기능. 꼭 필요한 기능부터 개발한다

- 탑다운 방식이라고 볼 수 있다

- 흔히 생각하는 - 실패하는 가장 간단한 테스트 코드부터 작성하라 - 라는 원칙은 다운탑 방식이다. 알고리즘 작성에는 효율적이나 실제 기능개발에 있어서는 사용되지않는 메소드까지 전부다 구현해야 하기 때문에 현실적인 상황에 맞지않을 수 있다.

- 런던학파 vs 시카고 학파. 

- 사용자 중심으로 생각하고 , 중요한 기능중심으로 테스트를 작성한다.

- given / when / then템플릿을 이용할 수 있다.


## TDD 실제사용

- 업무시나리오 생각 -> 사람이 하는 부분 제외 -> 하드웨어가 하는 부분 제외 -> 요구사항 정련

- enum 사용고려

- 매직넘버 -> static변수로 바꾸는 것고려. 명확하게 의미를 구분한다

- 변수명 및 메소드 명을 정돈한다

- assert하는 메소드 명을 추출, 이름을 붙여서 명확하게 하는 것을 고려한다

```

- ‘업무규칙’과 ‘기능 요구사항’을 분리한다. 

- ‘고유명사는 대명사로, 명시적인 숫자는 변수로’ 참조할 수 있도록 표시해두면 도움이 된다. 이때 종류 중 하나를 나타낼 때는 어떤(any)으로 치환해 표현하는 것도 때로 도움이 된다. 

- 행동의 주체를 가급적 명확히 표현한다. 

- 동작과 소유를 분리한다.  

예: 객체의 동작인가? 객체의 소유인가? 

- 복합 한자어는 유심히 봐서 분리 가능한지 확인해서 풀어쓰면 더 좋다.  

예: 대여요금 → 대여행위 시에 발생하는 요금 

- 상호작용을 유심히 관찰한다.  

예: 시스템의 행위인가? 고객의 행위인가? 

- 구어체는 좀 더 명확한 의미를 가진 문어체로 변경한다.  

예: 구한다 → 화면에 보여준다. 계산한다. 저장한다    올라간다 → 증가한다. 누적된다.

```


- 업무규칙(우리 회사의 룰), 요구사항(고객과 협의해서 정해야 하는룰) 등등 확인


## 테스트 자동화

- 빌드도구를 사용하여 테스트 케이스 자동화를 할 수 있다.

- 수행결과를 보고서로 확인할 수 있다. 

## 테스트커버리지

- 커버리지 퍼센트가 중요한 것이아니라, 내포된 업무조건을 파악하는 것이 더 중요.

2021-10-06

1006 JUnit 동작원리

 jUnit test시에 - 인스턴스변수가 계속 null이 뜨는 거다. 왜지 - 

이건 분명 jUnit프레임워크 동작원리에 의한것이다 생각. 

JUnit은 매번 테스트 시마다 클래스가 새로 생성된다. 

내가 만든 User객체 - (인스턴스 변수) 도 그때마다 새로 생성되어서. 

Assert를 하는데 null이 뜬다던지 size가 맞지 않는다던지 하였다. 

음!!! 

실험결과

@Before 어노테이션에 뭔가 문제가 있다. 

@Test어노테이션을 걸어서 Assert하면 예상한 결과가 나오는데

@Before을 부르니까 - add () 해서 insert했을때 계속 insert가 하나 밖에 안된다?? 

좀더 JUnit에 대해 공부해야겠음!!!


그리고 인스턴스 변수를 - 각각의 테스트 메소드끼리 공유하지 못한다는 것도 알았다. stateless한 객체 (@Autowired로 넣을수있는, 스프링 빈 같은 애들은 애초부터 무상태니까 괜찮지만) 가 아니면. 인스턴스 변수를 JUnit테스트 메소드에서 건너건너 쓰면 안된다.

하긴 그렇다. 각각의 테스트는 서로에게 영향을 끼치면 안되니까. TDD좀더 공부해야지.

2021-10-03

1003 토비의 스프링 - DI

 1. DI란

- 설계단계에서 클래스 레벨의 의존관계를 설정하는 것이 아니라, 런타임시에 의존관계를 설정하는 것.

2. 어떻게 가능한가?

- 설계 단계에서는 - 즉, 클래스레벨에서는 - 인터페이스만 의존하게 만들어두고, 런타임시에 factory혹은 컨테이너가 적절한 클래스를 생성하여, 생성자의 파라메터로 넣어주는 방식을 취한다. 

- 이것은 @Configuration만 바꾸어주면 가능하므로 - 코드를 일일이 고치지 않고, @Configuration의 수정만으로 의존관계 설정을 바꿀수있다!!

- 클래스간의 의존관계가아니라, 런타임시의 의존관계!! 동적 생성.

3. 응용

- 어떻게 응용할 수 있을까?


1) - 이를테면 db커넥션연결을 test시와 prod시를 분리하고 싶을 때 - 해당 커넥션에 따로따로 클래스를 만들고, @Configuraiton만 갈아끼운다는 전략이 있을수있다.

2)

- 또한 이를테면 관심사의 분리와 함께 응용할 수 있다.

- connection이 이루어질때마다 카운팅을 하는 요청을 생각해보자. 

그럼 커넥션이 이루어질때마다 코드를 수정해서 counter를 하고 , 다시 배포시에는 이걸 일일이 다 고쳐야 할까?! 아니다! 

- connection conter클래스를 따로 만들고, @Configuration에는 이 빈을 등록. 그리고 counter클래스의 생성자에 원래 쓰던 connection객체를 파라메터 생성자로 넘긴다.

그러면- 해당 커넥션이 맺어질떄마다관심사 분리로 counter가 1씩 증가.

실제 사용하는 커넥션 객체는 counter클래스의 생성자파라메터로 들어가있는 애가 커넥션을 수행하게 된다. !!!!

우와아아아.

2021-10-02

1002 토비의 스프링 학습

 


- 관심사의 분리. 

- 클라이언트는 내가 어떤 오브젝트를 사용하는지에 관심이없다. 

- 생성및 관계설정의 책임을 DaoFactory에게 위임한다.

- 원래는 각각의 클래스가 가지고 있던 의존성 책임을 -> DaoFactory에게 위임하고. 각각의 클래스는 본연의 비지니스 역할(콘택스트) 에만 집중할 수 있게된다.

- 결국 이 DaoFactory가 일종의 applicationContext로서 Ioc를 담당

- 프레임워크와 라이브러리의 차이는 제어의 흐름이 누구에게 있는가이다.

- 스프링은 '시간'을 '관계'를 담당해준다.

- 각종 오브젝트들을 적절한 시간에 만들고, 그 오브젝트들의 관계를 넣어준다.

- 우리는 비지니스 로직을 공개하지 않고 코드를 짤수있게 된다. 


- 위코드 확인 : 먼저 빈들을 싱글톤으로 등록해두고 -> 클라이언트가 해당 빈을 요청하면 -> getBean으로 찾아서 리턴한다. 


<용어 정리>

- bean:

스프링이 관리하는 오브젝트. 모든 객체가 빈이 아니라, 스프링이 직접 생명주기를 관리해야만 빈이라고 부른다. 

- bean factory

: 빈의 생명주기와 관계설정을 관리하는 클래스. 보통은 빈 팩토리 클래스를 막바로 사용하기보다 어플리케이션 콘텍스트 클래스를 불러서 사용한다. 

- applicationContext :

빈 팩토리를 상속한다. 빈생명주기 + 스프링이 제공하는 부가적인 기능 .




- 직접 제작한 DaoFactory 에서 만들어낸 userDao클래스는 각각 다른 메모리값이 할당된 별개의 인스턴스이다.

반면 @Configuration어노테이션을 통해 ApplicationContext를 생성하고,

이를 통해 Bean Factory 에서 불러낸 UserDao클래스는 동일하다. 테스트 케이스 초록불을 확인할 수 있다.

즉 스프링은 기본적으로 빈을 생성할때 싱글톤 전략을 사용한다. 하지만 왜일까?

- 번외) 동일성과 동등성

동일성 : 물리적 동일성. 같은 메모리상에 위치한다. 기본적으로 Object의 equals메소드는 동일성비교를 한다. (==)

동등성 : 논리적으로 같은가. 특정기준에 의해서 같은 인스턴스임을 보장한다. 단 이때 물리적 메모리 할당값은 다를 수 있다.  (equals)


- 스프링이 싱글톤으로 빈을 생성하는 이유

: 일단 기본적인 자바 싱글톤 전략을 직접 사용한다고 했을때 발생하는 문제점이 여럿있다.

private생성자이므로 상속불가하고 , 확장불가하고, 테스트 하기 어려워진다. 밖에서 생성할수가 없으니..

그리고 서버환경에서는 반드시 한개만 만들어진다고 보장할 수도 없다. 

-> 그렇지만, 싱글톤으로 생성하는 것 적극지지 - 왜냐하면, 유저의 요청에 따라 계속해서 클래스를 생성하면 메모리가 절대로 못버텨난다. 

- 스프링은 자바의 전통적인 싱글톤 전략 대신 Ioc를 이용하여 빈을 싱글톤으로 생성하고 관리한다. 


- 싱글톤사용시 주의점

: 멀티스레드 환경에서는 객체가 공유되기 때문에 주의한다 . 

따라서 -> 상태stateless해야한다. 변경되는 상태값을 가지고 있으면 안된다.

- 변경될수있는 값은 파라메터로 혹은 지역변수로 전달한다. 이건 스택에 쌓이는 정보이므로 공유되지 않으므로 괜찮다.

- 혹은 읽기전용 변수 / 혹은 다른 싱글톤객체를 인스턴스 변수로 가지고 있는 것은 괜찮다.

1002 리눅스 명령어 : date, uptime,passwd,uname

 # date

현재 날짜와 시간을 출력하는 명령어

- root사용자의 경우 -s (setting)옵션 사용하여 시간설정 가능

uptime

- 시간, 사용자, 접속율 통계

- 현재시간, 시스템 가동시간, 접속한 사용자 수, 평균 시스템 부하 확인가능

passwd

- 비밀번호 설정관련 명령어

- passwd [사용자이름] : 해당 유저의 패스워드 변경

uname

- 시스템 정보 출력

- uname -a : 모든 정보 출력

- 옵션 :

  -m, --machine   머신(하드웨어타입을 출력한다.

 

  -n, --nodename  머신의 네트웍 노드 호스트명을 출력한다.

 

  -r, --release   운영체제 릴리즈 넘버를 출력한다.

 

  -s, --sysname   운영체제의 이름을 출력한다.

 

  -v  운영체제의 버전을 출력한다.

 

   -p  프로세서 종류 출력. x86_64

  -s 커널(운영체제) 이름 출력. Linux

- o OS이름 출력. Linux/CLI

1002 Mock 객체 이용하기

 # 어떻게 의존성 관리를 할것인가?

## 더미 객체

- 해당 인터페이스 상속하는 더미 클래스를 임시로 만든다.

- 객체가 필요할 뿐 기능까지는 사용하지 않을때. 

- 해당 더미객체의 메소드 호출이 필요한 경우 정상적인 결과를 보장하지는 않음

## 테스트스텁

- 더미객체의 기능 + 특정한 값 혹은 메시지를 리턴해줌

- 특정 값 혹은 메시지가 하드코딩되어 있다.

## 페이크 객체(Fake Stub)

- 특정한 값, 메시지가 배열로 저장되어있다. 

- DB데이터의 아주아주 일부를 넣었다고 생각하면 될듯. 

## 사용포인트

- 해당 목 객체의 메소드가 몇번 호출되었는가

- 예상하는 결과값을 돌려주는가


## Mockito 프레임워크

- 메소드 호출 -> 수행 -> 값검증 

- mock객체 생성 -> when(조건 값 혹은 메소드 수행시) -> then( 이러이러한 결과여야 한다.)

- 예상값을 미리 안만들어도 되니까 편리하다.

- when then 으로 목객체 만들고 verify한다.

### 그외

- given / when / then 프레임워크 방식

- 목객체대신 실객체를 손쉽게 사용할 수 있다면 당연 그렇게 해야한다. 목객체를 사용하는 것에 매몰되어 실제 목표를 잊으면 안됨. 효율적으로 코드작성을 하자.

1002 좀더 나은 TDD

 ## 테스트 클래스 위치

### 소스폴더는 다르게, 패키지는 동일하게 , 컴파일된 클래스는 각각 다른 곳으로.

- 컴파일된 대상 클래스와 테스트 클래스의 위치가 서로 다르게 만들어지기 때문에 섞일 염려가 없다. 따라서 배포시에도 아주 빠르게 패키징이 가능하다.

- binary파일들이 위치하는 bin폴더(class들이 위치) 를 따로따로. output 지정하는 것임

### 아예 프로젝트 전체를 분리하기

- 테스트 수행시에 필요한 라이브러리를 분리하기 편하게 하기 위하여 선택하기도 함

### 스프링, 메이븐 프로젝트 방식

- 일반적으로 사용되는 방법. src폴더를 네개로 분류.

- /src/main/java 제품 코드가 들어가는 위치 

- /src/main/resources 제품 코드에서 사용하는 각종 파일, XML 등의 리소스 파일들 

- /src/test/java 테스트 코드가 들어가는 위치 

-/src/test/resources 테스트 코드에서 사용하는 각종 파일, XML 등의 리소스 파일들


# 테스트 메소드명 작성

- 한글을 사용해도 Ok.

- 시나리오 혹은 매개변수등을 추가로 입력해도 Ok.

# 테스트 케이스 작성시 고려사항

- happy day 시나리오를 작성 or Blue day시나리오 작성 등

- 동시성, 성능테스트 문제

- 다른 OS에서도 잘 돌아가는지

- GUI(뷰 영역) 테스트 문제

- 의존성문제 : 보통 목 객체 이용

1002 JUnit

 # 어노테이션

## 순서지정

- @Before, @After는 각각의 메소드별로

- @BeforeClass, @AfterClass는 테스트 클래스 한번씩만.

- 이를테면 tearDown메소드를 작성하여 커넥션 close를 @AfterClass로 작성할수있다.

## 예외 테스트 

- @Test(expected=NumberFormatException.class) 

## 시간 제한 테스트 

- @Test(timeout=1000)

## 테스트 무시 

- @Ignore("this method isn't working yet") 

## 러너

- RunWith(클래스이름.class) 

- JUnit Test 클래스를 실행하기 위한 러너(Runner)를 명시적으로 지정한다. 

- @RunWith는 junit.runner.Runner를 구현한 외부 클래스를 인자로 갖는다.

- 대표적인 스프링의 테스트러너는 자체적인 러너클래스를 구현하고 있다. 이를통해 스프링이 제공하는 새로운 테스트 기능도 사용할 수있게 된다.


1002 TDD 개발

 # TDD 필요성

- 개발자 본인의 우연적 판단에 근거한 프로그래밍을 방지하기 위함

# TDD 정의

- 비지니스코드를 작성하기 전에 테스트 코드를 작성하는 것

# 목표

- 제대로 동작하는 깔끔한 코드 작성

# 진행 방법

- 테스트 케이스 작성

- 테스트 케이스 통과할 수 있는 비지니스 코드 작성

- 리팩토링

- 반복

# 리팩토링 고려사항

- 중복코드 없는가?

- 이름 개선할 수 있는가?

- 소스코드 가독성은?

# JUnit 활용하기

- JUnit 라이브러리를 활용하여 데이터의 값을 직접확인후 테스트결과를 판단하는 것이 아니라  , 플래그의 색여부로 간단하게 테스트 통과여부 확인가능해진다.


## 흥미로웠던 점

- JUnit test class는 메소드 호출시마다 계속 자기자신의 생성자를 만든다.

각각의 테스트케이스를 독립적으로 수행하기 위해 클래스 자체를 리셋하는 것이다. 그래서 각각의 테스트 메소드들의 영향을 최소화한다.


메소드 4개, 생성자도 네번 각각 불리는 것을 확인할 수있다.

0328 fdisk, mkfs, mount, fstab

 1. 하드디스크를 붙인다. 2. fdisk -l로 하드디스크를 확인한다.  - interactiive한 커맨드모드 사용하여 (m) 붙인 하드디스크의 파티셔닝을 한다.  - 마지막에 w를 해야 실제로 반영이 된다.  3. mkfs를 하여 어떤 파일시스...