인프콘 2024를 다녀왔습니다.

개발자를 준비하면서 꼭 한번쯤은 이런 활동을 해보고 싶었는데요, 마침내 달성했습니다.

저는 “동료”라는 말을 자주 쓰는데요, 일을 하는 조직이 아니더라도 특정한 생각과 경험을 공유하는 집단에 속한다면 전부 동료가 아닌가 생각합니다.

저는 아직 현업의 개발자는 아니고 어떻게 보면 학생이자 취업을 준비하는 취준생 신분이지만, 인프콘에 참여해 활동하는 순간에는 백엔드 포지션의 한 사람으로서 제가 우러러보는 그들과 동일한 경험을 하게 된다고 생각합니다.

그런 점에서 인프콘은 그들의 “동료”로서 함께할 수 있는 시간이었습니다.

또 처음이다 보니 설레는 마음도 있었고, 나만 없는 개발자스러운 티셔츠와 개발 관련 스티커들이 탐나기도 했습니다.

할 수 있는 활동은 다 해보고 싶어 기업 부스도 돌고 네트워킹 파티도 참가하고 여러 세션도 들었는데요, 인프콘이 끝난 후 느낀 점은 “다음번에는 소비자가 아닌 생산자로서 인프콘에 와보고 싶다”였습니다.

정말 단순한 활동이라 할지라도 그들의 경험을 만드는 데 있어 내가 일조할 수 있다면 그것 자체가 큰 의미라 생각하거든요.

곧 백엔드 스터디 팀장 자격으로 구름톤 유니브의 임원들과 만나는 시간을 갖는데요, 제 개인적인 바람으로는 우리만의 작은 컨퍼런스를 열어 각자 발표하고 유튜브를 통한 기록을 남기는 것을 구상 중인데, 정확히 어떻게 될지는 모르겠습니다.

오늘은 참 인상 깊은 하루였습니다.

제 맥북에는 스티커가 덕지덕지 붙여졌고 앞으로의 만남에는 기업의 로고가 박힌 티셔츠를 입고 갈 거거든요.

앞으로 이런 기회가 더욱 많아지면 좋겠습니다. 감사합니다.

구름톤 유니브에 합격했습니다.

https://9oormthon.university/

아마 “구름톤”은 많이 들어보셨을 텐데요, 한국에서 가장 유명한 해커톤이 아닌가 생각합니다.
이름에서 알 수 있듯이 구름톤 유니브는 대학생을 대상으로 해커톤을 개최하는 것을 목표로 합니다.

카카오와 구름에서 후원하는 연합 동아리이며, 기업에서 이름을 걸고 후원하는 만큼 보통의 동아리보다는 낫다고 생각됩니다. 

대학교를 기준으로 각각의 “미르미”를 모집하고 활동하는 구조라,
지원하지 않는 대학교는 참여할 방법이 없다는 조금 아쉬운 점도 존재합니다.

저 같은 경우에는 BE 포지션으로 지원했으며 1차 서류, 2차 면접 후에 최종 합격했습니다.

서류에서는 다음의 문항을 작성했으며 아마 공통된 양식으로 다른 대학교들도 비슷하지 않을까 생각합니다.

1. 본인을 소개해주세요. (700자 이내)

2. 구름톤 유니브를 통해 얻어가고 싶은 점을 알려주세요. (500자 이내)

3. 지원 파트로 가장 애정있게 참여했던 프로젝트와 본인의 역할을 설명해주세요. (700자 이내)

이후에 포트폴리오랑 깃허브 링크 정도를 추가했습니다. (포르폴리오는 깃허브 README에 전부 개시되어있습니다.)

면접은 30분가량이었는데, 기술적인 질문보다는 판단과 이유에 대해서 질문을 받았습니다.

구름톤 유니브는 기업에서 후원한다고 해도 결국 연합 “동아리”이기 때문에 같은 대학교의 학생이 선별하는 방식이라 특별한 준비나 긴장을 하진 않았는데, 생각보다 질문이 날카로워서 놀랐던 기억이 납니다.

가장 기억에 남는 질문은 “오버엔지니어링과 MSA 아키텍처의 도입 의의” 정도였습니다. 그래도 나름 잘 답변해서 합격하게 되었고, 백엔드 스터디 팀장으로 3기 활동을 할 것 같습니다.

얼마 전에는 판교로 통합 OT를 다녀왔는데요, 제공되는 혜택이나 인프라가 매우 훌륭하기 때문에 공고를 유심히 보시다가 한 번쯤 지원해보시길 바랍니다.

아래는 OT 당일 찍은 사진입니다.

5개월만에 글을 써봅니다.

NHN 프로젝트 과정 마무리를 기준으로 하면 3개월 정도 됐는데요

분명 꾸준히 글을 쓰고 관리하려고 생각했는데 이게 참 쉽지가 않은 것 같습니다.
그럼 그동안 무엇을 했냐??...

놀았습니다.

좀 더 자세히 말하면.. 여행가고 게임하고 운동 했습니다.

항상 운동에 대한 열정이 있었는데 3개월 동안 정말 미친사람처럼 여한없이 한 것 같아요
또 글을 올리지 않는데도 불구하고 생각보다 많은 분들이 제 블로그를 방문해 주시더라구요

대충 계산해도 월간 200명 이상은 방문해주시는데 참 고마움을 느낍니다.
사실 글을 써도 아무도 봐주질 않으면 의미가 없다고 생각하거든요
글을 쓰는 이유 자체가 제 나름의 지식공유기 때문에 더 그런것 같습니다.

통계를 보면 NHN Academy 회고 글의 누적 조회수가 거진 2천회 정도 됩니다.
그만큼 아카데미를 지원하시려는 분들에게 도움이 됐다는 거겠죠??

또 최근에는 정보처리기사 자격증 시험을 봤습니다.
필기 합격을 해놓은 상태인데 전공자 기준으로는 짧게는 3일 길면 1주일 정도면 충분히 가능한 시험같아요

