[인프런 워밍업 스터디 클럽 1기] 첫번째 발자국

[인프런 워밍업 스터디 클럽 1기] 첫번째 발자국

원본 : https://itaekit.tistory.com/12

들어가기 전에


인프런 워밍업 클럽 스터디 1기에 참여하게 되었다.

함께 성장하는 즐거움을 맛보고 싶었고,

커뮤니티로부터 동기부여도 받고 싶었고,

무엇보다 막막하기만했던 독학에서 방향성을 얻고 싶었다.

3주 간의 여정에서 많은 성장을 해내고 싶다.

인프런 워밍업 클럽 스터디 소개


인프런에서 주최하는 온라인 스터디다.

이번 1기의 경우 Backend(Java/Spring), Frontend(JS/React), Product Design(Figma) 과정이 운영된다.

각 과정마다 강사와 서포가 배정되고 강사님의 인프런 강의를 수강하게 된다.

내가 참여하게 된 BE 스터디의 경우

총 4주 진행 중 3번의 온라인 세션이 예정되어 있다.

혼자서 강의를 듣고 공부했던 여태까지의 방식과 다르게,

커뮤니티에 참여해 함께 공부하게 되고 강사님 가까이서 배울 수 있단 점이 참 매력적이다.

또한,

과제 및 미니프로젝트가 제공되어 더욱 견고한 학습을 할 수 있고,

현직자의 멘토링을 받으며 학습의 방향성을 잡을 수 있단 점이 가장 큰 차별점이라고 생각한다.

뿐만 아니라,

수료자/우수 수료자를 뽑아 소정의 장학금, 굿즈, 인프콘 티켓, 1:1 멘토링 등이 제공되어 동기부여가 된다.

(굿즈 갖고 싶다...)

첫번째 Online Session : OT , 이런것 까지 알아야 할까?


온라인 세션을 통해 강사님과 첫번째 만남을 가졌다.

전반적인 과정 소개와 함께 과정에 앞서 알고 있으면 좋을 사전 지식들을 설명해주셨다.

Java는 컴파일 언어일까, 인터프리터 언어일까?

Compile

고급 언어로 작성된 소스코드를 로우 레벨의 기계어로 번역하는 과정이다.

한 번에 전체 코드를 모두 기계어로 번역하기 때문에 컴파일 이후 실행 속도가 빠르다는 장점이 있다.

Java의 경우 .java -> .class(Bytecode)가 컴파일 과정에 해당한다.

Interpreter

컴파일 방식과 다르게 소스코드 한 줄 씩 읽어들여 런타임으로 번역하는 과정이다.

Java의 경우 JVM이 .class를 실행할 때 처리하는 방식이다.

Java는 컴파일 언어일까, 인터프리터 언어일까?

Write Once, Run Anywhere
- James Gosling

Java는 두 방식 모두 채택하고 있다.

먼저 Bytecode로 컴파일 하고 이를 플랫폼별로 최적화된 JVM이 인터프리터 방식으로 실행한다.

이를 통해,

기존 컴파일 언어의 단점이었던 OS 종속을 해결했고,

기존 인터프리터 언어의 단점이었던 타입 불안전성을 극복할 수 있게된다.

JIT (Just-In Time) Compiler

인터프리터 언어의 단점은 실행 속도가 느리다는 점이다.

이를 극복하기 위해 JVM은 Just-In Time Compiler라는 기술을 사용한다.

JIT Compiler는 바이트코드를 분석하고,

자주 실행되는 코드 블록을 미리 구분하여 Native machine code로 컴파일하여 실행 속도를 높인다.

물론 장점만 얻을 수는 없다.

JIT Compiler는 애플리케이션 최초 배포시 사용된 적 없는 코드로 인해 분석에 많은 리소스가 발생하게 된다.

이를 해결하기 위해 배포 전 미리 웜업을 거쳐야한다.

JVM, JRE, JDK

JVM (Java Virtual Machine)

Bytecode를 읽고 검증하여 실행하는 가상 머신이다.

OS별로 최적화되어있어 동일한 Bytecode에 대해 플랫폼별 실행을 가능하게 한다.

JRE (Java Runtime Envrionment)

JVM 및 실제 실행에 필요한 여러 라이브러리 파일 포함하는 실행 환경

JDK (Java Development Kit)

JRE 및 Compiler, Debugger 등 포함하는 개발 환경

