<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발잼니?</title>
    <link>https://jamni.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 5 Jun 2026 08:06:43 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>김잼니</managingEditor>
    <item>
      <title>스프링 부트 핵심 가이드(6장)</title>
      <link>https://jamni.tistory.com/40</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;해당 게시글은 스프링부트 핵심 가이드 교재를 공부하며 작성한 글입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;06. 데이터베이스 연동&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ORM&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object Relational Mapping의 약자&lt;/li&gt;
&lt;li&gt;객체 관계 매핑&lt;/li&gt;
&lt;li&gt;객체지향 언어에서 의미하는 객체와 RDB(Relational Database)의 테이블을 자동으로 매핑하는 방법&lt;/li&gt;
&lt;li&gt;쿼리문 작성이 아닌 코드(메서드)로 데이터를 조작할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ORM의 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;ORM을 사용하면 데이터베이스 쿼리를 객체지향적으로 조작할 수 있다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿼리문을 작성하는 양이 현저히 줄어 개발 비용이 줄어든다.&lt;/li&gt;
&lt;li&gt;객체지향적으로 데이터베이스에 접근할 수 있어 코드의 가독성을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;재사용 및 유지보수가 편리하다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ORM을 통해 매핑된 객체는 모두 독립적으로 작성되어 있어 재사용이 용이하다.&lt;/li&gt;
&lt;li&gt;객체들은 각 클래스로 나뉘어 있어 유지보수가 수월하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;데이터베이스에 대한 종속성이 줄어든다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ORM을 통해 자동 생성된 SQL문은 객체를 기반으로 데이터베이스 테이블을 관리하기 때문에 데이터베이스에 종속적이지 않다.&lt;/li&gt;
&lt;li&gt;데이터베이스를 교체하는 상황에서도 비교적 적은 리스크를 부담한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ORM의 단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;ORM만으로 온전한 서비스를 구현하기에는 한계가 있다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 서비스의 경우 직접 쿼리를 구현하지 않고 코드로 구현하기 어렵다.&lt;/li&gt;
&lt;li&gt;복잡한 쿼리를 정확한 설계 없이 ORM 만으로 구성하게 되면 속도 저하 등의 성능 문제가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;애플리케이션의 객체 관점과 데이터베이스의 관계 관점의 불일치가 발생한다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세분성(Granularity) : ORM의 자동 설계 방법에 따라 데이터베이스에 있는 테이블의 수와 애플리케이션의 엔티티(Entity) 클래스의 수가 다른 경우 생긴다.(클래스가 테이블의 수보다 많아질 수 있다.)&lt;/li&gt;
&lt;li&gt;상속성(Inheritance) : RDBMS에는 상속이란 개념이 없다.&lt;/li&gt;
&lt;li&gt;식별성(Identity) : RDBMS는 기본 키(primary key)로 동일성을 정의한다. 하지만 자바는 두 객체의 값이 같아도 다르다고 판단할 수 있다. 식별과 동일성의 문제다.&lt;/li&gt;
&lt;li&gt;연관성(Associations) : 객체지향 언어는 객체를 참조함으로써 연관성을 나타내지만 RDBMS에서는 외래키(foreign key)를 삽입함으로써 연관성을 표현한다. 또한 객체지향 언어에서 객체를 참조할 때는 방향성이 존재하지만 RDBMS에서 외래키를 삽입하는 것은 양방향의 관계를 가지기 때문에 방향성이 없다.&lt;/li&gt;
&lt;li&gt;탐색(Navigation) : 자바와 RDBMS는 어떤 값(객체)에 접근하는 방식이 다르다. 자바에서는 특정 값에 접근하기 위해 객체 참조 같은 연결 수단을 활용한다. 이 방식은 객체를 연결하고 또 연결해서 접근하는 그래프 형태의 접근 방식이다. 반면 RDBMS에서는 쿼리를 최소화하고 조인(JOIN)을 통해 여러 테이블을 로드하고 값을 추출하는 접근 방식을 채택하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPA&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java Persistence API&lt;/li&gt;
&lt;li&gt;ORM이 큰 개념이라면 JPA는 더 구체화된 스펙을 포함한다.&lt;/li&gt;
&lt;li&gt;실제로 동작하는 것이 아니고 어떻게 동작해야하는지 메커니즘을 정리한 표준 명세로 생각하면 된다.&lt;/li&gt;
&lt;li&gt;내부적으로 JDBC를 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발자가 직접 JDBC를 구현하면 SQL에 의존하게 되는 문제 등이 있어 개발의 효율성이 떨어지는 문제를 보완&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발자 대신 적절한 SQL을 생성하고 데이터베이스를 조작해서 객체를 자동 매핑하는 역할을 수행&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하이버네이트(Hibernate)&lt;/b&gt;, 이클립스 링크(EclipseLink), 데이터 뉴클리어스(DataNucleus)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;하이버네이트&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Spring Data JPA&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하이버네이트의 기능을 더욱 편하게 사용하도록 모듈화한 것이다.&lt;/li&gt;
&lt;li&gt;CRUD 처리에 필요한 인터페이스를 제공한다.&lt;/li&gt;
&lt;li&gt;하이버네이트의 엔티티 매니저(EntityManager)를 직접 다루지 않고 리포지토리를 정의해 사용함으로써 스프링이 적합한 쿼리를 동적으로 생성하는 방식으로 데이터베이스를 조작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;영속성 컨텍스트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션과 데이터베이스 사이에서 엔티티와 레코드의 괴리를 해소하는 기능과 객체를 보관하는 기능을 수행한다.&lt;/li&gt;
&lt;li&gt;JPA는 엔티티 객체의 매핑 정보를 데이터베이스에 반영하는 작업을 수행한다.&lt;/li&gt;
&lt;li&gt;세션 단위의 생명주기를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔티티 매니저&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티를 관리하는 객체&lt;/li&gt;
&lt;li&gt;데이터베이스에 접근해서 CRUD 작업을 수행한다.&lt;/li&gt;
&lt;li&gt;Spring Data JPA를 사용하면 리포지토리를 사용해서 데이터베이스에 접근하는데 리포지토리에서 엔티티 매니저를 사용하는 것이다.&lt;/li&gt;
&lt;li&gt;엔티티 매니저 팩토리(EntityManagerFactory)가 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;엔티티 매니저 팩토리(EntityManagerFactory)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스가 대응하는 객체&lt;/li&gt;
&lt;li&gt;애플리케이션에서 단 하나만 생성되며, 모든 엔티티가 공유해서 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 매니저 팩토리로 생성된 엔티티 매니저는 엔티티를 영속성 컨텍스트에 추가해서 영속 객체로 만드는 작업을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트와 데이터베이스를 비교하면서 실제 데이터베이스를 대상으로 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔티티의 생명주기&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비영속(New)&lt;/b&gt; : 영속성 컨텍스트에 추가되지 않은 엔티티 객체의 상태를 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영속(Managed)&lt;/b&gt; : 영속성 컨텍스트에 의해 엔티티 객체가 관리되는 상태이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;준영속(Detached)&lt;/b&gt; : 영속성 컨텍스트에 의해 관리되던 엔티티 객체가 컨텍스트와 분리된 상태이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제(Removed)&lt;/b&gt; : 데이터베이스에서 레코드를 삭제하기 위해 영속성 컨텍스트에 삭제 요청을 한 상태이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터베이스 연동&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로젝트 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Data JPA 의존성을 추가한 후에는 별도의 설정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연동할 데이터베이스 정보를 application.properties에 작성해야 한다. 밑 코드는 .properties 대신 .yaml 사용&lt;/p&gt;
&lt;pre id=&quot;code_1727615376167&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    driverClassName: {연동하려는 데이터베이스의 드라이버 정의}
    url: {데이터베이스 경로}
    username: {데이터베이스 계정 정보}
    password: {데이터베이스 계정 정보}
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;엔티티 설계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA에서 엔티티는 데이터베이스의 테이블에 대응하는 클래스다.&lt;/li&gt;
&lt;li&gt;엔티티에 어노테이션을 사용하면 테이블 간의 연관관계를 정의할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔티티 관련 기본 어노테이션&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Entity&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 클래스가 엔티티임을 명시하는 어노테이션&lt;/li&gt;
&lt;li&gt;테이블과 일대일로 매칭&lt;/li&gt;
&lt;li&gt;인스턴스는 매핑되는 테이블에서 하나의 레코드를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Table&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스의 이름과 테이블의 이름을 다르게 지정해야 하는 경우 사용한다.&lt;/li&gt;
&lt;li&gt;@Table(name = 값) 형태로 데이터베이스의 테이블을 명시한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Id&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블의 기본값 역할로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@GeneratedValue&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 필드의 값을 어떤 방식으로 자동으로 생성할지 결정할 때 사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GeneratedValue를 사용하지 않는 방식(직접 할당)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션에서 자체적으로 고유한 기본값을 생성한 경우 사용하는 방식이다.&lt;/li&gt;
&lt;li&gt;내부에 정해진 규칙에 의해 기본값을 생성하고 식별자로 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Auto&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@GeneratedValue의 기본 설정값&lt;/li&gt;
&lt;li&gt;기본값을 사용하는 데이터베이스에 맞게 자동 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IDENTITY&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본값 생성을 데이터베이스에 위임하는 방식이다.&lt;/li&gt;
&lt;li&gt;데이터베이스의 AUTO_INCREMENT를 사용해 기본값을 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SEQUENCE&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@SequenceGenerator 어노테이션으로 식별자 생성기를 설정하고 이를 통해 값을 자동 주입받는다.&lt;/li&gt;
&lt;li&gt;SequenceGenerator를 정의할 때는 name, squenceName, allocationSize를 활용한다.&lt;/li&gt;
&lt;li&gt;@GeneratedValue 생성기를 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TABLE&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 DBMS를 사용하더라도 동일하게 동작하기를 원할 경우 사용한다.&lt;/li&gt;
&lt;li&gt;식별자로 사용할 숫자의 보관 테이블을 별도로 생성해서 엔티티를 생성할 때마다 값을 갱신하며 사용한다.&lt;/li&gt;
&lt;li&gt;@TableGenerator 어노테이션으로 테이블 정보를 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Column&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동으로 테이블 칼럼으로 매핑한다.&lt;/li&gt;
&lt;li&gt;name : 데이터베이스의 칼럼명을 설정하는 속성이다. 명시하지 않으면 필드명으로 지정된다.&lt;/li&gt;
&lt;li&gt;nullable : 레코드를 생성할 때 칼럼 값에 null 처리가 가능한지를 명시하는 속성이다.&lt;/li&gt;
&lt;li&gt;length : 데이터베이스에 저장하는 데이터의 최대 길이를 설정한다.&lt;/li&gt;
&lt;li&gt;unique : 해당 칼럼을 유니크로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Transient&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 클래스에는 선언돼 있는 필드지만 데이터베이스에서는 필요 없을 경우 이 어노테이션을 사용해 데이터베이스에서 이용하지 않게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리포지토리 인터페이스 설계&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리포지토리 인터페이스 생성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리포지토리는 Spring Data JPA가 제공하는 인터페이스&lt;/li&gt;
&lt;li&gt;엔티티가 생성한 데이터베이스에 접근하는 데 사용된다.&lt;/li&gt;
&lt;li&gt;접근하려는 테이블과 매핑되는 엔티티에 대한 인터페이스를 생성하고 JpaRepository를 상속받으면 된다.&lt;/li&gt;
&lt;li&gt;타입을 지정해야 하는데, 대상 엔티티를 product로 설정하고 해당 엔티티의 @Id 필드 타입으로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리포지토리 메서드의 생성 규칙&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FindBy : SQL문의 where절 역할을 수행하는 구문. findBy 뒤에 엔티티의 필드값을 입력해서 사용한다.&lt;/li&gt;
&lt;li&gt;AND, OR : 조건을 여러 개 설정하기 위해 사용한다.&lt;/li&gt;
&lt;li&gt;Like/NoLike : SQL 문의 like와 동일한 기능을 수행. 특정 문자를 포함하는지 여부를 조건으로 추가한다. 비슷한 키워드로 Containing, Contains, isContaing이 있습니다.&lt;/li&gt;
&lt;li&gt;StartsWith/StartingWith : 특정 키워드로 시작하는 문자열 조건을 설정한다.&lt;/li&gt;
&lt;li&gt;EndsWith/EndingWith : 특정 키워드로 끝나는 문자열 조건을 설정한다.&lt;/li&gt;
&lt;li&gt;IsNull/IsNotNull : 레코드 값이 Null이거나 Null이 아닌 값을 검색합니다.&lt;/li&gt;
&lt;li&gt;True/False : Boolean 타입의 레코드를 검색할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;Before/After : 시간을 기준으로 값을 검색한다.&lt;/li&gt;
&lt;li&gt;LessThan/GreaterThan : 특정 값(숫자)을 기준으로 대소 비교를 할 때 사용한다.&lt;/li&gt;
&lt;li&gt;Between : 두 값(숫자) 사이의 데이터를 조회한다.&lt;/li&gt;
&lt;li&gt;OrderBy : SQL 문에서 order by와 동일한 기능을 수행한다.&lt;/li&gt;
&lt;li&gt;countBy : SQL 문의 count와 동일한 기능을 수행하며, 결괏값의 개수(count)를 추출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DAO 설계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Data Access Object&lt;/li&gt;
&lt;li&gt;데이터베이스에 접근하기 위한 로직을 관리하기 위한 객체&lt;/li&gt;
&lt;li&gt;비즈니스 로직의 동작과정에서 데이터를 조작하는 기능을 수행한다.&lt;/li&gt;
&lt;li&gt;Spring Data JPA에서는 리포지토리가 대체한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DAO 클래스 생성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;'인터페이스 - 구현체' 구성으로 생성&lt;/li&gt;
&lt;li&gt;의존성 결합을 낮추기 위한 디자인 패턴&lt;/li&gt;
&lt;li&gt;서비스 레이어에 DAO 객체를 주입받을 때 인터페이스를 선언하는 방식으로 구성할 수 있다.&lt;/li&gt;
&lt;li&gt;데이터베이스에 접근하는 메서드는 리턴 값으로 데이터 객체를 전달한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 설계 원칙에서 엔티티 객체는 데이터베이스에 접근하는 계층에서만 사용&lt;/li&gt;
&lt;li&gt;다른 계층으로 데이터를 전달할 때는 DTO 객체를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반복되는 코드의 작성을 생략하는 방법 - 롬복(Lombok)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스를 생성할 때 반복적으로 사용하는 메서드를 어노테이션으로 대체하는 기능을 제공하는 라이브러리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Getter, @Setter&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getter/setter 메서드를 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;생성자 자동 생성 어노테이션&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NoArgsConstructor : 매개변수가 없는 생성자를 자동 생성한다.&lt;/li&gt;
&lt;li&gt;AllArgsConstructor : 모든 필드를 매개변수로 갖는 생성자를 자동 생성한다.&lt;/li&gt;
&lt;li&gt;RequiredArgsConstructor : 필드 중 final이나 @NotNull이 설정된 변수를 매개변수로 갖는 생성자를 자동 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@ToString&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;toString() 메서드를 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@EqualsAndHashCode&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 동등성(Equality)과 동일성(Identity)을 비교하는 연산 메서드를 생성한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;equals : 두 객체의 내용이 같은지 동등성을 비교한다.&lt;/li&gt;
&lt;li&gt;hashCode : 두 객체가 같은 객체인지 동일성을 비교한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Data&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위에 설명한 모두를 포괄하는 어노테이션이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Spring</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/40</guid>
      <comments>https://jamni.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 29 Sep 2024 23:40:03 +0900</pubDate>
    </item>
    <item>
      <title>스프링 부트 핵심 가이드(3~5장)</title>
      <link>https://jamni.tistory.com/39</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #353638;&quot;&gt;해당 게시글은 스프링부트 핵심 가이드 교재를 공부하며 작성한 글입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 개발 환경 구성&lt;/h2&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바 JDK 설치&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;자바 JDK는 Azul에서 제공하는 Open JDK를 사용합니다. (이 외에도 다른 방법도 가능)&lt;br&gt;윈도우에서 정상적으로 JDK를 사용하기 위해서는 환경변수를 추가해야 합니다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;인텔리제이 IDEA 설치&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;제트브레인의 인텔리제이 IDEA를 사용합니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 스프링 부트 애플리케이션 개발하기&lt;/h2&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 생성&lt;/h3&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;인텔리제이 IDEA에서 프로젝트 생성하기&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;인텔리제이 IDEA 얼티밋 버전을 사용한다면 내장된 Spring Initializr를 사용하여 스프링 프로젝트를 생성할 수 있다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;스프링 공식 사이트에서 프로젝트 생성하기&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 공식 사이트에는 스프링 부트 프로젝트를 자동으로 만들어주는 서비스가 있다.&lt;br&gt;&lt;a href=&quot;https://start.spring.io&quot; target=&quot;_self&quot; title=&quot;스프링 공식 사이트 프로젝트 생성&quot;&gt;&lt;span&gt;https://start.spring.io&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;pom.xml(Project Object Model) 살펴보기&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;pom.xml 파일은 메이븐의 기능을 사용하기 위해 작성하는 파일&lt;/li&gt;&lt;li&gt;프로젝트, 의존성 라이브러리, 빌드 등의 정보 및 해당 프로젝트를 관리하는 데 필요한 내용이 기술&lt;/li&gt;&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;빌드 관리 도구&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;개발 규모가 커질수록 관리할 라이브러리가 많아지고 라이브러리 간 버전 호환성을 체크해야 하는 어려움이 발생하는데, 빌드 관리 도구를 이용하면 이 같은 문제를 해결할 수 있음&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;메이븐&lt;/h4&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;대표기능&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;프로젝트 관리 : 프로젝트 버전과 아티팩트를 관리한다.&lt;/li&gt;&lt;li&gt;빌드 및 패키징 : 의존성을 관리하고 설정된 패키지 형식으로 빌드를 수행한다.&lt;/li&gt;&lt;li&gt;테스트 : 빌드를 수행하기 전에 단위 테스트를 통해 작성된 애플리케이션 코드의 정상 동작 여부를 확인한다.&lt;/li&gt;&lt;li&gt;배포 : 빌드가 완료된 패키지를 원격 저장소에 배포한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;메이븐의 생명주기&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;기본 생명주기(Default Lifecycle), 클린 생명주기(Clean Lifecycle), 사이트 생명주기(Site Lifecycle)로 구분&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;클린 생명주기&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;clean : 이전 빌드가 생성한 모든 파일을 제거&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 생명주기&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;validate : 프로젝트를 빌드하는 데 필요한 모든 정보를 사용할 수 있는지 검토&lt;/li&gt;&lt;li&gt;compile : 프로젝트의 소스코드를 컴파일&lt;/li&gt;&lt;li&gt;test : 단위 테스트 프레임워크를 사용해 테스트를 실행&lt;/li&gt;&lt;li&gt;package : 컴파일한 코드를 가져와서 JAR 등의 형식으로 패키징을 수행&lt;/li&gt;&lt;li&gt;verify : 패키지가 유효하며 일정 기준을 충족하는지 확인&lt;/li&gt;&lt;li&gt;install : 프로젝트를 사용하는 데 필요한 패키지를 로컬 저장소에 설치&lt;/li&gt;&lt;li&gt;deploy : 프로젝트를 통합 또는 릴리스 환경에서 다른 곳에 공유하기 위해 원격 저장소에 패키지를 복사&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사이트 생명주기&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;site : 메이븐의 설정 파일 정보를 기반으로 프로젝트의 문서 사이트를 생성&lt;/li&gt;&lt;li&gt;site-deploy : 생성된 사이트 문서를 웹 서버에 배포&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;웹 브라우저를 통한 동작 테스트&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트에서는 기본적으로 8080번 포트를 통해 웹 애플리케이션이 실행&lt;br&gt;'http://localhost:8080/~~'에 접속하면 작성한 코드가 반환하는 것을 확인할 수 있음&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Talend API Tester를 통한 동작 테스트&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;크롬 확장 프로그램인 Talend API Tester를 사용&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 data-ke-size=&quot;size26&quot;&gt;05. API를 작성하는 다양한 방법&lt;/h2&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;GET API 만들기&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러에 @RestController와 @RequestMapping을 붙여 내부에 선언되는 메서드에서 사용할 공통 URL을 설정합니다.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/api/v1/get-api&quot;)
