야놀자 테크캠프 - Git, Github

오늘 배운 강의 자료를 오늘 보면서 복습하려고 했는데, 바로 받을 수가 없다니ㅜㅜ

다음부터는 필기하면서 들어야할듯 하다

머릿속으로 정리하자면

 

1. 기본적인 터미널 명령어

   (1) 절대경로, 상대경로

      ① 절대경로 : root 디렉토리부터의 위치

      ② 상대경로 : 현재 디렉토리부터의 위치

   (2) mkdir : 디렉토리 만드는 명령어

   (3) touch : 새 파일을 만드는 명령어 (ex. touch test.txt)

   (4) vi : vi 편집기를 이용해서 파일 편집

      ① vi test.txt를 실행하면, 처음 모드는 명령모드(입력을 할 수 없음)

      ② 입력을 하려면 a, i를 눌러 입력모드로 변경 후 파일 편집

      ③ 편집을 끝냈으면 다시 명령모드로 변경(esc키)

      ④ :w는 저장, :q는 종료, 이 둘을 합치면 :wq

   (5) cat : 파일을 읽는 명령어

   (6) rmdir : 디렉토리를 지우는 명령어(디렉토리가 비어있을 때만 가능)

   (7) rm -rf : 파일이 있는 디렉토리를 지우는 명령어

 

2. Git

   (1) 버전을 관리하고, 협업을 편리하게 하기 위해서 사용

   (2) 버전이란? 유의미한 변경으로 인한 결과물을 뜻함

   (3) git init : git으로 버전관리를 하겠다

   (4) git add : 유의미한 변경으로 취급해서 staging area로 올리겠다

   (5) git commit : 커밋해서 하나의 버전으로 만들겠다

   (6) git reset : 해당 커밋으로 돌아가는 명령어

   (7) git revert : 해당 커밋을 취소하고 이전 커밋으로 다시 커밋하는 명령어


내 공부도 계속해서 하자. 조금씩이더라도 꼭 하자. 오늘도 고생했다!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.13  (0) 2023.07.13
2023.07.12  (0) 2023.07.12
2023.07.10  (0) 2023.07.10
2023.07.08  (1) 2023.07.10
2023.07.07  (0) 2023.07.07
야놀자 테크캠프 - OT

1. 개발자로 어떻게 성장할까?

   (1) 강의 듣고, 프로젝트만 하면 OK? -> NO

   (2) 강의를 통한 성장 -> 강의 '수강' 만으로는 그 어떤 것도 보장해주지 않는다(얻을 수 없다)

   (3) 실력은 절대 수강시간에 비례 X. 실력은 고민의 총량에 비례

   (4) 중요한 것은 '올바른 수강 방법'

      ① 코드의 의미 되새기기

      ② 강의 곱씹기

      ③ 다른 방법 생각해보기(비판적으로 코드 바라보기, 다르게 구현하기)

      ④ 오류 최대한 많이 내기 -> 오류는 개발자의 일상이므로 두려워하지 말기

   (5) 강의 시 다양한 그룹활동에서 적극적으로 참여

   (6) 블로그 / TIL을 통한 성장

   (7) 프로젝트 코드 달랑? -> NO

   (8) 성장, 성실함, 흡수력을 보여줘야 함 -> 블로그/TIL로 보여줄 수 있음

   (9) 잘쓴 블로그/TIL은 면접의 답안지 -> 면접 전날 '기록'을 정주행하면 끝

   (10) TIL 작성 방법

      ① 어떤 문제가 있었는지

      ② 내가 시도해본 것들

      ③ 어떻게 해결했는지

      ④ 새롭게 알게된 점

   (11) 토이 프로젝트를 통한 성장

   (12) 개발실력을 향상하기 위한 목적으로 만든 토이 프로젝트일 경우, 동작 가능한 코드만 개발 X -> 설명 가능한 코드 O

   (13) 커밋 로그를 통한 성장

   (14) 다른 사람 github의 커밋 로그를 보기

 

2. 어떻게 빠르게 성장할까?

   (1) 시간 배분하기

   (2) 최소 10시간 이상 공부(집중한 시간 6시간 이상)

   (3) 강의를 수강 후 언제 복습하는 것이 좋을까? -> 반드시 하루 이내, 되도록 한 시간 이내, 실습으로 복습하기

   (4) 질문하기

   (5) 질문 전 최소 10분이상 1시간 이하 고민해보기 -> 질문을 잘 정리해서 '좋은 질문'을 할 것

   (6) 좋은 질문

      ① 정돈된 질문(자신이 무엇을 아는지 명확히 아는 질문)

      ② 충분한 고민이 반영된 질문

      ③ 과거 답변 / 강의 / 구글링 / 공식문서를 통해서 해결하기 어려운 질문


내일도 열심히!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.12  (0) 2023.07.12
2023.07.11  (0) 2023.07.11
2023.07.08  (1) 2023.07.10
2023.07.07  (0) 2023.07.07
2023.07.06  (0) 2023.07.06
부트캠프 온보딩 강의

