1차 평가 정리

자바, 비동기, Json, HTTP, JWT,
SHIN's avatar
Oct 01, 2024
1차 평가 정리
 

1. Java에서 Solid 원칙 [디자인 패턴 활용]

1-1. SRP (단일 책임 원칙)
💡
  • 모든 클래스는 각각 하나의 책임만 가져야 하며, 수정할 이유는 단 한 가지여야 함
  • 클래스는 그 책임을 완전히 캡슐화해야 함
  • ex) 결제 클래스가 있으면 이 클래스는 오직 결제 기능만 책임지고, 만약 이 클래스를 수정해야 한다면 결제에 관련된 문제일 것.
 
1-2. OCP (개방-폐쇄 원칙)
💡
  • 소프트웨어 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확정에는 열려 있어야 하지만 변경에는 폐쇄적이어야 함
  • 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되는 원칙
  • ex) 캐릭터 하나를 생성한다고 할 때 각 캐릭터마다 움직임이 다를 경우, 움직임 패턴 구현을 하위 클래스에 맡긴다면 캐릭터 클래스의 수정은 필요 없고(closed), 움직임 패턴만 재정의 하면 됨(open)
  • 개방-폐쇄 원칙을 적용하기 위한 중요 메커니즘은 추상화와 다형성
 
1-3. LSP (리스코프 치환 원칙)
💡
  • 상위 타입은 항상 하위 타입으로 대체될 수 있어야 함
  • 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 역할을 하는데 문제가 없어야 한다는 점
    • notion image
      notion image
  • 리스코프 치환 원칙은 다형성과 확장성을 극대화하며, 개방-폐쇄 원칙을 구성
 
1-4. ISP (인터페이스 분리 원칙)
💡
  • 각 역할에 맞게 인터페이스를 분리하는 것
  • 최소한의 기능만 제공하면서 하나의 역할에 집중하라는 뜻
  • SRP, ISP는 같은 문제에 대한 두 가지 다른 해결책이라고 볼 수 있음
  • 가능한 최소한의 인터페이스를 사용하도록 하여 단일 책임을 강조
  • 일반적으로 ISP보다 SRP 할 것을 권장
 
1-5. DIP (의존 관계 역전 원칙)
💡
  • 의존 관계를 맺을 때 고수준 모듈이 저수준 모듈에 직접 의존하는 것을 피해야 하는 것
  • 고수준 모듈 : 변경이 없는 추상화 된 클래스(= 인터페이스)
  • 저수준 모듈 : 위의 추상화 된 클래스나 인터페이스를 상속받은 구현체 클래스
 
코드 Note
public interface Pizza { void prepare(); void bake(); void cut(); } public class CheesePizza implments Pizza { @Override public void prepare() { System.out.println("Preparing Cheese Pizza..."); } @Override public void bake() { System.out.println("Baking Cheese Pizza..."); } @Override public void cut() { System.out.println("Cutting Cheese Pizza..."); } } // 이렇게 Pizza라는 인터페이스(고수준 모듈)와 CheesePizza라는 구현 클래스(저수준 모듈)이 있을 때,
public class Chef { private final Pizza pizza; public Chef(Pizza pizza) { this.pizza = pizza; } public void makePizza() { pizza.prepare(); pizza.bake(); pizza.cut(); } } public class Main { public static void main(String[] args) { Pizza cheesePizza = new CheesePizza(); Chef chef = new Chef(cheesePizza); chef.makePizza(); } } // Chef 클래스에서 의존성 주입을 할 때 변하기 쉬운 CheesePizza 클래스에 직접 의존하지 말고, // 고수준 모듈인 Pizza 인터페이스를 의존하라는 의미.
 

 

2. Method Overriding & Overloading [디자인 패턴 활용]

  • Overloading
💡
  • 상속과 관련x
  • 한 클래스에서 같은 이름의 method를 여러개 정의하는 것(method 중복)
  • 매개변수 타입이 다르거나 개수가 달라야 함
  • 매개변수 순서가 달라야 함
  • return type과 접근 제어자는 영향을 주지 않음
  • Overriding
