728x90
반응형
SMALL

 

 

Intro

 🌐 우리는 지난 시간에, 소위 웹 어플리케이션이 어떠한 원리로 어떻게 동작하는지, 그 중에 웹서버(정확히는 Web Application Server)는 어떻게 동작하는지 아주 간략하게 알아봤습니다. 이번 시간에는 서버가 해주는 일을 조금 더 자세히 살펴보고, 스프링, 스프링부트에 대한 소개를 갖는 시간을 가져보면 좋을 것 같습니다.

 

 🤔 Issue : 서비스의 규모가 커지면 우리가 flask 서버에서 작성하던 것 과 같이 프로그래밍을 할 수 없습니다.

 

서비스 로직이 커져갈수록 연관된 데이터는 훨씬 더 많아지고, 처리해야 할 로직은 더 복잡해지고, 심지어는 이것들이 맞물려 프로그램의 복잡도는 기하급수적으로 올라갑니다. 특히 프로그램의 로직이 수정되어야 하거나 이미 동작하는 서버위에 새로운 기능을 추가하는건 사실상 불가능해지는 시점에 도달하게되고, 결국 실패를 인정하고 아예 서버나 프로그램을 새로 만드는 일도 심심치 않게 일어납니다.

그나마 다행인 점은, 우리의 선배 개발자들이 이와 같은 실패로 얻은 교훈이 헛되지 않게 많은 자료와 사례를 남겨두었고, 지금은 “~~패턴” 또는 “~~아키텍쳐로’ 불리우고 있습니다. 우리는 이러한 것들을 공부하는 것 만으로도 그들이 했었던 실수를 반복하지 않고 개인의 수천시간, 동료들의 수만시간을 아낄 수 있습니다.

소프트웨어 디자인 패턴(software design pattern)은 소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다. 소스나 기계 코드로 바로 전환될수 있는 완성된 디자인은 아니며, 다른 상황에 맞게 사용될 수 있는 문제들을 해결하는데에 쓰이는 서술이나 템플릿이다. 디자인 패턴은 프로그래머가 어플리케이션이나 시스템을 디자인할 때 공통된 문제들을 해결하는데에 쓰이는 형식화 된 가장 좋은 관행이다.

Software Architecture Patterns

소프트웨어 아키텍처 패턴

 🤔 디자인 패턴을 공부하는 것 역시 매우 중요한 주제이지만, 자칫 너무 맹신하려고 들면 또 오히려 매우 큰 역효과를 마주한다고 합니다. 지금 당장은 더 중요한 배울거리가 많기도 하고 특정 패턴등을 마주 할 때 마다 확실히 이해하고 인지하고 넘어가는 정도의 공부가 지금은 가장 좋은 것 같습니다.

 

복잡한 문제를 해결하는 방법- 문제를 나누자!

실제로 복잡한 문제를 아키텍처 적으로 해결하는 방법은 매우 다양하지만 주로 문제를 나누는 방식이 가장 애용됩니다. 지난 시간의 이야기들과 웹개발 플러스 강의를 통해 여러분들이 구현해둔 예시로 알게된 내용은 아래 그림과 같습니다. 우리의 서버는 “새로운 데이터를 처리하는 부분”, “서비스 로직을 처리하는 부분”, **“기존의 데이터를 이용하는 부분”**으로 되어 있습니다. 실제로 각 부분은 스프링과 스프링부트에서 각각의 레이어로 나뉘어져 있습니다.

레이어드 아키텍처 패턴

출처 : https://jojoldu.tistory.com/603


Presentation 계층

사용자와 상호 작용 처리 계층

CLI, HTTP 요청, HTML 처리 등을 담당한다.

HTTP 요청 처리 및 HTML 렌더링에 대해 알고 있는 웹 계층

흔히 말하는 MVC (Model / View / Controller) 도 이 계층에 속한다.

우리가 URL을 매핑해서 특정 메서드가 해당 URL로 요청이 올 때마다 호출되게 프로그래밍 했었죠? 그 계층을 말하는 것이며, 스프링에서는 @Controller 어노테이션을 사용하여 표현합니다!


Domain(Business or Service) 계층

서비스/시스템의 핵심 로직

유효성 검사 및 계산을 포함하는 Business 논리 계층