그 외에도 올해 SQLD , AWS Associate 자격증 정도를 취득하려 합니다.
취업에 필요하다고는 생각하지 않지만 정처기,SQLD 같은 경우에는 이미 갖고 있는 지식으로 충분히 취득이 가능해 보이고

AWS Associate 같은 경우는 다음에 진행할 개인 프로젝트에 AWS를 도입할 생각이기 떄문에
어차피 공부할겸 동기부여의 의미로 취득하려 해요

그리고 제가 정말 가고싶었던 INFCON 추첨에 당첨됐습니다.

시간표는 다음과 같이 작성했는데 이런 컨퍼런스는 처음이라 굉장히 설레네요

마지막으로 저는 9월에 복학하여 남은 학기를 마치고 졸업 할 것 같습니다.
내년에는 27살이 되는데 이게 마냥 적은 나이도 아니고.. 그렇다고 진짜 어른도 아니고..
참 애매한 구간인거 같네요, 저와 비슷한 나이대의 분들은 다 그렇게 느끼겠죠?

정말 두서없이 주절주절 글을 썼는데요 3개월간 정말 행복하게 푹 쉬었고 이제는 다시 달릴 떄가 오지 않았나 싶습니다.
다시 글도 열심히 써보고 , 기존의 글들도 수정하거나 보완할 생각이니 회고글 이외에도 많이 봐주시면 좋겠습니다.

감사합니다.

https://masiljangajji-coding.tistory.com/50

 

NHN Academy 4기 회고

NHN Academy(조선대) 4기 회고 여러 부트 캠프 중에 NHN Academy 관련해서는 정보가 많지 않아서 회고를 위장한 정보글을 써봅니다. 아카데미에 지원에 정보를 찾는 분들을 위해 글을 작성하는 것이며

masiljangajji-coding.tistory.com

작년 12월 31일 NHN Academy 관련해 회고 글을 썼었습니다.

제가 생각했던 거 보다 조회 수도 너무 잘 나오고 댓글도 많이 달려서
내 글이 많은 사람들에게 도움이 됐겠구나..라는 생각이 들어 기분이 참 좋네요

저번 회고 글은 회고를 가장한 정보글이었는데 이번에는 회고를 가장한 일기를 쓰려 합니다.

제목에서도 알 수 있지만 아카데미의 마지막 심화과정인 프로젝트 과정에 합격했습니다.
본 과정에서 팀을 이루어 함께 공부한 모든 분들이 프로젝트 과정에 같이 합격해 더욱 기쁜 마음입니다.

프로젝트의 팀원이 어떻게 매칭될지는 모르겠지만 저와 함께 공부했고 친하게 지내는 분들과 함께
과정을 수강한다는 것 자체가 저에게는 힘이 되는 것 같습니다.

예비과정부터 본 과정.. 스프링 과정.. 또 프로젝트까지
광주에서 생활하고 조선대학교를 집처럼 다닌 지 벌써 6개월이 지났네요

처음 광주로 내려와 공부를 할 때는 아무런 연고도 없이 내려와 참 외로웠던 기억이 납니다.
또 계절도 한 여름이라 몇 발작 걷는 것도 힘든데 조선대학교는 왜 이리 큰 건지..

그때 당시만 해도 본 과정 합격에 대한 확신이 없었기 때문에 방 계약을 할 수 없어
캐리어에 가방 하나 들고 모텔방에서 3주 정도를 지냈는데 그때가 가장 힘들었던 것 같습니다.

또한 과정을 진행하면서 정말 밀도 있게 개발에 대해서만 생각하고 하루건너 하루 밤새는 게 익숙해질 때쯤
개발자라는 직업에 대해서 고민하기 시작했고 당연하게만 생각했던 것에 대해 질문하게 됐습니다.

아.. 이거 개발자로 먹고사는 게 쉽지 않은 거 같은데.. 나는 진짜 개발자를 하고 싶나?
나는 개발자가 어울리는 사람인가? 나는 개발자로 평생을 먹고 살 수 있나?

그렇게 개발자에 대해 고민하고 제 나름의 답을 찾았을 때쯤부터는 단순히 취업만을 목적으로
바라보지 말고 내가 어떻게 하면 조금 더 얻어 갈 수 있고 조금 더 배울 수 있는지를 목표로 삼고
아카데미가 지원하는 과정들은 그것을 위한 수단으로 생각하게 됐습니다.

이렇게 생각하니 프로젝트 과정에 가야만 한다는 스트레스도 줄어들고 코드를 짜면서도
단순한 기능 구현에 끝나는 것이 아니라 더 좋은 방법은 없는지 고민하게 됐습니다.
아마도 이런 모습을 좋게 봐주셔서 프로젝트 과정도 합격할 수 있지 않았나 생각합니다.

어디에 취업을 하고 어떤 자격증을 따고 연봉을 얼마 받고.. 이런 것들이 목적 그 자체가 될 수도 있겠지만
저는 하나의 수단으로써 생각하기로 했습니다.

신년이 된 지 벌써 한 달이 지나 설을 앞두고 있습니다. 시간이 참 빠르게 지나간다는 생각을 자주 하게 되네요

이 글을 보시는 모든 분들이 기쁜일이 있으면 좋겠습니다.
감사합니다.

 

 

신입 개발자 취업 여정기 (feat: 가비아 인턴 합격)

들어가는 글안녕하세요 최근 정말 좋은 일이 있었는데요 백엔드 포지션으로 가비아에 합류하게 됐습니다.이번글은 합류의 과정과 제 개인적인 생각을 작성하려 합니다.서비스 회사에 가고싶다

masiljangajji-coding.tistory.com

 

 

2025년 상반기 회고 (feat: 카카오게임즈 최종탈락)

들어가는 글안녕하세요 오랜만에 글을 작성합니다.블로그를 꾸준히 이어가겠다고 다짐했는데,미디엄 기준 마지막 글 작성일이 5월, 티스토리 기준 2월인 것을 보면 반성하게도 되고돌아보면 글

masiljangajji-coding.tistory.com

 

Dependency Injection(의존관계 주입)이란?

 