1. 메서드와 변수의 관계를 이해하라

   (1) 객체지향에서 메서드는 '객체가 하는 동작'을 의미한다

   (2) 메서드 오버로딩

      ① 메서드를 만들다보면 머서드들의 동작이 서로 비슷할 때가 있다

      ② 이런 메서드들의 이름을 모두 다르게 쓰는 것이 아닌 동일하게 쓸 수 있는 개념이 메서드 오버로딩임

      ③ 그래서 사용자는 비슷한 동작을 하는 메서드 이름 하나만 알면 편리하게 사용할 수 있다

      ④ ex. System.out.println()이 있음. 이 메서드는 이름은 같지만 파라미터에 문자, 숫자 등등 다른 것을 넣어도 모두 콘솔에 찍힌다. 사용자는 단지 콘솔에 찍고 싶으면 System.out.println()만 알면 됨

      ⑤ 오버로딩의 제약조건은 메서드의 매개변수 타입이나 개수가 달라야 함

   (3) 그런데 같은 이름으로 메서드가 여러개 정의되어 있어서, 실행할때 메서드 하나씩 뒤져가면서 호출해야 할 메서드를 찾아야 할 것 같은데 이러면 너무 비효율 적이지 않을까?

   (4) 컴파일을 할 때 미리 사용될 메서드와 연결되어 있음. 이는 정적바인딩이라고 불리고, 따라서 실행속도는 느려지지 않음

 

2. 클래스로 객체 모델링하기

-> 기본적인 클래스를 정의하고 생성하는 이미 아는 내용이어서 확인하는 용도로 들었음


고생!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.11  (0) 2023.07.11
2023.07.10  (0) 2023.07.10
2023.07.07  (0) 2023.07.07
2023.07.06  (0) 2023.07.06
2023.07.05  (0) 2023.07.05
부트캠프 온보딩 강의

1. 데이터의 이동 배열을 이용하라

   (1) 배열 : 한개가 아닌 여러개의 데이터를 묶어서 관리하는 자료형

   (2) int[] a = new int[3]

      ① 배열도 객체처럼 먼저 new int[3]으로 메모리에 배열 공간을 만든다

      ② 그 주소를 a에 저장한다

   (3) 객체배열 : Book[] books = new Book[3]

      ① 메모리에 Book의 주소를 저장할 수 있는 배열 공간을 만든다

      ② 그 주소를 books에 저장한다

      ③ 배열 각각 하나의 공간에 새로운 Book을 만들어서 주소를 저장한다

   (4) 배열의 장점

      ① index를 이용해서 반복문을 사용하기 편리하다

      ② 데이터를 배열로 묶어서 이동하기에 편리하다

   (5) 2차원 배열 : int[][] a = new int[3][5]

      ① 메모리에 int배열(int[])의 주소를 저정할 수 있는 공간을 3개 만든다

      ② 그 공간의 주소를 a에 저장한다

      ③ 5개짜리 int배열을 만들고 각각의 공간에 그 주소를 저장한다

 

2. 논리적인 사고력 키우기 훈련

-> 반복문, 제어문 등등 이미 아는 부분이어서 확인하는 용도로 강의를 들었음


스프링 핵심 원리 고급편 (김영한 강의) - 섹션 4 : 프록시 패턴과 데코레이터 패턴

섹션 목적 : 프록시 패턴과 데코레이터 패턴을 알아보고 적용시켜, 새로운 요구사항을 만족시켜보자

 

1. 예제 프로젝트 만들기

   (1) v1 : 인터페이스와 구현 클래스 -> 스프링빈으로 수동 등록

   (2) v2 : 인터페이스 없는 구체 클래스 -> 스프링빈으로 수동 등록

   (3) v3 : 컴포넌트 스캔으로 스프링빈 자동 등록

 

2. 요구사항 추가

   (1) "원본 코드는 전혀 수정하지 않고, 로그 추적기를 적용하라"

   (2) 이 문제를 해결하려면 먼저 프록시 개념을 이해해야함

 

3. 프록시, 프록시 패턴, 데코레이터 패턴 - 소개

   (1) 클라이언트 : 서버에 필요한 것을 요청

   (2) 서버 : 클라이언트의 요청을 처리

   (3) 일반적으로 클라이언트가 서버를 직접 호출하고 처리 결과를 받음

   (4) 그런데 서버에 직접 요청하는 것이 아닌 '대리자'를 통해서 요청할 수 있음

   (5) 여기서 이 대리자를 '프록시'라 함

   (6) 대리자가 중간에 들어와서 여러가지 이점이 있다. 예시를 보자

      ① 엄마에게 라면을 부탁 -> 집에 이미 있음 -> 빠르게 라면을 먹음 => 접근제어, 캐싱

      ② 아빠에게 주유 부탁 -> 세차까지 해줌 => 부가기능 추가

      ③ 동생에게 라면 부탁 -> 동생은 또 동생에게 부탁 => 프록시 체인

   (7) 아무 객체나 프록시가 될 수 있는것 같지만, 객체에서 프록시가 되려면 클라는 서버에 요청한 것인지 프록시에 요청한 것인지 몰라야 함

   (8) 쉽게 말해서 서버와 프록시는 같은 인터페이스 또는 같은 조상이어야 함

   (9) 그리고 클라는 사용하는 서버 객체를 프록시로 변경해도 클라 코드는 변경하지 않고 동작해야함

   (10) 프록시의 주요 기능

      ① 접근제어 : 권한에 따른 접근 제한, 캐싱, 지연로딩

      ② 부가기능 추가 : 서버가 제공하는 기능에 더해 부가기능을 추가할 수 있음(ex. 로그추적기)

   (11) 프록시 패턴과 데코레이터 패턴은 둘 다 프록시를 사용하고 코드도 비슷하다

   (12) GOF 패턴에서 이 둘을 사용 의도에 따라 구분한다

      ① 프록시 패턴 : 접근 제어가 목적

      ② 데코레이터 패턴 : 새로운 기능 추가가 목적

 

