이번 주 항해 취업 리부트코스에서 내가 구현한 기능은 무엇인가요?

  • 회원
    • 회원가입(이메일 인증)
    • 로그인
    • 로그아웃
    • 회원정보 수정(주소, 전화번호, 비밀번호)
  • 상품
    • 전체 조회
    • 단 건 조회
    • 상품 등록
  • 주문
    • 주문하기

해당 기능을 구현하기 위해, 어떤 기술적 의사결정을 거쳤나요?

로그아웃을 어떻게 구현할까 고민을 했다. JWT 토큰 유효 시간이 있어 따로 관리할 필요는 없지만
로그아웃 시점에 토큰을 사용 못 하게 할 때에 두 가지 방식을 떠올렸습니다.

1. 블랙리스트 -> 리스트에 등록된 토큰(유효 시간이 남은 토큰)으로 API 요청이 오면 유효하지 않은 토큰이라는 식으로 응답을 주는 방식

2. Redis 사용 -> 로그인 시에 요청 성공 후 토큰 발급 시 Redis에 토큰을 key로 해서 토큰 유효 시간과
동일하게 ttl 설정 로그아웃 시에 요청한 토큰으로 된 key가 있으면 레디스에서 삭제한다.
토큰 필터에서는 api 요청 시에 토큰이 레디스에 존재하는지 여부를 판단

저는 블랙리스트 방식은 지속적으로 토큰이 블랙리스트에 쌓이는 경우 블랙리스트에 있는지 여부를 확인하려면  오래 걸릴 것이고 이후에 api 응답 속도 저하에도 영향이 있을 것으로 생각했습니다.
레디스 방식을 사용하면 즉각적인 토큰 무효화가 가능하기 때문에 2번 방식으로 로그아웃 기능을 구현했습니다.

 

이번 주 겪은 트러블 슈팅이 있다면 무엇인가요?

회원 가입 시에 이메일 인증을 위한 로직이 동기 방식으로 진행이 되니 회원가입 요청 시 응답 시간이 3.6초 정도나 걸렸다. 원인을 분석해 보니 이메일 발송 로직을 비동기로 처리하였더니 응답 시간이 0.7초 정도로 개선이 되었다.

이번 주 진행된 개인 프로젝트에서 얻은 인사이트는 무엇인가요?

우선 주어진 시나리오는 되게 포괄적이고 어떤 기능을 구현해야할 지에 대해서만 간략히 명시가 되어 있었기 때문에 어떻게 구현해야할 지에 대해서는 스스로 판단하고 여러 케이스를 생각을 해야하다보니 생각보다
개발 속도가 나오지 않았다. 처음부터 기획하고 설계하면서 이전에 얼마나 쉽게 생각하고 개발을 했는지에 대해서 뼈저리게 반성을 하고 있다.

이번 주 목표 

📢 이번주 목표는 도메인 주도 개발 시작하기 책 완독하기(78/357)

오늘 스케줄

09:00~13:00 역량 평가 문제 풀이
13:00~14:00 점심 식사
14:00~14:30 프로젝트 발제 듣기
14:30~17:00 코딩테스트 합격자 되기 책 읽기
17:30~18:00 팀 코드 선정 회의
18:30~18:50 기술매니저 님과 팀 코드 리뷰
18:50~17:50 저녁 식사

20:00~21:30 인프런 JPA 1편 강의 듣기
21:30~23:00 DDD 책 읽기
23:00~00:30 인프런 마이크로 서비스 강의 듣기

오늘 목표

👉 역량 평가 4문제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

👉 JPA 1편 강의 듣기

👉 DDD책 읽기

👉 정보처리산업기사 실기 준비

오늘 한 것

  • 역량 평가 4문제 풀기
  • TIL 빠지지 않고 작성하기
  • 북 스터디 참여
  • 인프런 마이크로 서비스 강의 듣기
  • JPA 1편 강의 듣기
  • DDD 책 읽기

오늘 못한 것

  • 정보처리산업기사 실기 준비

알게된 것

DDD(Domain-Driven Design)란?

도메인 주도 설계(Domain-Driven Design, DDD) 소프트웨어를 특정 도메인과 일치하도록 모델링하는 것으로, DDD는 비즈니스 도메인의 개념과 용어를 소프트웨어 코드의 구조와 언어로 표현하여 개발 과정에서 도메인 전문가와 개발자 사이의 의사 소통을 원활하게 하고, 도메인 지식을 더 잘 반영할 수 있도록 합니다.

 

DDD의 한 가지 중요한 특징은 소프트웨어 코드의 구조와 언어가 비즈니스 도메인의 용어와 일치한다는 점입니다. 예를 들어, 대출 응용 프로그램을 개발한다고 가정해보면, 소프트웨어 코드에는 "LoanApplication"과 "Customer"와 같은 클래스, "AcceptOffer"와 "Withdraw"와 같은 메소드가 있을 수 있습니다. 이렇게 함으로써 비즈니스 도메인 전문가와 개발자는 동일한 용어를 사용하며 의사 소통할 수 있으며, 소프트웨어는 실제 비즈니스 도메인을 잘 반영하게 됩니다.

 

DDD는 지속적으로 발전하는 모델의 구현에 초점을 맞춥니다. 즉, 도메인 모델은 초기에 설계되고 구현되지만 도메인의 복잡성과 요구사항의 변경에 따라 계속해서 발전하고 개선됩니다. DDD는 도메인 전문가와 개발자가 함께 도메인을 탐구하고 모델을 개선하며 도메인의 핵심 개념과 도메인 객체들 간의 관계를 명확하게 이해하는 데 도움을 줍니다. 이를 통해 소프트웨어 시스템이 비즈니스 도메인의 복잡성을 잘 다루고 유연하게 대응할 수 있습니다.

 