이 글은 IoC , Dependency 의 개념을 알고있다는 전제하에 작성된 글입니다.

원활한 이해를 위해서 아래글을 읽어주세요

https://masiljangajji-coding.tistory.com/51

 

IoC(Inversion Of Control)란

IoC/DI(Inversion Of Control/Dependency Injection)란 IoC(Inversion Of Control)란? IoC는 제어의 역전을 뜻합니다. 제어의 역전.. 제어가 역전된다.. 이게 어떤 의미일까요? 기존의 프로그램은 구현 객체가 프로그램

masiljangajji-coding.tistory.com

https://masiljangajji-coding.tistory.com/52

 

Dependency(의존관계)란?

Dependency(의존관계)란? 의존관계는 코드에서 두 모듈간의 연결을 의존관계라 합니다. 객체지향언어에서 두 클래스 간의 관계를 말하기도 합니다. 의존관계의 종류는 크게 4가지가 존재합니다. Dep

masiljangajji-coding.tistory.com

 

Spring Bean과 Context

Spring Bean

Spring Bean은 Spring Container에 등록된 객체를 의미합니다.

Java Beans 와는 다른것으로 Spring FrameWork에서 중요하게 관리하는 객체로 이해하면 됩니다.

 

Java Beans 의 조건

  1. public default (no argument) constructor
  2. getter/setter
  3. implement java.io.Serializable

Container에 Bean이 등록되기 위한 조건

  1. name(식별할 이름)
  2. class(타입)
  3. object(객체)

Java Beans와 다른 별개의 개념입니다.

 

Container/Context

Container는 Interface로 일종의 개념에 해당합니다.

프로그램의 구성 요소들을 담고 관리하는 환경을 나타내며 DI Container , 서블릿 컨테이너 , 웹 컨테이너 등등이 존재합니다.

 

Context는 Container라는 Interface의 구현체입니다.

(Container = DI Container = IoC Container)

 

스프링 프레임워크에서는 빈(Bean) 설정과 관련된 정보를 나타내는 Metadata에 따라

어떤 클래스의 ApplicationContext를 이용할지 정해집니다.

 

다음의 Git Repo를 참고하시길 바랍니다.

https://github.com/masiljangajji/DI_Exapmle

 

GitHub - masiljangajji/DI_Exapmle

Contribute to masiljangajji/DI_Exapmle development by creating an account on GitHub.

github.com

 

XML 을 이용한 DI

xml 파일을 이용해 의존관계를 주입하는 방식입니다.

Context에 등록을 돕는 메타데이터 형식이 xml형식이며 ClassPathXmlApplicationContext 클래스를 사용합니다.

<bean id="english" class="com.springframework.core.practice.language.domain.English"/>

id는 Bean에 등록될 이름을 , class는 클래스의 경로를 나타냅니다

 

이 코드는 다음과 같습니다.

  1. english라는 이름으로
  2. com.springframework.core.practice.language.domain.English 경로에있는
  3. 클래스파일을 reflection으로 읽어 객체를 생성하고 컨테이너에 등록해
public class XmlMain {


    public static void main(String[] args) {

        // 컨텍스트 등록을 돕는 메타데이터로 xml 선택시 ClassPathXmlApplicationContext 사용
        try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                // resources/beans.xml 파일을 읽어서 컨테이너에 객체 등록하겠다.
                "beans.xml")) {

            English english = context.getBean("english", English.class);
            Korean korean = context.getBean("korean", Korean.class);
            english.hello();
            korean.hello();
        }

    }

}

korean은 컨테이너에 등록이 안됐기 때문에 다음과 같은 에러가 발생 No bean named 'korean' available

(English와 같은 방식으로 xml에 추가하면 에러가 해결됩니다.)

 

생성자 주입

public class LanguageSpeakService {

    private final Language language;

    public LanguageSpeakService(Language language) {
        this.language = language;
    }

    public void speak() {
        System.out.println("Speak Service");
        language.hello();
    }

}

 

LanguageSpeakService 클래스는 Language에 대한 의존관계를 갖습니다.

 

Field로 갖고있는 타입이 Interface기 때문에 실질적인 동작은 Language의 SubType인

English,Korean 중 하나를 받아 동작할 것입니다.

 

따라서 기존과 같은 방법으로 DI시켜주게 된다면

LanguageSpeakService languageSpeakService =
                    context.getBean("languageSpeakService", LanguageSpeakService.class);

    <bean id="languageSpeakService" class="com.springframework.core.practice.language.service.LanguageSpeakService"/>

스프링은 Service가 필요한 Language가 English , Korean 중 무엇인지 알 수 없음으로 에러가 발생하게 됩니다.

 

이런 경우 Constructor Injection(생성자 주입) 방식을 사용합니다.

 

<bean id="languageSpeakService" class="com.springframework.core.practice.language.service.LanguageSpeakService">
        <constructor-arg ref="korean"/>
</bean>

 

이 코드는 다음과 같습니다.

  1. languageSpeakService라는 이름으로
  2. com.springframework.core.practice.language.service.LanguageSpeakService 경로에있는
  3. 클래스파일을 reflection으로 읽어 객체를 생성할때 korean 이름으로 등록된 Bean을 참고해
  4. 만들어진 languageSpeakService 객체를 컨테이너에 등록해
 public static void main(String[] args) {

        // 컨텍스트 등록을 돕는 메타데이터로 xml 선택시 ClassPathXmlApplicationContext 사용
        try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                // resources/beans.xml 파일을 읽어서 컨테이너에 객체 등록하겠다.
                "beans.xml")) {

            English english = context.getBean("english", English.class);
            Korean korean = context.getBean("korean", Korean.class);
            english.hello();
            korean.hello();


            LanguageSpeakService languageSpeakService =
                    context.getBean("languageSpeakService", LanguageSpeakService.class);

            languageSpeakService.speak();

        }

생성자 주입 사용시 코드가 문제없이 동작하게 됩니다.

 

setter 주입

public class LanguageSpeakService {

    private  Language language;