애플리케이션이 수행해야하는 도메인과 관련된 작업들을 담당한다.

입력/저장된 데이터를 기반으로 계산

Presentation 계층에서 받은 데이터의 유효성 (Validation) 검사

어떤 Data Access 를 선택할지 결정

우리의 서버 프로그램이 복잡해지면, 비즈니스 로직을 수행하기 위한 별도의 계층(Layer)이 필요합니다. 사실 더 이상적으로는 유능한 서버 프레임워크를 써서 Presentaion, Data Access계층에는 별로 할 일이 없고, 도메인 계층이 비대해지는게 가장 좋습니다. 스프링에서는 @Service 어노테이션을 사용해서 표현합니다!


Data Access(Persistence) 계층

DAO 계층

Database / Message Queue / 외부 API와의 통신 등 처리

데이터베이스 또는 원격 서비스에서 영구 데이터를 관리하는 방법을 분류하는 데이터 접근 계층

우리의 데이터베이스, 혹은 데이터를 저장하는 데이터 소스는 서버 외부에 별개로 존재하는 경우가 매우 많고, 그러한 데이터 소스와의 소통을 해주는 계층이라고 생각하시면 될 것 같습니다. 스프링에서는 @Repository 어노테이션을 사용해서 표현합니다.

 🙂 아래 그림은 서버를 레스토랑으로 비유한 예시이며, 이 그림을 통해 각각의 계층과 스프링에서의 해당 어노테이션이 어떠한 일을 하는지 감을 잡으면 좋을 것 같습니다.

 

Controller, Service, Respository 실제 코드들

 🙂 각각의 레이어와 실제 코드들은 하나하나 자세히 살펴볼 예정입니다! 지금은 이런게 있다는 생각으로 가볍게 봐주시고 실제 실습에서 위와 같은 코드들을 직접 쳐보면서 학습 할 예정입니다.

 

Controller 예시 코드

@Controller // #1
public class ContentController {

    private final ContentService contentService; // #2

		@GetMapping("/content/{contentId}") // #3
		public Content getContent(@PathVariable Long contentId) { // #4
        Content content = contentService.getContent(requestDto); //#2-1
        return "/contentPage";
    }

    @PostMapping("/content") //#5
		@ResponseBody// #6
    public Content createContent(@RequestBody ContentRequestDto requestDto) {
        Content content = contentService.createContent(requestDto);
        return content;
    }
}

#1 : 이 자바 객체가 컨트롤러 역할을 하는 객체라는 것을 알려주는 어노테이션 입니다!

#2 : 각각의 레이어는 “일반적으로” 자기와 인접한 레이어와 직접 소통합니다, 이 경우 ContentService객체를 가지고 있어, 컨트롤러 단에서 서비스 단으로 새로 받아온 데이터를 전달하거나 서비스 로직을 호출 할 수 있습니다. 예를들어 #2-1 처럼 말이죠!

#3 : 플라스크의 @app.route(”/”)와 비슷해서 이미 짐작하셨겠지만, 특정 요청에 호출될 메서드를 지정해주는 어노테이션 입니다!

#4 : 해당 메서드에 넘기는 인자값을 손쉽게 넘기도록 위와 같은 어노테이션을 사용 할 수 있습니다, 이러한 어노테이션이 있으면 자동으로 일치하는 변수값을 메서드 호출되는 시점에 같이 넘겨줍니다. (조금 뒤에 이해하셔도 좋습니다!)

#5 : #3과 #5가 다른 이유는 HttpMethod에 따라서 다른 Controller 메서드를 연결해줄 수 있기 때문입니다, 같은 주소로 온 GET 요청과 POST을 나눠서 각각 처리하기에 용이하겠죠?

#6 : 위의 메서드와 아래의 메서드는 이전에 배웠던, 뷰까지 같이 반환하느냐, 혹은 JSON 형식으로 데이터만 반환하느냐의 차이가 있습니다. 이 부분도 나중에 자세히 학습하겠습니다.

Service 예시 코드

@Service // #1
public class ContentService {
    private final ContentRepository contentRepository; //#2

    public ReturnDto getContent(Long id) {
        ReturnDto returnDto = contentRepository.findById(id);
        return returnDto; //#3
    }
	