💡
  • 상속에서 나온 개념
  • 상위 클래스(부모 클래스)의 method를 하위 클래스(자식 클래스)에서 상속받은 상태에서 본문 내용만 수정하는 것(method 재정의)
코드 Note
  • 하는 일이 비슷하기 때문에 이름을 다르게 다 정의하면 코드가 복잡해지기에 이를 방지?
// Overload : method 중복 public class OverloadExam { static void print() { System.out.println("hello"); } static void print(String a) { System.out.println(a); } // static void print(String b) { System.out.println(b); // } // static int print(String a) { // return 100; // } public static void main(String[] args) { print(); print(100); print("java"); } }
/* interface A { public void print(); } */ class A { void print() { System.out.println("a"); } } // class B implements A class B extends A { // override : method 재정의 public void print() { Systemout.println("a"); Systemout.println("b"); } } public class OverrideExam { public static void main(String[] args) { B b = new B(); b.print(); // polymophism A a = new B(); a.print(); A aa = new A(); aa.print(); } }
 

 

3. 다형성 [디자인 패턴 활용]

💡
  • 부모 자료형으로 다양한 자식 자료형들을 처리할 수 있는 능력
  • 부모 클래스의 인스턴스를 이용하여 자식 타입의 클래스를 다룸
  • Overrriding을 통해 동일 이름의 method를 이용하여 다양한 자식 클래스의 method를 호출
 

 

4. CSR, SSR 차이 [API 설계 및 모범 사례]

4-1. CSR
💡
  • 사용자와의 상호작용이 많은 웹 애플리케이션에 적합 → js를 통해 클라이언트 측에서 페이지의 콘텐츠를 동적으로 생성하고 업데이트 하기 때문.
  • 클라이언트 측에서 콘텐츠를 동적으로 생성하기에 사용자의 행동에 따라 실시간으로 페이지 콘텐츠를 업데이트 가능 → 풍부한 사용자 경험 제공
notion image
  1. User가 Website에 요청을 보냄
  1. CDN이 HTML 파일과 JS로 접근 가능한 링크를 클라이언트에게 전송 CDN : aws의 cloudflare. 엔드 유저의 요청에 물리적으로 가까운 서버에서 요청에 응답하는 방식
  1. 클라이언트는 HTML과 JS를 다운 → 이때 SSR과 달리 유저는 아무것도 볼 수 없음
  1. 생략
  1. 다운이 완료된 JS 실행. 데이터를 위한 API 호출 → 이때 유저들은 placeholder를 봄
  1. 서버가 API로부터의 요청에 응답
  1. API로부터 받아온 data를 placeholder 자리에 삽입. → 이제부터 페이지는 상호작용 가능
    1. notion image
      → 서버에서 처리 없이 클라이언트로 보내주기 때문에 JS가 모두 다운 되고 실행이 끝나기 전까지 사용자는 볼 수 있는게 없음
 
 
4-2. SSR
💡
  • 초기 페이지 로딩 속도가 빠르고 검색 엔진 최적화(SEO)에 유리 → 서버에서 렌더링된 페이지가 클라이언트에게 전송되기 때문에 검색 엔진이 콘텐츠를 쉽게 Indexing 가능
  • js가 비활성화된 환경에서도 페이지를 볼 수 있게 해줌
notion image
  1. User가 Website 요청을 보냄
  1. Server는 ‘Ready to Render’ → 즉시 렌더링 가능한 HTML 파일을 만듦 (리소스 체크, 컴파일 후 완성된 HTML 콘텐츠로 만듦)
  1. 클라이언트에 전달되는 순간, 이미 렌더링 준비가 되어있기 때문에 HTML은 즉시 렌더링 됨 → 하지만 사이트 자체 조작은 불가능(JS가 읽히기 전)
  1. 클라이언트가 JS를 다운받음
  1. 다운 받는 사이 유저는 콘텐츠를 볼 수 있지만 사이트 조작은 못함 → 이때 사용자 조작을 기억하고 있음
  1. 브라우저가 JS Framework를 실행
  1. JS까지 성공적으로 컴파일 되었기 때문에 기억하고 있던 사용자 조작이 실행되고, 이제 웹 페이지는 상호작용이 가능
