πŸ˜€
fistkim TECH BLOG
  • Intro
  • κ°•μ˜
    • Reactive Programming in Modern Java using Project Reactor
      • Reactor execution model 1
      • Reactor execution model 2
      • Reactor execution model 3 - parallelism
      • Reactor execution model 4 - overview
      • Transform
      • Combine
      • Side Effect Methods
      • Exception/Error handling
      • retry, retryWhen, repeat
      • BackPressure
      • Cold & Hot Streams
    • NEXTSTEP ν΄λ¦°μ½”λ“œ with java 9κΈ°
      • μ •λ¦¬λ…ΈνŠΈ
    • NEXTSTEP DDD μ„Έλ ˆλ‚˜λ° 2κΈ°
      • CH01 도메인 주도 섀계 이해
      • CH02 크게 μ†Œλ¦¬ λ‚΄μ–΄ λͺ¨λΈλ§ ν•˜κΈ°
      • CH03 도메인 주도 섀계 κΈ°λ³Έ μš”μ†Œ
      • CH04 도메인 주도 섀계 μ•„ν‚€ν…μ²˜
      • CH05 도메인 이벀트
    • NEXTSTEP 인프라 곡방 1κΈ°
      • 망 λΆ„λ¦¬ν•˜κΈ°
      • 톡신 ν™•μΈν•˜κΈ°
      • 도컀 μ»¨ν…Œμ΄λ„ˆ μ΄ν•΄ν•˜κΈ°
      • [λ―Έμ…˜ 1] μ„œλΉ„μŠ€ κ΅¬μ„±ν•˜κΈ° μ‹€μŠ΅
      • [λ―Έμ…˜ 2] μ„œλΉ„μŠ€ λ°°ν¬ν•˜κΈ° μ‹€μŠ΅
      • μ„œλ²„ μ§„λ‹¨ν•˜κΈ°
      • μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ§„λ‹¨ν•˜κΈ°
      • [λ―Έμ…˜ 3] μ„œλΉ„μŠ€ μš΄μ˜ν•˜κΈ°
      • μ›Ή μ„±λŠ₯ μ§„λ‹¨ν•˜κΈ°
      • λΆ€ν•˜ ν…ŒμŠ€νŠΈ
      • k6
      • [λ―Έμ…˜ 4] μ„±λŠ₯ ν…ŒμŠ€νŠΈ
      • λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ κ°œμ„ ν•˜κΈ°
      • 캐싱 ν™œμš©ν•˜κΈ°
      • [λ―Έμ…˜ 5] ν™”λ©΄ 응닡 κ°œμ„ ν•˜κΈ°
      • Redis Annotation 및 μ„€μ •
      • 인덱슀 μ΄ν•΄ν•˜κΈ° & DB νŠœλ‹
      • [λ―Έμ…˜ 6-1] 쑰회 μ„±λŠ₯ κ°œμ„ ν•˜κΈ°
      • [λ―Έμ…˜ 6-2] DB 이쀑화 적용
    • NEXTSTEP λ§Œλ“€λ©΄μ„œ λ°°μš°λŠ” Spring 3κΈ°
      • CH01 μ˜¬λ°”λ₯Έ λ°©ν–₯ 바라보기
      • CH02 HTTP 이해 - μ›Ή μ„œλ²„ κ΅¬ν˜„
        • HTTP νŒŒμ‹±
        • HTTP μ›Ή μ„œλ²„ κ΅¬ν˜„
      • CH03 MVC - @MVC ν”„λ ˆμž„μ›Œν¬ κ΅¬ν˜„
        • Servlet λ‹€μ‹œ 짚기
        • Cookie, Session λ‹€μ‹œ 짚기
        • MVC ν”„λ ˆμž„μ›Œν¬ κ΅¬ν˜„
      • CH04 λ‚˜λ§Œμ˜ 라이브러리 κ΅¬ν˜„
      • CH05 DI - DI ν”„λ ˆμž„μ›Œν¬ κ΅¬ν˜„
      • CH06 Aspect OP
    • μŠ€ν”„λ§ μ‹œνλ¦¬ν‹°
      • μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° μ•„ν‚€ν…μ²˜
      • WebAsyncManagerIntegrationFilter
      • SecurityContextPersistenceFilter
      • HeaderWriterFilter
      • CsrfFilter
      • (+) μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° + JWT
      • (+) 마치며
    • 더 μžλ°”, μ½”λ“œλ₯Ό μ‘°μž‘ν•˜λŠ” λ‹€μ–‘ν•œ 방법
      • CH01 JVM μ΄ν•΄ν•˜κΈ°
      • (+) 클래슀 λ‘œλ” μ΄ν•΄ν•˜κΈ°
      • CH02 λ°”μ΄νŠΈ μ½”λ“œ 뢄석 및 μ‘°μž‘
      • (+) jacoco
      • CH03 λ¦¬ν”Œλ ‰μ…˜
      • CH04 λ‹€μ΄λ‚˜λ―Ή ν”„λ‘μ‹œ
      • CH05 μ• λ…Έν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ
    • 더 μžλ°”, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ ν…ŒμŠ€νŠΈν•˜λŠ” λ‹€μ–‘ν•œ 방법
      • CH01 JUnit 5
      • CH02 Mockito
      • (+) Spy vs Mock
      • CH03 도컀와 ν…ŒμŠ€νŠΈ
      • CH04 μ„±λŠ₯ ν…ŒμŠ€νŠΈ
      • (+) VisualVM
      • (+) ν…ŒμŠ€νŠΈ μžλ™ν™”
      • CH05 운영 이슈 ν…ŒμŠ€νŠΈ
      • CH06 μ•„ν‚€ν…μ²˜ ν…ŒμŠ€νŠΈ
    • λͺ¨λ“  개발자λ₯Ό μœ„ν•œ HTTP μ›Ή κΈ°λ³Έ 지식
      • CH01 인터넷 λ„€νŠΈμ›Œν¬
      • CH02 HTTP κΈ°λ³Έ
      • CH03 HTTP λ©”μ„œλ“œ 속성
      • CH04 HTTP λ©”μ„œλ“œ ν™œμš©
      • CH05 HTTP μƒνƒœμ½”λ“œ
      • CH06 HTTP 헀더1 - 일반 헀더
      • CH07 HTTP 헀더2 - μΊμ‹œμ™€ 쑰건뢀 μš”μ²­
      • (+) HTTPS 원리
    • μŠ€ν”„λ§ ν”„λ ˆμž„μ›Œν¬ 핡심 기술
      • CH01 IOC μ»¨ν…Œμ΄λ„ˆ
      • CH02 AOP
      • (+) μŠ€ν”„λ§ μ˜μ‘΄μ„± 관리
      • (+) μƒμ„±μž μ£Όμž… μž₯점
    • μ½”λ”©μœΌλ‘œ ν•™μŠ΅ν•˜λŠ” GoF의 λ””μžμΈ νŒ¨ν„΄
      • 객체 생성
        • 싱글톀 νŒ¨ν„΄
        • νŒ©ν† λ¦¬ λ©”μ†Œλ“œ νŒ¨ν„΄
        • 좔상 νŒ©ν† λ¦¬ νŒ¨ν„΄
        • λΉŒλ” νŒ¨ν„΄
        • ν”„λ‘œν† νƒ€μž… νŒ¨ν„΄
      • ꡬ쑰
        • μ–΄λŒ‘ν„° νŒ¨ν„΄
        • λΈŒλ¦Ώμ§€ νŒ¨ν„΄
        • 컴포짓 νŒ¨ν„΄
      • 행동
        • (μž‘μ„±μ€‘)
    • μ‹€μ „ Querydsl
      • CH01 ν”„λ‘œμ νŠΈ ν™˜κ²½κ΅¬μ„±
      • CH02 예제 도메인 λͺ¨λΈ
      • CH03 기본문법
      • CH04 쀑급 문법
      • CH05 μ‹€λ¬΄ν™œμš© (μŠ€ν”„λ§ 데이터 JPA와 Querydsl)
      • CH06 μŠ€ν”„λ§λ°μ΄ν„°JPA κ°€ μ œκ³΅ν•˜λŠ” Querydsl κΈ°λŠ₯
      • (+) 별칭(alias)
      • (+) Slice 쿼리
    • μŠ€ν”„λ§ 데이터 JPA
      • CH01 ν•΅μ‹¬κ°œλ…μ΄ν•΄ 1
      • CH02 ν•΅μ‹¬κ°œλ…μ΄ν•΄ 2
      • CH03 ν•΅μ‹¬κ°œλ…μ΄ν•΄ 3
      • CH04 Spring Data Common
      • CH05 Spring Data JPA
    • μ‹€μ „! μŠ€ν”„λ§ λΆ€νŠΈμ™€ JPA ν™œμš©2 - API 개발과 μ„±λŠ₯ μ΅œμ ν™”
      • CH01 μ§€μ—° λ‘œλ”©κ³Ό 쑰회 μ„±λŠ₯ μ΅œμ ν™”
      • CH02 μ»¬λ ‰μ…˜ 쑰회 μ΅œμ ν™”
      • CH03 전체 정리
    • 초보λ₯Ό μœ„ν•œ μΏ λ²„λ„€ν‹°μŠ€ μ•ˆλ‚΄μ„œ
      • CH01 μΏ λ²„λ„€ν‹°μŠ€ μ‹œμž‘ν•˜κΈ°
      • CH02 μΏ λ²„λ„€ν‹°μŠ€ μ•Œμ•„λ³΄κΈ°
      • CH03 μΏ λ²„λ„€ν‹°μŠ€ μ‹€μŠ΅ μ€€λΉ„
      • CH04 μΏ λ²„λ„€ν‹°μŠ€ κΈ°λ³Έ μ‹€μŠ΅
    • Flutter Provider Essential
      • CH01 Introduction
      • CH02 Provider Overview
      • CH03 TODO App
      • CH04 Weather App
      • CH05 Firebase Authentication App
    • Flutter Bloc Essential
      • CH01 Introduction
      • CH02 Bloc Overview
      • CH03 TODO App
      • CH04 Weather App
      • CH05 Firebase Authentication App
    • Flutter Advanced Course - Clean Architecture With MVVM
      • CH01 Introduction
      • CH02 Clean Architecture 4 Layer
      • CH03 MVVM
      • CH04 Data Layer
      • (+) Data Layer - response to model
      • (+) Data Layer - Network
      • CH05 Domain Layer
      • CH06 Presentation Layer
      • CH07 Application Layer
      • (+) Application Layer - l10n
      • (+) Application Layer - DI
      • (+) Application Layer - environment
    • μžλ°” μ•Œκ³ λ¦¬μ¦˜ μž…λ¬Έ
      • CH01 λ¬Έμžμ—΄
      • CH02 Array(1, 2 차원 λ°°μ—΄)
      • CH03 Two pointers, Sliding window[νš¨μœ¨μ„±: O(n^2)-->O(n)]
      • CH04 HashMap, TreeSet (해쉬, 정렬지원 Set)
      • CH05 Stack, Queue(자료ꡬ쑰)
      • CH06 Sorting and Searching(μ •λ ¬, 이뢄검색과 κ²°μ •μ•Œκ³ λ¦¬μ¦˜)
      • CH07 Recursive, Tree, Graph(DFS, BFS 기초)
      • CH08 DFS, BFS ν™œμš©
      • CH09 Greedy Algorithm
      • CH10 dynamic programming(λ™μ κ³„νšλ²•)
  • λ„μ„œ
    • λ§Œλ“€λ©΄μ„œ λ°°μš°λŠ” 클린 μ•„ν‚€ν…μ²˜
      • ν•™μŠ΅λͺ©ν‘œ
      • CH01 κ³„μΈ΅ν˜• μ•„ν‚€ν…μ²˜μ˜ λ¬Έμ œλŠ” λ¬΄μ—‡μΌκΉŒ?
      • CH02 μ˜μ‘΄μ„± μ—­μ „ν•˜κΈ°
      • CH03 μ½”λ“œ κ΅¬μ„±ν•˜κΈ°
      • CH04 μœ μŠ€μΌ€μ΄μŠ€ κ΅¬ν˜„ν•˜κΈ°
      • CH05 μ›Ή μ–΄λŒ‘ν„° κ΅¬ν˜„ν•˜κΈ°
      • CH06 μ˜μ†μ„± μ–΄λŒ‘ν„° κ΅¬ν˜„ν•˜κΈ°
      • CH07 μ•„ν‚€ν…μ²˜ μš”μ†Œ ν…ŒμŠ€νŠΈν•˜κΈ°
      • CH08 경계 κ°„ λ§€ν•‘ν•˜κΈ°
      • CH09 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ‘°λ¦½ν•˜κΈ°
      • CH10 μ•„ν‚€ν…μ²˜ 경계 κ°•μ œν•˜κΈ°
      • CH11 μ˜μ‹μ μœΌλ‘œ 지름길 μ‚¬μš©ν•˜κΈ°
      • CH12 μ•„ν‚€ν…μ²˜ μŠ€νƒ€μΌ κ²°μ •ν•˜κΈ°
    • 클린 μ•„ν‚€ν…μ²˜
      • λ“€μ–΄κ°€λ©°
      • 1λΆ€ μ†Œκ°œ
        • 1μž₯ 섀계와 μ•„ν‚€ν…μ²˜λž€?
        • 2μž₯ 두 κ°€μ§€ κ°€μΉ˜μ— λŒ€ν•œ 이야기
      • 2λΆ€ λ²½λŒλΆ€ν„° μ‹œμž‘ν•˜κΈ°: ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„
        • 3μž₯ νŒ¨λŸ¬λ‹€μž„ κ°œμš”
        • 4μž₯ ꡬ쑰적 ν”„λ‘œκ·Έλž˜λ°
        • 5μž₯ 객체 μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°
        • 6μž₯ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°
      • 3λΆ€ 섀계 원칙
        • 7μž₯ SRP: 단일 μ±…μž„ 원칙
        • 8μž₯ OCP: 개방-폐쇄 원칙
        • 9μž₯ LSP: λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙
        • 10μž₯ ISP: μΈν„°νŽ˜μ΄μŠ€ 뢄리 원칙
        • 11μž₯ DIP: μ˜μ‘΄μ„± μ—­μ „ 원칙
      • 4λΆ€ μ»΄ν¬λ„ŒνŠΈ 원칙
        • 12μž₯ μ»΄ν¬λ„ŒνŠΈ
        • 13μž₯ μ»΄ν¬λ„ŒνŠΈ 응집도
        • 14μž₯ μ»΄ν¬λ„ŒνŠΈ κ²°ν•©
      • 5λΆ€
        • 15μž₯ μ•„ν‚€ν…μ²˜λž€?
    • μŠ€ν”„λ§ μž…λ¬Έμ„ μœ„ν•œ μžλ°” 객체 μ§€ν–₯의 원리와 이해
      • CH01 μ‚¬λžŒμ„ μ‚¬λž‘ν•œ 기술
      • CH02 μžλ°”μ™€ 절차적/ꡬ쑰적 ν”„λ‘œκ·Έλž˜λ°
      • CH03 μžλ°”μ™€ 객체 μ§€ν–₯
      • (+) μžλ°” μ½”λ“œ 싀행에 λ”°λ₯Έ λ©”λͺ¨λ¦¬ μ μž¬κ³Όμ •
      • CH04 μžλ°”κ°€ ν™•μž₯ν•œ 객체 μ§€ν–₯
      • CH05 객체 μ§€ν–₯ 섀계 5 원칙 - SOLID
      • CH06 μŠ€ν”„λ§μ΄ μ‚¬λž‘ν•œ λ””μžμΈ νŒ¨ν„΄
      • CH07 μŠ€ν”„λ§ μ‚Όκ°ν˜•κ³Ό μ„€μ • 정보
      • (뢀둝) λžŒλ‹€(lambda)
    • 객체지ν–₯의 사싀과 μ˜€ν•΄
      • CH01 ν˜‘λ ₯ν•˜λŠ” κ°μ²΄λ“€μ˜ 곡동체
      • CH02 μ΄μƒν•œ λ‚˜λΌμ˜ 객체
      • CH03 νƒ€μž…κ³Ό 좔상화
      • CH04 μ—­ν• , μ±…μž„, ν˜‘λ ₯
      • CH05 μ±…μž„κ³Ό λ©”μ‹œμ§€
      • CH06 객체 지도
      • CH07 ν•¨κ»˜ λͺ¨μœΌκΈ°
      • (+) μΈν„°νŽ˜μ΄μŠ€ κ°œλ… λ°”λ‘œμž‘κΈ°
    • 도메인 주도 개발 μ‹œμž‘ν•˜κΈ°
      • CH01 도메인 λͺ¨λΈ μ‹œμž‘ν•˜κΈ°
      • CH02 μ•„ν‚€ν…μ²˜ κ°œμš”
      • CH03 μ• κ·Έλ¦¬κ±°νŠΈ
      • CH04 리포지터리와 λͺ¨λΈ κ΅¬ν˜„
      • CH05 μŠ€ν”„λ§ 데이터 JPAλ₯Ό μ΄μš©ν•œ 쑰회 κΈ°λŠ₯
      • CH06 μ‘μš© μ„œλΉ„μŠ€μ™€ ν‘œν˜„ μ˜μ—­
      • CH07 도메인 μ„œλΉ„μŠ€
      • CH08 μ• κ·Έλ¦¬κ±°νŠΈ νŠΈλžœμž­μ…˜ 관리
      • CH09 도메인 λͺ¨λΈκ³Ό λ°”μš΄λ””λ“œ μ»¨ν…μŠ€νŠΈ
      • CH10 이벀트
      • CH11 CQRS
    • μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ°
      • CH01 JPA μ†Œκ°œ
      • CH02 JPA μ‹œμž‘
      • CH03 μ˜μ†μ„± 관리
      • CH04 μ—”ν‹°ν‹° λ§€ν•‘
      • CH05 연관관계 λ§€ν•‘ 기초
      • CH06 λ‹€μ–‘ν•œ 연관관계 λ§€ν•‘
      • CH07 κ³ κΈ‰ λ§€ν•‘
      • CH08 ν”„λ‘μ‹œμ™€ 연관관계 관리
      • CH09 κ°’ νƒ€μž…
      • CH10 객체지ν–₯ 쿼리 μ–Έμ–΄
      • CH11 μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ œμž‘
      • CH12 μŠ€ν”„λ§ 데이터 JPA
      • CH13 μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό μ˜μ†μ„± 관리
      • CH14 μ»¬λ ‰μ…˜κ³Ό λΆ€κ°€ κΈ°λŠ₯
      • CH15 κ³ κΈ‰ μ£Όμ œμ™€ μ„±λŠ₯ μ΅œμ ν™”
      • CH16 νŠΈλžœμž­μ…˜κ³Ό 락, 2μ°¨ μΊμ‹œ
    • μ†Œν”„νŠΈμ›¨μ–΄ 세상을 μ—¬λŠ” 컴퓨터과학
      • CH01 컴퓨터 κ³Όν•™ μ†Œκ°œ
      • CH02 데이터 ν‘œν˜„κ³Ό λ””μ§€ν„Έ 논리
    • μ΄νŽ™ν‹°λΈŒ μžλ°”
      • 1 μž₯ λ“€μ–΄κ°€κΈ°
      • 2μž₯ 객체 생성과 파괴
        • [01] μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό κ³ λ €ν•˜λΌ
        • [02] μƒμ„±μžμ— λ§€κ°œλ³€μˆ˜κ°€ λ§Žλ‹€λ©΄ λΉŒλ”λ₯Ό κ³ λ €ν•˜λΌ
        • [03] private μƒμ„±μžλ‚˜ μ—΄κ±° νƒ€μž…μœΌλ‘œ μ‹±κΈ€ν„΄μž„μ„ λ³΄μ¦ν•˜λΌ
        • [04] μΈμŠ€ν„΄μŠ€ν™”λ₯Ό λ§‰μœΌλ €κ±°λ“  private μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜λΌ
        • [05] μžμ›μ„ 직접 λͺ…μ‹œν•˜μ§€ 말고 의쑴 객체 μ£Όμž…μ„ μ‚¬μš©ν•˜λΌ
        • [06] λΆˆν•„μš”ν•œ 객체 생성을 ν”Όν•˜λΌ
        • [07] λ‹€ μ“΄ 객체 μ°Έμ‘°λ₯Ό ν•΄μ œν•˜λΌ
        • [08] finalizer 와 cleaner μ‚¬μš©μ„ ν”Όν•˜λΌ
        • [09] try-finally λ³΄λ‹€λŠ” try-with-resources λ₯Ό μ‚¬μš©ν•˜λΌ
      • 3μž₯ λͺ¨λ“  객체의 곡톡 λ©”μ„œλ“œ
        • [10] equalsλŠ” 일반 κ·œμ•½μ„ μ§€μΌœ μž¬μ •μ˜ν•˜λΌ
        • [11] equals λ₯Ό μž¬μ •μ˜ν•˜λ €κ±°λ“  hashCode도 μž¬μ •μ˜ν•˜λΌ
        • [12] toString 을 항상 μž¬μ •μ˜ν•˜λΌ
        • [13] clone μž¬μ •μ˜λŠ” μ£Όμ˜ν•΄μ„œ μ§„ν–‰ν•˜λΌ
        • [14] Comparable 을 κ΅¬ν˜„ν• μ§€ κ³ λ €ν•˜λΌ
      • 4μž₯ ν΄λž˜μŠ€μ™€ μΈν„°νŽ˜μ΄μŠ€
        • [15] ν΄λž˜μŠ€μ™€ λ©€λ²„μ˜ μ ‘κ·Ό κΆŒν•œμ„ μ΅œμ†Œν™”ν•˜λΌ
  • ν† ν”½
    • μ„œλ²„ λͺ¨λ‹ˆν„°λ§
      • CPU μ‚¬μš©λŸ‰
      • λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰
      • μŠ€λ ˆλ“œ ν’€
    • Spring Boot Monitoring
      • Spring actuator
      • Spring eureka
      • Prometheus
      • grafana
      • Spring actuator + Prometheus + grafana
    • JAVA 데일리 ν† ν”½
      • λ©”λͺ¨λ¦¬ λˆ„μˆ˜(memory leak)
      • 객체 참쑰의 μœ ν˜•
      • μ»€μŠ€ν…€ μŠ€λ ˆλ“œ ν’€
      • Mark And Compact
      • serialVersionUID μ΄ν•΄ν•˜κΈ°
      • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
      • λ©”μ†Œλ“œ μ°Έμ‘°
      • equals()와 hashCode()κ°€ 무엇이고 역할이 무엇인지
      • StringBuffer vs StringBuilder
      • String vs StringBuilder, StringBuffer
      • String interning
    • JAVA GC
    • ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ 문제 ν’€κΈ°
      • ν•΄μ‹œ
      • μŠ€νƒ/큐
      • νž™(Heap)
      • μ •λ ¬
      • 완전탐색
      • DFS/BFS
    • λ°μ΄ν„°λ² μ΄μŠ€ ꡬ성 및 μž‘λ™ 흐름
    • λ°μ΄ν„°λ² μ΄μŠ€ JOIN 원리
    • 객체지ν–₯μƒν™œμ²΄μ‘° 원칙
    • μƒνƒœ(state), 상속(inheritance), ν•©μ„±(composition) 의 상관관계
    • java enum은 λ©”λͺ¨λ¦¬μ— μ–Έμ œ, μ–΄λ–»κ²Œ ν• λ‹Ήλ˜λŠ”κ°€
    • Checked Exception vs UnChecked Exception
    • Reactive Streams 원리탐ꡬ - κ°„λ‹¨ν•œ 예제 직접 μž‘μ„±ν•΄λ³΄κΈ°
    • Flutter Basic
    • Flutter StatefulWidget 생λͺ…μ£ΌκΈ°
    • Flutter κ°€ μœ„μ ―μ„ κ·Έλ¦¬λŠ” 원리
    • Flutter 클린 μ•„ν‚€ν…μ²˜
      • application layer
        • νŒ¨ν‚€μ§€ ꡬ쑰 및 λ ˆμ΄μ–΄ μ„€λͺ…
        • environment
        • dependency injection
        • go_router
        • foreground & background
        • λ‹€κ΅­μ–΄μ²˜λ¦¬ (l10n, i18n)
        • Global 처리(μ‹œμŠ€ν…œ 점검, fore->back λ“±)
        • connection_manager
        • permission_manager
        • push_notification_manager
        • firebase 연동
      • data layer
        • νŒ¨ν‚€μ§€ ꡬ쑰 및 λ ˆμ΄μ–΄ μ„€λͺ…
        • network
        • repository
      • domain layer
        • νŒ¨ν‚€μ§€ ꡬ쑰 및 λ ˆμ΄μ–΄ μ„€λͺ…
      • presentation layer
        • νŒ¨ν‚€μ§€ ꡬ쑰 및 λ ˆμ΄μ–΄ μ„€λͺ…
        • resources
    • 기술 κ΄€λ ¨ ν¬μŠ€νŒ… 읽기
  • 기타
    • μž‘μ—…μΌμ§€
      • 2023. 10
      • 2023. 09
      • 2023. 08
      • 2023. 07
      • 2023. 06
      • 2023. 05
      • 2023. 04
      • 2023. 03
      • 2023. 02
      • 2023. 01
      • 2022. 12
    • Business Model
      • 아이디어 뢈패의 법칙
      • λ¦° λͺ¨λ°”일 μ•± 개발
      • λ¦° μŠ€νƒ€νŠΈμ—…
      • μ œλ‘œνˆ¬μ›
      • MIT μŠ€νƒ€νŠΈμ—… 바이블
      • λ¦°μΉ˜ν•€
    • 백둜그 μ’…ν•©