4. 프록시 패턴

   (1) Client와 Subject interface, 이를 구현한 RealSubject가 있다고 하자

   (2) 그리고 RealSubject는 1초나 걸리는 시스템에 큰 부하를 주는 데이터 조회라고 가정

   (3) 프록시를 적용하지 않으면 각 호출은 모두 1초가 걸린다(3번 호출 -> 3초)

   (4) 프록시를 통해서 캐시를 적용시켜 성능을 개선해보자

   (5) 프록시 객체는 Subject interface를 구현하고, 필드로 Subject와 cache를 갖고 있다. 여기서 Subject에는 실제 구현 객체를 주입받고, cache는 캐싱 데이터이다

   (6) 프록시 객체의 interface 메소드는 캐시에 있는지 확인하고 있으면 캐시를 내보내고 없으면 실제 객체를 동작하는 메소드 이다

   (7) 따라서, 사용할 때 프록시 객체에 실제 객체를 주입하고, 클라이언트에 프록시 객체를 주입해서 사용한다

   (8) 이렇게할 경우, 클라이언트는 코드의 변경 없이 프록시를 자유롭게 사용할 수 있다

 

5. 데코레이터 패턴

   (1) 프록시 패턴과 코드의 모양은 동일하다

   (2) 실제 객체의 interface를 구현하고 실 객체를 주입받아서 이것저것 부가기능을 한 후 실객체의 로직을 실행하는 방법이다

   (3) 프록시를 체인처럼 사용이 가능하다. 프록시 안에 프록시를 넣고 체인처럼 이어가는 방식이다

   (4) 프록시와 데코레이터 패턴은 앞서 본 것처럼 '사용의도'에 따라 구분한다

 

6. V1에 프록시 적용

   (1) Controller, Service, Repository interface를 구현해서 프록시 객체를 만든다

   (2) 이 후 프록시 안에 실 객체를 target 필드로 만든다

   (3) interface 구현 로직에 로그를 찍고 -> target.XXX() -> 로그 찍기를 넣는다

   (4) 이 후 의존관계 설정에서 실제 객체가 아닌 프록시를 스프링 빈으로 등록한다

   (5) 프록시 안에 실제 객체를 주입하고, 실제 객체에는 프록시를 주입하는 방식으로 구현한다

   (6) 너무 많은 프록시 클래스를 생성해야하지만 나중에 해결하도록 하자

 

7. V2에 프록시 적용

   (1) Controller, Service, Repository 구체 클래스를 상속받아서 프록시 객체를 만든다

   (2) 이 후 똑같이 프록시 안에 실 객체를 target 필드로 만든다

   (3) 여기서 단점은 부모 클래서의 생성자를 사용하지 않는데 자바 규칙때문에 호출해야한다는 점이다. super(null)로 부모 생성자를 호출한다

   (4) V1과 같이 부모 로직을 overriding해서 로그를 찍고 -> target.XXX() -> 로그 찍기를 넣는다

   (5) 의존관계 설정은 V1과 같다

   (6) 위 두가지 방법으로 기존 코드 변경없이 로그 추적기를 적용했다. 하지만 너무 많은 프록시 클래스를 만들어야 한다. 어떻게 해결할까?


오늘 하루도 고생 많았다!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.10  (0) 2023.07.10
2023.07.08  (1) 2023.07.10
2023.07.06  (0) 2023.07.06
2023.07.05  (0) 2023.07.05
2023.07.04  (0) 2023.07.04
부트캠프 온보딩 강의

1. 자료형을 이해하라

   (1) 자료형에는 기본자료형과 객체자료형이 있다

   (2) 기본자료형은 기본으로 제공해주는 자료형이고 객체자료형은 사용자가 정의한 새로운 자료형이다(class는 사용자 정의 자료형을 만드는 도구)

   (3) 컴파일러는 기본자료형을 보고 바로 알 수 있지만, 사용자 정의 자료형을 보면 무엇인지 몰라서 찾아야함

   (4) 그래서 개발자는 사용자 정의 자료형의 위치를 알려줘야함(ex. java.lang.String)

   (5) 하지만 java.lang은 많이 사용하기에 컴파일러는 별다른 표시가 없으면 java.lang으로 이해하고 이 패키지를 찾아 클래스를 인식함

   (6) 기본자료형은 byte에 따라 담을 수 있는 숫자의 범위가 정해진다(ex. int = 4byte = 32bit = -2^31 ~ 2^31 - 1)

   (7) int a = 0b0010, 0105, 0x45 등 2진수, 8진수, 16진수로 표현할 수 있다

   (8) 문자자료형은 기보적으로 int로 보관한다

   (9) char c = 'a'에서 'a'를 정수로 바꿔서 저장해야함

   (10) 그래서 문자랑 정수를 코드로 매핑시켜 놓은 것에 아스키코드와 유니코드가 있음

   (11) 예를 들어 'A' : 65, 'a' : 97, '가' : 44032 처럼 매핑이 되어있음

   (12) 아스키코드는 1byte여서 비영어권은 매핑이 안돼서 자바는 2byte인 유니코드를 사용함

   (13) 변수의 타입을 다른 타입으로 변환하는 것을 '캐스팅'이라고 함

   (14) 작은 데이터 타입 -> 큰 데이터 타입으로 변환하는 것은 자동으로 되지만, 큰 데이터 타입 -> 작은 데이터 타입으로 변환할 경우 명시적으로 형변환을 작성해야 함

   (15) 기본형 타입에서 연산시

      ① 두 타입을 같게 일치시킨다(ex. long + int -> long + long -> long, float + int -> float + float -> float)

      ② int보다 작은 타입이면 int로 변환된다(ex. char + char -> int + int -> int, byte + short -> int + int -> int)

 