    public Content createContent(ContentRequestDto contentRequestDto) {
		    Content content = new Content(contentRequestDto);
		    contentRepository.save(content);
		    return content;
		}

}

#1 : 마찬가지로 이 자바 객체가 서비스 역할을 하는 객체라는 것을 알려주는 어노테이션 입니다!

#2 : 인접한 계층인 Repository 객체를 가지고 있어야 겠죠?

#3 : 사실 이 부분 역시 인접한 계층으로 데이터를 전달하는 중 입니다. 이해가 안가신다면 이 페이지의 내용을 다시 읽어보시면 좋을 것 같네요!

Repository 예시 코드

@Repository
public interface ContentRepository extends JpaRepository<Content, Long> {

}

#1 : 마찬가지로 이 자바 객체가 서비스 역할을 하는 객체라는 것을 알려주는 어노테이션 입니다!

#2 : 사실 리포지토리는 상당히 다양한 기술과 얽혀 있고 다양한 케이스가 있어 예시 코드를 보여드리기는 조금 어려운 것 같기도 합니다. 그래도 우리가 직접 사용하게 될 SpringDataJpa 의 JpaRepository는 이정도로 생겼네요

Outro

Outro 1. IOC? DI?

private final ContentService contentService; // #2
private final ContentRepository contentRepository; //#2

자바를 정말 열심히 공부하시고, 스프링만 처음이라면 위와 같은 코드의 위화감을 느끼셨을 겁니다.

분명 해당 객체의 메서드도 호출하고 있는데, 해당 객체는 어디서 어떻게 들어와있을까요?

이외에도 앞으로 지엽적인 컨트롤러나 리포지토리 서비스쪽 코드를 보게되다 보면

자바 문법과 묘하게 다른 부분들이 보일 겁니다.

때로 어떠한 지식은 뒤의 내용을 알아야 이해가 더 쉬운 경우가 있어 지금 설명하지는 않겠습니다.

위와같이 기존까지 알고 계시던 자바 문법과 다른 부분은 꼭 메모를 하시고 의아해 하시는 습관을 가지시면,

이후 IOC, DI 등 설계 철학 등을 배우고 이해하는데 큰 자산이 될 것 같습니다.

Outro 2. 스프링/스프링부트를 사용하는 이유?

이 부분도 지금은 와닿기 어려운 이유일 수 있습니다.

다만 지겹고 공부해야 할 많은 부분들이 전부 공부해야 할 이유가 있습니다.

결론적으로는 예전에 불편했던 것들을 정말 획기적으로 편하게 해줬기 때문에 스프링 프레임워크를 사용하는데,

구체적인 스프링에 관련된 내용을 학습하다 보면 왜 스프링이 편한지를 소개시켜드리는 계기가 있을 것 같습니다.

 🤔 그래도 일반적으로 가장 많이 꼽는 이유로는, 단순 반복작업부분이 많았던 Controller와 Repository쪽을 개발 관점에서 매우 쉽고 편하게 처리해줘 가장 중요한 핵심 비즈니스 로직인 Service 레이어에 더 집중 할 수 있도록 하게 해준다는 이유를 꼽기도 합니다.

 

 

 

728x90
반응형
LIST

'개발 > Spring' 카테고리의 다른 글

spring 서버 연결 메모만들기  (0) 2023.02.04
mvc  (0) 2023.02.04
JPA 연습!  (0) 2023.02.04
SQL 설정 및 연습!  (0) 2023.02.03
웹 동작방식 이해하기  (1) 2023.02.03
728x90
반응형
SMALL

웹 동작방식 이해하기

웹의 동작방식

IP 주소란?

image from PIXABAY

거대한 네트워크망에서 여러분의 컴퓨터를 식별하기 위한 위치 주소 입니다.

지금은 실제로 네트워크라는 공간에서 여러분 컴퓨터의 집주소라고 비유적으로 생각하셔도 좋습니다.

네트워크상에서의 데이터 송/수신은 이 주소를 기준으로 이루어지고 있습니다.

 👌 192.168.0.123 와 같이 생긴 숫자가 IP주소라고 불리는 것을 본 적 있으시죠?

 

브라우저란?

image from PIXABAY

지금 여러분이 사용하고 계시는 크롬, 사파리, 엣지와 같이