DDD는 비즈니스 도메인에 집중하고 도메인 모델을 중심으로 개발을 진행함으로써 소프트웨어의 복잡성을 줄이고 유지보수성을 향상시킬 수 있는 장점을 가지고 있습니다. 또한, 도메인 주도 설계는 마이크로서비스 아키텍처와 함께 사용될 때 특히 유용하며, 비즈니스 도메인을 기반으로 서비스를 분리하고 개별적으로 개발하고 배포할 수 있는 이점을 제공합니다.

 

DDD의 원칙과 패턴

도메인 주도 설계는 도메인의 복잡성을 다루기 위해 다양한 원칙과 패턴을 제공하는데, 이에 대해 자세히 설명하겠습니다.

유비쿼터스 랭귀지 (Ubiquitous Language)

유비쿼터스 랭귀지는 도메인에 대해 모든 관계자가 공통으로 사용하는 언어입니다. 코드, 문서, 대화 등 모든 커뮤니케이션에서 일관되게 사용되어야 하며 유비쿼터스 랭귀지를 사용함으로써 도메인 지식을 공유하고, 오해를 줄이며, 협업을 촉진할 수 있습니다.

애그리거트 (Aggregate)

애그리거트는 서로 관련된 도메인 객체들의 묶음으로, 하나의 루트 엔티티를 가지고 루트 엔티티를 통해서만 다른 객체에 접근할 수 있습니다. 애그리거트는 일관성을 유지하기 위해 경계를 정하고 불변식을 지키는데, 이는 도메인 모델의 중요한 구성 요소로 도메인 객체들 간의 관계와 상호작용을 명확하게 정의하고 제한함으로써 도메인의 복잡성을 다룰 수 있습니다.

도메인 서비스 (Domain Service)

도메인 서비스는 엔티티나 값 객체로 표현하기 어려운 도메인 로직을 수행하는 서비스입니다. 도메인 서비스는 상태를 가지지 않으며, 파라미터로 엔티티나 값 객체를 받아서 결과를 반환합니다. 또한 비즈니스 로직을 명확하게 구현하고 중복을 줄이며 응집도를 높이는 역할을 합니다. 이를 통해 도메인 모델에 표현하기 어려운 복잡한 도메인 로직을 분리하고 도메인 객체들 간의 의존성을 관리할 수 있습니다.

리포지토리 (Repository)

리포지토리는 애그리거트의 영속성을 관리하는 저장소로 애그리거트의 생성, 조회, 수정, 삭제 등의 기능을 제공합니다. 리포지토리는 인터페이스와 구현으로 분리되어야 하며, 구현은 메모리, 데이터베이스, 파일 등 다양한 방식으로 이루어질 수 있습니다. 리포지토리를 사용하여 도메인 객체들을 영속화하고, 검색 및 조작할 수 있으며, 도메인 객체의 상태를 관리할 수 있습니다.

도메인 주도 설계의 장점

비즈니스 도메인에 집중: DDD는 비즈니스 도메인을 중심으로 개발을 진행하는 방법론입니다. 개발자들은 도메인 전문가와 긴밀한 협력을 통해 비즈니스 도메인에 대한 이해를 깊이 있게 할 수 있습니다. 이는 개발자들이 비즈니스 도메인의 복잡성을 이해하고 실제 요구사항을 반영하는 소프트웨어를 개발할 수 있도록 돕습니다.

 

의사소통과 협업의 강화: DDD는 도메인 전문가와 개발자 간의 의사소통과 협업을 강화합니다. 비즈니스 도메인의 용어와 개념을 코드에 반영함으로써, 비즈니스 전문가와 개발자는 동일한 언어를 사용하여 서로간의 의사소통을 원활하게 할 수 있습니다. 이는 비즈니스 요구사항을 명확하게 이해하고, 개발자들이 올바른 솔루션을 제공할 수 있도록 돕습니다.

 

유연하고 확장 가능한 설계: DDD는 모델 주도 설계를 강조하므로, 소프트웨어 설계는 비즈니스 도메인 모델을 중심으로 이루어집니다. 이는 소프트웨어가 비즈니스 도메인을 잘 반영하고, 도메인의 복잡성을 다룰 수 있도록 합니다. 또한 도메인 모델은 지속적으로 발전하고 개선될 수 있으므로, 소프트웨어 시스템이 변화하는 요구사항에 유연하게 대응할 수 있습니다.

 

복잡성 관리: DDD는 복잡한 비즈니스 도메인을 모델링하는데 도움을 줍니다. 도메인 모델은 도메인의 핵심 개념과 규칙을 표현하므로 복잡한 비즈니스 도메인을 단순하고 이해하기 쉬운 구조로 변환할 수 있습니다. 이는 개발자들이 복잡성을 이해하고 제어하는데 도움을 주며 유지보수성을 향상시킵니다.

 

품질 향상: DDD는 품질을 중요시하는 설계 원칙과 기법을 제공합니다. 도메인 모델을 통해 비즈니스 도메인의 핵심 개념과 규칙을 명확하게 표현할 수 있으며, 이를 기반으로 한 테스트 가능한 코드를 작성할 수 있습니다. 또한 DDD는 도메인 모델에 대한 테스트를 지원하는 다양한 도구와 패턴을 제공하여 품질 관리를 강화합니다.

 