    // setter 주입을 위한 기본 생성자
    public LanguageSpeakService(){

    }
    public LanguageSpeakService(Language language) {
        this.language = language;
    }

    public void setLanguage(Language language) {
        this.language = language;
    }

    public void speak() {
        language.hello();
    }

}

<bean id="languageSpeakService" class="com.springframework.core.practice.language.service.LanguageSpeakService">
        <property name="language" ref="english"/>
</bean>

이 방식은 language 에 대한 표준 명명규칙을 따르는 set메서드를 찾아갑니다.

 

실질적으론 setLanguage 메서드를 찾아 동작하는 것이죠 따라서 name을 바꾼다면 정상동작 하지 않습니다.

<bean id="languageSpeakService" class="com.springframework.core.practice.language.service.LanguageSpeakService">
        <property name="language2" ref="english"/>
</bean>

 

표준 명명규칙을 따르지 않기 떄문에 오류가 발생 (property name 을 language로 변경하면 정상동작 합니다.)

 

 public void setLanguage2(Language language) {
        this.language = language;
    }

<bean id="languageSpeakService" class="com.springframework.core.practice.language.service.LanguageSpeakService">
        <property name="language2" ref="english"/>
</bean>

이렇게 set메서드 이름을 맞춰줄시 정상동작 합니다.
(name = setLanguage2 를 부르겠다 , 넣어줄 인자는 english 이름을 가진 빈)

 

이렇듯 setter주입은 명명규칙을 지켜줘야 하며 기본 생성자가 필요합니다.

 

Autowired Injection

autowired injection 은 다음의 방식을 사용할 수 있습니다.

  1. byType
  2. byName
<bean id="koreanChef" class="com.springframework.core.practice.domain.chef.KoreanChef"/>
<bean id="chefCookService" class="com.springframework.core.practice.service.ChefCookService" autowire="byType"/>

public class ChefCookService {
    private Chef chef;

    public ChefCookService() {
    }

    public void setChef(Chef chef) {
        this.chef = chef;
    }

    public void makeFood() {
        chef.cook();
    }

}

autowired byType설정을 사용하려면 일치하는 빈이 하나여야 합니다.

 

지금은 일치하는 빈이 KoreanChef 하나기 때문에 정상동작 합니다.

하지만 AmericanChef가 추가된다면 일치하는 빈에 중복이 생기며 에러가 발생합니다.

 

<bean id="chefCookService" class="com.springframework.core.practice.service.ChefCookService" autowire="byName"/>

// 양식 조리 출력 
public void setAmericanChef(Chef chef) {
        this.chef = chef;
}

// 한식 조리 출력
public void setKoreanChef(Chef chef) {
        this.chef = chef;
    }

byName을 사용하게되면 set메서드의 이름을 따라갑니다.

 

XML 이용한 DI With Annotation

XML 방식으로 Bean 의존성 주입을 Annotation으로 구현할 수 있습니다.

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

(Autowired는 생성자 , 메서드 , 파라미터 , 필드 등 대부분에 사용가능)

 

<bean id="koreanChef" class="com.springframework.core.practice.domain.chef.KoreanChef"/>
<bean id="americanChef" class="com.springframework.core.practice.domain.chef.AmericanChef"/>
<bean id="chefCookService" class="com.springframework.core.practice.service.ChefCookService"/>

public class ChefCookService {

    //// Autowired 어노테이션 기반 설정
    @Autowired
    // americanChef 이름을 가진 빈을 사용하겠다
    @Qualifier("americanChef")
    private  Chef chef;

    public ChefCookService() {
    }

    public void makeFood() {
        chef.cook();
    }
}

Annotation 을 이용하지만 XML방식을 기반으로 두고있기 떄문에

등록하고자 하는 객체들은 기존과 동일하게 전부 XML 파일안에 정의되있어야 합니다.

 

이러한 방법은 설정을 아예 분리함으로써 프레임워크와의 의존성을 최소화합니다.

하지만 만약 클래스가 5천개쯤 된다면?

 

지금은 프로그램이 간단해 xml을 읽고 설정하는게 쉽지만 프로그램이 커지는 경우 XML방식은 큰 부담이 됩니다.

 

따라서 프레임워크와의 의존성이 강화되더라도 순수 자바코드로 해결하는 Java Configuration 방식이 도입됩니다.

 

Java Configuration 을 이용한 DI

 

기존에는 XML파일을 메타데이터로 사용했지만 이제는 순수자바를 사용하기 떄문에

AnnotationConfigApplicationContext를 사용합니다.

 

Java Configuration 이용한 방법은 크게 2가지가 존재합니다.

  1. 자바코드로 Bean등록
  2. Component Scan

자바코드로 Bean등록

// 이건 설정하는 파일이야
@Configuration
// JavaConfiguration 에서 XML 설정을 사용할 수 있습니다.
@ImportResource("classpath:/beans.xml")
public class JavaConfig {

    @Bean
    public AmericanChef americanChef() {
        return new AmericanChef();
    }

    @Bean
    public KoreanChef koreanChef() {
        return new KoreanChef();
    }

    // 메서드 주입방식이라 합니다.
    @Bean
    ChefCookService chefCookService() {
        return new ChefCookService(americanChef());
    }
}

여기서 Bean에 등록될 이름은 메서드의 이름과 같습니다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.springframework.core.practice");

이 코드는 다음과 같습니다.

  1. com.springframework.core.practice 경로 아래에있는 모든 파일에서
  2. @Configuration , @Component , @Controller , @Service , @Repository 에 해당하는 
  3. 어노테이션이 붙은 클래스들을 자동으로 빈에 등록해.

 

Component Scan

컴포넌트 스캔은 다음의 어노테이션을 포함하는 클래스를 읽어 자동으로 빈에 등록시킵니다.

  1. @Component : 컴포넌트 스캔에서 사용
  2. @Controller : 스프링 MVC 컨트롤러에서 사용
  3. @Service : 스프링 비즈니스 로직에서 사용
  4. @Repository : 스프링 데이터 접근 계층에서 사용
  5. @Configuration : 스프링 설정 정보에서 사용