Powered by GitBook
On this page
  • State λ₯Ό λ‹€λ£°λ•Œ immutable state 을 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 이유 (+ Equatable 원리)
  • Object.dart 의 == κ³Ό hashCode
  • Equatable μ—μ„œλŠ” == κ³Ό hashCode λ₯Ό override ν•œλ‹€
  1. κ°•μ˜
  2. Flutter Provider Essential

CH03 TODO App

PreviousCH02 Provider OverviewNextCH04 Weather App

Last updated 1 year ago

  • TODO App 을 μœ„ μŠ¬λΌμ΄λ“œμ— λ‚˜μ˜¨ μ„Έ κ°€μ§€ λ°©μ‹μœΌλ‘œ 각각 총 μ„Έ 번 κ΅¬ν˜„ν•œλ‹€.

  • ν•˜λ‚˜μ˜ 폴더 내에 μ„Έ 앱을 각각 λ§Œλ“€κ³ , μ†ŒμŠ€λŠ” 폴더 μ΅œμƒλ‹¨μ—μ„œ git init ν•΄μ„œ 관리해야겠닀.

  • Independent State 의 μ˜ˆμ‹œλ‘œλŠ” TODO Item 의 β€˜μ™„λ£Œμ—¬λΆ€β€™ λ₯Ό λ“€ 수 μžˆλ‹€.

    • λΆˆλ³€ν•˜λŠ” 값이 μ•„λ‹ˆκ³  μ™„λ£Œκ°€ 될 경우 값이 λ³€ν•˜λŠ” μ„±μ§ˆμ΄ 있고, 이 λ³€κ²½μ˜ 여뢀에 따라 Widget 의 rebuild κ°€ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— ChangeNotifierProvider λ₯Ό μ‚¬μš©ν•΄μ•Όν•œλ‹€.

  • Computed State λŠ” λ‹€λ₯Έ 것(것듀) 에 의쑴된 Computed 된 값이닀. μ˜ˆμ‹œλ‘œλŠ” β€˜λ―Έμ™„λ£Œ Item μˆ˜β€™ λ₯Ό λ“€ 수 μžˆλ‹€.