마이크로서비스 아키텍처와의 결합: DDD는 마이크로서비스 아키텍처와 자연스럽게 결합됩니다. 비즈니스 도메인을 기반으로 서비스를 분리하고 개별적으로 개발하고 배포함으로써, 마이크로서비스 아키텍처의 이점을 최대화할 수 있습니다. DDD는 마이크로서비스 간의 경계 설정과 상호작용을 명확하게 정의하고, 각 서비스를 독립적으로 발전시킬 수 있는 구조를 제공합니다.

 

도메인 주도 설계의 단점

학습 곡선과 복잡성: DDD는 상대적으로 복잡한 개념과 패턴을 포함하고 있어 학습 곡선이 가파를 수 있습니다. 새로운 개념과 용어를 이해하고 적용하는 데 시간이 걸릴 수 있으며, 초기에는 설계 및 구현에 대한 추가적인 노력과 복잡성이 발생할 수 있습니다. 이는 팀의 경험 수준에 따라 영향을 받을 수 있습니다.

 

과도한 추상화: DDD는 도메인의 복잡성을 다루기 위해 추상화를 사용합니다. 하지만 과도한 추상화는 코드의 이해를 어렵게 하고 개발자들이 복잡한 구조를 해석하고 유지보수하는 데 어려움을 줄 수 있습니다. 잘못된 추상화는 오히려 코드의 가독성을 저하시킬 수 있습니다.

 

초기 비용과 시간: DDD는 비즈니스 도메인에 집중하는 설계 방법론으로, 초기에 도메인 모델을 개발하고 도메인 전문가와의 협업을 강조합니다. 이는 초기 개발 비용과 시간을 증가시킬 수 있는데 특히, 도메인의 복잡성이 큰 경우에는 초기 분석과 설계에 많은 시간과 노력이 필요할 수 있습니다.

 

팀 구성과 조직적인 도입 난이도: DDD는 도메인 전문가와 개발자 간의 협업을 강조하므로 팀의 구성이 중요합니다. 도메인 전문가와 개발자가 적절한 수준으로 협력하지 않는다면 DDD의 장점을 충분히 활용하기 어려울 수 있습니다. 또한 기존 조직에서 DDD를 도입하려면 조직 문화와 프로세스의 변경이 필요할 수 있으며 이는 도입 난이도를 높일 수 있습니다.

 

오용과 오버 엔지니어링: DDD는 강력한 도구이지만 오용하면 과도한 복잡성과 오버 엔지니어링으로 이어질 수 있습니다. 적절한 상황과 도메인의 복잡성을 고려하지 않고 과도하게 DDD를 적용하면 개발 프로젝트의 비용과 일정을 증가시키고, 유지보수성을 저하시킬 수 있습니다. DDD는 적절한 규모와 범위에서 적용해야 합니다.

 

기술 종속성: DDD는 도메인 중심의 설계 방법론이지만, 특정 기술과 밀접하게 연결될 수 있습니다. 특히, DDD와 ORM(Object-Relational Mapping) 프레임워크를 함께 사용할 경우 기술 종속성이 커질 수 있습니다. 이는 기술 스택 변경이 어려워지고, 다른 환경에서의 적용이 제한될 수 있다는 점을 의미합니다.

 

정리

도메인 주도 설계(Domain-Driven Design, DDD)는 비즈니스 도메인에 집중하고 복잡성을 다루기 위한 강력한 설계 방법론입니다. DDD는 소프트웨어를 비즈니스 요구사항과 도메인 지식에 밀접하게 맞추어 개발하는데 중점을 두며, 유비쿼터스 랭귀지, 애그리거트, 도메인 서비스, 리포지토리 등 다양한 원칙과 패턴을 제공합니다.

 

이를 통해 DDD는 비즈니스 도메인의 이해와 소통을 강화하고, 개발자와 도메인 전문가 간의 협업을 원활하게 도모합니다. DDD는 복잡한 도메인을 모델링하고 관리하는데 도움을 주며, 유연하고 유지보수 가능한 소프트웨어를 개발하는 데 도움이 됩니다.

 

하지만 DDD도 완벽하지는 않습니다. 학습 곡선이 가파르고 초기 비용과 시간이 소요될 수 있으며 과도한 추상화와 오용으로 인해 코드의 복잡성이 증가할 수도 있습니다. 또한 팀 구성과 조직적인 도입 난이도, 기술 종속성 등의 문제점도 있을 수 있습니다.

 

DDD의 성공적인 도입을 위해서는 팀의 역량과 조직 문화의 지원이 중요하며 상황과 프로젝트 특성을 고려하여 적절한 범위와 규모로 DDD를 적용해야 합니다. 항상 실용성과 목표를 유지하면서 DDD를 적용하고, 도메인 모델을 지속적으로 발전시키는 데 집중해야 합니다.

 

DDD는 비즈니스 도메인을 중심으로 소프트웨어를 개발하고 유지보수하는 데 도움을 주는 강력한 도구입니다. 올바르게 이해하고 적용한다면 DDD는 소프트웨어 시스템의 품질과 유연성을 향상시키고 비즈니스 요구사항을 보다 효과적으로 충족시킬 수 있습니다.

출처: https://tech1.tistory.com/93

🤔오늘의 반성

- TIL 늦게 씀
- 실기 얼마 안남았는데 준비를 못함..

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. 북 스터디 참여
3. 역량 평가 4문제 모두 품
4. 그래도 오늘 하루 열심히 살았다...

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

이번 주 목표 

📢 이번주 목표는 마이크로서비스 구축 가이드 책 완독하기(274/697)

오늘 스케줄

09:00~09:20 모닝 스크럼
09:30~12:00 데일리 과제 문제 풀이