Build, Build Tools

Build

소스파일로 부터 Artifact를 생성하는 일련의 과정

  1. 소스코드 컴파일

  2. 테스트코드 컴파일, 실행, 리포트

  3. 기타 추가 설정 작업

  4. 패키징

  5. Artifact 생성

Build Tools

Build 자동화 관리 프로그램으로 대표적으로 Gradle(Groovy), Maven(xml) 사용

짧은 회고

Java/Spring이 처음인 내게,

강사님의 모든 말들은 그 자체로 지식의 확장이었다.

간간히 들어서 익숙하긴한데,

실제 내용을 알지 못하는 부분에 대해 많이 알아갈 수 있었다.

이런 기본적인 것들을 왜 두려워하기만 했을까?

알아간다는 즐거움과 함께 앞으로 알아가야 할 것들이 얼마나 많을까라는 걱정도 공존했지만,

정말 오랜만에 능동적으로 학습하는 기분이 들어 행복했다.

Day 01 : 서버 개발을 위한 환경 설정 및 네트워크 기초


첫째날 학습한 내용은 아래와 같다.

  1. 스프링 프로젝트를 시작하는 방법

  2. 서버 개발에 필요한 기본 지식

  3. 간단한 API 작성 및 테스트

스프링 프로젝트 시작

스프링 프로젝트를 시작하는 방법은 크게 2가지다.

  1. 기존 프로젝트를 다운 받아 시작

  2. spring initializr를 사용해 새 프로젝트 생성

1번의 경우,

프로젝트를 위한 모든 의존성 및 설정이 완료되어 있어 바로 시작할 수 있다.

2번의 경우,

프로젝트를 위한 모든 의존성 및 설정을 직접 지정해야한다.

spring initializr 사용해 프로젝트 생성하기

spring initializr에 접속해 프로젝트를 설정한다.

각 항목에 대한 내용은 아래와 같다.

  • Project : 프로젝트에 사용될 Build Tools 선택

  • Language : 프로젝트에 사용될 Main language

  • Spring Boot : Spring Boot의 Version을 지정

    • 괄호가 있는 version의 경우, 베타버젼이므로 안정적인 프로젝트를 위해 소괄호 없는 버전 선택을 권장

  • Project Metadata : 프로젝트의 메타데이터를 지정

    • Group : 그룹명, 일반적으로 도메인 작성

    • Artifact : 애플리케이션 이름

    • Name : 프로젝트 이름, 별도의 지정이 없는 경우 artifact명을 따름

    • Description : 프로젝트에 대한 설명

    • Package Name : 패키지명, Group과 Artifact의 조합으로 작성됨

    • Packaging : 패키징 방식 지정

    • Java : JDK Version

  • Dependencies : 프로젝트에서 사용할 Library, Framework 등 의존성 설정

Library vs Framework

  • Library : 프로그래머가 미리 만들어져 있는 기능을 가져와 사용

  • Framework : 프레임워크가 프로그래머의 코드를 가져가 사용

Server Programming 기본 개념 : Server, Network, HTTP,  URL,  API

Server

요청에 대한 응답을 처리하는 컴퓨터 또는 프로그램

Network

네트워크란,

노드 간 연결로 형성된 디지털 전기통신망이다.

각 노드는 상호연결을 통해 리소스를 공유할 수 있다.

LAN 부터 Internet Network까지 그 범위는 광범위하다.

Internet

인터넷이란,

전세계 컴퓨터 네트워를 연결하는 광범위한 네트워크를 의미한다.

각 디바이스는 각각 Client/Server로 구성되며 TCP/IP 기본 프로토콜을 제공한다.

Web

Internet을 기반으로 HTML 문서 기반의 리소스를 공유하는 기술, 인프라 그 자체

광범위한 Network의 일종인 Internet을 기반으로 HTML Resource를 공유하는 기술 및 Infra 그 자체가 Web이다. 

IP (Internet Protocol)

Internet에서사용되는 통신 규약

IP Address

Internet에 연결된 Device를 식별하기 위해 부여되는 고유 주소

Domain Name

DNS(Domain Name System)에 의해 IP Address와 매핑되어 사용되는 이름으로,

사람이 직접 IP 주소를 다루는 것은 불편하여 고안된 방법

ping www.google.com으로 구글 ip 확인

ex. google에 접속하기 위해 142.250.66.100으로 접속하는 대신 google.com으로 접속