차이점
💡
  1. 웹 페이지 로딩 시간
      • 첫 페이지 로딩 시간
        • CSR의 경우 HTML, CSS와 모든 스크립트들을 한 번에 로드. 반면 SSR은 필요한 부분의 HTML과 스크립트만 로드 → SSR이 더 빠름
      • 나머지 로딩 시간
        • 첫 페이지 로딩 후, 사이트의 다른 곳으로 이동하는 식의 동작을 가정 → CSR은 이미 첫 페이지 로딩 시 나머지 부분을 구성하는 코드를 받아와서 빠름. 반면 SSR은 첫 페이지를 로딩한 과정을 정확하게 다시 실행함(더 느림)
  1. 서버 자원 사용
      • 매번 서버에 요청을 하기 때문에 SSR이 서버 자원을 더 많이 사용
      • 반면 CSR은 클라이언트에 일을 몰아주기에 서버 부하가 적음
선택 기준
💡
  • 두개 중 어떤 방식을 선택할지는 프로젝트의 요구 사항과 목표에 따라 달라짐. SEO가 중요하거나 초기 페이지 로딩 속도가 중요한 프로젝트의 경우 SSR을, 사용자 경험과 상호작용이 중요한 웹 애플리케이션의 경우 CSR 선택이 좋음
 

 

5. AJAX 통신 [API 설계 및 모범 사례]

💡
  • JS를 통해 비동기식으로 서버에 데이터를 요청하여 필요한 데이터를 받아와 전체 페이지를 새로 고치지 않고 변경이 필요한 페이지 부분만을 고치는 기술
  • 주목적은 화면 전환 없이 클라이언트와 서버간의 정보를 교환하기 위함
notion image
→ 동기식은 요청 후 응답을 받아야 다음 동작이 이루어지고 비동기식에서는 요청을 보낸 후 응답과는 상관없이 동작하는 방식. → 이러한 이유로 HTTP 전송 중에도 클라이언트가 웹 애플리케이션과 상호작용을 할 수 있는 것.
 