웹페이지, 이미지, 비디오등의 컨텐츠를 송/수신하고 표현해주는 소프트웨어입니다.

👌 브라우저가 해주는 일 중 그래도 가장 큰 일 두가지를 명심하면 좋을 것 같습니다 ”컨텐츠를 송/수신한다”, “컨텐츠를 표현한다” 그리고 지금은 “컨텐츠를 송/수신한다”에 초점을 더 맞춰볼까 합니다.

 

지금 모두 이야기 할 수 없지만, 컴퓨터, 전기신호등은 0과 1밖에 표현하지 못합니다. 데이터의 송/수신 역시 0과 1의 아날로그 신호로 이루어지는데, 여러분의 브라우저는 여러분의 메세지가 OSI 7 계층을 거쳐 랜선을 통해 0과 1로 변경되어 흘러갈 수 있도록 여러분을 도와주는 응용프로그램이자, 여러분과 상호작용해서 요청을 보내는 응용프로그래밍 계층의 첫 출발점입니다.

DNS(Domain Name Server)란?

image from PIXABAY

개발자가 아닌 일반적인 삶을 살 때 IP주소와 같은 것들을 접할 기회는 거의 없습니다. 우리가 실제로 웹 브라우저를 열고 웹 사이트로 이동할 때는 긴 숫자를 기억해 입력한적은 없죠. 그 대신 abcdefg.com과 같은 도메인 이름 을 입력해서 원하는 웹 사이트로 이동해왔습니다.

어떻게 이런일이 가능했을까요?

바로 중간에 여러분의 요청을 받아줄 서버의 IP주소(192.168.0.123)와 여러분이 외우고 있는 도메인 이름을 중개해주는 전화번호부와 같은 서버가 중간에 있었기 때문입니다.

IP 주소 Domain 이름

192.168.0.123 www.hello.com
192.168.0.124 www.world.com

실제로도 위와 같은 모습으로 되어 있는 중개 서버가 있기에, 여러분은 도메인 이름(사이트 주소)만 외워도 목적지를 알 수 있어 요청을 보낼 수 있게 됩니다.

서버로 요청을 보낸다면?

🤔 요청을 받을 주소(IP주소)도 알았고, 요청을 보낸 주소도 알았고(DNS를 통해서), 요청을 송/수신해주는 도구도 있는데 그러면 요청을 보낼 수 있겠네요?

 

네이버의 도메인이 www.naver.com 이라는건 알고 있고, DNS를 통해 받아온 주소가 (192.0.0.0)이라고 생각하고, 내 IP주소가 (192.0.0.1)이라고 생각하고 요청을 보내볼까요?

 🙂 to. 192.0.0.0 안녕하세요! 저는 192.0.0.1 라는 IP를 가지고 있는 사람인데요! 저에게 네이버의 첫 페이지의 html/css/js를 조금 주실 수 있나 해서요! 제 IP 주소로 보내주시면 될 것 같아요.

 🙃 (네이버의 서버 개발자) : ….

서버개발자 입장에서 저 요청을 어떻게 받아들여야 할까요?

서버 프로그램도 결국 컴퓨터고, 사람이나 ai가 아닌 컴퓨터 프로그램입니다.

여러분이 프로그래밍을 한다면 어떻게 해야 할까요?

사실 저렇게 메세지를 보낸다면, 결국 저 요청의 텍스트를 “\n”으로 자르고,

정규식으로 데이터를 각각 받아서 잘라줘야 할 겁니다.

만약 어떻게든 요청을 처리했는데, 다른 사람은 또 다르게 보내면 어쩌죠?

사람마다 코드를 다시 짜야 할까요?

여기서 여러분들이 잘 알고있는 메세지 송신자와 수신자가 공유하고 있는 “약속”의 개념이 등장합니다.

HTTP란 ??

image from PIXABAY

다시 돌아와서 요청을 보내고 받는 상호간에 “**약속”**을 하고 있다면 어떨까요?

예를 들어 요청을 보내는 사람은

첫줄에 주소를 적고,

두 번째 줄에 자신의 IP주소를 적고,

세 번째 줄에 보내고자 하는 정보를 적고,

각각의 정보를 “ : “ 로 구분해서 적겠다고 약속하고,