import 'package:flutter/material.dart';
import 'package:flutter_state_notifier/flutter_state_notifier.dart';
import 'package:provider/provider.dart';

import 'providers/providers.dart';
import 'screens/screens.dart';

void main() {
  runApp(const TodoApp());
}

class TodoApp extends StatelessWidget {
  const TodoApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        StateNotifierProvider<SearchTerm, SearchTermState>(
          create: (_) => SearchTerm(),
        ),
        StateNotifierProvider<Filter, FilterState>(
          create: (_) => Filter(),
        ),
        StateNotifierProvider<Todos, TodosState>(
          create: (_) => Todos(),
        ),
        StateNotifierProvider<ActiveTodoCount, ActiveTodoCountState>(
          create: (_) => ActiveTodoCount(),
        ),
        StateNotifierProvider<FilteredTodos, FilteredTodosState>(
          create: (_) => FilteredTodos(),
        ),
        // ChangeNotifierProvider(
        //   create: (_) => SearchTerm(),
        // ),
        // ChangeNotifierProvider(
        //   create: (_) => Filter(initialFilterType: FilterType.all),
        // ),
        // ChangeNotifierProvider(
        //   create: (_) => Todos(initialTodos: []),
        // ),
        // ProxyProvider<Todos, ActiveTodoCount>(
        //   update: (
        //     _,
        //     Todos todos,
        //     __,
        //   ) =>
        //       ActiveTodoCount(todos: todos),
        // ),
        // ProxyProvider3<Todos, Filter, SearchTerm, FilteredTodos>(
        //   update: (
        //     _,
        //     Todos todos,
        //     Filter filter,
        //     SearchTerm searchTerm,
        //     __,
        //   ) =>
        //       FilteredTodos(
        //           todos: todos, filter: filter, searchTerm: searchTerm),
        // )
      ],
      child: const MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Home(),
      ),
    );
  }
}
import 'package:equatable/equatable.dart';
import 'package:flutter_state_notifier/flutter_state_notifier.dart';