12:00~13:00 점심 식사
13:00~17:30 데일리 과제 문제 풀이
17:30~18:00 팀 코드 선정 회의
18:20~18:40 기술매니저님과 팀 코드 리뷰
18:40~19:40 저녁 식사
20:00~정보처리산업기사 실기 준비

오늘 목표

👉 데일리 과제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

👉 정보처리산업기사 실기 준비

오늘 한 것

  • TIL 빠지지 않고 작성하기
  • 데일리 과제 모두 풀기
  • 북 스터디 참여
  • 정보처리산업기사 실기 준비

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기

알게된 것

오늘은 기술 매니저님이 이력서나 포트폴리오에 너무 부트캠프티가 많이 나지 않아야 한다 고 조언을 주셨다.

해시(Hash)


해시(Hash)는 입력 데이터를 고정된 길이의 데이터로 변환된 값을 말합니다. 다른 말로는 '해시 값(Hash value), 해시 코드, 체크섬' 이라고도 합니다. 이러한 해시는 뒤에서 알아볼 '해시 함수'에 의해서 얻게 됩니다. 간단하게 말하자면, 데이터의 KEY 값이 해시 함수를 통해서 변환된 간단한 정수입니다. 이렇게 정수로 변환된 해시는 배열의 인덱스, 위치, 데이터 값을 저장하거나 검색할 때 활용됩니다.

 

 

 

01. 자료구조의 특징

  • 키(KEY)에 데이터(Value)를 매핑할 수 있는 데이터 구조
  • 해시 함수를 통해 키의 데이터를 배열에 저장할 수 있는 주소(인덱스 번호)를 계산
  • 키를 통해서 저장된 데이터를 빠르게 찾고, 저장 및 탐색 속도가 획기적으로 빨라짐

 

02. 알아둘 용어

1) 해시 함수(Hash Function)

임의의 데이터를 고정된 길이의 값으로 리턴해주는 함수

해시 함수(Hash function)는 입력받은 데이터를 해시 값으로 출력시키는 알고리즘을 말합니다. 이렇게 출력된 해시 값은 알고리즘에 따라 다양한 결과를 보입니다. 그렇기 때문에 함수는 목적에 맞게 다양하게 설계되고 자료구조, 캐시, 검색, 에러 검출, 암호 등으로 유용하게 사용됩니다.

// 해시 함수 예시
Integer hashFunction(String key) {
	
    return (int)(key.charAt(0)) % 100;
}
위 코드는 입력받은 키에서 문자의 0번에 해당하는 부분을 정수화하여 100으로 나눈 뒤, 나오는 나머지를 반환하는 함수(메서드)입니다. 이렇게 반환된 값은 배열의 인덱스가 되고, 해당 인덱스에 맞게 저장을 할 수 있게 되는 것입니다.
이처럼 함수의 로직은 단순할 수도 있고, 복잡할 수도 있습니다.

 

2) 해시 테이블(Hash Table)

키 값의 연산에 의해 직접 접근이 가능한 데이터 구조

해시 테이블(Hash table)은 키와 값을 함께 저장해 둔 데이터 구조입니다. 이는 데이터가 행과 열로 구성된 표에 저장되는 것과 유사합니다. 테이블에 데이터를 저장할 때 위치는 무작위로 지정되어 작성됩니다. 따라서 중간에 여유 공간이 발생할 수 있습니다.

 

표와 유사한 해시 테이블

 

추가 용어
- 버킷(bucket) : 하나의 주소를 갖는 파일의 한 구역, 버킷의 크기는 같은 주소에 포함될 수 있는 레코드 수
- 슬롯(slot) : 한 개의 레코드를 저장할 수 있는 공간, 한 버킷 안에 여러 개의 슬롯이 있음

 

03. 해싱(Hashing)

해싱은 해시 함수에서 해시를 출력하고, 해시 테이블에 저장하는 과정까지의 행위를 말합니다. 이 과정을 그림을 나타내면 아래와 같습니다.

 

해싱(Hashing)

 

 

04. 해시 자료구조의 장, 단점과 용도

1) 장점

  • 데이터 저장 / 일기 속도가 빠름 ( 검색 속도가 빠름)
  • 해시는 키에 대한 데이터가 있는지 확인이 쉬움

2) 단점

  • 일반적으로 저장공간이 많이 필요
  • 여러 키에 해당하는 주소(인덱스)가 동일한 경우 충돌을 해결하기 위한 별도 자료구조 필요

3) 주요 용도

  • 검색이 많이 필요한 경우
  • 저장, 삭제, 읽기가 빈번한 경우
  • 캐쉬 구현
참고 : JAVA 에서는 주로 HashMap 클래스를 사용합니다.
→ 해시 테이블 구조를 활용하여 구현된 JAVA Collection Framework에 속한 클래스

05. 해시 구현하기

// 기본적인 해시 테이블 구현
public class Hash {

    // Hash table
    public Slot[] hashTable; // 배열 형태로 선언

    // Hash 객체를 생성할 때 table 사이즈 지정
    public Hash(Integer size) {
        this.hashTable = new Slot[size];
    }

    // Slot에는 value를 가짐
    public class Slot {

        String value;

        Slot(String value) {
            this.value = value;
        }
    }

    //Hash function
    public int hashFunction(String key) {
        return (int)(key.charAt(0)) % this.hashTable.length; // 나머지
    }
	