상호간에 “**그 약속을 공유”**하고 있다면 어떨까요?

🤔 Request URL : www.naver.com Address : 192.0.0.1 … Request Body : “네이버 첫 페이지 데이터좀 주세요!”

 

모든 요청이 이처럼 약속된 방식으로 들어오고 모든 응답도 양식을 정해뒀다면, 그 요청을 일괄로 처리 할 수 있게 됩니다. 멀리 떨어져서 서로에 대한 정보가 없는 메세지의 송/수신자가 서로 필요한 요청과 응답을 할 수 있도록 미리 규약을 정해놓은 것을 **“프로토콜”**이라고 하고, 웹 상에서는 HTTP 라는 프로토콜을 통해서 데이터를 송/수신 하고 있습니다.

여러분이 서버개발자가 되고자 한다면, 혹은 프론트엔드 개발자로 직군을 변경한다고 해도, 웹 프로그래밍을 하려면 HTTP라는 프로토콜을 정확하게 이해하고 있어야, 정확하게 요청을 받고, 요청을 처리한 결과를 응답 할 수 있습니다. 다만 너무 걱정할 필요 없는 것은, HTTP 프로토콜이 웹 프로토콜중 가장 많이 사용 되는 이유는 상대적으로 간단하고 쉽기 때문이기에 여러분들이 적당한 시간만 투자한다면, 주요한 내용을 습득하는데 어려움이 있지 않을거에요. 물론 더 자세한 내용은 조금 더 뒤에 다루도록 하고, 지금은 이러한 통신 규약이 있어서 클라이언트와 서버간에 메세지를 주고받을 수 있다고 생각해주시면 좋을 것 같습니다.

🙂 더 자세한 http 관련 내용이 궁금하시다면, 아래 보너스 자료를 이용해주세요!

HTTP 이해

 

드디어 요청이 서버에 도달했습니다!

잘 따라오셨다면, 지금까지 한 이야기가 “우리가 지금까지 이야기 한 내용!!” 이라고 적힌 부분에 대한 이야기라는 것을 이해하실 수 있으실 겁니다. 결과적으로 클라이언트(지금까지 웹서핑을 해오던 우리)의 요청은 서버에 도달했고, “**API”**라는 서버의 창구와 같은 곳에 도달합니다. 그리고 당연하게도 지금부터 이야기들은 전부 우리가 “서버 개발자”로서 실제로 코딩을 해야하는 부분과 관련된 이야기 입니다.

API(application programming interface)는 다른 소프트웨어 시스템과 통신하기 위해 따라야 하는 규칙을 정의합니다. 개발자는 다른 애플리케이션이 프로그래밍 방식으로 애플리케이션과 통신할 수 있도록 API를 표시하거나 생성합니다. 예를 들어, 근무 시간 기록 애플리케이션은 직원의 전체 이름과 날짜 범위를 요청하는 API를 표시합니다. 이 정보가 수신되면 내부적으로 직원의 근무 시간 기록을 처리하고 해당 날짜 범위에서 근무한 시간을 반환합니다.

웹 API는 클라이언트와 웹 리소스 사이의 게이트웨이라고 생각할 수 있습니다.

인터페이스(interface)는 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다. 즉, 사용자가 기기를 쉽게 동작시키는데 도움을 주는 시스템을 의미한다. 컴퓨팅에서 컴퓨팅 시스템끼리 정보를 교환하는 공유 경계이다. 이러한 교환은 소프트웨어, 컴퓨터 하드웨어, 주변기기, 사람간에 이루어질 수 있으며, 서로 복합적으로 이루어질 수도 있다.

아직 설명이 와닿지 않는다면, 하나의 "약속" 이자, 서로 다른 어플리케이션 간에 약속한 방식으로 요청을 하면 정해진 결과물, 즉 요청을 받아 응답을 돌려주는 식당의 점원이라고 비유적으로 이해하셔도 좋을 것 같습니다.

이 부분은 우리 모두가 들었던 웹개발 플러스 강의 내용을 떠올려보면 좋을 것 같습니다.

from flask import Flask