2. 객체와 클래스의 등장

   (1) 객체데이터는 하나가 아닌 여러개의 구조로 이루어진 데이터이다

   (2) 여러개의 데이터를 묶어서 하나의 자료형으로 만들고 이를 사용자 정의 자료형이라 함

   (3) 클래스란 새로운 자료형을 만드는, 설계하는, 모델링하는 도구임

   (4) Book b = new Book()에서 new Book()으로 메모리에 Book 인스턴스를 생성하고 이 주소를 b에 담는 방식으로 객체가 생성됨

   (5) '.'을 이용해서 객체의 프로퍼티에 접근함


스프링 핵심 원리 고급편 (김영한 강의) - 섹션 3 : 템플릿 메서드 패턴과 콜백 패턴

섹션 목적 : 템플릿 메서드 패턴부터 템플릿 콜백 패턴까지 진화하면서 코드를 발전시켜보자

 

1. 템플릿 메서드 패턴 - 시작

   (1) 지금까지 로그 추적기를 다 만들고 도입하려하니 문제점이 있음

   (2) 핵심 로직보다 부가기능인 로그를 출력해야하는 부분의 코드가 더 많고 복잡함

   (3) 이 문제를 어떻게 해결할까?

   (4) 코드를 보면 try-catch처럼 동일한 패턴이 있다

   (5) 부가기능을 메서드로 빼고 싶지만 핵심기능이 중간에 있어서 추출하는 것은 어렵다

   (6) 변하는 것과 변하지 않는 것을 분리하자

   (7) 비즈니스 로직인 핵심기능은 변하고, 로그 추적기를 사용하는 부가기능은 변하지 않는다

   (8) 따라서 이 둘을 분리해서 모듈화해야 한다

   (9) 템플릿 메서드 패턴은 이런 문제를 해결하는 디자인 패턴이다

 

2. 템플릿 메서드 패턴

   (1) 템플릿 : 기준이 되는 거대한 틀, 양식이고 그 안에 내용물이 바뀜

   (2) 템플릿 메서드 패턴은 부모 클래스(abstract)에 변하지 않는 템플릿 코드를 두고 변하는 부분만을 자식 클래스에 두는 방법임. 상속과 오버라이딩을 통해 해결함

   (3) 템플릿 메서드 패턴은 매번 자식 클래스를 만들어야하는 단점이 있는데, 익명 내부클래스를 사용하면 단점을 보완할 수 있다

   (4) 적용시켜보자 -> 핵심기능과 부가기능을 분리함으로써 핵심기능에 더 집중할 수 있게 됐다

   (5) 정의 : 부모클래스에서 알고리즘의 골격인 템플릿을 정의하고, 변경되는 로직은 자식클래스에 정의하는 것

   (6) 자식 클래스가 알고리즘의 전체구조를 변경하지 않고, 특정 부분만 재정의 할 수 있다

   (7) 하지만, 단점

      ① 상속을 사용하기 때문에 상속에서 오는 단점을 안고간다. 자식 클래스는 부모의 기능을 사용하지 않는데 강하게 의존하고 있어서, 부모를 수정하면 자식에도 영향을 준다

      ② 상속구조를 사용해야해서 익명 내부 클래스를 만드는 것도 복잡하다

   (8) 이러한 단점을 개선하려면 어떻게? 전략패턴을 사용하자

 

3. 전략 패턴 1

   (1) 전략패턴은 변하지 않는 부분을 Context에 두고 변하는 부분은 Strategy라는 인터페이스를 만들어 구현하도록해서 문제를 해결함

   (2) 전략패턴에서 Context는 변하지 않는 템플릿 역할이고, Strategy는 변하는 알고리즘 부분임

   (3) Context 내부에 Strategy 필드를 갖고 있고, 이 필드에 Strategy 구현체를 주입하면 됨

   (4) 스프링의 의존관계 주입에서 사용하는 방식임

   (5) 전체 흐름

      ① Context에 원하는 Strategy구현체를 주입

      ② Context의 execute를 실행

      ③ Context는 중간에 Strategy.call()을 호출해서 Strategy 로직을 실행함

      ④ Context는 나머지 로직을 실행

   (6) Strategy는 메서드가 1개만 있는 인터페이스이므로 람다로 변경 가능함 -> 굉장히 깔끔해짐

   (7) 정리 : 변하지 않는 부분 Context에 변하는 부분 Strategy를 주입해서 만든다

   (8) 선 조립 후 실행 방식임. 실행 전에 Context와 Strategy를 먼저 조립하고 실행하기만 하면 됨

   (9) 하지만 이 방식의 단점은 조립한 이후에 Strategy를 변경하기 어렵다는 점임

   (10) Context를 싱글톤으로 사용할 때 동시성 이슈 등 고려할 점이 많다

   (11) 먼저 조립해서 사용하는 것이 아닌 유연하게 전략패턴을 사용하는 방법은 없을까?

 