    // 입력 받은 key를 해시 함수로 인덱스화 하고, 해당 인덱스에 value 저장
   public boolean saveData(String key, String value) {

		// key는 해시 함수를 거쳐서 해시 값(해시, 해시 주소)을 반환 -> 여기선 배열의 index와 동일
        Integer address = this.hashFunction(key);

		if(this.hashTable[address] != null) { // 해당 주소에 이미 데이터가 있을 경우
        	this.hashTable[address].value = value;
        } else {
        	this.hashTable[address] = new Slot(value);
        }
        
        return true;
    }

	// key에 해당하는 값을 반환
    public String getData(String key) {

		// key는 해시 함수를 거쳐서 해시 값(해시, 해시 주소)을 반환
        Integer address = this.hashFunction(key);

        if(this.hashTable[address] != null) {
            return this.hashTable[address].value;
        } else {
            return null;
        }
   }

실행

    public static void main(String[] args) {

        Hash myHash = new Hash(20);

        myHash.saveData("Lee","30000");
        myHash.saveData("James","15000");
        myHash.saveData("Denny","5000");

        System.out.println(myHash.getData("Lee"));
        System.out.println(myHash.getData("James"));
        System.out.println(myHash.getData("Denny"));

    }

결과

30000
15000
5000

출처: https://kang-james.tistory.com/entry/자료구조-해시HASH-알아보기 [내 꿈을 JAVA:티스토리]

🤔오늘의 반성

- TIL 늦게 씀
- 마이크로서비스 강의 못 들은 점

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. 북 스터디 참여
3. 데일리 과제 모두 품
4. 백준 골드1 달성

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

이번 주 목표 

📢 이번주 목표는 백준 골드2까지 승급하는 것이다. 현재 골드3이다.
     마이크로서비스 구축 가이드 책 완독하기(274/697)

오늘 스케줄

09:00~09:20 모닝 스크럼
09:30~12:00 데일리 과제 문제 풀이

12:00~13:00 점심 식사
13:00~17:30 데일리 과제 문제 풀이
17:30~18:00 팀 코드 선정 회의
18:00~18:20 기술매니저님과 팀 코드 리뷰
18:20~19:20 저녁 식사
19:30~20:30 데일리 과제 못 풀었던 8번 풀기
20:40~휴식

오늘 목표

👉 데일리 과제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

오늘 한 것

  • TIL 빠지지 않고 작성하기
  • 데일리 과제 모두 풀기
  • 북 스터디 참여

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기

알게된 것

다익스트라

  • 최단 경로를 구하는 알고리즘
  • 가중치가 있는 그래프의 최단 경로를 구하는 문제는 대부분 다익스트라 알고리즘을 사용
  • 가중치가 양수일 때 사용이 가능하다.

다익스트라 알고리즘 특징

다익스트라 알고리즘의 특징은 다음과 같습니다.