Port

IP를 통해 인터넷에서 하나의 디바이스를 특정할 수 있었다면,

Port를 통해 해당 디바이스의 특정 프로세스에 접근할 수 있게 된다.

즉, Port는 일종의 네트워크상 프로세스의 고유 주소가 되는 셈이다.

HTTP (HyperText Transfer Protocol)

Web에서 사용하는 기본 통신 규약

HTTP Method

서버가 수행해야 할 action을 지정하는 방식으

수행 목적에 따라 GET, POST, PUT, DELETE 등으로 구분된다.

HTTP Request

HTTP Request Format

Client에서 Server로 보내는 HTTP 포맷

첫째줄에 HTTP Method와 함께 Path 정보가 포함됨

HTTP Response

HTTP Response Format

Server에서 Client로 보내는 HTTP 포맷

첫째줄에서 Status Code를 반환

URL (Uniform Resource Locator)

URL Sample

Web 상에 존재하는 Resource의 주소

API (Application Programming Interface)

프로그램간 통신하기 위한 규약

정해진 약속에 따라 특정 기능을 수행

@SpringBootApplication

image

스프링 프로젝트를 실행시키기 위해 필요한 설정들을 모두 자동으로 처리

GET API 개발 및 테스트

@RestController

Controller Class 등록을 위한 어노테이션

@GetMapping(Path)

GET Method에 대한 API 지정을 위한 어노테이션

@RequestParam

Query 추출을 위한 어노테이션

GET API 실습

  • API : GET /add

  • Query로부터 두 정수를 추출하여 더한 값 반환

과제 리뷰

첫째날 과제는 어노테이션에 대한 학습이었다.

소스코드에서 메타데이터를 제공할 수 있는 방법인 어노테이션은

프레임워크에서 적극적으로 활용되기 때문에 어노테이션에 대한 기본적인 학습이 필요했다.

이전까지 써본 어노테이션이라고는 @Override, @FunctionalInterface 정도였지만

이번 과제를 통해 어노테이션에 대한 기본적인 내용을 정리할 수 있었다.

Annotation 기본 지식

소스코드에 메타데이터를 직접 추가하기 위해 고안된 방법으로

JDK 5부터 지원한다.

주석과 같이 로직 자체에 영향을 주진 않지만 코드의 연결 방법, 구조를 변경하므로

실행 흐름을 변경할 수 있다.

컴파일 전처리 대상인 주석과 다르게,

런타임 시점에 사용될 정보를 포함할 수 있다.

클래스, 메서드, 변수 등에 추가할 수 있다.

어노테이션의 종류로는,

기본 제공되는 Built-In 어노테이션,

직접 만드는 사용자 정의 어노테이션,

그리고 사용자 정의 어노테이션을 만들 때 필요한 메타 어노테이션 등이 있다.

어노테이션은 오직 자신이 유효한 프레임워크에서만 동작한다는 특징을 가진다.

ex. @SpringBootApplication은 Spring framework에서 동작하며 실행에 필요한 설정들을 처리한다.

짧은 회고

다음 스텝으로 넘아가는 것에 두려움을 가졌던 내 학습 스타일이 깨져가고 변해가는 귀한 시간이었다.

본격적인 스프링 프레임워크 학습에 앞서 필요한 지식들을 학습할 수 있었다.

그동안 대충 알고 있었던 용어들에 대해 정리하니 개운해졌다고나 할까.

특히 그동안 괜히 어려울 것만 같았던 스프링 프로젝트를 직접 실습해보며

"생각보다 할만한데?"라는 느낌을 받았다.

왜 겁을 먹었던 걸까,

이렇게 즐겁기만 한데!

자,

시작이 반이라고 했던가.

정말 필요한 기본 지식들은 모두 끝났다.

본격적인 스프링 프레임워크의 학습에 뛰어들어보자!

Day 02 : 첫 HTTP API 개발


두번째 날,

POST API 실습을 진행했다.

POST API 개발 및 테스트

조회를 위해 사용했던 GET API와 다르게,

POST API는 Server에 데이터 생성을 요청한다.

생성을 위해 필요한 데이터는 기본적으로 Request Body의 형태로 전달한다.

@PostMapping(Path)

POST API 지정을 위한 어노테이션

@RequestBody

Request Body를 DTO로 받기 위해 사용하는 어노테이션

DTO의 field와 이름이 같은 경우,