4. 전략패턴 2

   (1) Context 필드에 Strategy를 주입했다면, 실행할 때 전략을 파라미터로 넘겨서 사용해보자

   (2) Context는 Strategy를 필드로 갖고 있지 않는다. 대신에 execute()의 파라미터로 전달받는다

   (3) Context와 Strategy를 선조립 후 실행이 아니라 Context를 실행하는 시점에 Strategy를 전달한다 -> 훨씬 유연해짐

   (4) 하나의 Context만 생성해서 여러개의 전략을 인수로 전달해서 유연하게 실행

   (5) 전체 흐름

      ① 클라이언트는 Context를 실행할 때 인수로 Strategy를 전달

      ② Context는 execute() 로직을 실행

      ③ Context는 파라미터로 넘어온 Strategy.call()을 실행

      ④ Context의 나머지 로직 실행 후 종료

   (6) 당연히 Strategy를 람다로 사용해서 코드를 간결히 할 수 있음

   (7) 정리

      ① ContextV1은 필드에 Strategy를 저장하는 방식으로 전략패턴을 구현

         * 선 조립 후 실행에 적합

         * Context를 실행하는 시점에 조립이 끝났기에 전략을 신경쓰지 않고 실행만하면 됨

      ② ContextV2는 파라미터에 Strategy를 전달받는 방식으로 전략패턴을 구현

         * 실행할 때마다 전략을 유연하게 변경가능

         * 실행할때마다 전략을 계속 지정해줘야하는 단점

   (8) 우리는 변하지 않는 템플릿 안에서 변하는 부분에 약간 다른 코드 조각을 넘겨서 실행하는 것이 목적임

   (9) 따라서 실행시점에 유연하게 실행 코드 조각을 전달하는 ContextV2가 더 적합

 

5. 템플릿 콜백 패턴

   (1) 앞서 본 ContextV2가 템플릿 콜백 패턴임

   (2) ContextV2는 템플릿 역할, 파라미터로 넘어온 실행가능한 코드 조각인 Strategy를 콜백이라 함

   (3) 자바 언어에서는 자바8 이후부터 람다를 사용해서 콜백을 구현함

   (4) 이 패턴은 스프링에서 자주 쓰이며, xxxTemplate는 템플릿 콜백 패턴으로 되어있음 -> 떠올리자!

 

6. 한계

   (1) 이렇게 수정했지만, 로그 추적기를 적용하려면 적게든 원본 코드를 수정해야함(만개면 어떻게할거?)

   (2) 위 문제를 앞으로 프록시 방법으로 개선해보자


부트캠프 온보딩 강의랑 스프링 강의를 들으니깐 시간이 빠듯하다. 일단 우선순위에 따라서 되는것까지 해보자.

오늘 하루도 고생했다!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.08  (1) 2023.07.10
2023.07.07  (0) 2023.07.07
2023.07.05  (0) 2023.07.05
2023.07.04  (0) 2023.07.04
2023.07.03  (0) 2023.07.03
부트캠프 온보딩 강의

1. 생각, 표현, 코딩하기

   (1) 주어진 문제를 컴퓨팅적 사고로 생각하고 -> 그림으로 표현하고 -> 코딩으로 옮기기

 

2. 자바 개발환경 구축하기

   (1) JDK, IntelliJ를 다운받아 자바 개발환경 구축

   (2) JDK는 Java기반 데스크톱 앱을 개발하기 위해서 다운로드가 필요하다

 

3. 첫 자바 프로그래밍 도전하기

   (1) .java 파일을 -> JDK의 javac가 컴파일해서 바이트코드로 된 .class파일을 만든다 -> 이후 JDK의 java가 JVM을 동작시켜서 .class파일을 실행한다

   (2) JVM은 바이트코드로 된 .class파일을 해당 운영체제에 맞는 .exe(실행파일)로 변환해서 실행한다

   (3) 그래서 컴파일 된 .class파일과 운영체제에 맞는 JVM만 있으면, 운영체제에 독립적으로 어디에서 실행할 수 있다

 

4. 이것만 알자! 프로그래밍 3대 요소

   (1) 변수, 자료형, 할당

   (2) 자료형 + 변수명으로 변수를 선언한 후, 변수에 데이터를 할당한다 -> 이것이 프로그래밍 3대 요소

   (3) 변수명은 규칙에 따라 작성해야 함(숫자로 시작X, 이미 정의된 문자 사용X)

   (4) 자료형에는 기본자료형과 사용자정의 자료형이 존재

   (5) 지역변수는 꼭 초기화가 되어야함. 그렇지 않고 연산을 했을 시 컴파일 오류(초기화를 해주세요)가 남

   (6) 변수가 만들어지면 변수를 관리하는 '심볼 테이블'에 저장이 된다

   (7) 심볼 테이블은 key로 변수명을 value로 메모리의 주소를 갖고 있다

   (8) 그래서 변수가 만들어지면 key에 변수명, value에 메모리 주소가 생성되고 이후에 변수를 찾아갈 때 심볼 테이블에서 메모리 주소를 찾고 그 주소로 찾아간다

   (9) 선언되지 않은 변수(c = 100;)을 하면 IDE에서 'cannot resolve symbol 'c''가 나오는데 이 컴파일 오류의 뜻이 심볼 테이블에서 변수를 찾을 수 없다는 뜻이다


이펙티브 자바 - 아이템 10 : equals는 일반 규약을 지켜 재정의하라

- equals는 재정의하기 쉬워보이지만 곳곳에 함정이 있음. 아래와 같은 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선임

   ① 각 인스턴스가 본질적으로 고유하다

   ② 인스턴스의 논리적 동치성을 검사할 일이 없다

   ③ 상위 클래스에서 재정의한 equals가 하위에서도 딱 들어맞는다

   ④ equals 메서드를 호출할 일이 없다

   -> 이럴 경우 equals는 재정의하지 말아라