def create_app():
    app = Flask(__name__)

    @app.route('/PrintHelloWorld')
    def hello_world():
        return 'Hello, World!'

    @app.route('/HelloWorldTemplate')
    def hello_world():
        return render_template('HelloWorldTemaplate")

    return app

우리의 서버 역할을 해주던 플라스크에 있었던 위와 같은 코드가 기억나시죠? 도메인 이름 뒤에 오는 양식을 맞춰주기만 하면 플라스크가 알아서 해당 함수를 호출해줬던 것을 기억하실겁니다.

 🙂 만약 우리의 도메인이 (www.serverDeveloper.com)이고, 도메인 뒤에 @app.route()안에 들어간 정보들을 써주면, 해당 어노테이션이 붙어있는 함수가 호출되었습니다.

www.serverDeveloper.com/HelloWorldTemplate ⇒ HelloWorldTemplate이라는 html/css/javascript 로 구성된 template이 클라이언트로 전송되어 브라우저가 그려주게됩니다. 아마도 해당 template에는 그 “웹페이지”안에서 다른 요청을 보낼 수 있는 ajax와 같은 코드들도 포함되어 있어 연속적으로 웹페이지를 이용 할 수 있게 하겠죠?

 

즉 @app.route()와 같은 표시가 붙은 함수들이 사용자들의 요청을 가장 먼저 맞이해주는 역할을 해줬고, 이러한 역할과 명세를 잘 정리해두면 api 명세가 되고, 우리 서버 프로그램의 식당 점원의 역할을 해줬던 겁니다.

🤔 그러면 서버는 요청을 받아 html/css/js 파일을 반환해주는게 주 업무인가요?

☝ 당연히 정답은 없지만, 최근의 경향으로는 그렇지는 않습니다. 예전에는 조금 더 그랬었던 편이지만, 웹 생태계가 고도화 되는 과정중에 상대적으로 프론트엔드와 백엔드가 각각 따로 발전하게 되면서, 느슨하게 결합하는 방식을 더 많이 채택하게 되었고, 최근에는 서버가 직접 뷰(html/css/js)를 반환하기 보다는 요청에 맞는 특정한 정보만 반환하는 것을 조금 더 선호하기도 합니다. 그래서 요즘에는 주로 서버는 JSON이라는 형태로 데이터만 반환하기도 하는데, 보통 이렇게 생겼습니다!

 

RESTful API란?

REST란 무엇인가요?

Representational State Transfer(REST)는 API 작동 방식에 대한 조건을 부과하는 소프트웨어 아키텍처입니다. REST는 처음에 인터넷과 같은 복잡한 네트워크에서 통신을 관리하기 위한 지침으로 만들어졌습니다. REST 기반 아키텍처를 사용하여 대규모의 고성능 통신을 안정적으로 지원할 수 있습니다. 쉽게 구현하고 수정할 수 있어 모든 API 시스템을 파악하고 여러 플랫폼에서 사용할 수 있습니다.

API 개발자는 여러 아키텍처를 사용하여 API를 설계할 수 있습니다. REST 아키텍처 스타일을 따르는 API를 REST API라고 합니다. REST 아키텍처를 구현하는 웹 서비스를 RESTful 웹 서비스라고 합니다. RESTful API라는 용어는 일반적으로 RESTful 웹 API를 나타냅니다. 하지만 REST API와 RESTful API라는 용어는 같은 의미로 사용할 수 있습니다.

RESTful API란 무엇인가? - RESTful API 초보자 가이드 - AWS

걱정마세요 지금은 이해가 어려워도 나중에 http를 더 알게되면 알 수 있습니다.

조금 일반적으로 쉬운 말로 바꾸면, 여러분 서버의 api가 적절하게 http를 준수하며 잘 설계되어있으면 RESTful 하게 설계되어 있다고 당분간은 이해하셔도 좋을 것 같습니다.

예를들어 여러분이 api의 리소스 식별자를 ex - (”/”) 중복 없이 고유하게 잘 만들고,

해당 api에 적절하게 http메서드를 사용했다면, RESTful하게 설계했다고 볼 수 있겠죠?

 🤔 지금은 여러분 서버의 api가 HTTP 프로토콜을 잘 준수하면 저렇게 멋있는 형용사가 붙는다는 정도로만 기억하면 좋을 것 같습니다! RESTful!

 

서버가 요청을 처리하기 위한 자료들?

우리가 서버로 특정한 요청을 처리하는데, 필요한 것이 하나 더 있습니다.

그리고 그 부분을 지금 이야기 해 보려고 합니다.

마찬가지로 우리가 웹개발 플러스 강의를 들으며 진행했던 로그인 로직을 생각해보면 좋을 것 같습니다.

@app.route('/sign_in', methods=['POST'])
def sign_in():

    username_receive = request.form['username_give']
    password_receive = request.form['password_give']

    pw_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
		# 여기!!!!
    result = db.users.find_one({'username': username_receive, 'password': pw_hash})

    if result is not None:
        payload = {
         'id': username_receive,
         'exp': datetime.utcnow() + timedelta(seconds=60 * 60 * 24)  # 로그인 24시간 유지
        }
        token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')

        return jsonify({'result': 'success', 'token': token})
    
    else:
        return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})