AJAX 사용법
$.ajax({ url : requestUrl, type : 'DELETE', // 요청 방식 async : true, // 디폴트값 true (false = 동기) data : JSON.stringify(requestParam), // 전달 파라미터 dataType : "json", // 서버에서 반환되는 데이터 형식 (text, html, xml, json 등) timeout : 10000, contentType : "application/json", // 서버에서 데이터를 보낼 때 사용 (content-type 헤더 값) befireSend:function(){ }, complete:function(){ }, success:function(){ }, error:function(){ }, fail:function(){ } }); }
 

 

6. JSON [API 설계 및 모범 사례]

💡
  • Java Script 객체 표기법으로 데이터를 쉽게 교환하고 저장하기 위한 텍스트 기반의 데이터 교환 표준
  • 텍스트 기반이기에 다양한 프로그래밍 언어에서 데이터를 읽고 사용 가능
 
기본형태
// Key와 Value의 쌍으로 이루어진 구조. { key : value} // 여러 데이터를 나열할 경우 쉼표 사용 {key1 : value, key2 : value2} // 객체(Object)는 중괄호로 묶어서 표현, 배열은 대괄호로 묶어서 표현 {key1 : {inKey : inValue}, key2 : [arr1, ar2, arr3] } {"판매자정보" : {"이름" : "신민재", "지역" : "부산" }, "판매품목" : ['옷', '바지', '신발'] } // ---------------------------------------------- // 데이터 값으로 다양한 타입 사용 가능 // 숫자 문자열 불리언 객체 배열 널 [ 1, "str", true, {inKey : "value"}, ["일", "이"], null]
 
JSON 사용
  1. JSON.stringify(arg) : 객체를 문자열로 변환
var json = {"test" : "value"} var incodingData = JSON.stringify(json); // console.log(incodingData);
 
  1. JSON.parse(arg) : 문자열을 객체로 변환
var str = '{"test" : "value"}'; var parsingData = JSON.parse(str); // console.log(incodingData);
 
예제 - [이름, 성별, 나이] 객체 생성
var Characters = [ { '이름' : '신민재', '성별' : '남', '나이' : 28 }, { '이름' : '신민지', '성별' : '여', '나이' : 27 } ] // 여기서 성인여부 항목 추가시 Character.성인여부 = true; // or Character["성인여부"] = true;
 
key를 동적으로 생성해야 하는 경우
var key = "직접잡은범인"; Character.key = 0; // X // {이름 : "신민재", 성별: "남", 나이: "28", key:0} // 이렇게 하면 key값이 올바르게 추가됨. 즉 동적으로 생성해야한다면 이와 같은 방법 사용 var key = "직접잡은범인"; Character[key] = 0; // X // {이름 : "신민재", 성별: "남", 나이: "28", 직접잡은범인:0}
 

 

7. HTTP 401, 403 [서비스 인증과 권한 부여]

 
401 Unauthorized
// 인증 실패 (클라이언트가 인증 없이 요청했거나, 인증 도중 실패 @ExceptionHandler(Exception401.class) public String ex401(Exception e) { return Script.href("인증되지 않았습니다", "/login-form"); }
  • 인증(Authentication) : 본인이 누구인지 확인 → 로그인
  • 인가(Authorization) : 권한 부여
  • 오류 메시지가 Unauthorized이지만 인증되지 않음
 
 
403 Forbidden
// 권한 실패 (인증은 되어있으나, 삭제하려는 게시글이 내가 적은 글이 아님) @ExceptionHandler(Exception403.class) public String ex403(Exception e) { return Script.back(e.getMessage()); }
  • 서버가 요청을 이해했지만 승인을 거부함
  • 주로 인증 자격 증명은 있지만 접근 권한이 불충분한 경우
  • Admin 등급이 아닌 사용자가 로그인 했지만, Admin 등급의 리소스에 접근하는 경우 발생
 

 

8. JWT와 Session 차이 [스프링 시큐리티와 JWT 적용]

Session 방식
notion image
  1. 클라이언트가 로그인을 위해 인증 정보를 서버에 전송
  1. 서버는 메모리에 사용자를 저장하고, 세션 아이디를 쿠키로 전달
  1. 클라이언트는 쿠키에 저장된 세션 아이디를 이용하여 요청
  1. 서버는 일치하는 세션 아이디를 메모리에서 검색한 후 응답
💡
  • 서버 인증 기반의 문제점?
    • 세션을 DB에 저장해서 탐색하기 때문에 유저가 늘어날수록 서버의 램 과부하
    • 여러 개의 프로세스를 돌리거나 서버 컴퓨터를 추가하는 것이 쉽지 않음
    • 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 있어서 여러 도메인에서 관리하기 힘듦
 
JWT (Json Web Token)
💡
  • JWT는 JSON 개체로 안전하게 전송하기 위한 국제 표준 (RFC 7519)
  • 디지털 서명이 되어 있어서 확인하고 신뢰 가능
notion image
  1. 클라이언트가 로그인을 위해 인증 정보를 서버에 전송
  1. 서버는 secret 정보를 이용하여 JWT를 생성하고 클라이언트에게 전달
  1. 클라이언트는 로컬 혹은 브라우저에게 저장해뒀던 JWT를 이용하여 요청
  1. 서버는 JWT가 일치하는지 확인한 후, 응답
 
JWT 구조 (xxxxx.yyyyy.zzzzz)
  1. Header
    1. 토큰 타입과 어떤 알고리즘이 쓰였는지 나타냄
{ "alg" : "HS256", "typ" : "JWT" } // 이 json은 Base64Url로 인코딩 된 JWT의 첫번째 부분
 
  1. Payload
    1. 토큰의 두번째 부분은 사용자 및 정보가 담겨있는 payload 부분
    2. payload에 담긴 정보는 인코딩만 되어 있어서 누구라도 디코딩하여 확인할 수 있으므로 중요한 정보를 담으면 보안상 위험
 
  1. Signature
    1. 마지막 Signature 영역을 생성하려면 인코딩 된 header, payload, secret, 헤더에 지정된 알고리즘을 이용하여 해싱
    2. 만약 어느 하나라도 일치하지 않으면 완전히 다른 값을 갖게 됨
 
토큰 작동 방식
  • 로그인하면 JSON 웹 토큰이 반환
  • 토큰은 자격 증명이므로 보안 문제를 방지하기 위해 세심한 주의 필요
  • 일반적으로 토큰을 필요 이상으로 오래 보관해서는 안되며 보안이 취약하기에 민감한 세션 데이터를 부라우저 저장소에 저장해서는 안됨
  • 앱에서는 설치된 앱 별로 안전한 저장 공간이 제공되지만 웹에서는 세션 인증이 나은 선택일 수 있음
💡
  • Token 인증방식의 장점?
    • 무상태와 확장성, 토큰은 클라이언트쪽에만 저장되므로 stateless 하며, 서버를 확장하기에 적합한 환경을 제공
    • 쿠키를 사용함으로 인해 발생하는 보안 취약점이 사라짐
    • 토큰을 사용하여 다른 서비스에도 권한 공유
 
Session과 JWT 차이
  • 서버에 인증 정보를 저장하지 않는다는 점이 상이
  • 클라이언트의 요청마다 인증을 위해 DB를 탐색하는 과정이 필요 없고 저장 공간도 필요 없음
 
CSRF 이슈
  • Cross Site Request Forgery
POST /email/change HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 30 Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE email=wiener@normal-user.com
<html> <body> <form action="https://vulnerable-website.com/email/change" method="POST"> <input type="hidden" name="email" value="pwned@evil-user.net" /> </form> <script> document.forms[0].submit(); </script> </body> </html>
 
  • 보완책
    • CSRF 토큰 - CSRF 토큰은 서버 측 응용 프로그램에서 생성하고 클라이언트와 공유하는 고유한 비밀 및 예측 불가능한 값
      • 양식 제출과 같은 중요한 작업을 수행할 때 클라이언트는 요청에 올바른 CSRF 토큰을 포함하여 전달
    • SameSite 쿠키 - 웹 사이트의 쿠키가 다른 웹 사이트에서 발생하는 요청에 포함되는 시기를 결정하는 브라우저 보안 메커니즘
      • 중요한 작업을 수행하기 위한 요청에는 일반적으로 인증된 세션 쿠키가 필요하므로, 적절한 SameSite 제한으로 인해 공격자가 사이트 간 이러한 작업을 트리거 X
    • Referer 기반 검증 - 일부 응용 프로그램은 HTTP Referer 헤더를 사용하여 CSRF 공격을 방어
      • 일반적으로 요청이 응용 프로그램의 자체 도메인에서 발생했는지 확인
 

 

9. Cross Flatform [Flutter와 Meterial 디자인 활용]

💡
  • 교차를 뜻하는 Cross와 Flatform의 합성어로, 다양한 플랫폼에서 사용할 수 있는 뜻
  • 하나의 개발 언어로 안드로이드와 iOS에서 사용 가능한 앱 개발
    • Flutter (구글)
    • React Native (페이스북)
    • Xamarin (마이크로소프트)
 
장점
  • 하나의 개발 언어와 도구로 안드로이드와 iOS 모두에서 동작할 수 있는 앱을 만들 수 있다는 것
  • Native 앱과 비교했을 때 개발과 운영에 필요한 비용과 시간을 절약 가능
  • Flutter는 안드로이드, iOS뿐 아닌 웹, 리눅스, 윈도우 등에서 동작하는 데스크탑 앱 개발까지 지원하는 툴
 
단점
  • Native 앱만큼 높은 성능과 OS에서 제공하는 API를 활용하기 어려움
  • OS에서 새롭게 API를 업데이트 했다면, 크로스 플랫폼에서 지원해 줄 때까지 즉시 사용 불가
  • 크로스 플랫폼 측 버그 발생 시 해당 플랫폼 개발자가 버그를 해결할 때까지 기다릴 수 밖에 없음
    • Airbnb는 초기에 React Native로 서비스를 개발/운영 하다가 위와 같은 이슈로 2018년부터 Native 앱 활용
 

10. 동기 & 비동기 [Flutter Animation 처리]

동기
  • 작업이 순차적으로 진행 → 한 작업이 시작되면 해당 작업이 완료될 때까지 다른 작업이 기다려야함
  • 동기 방식은 호출한 함수 또는 작업이 반환될 때까지 대기하는 동안 실행 흐름이 차단되는 특징
  • 일반적으로 간단하고 직관적인 코드 작성이 쉬우나 여러 작업이 동시에 실행되어야 하는 경우, 각 작업의 완료를 기다리는 동안 시간이 소요되어 전체 프로세스의 성능이 저하될 수 있음
  • 또한 한 작업이 지연되면 다른 작업들도 모두 지연되는 문제 발생 가능
 
 
비동기
  • 작업이 독립적으로 실행 → 작업의 완료 여부를 기다리지 않고 다른 작업을 실행할 수 있는 방식
  • 작업 시작 시 해당 작업이 완료될 때까지 기다리지 않고 다음 코드 실행 가능
  • 주로 I/O 작업이나 네트워크 요청과 같은 시간이 오래 걸리는 작업에 유용
  • 이러한 작업을 비동기적으로 처리하면 프로그램은 작업이 완료되기를 기다리는 동안 다른 작업을 처리할 수 있으므로 전체적인 성능이 향상
  • 비동기 방식은 callback, promise, async/await 등의 메커니즘을 통해 구현 가능

 

11. 데이터의 불변성이 중요한 이유 [Flutter 상태관리]

💡
  • 불변성 : 값이나 상태를 변경할 수 없는 것
  • 프로그래밍에서의 불변성은 데이터 원본의 훼손을 막는 것 → 어떤 값을 직접적으로 변경하지 않고 새로운 값을 만들어내는 것
  • JS에서는 원시타입은 불변성을 지니지만, 객체타입은 값이 변할 수 있음
 
원시타입
💡
Boolean, Number, String, null, undefined, Symbol
 
let str = "example1"; str = "example2"; console.log(str) // example2 // 값이 변경된 것이 아닌, 새로 선언된 값이 메모리에 저장되고 변수가 새로운 메모리를 가리키는 것.
let name = 'SHIN'; let new_name = name; // -> new_name이 name이 가리키고 있는 메모리를 같이 가리킴 name = 'KIM'; console.log(new_name); // SHIN console.log(name); // KIM
 
객체 타입
var person = { name: 'SHIN', age: 28, } var new_person = person; person.name = 'KIM'; console.log(person.name); // 'KIM' console.log(new_person.name); // 'KIM' // 객체 타입은 원시 타입과 다르게 이름이 모두 변경됨 // 객체는 객체 내부의 값을 변경하면 객체를 참조하고 있는 다른 값들도 모두 변경
 
불변성을 지켜야 하는 이유
  • 리액트는 상태값을 업데이트 할 때 얕은 비교를 수행함
  • 리액트는 객체의 속성 하나하나를 비교하는게 아닌, 참조값만 비교하여 상태 변화를 감지
💡
  • 얕은 비교 : 객체, 배열, 함수와 같은 참조 타입들을 실제 내부 값까지 비교하지 않고 동일 참조인지(동일한 메모리 값을 사용하는지)를 비교하는 것
 
Ex)
  1. 컴포넌트를 ReRendering 해야하는 상황이 있다고 가정하고 타입이 배열인 state를 바꿈
  1. 이때 state.push(1)을 통해 state 배열에 직접 접근하여 요소를 추가
  1. 우리는 push 전과 다른 값이라고 생각하지만, 리액트는 state라는 값은 새로운 참조값이 아니기 때문에 이전과 같은 값이라고 인식하고 ReRendering 하지 않음
 
불변성의 장점
💡
  • 효율적인 상태 업데이트 (얕은 비교 수행)
    • 계산 리소스를 줄여주기 때문에 리액트는 효율적으로 상태 업데이트 가능
  • 사이드 이펙트 방지 및 프로그래밍 구조의 단순성
    • 원시타입은 불변성 특징을 가지고 있지만 참조타입인 객체나 배열의 경우 새로운 값을 변경할 때 원본 데이터가 변경됨 (불변성이 지켜지지 않음). 이렇게 원본 데이터가 변경될 경우, 이 원본 데이터를 참조하고 있는 다른 객체에서 예상치 못한 오류 발생 가능 → 프로그래밍의 복잡도 상승
    • 즉 불변성을 지키면 이를 방지할 수 있음
 
불변성을 지키는 법
// Spread 문법 // 원시 타입 const [number, setNumber] = useState(0) setState(10) // 참조 타입 const [person, setPerson] = useState({ name: '', age: 28 }) setState({...person, name: 'SHIN'}) setUsers( users.map(user => user.id === id ? { ...user, name: "SHIN" } : user ) );
 
// immer 사용 import produce from "immer"; const user = [ { name: "SHIN", age: 28 }, { name: "KIM", age: 32 } ]; const new_user = produce(user, draft => { draft.push({ name: "LEE" }); draft[1].age = 29; });
 

 

12. Hash 알고리즘 [Flutter 상태관리]

  • 임의의 길이를 가진 데이터를 고정된 길이의 hash 값으로 변환하는 알고리즘
  • 이 알고리즘은 입력 데이터에 대해 일관된 hash 값을 생성하고, 입력 데이터가 조금만 변경되어도 완전 다른 hash 값을 반환하는 특징을 가짐
  • 일반적으로 hash 함수라고도 불리며, 다양한 분야에서 데이터 무결성 검사, 데이터 식별, 암호화, 암호화 인증, 자료구조 등에 활용
  • 대표적인 종류
    • MD5 (Message Digest Algorithm5)
    • SHA (Secure Hash Algorithm)
  • 충돌(collision)을 최소화하여 hash 값 중복 방지 및 안전성과 보안성을 강화하기 위해 설계
 
목적
💡
  • 데이터 무결성 검사 : 데이터가 변경되지 않았는지 확인을 위해 hash 값 사용
  • 데이터 식별 : 데이터를 고유하게 식별하기 위해 hash 값 사용
  • 암호화 : 암호화 알고리즘에서 키를 생성하거나 데이터를 변환하기 위해 사용
  • 암호 인증 : 사용자의 비밀번호나 인증 토큰 등을 안전하게 저장하고 검증을 위해 사용
  • 자료구조 : hash 테이블, hash 집합, hash map 등 자료구조를 구현하기 위해 사용
 
hash 알고리즘이 빠른 이유
💡
  • 고정된 출력 크기
    • 입력 데이터의 크기에 관계없이 항상 고정된 크기의 hash 값(hash 코드 또는 hash 체크섬)을 생성 → 입력 데이터의 크기에 관계없이 일정한 연산 시간을 유지하도록 함
  • 단방향 함수(일방향 함수)
    • hash 값에서 기존 데이터로의 복원이 어렵거나 불가능
    • 이로 인해 hash 알고리즘은 데이터의 비밀성을 유지하는 데에 적합, 암호화 및 인증 등의 보안 기능에 활용 가능
  • 고속 연산
    • hash 함수의 수행 시간이 입력 데이터의 크기와는 관련이 없고, 일정한 시간 내에 연산이 완료되기 때문
    • hash 알고리즘은 대부분의 경우 빠른 실행 속도를 제공하여 대량의 데이터를 효율적으로 처리 가능
  • 충돌 저항성
    • 좋은 hash 알고리즘은 입력 데이터의 작은 변경에도 전혀 다른 해시 값을 생성하도록 설계(충돌 저항성)
    • 충돌은 서로 다른 입력 데이터가 동일한 hash 값을 가질 때 발생하는 현상
    • 충돌을 최소화하고 안정적인 분포를 갖는 hash 알고리즘은 검색 성능을 향상 시키고 데이터의 고르고 균형 잡힌 분산을 도모
  • 하드웨어 최적화
    • 일부 hash 알고리즘은 하드웨어에서 효율적으로 구현될 수 있도록 최적화 되야함
    • 이러한 최적화는 CPU 명령어 세트 확장, 병렬 처리, 하드웨어 가속 등을 활용하여 hash 알고리즘의 실행 속도를 높이는데 도움
 
결론
  • 고정된 출력 크기, 단방향 함수, 고속 연산, 충돌 저항성 및 하드웨어 최적화 등의 특징으로 인해 빠른 속도를 제공
 

 

13. Http Header에서 Content-Type & User-Agent [Flutter JWT 토큰 관리] - 출처 MDN

Content-Type
  • 클라이언트와 서버 간 주고받는 데이터의 유형을 지정
  • Ex) 서버가 클라이언트에게 HTML 파일을 보낼 때 Content-Type을 text/html 로 설정하여 HTML로 해석하도록 함
  • 클라이언트가 데이터를 서버로 보낼 때도 Content-Type을 사용해 서버가 어떤 형식의 데이터를 처리해야 하는지 알려줌
 
