semtax의 개발 일지

스프링부트로 게시판 만들기 1 : 스프링 부트 소개 및 환경 설정 본문

개발/Java

스프링부트로 게시판 만들기 1 : 스프링 부트 소개 및 환경 설정

semtax 2020. 1. 16. 23:21
반응형

개요

이번 시리즈 에서는 스프링 부트를 이용해서 간단한 웹 서버를 만들어 보도록 하겠습니다.

게시판을 만들기에 앞서 이번 포스팅에서는, 스프링 부트가 무엇인지에 대해서와 환경설정을 하는법을 다루도록 하겠습니다.

스프링 부트란?

스프링 부트를 설명하기 전에 먼저 스프링 프레임워크에 대해서 간략하게 설명하도록 하겠습니다.

맨 처음 소프트웨어의 위기가 찾아왔을때, 사람들은 그 고민을 해결하기 위해 객체지향 프로그래밍(OOP) 이라는 패러다임을 도입하였습니다. 하지만 막상 객체지향 프로그래밍을 도입하였음에도 이전보다는 생산성이 늘기는 했지만, 생각 보다 재사용성도 잘 되지 않았고, 유지보수도 여전히 힘들었습니다. 객체지향이나 절차지향, 함수 지향 패러다임 이전에 보다 근본적인 원인을 해결하지 못한 것이지요.

과연 무엇이 원인이었을까요? 바로 코드 의존성과 결합도 입니다. 즉, 코드 의존성(결합도)은 낮추고 응집성은 높여야 된다는 말입니다.

코드 의존성이 무엇인지는 여러분도 많이 프로그래밍을 하면서 겪어보셨을겁니다. 한 가지 상황을 가정 하도록 하겠습니다.

 

프로젝트를 하는데, 이미 코드가 많이 짜여진 상태입니다. 한 클래스 50개에 3만줄 정도 되는 코드라고 가정을 해봅시다. 그런데 어느날 프로그램을 짜다보니 버그가 발생했습니다. 다행히도 당신은 빠르게 그 원인을 발견하였습니다. 하지만, 그 코드를 고치기 위해서는 약 클래스 30개에 존재하는 코드 1만줄을 뜯어 고쳐야한다는 사실을 깨닫게 되었습니다. 하지만 프로젝트 마감은 고작 하루밖에 남지 않았습니다.

 

그렇습니다. 바로 위에서 나온 하나를 고치기 위해 수많은 코드를 뜯어 고쳐야 하는 상황 이 바로 코드 의존성이 높다는 말입니다. 즉, 저러한 상황을 방지하기 위해서는 코드 의존성을 낮춰야 합니다.

또 한가지의 상황을 가정하도록 하죠.

 

프로젝트를 하는데, 역시나 이미 코드가 많이 짜여진 상태입니다. 다행히도 당신은 코드 의존성에 대한 개념을 알기 때문에, 모듈을 쪼개면서 개발을 하였습니다. 그러나 너무 코드를 잘게 쪼갠 나머지 단 200줄 짜리 프로그램인데 클래스가 한 40개정도가 되는 상황이 발생했습니다. 결국 당신은 겨우 수십줄의 코드를 고치기 위해 10개넘는 클래스를 돌아다니면서 일일히 다 뜯어 고쳐야 되는 상황이 발생했습니다. 이런;;

 

위에서 나온 상황 같이 서로 유사한 역할을 하는 코드들은 같이 모아둬야 한다는 것이 바로 코드 응집성을 말하는 것입니다.

이러한 관계 없는 코드 의존성(결합도)을 낮추고 관계있는 코드간의 응집성를 높혀서 재사용성과 유지보수, 개발의 생산성을 높이는 주요한 5가지 원칙이 존재합니다. 바로 할리우드 원칙과 SOLID원칙입니다.

할리우드 원칙은 단 한 문장으로 설명됩니다.

 

You don't call me, I'll call You(당신이 나를 부르는게 아니야, 내가 당신을 부르는 거지)

 

즉 프로그램의 전체적인 제어 흐름을 사용자가 아닌 이미 만들어진 코드(즉 프레임워크)에 맡기는 것입니다. 이렇게 함으로써, 사용자는 이미 만들어진 흐름에 자기의 코드를 끼워 넣기만 하면 되기 때문에 프레임워크와 사용자의 역할이 분리가 되는것이지요.

SOLID는 아래의 5가지 원칙을 말하는 것입니다.

 

  • Single Responsibility Principle(단일 책임의 원칙)
  • Open-Closed Principle(개방 폐쇄 원칙)
  • Liskov's Principle(리스코프의 원리)
  • Interface Segregation Principle(인터페이스 분리의 원칙)
  • Dependancy Inversion Principle(의존성 역전의 법칙)