public class GetController {

}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@RequestMapping으로 구현하기&lt;/h4&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
 &lt;li&gt;@RequestMapping 어노테이션을 별다른 설정 없이 선언하면 HTTP의 모든 요청을 받는다.&lt;/li&gt; 
 &lt;li&gt;method 요소의 값을 RequestMethod.GET으로 설정하면 요청 형식을 GET으로만 설정한다.&lt;/li&gt; 
 &lt;li&gt;스프링 4.3 버전 이후로는 @RequestMapping 어노테이션은 더 이상 사용되지 않는다. 아래 어노테이션 사용 
  &lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;@GetMapping&lt;/li&gt; 
   &lt;li&gt;@PostMapping&lt;/li&gt; 
   &lt;li&gt;@PutMapping&lt;/li&gt; 
   &lt;li&gt;@DeleteMapping&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;매개변수가 없는 GET 메서드 구현&lt;/h4&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/get-api/name
@GetMapping(value = &quot;/name&quot;)
public String getName() {
	return &quot;Flature&quot;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@PathVariable을 활용한 GET 메서드 구현&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;URL 자체에 값을 담아 요청하는 것&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/get-api/variable1/{String 값}
@GetMapping(value = &quot;/variable1/{variable}&quot;)
public String getVariable1(@PathVariable String variable) {
	return variable;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;@PathVariaㅠle을 명시, @GetMapping 어노테이션과 @PathVariable에 지정된 변수의 이름을 동일하게 맞춰야함&lt;br&gt;동일하게 맞추지 못할 경우&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/get-api/variable2/{String 값}
@GetMapping(value = &quot;/variable2/{variable}&quot;)
public String getVariable2(@PathVariable(&quot;variable&quot;) String var) {
	return var;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@RequestParam을 활용한 GET 메서드 구현&lt;/h4&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;쿼리 형식으로 값을 전달할 수 있다.&lt;/li&gt;&lt;li&gt;URI에서 '?'를 기준으로 우측에 '{키}={값}' 형태로 구성&lt;/li&gt;&lt;li&gt;@RequestParam 어노테이션을 명시해 쿼리 값과 매핑하면 됩니다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/get-api/request1?name=value1&amp;amp;email=value2&amp;amp;organization=value3
@GetMapping(value=&quot;request1&quot;)
public String getRequestParam1(
	@RequestParam String name,
	@RequestParam String email,
	@RequestParam String organization) {
	return name + &quot; &quot; + email + &quot; &quot; + organization;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 value 요소를 사용하여 매핑할 수 있음&lt;br&gt;&amp;nbsp;&lt;br&gt;어떤 값이 들어올 지 모른다면 Map 객체를 활용한다.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt; // http://localhost:8080/api/v1/get-api/request2?key1=value1&amp;amp;key2=value2
@GetMapping(value = &quot;/request2&quot;)
public String getRequestParam2(@RequestParam Map&amp;lt;String, String&amp;gt; param) {
	StringBuilder sb = new StringBuilder();

	param.entrySet().forEach(map -&amp;gt; {
		sb.append(map.getKey() + &quot; : &quot; + map.getValue() + &quot;\n&quot;);
	});

	return sb.toString();
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;*entrySet() : Map에서 모든 Entry(key-value 쌍)를 가져와 Set 객체로 반환&lt;br&gt;*forEach : 그냥 순회. for문과 동일&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;URI와 URL의 차이&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;URI는 특정 리소스를 식별할 수 있는 식별자를 의미&lt;br&gt;URL은 우리가 흔히 말하는 웹 주소&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;DTO 객체를 활용한 GET 메서드 구현&lt;/h4&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;DTO란?&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;Data Transfer Object의 약자&lt;/li&gt;&lt;li&gt;데이터 교환에 활용&lt;/li&gt;&lt;li&gt;각 클래스 및 인터페이스를 호출하면서 전달하는 매개변수로 사용되는 데이터 객체&lt;/li&gt;&lt;li&gt;데이터 교환 용도로만 사용되기에 별도의 로직이 포함되지 않음&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/get-api/request3?name=value1&amp;amp;email=value2&amp;amp;organization=value3
@GetMapping(value = &quot;/request3&quot;)
public String getRequestParam3(MemberDto memberDTO) {
	//return memberDto.getName() + &quot; &quot; + memberDto.getEmail() + &quot; &quot; + memberDto.getOrganization();
	return memberDTO.toString();
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;POST API 만들기&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;저장하고자 하는 리소스나 값을 HTTP 바디(body)에 담아 서버에 전달&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@RequestBody를 활용한 POST 메서드 구현&lt;/h4&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;클라이언트가 서버에 리소스를 저장하는 데 사용&lt;/li&gt;&lt;li&gt;클라이언트의 요청 트래픽에&amp;nbsp; 값이 포함&lt;/li&gt;&lt;li&gt;HTTP Body에 값을 넣어 전송&lt;/li&gt;&lt;li&gt;일반적으로 JSON 형식으로 전송&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 통해 어떤 값이 들어오게 될지 특정하기 어려울 땐 Map 객체를 사용, 들어갈 값이 정해져 있다면 DTO 객체를 매개변수로 삼아 작성할 수 있다.&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/post-api/member2
@PostMapping(value = &quot;/member2&quot;)
public String postMemberDto(@RequestBody MemberDto memberDTO) {
	return memberDTO.toString();
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;PUT API 만들기&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;데이터베이스 같은 저장소에 존재하는 리소스의 값을 업데이트&lt;/li&gt;&lt;li&gt;POST API와 비교하면 요청을 받아 실제 데이터베이스에 반영하는 과정에서 차이가 있지만, 구현하는 방법은 거의 동일&lt;/li&gt;&lt;li&gt;HTTP Body를 활용&lt;/li&gt;&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@RequestBody를 활용한 PUT 메서드 구현&lt;/h4&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 예제 5.16
// http://localhost:8080/api/v1/put-api/member1
@PutMapping(value = &quot;/member1&quot;)
public String postMemberDto1(@RequestBody MemberDto memberDto) {
	return memberDto.toString();
}

// http://localhost:8080/api/v1/put-api/member2
@PutMapping(value = &quot;/member2&quot;)
public MemberDto postMemberDto2(@RequestBody MemberDto memberDto) {
	return memberDto;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String 타입과 DTO 객체의 차이&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;String 타입의 경우 보낸 요청 내용이 그대로 결괏값으로 전달되지만 HEADERS 항목의 content-type을 보면 'text/plain'으로서 결괏값으로 일반 문자열이 전달됐음을 확인할 수 있다.&lt;/li&gt;&lt;li&gt;DTO 객체의 경우 형식만 유지한 채 전달한다. HEADERS 영역의 Content-Type 항목도 'application/json' 형식으로 전달된 것을 확인할 수 있다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;@RestController 어노테이션이 지정된 클래스는 @ResponseBody를 생략할 수 있는데, @ResponseBody 어노테이션은 자동으로 값을 JSON과 같은 형식으로 변환해서 전달하는 역할을 수행한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;ResponseEntity를 활용한 PUT 메서드 구현&lt;/h4&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;헤더와 Body로 구성된 HTTP 요청과 응답을 구성하는 역할을 수행하는 HttpEntity 클래스가 있다.&lt;/li&gt;&lt;li&gt;ResponseEntity는 서버에 들어온 요청에 대해 응답 데이터를 구성해서 전달할 수 있게 한다.&lt;/li&gt;&lt;li&gt;HttpHeaders와 Body를 가지고 자체적으로 HttpStatus를 구현한다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/put-api/member3
@PutMapping(value = &quot;/member3&quot;)
public ResponseEntity&amp;lt;MemberDto&amp;gt; postMemberDto3(@RequestBody MemberDto memberDto) {
	return ResponseEntity
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.status(HttpStatus.ACCEPTED) // 응답코드 202
	&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.body(memberDto);
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;DELETE API 만들기&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;저장소에 있는 리소스를 삭제할 때&lt;/li&gt;&lt;li&gt;리소스를 식별할 수 있는 값을 받아 데이터베이스나 캐시에 있는 리소스를 조회하고 삭제하는 역할&lt;/li&gt;&lt;li&gt;GET메서드와 같이 URI에 값을 넣어 요청 받는 형식&lt;/li&gt;&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;@PathVariable과 @RequestParam을 활용한 DELETE 메서드 구현&lt;/h4&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// http://localhost:8080/api/v1/delete-api/{String 값}
@DeleteMapping(value = &quot;/{variable}&quot;)
public String DeleteVariable(@PathVariable String variable) {
	return variable;
}

// http://localhost:8080/api/v1/delete-api/request1?email=value
@DeleteMapping(value = &quot;/request1&quot;)
public String getRequestParam1(@RequestParam String email) {
	return &quot;e-mail : &quot; + email;
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;REST API 명세를 문서화하는 방법 - Swagger&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;명세란?&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;해당 API가 어떤 로직을 수행하는지 설명하고 이 로직을 수행하기 위해 어떤 값을 요청하며, 이에 따른 응답값으로는 무엇을 받을 수 있는지를 정리한 자료&lt;br&gt;&amp;nbsp;&lt;br&gt;API는 개발과정에서 계속 변경되기에 작성한 명세 문서도 주기적인 업데이트가 필요&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Swagger 관련 설정 코드&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Bean
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Docket api() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new Docket(DocumentationType.SWAGGER_2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.apiInfo(apiInfo())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.select()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.apis(RequestHandlerSelectors.basePackage(&quot;com.springboot.api&quot;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.paths(PathSelectors.any())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.build();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private ApiInfo apiInfo() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new ApiInfoBuilder()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.title(&quot;Spring Boot Open API Test with Swagger&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.description(&quot;설명 부분&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.version(&quot;1.0.0&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.build();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;RequestHandlerSelectors.basePackage() 메서드는 Swagger에서 스캔한 패키지 범위를 설정&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;로깅 라이브러리 - Logback&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;로깅이란?&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;애플리케이션이 동작하는 동안 시스템의 상태나 동작 정보를 시간순으로 기록하는 것&lt;/li&gt;&lt;li&gt;비기능 요구사항&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Logback의 특징&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
 &lt;li&gt;크게 5개의 로그 레벨 
  &lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li&gt;ERROR : 로직 수행 중에 시스템에 심각한 문제가 발생해서 애플리케이션의 작동이 불가능한 경우를 의미&lt;/li&gt; 
   &lt;li&gt;WARN : 시스템 에러의 원인이 될 수 있는 경고 레벨을 의미&lt;/li&gt; 
   &lt;li&gt;INFO : 애플리케이션의 상태 변경과 같은 정보 전달을 위해 사용&lt;/li&gt; 
   &lt;li&gt;DEBUG : 애플리케이션의 디버깅을 위한 메시지를 표시하는 레벨을 의미&lt;/li&gt; 
   &lt;li&gt;TRACE : DEBUG 레벨보다 더 상세한 메시지를 표현하기 위한 레벨을 의미&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;실제 운영 환경과 개발 환경에서 각각 다른 출력 레벨을 설정해서 로그를 확인할 수 있다.&lt;/li&gt; 
 &lt;li&gt;Logback의 설정 파일을 일정 시간마다 스캔해서 애플리케이션을 재가동하지 않아도 설정을 변경할 수 있다.&lt;/li&gt; 
 &lt;li&gt;별도의 프로그램 지원 없이도 자체적으로 로그 파일을 압축할 수 있다.&lt;/li&gt; 
 &lt;li&gt;저장된 로그 파일에 대한 보관 기간 등을 설정해서 관리할 수 있다.&lt;/li&gt; 
&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;Logback 설정&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 폴더 안에 logback-spring.xml의 이름으로 설정 파일을 생성&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;configuration&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;property name=&quot;LOG_PATH&quot; value=&quot;./logs&quot;/&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- Appenders --&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;appender name=&quot;console&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter class=&quot;ch.qos.logback.classic.filter.ThresholdFilter&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;level&amp;gt;INFO&amp;lt;/level&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/filter&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;encoder&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;pattern&amp;gt;[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n&amp;lt;/pattern&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/encoder&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/appender&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;appender name=&quot;INFO_LOG&quot; class=&quot;ch.qos.logback.core.rolling.RollingFileAppender&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;filter class=&quot;ch.qos.logback.classic.filter.ThresholdFilter&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;level&amp;gt;INFO&amp;lt;/level&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/filter&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;file&amp;gt;${LOG_PATH}/info.log&amp;lt;/file&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;append&amp;gt;true&amp;lt;/append&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;rollingPolicy class=&quot;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;fileNamePattern&amp;gt;${LOG_PATH}/info_${type}.%d{yyyy-MM-dd}.gz&amp;lt;/fileNamePattern&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;maxHistory&amp;gt;30&amp;lt;/maxHistory&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/rollingPolicy&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;encoder&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;pattern&amp;gt;[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n&amp;lt;/pattern&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/encoder&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/appender&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- TRACE &amp;gt; DEBUG &amp;gt; INFO &amp;gt; WARN &amp;gt; ERROR &amp;gt; OFF --&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!-- Root Logger --&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;root level=&quot;INFO&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;appender-ref ref=&quot;console&quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;appender-ref ref=&quot;INFO_LOG&quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/root&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Appender 영역&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;로그의 형태를 설정하고 어떤 방법으로 출력할지를 설정하는 곳&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;ConsoleAppender : 콘솔에 로그를 출력&lt;/li&gt;&lt;li&gt;FileAppender : 파일에 로그를 저장&lt;/li&gt;&lt;li&gt;RollingFileAppender : 여러 개의 파일을 순회하면서 로그를 저장&lt;/li&gt;&lt;li&gt;SMTPAppender : 메일로 로그를 정송&lt;/li&gt;&lt;li&gt;DBAppender : 데이터베이스에 로그를 저장&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Root 영역&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;설정 파일에 정의된 Appender를 활용하려면 Root 영역에서 Appender를 참조해서 로깅 레벨을 설정한다.&lt;/p&gt;</description>
      <category>Spring</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/39</guid>
      <comments>https://jamni.tistory.com/39#entry39comment</comments>
      <pubDate>Sun, 29 Sep 2024 16:20:53 +0900</pubDate>
    </item>
    <item>
      <title>스프링 부트 핵심 가이드(1~2장)</title>
      <link>https://jamni.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;해당 게시글은 스프링부트 핵심 가이드 교재를 공부하며 작성한 글입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;01. 스프링 부트란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 프레임워크&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바에서 가장 많이 사용하는 프레임워크&lt;/li&gt;
&lt;li&gt;자바 언어를 이용해 *엔터프라이즈급 개발을 편리하게 만들어주는 '오픈소스 경량급 어플리케이션 프레임워크'&lt;/li&gt;
&lt;li&gt;*엔터프라이즈급 개발 : 기업 환경을 대상으로 하는 개발&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링의 핵심 가치 : &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;애플리케이션 개발에 필요한 기반을 제공해서 개발자가 비즈니스 로직 구현에만 집중할 수 있게끔 하는 것&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;제어 역전(IoC)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Inversion of Control의 약자&lt;/li&gt;
&lt;li&gt;일반적인 자바 개발의 경우 사용하려는 객체를 선언하고 해당 객체의 의존성을 생성한 후 객체에서 제공하는 기능을 사용한다.&lt;/li&gt;
&lt;li&gt;IoC를 적용한 환경에서는 사용할 객체를 직접 생성하지 않고 객체의 생명주기 관리를 *외부에 위임한다.&lt;/li&gt;
&lt;li&gt;*외부 : 스프링 컨테이너 혹은 IoC 컨테이너&lt;/li&gt;
&lt;li&gt;객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것 &amp;rarr; 개발자는 비즈니스 로직을 작성하는 데 더 집중할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;의존성 주입(DI)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dependency Injection의 약자&lt;/li&gt;
&lt;li&gt;제어 역전의 방법 중 하나&lt;/li&gt;
&lt;li&gt;외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링에서 의존성을 주입받는 방법 3가지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 생성자를 통한 의존성 주입&lt;/p&gt;
&lt;pre id=&quot;code_1727348586139&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
public class DIController {
	
    // ---
    MyService myService;
    
    @Autowired 										
    public DIController(MyService myService) {		
    	this.myService = myService;					
    }
    // ---
    
    @GetMapping(&quot;/di/hello&quot;)
    public String getHello() {
    	return myService.getHello();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 필드 객체 선언을 통한 의존성 주입&lt;/p&gt;
&lt;pre id=&quot;code_1727348690165&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
public class FieldInjectionController {    
    // ---
    @Autowired
    private MyService myService;
    // ---
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. setter 메서드를 통한 의존성 주입&lt;/p&gt;
&lt;pre id=&quot;code_1727348768030&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
public class SetterInjectionController {
    // ---
    MyService myService;
    
    @Autowired
    public void setMyService(MyService myService) {
    	this.myService = myService;
    }
    // ---
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자를 통해 의존성을 주입받는 방식을 권장. 레퍼런스 객체 없이는 객체를 초기화할 수 없게 설계할 수 있기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;관점 지향 프로그래밍(AOP)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Aspect-Oriented Programming&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;OOP를 더욱 잘 사용하도록 돕는 개념&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;*관점을 기준으로 묶어 개발하는 방식&lt;/li&gt;
&lt;li&gt;*관점 : 어떤 기능을 구현할 때, '핵심 기능'과 '부가 기능'으로 구분해 각각을 하나의 관점으로 보는 것을 의미&lt;/li&gt;
&lt;li&gt;로깅이나 트랜잭션 같은 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화해 삽입하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AOP를 구현하는 방법 3가지&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컴파일 과정에 삽입하는 방식&lt;/li&gt;
&lt;li&gt;바이트코드를 메모리에 로드하는 과정에 삽입하는 방식&lt;/li&gt;
&lt;li&gt;프락시 패턴을 이용한 방식&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링 AOP의 목적 : 모듈화해서 재사용 가능한 구성을 만드는 것이고, 모듈화된 객체를 편하게 적용할 수 있게 함으로써 개발자가 비즈니스 로직을 구현하는 데만 집중할 수 있게 도와주는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 프레임워크 vs 스프링 부트&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 프레임워크는 기존 개발 방식의 문제와 한계를 극복하기 위해 다양한 기능을 제공하지만 기능이 많은 만큼 설정이 복잡한 편&lt;/li&gt;
&lt;li&gt;필요한 모듈들을 추가하다 보면 설정이 복잡해지는 문제를 해결하기 위해 등장한 것이 스프링 부트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링 부트를 이용하면 단독으로 실행 가능한 상용 수준의 스프링 기반 애플리케이션을 손쉽게 만들 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;의존성 관리&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 프레임워크에서는 개발에 필요한 각 모듈의 의존성을 직접 설정&lt;/li&gt;
&lt;li&gt;스프링 부트에서는 이러한 불편함을 해소하기 위해 'spring-boot-starter'라는 의존성을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;spring-boot-starter 라이브러리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;spring-boot-starter-web: 스프링 MVC를 사용하는 RESTful 애플리케이션을 만들기 위한 의존성. 기본으로 내장 톰캣(Tomcat)이 포함돼 있어 jar 형식으로 실행 가능합니다.&lt;/li&gt;
&lt;li&gt;spring-boot-starter-test: JUnit, Jupiter, Mockito 등의 테스트용 라이브러리를 포함합니다.&lt;/li&gt;
&lt;li&gt;spring-boot-starter-jdbc: HikariCP 커넥션 풀을 활용한 JDBC 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;spring-boot-starter-security: 스프링 시큐리티(인증, 권한, 인가 등) 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;spring-boot-starter-data-jpa: 하이버네이트를 활용한 JPA 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;spring-boot-starter-cache: 스프링 프레임워크의 캐시 기능을 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자동 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@SpringBootApplication 어노테이션&lt;/b&gt;은 다음 3개의 어노테이션을 합쳐놓은 구성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@SpringBootConfiguration&lt;/li&gt;
&lt;li&gt;@EnableAutoConfiguration&lt;/li&gt;
&lt;li&gt;@ComponentScan&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;02. 개발에 앞서 알면 좋은 기초 지식&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서버 간 통신&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 서버가 다른 서버에 통신을 요청하는 것을 의미&lt;/li&gt;
&lt;li&gt;가장 많이 사용되는 방식은 HTTP/HTTPS방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 부트의 동작 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring-boot-starter-web 모듈을 사용하면 기본적으로 톰캣(Tomcat)을 사용하는 스프링 MVC 구조를 기반으로 동작&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서블릿(Servlet)은 클라이언트의 요청을 처리하고 결과를 반환하는 자바 웹 프로그래밍 기술&lt;/li&gt;
&lt;li&gt;서블릿은 서블릿 컨테이너에서 관리한다.&lt;/li&gt;
&lt;li&gt;서블릿 컨테이너는 서블릿 인스턴스를 생성하고 관리하는 역할을 수행하는 주체&lt;/li&gt;
&lt;li&gt;톰캣은 WAS의 역할과 서블릿 컨테이너의 역할을 수행하는 대표적인 컨테이너&lt;/li&gt;
&lt;li&gt;스프링에서는 DispatcherServlet이 서블릿의 역할을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;서블릿 컨테이너의 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기를 관리합니다.&lt;/li&gt;
&lt;li&gt;서블릿 객체는 싱글톤 패턴으로 관리됩니다.&lt;/li&gt;
&lt;li&gt;멀티 스레딩을 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;DispatcherServlet의 동작 과정&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DispatcherServlet으로 요청(HttpServletRequest)이 들어오면 핸들러 매핑을 통해 요청 URI에 매핑된 핸들러를 탐색&lt;/li&gt;
&lt;li&gt;핸들러 어탭터로 컨트롤러를 호출&lt;/li&gt;
&lt;li&gt;핸들러 어댑터에 컨트롤러의 응답이 돌아오면 ModelAndView로 응답을 가공해 반환&lt;/li&gt;
&lt;li&gt;뷰 형식으로 리턴하는 컨트롤러를 사용할 때는 View Resolver를 통해 뷰를 받아 리턴&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;View Resolver는 뷰의 렌더링 역할을 담당하는 뷰 객체를 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰가 없는 REST 형식의 @ResponseBody는 View Resolver를 호출하지 않고 MessageConverter를 거쳐 JSON 형식으로 변환해서 응답&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;레이어드 아키텍처&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션의 컴포넌트를 유사 관심사를 기준으로 레이어로 묶어 수평적으로 구성한 구조를 의미&lt;/li&gt;
&lt;li&gt;3계층 또는 4계층 구성 - 차이는 인프라(데이터 베이스) 레이어의 추가 여부로 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프레젠테이션 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션의 최상단 계층으로, 클라이언트의 요청을 해석하고 응답하는 역할&lt;/li&gt;
&lt;li&gt;UI나 API를 제공&lt;/li&gt;
&lt;li&gt;프레젠테이션 계층은 별도의 비즈니스 로직을 포함하고 있지 않으므로 비즈니스 계층으로 요청을 위임하고 받은 걸 응답하는 역할만 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비즈니스 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션이 제공하는 기능을 정의하고 세부 작업을 수행하는 도메인 객체를 통해 업무를 위임하는 역할을 수행&lt;/li&gt;
&lt;li&gt;DDD(Domain-Driven Design) 기반의 아키텍처에서는 비즈니스 로직에 도메인이 포함되기도 하고, 별도로 도메인 계층을 두기도함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 접근 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스에 접근하는 일련의 작업을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;레이어드 아키텍처 기반 설계의 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 레이어는 가장 가까운 하위 레이어의 의존성을 주입받는다.&lt;/li&gt;
&lt;li&gt;각 레이어는 관심사에 따라 묶여있으며, 다른 레이어의 역할을 침범하지 않는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 컴포넌트의 역할이 명확하므로 코드의 가독성과 기능 구현에 유리하다.&lt;/li&gt;
&lt;li&gt;코드의 확장성도 좋아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 레이어가 독립적으로 작성되면 다른 레이어와의 의존성을 낮춰 단위테스트에 용이하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링의 레이어드 아키텍처&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring MVC는 Model-View-Controller의 구조로 View와 Controller는 프레젠테이션 계층 영역, Model은 비즈니스와 데이터 접근 계층의 영역으로 구분&lt;/li&gt;
&lt;li&gt;비즈니스 계층에 서비스를 배치해 엔티티와 같은 도메인 객체의 비즈니스 로직을 조합&lt;/li&gt;
&lt;li&gt;데이터 접근 계층에서는 DAO(Spring Data JPA에서는 Repository)를 배치해 도메인을 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프레젠테이션 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황에 따라 유저 인터페이스 계층이라고도 함&lt;/li&gt;
&lt;li&gt;클라이언트와의 접점이 됨&lt;/li&gt;
&lt;li&gt;클라이언트로부터 데이터와 함께 요청을 받고 처리 결과를 응답으로 전달하는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비즈니스 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황에 따라 서비스 계층이라고도 함&lt;/li&gt;
&lt;li&gt;핵심 비즈니스 로직을 구현하는 영역&lt;/li&gt;
&lt;li&gt;트랜잭션 처리나 유효성 검사 등의 작업을 수행하기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 접근 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황에 따라 영속 계층이라고도 함&lt;/li&gt;
&lt;li&gt;데이터베이스에 접근해야하는 작업을 수행&lt;/li&gt;
&lt;li&gt;DAO 역할을 Spring Data JPA에서는 리포지토리로 대체할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;디자인 패턴&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인 *패턴은 소프트웨어를 설계할 때 자주 발생하는 문제들을 해결하기 위해 고안된 해결책&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*패턴은 애플리케이션 개발에서 발생하는 문제는 유사한 경우가 많고 해결책도 동일하게 적용할 수 있다는 의미를 내포함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;디자인 패턴의 종류&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;생성 패턴 : 객체 생성에 사용되는 패턴으로, 객체를 수정해도 호출부가 영향을 받지 않게 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;추상 팩토리 :&amp;nbsp;&lt;/b&gt;구체적인 클래스를 지정하지 않고 상황에 맞는 객체를 생성하기 위한 인터페이스를 제공하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빌더 :&amp;nbsp;&lt;/b&gt;객체의 생성과 표현을 분리해 객체를 생성하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팩토리 메서드 :&amp;nbsp;&lt;/b&gt;객체 생성을 서브 클래스로 분리해서 위임하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토타입 :&amp;nbsp;&lt;/b&gt;원본 객체를 복사해 객체를 생성하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;싱글톤 :&amp;nbsp;&lt;/b&gt;한 클래스마다 인스턴스를 하나만 생성해서 인스턴스가 하나임을 보장하고 어느 곳에서도 접근할 수 있게 제공하는 패턴입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;구조 패턴 : 객체를 조합해서 더 큰 구조를 만드는 패턴입니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;어댑터 :&lt;/b&gt; 클래스의 인터페이스를 의도하는 인터페이스로 변환하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브리지 :&amp;nbsp;&lt;/b&gt;추상화와 구현을 분리해서 각각 독립적으로 변형케 하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포지트 :&amp;nbsp;&lt;/b&gt; 여러 객체로 구성된 복합 객체와 단일 객체를 클라이언트에서 구별 없이 다루는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데코레이터 :&amp;nbsp;&lt;/b&gt;객체를 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;퍼사드 :&amp;nbsp;&lt;/b&gt;서브 시스템의 인터페이스 집합들에 하나의 통합된 인터페이스를 제공하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플라이웨이트 :&amp;nbsp;&lt;/b&gt;특정 클래스의 인스턴스 한 개를 가지고 여러 개의 '가상 인스턴스'를 제공할 때 사용하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프락시 :&amp;nbsp;&lt;/b&gt;특정 객체를 직접 참조하지 않고 해당 객체를 대행하는 객체를 통해 접근하는 패턴입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;행위 패턴 : 객체 간의 알고리즘이나 책임 분배에 관한 패턴입니다. 객체 하나로는 수행할 수 없는 작업을 여러 객체를 이용해 작업을 분배합니다. 결합도 최소화를 고려할 필요가 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;책임 연쇄 :&amp;nbsp;&lt;/b&gt;요청 처리 객체를 집합으로 만들어 결합을 느슨하게 만드는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커맨드 :&amp;nbsp;&lt;/b&gt;실행될 기능을 캡슐화해서 주어진 여러 기능을 실행하도록 클래스를 설계하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터프리터 :&amp;nbsp;&lt;/b&gt;주어진 언어의 문법을 위한 표현 수단을 정의하고 해당 언어로 구성된 문장을 해석하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이터레이터 :&amp;nbsp;&lt;/b&gt;내부 구조를 노출하지 않으면서 해당 객체의 집합 원소에 순차적으로 접근하는 방법을 제공하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;미디에이터 :&amp;nbsp;&lt;/b&gt;한 집합에 속한 객체들의 상호작용을 캡슐화하는 객체를 정의한 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메멘토 :&lt;/b&gt; 객체의 상태 정보를 저장하고 필요에 따라 상태를 복원하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옵저버 :&amp;nbsp;&lt;/b&gt;객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버 목록을 객체에 등록해 상태가 변할 때마다 메서드 등을 통해 객체가 직접 옵저버에게 통지하게 하는 디자인 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스테이트 :&amp;nbsp;&lt;/b&gt;상태에 따라 객체가 행동을 변경하게 하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스트래티지 :&amp;nbsp;&lt;/b&gt;행동을 클래스로 캡슐화 해서 동적으로 행동을 바꿀 수 있게 하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;템플릿 메서드 :&amp;nbsp;&lt;/b&gt;일정 작업을 처리하는 부분을 서브 클래스로 캡슐화해서 전체 수행 구조는 바꾸지 않으면서 특정 단계만 변경해서 수행하는 패턴입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비지터 :&amp;nbsp;&lt;/b&gt;실제 로직을 가지고 있는 객체가 로직을 적용할 객체를 방문하며 실행하는 패턴입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;REST API&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대중적으로 가장 많이 사용되는 애플리케이션 인터페이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST 란?&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Representational State Transfer&lt;/li&gt;
&lt;li&gt;분산 하이퍼미디어 시스템 아키텍처의 한 형식&lt;/li&gt;
&lt;li&gt;HTTP 메서드(GET, POST, PUT, DELETE)를 통해 해당 자원의 상태를 주고받는 것을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST API란?&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API는 Application Programming Interface의 약자&lt;/li&gt;
&lt;li&gt;애플리케이션에서 제공하는 인터페이스를 의미&lt;/li&gt;
&lt;li&gt;서버 또는 프로그램 사이를 연결&lt;/li&gt;
&lt;li&gt;REST 아키텍처를 따르는 시스템/애플리케이션 인터페이스라고 볼 수 있음&lt;/li&gt;
&lt;li&gt;'RESTful 하다'라고 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST의 특징&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;유니폼 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일관된 인터페이스를 의미&lt;/li&gt;
&lt;li&gt;어떤 프로그래밍 언어로 만들어졌느냐와 상관없이 종속되지 않고 타 언어, 플랫폼, 기술 등과 호환해 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;무상태성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에 상태 정보를 따로 보관하거나 관리하지 않는다는 의미&lt;/li&gt;
&lt;li&gt;세션이나 쿠키 정보를 별도로 보관하지 않는다&lt;/li&gt;
&lt;li&gt;불필요한 정보를 관리하지 않으므로 비즈니스 로직의 자유도가 높고 설계가 단순&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;캐시 가능성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP의 캐싱 기능을 적용할 수 있음&lt;/li&gt;
&lt;li&gt;캐싱이 가능한 경우 클라이언트에서 캐시에 저장해두고 같은 요청에 대해서는 해당 데이터를 가져다 사용&lt;/li&gt;
&lt;li&gt;서버의 트랜잭션 부하가 줄어 효율적이며 사용자 입장에서 성능이 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;레이어 시스템&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 상의 여러 계층으로 구성될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;클라이언트-서버 아키텍처&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST 서버는 API를 제공하고 클라이언트는 사용자 정보를 관리하는 구조로 분리해 설계합니다.&lt;/li&gt;
&lt;li&gt;서로에 대한 의존성을 낮추는 기능을 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST의 URI 설계 규칙&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;URI의 마지막에는 '/'를 포함하지 않습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;옳은 예) http://localhost.com/product&lt;/li&gt;
&lt;li&gt;잘못된 예) http://localhost.com/product/&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;언더바(_)는 사용하지 않습니다. 대신 하이픈(-)을 이용합니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;옳은 예) http://localhost.com/provider-company-name&lt;/li&gt;
&lt;li&gt;잘못된 예) http://localhost.com/provider_company_name&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;URL에는 행위(동사)가 아닌 결과(명사)를 포함합니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;옳은 예) http://localhost.com/product/123&lt;/li&gt;
&lt;li&gt;잘못된 예) http://localhost.com/delete-product/123&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;URI는 소문자로 작성해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;파일의 확장자는 URI에 포함하지 않습니다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/38</guid>
      <comments>https://jamni.tistory.com/38#entry38comment</comments>
      <pubDate>Fri, 27 Sep 2024 01:53:40 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 회고</title>
      <link>https://jamni.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;(※명수옹 주의 ※)&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이제 진짜 마지막이네요.&lt;br&gt;&amp;nbsp;&lt;br&gt;이 회고를 언제가는 쓰게 될 것이라 생각했었는데&lt;br&gt;너무 일찍 쓰게 된 것은 아닌지 ...&lt;br&gt;&amp;nbsp;&lt;br&gt;어떻게 작성을 해야할지도 잘 모르겠습니다.&lt;br&gt;&amp;nbsp;&lt;br&gt;2024년에 졸업을 앞두고 막막하던 시점 같이 수강한 현서의 도움으로 알게 됐고, 같이 수강하게 되었습니다.&lt;br&gt;그렇게 강사님과 매니저님들 그리고 다른 수강생들과 함께 추운 겨울에 시작해서 무더운 여름에 마무리 지었네요.&lt;br&gt;껄껄... 어우 오글거려 ㅋㅋㅋㅋㅋㅋ&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;초반 내 실력?&lt;/b&gt;&lt;/h4&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHzs1S/btsJeC29HSu/Ipohyx1rYsxC0kt7BHkC61/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHzs1S/btsJeC29HSu/Ipohyx1rYsxC0kt7BHkC61/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHzs1S/btsJeC29HSu/Ipohyx1rYsxC0kt7BHkC61/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHzs1S%2FbtsJeC29HSu%2FIpohyx1rYsxC0kt7BHkC61%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;512&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터공학과를 전공했지만 정말 처참했습니다...ㅋㅋ 할 줄 아는 거라곤 발표와 PPT 만들기? 이거라도 잘했으면&lt;br&gt;영업직으로 빠졌을 거에요.&lt;br&gt;진짜 코딩도 제대로 못하고, 발표도 엉망, 디자인 감각이라곤 1도 찾아볼 수 없어서 PPT도 엉망, 서버는 뭔데? 할 정도의 정말 난 뭐였을까... 상태였습니다. 진짜로.&lt;br&gt;이제와서 솔직하게 말하면 프론트엔드 공부해서 프론트엔드로 가려고 했는데요. 백엔드가 연봉이 더 많다는 소리를 어디선가 들은거 같아서 무작정 백엔드 부트캠프 찾다가 현서랑 지원했습니다 ㅋㅋㅋㅋㅋㅋㅋㅋ&lt;br&gt;백엔드만 할 줄 알고 신청했던 부트캠프가 사실 풀스택 백엔드 였지만!! 이것은 오히려 좋아.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지금 내 실력?&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;객관적으로 생각해보면 잘하진 않다고 생각합니다.&lt;br&gt;강사님께서는 항상 제가 생각하는 것보다 저는 잘한다고 말해주셨고, 최종 프로젝트 팀장이었던 미람이도 잘한다고 말해줬고, 잘한다 잘한다 하니까 혼란이 오는데요. 저는 잘하진 않는다고 생각합니다. 앞으로도 그렇게 생각할거고, 항상 부족함을 느끼고 공부....해야죠 그쵸... 이 쪽 길로 발을 들인 이상 계속 공부해야죠...&amp;nbsp;&lt;br&gt;그래서 지금 실력이 어느 정도냐구요? 시간만 널널하고 제가 부지런하다면 웹 사이트 하나 정도는 만들 수 있지 않을까... 싶습니다. 무엇보다 자신감이 생겼답니다 룰루~&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdIisC/btsJfHvAZgG/TF6vWHflqDfeQ2MU3GP6Q0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdIisC/btsJfHvAZgG/TF6vWHflqDfeQ2MU3GP6Q0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdIisC/btsJfHvAZgG/TF6vWHflqDfeQ2MU3GP6Q0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdIisC%2FbtsJfHvAZgG%2FTF6vWHflqDfeQ2MU3GP6Q0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;309&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 글로만 보시는 분들은 어떨지 모르겠지만 제가 직접 느끼는 건 또 다르거든요. 진짜 매일 코딩하고 공부하고 하니까 늘어요. 신기하게 늘어요. 아니 사실 안 늘면 이상합니다...ㅋㅋㅋㅋㅋ&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;부트캠프 하면서 일과&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;9시에 출근? 입실하구요. 평균적으로 9시에 퇴근? 퇴실했습니다. 예 진짜로.&lt;br&gt;집에서는 코딩도 공부도 안되는 성격이라 수업 끝나면 그냥 캠퍼스에 남아서 할 거 다하고 가는 편이었습니다. 물론 일찍 간 날도 많았죠. 근데 9시 30분 이후에 간 날이 훨~~~씬 많을 거에요.&lt;br&gt;이렇게 하는데 안늘면... 이 길이 아닌거죠 뭐 120일 동안 하루에 열두시간... 1440시간... 생각보다 안되네요?&lt;br&gt;진짜 많은 시간 공부했다 생각하고 계산해봤는데... 에잉 ..&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfPmpC/btsJd9AupFR/RiN9DgrNUUPDS6787kY6bK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfPmpC/btsJd9AupFR/RiN9DgrNUUPDS6787kY6bK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfPmpC/btsJd9AupFR/RiN9DgrNUUPDS6787kY6bK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfPmpC%2FbtsJd9AupFR%2FRiN9DgrNUUPDS6787kY6bK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;375&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반에는 알바도 같이 했습니다. 평일에는 9 to 21로 공부하고 주말에는 8시 30분 오픈 알바(빽다방 경력 1년 차)로 돈 벌고!! 진짜... 이거 사람이 할 짓 못됩니다... 사람은 잠을 자야돼요... 주변에서 대단하다고 진짜 어떻게 그렇게 하냐고... 그런 말에 '&lt;b&gt;에이.. 다들 저보다 열심히 사시는데요 뭘...&lt;/b&gt;' 이라고 대답했지만 사실 속마음은 '&lt;b&gt;맞아요!!! 진짜 이렇게 못살아요 ㅠㅠㅠ 살려주세요 ㅠㅜ&lt;/b&gt;' 였다는 ... 하지만 인생에 있어서 이렇게 열심히 살아보는 것도 좋은 경험이라 생각하고 열심히 살았습니다 !&lt;br&gt;&amp;nbsp;&lt;br&gt;마지막 회고에는 또 무슨 말을 적어야 좋을까요 후후...&lt;br&gt;그냥 다 적어봅니다 진짜 그냥 싹다 적어요!!!&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;최고의 스승!!&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;제 실력을 이렇게까지 끌어올린데 한 몫하신건 누가 뭐라 그래도 강사님이죠.&lt;br&gt;진짜 강사님 최고였습니다. 수업이 솔직히 노베이스 비전공자라면 어려울 것 같긴 했어요. 왜냐면 저도 그렇게 느꼈으니까... 하지만 !! 잠재력을 끌어올려주시는데 진짜 능력 있으신 분....&lt;br&gt;때로는 냉정하게 말씀해주시면서도 때로는 따뜻하게 말씀해주시고 자신감 심어주시고 !! 무엇보다도 동네 친한 형 같은 느낌을 주셨답니다. 수업이 끝나고 남아서 공부하는 수강생들도 늦게까지 봐주시다가 퇴근하시고 !! 이런 강사님 또 있으면 나와보라 그래~~&lt;br&gt;아직도 저에게 처음 주어주셨던 과제가 있었는데... 자바의 특징... SOLID ... 공부하고 예제 코드 짜오기 ... 이거 진짜 초반에 할 땐 너무 힘들었거든요 ... 근데 그 때 이거 안했으면 저 지금까지 성장 못했습니다..&lt;br&gt;그리고 무심해 보이시지만 생각보다 학생에게 관심이 엄청 많으셨어요. 툭 던져 질문한 거 다 기억하셨다가 나중에 그거 관련해서 과제도 내주시고 저도 기억 못하는거 다 기억하시고...!! 강사님은 천재가 맞으십니다.&lt;br&gt;최종 시작하시면서 &quot;이제 수료하면 나 없다~&quot; 하시던 말씀을 수료식 당일날 &quot;월요일부터 나 없다~&quot; 하시는데 뭉클 ... 울컥 ..&lt;br&gt;이제 누가 나한테 맞춤 과제 내줘... 누가 나 공부하라고 옆에서 쓴 소리 해줘!!!&lt;br&gt;&amp;nbsp;&lt;br&gt;네. 이제 제가 해야겠죠? 하하... 열심히 살아봅시다... 강사님 감사했습니다...&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;매니저님들&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;매니저님들도 감사한게 참 많죠 !! 제 회고도 항상 읽어주시고... 댓글 달아주시고... 이거 댓글 달아주시는거 다 읽어보는데 대충 보고 댓글 다는게 아닌 진짜 꼼꼼하게 다 읽어보시고 댓글 달아주시는!! 그런 댓글들이 저를 힘나게 하시는거 또 어떻게 아시고 ... 회고 완주 하는 것이 OT때부터 목표였습니다. 진짜 꼭 열심히 해보자. 하는 마음가짐으로 다른 건 몰라도 회고 만큼은 다 채우자 하고 목표를 잡았는데 제가 쓰는 회고에 자꾸 고맙다고 해주시는데 그런 말을 듣고 제가 더 열심히 쓰게 되잖아요!! ... 물론 마지막엔 바빠서 대충대충 적긴 했지만 ㅎ 엄청 꼼꼼하게 신경써주시고 지나가다 뵈면 피곤해 보인다고 걱정도 해주시고... 맛있는 것도 주시고 !! 월간 회고에 작성했지만 맛있는 거 주는 사람 = 착한 사람 입니다.&lt;br&gt;아플 땐 약도 챙겨주셨답니다 ... 매니저님들의 케어가 없었다면 지금의 저는 조금 더 부족했을 겁니다. 다른 매니저님들이랑도 이제 막 친해졌는데 !! 수료라니 ... 저희 그냥 눈 딱 감고 3개월만 더 하시죠... 그냥 3개월 더 열심히 할 수 있으니까 딱 3개월만 ... 이대로 끝내기는 아쉽단 말이야 ~&lt;br&gt;&amp;nbsp;&lt;br&gt;아무튼 감사했고 즐거웠습니다. 매니저님들 !&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;캠퍼스?&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;캠퍼스 입구에 카페 아니라고 적혀 있을 정도로 카페로 오해할만한... 그만큼 쾌적한 라운지와 강의실 !! ㅋㅋㅋㅋㅋㅋㅋ&lt;br&gt;집중 안될 때 라운지에 나가서 딱 공부하면 그것만큼 공부 잘되던게 없었는데... 이제 못느끼네 ... 아쉽다 ...&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;수강생들&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;비록 OT때 인원과는 약간의 변동이 있었던 최종 수료 인원들 마지막까지 같이 수료한 14명과 취업해서 조기 수료한 1명! 그리고 항상 대단하고 느꼈지만 중간에 나간 1명까지! 모두들에게 정말 많은 걸 배웠고, 분위기가 참 좋아서 잊지 못할 것 같아요.&lt;br&gt;친구처럼 대해주신 형들도 감사했고 좋은 말만 해줬던 친구들이랑 항상 재밌게 해준 동생들까지 완벽 그 자체였던 백엔드 5기였습니다 !! 이 멤버 리멤버 ...&lt;br&gt;&amp;nbsp;&lt;br&gt;응 맞아. 더 할 말 없어.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;프로젝트?&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 참 많았는데요. 대충 얘기해보자면 커리큘럼에 없었던 자바 프로젝트가 하나 더 추가해서 총 6개입니다.&lt;br&gt;맨 처음 자바를 배우고 강사님께서 자바 프로젝트를 내주셨는데요. &lt;b&gt;호텔 관리 프로젝트&lt;/b&gt;였습니다.&lt;br&gt;이 때 처음으로 컨트롤러, 서비스 이런 식으로 나눠서 코딩을 해본 것 같은데 흐름이 눈에 보이고 잡혀버리니까 이거이거... 재밌더라구요 후후 ... 어쩌면 백엔드가 적성에 맞나봐요. 이때는 수진이의 도움을 많이 받은 것 같아요. 첫 번째 팀이 수진이었기에 급 성장을 하지 않았나 ... main 메소드를 2개 만들고 서비스부터 DB까지는 1개로 고객 쪽 main과 호텔 관리 쪽 main으로 데이터를 공유하는 프로젝트... main 2개인 걸 신박하고 좋았다고 평가 해주셨다. Thread 사용해서 체크아웃이 됐을 때 방청소를 해서 객실까지 비워주는 그런 프로젝트! 지금 생각해보니까 진짜 잘했잖아? 오...&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;두 번째 프로젝트 Welon!!&amp;nbsp;&lt;/b&gt;&lt;br&gt;Melon에서 M만 뒤집은 Welon인데 음원 사이트 느낌으로 만드는 프로젝트였다. 사실 Front-end 프로젝트였는데 이 당시 판단 미스로 프론트보다 서버에 집중했단 사실 ... 하지만 이 때 서버를 하지 않았더라면 서버랑 친해지기 더 어려웠겠지 ..&lt;br&gt;처음하는 서버에 처음으로 nest.js를 사용해야한다는 것이 진짜 멘붕 그 자체였고, 다대다 매핑이랑 ELK Stack도 적용시켜서 했어야하는지라 진짜 멘붕 그 자체... 돌이켜보면 이 프로젝트가 제일 힘들었던 것 같다...&lt;br&gt;하지만 이 프로젝트 덕분에 프론트 - 서버간 통신도 자리 잡히게 되었고, 무엇보다도 서버가 무엇인지 제대로 알게된 프로젝트! Elastic search로 검색 기능까지 넣었던 프로젝트. 이것도 내 성장에 많은 도움을 줬던 프로젝트다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;세 번째 프로젝트 Joream&lt;/b&gt;&lt;br&gt;이 프로젝트는 이제 MSA를 사용해서 하려던 프로젝트였는데 이 당시 MSA의 개념을 잘 못 이해해서 MSA인줄 알고 했던 프로젝트가 사실 모놀로식으로 구현했다는 ... Cream 사이트 클론 코딩한 프로젝트였는데, 나는 오히려 이 때 프론트를 좀 더 열심히 하지 않았나... 이거 완전 커리큘럼대로 안하고 말 안듣는 짱구였잖아.&lt;br&gt;Welon 때 했던 다대다 매핑을 다시 한 번 사용해볼 수 있는 기회! 덕분에 다대다는 어떻게 구현해야될지 감이 잡힌 그런 프로젝트였다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;네 번째 프로젝트 Naver 부동산&lt;/b&gt;&lt;br&gt;이 프로젝트는 이제 4개의 팀이 하나의 네이버를 만드는 것이었다. 우리 팀이 맡았던 건 네이버 부동산 파트. 네이버 부동산은 거의 대부분 지도에서 이뤄진 시스템이라 네이버 지도 API를 사용하는 것이 관건이었는데 빛홍범 덕분에 많은 걸 배웠고, 대희석 덕분에 토큰 사용하는 것 까지 공부할 수 있었던... 또 당시 어려워하던 진석이 알려준다고 내 성장에 도움이 되었던 !! 이 프로젝트 때 뭔가 가장 많은 성장을 했던 것 같기도? API도 써보고, 토큰도 써보고, 이 때 했던 프로젝트가 처음으로 시도했던 MSA가 되는 것 같다. 이 전 프로젝트는 잘못 설계를 했으니..&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;다섯 번째 프로젝트 동행복권 클론 코딩&lt;/b&gt;&lt;br&gt;강사님의 칭찬을 많이 받았던 동행복권. 만족만족 대만족 !! 프로젝트 설계 단계에서 가장 많은 고민을 했었던 프로젝트 !!&lt;br&gt;여기서 가장 기억에 남는 것은 Redis의 분산락을 사용해서 동시성 처리를 했던 것 같다. 사실 이거 아직도 어렵다 ... 이거 다시 공부하는 것이 가장 큰 과제로 남아있다...ㅠ&lt;br&gt;또 제대로된 MSA를 해본 것이 아닌가! 동행복권 사이트야 말로 진짜 로또면 로또 / 연금복권이면 연금복권 딱 나눠져있고 여기서 연금복권 서버에서 또 어느 쪽에 부하가 많이 걸릴 것인지 고민해보고 서버를 또 나누는 걸 생각하는 과정이 진짜 재밌었던 것 같다. 사실 머리아프고 힘들었지만 코딩에서는 그게 재밌는 것 같다.&lt;br&gt;데이터의 흐름이 눈에 보인다고 하셔서 데이터 흐름 생각하면서 DFD 그려봤던 것이 얼마나 재밌던지 ... 그때 그 기분은 잊지 못해...&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;마지막 프로젝트 딸깍 금융 프로젝트&lt;/b&gt;&lt;br&gt;최종 프로젝트였다. React-Native, Expo를 사용해서 어플로 만들었던 금융 프로젝트.&lt;br&gt;Spring Batch, GraphQL, MongoDB까지 또 새로운 시도를 해봤던 프로젝트 !! 다른 프로젝트에서도 사용할 수 있게끔 구현해낸 결제 API까지 완성도는 가장 좋았던 프로젝트였고, 진짜 프로젝트처럼 스크럼도 진행하고 사장 계획에 맞춰서 진행됐기에 진짜 현업에서 하던 프로젝트와 가장 가까운 느낌으로 경험해볼 수 있었던 프로젝트였다.&lt;br&gt;이 프로젝트 또한 MSA로 진행했긴 했으나 은행 특성상 연결된 부분이 너무 많았기 때문에 MSA보다는 모놀로식이 더 맞는 프로젝트였던 것 같은 아쉬움이 있긴했다.&lt;br&gt;&amp;nbsp;&lt;br&gt;자바도 겨우 알던 내가 여기까지 성장할 거라고 생각치도 못했다 ...&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;앞으로의 계획에 대해서 몇 가지 목표&lt;/b&gt;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;강사님이 수료식 회식 때 하신 건배사가 있다!&lt;br&gt;&quot;다른 건 몰라도 깃허브에 잔디밭 끊기면 회사가 싫어한다!&quot;&lt;br&gt;ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 진짜 마지막까지 강사님이셨다.&lt;br&gt;이 말듣고 정신 확 차려졌다 ... 또 수료 전 며칠동안 코딩테스트를 준비해야한다고 하셨다.&lt;br&gt;그래서 아마 적어도 평일에 코테 한 문제 이상씩 풀고 깃에 커밋을 하지 않을까 싶다!&lt;br&gt;이게 첫 번째 목표고 두번째 목표는 취업해야죠잉~~&lt;br&gt;매니저님의 댓글처럼 우리의 목표는 1승 !! 이력서와 자소서 준비 야무지게 해서 취뽀 해보자고~~&lt;br&gt;취업하면 여기저기 베풀고 싶은 곳이 많다 ...&lt;br&gt;&amp;nbsp;&lt;br&gt;이제 진짜 끝이네요. 부트캠프 회고는 여기서 마무리 되지만 개발자로서 회고는 계속...될걸요? ㅋㅋㅋㅋㅋㅋㅋㅋ 열심히 하는 개발자가 돼야죠,, 기대해주세요!&lt;br&gt;저는 그럼 이제 진짜 안녕 해보도록 하겠습니다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PiyAa/btsJeRFFBqG/b9jDkjyEjJ2fK2VJJkygGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PiyAa/btsJeRFFBqG/b9jDkjyEjJ2fK2VJJkygGk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PiyAa/btsJeRFFBqG/b9jDkjyEjJ2fK2VJJkygGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPiyAa%2FbtsJeRFFBqG%2Fb9jDkjyEjJ2fK2VJJkygGk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;430&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정들었습니다. 플레이데이터.. ㅠㅜㅠ (중간에 명수옹 안넣었으니까 마지막에 좀 많이 넣을게요)&lt;br&gt;그리울거에요.. 취업하고 명함드리러 오겠습니다 !&lt;br&gt;&amp;nbsp;&lt;br&gt;그럼 안녕 !&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kIvyR/btsJe90qpx4/St0M4nZjoqKK9kkBnURsG1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kIvyR/btsJe90qpx4/St0M4nZjoqKK9kkBnURsG1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kIvyR/btsJe90qpx4/St0M4nZjoqKK9kkBnURsG1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkIvyR%2FbtsJe90qpx4%2FSt0M4nZjoqKK9kkBnURsG1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baHRHd/btsJfkUZGRn/OoCIabXK08KxQeryF9SBC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baHRHd/btsJfkUZGRn/OoCIabXK08KxQeryF9SBC0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baHRHd/btsJfkUZGRn/OoCIabXK08KxQeryF9SBC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaHRHd%2FbtsJfkUZGRn%2FOoCIabXK08KxQeryF9SBC0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;736&quot; height=&quot;618&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;</description>
      <category>playdata 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/37</guid>
      <comments>https://jamni.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 26 Aug 2024 02:17:16 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 6개월 차 회고</title>
      <link>https://jamni.tistory.com/36</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;뭐지? 분명 5개월 차 회고 쓴지 얼마 안됐는데 왜 벌써 돌아왔지~~~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만큼 이번 8월 짧게 느껴졌다.(실제로 23일이니까 짧기도 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 프로젝트 / 전반적인 느낀 점 / Keep / Problem / Try로 나눠서 월간 회고를 써봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1개월 간 프로젝트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 달에는 특별한 기능을 추가한 것 없이 버그와의 사투였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계를 잘 못했던 탓인지 너무 많은 버그가 있었다. MongoDB의 데이터가 변하지 않는 버그, 데이터가 변하면 변한대로 다른 부분에도 적용이 되어야하는데 적용이 안되는 버그 등 기능적으로도 버그가 많았고,&amp;nbsp; Batch 서버 배포가 되지 않는 문제 때문에 또 힘들었었다. 그만큼 이번 프로젝트에서 설계의 중요성을 느꼈다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 주에는 쉬엄쉬엄 이력서도 쓰면서 발표 준비를 할 줄 알았는데 마지막 주까지도 버그를 잡았었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 모든 버그를 다 잡고 겉으로 보기에 전~혀 문제 없는 프로젝트를 완성시키고(진짜 무슨 문제가 있는지 모름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미람이의 캐리로 프론트 퍼블리싱까지 예쁘게 만들어서 발표를 했다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;전반적인 느낀 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트는 기간이 2주, 1개월, 2개월. 며칠을 줘도 기간이 짧게 느껴지는 것 같다. 하하...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 가면 정신 없이 버그 틀어막느라 코드 더러워지고,,, 커밋 막 하고,,, 프로젝트 관리 안하고,,, WBS 다 무시하고 !!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅋ.... 내가 너무 잘 못하고 있나... 라는 생각이 들 때 쯤 현업에 계신 분들도 대부분 그렇게 하신다는 멘토님의 따스한 한마디 ... 아 다시 생각해도 따뜻하다..ㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 다행이었던 것은 멘토님이 정말 너무 좋으신 분이셔서 팀원들이 모두 만족만족 대만족이었다는 점이다. 프로젝트 피드백도 해주시고, 취업할 때 도움 되는 이야기도 많이 해주시고, 맛있는 것도 많이 사주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맛있는 거 사주는 사람 = 착한 사람&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Keep&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6개월 간 열심히 했던 지금 열정 잊지 않고 취업 준비까지 열심히 달려봐야겠다 ! 그것만이 이제 내가 계속 지켜나가야할 목표&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Problem&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제.. 문제라고 하면 좀 아프다. 최종 발표 그리고 수료에 맞춰서 그 동안 쌓인 피로가 터진 것인지 몸이 좀 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후딱 털고 일어나야지&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Try&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이력서 넣어보자. 이제는! 진짜로 취업하면 커피 사들고 캠퍼스 놀러갈거임. 다들 반겨주시겠지... 안 반겨주시면.. 나 울어&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 주간 회고, 마지막 월간 회고, 부트캠프 회고까지 3개의 회고를 다 쓰자니 주간회고와 월간회고에 무슨 말을 적어야할지 모르겠다 ㅎ.&lt;/p&gt;</description>
      <category>playdata 회고/월간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/36</guid>
      <comments>https://jamni.tistory.com/36#entry36comment</comments>
      <pubDate>Sun, 25 Aug 2024 23:50:15 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 마지막 주 차 회고</title>
      <link>https://jamni.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;플레이데이터 백엔드 개발 부트캠프 26주 차 회고(8월 3주 차)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벌써 6개월이 지나 마지막 주간 회고를 작성한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 마지막 주였다. 일단 내 서버에서는 큰 문제는 없었다. 다른 팀원들이 맡은 파트에서 약간의 버그가 있어서 다른 팀원들이 수정을 진행하고, 나는 다이어그램을 그렸다. 저번 프로젝트에서 Data Flow Diagram을 그리는게 재밌어서 이번에도 눈에 보이는 데이터의 흐름을 그렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;거래 내역 DFD.png&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baxGY8/btsJfpBC0TP/lby07sdevTSviZczZxgWO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baxGY8/btsJfpBC0TP/lby07sdevTSviZczZxgWO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baxGY8/btsJfpBC0TP/lby07sdevTSviZczZxgWO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaxGY8%2FbtsJfpBC0TP%2Flby07sdevTSviZczZxgWO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1223&quot; height=&quot;832&quot; data-filename=&quot;거래 내역 DFD.png&quot; data-origin-width=&quot;1223&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거래 내역파트만 그렸었는데, 다른 쪽 DFD를 그리다 보니 전체적으로 한번에 그리는 것이 나아보여서 전체적인 DFD를 그렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;전체 DFD.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGZzQ/btsJeb5uBwU/dp9YPgj44iy4agd1AcOCLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGZzQ/btsJeb5uBwU/dp9YPgj44iy4agd1AcOCLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGZzQ/btsJeb5uBwU/dp9YPgj44iy4agd1AcOCLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGZzQ%2FbtsJeb5uBwU%2Fdp9YPgj44iy4agd1AcOCLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2192&quot; height=&quot;1072&quot; data-filename=&quot;전체 DFD.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1072&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음.. 좀 복잡한가? 싶었는데 깔끔하고 좋다는 평을 많이 받아서 그냥 사용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버간 어떤 데이터를 주고 받으면서 통신을 하는지 다이어그램을 통해서 볼 수 있어서 좋고, DFD를 그리다보면 다른 서버도 이해가 더 잘되는 것 같아서 DFD 그리는 게 참 재밌었던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일에 마지막 멘토링이 있었는데, 그간 버그와 프론트의 미완성 때문에 보여드리지 못했던 프로젝트를 결국 마지막이 되어서야 멘토님께 보여드렸다. 여러 버그에 대한 답변도 들었고, 내 파트에서는 카테고리 별 지출이 이런 점이 추가되면 좋겠다 라는 피드백을 들었다. 그 부분을 화요일에 수정을 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 회고에서 한번 올린 적이 있었는데&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cA8HdO/btsJfCt0gd0/mB8hWKNiQqmGSyGhKVyTk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cA8HdO/btsJfCt0gd0/mB8hWKNiQqmGSyGhKVyTk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cA8HdO/btsJfCt0gd0/mB8hWKNiQqmGSyGhKVyTk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcA8HdO%2FbtsJfCt0gd0%2FmB8hWKNiQqmGSyGhKVyTk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;378&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 밋밋한 화면과 어떤 카테고리에 돈을 썼는지는 알겠다만 얼마나 썼는지는 모를 것 같은 그래프와 색이 비슷해서 구분도 제대로 안가던 이 카테고리 별 지출은 수정을 통해서&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VSX2j/btsJfoW1kJQ/QckwoklnukXYNJxrKrSFyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VSX2j/btsJfoW1kJQ/QckwoklnukXYNJxrKrSFyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VSX2j/btsJfoW1kJQ/QckwoklnukXYNJxrKrSFyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVSX2j%2FbtsJfoW1kJQ%2FQckwoklnukXYNJxrKrSFyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;421&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;1231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 변했다. 지금 생각해도 바꾸길 잘한 것 같다. 프론트 퍼블리싱 수정해준 미람이에게 박수 !!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트는 미람이가 수정해줬고, 얼마나 썼는지 볼 수 있게, 어디에 많이 썼는지 정렬하는 부분은 내가 수정을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS로 배포를 진행하려고 했는데, 아직 제대로 배포가 되지 않아서 혹시 몰라서 GCP를 하나 새로 팠다. 곧 무료 이용이 만료였기 때문 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 판 GCP로 서버를 새로 다시 띄우고 Jenkins도 새로 띄웠기 때문에 백업해뒀던 파이프라인을 다시 작성해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 이제 슬슬 진짜 발표였기 때문에 발표 준비도 시작해야했다. 피피티도 만들고, 대본도 대충 작성해보고,,, 바빴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면 프로젝트하면서 이력서도 썼어야하니까 ... 내가 할 파트는 거의 다 한 것 같아서 이력서 작성하는데 좀 오랜 시간 사용한 듯 하다. 이력서는 여전히 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이력서 사진 찍는다고 휴가쓰고 수업 늦게 갔다. 사진 찍고 점심 쯤 가서 제일 먼저 아키텍쳐 다이어그램을 그렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS로 배포를 진행할 줄 알고 AWS로 아키텍쳐 다이어그램을 그렸는데 결국 마지막까지 AWS는 제대로 배포하지 못했고, 결국 GCP로 배포를 해서 GCP 버전으로 다시 그렸다. 이 후 이력서 피드백도 받고 발표 준비를 하고 있었는데,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 몸이 안좋아지기 시작했다. 느낌이 좋지 않았다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들한테 양해를 구하니까 내가 해야할 부분은 다 했으니 일찍 들어가서 쉬라고 했다.. 다들 정말 고마워요...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발표 당일&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아침에 일어나서 보니 다들 새벽까지 열심히 했었다 ... 진짜 너무 미안했다. 갑자기 몸이 너무 안좋아져서 ... 발표라도 잘해야겠단 생각 때문에 학원에 가서 발표에 신경을 최대한 썼던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 다행히 만족스럽게 마무리 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수료식까지 마무리 하고 다 같이 회식하러 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 느낀 점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 이번 프로젝트에서 Spring Batch, MongoDB, GraphQL, ReactNative 등 처음 사용해보는 기술들을 많이 써봐서 좋았다. 내가 사용할 수 있는 기술 스택이 조금 늘어서 좋은 것도 있지만 중요한 프로젝트에서 처음 써보는 기술을 잘 마무리해서 사용할 수 있다는 자신감이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각하기엔 내가 맡은 부분이 다른 팀원들이 한 부분보다 한게 없다고 생각했는데 오히려 팀원들은 내가 여러가지 기술 쓴 것에 대해서 좋게 평가해주고, 많이 했다고 얘기해줘서 고마웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주 느낀 점!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 주간 회고 마지막이다. 벌써 26주가 지났다니. 믿겨지지 않는다. 나도 내가 이걸 다 쓸 줄 몰랐는데 열심히 하긴 했나보다. 사실 대학교 4년보다 이번 6개월을 훨씬 열심히 산 것 같다. 빨리 취업하고 싶으니까 한 두달 더 열심히 살아서 후딱 취업해버려야겠다.&lt;/p&gt;</description>
      <category>playdata 회고/주간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/35</guid>
      <comments>https://jamni.tistory.com/35#entry35comment</comments>
      <pubDate>Sun, 25 Aug 2024 18:27:23 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 25주 차 회고</title>
      <link>https://jamni.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;플레이데이터 백엔드 개발 부트캠프 25주 차 회고(8월 2주 차)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 주 몽고DB의 업데이트를 시도하다가 실패하고 다시 시도하였다. 분명 setter를 실행한 뒤에 새로 save를 해주면 된다는 블로그를 많이 봤는데 계속해서 PK인 ID의 중복때문에 해결하지 못했다. 그래서 잠시 쉬어갈 겸 다른 부분의 수정을 시도했다. 월 별 지출을 보여주는 페이지가 있는데 생각하고 보니 월이 바뀔 때, 지출의 값을 초기화 해주지 않았던 것이 기억 나서 수정이 들어갔다. 어떻게 하면 좋을까 고민하다 Disable이란 필드를 새로 추가해서 매월 1일 스케쥴러를 통해 disable 필드의 값을 false로 바꿔주고 새로 저장되는 값은 true로 저장해서 값을 읽어올 때 true인 값만 꺼내오게 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 몽고DB의 수정은 다른 팀 성민이형의 도움을 받아 setter를 사용하지 않고 mongotemplate으로 쿼리문으로 직접 바꿔주는 방식으로 수정했다. 그랬더니 귀신 같이 성공 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이리저리 프론트를 확인하면서 테스트를 하다 보니 버그가 상당히 많았다... 이번 버그는 카테고리를 수정해도 카테고리 별 지출이 변하지 않는 버그를 찾아서 수정에 들어갔다. 수정이 이뤄질 때 이전 카테고리 값에 해당하는 가격을 (-) 해주고 새로 바뀌는 카테고리의 값을 (+) 해주는 것이 시간이 부족한 시점 가장 빠르게 수정할 수 있을 것 같아서 그 방법으로 진행했다. 그 외로도 입금인데 지출로 잡히는 버그까지 있었다.. 버그를 적다 보니 버그가 참 많았다. 이 부분은 간단하게 출금일 때만 지출 저장하는 방식으로 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 전부터 말했던 Paging을 드디어 도입시켰다. +더보기 버튼을 하나 만들어서 누를 때마다 count 값을 증가시켜서 Page의 값으로 사용하고 size는 10으로 고정시켰다. 데이터를 가져왔을 때 10보다 작은 경우 더보기 버튼을 보이지 않게 프론트에서 추가해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강사님이 ArgoCD로도 배포를 진행해보라 하셔서 블로그 찾아보면서 해봤다. 어렵지 않았다. 그냥 Helm, Kubernetes 하는 기분. 다 하고 보니 ArgoCD 나쁘지 않았따. 배포된 서버를 모니터링 할 수 있다는게 가장 좋았던 것 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수요일&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웬만한 버그들을 다 고쳐서 내가 시간이 좀 떴었다. 간단하게 미람이가 알려준 Pull To Refresh 기능을 추가하고(위에서 밑으로 화면을 쭉 당겼을 때 새로고침) 기억도 나지 않을 정말 짜잘한 버그들을 몇개 고친 것 같다. 이제 정말 끝이 보였다 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광복절 기념 휴식을 취했습니다...ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버, 프론트도 다 수정을 했다 생각해서 나 먼저 문서작업에 들어갔다. GitHub에 올린 내 서버에 대한 Readme를 작성하고 그간 소홀해졌었던 Project 관리와 WBS 작성도 진행했다. 발표 자료에 추가할 아키텍쳐다이어그램과 데이터 플로우 다이어그램도 완성시켰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;느낀 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각했던 것보다 설계를 잘못했다는 걸 크게 느꼈다. 버그 수정도 엄청 많았고, 수정하게 되는 로직도 많았다. 아마 내가 찾지 못한 버그들이 더 남아 있을 것 같다. 하지만 이제 점점 진짜 마무리 되어가는 느낌을 받았다. 다음 주가 마지막이라 생각하니 시원섭섭하기도 하고 두렵기도 하다... 취업의 벽... 마무리 잘 해서 좋은 프로젝트로 남기고 포트폴리오 쓰고 싶다. 팀원들 사이에서 수료 하고도 더 업그레이드 시킬 생각 있는지에 대해 말이 나오고 있다. 아마 수료하고도 더 업그레이드 시키지 않을까... 빨리 취업하고파 ~~&lt;/p&gt;</description>
      <category>playdata 회고/주간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/34</guid>
      <comments>https://jamni.tistory.com/34#entry34comment</comments>
      <pubDate>Tue, 20 Aug 2024 00:14:11 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 24주 차 회고</title>
      <link>https://jamni.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;플레이데이터 백엔드 개발 부트캠프 24주 차 회고(8월 1주 차)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 주 GraphQL을 마무리하고, 말썽이던 배치 서버를 수정하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 구현한 배치 서버에 대해서 간단하게 설명하자면, 은행 어플 상 거래 상당히 많은 양의 거래 내역이 존재하기 때문에 해당 거래 내역의 양이 많아질 경우 데이터를 조회할 때, 성능이 안 좋아질 것이라 판단했다. 자정에 가까운 시간에 은행이 점검을 들어가는 것처럼 자정에 배치 서버를 돌려서 RDB에 저장되어 있던 거래 내역을 MongoDB로 데이터를 옮기고, RDB에 있는 데이터를 날려주는 역할을 하는 것이 내가 구현하는 배치 서버다. 이후 조회할 때, RDB와 MongoDB에 있는 데이터를 Paging을 통해서 가지고 오게 된다면 성능이 좋아질 것으로 기대하며 구현을 했다. 이전에 구현해서 배포했던 것이 무슨 문제였는지 동작이 되지 않아서 코드를 새로 짰다 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하루 종일 걸렸다... 원래 하나의 Job에 Step이 두 개였던 것을 하나의 Step으로 만들어서 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 환경에서는 잘 작동이 되길래. 배포를 하고 다음 날 결과를 확인할 계획으로 마무리 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인해본 결과 제대로 작동이 되지 않았던 것을 알 수 있었다 ... 이유를 모르겠다. 분명 로컬에서 작동된 것을 보니 코드의 문제는 아닌 듯했고, Helm Charts의 문제라고 판단해서 Helm Charts를 거듭 수정했는데 계속해서 배치 서버와 MongoDB가 연결이 안되는 문제가 있었다. 계속 잡고 있기엔 다른 일들을 진행을 하지 못할 것 같아서. 거래 내역 서버의 다른 기능을 마무리 하고 수정하고자 미뤄뒀다. 이후 거래 내역 서버에서 MongoDB에서 데이터를 읽어오는 것과 Paging을 사용해서 데이터를 조회하는 것까지 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB에서 불러온 데이터를 프론트에 띄워주는 작업과 배치 서버 수정이 남았었는데, 프론트에 MongoDB 데이터를 띄우기 위해서는 배치 서버가 먼저 동작했어야했다. 그래서 어쩔 수 없이 배치 서버를 먼저 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 날은 코딩 인생 최악이었다 ... 9 to 21:40 까지 정말 아무런 진전이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유를 모르게 배치 서버와 MongoDB가 연결이 안돼서 Step이 작동하지 않았다 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아쉬움을 뒤로 한 채 마무리 했다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 서버 오류를 다시 보기 위해 계속 생각해봤다. 오류로 뜨는 문제는 MongoDB 인증이 되지 않는다는 문제?&lt;/p&gt;
&lt;pre id=&quot;code_1723475732446&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;org.springframework.data.mongodb.UncategorizedMongoDbException:
Command failed with error 13 (Unauthorized):
'Command update requires authentication' on server click-account-history-mongodb:27017.
The full response is {&quot;ok&quot;: 0.0, &quot;errmsg&quot;: &quot;Command update requires authentication&quot;, &quot;code&quot;: 13, &quot;codeName&quot;: &quot;Unauthorized&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 에러가 계속해서 떴다... 무슨 문제인가 계속 수정 끝에 마지막에 수정을 했을 때 작동된 것은&lt;/p&gt;
&lt;pre id=&quot;code_1723475917649&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;env:  
  - name: &quot;SPRING_DATA_MONGODB_URI&quot;
    value: &quot;mongodb://username:password@database-deploy:27017/database?authSource=admin&quot;
  - name: &quot;SPRING_BATCH_JDBC_INITIALIZE-SCHEMA&quot;
    value: &quot;embedded&quot;
  - name: &quot;SPRING_DATA_MONGODB_USERNAME&quot;
    value: &quot;username&quot;
  - name: &quot;SPRING_DATA_MONGODB_PASSWORD&quot;
    value: &quot;password&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경변수 URI 앞부분에 username:password를 추가해주니까 작동됐다... 저 과정도 분명 수정 중에 한번 있었는데 그땐 작동이 안되고 갑자기 왜 됐는지 의문이다 ... 이해 할 수 없다 ....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이유는 잘 모르겠는데 어쨌든 수정하고 이후 프론트를 수정하다가 데이터를 불러올 때, MongoDB와 RDB의 필드명이 맞지 않아서 맞춰주는 작업을 진행하고 하루가 마무리 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일은 휴가였지만 오전에 잠시 작업을 했다. MongoDB의 데이터를 불러오다 보니 Update 작업도 진행되어야할 것 같아서 Update 작업을 진행했다. 여기서도 문제가 터진 것이... MongoDB에서는 업데이트 할 필드를 set 하고 save를 진행해준다고 봤는데 왜 !! 왜 !! id가 중복된다고 계속 업데이트가 되지 않고 insert를 시도했다 ... 이 작업만 하다 오전 시간이 다 지나서 주말로 미뤘다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;느낀 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 시간 대비 성과가 가장 없었던 한 주였던 것 같다. Batch 서버 때문에 마음 고생한 것이 가장 큰 문제 ... 하지만 계속해서 붙잡고 있던 에러가 해결되던 그 순간의 기분은 말로 설명 못한다 ㅎ... 이런 맛에 코딩하는 것 같다. 이제 프로젝트 막바지에 들어섰다. 좀 더 바쁘고 성실하게 움직여서 얼른 통합과 문서 작업까지 마무리 해야겠다.&lt;/p&gt;</description>
      <category>playdata 회고/주간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/33</guid>
      <comments>https://jamni.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 13 Aug 2024 00:25:31 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 5개월 차 회고</title>
      <link>https://jamni.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;벌써 8월 .. 이제 남은 기간 약 3주 ... 사실 3주도 안 남았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 한 달은 프로젝트만 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 프로젝트의 주제는 금융. 쉽고 간단한 서비스의 금융 서비스와 그 외로 경험을 쌓고자 여러가지 기술을 사용해볼 겸 선택한 주제였고, 그 결과 프론트는 React-native를 사용하게 되었다. 그것도 TypeScript를 곁들인 ..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 프로젝트에서는 지난 프로젝트에 아쉬웠던 점을 보완하고자 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 프로젝트의 가장 큰 아쉬움은 소통이 잘 되지 않았다고 생각했다. MSA로 진행하다보니 각각 개발하는 서버가 달랐고, 소통이 부족하니, 각 팀원의 진행 상황과 팀원이 어떤 기술을 써서 어떻게 기능을 구현하는지를 알기 어려웠다. 그래서 이번에는 처음부터 매일매일 스크럼을 진행해서 각각의 진행상황과 어떻게 진행할 것인지에 대해 소통하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 5주차가 지난 현 시점 굉장히 성공적이다. 매일 소통을 진행하다보니 각자 어떤 파트를 맡고 진행하는지 알기 쉬웠고, 어떤 기술을 사용하는지도 알 수 있었다. 강사님께서도 이런 부분에 있어서는 우리 조가 가장 잘 되고 있다고 얘기해주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 주는 프로젝트를 설계하는데만 시간을 쏟았다. 바보같이 MSA로 개발 예정이었는데 폭포수 모델로 회의를 하는데 시간을 사용해버려서 설계가 좀 더 오래 걸렸다. 하지만 이는 후에 가서 추가할 것에 대해 미리 했다고 생각하고 가장 기본적인 테이블과 기술 스택, 기능 정리, WBS 정도만 진행했다. 처음 ERD는 굉장히 초라했다. 처음 기능정리를 보신 멘토님께서 기능이 너무 많다고 순위를 정해서 조금 빼라고 얘기해주셔서 테이블이 더 적어졌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째 주는 본격적으로 코드를 치기 시작했다. 가장 기본적으로 CRUD를 작성했다. CRUD와 함께 이번 목표였던 Test Code를 밀리지 않고 꾸준히 작성했다. 처음에는 어색해서 GPT와 팀원의 도움을 받았는데 수진이의 설명으로 제대로 이해해버려서 혼자서도 작성할 수 있게 되었다. 나는 거래 내역 파트를 맡았는데 내 쪽은 기능이 단순해서 금방 끝났다. 그래서 나는 추가로 카테고리 별 분석과 예산을 진행하기로 했다. 두개 다 진행하기에는 시간이 부족해서 둘째 주에는 카테고리 별 분산 CRUD만 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째 주에는 Spring Batch를 도입했다. 이유는 대용량 데이터를 다루기 위해서였다. 현재 모든 유저의 모든 거래 내역이 하나에 테이블에 저장이 되는 구조였다. 하지만 특성상 데이터가 굉장히 많아질 수 밖에 없기 때문에 데이터가 쌓이면 쌓일수록 속도가 느려질 것이라 생각해서 배치를 통해서 거래 내역 테이블을 비우기로 했다. 테이블을 비우면 해당 데이터는 더이상 볼 수 없는가? 이는 배치가 돌아갈 때 MongoDB로 따로 저장하기로 했다. 처음 화면에서는 RDB에서만 조회를 하고, 이 후 추가 데이터를 유저가 원할 때는 MongoDB에서 조회할 수 있게끔 구상했다. 하지만 배치에 있어서 공부와 코딩에 너무 많은 시간을 뺏겨 정작 중요한 기능을 못하는 것 같아서 틀만 잡아놓고 다음에 고도화를 진행할 때 하기로 하고 남겨놨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;넷째 주에는 카테고리 별 분산과 예산 설정을 본격적으로 코딩하기 시작했다. 카테고리 별 분석을 그래프로 보여주고자 react-native-chart-kit 라는 라이브러리를 사용해줬다. &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;1072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qycYr/btsITBcThum/OraRsfXF8xK7vqJLmhd6S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qycYr/btsITBcThum/OraRsfXF8xK7vqJLmhd6S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qycYr/btsITBcThum/OraRsfXF8xK7vqJLmhd6S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqycYr%2FbtsITBcThum%2FOraRsfXF8xK7vqJLmhd6S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;350&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;1072&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진은 실제로 구현한 이미지다. 이정도면 잘 나왔다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 하나 트러블 슈팅이 있었는데, 처음에는 거래 내역 테이블에서 쿼리를 통해 계산을 했었다. 하지만 내가 생각하지 못했던 것은 금융 파트에서 특히 거래 내역 같은 경우 굉장히 많은 데이터가 저장된다는 것. 대용량 데이터에서 쿼리를 통해 SUM을 해서 값을 가지고 온다는 것은 굉장히 시간이 오래 걸릴 것 같았다. 그래서 거래 내역에 기록이 될 때마다 다른 테이블에 카테고리 별로 값을 더해서 업데이트 해줬다. 이후 조회를 할 때는 거래 내역 테이블이 아닌 카테고리 별 지출 테이블에서 데이터를 조회해서 온다면 시간이 훨씬 줄어들 것이라 생각하고 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예산을 설정할 때도 예산을 저장할 테이블이 필요할 것 같아서 이 기능들을 구현하는데만 테이블 두개가 추가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다섯째 주에는 원래 Pay 서비스를 진행하려 했는데, 카드 서비스 쪽에서 GraphQL을 도입하기로 했다. GraphQL도 처음 다뤄보는 내용이라 공부하고 적용하는데 시간이 조금 걸렸다. 하지만 전에 Batch보다는 빠르게 적응해서 프론트와 서버 통신까지도 마무리 한 상태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 한 달간 한 내용이었다. 막상 적어놓고 보니 시간이 많았는데 결과물이 아쉬운 듯 하다. 분명 열심히 했는데... 더 열심히 할 수 있었나보다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 달에는 배치 서버를 완벽하게 마무리하고 MongoDB에서 데이터를 조회하는 것 까지 첫째 주에 마무리 하는 것이 목표다. 그 다음 주에는 다른 팀원의 서비스를 모두 연동시켜보고 시간이 남으면 GraphQL을 현재 Read 하는데만 사용했는데 Create, Update, Delete 하는데까지 사용하거나 거래 내역 파트에서 사용해볼까 한다. 물론 시간이 남는다면 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 주에는 문서작업을 하고 발표를 해야한다. 이렇게 말하니까 진짜 얼마 안남았다 !!! ..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;남은 한 달도 열심히 하고 공부해야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 프로젝트라 해서 단순 코딩만 하고 배운 것만 써먹을 줄 알았는데, Spring batch, MongoDB, GraphQL 등 많은 것을 알게 됐고, 따로 Next.js까지 공부 중이라 생각보다 더 성장 할 수 있는 시간이었던 것 같다. 추가로 다른 팀원이 쓴 기술에 대해서도 알 수 있으니 좋은 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 한번 남은 월간 회고까지 프로젝트가 끝나면 작성해보겠다!&lt;/p&gt;</description>
      <category>playdata 회고/월간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/32</guid>
      <comments>https://jamni.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 5 Aug 2024 20:54:12 +0900</pubDate>
    </item>
    <item>
      <title>플레이데이터 백엔드 개발 5기 23주 차 회고</title>
      <link>https://jamni.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;플레이데이터 백엔드 개발 부트캠프 23주 차 회고(7월 5주 차)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 주 카테고리 수정에 대한 테스트 코드를 작성하지 않아서 테스트 코드부터 작성해주었다. 멘토님께서 테스트 코드를 그때 그때 작성해주지 않으면 나중에 테스트 코드 짜야할 것들이 쌓여서 힘드니, 바로바로 작성하는 습관을 들이라고 추천해주셨다.&amp;nbsp; 그리고 지난 주 회의를 통해 적어놨던 Pay 서비스의 기능을 쭉 적어보고 해당 기능의 CRUD를 작성했다. 크게 가맹점 측과 결제 내역 측 두 가지가 있는데 나는 가맹점 측 CRUD를 맡아서 작성해주었다. 이제 CRUD는 진짜 금방 끝내는 것 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강사님께서 나는 Pay쪽 서비스를 하지말고, GraphQL을 사용해보라고 하셔서 급하게 GraphQL을 공부했다. 이 날은 코딩보다도 GraphQL을 사용하는 방법에 대해 더 공부를 한 것 같다. GraphQL에 대한 내용은 밑에다 정리해볼게요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 날부터는 본격적으로 GraphQL을 적용시키는 날이었다. 일단 GraphQL은 Query(Read)와 Mutation(Create, Update, Delete)로 나눠져 있었는데 나는 일단 Read에 대한 부분부터 적용시켜보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 팀원이 짜둔 카드 CRUD에서 Read 부분만 바꿔주기 위해서는 설정해야할 것들이 있었다. 가장 큰 건 스키마. 스키마를 만들어 두고 Read 부분을 바꾸어주었다. 스키마도 밑에서 다뤄볼게요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어제 적용시킨 Read 부분. 즉 Get 요청을 통해서 프론트와 통신하는 과정까지 진행했다. 적용시킨 부분은 내 카드 목록, 내 카드 정보, 카드 상품 목록, 카드 상품 정보까지 총 4부분이었는데 한번 적응을 하니까 GraphQL을 사용하는 것도 편하고 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휴가였습니다. ㅎ_ㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;GraphQL&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GraphQL. 일단 QL 어디서 들어보지 않았나? 싶었다. SQL에서 들어본 거였다. 역시나 제일 먼저 SQL과의 차이가 나오더라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SQL과의 차이&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SQL은 &lt;u&gt;데이터베이스 시스템에 저장된 데이터를 효율적으로 가져오는 것&lt;/u&gt;이 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GraphQL(이하 GQL)은 &lt;u&gt;웹 클라이언트가 데이터를 서버로부터 효율적으로 가져오는 것&lt;/u&gt;이 목적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 목적에서의 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면&lt;b&gt; Rest API와의 차이&lt;/b&gt;는 무엇일까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rest API는 URL, Method 등을 조합하기 때문에 각각 Endpoint가 있지만 GQL은 하나의 Endpoint만 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GQL API에서는 불러오는 데이터의 종류를 쿼리 조합을 통해서 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 쿼리와 뮤테이트가 있다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리는 위에서 말했듯 Read 하는데 사용되고, 뮤테이트는 데이터를 변조하는 Create, Update, Delete에 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GQL에는 리졸버(Resolver)라는 것이 있다. 이는 데이터를 가져오는 구체적인 과정을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 Endpoint&lt;/li&gt;
&lt;li&gt;필요한 데이터만 요청&lt;/li&gt;
&lt;li&gt;DTO의 사용이 줄어든다.&lt;/li&gt;
&lt;li&gt;응답 Size를 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;응답 객체의 Depth가 깊은 경우에도 원하는 데이터만 요청할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스키마에서 필드를 정확하게 모두 명시해줘야한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;DTO는 상속을 통해 필드 생략이 가능&lt;/li&gt;
&lt;li&gt;Map이나 Object 사용 불가&lt;/li&gt;
&lt;li&gt;필드 하나만 있어도 모든 응답을 객체로 만들어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파일 업로드
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;application/json 형식만 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Client에서도 모든 필드를 작성&lt;/li&gt;
&lt;li&gt;필드 타입(스칼라 타입)이 한정적
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;그 외 필요한 건 커스텀 해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;백엔드 입장에서 설정해야 할 것이 많다.&lt;/li&gt;
&lt;li&gt;데이터 쿼리의 상당 작업을 서버 측으로 옮겨 서버 개발자 작업의 복잡성이 커진다.&lt;/li&gt;
&lt;li&gt;캐싱이 Rest 보다 훨씬 복잡하다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점이 많아 보이지만 일부 단점을 제외하면 크게 불편함을 느끼진 못했던 것 같다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개선해야할 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상하게 프로젝트 마감이 다와갈수록 캠퍼스에 남아있을 때 집중이 되지 않는다.. 뭘 해야할지 찾지 못할 때도 있는 것 같다. 아무래도 목표를 설정하는데 있어서 좀 더 구체화를 시켜야할 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 좀 더 구체적인 목표를 설정해보자 !&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;느낀 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트만 하는 것이 아니라 계속 다른 공부를 하면서 프로젝트도 진행하니 조금씩 아는 것도 계속 늘어나는 기분이고 그만큼 실력도 늘어나는 것 같다. 다만 조금 피곤할 뿐... 이제 3주 정도 남았다. 남은 3주 파이팅하고 취뽀도 빠른 시일 내에 하고싶다... !&lt;/p&gt;</description>
      <category>playdata 회고/주간 회고</category>
      <author>김잼니</author>
      <guid isPermaLink="true">https://jamni.tistory.com/31</guid>
      <comments>https://jamni.tistory.com/31#entry31comment</comments>
      <pubDate>Sun, 4 Aug 2024 22:47:17 +0900</pubDate>
    </item>
  </channel>
</rss>