class SearchTermState extends Equatable {
  final String? searchTerm;

  const SearchTermState({
    required this.searchTerm,
  });

  @override
  bool get stringify => true;

  @override
  List<Object> get props => [searchTerm ?? ''];

  SearchTermState copyWith(String searchTerm) {
    return SearchTermState(searchTerm: searchTerm);
  }
}

class SearchTerm extends StateNotifier<SearchTermState> {
  SearchTerm() : super(const SearchTermState(searchTerm: ''));

  void searchTermChange(String searchTerm) {
    state = SearchTermState(searchTerm: searchTerm);
  }
}

// class SearchTerm with ChangeNotifier {
//   late SearchTermState _state;
//   final String? initialSearchTerm;
//
//   SearchTermState get state => _state;
//
//   SearchTerm({
//     this.initialSearchTerm,
//   }) {
//     _state = SearchTermState(searchTerm: initialSearchTerm);
//   }
//
//   void update(String searchTerm) {
//     _state = _state.copyWith(searchTerm);
//     notifyListeners();
//   }
// }
import 'package:equatable/equatable.dart';
import 'package:state_notifier/state_notifier.dart';

import '../models/model.dart';
import '../providers/providers.dart';

class ActiveTodoCountState extends Equatable {
  final int activeTodoCount;