(Configuration,Controller,Service,Repository 모두 내부적으로 @Component을 상속하고있습니다.)

@Component
public class English implements Language{
    @Override
    public void hello() {
        System.out.println("Hello");
    }
}

@Component
public class Korean implements Language {
    @Override
    public void hello() {
        System.out.println("안녕하세요");
    }
}

생성자 주입

@Component
public class LanguageSpeakService {

    private  final Language language;


    // 생성자 주입
    @Autowired
    public LanguageSpeakService(@Qualifier("english") Language language) {
        this.language = language;
    }

    public void speak() {
        language.hello();
    }

}

생성자를 이용하기 떄문에 Field를 final로 선언 가능해 불변성을 지킬수 있습니다.

가장 권고되는 주입방식입니다.

setter 주입

@Component
public class LanguageSpeakService {
    private Language language;

    // setter 주입
    @Autowired
    public void setLanguage(@Qualifier("english") Language language) {
        this.language = language;
    }

    public void speak() {
        language.hello();
    }

}

기본생성자 필요 , final 선언 불가 

필드주입

@Component
public class LanguageSpeakService {

    // 필드주입 
    @Autowired
    @Qualifier("english")
    private Language language;


    public void speak() {
        language.hello();
    }
}

코드가 가장 간결하지만 외부에서 변경이 불가능해 테스트가 어렵습니다.

또한 setter와 마찬가지로 final 선언이 불가합니다.

 

(이러한 단점들 때문에 거의 사용하지 않음이 권고됩니다.)

Bean Vs Component

자바코드를 이용한 Bean등록은 주로 System 전체에서 공통적으로 사용되야 하는 것들을 대상으로 합니다.

 

예를들어 전체에서 공통적으로 사용되는 Thread Pool , Connection Pool의 경우 

설정파일(JavaConfig.class)에 모아서 셋팅하게되면 "아 이것들은 공통적으로 전체 System에서 사용하는 구나" 이런 이해를 돕습니다.

 

반대로 Business Model들은 각각의 것들이 고유한 성질을 갖습니다.(ChefCookService , LanguageSpeakService...)

이런경우 @Service , @Controller 같은 Component Scan 방식을 이용합니다.

 

 

도움이 되셨으면 좋겠습니다.

'Spring > Spring Core' 카테고리의 다른 글

Dependency(의존관계)란?  (3) 2024.01.04
IoC(Inversion Of Control)란  (1) 2024.01.02

Dependency(의존관계)란?

의존관계는

  • 코드에서 두 모듈간의 연결을 의존관계라 합니다.
  • 객체지향언어에서 두 클래스 간의 관계를 말하기도 합니다.

 

의존관계의 종류는 크게 4가지가 존재합니다.

  1. Dependency(의존관계)
  2. Association(연관관계)
  3. Aggregation(집합관계)
  4. Composition(합성관계)

보통 4가지를 통틀어 Dependency라고 뭉뚱그려 부르긴 하지만 각각의 차이를 인지하는 것이 중요합니다. 

 

이제부터 하나씩 알아보겠습니다.

Dependency(의존관계)

public class UserService {

    public void saveUser(UserRepository userRepository){
        System.out.println("유저저장");
        userRepository.save();
    }

}


public class UserRepository {

    public void save(){
        // do something ..
    }

}

의존관계란 클래스가 다른 클래스를 일시적으로 참조하는 형태입니다.

이 코드에서는 Service가 User를 저장할 때 UserRepository를 param으로 불러와 사용합니다.

saveUser 연산을 동작시킬때만 일시적으로 참조하게 되며 생명주기와 같은 어떤것도 일치하지 않습니다.

가장 낮은 수준의 결합도를 가집니다.

 

Association(연관관계)

public class UserService {
    private UserRepository userRepository;

    public UserRepository getUserRepository() {
        return userRepository;
    }

    public void saveUser() {
        this.userRepository = new UserRepository();
        System.out.println("유저저장");
        userRepository.save();
    }

}


public class UserRepository {

    public void save(){
        // do something ..
    }

}

UserService 객체를 생성할 때는 UserRepository가 생성돼있지 않습니다.
이 부분은 의존관계와 동일하지만 saveUser() 메서드를 호출 해 동작이 끝났음에도 Repository 객체가 남아있게 됩니다.

 

public class Main {

    public static void main(String[] args) {

        UserService userService = new UserService();

        System.out.println(userService.getUserRepository());

        userService.saveUser();

        System.out.println(userService.getUserRepository());

    }

}


이것이 의존관계와의 차이점이며 의존관계보다 높은 결합도를 가집니다.

 

Aggregation(집합관계)

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserRepository getUserRepository() {
        return userRepository;
    }

    public void saveUser() {
        System.out.println("유저저장");
        userRepository.save();
    }

}

public class UserRepository {
    public void save() {
        // do something ..
    }

}

생성자를 통해 다른 클래스의 객체를 받아오는 경우입니다.

(Field를 Final로 선언할 수 있다는 장점이 있습니다.)

UserService 생성을 위해서 필수적으로 UserRepo가 필요합니다.

하지만 이것이 UserService와 UserRepository가 동일한 생명주기를 가진다는 건 아닙니다.

 

UserRepository가 먼저 생성되고 사용된 후 Service 생성도 가능하기 때문입니다.

public class Main {

    public static void main(String[] args) {

        UserRepository userRepository = new UserRepository();

        userRepository.save();
        userRepository.save();
        userRepository.save();

        UserService userService = new UserService(userRepository);
        System.out.println(userService.getUserRepository());
        userService.saveUser();
    }

}

 


기존 관계들과의 차이점은 메서드 호출없이 객체 생성만해도 Repository가 존재합니다.

 

Composition(합성관계)

public class UserService {
    private final UserRepository userRepository;

    public UserService() {
        this.userRepository = new UserRepository();
    }

    public UserRepository getUserRepository() {
        return userRepository;
    }

    public void saveUser() {
        System.out.println("유저저장");
        userRepository.save();
    }

}