자동으로 매핑되어 처리

POST API 실습

  • POST /multiply

  • 전달된 Request Body의 두 Integer 객체로부터 곱을 구하여 전달

유저 생성 API 개발 및 테스트

이어지는 API 실습에서는,

  1. User DTO를 활용하여

  2. User를 생성하는 POST API를 만들고

  3. 전체 User를 조회하는 GET API를 만든다

Controller에서 사용하기 위해 동일한 객체에 대해 다양한 DTO를 설계하였다.

  • Request Body로 받아들이기 위한 DTO

  • 실제 서버에서 사용할 User

  • Response로 사용할 DTO

이를 통해 각 객체의 역할을 구분할 수 있었고,

용도에 맞춰 사용해 개발하기 한결 수월했다.

과제 리뷰

둘째날 과제는 주어지는 API Specification에 따른 API 개발이었다.

그 중,

Query에 날짜를 전달하여 요일을 전달받는 GET API 문제가 가장 재밌었다.

특정 날짜에 대해 요일을 영어로 출력하되,

이 때 마지막의 "DAY"는 제외하고 반환해야한다.

Response DTO를 설계하여

문제에서 주어진 JSON 포맷으로 반환하는 것 또한 공부가 되었다.

짠-

짧은 회고

API 실습을 통해

Client와 Server가 통신하는 원리를 배울 수 있었다.

뿐만 아니라,

API 명세에 따라 구현을 하다보니

정말 서버 개발자로써 일을 하고 있는 것 같은 기분이 들어 즐거웠다.

과제 중 list 형태의 Request Body로부터 합을 계산하여 반환하는 문제가 있었는데,

해당 문제에는 Stream API를 사용하니

뭐랄까... "은근 Java 좀 치는데?"같은 감상도 들었다.

배웠던 내용이 자연스레 떠오르고 코드로 작성되는 순간의 희열은 이루 말할 수 없는 것 같다.

아,

아직 API 요청에 대해 DB를 연동하지 않았기 때문에

Server 메모리 상에서만 데이터를 다루고 있다.

얼른 DB를 배워 연동해서 실제 살아있는 서버를 만들고 싶다.

Day 03 : 기본적인 DB 사용법


DB 활용에 앞서 DB에 대한 기초 및 연결을 학습하는 시간이었다.

Database

저장 원리

기본적으로 컴퓨터의 모든 리소스는 Disk와 같은 저장장치에 반영구적으로 보존된다.

프로그램을 실행하게 되면 디스크로부터 프로그램을 RAM에 올려 CPU로 계산을 한다.

그렇다면, 

클라이언트로부터 데이터를 받은 서버 컴퓨터에서는 해당 데이터를 보존하기 위해 어떻게 해야할까?

당연히 서버 컴퓨터에 저장해야한다.

RAM과 같이 휘발성이 없는 장치에다가.

물론, 서버 컴퓨터에 파일 형태로도 보존할 수 있다.

그렇지만 대용량 데이터에 대해 효율적인 연산을 지원하는 DB의 사용이 일반적이고 정석이다.

따라서 서버 개발자라면,

DB에 대한 지식이 필요하다.

Database

DB는 대용량 데이터에 대해 효율적인 연산을 제공하는 가상의 저장장치 및 프로그램이다.

구조화 방식에 따라 RDB, NoSQL 등이 있으며

각각의 목적에 따라 사용된다.

프로그래머는 DBMS(Database Management System)을 통해 DB를 관리하는데,

여기에는 MySQL, PostgreSQL, MongoDB 등 다양한 제품이 있다.

이 때,

DBMS에서 DB와 통신하기 위해 사용되는 언어를 SQL(Structured Query Language)라고 한다.

Spring에서 DB 연동하기

application.yml

Spring framework가 DB에 접근하기 위한 설정 등록한다.

/resource에서 관리하며 이미 application.properties가 있는 경우 확장자를 변경한다.

dependency

application.yml에서 mysql을 위한 Driver를 지정하였는데,

이를 위해 의존성에 추가한다.

IntelliJ에서 DB연동

IntelliJ Ultimate를 사용하는 경우,

IDEA와 DB를 연결하여 DBMS로 활용할 수 있다.

해당 서비스 이용이 어려운 경우,

MySQL Client 또는 DBeaver와 같은 프로그램을 사용하면된다.

intelliJ에서 MySQL 연결