  const ActiveTodoCountState({
    required this.activeTodoCount,
  });

  @override
  List<Object> get props {
    return [activeTodoCount];
  }

  @override
  bool get stringify => true;

  ActiveTodoCountState copyWith(int activeTodoCount) {
    return ActiveTodoCountState(activeTodoCount: activeTodoCount);
  }
}

class ActiveTodoCount extends StateNotifier<ActiveTodoCountState>
    with LocatorMixin {
  ActiveTodoCount() : super(const ActiveTodoCountState(activeTodoCount: 0));

  @override
  void update(Locator watch) {
    final List<Todo> todos = watch<TodosState>().todos;
    final int newActiveTodoCount =
        todos.where((todo) => !todo.isCompleted).toList().length;
    state = ActiveTodoCountState(activeTodoCount: newActiveTodoCount);

    super.update(watch);
  }
}

// class ActiveTodoCount {
//   final Todos todos;
//
//   ActiveTodoCount({
//     required this.todos,
//   });
//
//   ActiveTodoCountState get state {
//     final int newActiveTodoCount =
//         todos.state.todos.where((todo) => !todo.isCompleted).toList().length;
//
//     return ActiveTodoCountState(activeTodoCount: newActiveTodoCount);
//   }
// }

State λ₯Ό λ‹€λ£°λ•Œ immutable state 을 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 이유 (+ Equatable 원리)