- 그렇다면 재정의 해야할 때는 언제야? 

- 객체를 무리적으로 같은지가 아니라 논리적으로 같은지를 확인해야하는데, 상위 클래스의 equals가 논리적 동치성을 비교하도록 재정의되지 않았을 때

- 예를 들어 Integer나 String처럼 값 클래스들이 여기에 해당함(우리는 값을 비교하고 싶기 때문)

- equals를 재정의할 때는 아래와 같은 규약을 지켜야 함 (x,y,z는 모두 null이 아님)

   ① 반사성 : x.equals(x)는 true

   ② 대칭성 : x.equals(y)가 true이면 y.equals(x)도 true여야 함

   ③ 추이성 : x.equals(y)가 true이고 y.equals(z)가 true이면 x.equals(z)도 true여야 함

   ④ 일관성 : x.equals(y)를 반복해서 호출했을 때 항상 같은 값이 나와야함

   ⑤ null 아님 : x.equals(null)은 항상 false임

- 이제 하나씩 알아보자

- 반사성 

   ① 자기 자신과 같아야 한다 -> 규약을 따르기 쉽다

- 대칭성

   ① 서로에 대한 동치 여부에 똑같이 답해야 한다

   ② 예를 들어 CaseInsensitiveString이 String과도 비교를 할 수 있도록 재정의하면, cis.equals(str)은 true가 나올 수 있지만 str.equals(cis)는 false가 나와서 대칭성에 위반된다

   ③ 그러므로 CaseInsensitiveString은 자신과 같은 instance들하고만 비교해야 한다

- 추이성

   ① Point(x,y)가 있고 Point를 상속한 ColorPoint(x,y,color)가 있다고 하자

   ② 이 때 Point는 같은 instance인지와 x,y 값을 비교하고 ColorPoint는 같은 instance와 x,y,color 값을 비교할 때, p.equals(cp)는 true일 수 있지만 cp.equals(p)는 false가 된다(대칭성 위반)

   ③ 이렇게 구체클래스를 확장하면서 새로운 값을 추가할 때 equals 규약을 만족시킬 방법은 존재하지 않음

   ④ 그래서, 상속 대신 컴포지션 방법을 사용할 수 있다(ColorPoint(Point, color)로 만드는 방법)

- 일관성

   ① 두 객체가 같다면 수정되지 않는한 영원히 같아야 함

   ② 불변객체는 한번 다르면 끝ㄴ까지 달라야 하므로, 불변 클래서로 만드는게 나을지 고민해보자

- null 아님

   ① null이 아닌 객체는 null과 같지 않아야 함

   ② 굳이 null을 검사할 필요 없이 instanceof로 검사하면 null인지 자동으로 체크 된다

- 위의 방법을 종합해서 양질의 equals 메서드 구현 방법을 정리

   ① == 을 이용해 자기 자신의 참조인지 확인하자. 성능 최적화용임

   ② instanceof 연산자로 입력이 올바른 타입인지 확인

   ③ 올바른 타입으로 형변환

   ④ 핵심 필드들이 일치하는지 하나씩 검사

- 아래는 좋은 equals 예시

@Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Car)) {
            return false;
        }
        Car car = (Car)o;
        return car.number == number && car.name==name;
    }

- 마지막 주의사항

   ① equals를 재정의할 때는 hashCode도 반드시 재정의하자

   ② Object외에 타입을 매개변수로 받는 equals 메서드는 선언하지 말자

- 꼭 필요한 경우가 아니라면 equals를 재정의하지 말자. 재정의해야할 때는 규약을 지키고 핵심 필드들을 모두 빠짐없이 비교하자


해야할 것이 늘었다. 스프링 강의, 부트캠프 온보딩 강의, 이펙티브 자바, 면접질문 정리를 기본으로 하고 시간이 남으면 코테 문제를 풀도록 하자. 쪼금 벅차지만 열심히 해보자!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.07  (0) 2023.07.07
2023.07.06  (0) 2023.07.06
2023.07.04  (0) 2023.07.04
2023.07.03  (0) 2023.07.03
2023.06.30  (0) 2023.06.30
스프링 핵심 원리 고급편 (김영한 강의) - 섹션 2 : 쓰레드 로컬(ThreadLocal)

섹션 목적 : 쓰레드 로컬에 대해 알아보자

 

1. 필드 동기화 - 개발

   (1) 앞서 로그 추적기를 만들때, id와 level을 동기화해야하는 문제가 있었다. 그래서 이 문제를 해결하기 위해 TraceId를 파라미터로 넘기는 방식을 선택

   (2) 동기화에는 성공했지만, 모든 메서드에 TraceId를 파라미터로 추가해야하는 문제가 있었다

   (3) TraceId를 파라미터로 넘기지 않고 해결할 수 없을까?

   (4) 먼저, 파라미터를 넘기지 않는 LogTrace 인터페이스를 만들고 이를 기반으로 개발해보자

   (5) 이제, 필드로 TraceId를 동기화할 수 있는 FieldLogTrace 구현체를 만들자

   (6) FieldLogTrace 특징 

      ① TraceId를 동기화히기 위해 TraceId를 필드로 갖고 있음. 이제 직전 로그의 TraceId는 TraceHolder에 저장됨

      ② syncTraceId() : 최초 호출인 경우 TraceId를 새로 생성하고, 직전 로그가 있으면 id를 동기화하고 level을 1 증가시킴

      ③ releaseTraceId() : level이 0일 경우 null로 바꾸고, 아닐 경우 id를 동기화하고 level을 1 감소시킴

   (7) 테스트 -> 정상 동작함

   (8) 이제 불필요하게 TraceId를 파라미터로 전달하지 않아도 되고, 애플리케이션의 메서드 파라미터도 변경하지 않아도 됨

 