JdbcTemplate를 사용한 간단한 DB 연동 프로그래밍

DB를 연결했으니 직접 사용해본다.

JdbcTemplate 필드에 대한 의존성 주입

서버 코드에서 DB와 연동하기 위한 API로 JdbcTemplate를 사용한다.

API 코드 수정

이 때 주의해야 할 점으로,

jdbcTemplate 필드로 SELECT문을 사용해 반환받은 결과는 List다.

또한,

RowMapper 구현을 통해

List를 생성하기 전 Table의 각 row에 대해 필요한 정보를 지정하여 임의의 객체를 만들어야 한다.

과제 리뷰

이번 과제는 람다식에 대한 내용이다.

함수형 인터페이스에 대해 익명 클래스를 기반으로 동작하는 람다식은 JDK 8부터 추가되었다.

생산성 및 가독성을 올려주며,

함수형 프로그래밍을 구현할 수 있게 된다.

이미 Java 문법에서도 배웠던 내용이라

다시 한번 점검할 수 있었다.

짧은 회고

살아있는 서버를 만드는 일은 정말 즐거웠다.

점점 실제 서비스를 만들 수 있는 재료들을 배워가고 있다는 생각에,

빨리 이 과정을 졸업하고 프로젝트에 뛰어들고 싶어 근질근질하다.

이전에 SQLD를 준비하며 배웠던 SQL이 기억나

조금 더 수월하게 따라갈 수 있었다.

역시 배운 건 어디 안간다.

간단한 CRUD 정도야 바로 사용할 수 있었지만,

복잡한 쿼리문을 설계하고 이를 스프링에서도 사용하기 위해

DB, SQL을 깊게 파봐야할 것 같다.

Day 04 : DB를 사용해 만드는 API


지난 시간과 이어지는 DB연동으로,

UPDATE, DELETE API를 작성했다.

PUT API로 UPDATE 기능 구현, DELETE  API로 DELETE 기능 구현

각 API에 대해 예외처리한 코드다.

과제 리뷰

계속해서 이어지는 API 실습이다.

서버 개발자는 결국 Client 요청을 처리하기 위한 API를 개발하는 일을 하는만큼,

API 연습만이 살 길이다!

과제 중,

로직도 복잡하고 DB 테이블을 확장해야 했던 3번이 가장 재미있었지만...

이유를 몰라 헤맸던 문제 2번을 해결한 경험을 나누고자 한다.

RequestBody DTO에 기본 생성자가 정의되지 않은 경우

처음 작성한 코드에는 기본 생성자를 작성하지 않았다.

단순히 @RequestBody에 의해 오버라이드한 생성자가 호출되는 줄 알고 아무런 문제를 느끼지 못했다.

이상없다고 단정지은 코드...

그러나 INSERT 되지 않았다.

Status code는 400을 반환 받았고 요청 자체가 잘못되었음을 알 수 있었다.

무엇이 문제일까?

이를 이해하기 위해서는 @RequestBody의 동작을 이해해야한다.

@RequestBody의 동작

@RequestBody는 요청으로 넘어온 객체를 지정한 DTO에 매핑시켜 반환한다.

이 때,

Spring은 Reflection을 사용하는데

DTO 클래스에 기본 생성자가 없는 경우 변환하는 과정에서 문제를 일으킬 수 있다.

따라서,

DTO 클래스를 생성할 때는 반드시 기본 생성자를 작성한다.

편-안

짧은 회고

많은 API 연습을 통해

Client와 Server 사이에서 이루어지는 동작에 대해 보다 이해할 수 있었고,

무엇보다 API 작성에 자신감을 갖게 되었다.

가장 기본이자, 가장 중요한 CRUD API에 대해 모두 학습하였다.

API 디자인은 더 많은 연습이 필요하겠지만,

API 명세를 이해하고 이를 바탕으로 실제 구현하는 일은 곧 내가 현업에서 밥 먹듯이 하게 될 일이다.

기본기가 중요한만큼,

더욱 집중해서 학습하고 연마하자!

Day 05 : 클린코드의 개념과 첫 리팩토링


1주차 마지막 날이다.

단순 구현에서 벗어나 좋은 코드에 대한 고민을 시작하게됐다.

Clean Code

개발자를 준비하면서 심심찮게 들어본 단어 중 하나가 바로 '클린코드'다.

실제 개발자는 코드를 작성하는 시간보다 읽는 시간이 더 많다고 한다.