클라이언트의 요청이 네트워크를 타고 들어와서, “새로운 정보”인 유저의 ID/Password를 들고 들어왔습니다.

@app.route('/sign_in', methods=['POST'])

이제는 위와같은 어노테이션을 통해 sign_in 메서드가 요청을 처리하기 위해 점원의 역할을 한다는 것도 알게 되었죠

하지만 우리에게는 한 가지 정보가 더 필요합니다. 바로 “기존의 정보” 입니다.

기존의 정보가 있어야 유저가 로그인을 시도하려는 아이디 비밀번호와 같이 대조 해 볼 수 있겠죠?

그리고 그러한 정보는 이미 생성되어 가지고 있거나, 서버의 동작을 통해서(예를들어 회원가입과 같은) 저장되어 활용이 가능해야 합니다.

보통의 서버는 위와 같은 필요성 때문에, 데이터를 저장하고 관리하는 데이터베이스를 두게 됩니다.

“여기 !!!!” 라고 주석처리된 부분의 코드를 보시면 알 수 있듯 우리는 웹개발 플러스 프로젝트에서 몽고디비라는 데이터 베이스를 이용했었죠.

하지만 일반적으로 몽고디비와 같은 데이터베이스는 빅데이터 등 특정 도메인에서 매우 유용하지만, 우리가 앞으로 처리할 다양한 상황에서 아쉬운 점이 있습니다. 그래서 우리는 곧 산업군에서 가장 많이 사용되고 있는 관계형 데이터 베이스에 대해서도 알아볼 예정입니다.

 🤔 데이터베이스는 왜 있으며, 왜 다양한 종류가 있나요?

👉 처음 접하는 분들이 가장 쉽게 오해하기로는, “정해진 공간에 최대한 많은 데이터를 저장하기 위해서” 일 겁니다. 하지만 사실 데이터베이스는 데이터를 “효율적으로 성능 좋게” 다루기 위해 존재합니다.

즉 더 많이 저장하기 위해서가 아니라, 저장 조회 수정 삭제등을 더 빠르고 효율적으로 처리하기 위해서, “성능상의 이점”을 얻기 위해서 사용한다고 생각하면 좋을 것 같습니다.

이러한 맥락에서 데이터를 사용,활용하는 주체에 따라서 더 효율적인 방법이 각각 다르다 보니 다양한 형식의 데이터베이스가 존재하게 됩니다.

결론

👉결론적으로 서버 개발에서 그래도 가장 많이 하는 일은, “새로운 정보”와 “기존의 정보”를 가지고 “정해진 로직”을 수행하는 일 입니다. 위와같은 이야기를 하기 위해서, 0. 기존에 알고있던 웹 프로그램이 어떻게 동작하는지를 살펴봤고 1. 어떻게 새로운 정보인 클라이언트의 요청이 서버로 도달하는지를 살펴봤고 2. 어떻게 기존의 정보를 저장하는지를 살펴봤습니다. 다음시간에는 이 세가지 맥락을 그대로 가져가면서 드디어 우리의 주특기인 스프링 부트를 설명해보려 합니다!

 

728x90
반응형
LIST

'개발 > Spring' 카테고리의 다른 글

spring 서버 연결 메모만들기  (0) 2023.02.04
mvc  (0) 2023.02.04
JPA 연습!  (0) 2023.02.04
SQL 설정 및 연습!  (0) 2023.02.03
SpringBoot 및 서버 이해  (0) 2023.02.03
728x90
반응형
SMALL