  • 음수 가중치를 가진 간선이 존재하지 않는다.
  • 탐욕 알고리즘(Greedy Algorithm)을 사용한다.
    • Greedy Algorithm의 설명은 이곳을 참조
  • 미방문(non-visited) 정점(vertexes)들을 저장하기 위해 우선순위 큐 사용

 

다익스트라의 컨셉(The concept of Djkstra's)

여러 도시 중 A라는 도시에서 G라는 도시까지 간다고 가정합시다.

 

경로는 여러가지가 있을 것을 것입니다.

  • A - B - G
  • A - D - F - G
  • ....

만약 한 경로마다 소모되는 시간은 다음 그림과 같다고 합시다.

그렇다면 이때 가장 최단 거리의 경로는 어떤 것일까요?

 

다익스트라 알고리즘은 이 문제를 다음과 같은 명제로 제시합니다.

"부분 경로에서 최단 거리의 집합"

 

 

아래 그림에 나오는 숫자들의 색깔은 다음을 의미합니다.

  • 파란색 숫자: 예상 소요 시간
  • 빨간색 숫자: 해당 노드까지 실제 소요한 시간

 

A 도시에서 출발

다음에 갈 수 있는 도시는 3개뿐 : B, C, D

다음 세 도시(B, C, D) 중 다음으로 갈 수 있는 경로 탐색합니다.

 

1. B도시에서 다음으로 갈 수 있는 경로는

  • E 도시(A-B-E): 6시간 소모
  • G 도시(A-B-G): 11시간 소모 (도착)

2. C도시에서 다음으로 갈 수 있는 경로는

  • E 도시(A-C-E): 8시간 소모

위에서 B를 거쳐 E를 가는 것이 더 빠르기 때문에 이 경로는 제외합니다.

 

  • F 도시(A-C-F): 4시간 소모

3. D도시에서 다음으로 갈 수 있는 경로는

  • F 도시(A-D-F): 9시간 소모

 

위에서 C를 거쳐 F에 가는 것이 더 빠르기 때문에 이 경로는 제외합니다.

 

 

남은 두 도시(E, F)에서 다음으로 갈 수 있는 경로 탐색합니다.

1. E 도시에서 다음으로 갈 수 있는 경로는

  • G 도시(A-B-E-G): 7시간 소모 (도착)

이전에 A에서 B를 거쳐 G에 도착했던 경로(11시간 소모)보다 시간 소모가 더 적기 때문에 해당 경로로 update합니다.

 

2. F도시에서 다음으로 갈 수 있는 경로는

  • G도시(A-C-F-G): 6시간 소모(도착)

바로전에 A-B-E-G 경로에 비해 1시간이 더 적은 6시간이 소모되므로 이 경로로 다시 update합니다.

 

 

이를 통해 다익스트라는 전체 경로의 최단 경로를 찾기 위해서 중간중간 부분 노드에서의 최단 경로를 찾고 새로 탐색한 경로가 내가 이전에 찾았던 경로보다 더 짧은 거리라면 해당 거리로 계속해서 업데이트합니다.

이런 방식을 통해 최종적으로 목적지에 도착했을 때의 최단 거리를 찾아내는 방식인 것입니다.

 

출처: https://cdragon.tistory.com/entry/Algorithm-Dijkstra-Algorithm%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

🤔오늘의 반성

- TIL 늦게 씀
- 마이크로서비스 강의 못 들은 점

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. 북 스터디 참여
3. 데일리 과제 모두 품

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

 

이번 주 목표 

📢 이번주 목표는 백준 골드2까지 승급하는 것이다. 현재 골드3이다.
     마이크로서비스 구축 가이드 책 완독하기(252/697)

오늘 스케줄

09:00~09:20 모닝 스크럼
09:30~12:00 데일리 과제 문제 풀이

12:00~13:00 점심 식사
13:00~17:30 데일리 과제 문제 풀이
17:30~18:00 팀 코드 선정 회의
18:20~18:40 기술매니저님과 팀 코드 리뷰
18:40~19:40 저녁 식사
20:00~22:00 프로그래머스 5문제 풀기
22:00~00:00 코딩테스트 관련 책 읽기

오늘 목표

👉 데일리 과제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

👉 프로그래머스 5문제 풀기

오늘 한 것

  • TIL 빠지지 않고 작성하기
  • 데일리 과제 모두 풀기
  • 프로그래머스 5문제 풀기

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기
  • 북 스터디 참여

알게된 것

그리디(Greedy)

  • 탐욕스러운 또는 욕심이 많은 이라는 뜻
  • 문제 해결 과정에서 결정 순간마다 눈앞에 보이는 최선의 선택을 하며 선택은 번복하지 않음

거스름돈 내어주기

손님에게 8원을 거슬러줘야 하는데 동전 종류가 5, 4, 1원만 있는 상황
동전을 가장 적게 만들기 위해 그리디를 활용
  1. 가장 값이 큰 동전부터 주기 -> 그리디 알고리즘은 현재 상황에서 최선의 선택을 하니 값이 가장 큰 동전부터 준다고 생각 여기서는 5원부터 5원을 주면 3원을 거스름돈으로 더 줘야 한다.
  2. 나머지 3원은 1원 3개를 주는 방법 밖에 없다. 그러면 총 4개의 동전으로 거스름돈을 줬다
  3. 그렇지만 이건 최선이 아니다. 눈으로 봐도 4원 2개를 주는 것이 더 적다. 이처럼 그리디 알고리즘이 항상 최적의 해를 보장하지는 않음

최적해를 보장하려면?

  • 그리디는 특정한 상황에서 최적화를 보장
  • 최적 부분 구조: 부분해를 푸는 과정이 최적해를 구하는 과정과 일치
  • 그리디 선택 속성: 선택 과정이 다른 과정에 영향을 주지 않음

출처: 코딩 테스트 합격자 되기: 자바편

🤔오늘의 반성

- 시간 내에 필수문제를 모두 못 품
- 마이크로서비스 강의 못 들은 점
- 마이크로서비스 구축 가이드 책 못 읽음

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. TIL을 빠지지 않고 작성했다.
3. 백준 골드3 달성
4. 병원 다녀옴

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

이번 주 목표 

📢 이번주 목표는 백준 골드2까지 승급하는 것이다. 현재 골드4이다.
     마이크로서비스 구축 가이드 책 완독하기(252/697)

오늘 스케줄

09:00~09:20 모닝 스크럼
09:30~10:30 완전탐색 강의 수강
10:30~12:00 데일리 과제 문제 풀이
12:00~13:00 점심 식사
13:00~16:30 데일리 과제 문제 풀이
16:30~18:00 병원 진료
18:40~19:10 기술매니저님과 팀 코드 리뷰
19:10~20:10 저녁 식사
20:10~20:40 산책
21:00~22:30 마이크서비스 구축 가이드 책 읽기
22:30~00:00 JPA 프로그래밍 책 읽기

오늘 목표

👉 데일리 과제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

오늘 한 것

  • TIL 빠지지 않고 작성하기
  • 북 스터디 참여

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기
  • 데일리 과제 모두 풀기

알게된 것

완전 탐색이란?

모든 경우의 수를 시도하는 방법
Exhaustive search, Brute force

  • 상대적으로 구현이 간단하고, 해가 존재하면 항상 찾게 됨
  • 경우의 수에 따라 실행 시간이 비례하기 때문에 입력 값의 범위가 작은 경우 유용.

완전 탐색 알고리즘

  • 단순 Brute-Force
    • 단순히 반복문과 조건문으로 모든 경우를 만들어 답을 구하는 방법.
    • 이 방법만을 사용하는 문제는 거의 나오지 않음.
  • 비트마스트 (Bitmask)
    • 나올 수 있는 모든 경우의 수가 각각의 원소가 포함되거나, 포함되지 않는 두 가지 선택으로 구성되는 경우 유용하게 사용
    • ex) '원소가 n개인 집합의 모든 부분 집합'을 구한다면, 각 원소가 포함되는지 포함되지 않는지를 0, 1로 구분하여 배열에 저장해둘 수 있음
  • 재귀함수
    • 비트마스크와 마찬가지로 각 원소가 두 가지 선택지를 가질 때 유용하게 사용.
    • 포함이 되면 해당 원소를 넣어 함수를 호출하고, 포함되지 않으면 그 상태에서 함수를 호출하는 등의 식
    • ex) 피보나치 수열
    • 시간 복잡도 O(N)
  • 순열
    • 순열(permutation)은 서로 다른 N개를 일렬로 나열하는 방법(경우의 수)를 말함.
    • 순열의 경우의 수는 N!으로 완전 탐색을 이용하기 위해서는 N이 한자리 수는 되어야 함.
    • 순열에 원소를 하나씩 채워가는 방식.
    • 재귀함수 이용 or C++의 next_permutation() 함수 이용.
    • 시간복잡도 O(N!)
  • 너비 우선 탐색(BFS), 깊이 우선 탐색(DFS)
    • 너비우선탐색(Breadth-First Search, BFS)는 하나의 요소를 방문하고 그 요소에 인접한 모든 요소를 우선 방문하는 방식
    • 깊이우선탐색(Depth-First Search, DFS)는 트리의 한 요소(노드)와 다음 수준(level)의 자식 노드를 따라가는 방향으로 탐색하는 방식
    • 길 찾기 등에 주로 쓰이는 알고리즘
      : 단순 길찾기에는 BFS/DFS만 써도 무방하지만,
      장애물이 존재하는 등 추가적 연산이 필요할 때 완전탐색 병용하기도 함.
    • ex) 지구 상에 존재하는 모든 친구 관계를 그래프로 표현하고 A와 B 사이에 존재하는 경로 찾을 때
      - DFS : 모든 친구 관계 다 살펴야한다.
      - BFS : A와 가까운 관계부터 탐색한다.
  • 너비 우선 탐색(BFS, Bread-First Search)
    • 재귀적으로 동작하지 않음
    • 그래프 탐색의 경우, 어떤 노드를 방문했었는지 여부를 반드시 검사
      (검사하지 않으면 무한루프)
    • BFS는 방문한 노드들을 차례로 저장하고 꺼낼 수 있는 큐 사용(FIFO)
    • 넓게 탐색
    • 두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때 이 방법을 사용.