public class UserRepository {
    public void save() {
        // do something ..
    }

}

UserService와 UserRepository의 생명주기가 완전히 일치하게 됩니다.
이런 형태를 강하게 결합한다 라고도 말합니다.

 

코드의 결합이 강해지게되면 재사용성이 크게 떨어지기 때문에 보통 Aggregation 관계를 사용합니다.

 

IoC/DI와 Dependency의 관계

 

IoC는 프로그램이 흐름의 제어권을 갖음을 말합니다.

Spring에 경우 Context에 Bean을 등록하고 관리하는 등 Spring Bean의 생명주기를 스스로 관리합니다.

그런데 Aggregation , Composition 과 같이 객체 생성을 위해서 다른 클래스를 필요로하는 경우는 어떡할까요??

 

public interface Language {
    // do something
}

public class Korean implements Language{
    // do something
}

public class English implements Language{
    // do something
}

public class LanguageService {

    private final Language language;

    public LanguageService(Language language) {
        this.language = language;
    }
}

LanguageService는 Aggregation 의존관계를 갖습니다.

따라서 자체적인 객체생성이 불가능하며 다른 타입의 객체가 필요합니다.

하지만 Type이 Language로 되어있기 떄문에 필요한 객체의 타입은 English가 될 수도 Korean이 될 수도 있습니다.

따라서 프로그램이 무엇을 의존할지 자체적으로 정할 수 없게되고

어떤 타입의 객체를 사용할 것인지를 외부에서 주입해줘야 합니다.
(Korean,English 또한 설정을 추가해 주입해줘야 함)

 

이를위한 여러가지 의존관계 주입방법이 나오게됐으며 이를 통틀어 Dependency Injection 이라 부릅니다.

 

아래는 같이읽어보면 좋은 글입니다. 

https://masiljangajji-coding.tistory.com/51

 

IoC(Inversion Of Control)란

IoC/DI(Inversion Of Control/Dependency Injection)란 IoC(Inversion Of Control)란? IoC는 제어의 역전을 뜻합니다. 제어의 역전.. 제어가 역전된다.. 이게 어떤 의미일까요? 기존의 프로그램은 구현 객체가 프로그램

masiljangajji-coding.tistory.com

 

https://masiljangajji-coding.tistory.com/53

 

Dependency Injection(의존관계 주입)이란

Dependency Injection(의존관계 주입)이란? 이 글은 IoC , Dependency 의 개념을 알고있다는 전제하에 작성된 글입니다. 원활한 이해를 위해서 아래글을 읽어주세요 https://masiljangajji-coding.tistory.com/51 IoC(Inver

masiljangajji-coding.tistory.com

도움이 되셨으면 좋겠습니다.

'Spring > Spring Core' 카테고리의 다른 글

Dependency Injection(의존관계 주입)이란  (3) 2024.01.04
IoC(Inversion Of Control)란  (1) 2024.01.02

IoC(Inversion Of Control)란?

IoC는 제어의 역전을 뜻합니다.
제어의 역전.. 제어가 역전된다.. 이게 어떤 의미일까요?

 

기존의 프로그램은 구현 객체가 프로그램의 제어 흐름을 조종합니다.
즉 사용자에 의해서 흐름이 제어되며 프로그램은 사용자가 만들어놓은 흐름에 따라 실행 될 뿐입니다.

 

IoC는 이 상태를 반전시킨 것으로 사용자에 의해 흐름이 제어되는 것이 아닌 프로그램 자체가 제어권을 갖는 것입니다.

 

Non - IoC Exapmle

public class Main {


    public static void main(String[] args) {


        MemoryMemberRepository memoryMemberRepository = new MemoryMemberRepository();
        MemberService memberService = new MemberServiceImpl(memoryMemberRepository);

        /**
         * memberService 를 이용한 코드
         */

    }

}

 

일반적인 형태의 코드입니다.

 

main문 안에서 필요한 객체들을 생성하고 사용하게 됩니다

이 경우 해당 객체들의 생명주기는 main이 시작하면서 생성되고 main이 종료되면서 삭제됩니다.

 

만약 사용자가 코드를 변경한다면

public class Main {

    public static MemberService memberService = new MemberServiceImpl(new MemoryMemberRepository());

    public static void main(String[] args) {

        /**
         * memberService 를 이용한 코드
         */

    }

}

 

객체들의 생명주기는 클래스가 로드될때 생성되고 프로그램 종료시 삭제됩니다.

또한 사용자가 언제 memberService를 호출해 사용할 지 흐름을 정의할 수 있습니다.

 

사용자가 코드를 만드는 방식에 따라서 객체의 생명주기와 동작의 흐름이 바뀌게되며

이는 사용자가 프로그램의 제어 흐름을 조종하는 것과 같습니다.

 

IoC는 이러한 흐름을 역전시켜 프로그램이 자체적으로 흐름을 제어하는 것입니다.

 

IoC Exapmle

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memoryMemberRepository());
    }

    @Bean
    public MemoryMemberRepository memoryMemberRepository() {
        return new MemoryMemberRepository();
    }

}

 

Spring FrameWork에서 자바 코드를 이용해 Bean을 등록하는 코드입니다.

 

이 코드를 통해서 MemberService , MemoryMemberRepository는 Spring Bean의 형태로 Context에 등록됩니다.

또한 Bean들의 생명주기또한 Context가 스스로 제어합니다.

 

사용자는 이 과정에 개입하지 않으며 모든 동작은 Spring이 정의해놓은 순서와 규칙을 통해 이루어집니다.

 

즉 사용자에게 제어권이있는게 아닌 프로그램 자체가 제어권을 갖고있는 것입니다.
이것을 제어권이 역전되었다 , IoC 되었다 라고 말합니다.

 

FrameWork없이 순수 자바코드로도 가능합니다.

@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    enum Method{
        POST,GET
    }
    String[] value();
    Method method() default Method.GET;

}

(사용자정의 어노테이션)