즉 요약하면, 한 모듈은 한가지의 일만 잘 해야하고, 기존 코드를 수정하지 않고 코드를 추가하는것이 두렵지 않아야 하고, 인터페이스로 역할을 분리하여 코드간의 의존성을 낮춰야 된다는 말입니다. (사실 리스코프 원칙도 비슷한 관계, 즉 상속관계에 있는 객체 간에 있어서 부모 클래스 대신 자식 클래스로 대체해도 된다는 말이니 코드 유지보수에 결국 도움이 되는 원칙이지요.)

사실 절차지향적 언어인 C로 이러한 5가지 원칙과 할리우드 원칙을 잘 지켜서 프로그래밍 하고 있는 아주 거대한 프로젝트가 존재합니다. 바로 리눅스와 유닉스 커널입니다.

 

아래가 리눅스 커널에서 C로 인터페이스를 구현한 예제입니다.

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iopoll)(struct kiocb *kiocb, bool spin);
  ....
};

 

그리고 실제 C로 프로그래밍 하는 사용자는 다음과 같이 프로그래밍 합니다.

 

#include<stdio.h> 
#include <fcntl.h> 

int main() 
{ 
  int fd, sz; 
  char *c = (char *) calloc(100, sizeof(char)); 

  fd = open("foo.txt", O_RDONLY); 
  if (fd < 0) { perror("r1"); exit(1); } 

  sz = read(fd, c, 10); 
  printf("called read(% d, c, 10).  returned that"
         " %d bytes  were read.\n", fd, sz); 
  c[sz] = '\0'; 
  printf("Those bytes are as follows: % s\n", c); 
} 

 

즉, 파일을 어떠한 방식으로(어떤 파일시스템을 쓰는지) 읽고 쓰는지 실제 사용자가 전혀 알지 못하더라도 이와 같은 추상화를 통해 역할을 분리함으로써 여러가지 디바이스나 파일시스템에 대응해서 I/O 작업을 수행할 수 있는겁니다.

이와 비슷하게 스프링은 저 5가지의 원칙과 할리우드 원칙을 잘 반영한 프레임워크 입니다. 스프링은 DI(의존성 주입)를 이용해서 저 5가지의 원칙을 잘 지켜가며 아주 우아하게 대규모 프로젝트를 빠르고 정확하게 개발 할 수 있는것입니다.

 

하지만 스프링에도 단점이 존재합니다. 애초에 대규모 엔터프라이즈 용으로 개발을 한것이기 떄문에 수많은 설정들이 존재하고, 그만큼 설정이 엄청나게 복잡합니다. 또한 각 버전별 의존성을 맞추는것도 힘듭니다. 사실 개인이 심심풀이로 만드는 프로젝트에 적용하기에는 조금 과합니다.

 

또한, 생산성을 위해 저런것이 나왔지만 역설적으로 저런 복잡한 설정과 의존성 문제 때문에 오히려 저런 환경설정과 트러블 슈팅에 개발시간을 과도하게 뺏기는 일이 발생합니다.

 

실제로 빠른 프로토타입 출시가 목표인 스타트업에서 처음만드는 프로젝트를 스프링으로 진행하는 경우는 거의 없습니다.

이러한 단점을 보완 하기 위해 스프링 부트가 나왔습니다. 스프링 부트는 저러한 복잡한 설정과 각 버전별 의존성 문제를 쉽게 해결할수 있게 해주는 여러가지 편리한 기능들을 제공합니다.

 

자 그럼 이제 스프링부트를 맛볼 차례입니다!

 

본 포스팅은 다음과 같은 환경에서 진행하였습니다

  • OS : MAC OS X 10.15(카탈리나)
  • IDE : IntelliJ
  • JDK : Java 8

설치 및 환경설정

먼저 인텔리 제이를 켜서 Maven 프로젝트를 생성합니다.

폴더 구조는 아래와 같습니다.

 

그런뒤 pom.xml(즉 메이븐 설정 파일을 아래와 같이 작성합니다.)

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>springwebexample</groupId>
    <artifactId>com.semtax.springwebexample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>demospringmvc</name>
    <description>Demo Project</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

 

그런 뒤 com.semtax.application 패키지를 생성하고 그 안에 SemtaxApplication.java 파일을 생성 한뒤, 아래와 같이 작성합니다.

 

package com.semtax.application;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SemtaxApplication {
    public static void main(String[] args) {
        SpringApplication.run(SemtaxApplication.class, args);
    }
}

 

그 다음, com.semtax.application 패키지 안에 controller 패키지를 생성하고 그 안에 BasicController 라는 클래스 파일을 작성합니다.

 

package com.semtax.application.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BasicController {

    @GetMapping("/")
    public String hello(){
        return "Hello World!";
    }
}

 

그런뒤 다시 Application.java로 가서 실행 버튼을 눌러줍시다.

 

실행이 되면 브라우저를 켜서 http://localhost:8080/ 으로 접속하면 브라우저에 "Hello World!" 라는 문자열이 떠있는 것을 볼 수 있습니다.

 

 

이상으로 본 포스팅을 마치도록 하겠습니다.

 

다음시간에는 스프링 JPA를 이용해서 데이터베이스를 연동 하는 법을 배워보도록 하겠습니다.

반응형
Comments