// bfs, 큐 사용, 인접행렬, i 정점부터 시작
public static void bfs(int i) {
	Queue<Integer> q = new LinkedList<>();
	q.offer(i);
	visit[i] = true;
	while(!q.isEmpty()) {
		int temp = q.poll();
		for(int j=1; j<n+1; j++) {
			if(map[temp][j] == 1 && visit[j] == false) {
				q.offer(j);
				visit[j] = true;
			}
		}
	}
}
  • 깊이 우선 탐색(DFS, Depth-First Search)
    • 재귀적으로 동작(재귀, 스택)
    • 그래프 탐색의 경우, 어떤 노드를 방문했었는지 여부를 반드시 검사
      (검사하지 않으면 무한루프)
    • 모든 노드 방문하고자 할 때 사용
    • BFS 보다 간단, BFS 비해서 검색 속도 느림
    • 모든 노드 방문하고자 할 때 사용.
// dfs, 재귀, 인접 행렬, i 정점부터 시작
public static void dfs(int i) {
	visit[i] = true;
	for(int j=1; j<n+1; j++) {
		if(map[i][j] == 1 && visit[j] == false) {
			dfs(j);
		}
	}
}

Tip

  • 하나도 빠짐없이 모든 경우의 수를 확인하고 있는지만 확인하면 됨

문제 예시

프로그래머스 - 소수찾기

  • 숫자 카드 7장으로 만들 수 있는 모든 숫자를 만들었는지
  • 만든 모든 숫자가 소수인지
// 모든 숫자 조합 만들기 (dfs)
public void dfs(String numbers, String tmp, int depth) {
	if (tmp.length() == depth) {
		int number = Integer.parseInt(tmp);
        if(!arrNum.contains(number)) arrNum.add(number);
        return;
	}
    else {
		for(int i = 0; i < numbers.length(); i++) {
			if(!visit[i]) {
				visit[i] = true;
                tmp += numbers.charAt(i);
                dfs(numbers, tmp, depth);
                isit[i] = false;
                tmp = tmp.substring(0, tmp.length() - 1);
            }
        }
    }
}
    
// 소수찾기
boolean isPrime(int number) {
	if(number == 0 || number ==1) return false;
	for(int i = 2; i <= Math.sqrt(number); i++){
		if(number % i == 0) return false;
	}
    return true;
}

 

출처: https://velog.io/@hyehyes

🤔오늘의 반성

- 데일리 과제를 처음으로 모두 다 못 풀었다 문제가 어렵다ㅠ
- 마이크로서비스 강의 못 들은 점

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. TIL을 빠지지 않고 작성했다.
3. 북 스터디 참여
4. 병원 다녀옴

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

이번 주 목표 

📢 이번주 목표는 백준 골드2까지 승급하는 것이다. 현재 골드4이다.
     마이크로서비스 구축 가이드 책 완독하기(204/697)

오늘 스케줄

09:00~13:00 역량 평가 문제 풀이
13:00~14:00 점심 식사
14:00~16:30 마이크로서비스 구축 가이드 책 읽기
16:30~17:00 역량 평가 풀이 코드 정리
17:00~17:20 팀 코드 선정 회의
17:20~18:00 휴식
18:00~18:20 기술매니저님과 팀 코드 리뷰
18:20~19:20 저녁 식사
19:30~21:00 JPA 프로그래밍 책 읽기
21:00~22:00 인프런 DB 1편 강의 수강(예외 처리)
22:00~00:00 백준 문제 풀기 5문제
00:00~00:20 TIL 작성

오늘 목표

👉 역량 평가 4문제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 인프런 DB 1편 강의 수강(예외 처리)

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