public void initialize(Set<Class<?>> c, ServletContext ctx) {

        if (Objects.isNull(c)) {
            log.info("Controller not found");
            return;
        }

        for (Class<?> controllerClass : c) {
            try {
                Constructor<?> constructor = controllerClass.getConstructor();
                Object controllerInstance = constructor.newInstance();

                RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
                if (requestMapping != null) {
                    String[] values = requestMapping.value();

                    for (String value : values) {
                        String key = getKey(requestMapping.method().name(), value);
                        beanMap.put(key, controllerInstance);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }


        ctx.setAttribute(CONTEXT_CONTROLLER_FACTORY_NAME, this);

    }

 

이 코드는 Java Servlet을 이용해 WebApplication 을 구축하는 코드의 일부입니다.

(Java Servlet은 FrameWork이 아닌 순수자바)

 

Reflection 을 통해 RequestMapping 어노테이션을 갖고있는 클래스의 정보를 읽어와 객체를 생성한 후

Map에 넣어 관리하는 코드로 프로그램이 실행될 때 동적으로 클래스들을 읽어 관리하게 됩니다.

 

 

단위 테스트를 수행하는데 사용되는 프레임워크인 JUnit또한 실행 및 관리를 위한 생명주기를 갖습니다.

@SpringBootTest
class CoreApplicationTests {

    @BeforeEach
    void beforEach() {
    }

    @Test
    void contextLoads() {
    }

    @AfterEach
    void afterEach() {
    }

}

 

사용자는 @BeforeEach , @Test , @AfterEach 어노테이션만 사용하면 프로그램이 알아서 테스트로 인식하고

실행시 JUnit이 이미 정의한 동작 순서와 생명주기에 따라 테스트하게 됩니다.

 

따라서 IoC가 됐다 = 프로그램이 자체적으로 흐름을 제어한다.

이렇게 정리할 수 있습니다.

 

프로그램의 자체적인 흐름이란??

  1. 프로그램이 컨테이너를 통해 생명주기를 관리한다.
  2. 동작의 순서가 프로그램이 정의한 흐름을 따른다.

(이런 흐름에 사용자가 억지로 개입할수는 있지만 일반적인 경우만 다루겠습니다.)

 

IoC의 이점

 

IoC/DI를 구현함으로 사용영역과 구성영역을 나눌 수 있습니다.

쉽게말하면 사용자는 객체의 실행에만 신경쓰고 , 객체들의 관리와 동작의 흐름은 프로그램이 하게 하는것입니다.

// 실행영역 
public static void main(String[] args) {

        // 사용자가 객체 사용시 new 를 이용해 찍어내지 않음 , Context에 등록된 Bean을 꺼내 사용
        // 즉 객체를 사용자가 관리하는게 아님 
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);

        // 따라서 객체자체의 실행에만 집중할 수 있음 
        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member);
    }


// 여기는 구성영역 , 해당 객체들이 Bean에 등록되는 과정과 관리방법은 이미 Spring에 정의돼있음
@Configuration 
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memoryMemberRepository());
    }

    @Bean
    public MemoryMemberRepository memoryMemberRepository() {
        return new MemoryMemberRepository();
    }

}

실행하는 코드와 구성하는 코드를 분리하게 됨으로써 유지보수의 용이성과 가독성을 높여줍니다.

 

이런 IoC개념이 기본적으로 깔려있는 FrameWork는 사용자가 제어 해야 할 상당 부분들을 대신함으로써

개발 생산성을 크게 증가시켜줍니다.

 

Ex) 스프링 사용시 사용자는 객체의 

의존관계를 어떻게 주입할것 인지만 설정해주면 
Bean을 등록하고 관리하는 모든 과정은 스프링이 제어 함 (IoC/DI의 개념)

 

추가적으로 흔히 말하는 FrameWork Vs Library 의 가장 큰 차이도 IoC개념이 있냐 없냐의 차이가 가장 핵심적입니다.

 

아래는 추가로 읽으면 좋은 글입니다.

https://masiljangajji-coding.tistory.com/52

 

Dependency(의존관계)란?

Dependency(의존관계)란? 의존관계는 코드에서 두 모듈간의 연결을 의존관계라 합니다. 객체지향언어에서 두 클래스 간의 관계를 말하기도 합니다. 의존관계의 종류는 크게 4가지가 존재합니다. Dep

masiljangajji-coding.tistory.com

https://masiljangajji-coding.tistory.com/53

 

Dependency Injection(의존관계 주입)이란

Dependency Injection(의존관계 주입)이란? 이 글은 IoC , Dependency 의 개념을 알고있다는 전제하에 작성된 글입니다. 원활한 이해를 위해서 아래글을 읽어주세요 https://masiljangajji-coding.tistory.com/51 IoC(Inver

masiljangajji-coding.tistory.com

도움이 되셨으면 좋겠습니다.

'Spring > Spring Core' 카테고리의 다른 글

Dependency Injection(의존관계 주입)이란  (3) 2024.01.04
Dependency(의존관계)란?  (3) 2024.01.04

NHN Academy(조선대) 4기 회고

여러 부트 캠프 중에 NHN Academy 관련해서는 정보가 많지 않아서 회고를 위장한 정보글을 써봅니다.

아카데미에 지원에 정보를 찾는 분들을 위해 글을 작성하는 것이며 제가 겪은 4기를 기준으로 말씀드리겠습니다.

저의 경우는 체험과정(끝) - 본 과정(끝) - Spring 과정(진행 중) - 프로젝트 과정(추후 선발 필요)의 과정을 거쳤습니다

이는 어디까지나 4기를 기준으로 쓴 글이며 향후 아카데미 교육정책에 따라서 변경이 가능합니다.

 

교육방식

아카데미가 지향하는 교육 방법은 동료 학습을 통한 성장입니다.

3명~5명을 기반으로 팀을 이루어서 학습이 진행되며 아카데미에서는 공부할 것들에 대한 교재 및 자료들을 제공하고 관리합니다.

각 팀마다 TA(조교)가 배정되고 TA 또한 플레잉코치와 비슷하게 팀원들과 같이 공부하고 코드 리뷰를 진행합니다.