의존성 역전 원칙

Dependency Inversion Principle, DIP

**“고차원 모듈은 저차원 모듈에 의존하면 안 된다. 이 두 모듈 모두 다른 추상화된 것에 의존해야 한다.”“추상화된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다.” "자주 변경되는 구체(Concrete) 클래스에 의존하지 마라“ - 로버트 C. 마틴

세부적인 사항은 추상화에 의존해야 합니다.

의존성 역전 원칙을 적용한 대표적 사례로는 이전 OCP 에서 설명했던 JDBC 에서 찾아볼 수 있습니다.

또한 OCP 에서 본 계산기 예제도 마찬가지입니다.

의존성 역전 원칙을 위반한 계산기

원칙 위반 증상

저수준 모듈에서 변경이 발생되면 고수준 모듈에 수정사항이 발생합니다.

public class Calculator {
    private AddOperation addOperation;
    private SubstractOperation substractOperation;
    private MultiplyOperation multiplyOperation;
    private DivideOperation divideOperation;

    public Calculator(AddOperation addOperation, SubstractOperation substractOperation, MultiplyOperation multiplyOperation, DivideOperation divideOperation) {
        this.addOperation = addOperation;
        this.substractOperation = substractOperation;
        this.multiplyOperation = multiplyOperation;
        this.divideOperation = divideOperation;
    }

    public int calculate(String operator, int firstNumber, int secondNumber) {
        int answer = 0;

        if(operator.equals("+")){
            answer = addOperation.operate(firstNumber, secondNumber);
        }else if(operator.equals("-")){
            answer = substractOperation.operate(firstNumber, secondNumber);
        }else if(operator.equals("*")){
            answer = multiplyOperation.operate(firstNumber, secondNumber);
        }else if(operator.equals("/")){
            answer = divideOperation.operate(firstNumber, secondNumber);
        }

        return answer;
    }
}
public class Client {
    public static void main(String[] args) {
        Calculator calculator = new Calculator(
                new AddOperation(),
                new SubstractOperation(),
                new MultiplyOperation(),
                new DivideOperation()
        );

        int firNum = 140;
        int secNum = 60;

        String operator = "+";
        int answer = calculator.calculate(operator, firNum, secNum);
        System.out.println(operator + " answer = " + answer);

        operator = "-";
        answer = calculator.calculate(operator, firNum, secNum);
        System.out.println(operator + " answer = " + answer);

        operator = "*";
        answer = calculator.calculate(operator, firNum, secNum);
        System.out.println(operator + " answer = " + answer);

        operator = "/";
        answer = calculator.calculate(operator, firNum, secNum);
        System.out.println(operator + " answer = " + answer);
    }
}
public class AddOperation {
    public int operate(int firstNumber, int secondNumber){
        return firstNumber + secondNumber;
    }
}
public class SubstractOperation {
    public int operate(int firstNumber, int secondNumber){
        return firstNumber - secondNumber;
    }
}
public class MultiplyOperation {
    public int operate(int firstNumber, int secondNumber){
        return firstNumber * secondNumber;
    }
}
public class DivideOperation {
    public int operate(int firstNumber, int secondNumber){
        return firstNumber / secondNumber;
    }
}

계산기(고수준 모듈)가 개별 연산 클래스(저수준 모듈)을 포함하며 계산 기능을 구현할 때 연산 클래스에 의존하고 있습니다.

원칙 적용 방법

고수준 모듈의 변화되는 부분을 추상화합니다.

저수준 모듈을 추상화에 의존시킵니다.

계산기 클래스에 추상화된 부모 클래스를 포함시킵니다.

연산 클래스는 추상화된 부모 클래스를 상속받아 기능별로 구현합니다.

AbstractOperation : 추상 클래스

operate : 추상 메서드

728x90
반응형
LIST

'개발 > JAVA' 카테고리의 다른 글

열거형  (0) 2023.02.23
생성자와 세터의 차이  (0) 2023.02.10
인터페이스 분리 원칙  (0) 2023.01.27
리스코프 치환 원칙  (0) 2023.01.27
개방-폐쇄 원칙  (0) 2023.01.27

+ Recent posts