오늘 한 것

  • 역량 평가 4문제 모두 풀기
  • TIL 빠지지 않고 작성하기
  • 인프런 DM 1편 강의 수강(예외 처리)
  • 북 스터디 참여

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기

알게된 것

⭐ JPA(Java Persistence API)

  • 자바 진영의 ORM 기술 표준이다.
  • 애플리케이션과 JDBC 사이에서 동작한다.

⭐ ORM(Object-Relational Mapping)

  • 객체와 관계형 데이터베이스를 매핑한다는 뜻
  • 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다.
  • ORM을 사용하면 객체를 데이터베이스에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다.
  • 그러면 ORM 프레임워크가 적절한 INSERT SQL을 생성해서 데이터베이스에 객체를 저장해준다.

⭐ JPA를 왜 사용해야 하는가?

  • 생산성
    • JPA를 사용하면 개발자가 직접 SQL을 작성하지 않아도 된다.
  • 유지보수
    • SQL을 직접 다루면 엔티티에 필드 하나만 추가해도 관련된 CRUD 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야 함
    • JPA는 이런 과정을 대신 처리해줘 유지보수해야 하는 코드 수가 줄어든다.
  • 패러다임 불일치 해결
    • 객체와 테이블 간의 상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제를 해결해준다.
  • 성능
    • JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공

출처: 자바 ORM 표준 JPA 프로그래밍 - 기본편(김영한 저)

 

🤔오늘의 반성

- 책 보면서 유튜브 조금씩 본 점
- 운동이랑 병원을 빼먹은 점
- 마이크로서비스 강의 못 들은 점

 

👍 오늘의 칭찬

1. 깃헙 1일 1커밋 달성
2. TIL을 빠지지 않고 작성했다.
3. 역량 평가 4문제 모두 풀었다
4. 북 스터디 참여

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

이번 주 목표 

📢 이번주 목표는 백준 골드2까지 승급하는 것이다. 현재 골드4이다.
     마이크로서비스 구축 가이드 책 완독하기(152/697)

오늘 스케줄

09:00~09:20 팀 모닝 스크럼
09:20~12:00 마이크로서비스 구축 가이드 책 읽기
12:00~13:00 점심 식사
13:00~17:00 데일리 과제 문제 풀이
17:00~17:40 팀 코드 선정 회의
18:20~18:40 기술 매니저님과 팀 코드 리뷰
18:40~19:40 저녁 식사
19:40~20:20 산책
20:30~00:10 백준 문제 풀이
00:10~00:25 TIL 작성

오늘 목표

👉 데일리 과제 모두 풀기

👉 TIL 빠지지 않고 작성하기

👉 백준 골드4 달성하기

👉 북 스터디 참여

👉 인프런 마이크로서비스 강의 수강하기

오늘 한 것

  • 데일리 과제 모두 풀기
  • TIL 빠지지 않고 작성하기
  • 백준 골드4 달성하기
  • 북 스터디 참여

오늘 못한 것

  • 인프런 마이크로서비스 강의 수강하기 -> 이건 TIL 쓰고 듣고 잘 예정

알게된 것

⭐ ArrayDeque vs LinkedList

오늘 다른 팀원분의 코드가 실행 속도는 비슷했는데 메모리 관점에서 상당히 세이브하신 것이 인상적이여서
원인을 보니 차이점은 Queue 생성 시 ArrayDeque로 생성하신 것이였다.일반적으로는 LinkedList를 사용한다.
블로그 글을 보니 내가 궁금해 하던 점이 해결이 되었다.
ArrayDeque는 Queue의 서브인터페이스인 Deque의 구현체이고,
LinkedList는 List와 Queue의 구현체이다. 따라서 LinkedList는 List의 특징을 가지고 있고, ArrayDeque은 배열의 특성을 가지고 있다고 할 수 있다. 이것을 기억하고 아래의 차이점들을 살펴보자.

연산 성능
ArrayDeque을 배열의 측면에서 바라봤을 때, deque의 양끝에서 삽입/삭제 연산이 일어날 경우 시간 복잡도가 O(1)이므로 삽입/삭제 성능이 우수하다. 또한 Random access가 가능하기에 원소 조회 시에도 속도가 빠르다. LinkedList도 삽입/삭제 연산 성능이 좋지만, 특정 원소에 접근 시의 성능은 ArrayDeque에 비해 떨어진다. 또한 ArrayDeque는 LinkedList에 비해 cache-locality에 더 친숙하여 연산 속도가 더 빠르다.

메모리
ArrayDeque은 LinkedList와 달리 다음 노드에 대한 참조를 유지할 필요가 없기 때문에 더 적은 메모리를 사용한다. 이런 차이점 때문에 큐 구현 시 ArrayDeque가 LinkedList보다 속도와 메모리 측면에서 더 효율적이라고 할 수 있으며, 이는 자바 공식문서에도 언급되어있다.

출처:  https://velog.io/@newdana01/Java-%ED%81%90-%EA%B5%AC%ED%98%84%EC%8B%9C-ArrayDeque%EC%99%80-LinkedList-%EC%84%B1%EB%8A%A5-%EC%B0%A8%EC%9D%B4-Deque-Queue-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4

 

🤔오늘의 반성

- 오늘은 낮에 조금 집중하지 못한 것이 아쉬웠다.

 

👍 오늘의 칭찬

1. 지각하지 않았다.
2. 깃헙 1일 1커밋 달성
3. TIL을 빠지지 않고 작성했다.
4. 오늘의 데일리 과제 모두 풀었다.
5. 백준 골드4 달성(처음: 브론즈1)

❗ 항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.
https://hanghae99.spartacodingclub.kr/reboot

+ Recent posts