어느 한 사람만 이해하고 시간이 지나면 아무도 이해하지 못하는 코드는 결코 좋은 코드라고 말할 수 없을 것이다.

코드란 요구사항에 대한 실제 구현이며,

좋은 코드란 읽기 좋은 코드를 의미한다.

즉,

클린코드로 작성하여 가독성을 높여 최종적으로는 생산성을 높이는 것이 가장 중요한 목적이다.

Layered Architecture

이전의 코드는 모두 하나의 Controller에서 작성되었다.

즉, Controller에서 작성된 하나의 메서드가

  1. API 진입점으로 사용되고

  2. 로직을 수행하며

  3. DB와 통신을 한다

더 좋은 코드를 위해,

더 좋은 구조를 위해,

역할에 따라 클래스를 구분하고

이를 기반으로 통신하는 Layered Architecure를 적용한다.

Controller

API의 진입점으로 사용되는 클래스다.

API 진입점으로 Service와 통신

Service

비즈니스 로직을 작성하는 클래스다.

Controller, Repository와 통신

Repository

DB와 통신하는 클래스다.

Service, Database와 통신

과제 리뷰

좋은 코드를 위한 고민은 멈추지 말아야한다.

작성하는 입장보다 읽는 입장을 고려하며 작성하는 것이 좋은 자세일 것이다.

그리고 이러한 고민은 아주 오래 전 부터 수많은 개발자에 의해 이뤄져왔다.

어느정도 일반적인 클린코드에 대한 가이드가 생겨났다.

<Clean Code>라는 책이 좋은 참고가 될 것이며,

이론적으로 아는 것 보다 실제 작성하고 읽어보며 체득하는 것이 더욱 유익할 것 같다.

짧은 회고

처음으로 내가 작성한 코드를 바라보게 되었다.

"내가 작성한 코드는 좋은 코드인가?"라는 고민을 멈추지 말아야겠다.

좋은 습관이 벨 수 있도록,

고민하고 작성하자!

두번째 Online Session : Live Q&A


두번째 온라인 미팅이 진행되었다.

이번 세션은 QnA 위주로 진행되었고 가장 도움되었던 내용을 기록해본다.

Q. 포트폴리오 주제

지원하는 회사에서 하고 있는 프로덕트가 최고다.

가장 가고 싶은 회사 한 곳을 선정하여 관련 서비스를 만들어보자.

실제 서비스되고 있는 기능을 분석하고 구현하면서 자신의 사용 경험을 기반으로 새로운 기능도 추가해보자.

분명 좋은 평가를 받을 것이다.

Q. 신입 개발자 역량

회사의 사정과 규모에 따라 나뉘겠지만 멘토님이 제시해주신 방향은 아래와 같다.

개발자 시작 가능한 수준

  1. 기본적인 Java 이해 : Java 기본서 90% 이해 및 기본적인 구현 능력

  2. 기본적인 CRUD 및 Spring 기본

  3. 최소한의 배포

취업 99%의 능력

  1. Java 심화

    • 추천 도서 : <이펙티브 자바>, <모던 자바 인 액션>, <자바 성능 최적화>

  2. Spring 심화 : 통계, 엑셀, 메일을 Spring으로 구현할 수 있어야 함

  3. 기술에 대한 고민을 할 수 있을 정도의 이해

  4. 무중단 배포, 서버 확장 전략

이번 스터디를 통해 내 수준이 어디까지 올라갈지는 모르겠으나,

폭.풍.성.장 하자!

1주차 후기


이렇게까지 많이 배운 한 주가 있었나 싶을 정도로

많이 배웠고, 연습했고, 성장했다.

한편으로,

이전부터 이렇게 학습했다면 진작 취업하지 않았을까? 라는 아쉬움이 사무쳤다.

배운 내용을 완벽히 이해해야만 다음 단계로 넘어갈 수 있었고

무엇을 학습하면 좋을지 몰라 닥치는대로 학습했고

정작 중요한 서버 지식과 스프링을 배우기 위해서 무엇을 하면 좋을지 몰라

지레 겁을 먹었던 지난 날들이었다.

이제라도,

어떻게 성장해야하는 지 알아가고 있음에 감사하자.

제대로 성장하는 방법을 알아가고 있음에 위로를 얻자.

앞으로의 성장이 기대되기 시작한 1주차였다.

댓글을 작성해보세요.