Todo app μ‹€μŠ΅ 쀑 todo λ₯Ό μ‚­μ œν•˜λŠ” κ³Όμ •μ—μ„œ rebuild κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ” ν˜„μƒμ΄ λ°œμƒν–ˆλ‹€. κ·Έλž˜μ„œ κ°•μ‚¬λ‹˜ μ½”λ“œλ₯Ό 보고 μˆ˜μ •ν–ˆλ”λ‹ˆ rebuild κ°€ 잘 μž‘λ™ν–ˆλ‹€. 덕뢄에 κΈ°κ³„μ μœΌλ‘œ μ‚¬μš©ν–ˆλ˜ Equatable 을 λ‹€μ‹œ μ‚΄νŽ΄λ΄€κ³ , Notifier 의 state 비ꡐ λ‘œμ§λ„ λ‹€μ‹œ μ‚΄νŽ΄λ³΄μ•˜λ‹€.

Object.dart 의 == 과 hashCode

dart 의 λͺ¨λ“  객체듀은 Object λ₯Ό μƒμ†ν•˜κ³  있으며, Object 의 == 은 μ•„λž˜μ™€ κ°™λ‹€.

  /// The equality operator.
  ///
  /// The default behavior for all [Object]s is to return true if and
  /// only if this object and [other] are the same object.
  ///
  /// Override this method to specify a different equality relation on
  /// a class. The overriding method must still be an equivalence relation.
  /// That is, it must be:
  ///
  ///  * Total: It must return a boolean for all arguments. It should never throw.
  ///
  ///  * Reflexive: For all objects `o`, `o == o` must be true.
  ///
  ///  * Symmetric: For all objects `o1` and `o2`, `o1 == o2` and `o2 == o1` must
  ///    either both be true, or both be false.
  ///
  ///  * Transitive: For all objects `o1`, `o2`, and `o3`, if `o1 == o2` and
  ///    `o2 == o3` are true, then `o1 == o3` must be true.
  ///
  /// The method should also be consistent over time,
  /// so whether two objects are equal should only change
  /// if at least one of the objects was modified.
  ///
  /// If a subclass overrides the equality operator, it should override
  /// the [hashCode] method as well to maintain consistency.
  external bool operator ==(Object other);