User-Agent
  • 클라이언트가 서버에 자신을 식별하기 위해 사용하는 문자열
  • 요청을 보내는 소프트웨어의 종류(ex:웹 브라우저, 웹 크롤러), 버전, 운영체제 등을 포함하여 서버가 클라이언트의 특성을 이해하고 이에 맞는 응답을 제공할 수 있도록 도움
  • Ex) 서버는 User-Agent 정보를 사용해 특정 브라우저에서만 동작하는 기능을 활성화하거나 모바일 기기용 페이지를 제공

 

14. REST API [Retrofit 구현과 활용]

💡
 

15. MVC 패턴 [Restrofit 구현과 활용]

💡
  • 코드 재사용이 유용하며 사용자 인터페이스와 응용프로그램 개발에 소요되는 시간을 현저하게 줄여줌
MVC 구성요소
  • Model : 소프트웨어 응용과 그와 관련된 고급 클래스 내의 논리적 데이터 기반 구조를 표현
  • View : 사용자 인터페이스 내의 구성요소들을 표현(사용자에게 보여지는 화면)
  • Controller : Model과 View를 연결하고 흐름을 제어하는 클래스. Model과 View 사이의 정보를 교환하는데 사용
 

16. Interceptor [Retrofit 구현과 활용]

  • Spring MVC에서 인터셉터는 웹 어플리케이션 내에서 특정한 URI 호출을 ‘가로채는’ 역할
  • 이를 활용하면 기존 컨트롤러의 로직을 수정하지 않고도 사전이나 사후에 제어 가능 → 요청과 응답을 가로채서 원하는 동작을 추가하는 역할
  • Ex) 세션을 통한 인증을 쉽게 구현 가능
    • 요청을 받아 들이기 전, 세션에서 로그인 한 사용자가 있는지 확인해보고 없다면 로그인 페이지로 redirect 시킴
    • 인터셉터가 없다면 모든 컨트롤러마다 해당 로직을 넣어야 해서 비효율적
    • 주기적으로 결과 페이지에 등장하는 데이터들을 인터셉터에서 응답을 가로채어 데이터를 추가한 후 보낼 수 도 있음 → 메일 알림 개수 조회 후 추가, 헤더 데이터 같은 것들
 
Filter와 혼동 가능!
 
Filter
  • DS 처리 전 후에 동작하여 사용자의 요청이나 응답의 최전방에 존재
  • 스프링의 독자적 기능이 아닌 Java Servlet에서 제공
    • notion image
 
public interface Filter { public default void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public default void destroy() {} }
 
Filter Interface의 3가지 Method
  1. init : 필터가 웹 컨테이너에 생성될 때 실행
  1. doFilter : Request, Response가 필터를 거칠 때 수행되는 메소드, 체인을 따라 다음에 존재하는 필터로 이동
  1. destroy : 필터가 소멸될 때 실행됨
 
 
Interceptor와 Filter 공통점
  • Servlet 기술의 Filter와 Spring MVC의 HandlerInterceptor는 특정 URI에 접근할 때 제어하는 용도로 사용된다는 공통점을 가지고 있음
 
차이점 : 영역의 차이
  • 실행 시점에 속하는 영역(Context)
    • notion image
Share article

SHIN