2. 필드 동기화 - 적용

   (1) 애플리케이션에서 문제없이 동작

   (2) 이제 실제 서비스에 배포한다고 가정해보자

 

3. 필드 동기화 - 동시성 문제

   (1) FieldLogTrace는 심각한 동시성 문제를 가지고 있다. 이 문제를 확인하기 위해 1초에 2번 실행해보자

   (2) 동시에 여러 사용자가 요청하면 여러 쓰레드가 동시에 애플리케이션 로직을 호출하게 된다

   (3) 그런데 이 때, 싱글턴으로 등록된 FieldLogTrace의 TraceHolder 필드를 여러 쓰레드가 동시에 접근하기 때문에 로그가 섞이는 문제가 발생하는 것임

 

4. 동시성 문제 - 예제 코드

   (1) 결국 동시성 문제는 여러 쓰레드가 동시에 '같은 인스턴스'의 필드를 변경하면서 발생하는 문제임

   (2) 특히 스프링 빈처럼 싱글턴 객체의 필드를 변경하며 사용할 때, 조심해야 함

   (3) 동시성 문제는 지역 변수에서는 발생하지 않음. 싱글턴 인스턴스의 필드 또는 static 같은 공용 필드일 때 발생함

   (4) 동시성 문제는 값을 읽기만 할 때는 발생하지 않음. 변경 때문에 발생함

   (5) 싱글턴 객체의 필드를 사용하면서 동시성 문제를 어떻게 해결할까?

   (6) 이 때 사용하는 것이 'ThreadLocal' 임

 

5. ThreadLocal - 소개

   (1) 쓰레드 로컬은 해당 쓰레드만 접근할 수 있는 특별한 저장소임

   (2) 물건보관창구와 비슷한 개념임. 여러 사람이 같은 종류의 물건을 창구에 보관하더라도, 창구 직원이 사용자를 인식해서 사용자별로 물건을 보관함

   (3) 그래서, 나중에 물건을 꺼낼 때도 창구 직원이 사용자에 따라 물건을 구분해서 주는 것임

 

6. ThreadLocal - 예제 코드

   (1) ThreadLocal<String> nameStore = new ThreadLocal<>(); 로 사용할 수 있음

   (2) nameStore.set(xxx), nameStore.get(), nameStore.remove() 메소드를 사용할 수 있음

   (3) 쓰레드 로컬을 사용함으로써 쓰레드마다 별도의 데이터 저장소를 갖게되어서 동시성 문제가 발생하지 않음

 

7. 쓰레드 로컬 동기화 - 개발 및 적용

   (1) ThreadLocal<TraceId> traceIdHolder = new ThreadLocal<>(); 로 바꿈

   (2) 이렇게 해서 쓰레드 마다 다른 TraceId를 가짐으로써 동시성 문제를 해결할 수 있음

 

8. 쓰레드 로컬 - 주의사항

   (1) 쓰레드 로컬의 값은 사용 후 제거하지 않으면 WAS(톰캣)처럼 쓰레드 풀을 사용하는 경우 문제가 발생할 수 있음

   (2) 쓰레드 1,2,3이 쓰레드 풀에 있고 쓰레드 로컬의 데이터를 삭제하지 않았다고 가정하자

   (3) 사용자 A에 쓰레드 1이 할당되고 반납되고, 사용자 B에 다시 쓰레드 1이 할당되면, 사용자 B는 사용자 A의 데이터가 조회되는 문제가 발생할 수 있다.

   (4) 그러므로 사용자 A의 요청이 끝나면 ThreadLocal.remove()를 통해서 꼭 값을 제거해야한다


이펙티브 자바 - 아이템 9 : try-finally보다는 try-with-resources를 사용하라

- 자바 라이브러리에는 close메서드를 호출해 직접 닫아줘야하는 자원이 많다(ex. InputStream, OutputStream ...)

- 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 함

- 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다

- try-finally문의 문제점

   ① 자원을 두 개이상 사용할 때 코드가 지저분해짐

   ② try문과 finally문에서 모두 예외가 발생할 수 있는데, 이 때 finally에서 발생한 예외가 이전 예외를 먹어버려서 예외 추적을 어렵게 함

- 따라서, try-with-resources문을 사용하자

- 이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 함(close 메소드룰 구현해야하기 때문)

- 이 구조를 사용하면 

   ① 자원을 여러개 사용하더라도 코드가 짧아서 읽기가 더 수월하다

   ② close에서 발생한 예외는 숨겨지고 그 앞에서 발생한 예외가 기록돼서, 문제를 진단하기도 훨씬 좋다(close에서 발생한 예외는 버려지지는 않고, 스택 추적 내역에 숨겨짐)

- 그러므로, 꼭 회수해야하는 자원을 다룰 때는 try-finally대신 try-with-resources를 사용하자


내일부터는 부트캠프 온보딩 강의와 미션도 시작되니깐 화이팅해보자!!!

 

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.06  (0) 2023.07.06
2023.07.05  (0) 2023.07.05
2023.07.03  (0) 2023.07.03
2023.06.30  (0) 2023.06.30
2023.06.29  (0) 2023.06.30
스프링 핵심 원리 고급편 (김영한 강의) - 섹션 1 : 예제 만들기