The default behavior for all [Object]s is to return true if and only if this object and [other] are the same object. 핡심은 이 문ꡬ닀. μ£Όμ†Œκ°’μ΄ κ°™μ•„μ•Ό Object 의 == λŠ” true λ₯Ό return ν•œλ‹€.

μ’…ν•©ν•΄μ„œ 보면 dart μ—μ„œ νŠΉλ³„νžˆ == 을 override ν•˜μ§€ μ•ŠλŠ” 이상, μ£Όμ†Œκ°’μ΄ κ°™μ•„μ•Όλ§Œ == μ—μ„œ true λ₯Ό 받을 수 있고 κ·Έ μ™Έμ—λŠ” λͺ¨λ‘ false 이닀.

또 == κ³Ό λ°€μ ‘ν•œ 연관이 μžˆλŠ”(== 에 영ν–₯을 μ£ΌλŠ”) hashCode λ₯Ό μ‚΄νŽ΄λ³΄μž.

  /// The hash code for this object.
  ///
  /// A hash code is a single integer which represents the state of the object
  /// that affects [operator ==] comparisons.
  ///
  /// All objects have hash codes.
  /// The default hash code implemented by [Object]
  /// represents only the identity of the object,
  /// the same way as the default [operator ==] implementation only considers objects
  /// equal if they are identical (see [identityHashCode]).
  ///
  /// If [operator ==] is overridden to use the object state instead,
  /// the hash code must also be changed to represent that state,
  /// otherwise the object cannot be used in hash based data structures
  /// like the default [Set] and [Map] implementations.
  ///
  /// Hash codes must be the same for objects that are equal to each other
  /// according to [operator ==].
  /// The hash code of an object should only change if the object changes
  /// in a way that affects equality.
  /// There are no further requirements for the hash codes.
  /// They need not be consistent between executions of the same program
  /// and there are no distribution guarantees.
  ///
  /// Objects that are not equal are allowed to have the same hash code.
  /// It is even technically allowed that all instances have the same hash code,
  /// but if clashes happen too often,
  /// it may reduce the efficiency of hash-based data structures
  /// like [HashSet] or [HashMap].
  ///
  /// If a subclass overrides [hashCode], it should override the
  /// [operator ==] operator as well to maintain consistency.
  external int get hashCode;

If a subclass overrides [hashCode], it should override the [operator ==] operator as well to maintain consistency. λΌλŠ” 것을 보면 == λ₯Ό override ν•  경우 λ°˜λ“œμ‹œ hashCode 도 override ν•΄μ€˜μ•Ό ν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

Equatable μ—μ„œλŠ” == κ³Ό hashCode λ₯Ό override ν•œλ‹€

μ•„λž˜λŠ” Equatable 내에 μžˆλŠ” == 와 hashCode 이닀. 이λ₯Ό 보면 Equatable λ₯Ό 상속할 경우 Object 의 ==, hashCode λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , μ•„λž˜μ˜ Equatable 의 ==, hashCode λ₯Ό μ‚¬μš©ν•˜κ²Œ λœλ‹€λŠ” 것을 μ•Œ 수 μžˆλ‹€.

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Equatable &&
          runtimeType == other.runtimeType &&
          equals(props, other.props);

  @override
  int get hashCode => runtimeType.hashCode ^ mapPropsToHashCode(props);

이λ₯Ό λ°”νƒ•μœΌλ‘œ Equatable 을 μƒμ†ν•˜κ³  μžˆλŠ” TodosState 을 μ‚΄νŽ΄λ³΄μž.

    Todo todo1 = Todo(id: '1', description: 'test');
    Todo todo2 = Todo(id: '2', description: 'test');
    List<Todo> todos1 = [todo1, todo2];
    List<Todo> todos2 = [todo1, todo2];
    print(todos1.hashCode); // 807548389
    print(todos2.hashCode); // 639492342

    TodosState todosState1 = TodosState(todos: todos1);
    TodosState todosState2 = TodosState(todos: todos2);
    print(todosState1.hashCode); // 556324449
    print(todosState2.hashCode); // 556324449
    print(todosState1 == todosState2); // true

μœ„μ™€ 같이 todos μžμ²΄λŠ” λ‹€λ₯Έ μ£Όμ†Œκ°’μ„ κ°€μ§€κ³  μžˆμ–΄λ„ ν•΄λ‹Ή todos 의 ꡬ성이 todo1, todo2둜 같기에 todosState1, todosState2 의 hashCode λŠ” 같은 값을 return ν•˜κ³  비ꡐ μ—­μ‹œ true κ°€ return λœλ‹€.

μ΄λ²ˆμ—” μ›μ†Œμ˜ ꡬ성에 λ³€ν™”λ₯Ό 쀘보자.

    Todo todo1 = Todo(id: '1', description: 'test');
    Todo todo2 = Todo(id: '2', description: 'test');
    List<Todo> todos = [todo1, todo2];

    print(todos.length); // 2
    print(todos.hashCode); // 960134229
    TodosState todosState1 = TodosState(todos: todos);
    print(todosState1.hashCode); // 592161286

    todos.removeWhere((element) => element.id == '1');
    print(todos.length); // 1
    print(todos.hashCode); // 960134229
    TodosState todosState2 = TodosState(todos: todos);
    print(todosState1.hashCode); // 680645052
    print(todosState2.hashCode); // 680645052

    print(todosState1 == todosState2); // true