이 부분에 대해서는 자유도가 매우 높아 정해진 교재나 자료를 활용하지 않고 팀 자체적으로 다른 자료를 참고하는 학습도 가능합니다.

뿐만 아니라 학습 진도에 대해서도 팀 차원에서 자율적으로 이루어집니다.

 

중간중간에 교육 전반에 것들을 책임 지시는 학장님, DB를 담당하시는 부학장님이 단체 교육을 하실 때도 있고 특강의 형태로

진행될 때도 있으며 과제 및 시험을 통한 검증 시스템이 존재합니다.

장점

보장된 교육

가장 중요한 부분은 학습에 도움을 주시는 모든 분들이 NHN 소속이십니다.

오시는 강사분들이 CTO부터 시작해 최소 팀장급의 인사가 오기 때문에 제공하는 교육과 자료의 질 또한 매우 뛰어난 편입니다.

 

개인적으로 저는 이 부분이 특장점이라 생각합니다.

 

보통의 부트 캠프에서는 강사진에 대한 정확한 레퍼런스를 알 수 없을 때가 많습니다.

 

뛰어난 강사진, 네카라 출신 강사진, 현직 xx 개발자 ... 이런 식의 홍보를 하지만 그것이 사실인지

또 사실이라면 얼마나 경력을 쌓은 건지 , 이전 근무지가 어디인지 공개하지 않는 경우가 많습니다.

 

보통의 회사에서는 겸업금지 조항이 있기 때문에 실제 현직 개발자여도 그 레퍼런스를 공개할 순 없으며
개인적으로 이는 교육과정 자체에 대한 신뢰를 매우 떨어트린다 생각합니다.
(이런 이유로 강사진의 수준을 보장받는 네이버 부스트 캠프, 우아한 테크 코스 등등이 유명한 것이라 생각합니다.)

 

특히 아카데미의 빛과 소금이자 코드의 메시아이신 학장님은 정말 대단합니다.

자유로운 분위기

학습에 대한 자유도가 매우 높기 때문에 중간중간 공부하면서 자체적인 팀 과제를 설정하거나

진도를 재설정하는 것이 가능해 유연하게 계획을 세울 수 있습니다.

 

동료 학습을 기반으로 하기 때문에 개인으로는 할 수 없는 경험이 가능합니다.

Git을 통해 PR 날리고... Merge 하고.... 코드 리뷰하고...

동료들과 같이 학습하고 리뷰하는 시간을 통해 다양한 의견을 주고받는 것은 협업에 대한 경험치를 확실히 축적시켜줍니다.

 

충분한 토의 후에도 결론이 나지 않는 문제들에 대해서는 TA를 이용하거나 학장님께 가서 의견을 물을 수 있기 때문에

개인적으로는 이 방식을 매우 선호합니다.

자유로운 장소

기본적으로 조선대에서 제공하는 독자적인 공간을 사용합니다.

이 공간은 NHN Academy 연수생들만 사용 가능하며, 시설 또한 괜찮은 편입니다.

배정된 공간 이외에도 학교 시설물을 이용 가능하기 때문에 공간의 제약이 적은 편입니다.

연계채용

본 과정을 수료한 뒤 선발을 거쳐 프로젝트 과정을 들어가게 되면

프로젝트 결과물과 추가적인 심사 후 NHN에 연계 채용이 가능합니다.

단점

자유로운 분위기

앞서 말했듯이 팀을 이루어 학습하는 동료학습의 방식입니다.

따라서 정해진 시간에 교육장소만 온다면 무엇을 공부하든 , 얼마나 공부하든 그것은 팀의 책임입니다.

 

이런 높은 자유도는 성향에 따라 장점이 될 수도 단점이 될 수도있습니다.

 

개개인의 실력이 다르기 떄문에 팀의 학습 진도를 따라가는게 벅찬 경우도 있으며
팀원 모두가 열성적으로 참여하지 않으면 팀 전체의 학습에 지장이 생길 수 있습니다.

 

"팀의 학습이 느리고 정체되는 건 우리가 직접 개입할건 아니고 팀의 문제야 , 네가 원하면 팀을 변경해 줄게"
이것이 아카데미의 기조기 때문에 빡센 관리를 원하시는 분 혹은 집체교육으로 빠르게 학습하는 방식을 선호하시는 분들에게는 적합하지 않습니다.

거주지

교육이 진행되는 장소는 조선대학교(전라도 광주)입니다.

만약 거주지가 가깝다면 문제가 없지만 타 지역에서 교육을 수강하기에는 무리가 있을 수 있습니다.

저 같은 경우에도 본가는 경기도, 학교는 서울이었기 때문에 자취를 하고 있습니다.

마무리

가장 중요한 건 개인의 성향이라 생각합니다.

 

자유로운 분위기에서 유동적으로 행동하시는 걸 좋아하시는 분들께는 정말 좋은 경험이겠지만
그렇지 않으신 분들은 만족하기 힘들지 않을까 생각합니다.

 

개인적으로는 교육에 너무 만족했고 더 많은 사람들 참여해 더욱 뛰어난 분들이 배출되면 좋겠습니다.

 

아래는 실제 저의 팀 페이지입니다.

 

 

도움이 되셨으면 좋겠습니다.

 

 

신입 개발자 취업 여정기 (feat: 가비아 인턴 합격)

들어가는 글안녕하세요 최근 정말 좋은 일이 있었는데요 백엔드 포지션으로 가비아에 합류하게 됐습니다.이번글은 합류의 과정과 제 개인적인 생각을 작성하려 합니다.서비스 회사에 가고싶다

masiljangajji-coding.tistory.com

 

 

2025년 상반기 회고 (feat: 카카오게임즈 최종탈락)

들어가는 글안녕하세요 오랜만에 글을 작성합니다.블로그를 꾸준히 이어가겠다고 다짐했는데,미디엄 기준 마지막 글 작성일이 5월, 티스토리 기준 2월인 것을 보면 반성하게도 되고돌아보면 글

masiljangajji-coding.tistory.com

 

+ Recent posts