섹션 목적 : 예제 프로젝트를 만들고, 점차 하나씩 발전시켜보자

 

1. 예제 프로젝트 만들기 - V0

   (1) 상품을 주문하는 프로세스를 가정하고, 일반적인 웹 애플리케이션 흐름인 Controller -> Service -> Repository로 이어지는 흐름을 최대한 단순하게 만들어보자

   (2) OrderRepository

      ① 상품을 저장하는데 약 1초정도 걸린다고 가정(Thread.sleep(1000))

      ② itemId가 "ex"인 경우 예외 발생

   (3) OrderService

      ① OrderRepository에 저장

   (4) OrderController

      ① OrderService에 orderItem 호출

 

2. 로그 추적기 - 요구사항 분석

   (1) 각 메서드마다 실행시간을 로그로 출력하는 기능을 구현해보자

   (2) ex)

[11111] Controller
[11111] |--> Service
[11111] |<-- Service time = 1004ms
[11111] Controller time = 1014ms

 

3. 로그 추적기 V1 - 프로토타입 개발

   (1) TraceId : id, level을 필드로 가지고 있음

   (2) TraceStatus : TraceId, startTimeMs, message를 필드로 가지고 있음

   (3) HelloTraceV1

      ① begin(message) : 새로운 TraceId를 만들고 이를 이용해서 새로운 TraceStatus를 생성함. 그리고 시작 로그 출력

      ② end(status) : TraceStatus의 시작시간과 현재시간의 차를 계산해서 로그 출력

      ③ exception(status, e) : 예외가 발생한 경우 예외 로그도 함께 출력

 

4. 로그 추적기 V1 - 적용

   (1) Controller, Service, Repository에 HelloTraceV1을 주입함

   (2) 이 후 try-catch문으로 로그 시작 -> 비즈니스 로직 -> 로그 끝의 프로세스를 거침

      ① try : trace.begin() -> 로직 -> trace.end(status)

      ② catch : trace.exception(status, e)를 하고 throw e를 함(예외를 먹어버리면 애플리케이션 흐름에 영향을 주므로)

   (3) 이렇게 할 경우 시간 로그는 잘 출력됨

   (4) 하지만, Controller, Service, Repository 모두 id가 다르고, level은 항상 0임

   (5) id와 level을 동기화해주어야 함

 

5. 로그 추적기 V2 - 파라미터로 동기화 개발

   (1) 트랜잭션 id와 level을 동기화하는 가장 단순한 방법은 다음 로그에 파라미터로 넘겨주면 됨

   (2) TraceId에 이 정보가 담겨 있으므로, TraceId를 넘겨주자

   (3) HelloTraceV2에 beginSync(beforeTraceId, message)를 만들고, 넘겨받은 traceId로 id를 유지하고 level은 1증가시킴

   (4) 이렇게 하면 transaction id를 유지하고 level은 다르게 할 수 있음

 

6. 로그추적기 V2 - 적용

   (1) 이제 Controller -> Service -> Repository로 넘어갈 때, TraceId를 같이 넘겨준다

   (2) 이렇게 하면, 모든 요구사항을 만족하는 로그 추적기를 완성

   (3) 하지만 문제점

      ① TraceId의 동기화를 위해 모든 파라미터를 추가해야함. 인터페이스까지 고쳐야함

      ② 처음 시작할 때는 begin()을 그 다음부터는 beginSync()를 사용해야 함. 만약 바로 Service를 호출할 경우 넘겨진 TraceId가 없음

   (4) 이제 앞으로 하나씩 해결해보자


이펙티브 자바 - 아이템 8 : finalizer와 cleaner 사용을 피하라

- 자바는 finalizer와 cleaner라는 두 가지 객체 소멸자를 제공한다

- 하지만 이 둘은 문제가 있다

   ① Java에서 접근할 수 없게 된 객체를 회수해 가는 역할은 가비지 컬렉터가 하는데, finalizer와 cleaner는 GC가 제때 회수해간다는 보장이 없다 -> 계속 회수되기만을 기다리다가 OutOfMemoryError가 발생할 수 있다

   ② finalizer를 사용해서 객체를 파괴하면 성능이 낮아진다

   ③ finalizer는 보안 문제도 발생할 수 있다

- 그렇다면 해결책은?

- AutoCloseable을 implements하고 클라이언트가 try-with-resources를 이용해서 인스턴스를 다 쓰고나면 close 메소드가 호출되게끔 한다

- cleaner나 finalizer는 혹시나 close 메서드가 호출하지 않을 것에 대비하는 안전망 역할 정도로 사용할 수 있다. 물론 언제 GC가 회수하리라는 보장은 없다

- 따라서 finalizer와 cleaner는 사용하지 말자


코테준비

1. 프로그래머스 - 등굣길

- top-down 방식으로 memoization으로 풀이

- dfs로 작성한 후 중복되는 계산을 cache배열에 저장


다음주부터 패캠X야놀자 부트캠프 시작이니깐 꾸준히 공부하자

'TIL(Today I Learned)' 카테고리의 다른 글

2023.07.05  (0) 2023.07.05
2023.07.04  (0) 2023.07.04
2023.06.30  (0) 2023.06.30
2023.06.29  (0) 2023.06.30
2023.06.28  (1) 2023.06.29

+ Recent posts