κ²°κ΅­ μ΅œμ’…μ μœΌλ‘œ todosState1, todosState2 각각의 μ›μ†ŒλŠ” todos λΌλŠ” λ˜‘κ°™μ€ μΈμŠ€ν„΄μŠ€λ‹€. κ·Έλž˜μ„œ todos κ°€ μ–΄λ–»κ²Œ λ³€ν•˜λ“ μ§€κ°„μ— ν•΄λ‹Ή μ£Όμ†Œκ°’μ€ λ™μΌν•˜λ‹€. κ·Έλž˜μ„œ todosState1, todosState2 λŠ” λͺ¨λ‘ λ˜‘κ°™μ€ todos λΌλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό μ›μ†Œλ‘œ κ°–κ³  μžˆμœΌλ―€λ‘œ 항상 같을 수 밖에 μ—†λ‹€.

λ‚΄κ°€ λ²”ν•œ μ‹€μˆ˜λŠ” 이 ν¬μΈνŠΈμ—μ„œ λ‚˜μ˜€λŠ”λ°, old state κ³Ό new state 을 μ§€κΈˆμ˜ μ˜ˆμ‹œμ—μ„œ todosState1, todosState2 둜 λ’€λ‹€. 즉, StateNotifier μ—μ„œ custom method λ₯Ό 톡해 state 에 λ³€ν™”λ₯Ό μ€˜μ•Ό ν•˜λŠ”λ° state μžμ²΄λŠ” κ·ΈλŒ€λ‘œ 두고 state λ‚΄μ˜ μ›μ†Œλ§Œ λ°”κΎΌ 것이닀.

λ‹€μ‹œ 말해, state 에 λ³€ν™” λ₯Ό μ€€λ‹€λŠ” 것은 identical νŒμ •μ— λŒ€ν•΄ μ™„μ „νžˆ λ³€ν™”λ₯Ό μ£ΌκΈ° μœ„ν•΄μ„œ μ£Όμ†Œκ°’ λ³€κ²½κΉŒμ§€ κ³ λ €ν–ˆμ–΄μ•Ό ν•˜λŠ”λ° λ™μΌν•œ 객체λ₯Ό 두고 λ‚΄λΆ€ μ›μ†Œλ§Œ λ°”κΏ”λ²„λ¦¬λ‹ˆ μœ„ μ˜ˆμ‹œμ²˜λŸΌ λ³€ν™”λ₯Ό μ€¬λ‹€ν•œλ“€ κ²°κ΅­ 같은 object κ°€ 된 것이닀. todosState1 μ—μ„œ todosState2 와 같이 λ°”κΏ¨μ§€λ§Œ κ²°κ΅­ 같은 object 인 것이닀.

κ·Έλž˜μ„œ state λ₯Ό λ‹€λ£°λ•ŒλŠ” μ™„μ „νžˆ immutable object 둜 μƒˆλ‘œ λ§Œλ“€μ–΄λ‚΄μ•Ό ν•œλ‹€. 그것이 μƒκ°ν•˜κΈ°λ„ νŽΈν•˜κ³  버그λ₯Ό μ€„μ΄λŠ” 방법이닀. 그럼 λ‚΄κ°€ μ‹€μˆ˜ν•œ μ½”λ“œλ₯Ό 보자.

// state κ°€ λ³€κ²½λ˜μ—ˆλ‹€κ³  μΈμ‹λ˜μ§€ μ•ŠμŒ
void removeTodo(String removeTargetTodoId) {
  print('before : ${state.todos.length}');
  state.todos.removeWhere((todo) => todo.id == removeTargetTodoId);
  print('after : ${state.todos.length}');

  final List<Todo> todos = [...state.todos];
  state = state.copyWith(todos);
}

// 잘 μž‘λ™ν•˜λŠ” μ½”λ“œ
void removeTodo(String removeTargetTodoId){
final List<Todo> todos = [...state.todos.where((todo) => todo.id != removeTargetTodoId).toList()];
state = state.copyWith(todos);
}

잘λͺ»λœ μ½”λ“œλ₯Ό 보면 κ²°κ΅­ removeTodo() ν•¨μˆ˜κ°€ λ™μž‘ν•˜κΈ° μ „κ³Ό ν›„λŠ” state κ°€ κ°€μ§„ todos 의 λ‚΄μš©μ€ λ°”λ€Œμ—ˆμ„μ§€μ–Έμ •, todos μžμ²΄λŠ” κ·ΈλŒ€λ‘œμ΄κΈ° λ•Œλ¬Έμ— κ²°κ΅­ state 의 λ³€ν™”λŠ” λ°œμƒν•˜μ§€ μ•Šμ•˜λ‹€κ³  νŒμ •λœλ‹€. 고쳐진 μ½”λ“œμ—μ„œλŠ” removeWhere 이 μ•„λ‹ˆλΌ where 을 ν†΅ν•΄μ„œ ν•„μš”ν•œ μ›μ†Œλ“€μ„ 찾은 ν›„ toList() 둜 μ™„μ „νžˆ λ‹€λ₯Έ todos λ₯Ό λ§Œλ“€μ–΄μ„œ κ²°κ΅­ state λ₯Ό λ°”κΎΈκ³  μžˆλ‹€.

μ΅œμ’…μ μœΌλ‘œ StateNotifierProvider 둜 앱을 κ΅¬ν˜„ν–ˆλ‹€. 에 ν‘Έμ‹œν•΄λ‘μ—ˆλ‹€. 기둝을 μœ„ν•΄ Provider μ£Όμž… λΆ€λΆ„κ³Ό independent state, computed state μƒ˜ν”Œλ§Œ μ½”λ“œλ₯Ό 남긴닀.

μΆ”κ°€λ‘œ Equatable κ³Ό κ΄€λ ¨ν•˜μ—¬ μ°Έκ³ ν•˜κΈ° μ’‹μ•˜λ˜ 링크λ₯Ό 남긴닀.

κΉƒν—ˆλΈŒ
포슀νŒ