<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jihye-woo.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 27 Jul 2021 11:14:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jihye-woo.log</title>
            <url>https://images.velog.io/images/jihye-woo/profile/fbd98395-f136-4ca4-be3b-f872deae7f33/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jihye-woo.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jihye-woo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Spring DI/IoC]]></title>
            <link>https://velog.io/@jihye-woo/Spring-DIIoC</link>
            <guid>https://velog.io/@jihye-woo/Spring-DIIoC</guid>
            <pubDate>Tue, 27 Jul 2021 11:14:25 GMT</pubDate>
            <description><![CDATA[<h4 id="의존성-주입di">의존성 주입(DI)</h4>
<p>하나의 처리를 위해서 여러 개의 컴포넌트를 통합하려고 할 때 DI 방식이 유리하다. </p>
<p>예를 들어 UserSerivce 클래스에서 회원가입 로직을 구현한다고 했을 때 UserRepository(User 엔티티에 대한 Repository), PasswordEncoder(패스워드 인코딩 관련 클래스) 두 가지 의존성이 필요하다고 가정해보자.</p>
<pre><code class="language-java">
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
}</code></pre>
<p>일반적인 방식은 UserService 클래스 내부에서 new 키워드를 통해 필요한 의존성을 직접 생성한다.</p>
<pre><code class="language-java">
public UserService() {
    this.userRepository = new UserRepository();
    this.passwordEncoder = new PasswordEncoderA();
}</code></pre>
<p>여기서 단점은, 한 번 클래스가 생성되고 나면 의존성을 변경할 수 없다는 것이다. 아래 사진과 같이 PasswordEncoder에 대해서 두 개 이상의 클래스가 구현이 되었을 때, 처음에는 PasswordEncoderA에 있는 인코딩 방식을 사용하다가 유저에 따라 PasswordEncoderB를 사용하고 싶더라도 교체가 불가능하다.</p>
<p><img src="https://images.velog.io/images/jihye-woo/post/63e70937-e4f8-4df3-864e-a9d1f2945e51/Screen%20Shot%202021-07-27%20at%207.48.06%20PM.png" alt=""></p>
<p>동적으로 의존성을 변경하고싶다고 하더라도 UserSerivce가 구체적인 컴포넌트에 의존하고 있기 때문에 때문에 변경이 불가능하다. 즉, DIP 의존성 역전 원칙에 위배되어 결합도가 높은 코드가 된다.</p>
<p>구체 클래스가 아닌 추상 클래스에 의존한 코드를 만들기 위해서는 의존성 주입 방식이 필요하다.</p>
<p>대표적인 예로 생성자 주입 방식이 있다.</p>
<pre><code class="language-java">
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
    this.userRepository = userRepository;
    this.passwordEncoder = passwordEncoder;
}</code></pre>
<p>위와 같이 생성자를 통해 외부에서 의존성을 주입받을 경우, 상황에 따라 PasswordEncoder 구체 클래스를 변경해서 주입받을 수 있다!!</p>
<h4 id="ioc-컨테이너">IoC 컨테이너</h4>
<ul>
<li>아직 정리하지 않았어용..ㅎㅎ</li>
</ul>
<hr>
<h4 id="질문할만한-요소">질문할만한 요소</h4>
<ul>
<li>IoC는 개발자가 프로그램의 제어 흐름을 직접 제어</li>
<li>IoC 컨테이너의 역할은 무엇이 있을까요</li>
<li>DI 종류는 어떤 것이 있고, 이들의 차이는 무엇인가요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[이슈 트래커 - 코드리뷰 정리]]></title>
            <link>https://velog.io/@jihye-woo/%EC%9D%B4%EC%8A%88-%ED%8A%B8%EB%9E%98%EC%BB%A4-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jihye-woo/%EC%9D%B4%EC%8A%88-%ED%8A%B8%EB%9E%98%EC%BB%A4-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 27 Jul 2021 10:26:05 GMT</pubDate>
            <description><![CDATA[<h3 id="이슈트래커--리뷰-정리">이슈트래커  리뷰 정리</h3>
<h3 id="1-중복-로직-통합">1. 중복 로직 통합</h3>
<p>현재 코드에는 Github Web과 iOS</p>
<pre><code class="language-java">@RestController
@RequestMapping(&quot;/login&quot;)
public class GitHubLoginController {

    private final GitHubLoginService loginService;

    public GitHubLoginController(GitHubLoginService loginService) {
        this.loginService = loginService;
    }


    @GetMapping(&quot;/github&quot;)
    public ApiResponse&lt;GitHubUserResponse&gt; githubLogin(@RequestParam String code) {
        GitHubUserResponse response = loginService.login(code);
        return ApiResponse.ok(response);
    }

    @GetMapping(&quot;/github/iOS&quot;)
    public ApiResponse&lt;GitHubUserResponse&gt; githubIOSLogin(@RequestParam String code) {
        GitHubUserResponse response = loginService.loginIOS(code);
        return ApiResponse.ok(response);
    }
}
</code></pre>
<ul>
<li>&#39;USER-AGENT&#39; 혹은 &#39;USER-ID&#39; 등과 같이 사용자를 식별하는 커스텀 header를 사용해 인터셉터에서 iOS와 Web을 구분하는 로직을 만들고 컨트롤러 레이어부터는 로그인 시 공통 로직을 사용하게 하는 방식을 사용해도 좋을 것 같다는 생각이 든다.</li>
</ul>
<blockquote>
<p>💡 <strong>커스텀 헤더 네이밍</strong>?
[ 참고 : <a href="https://stackoverflow.com/questions/3561381/custom-http-headers-naming-conventions">Custom HTTP headers : naming conventions</a> ]</p>
<ul>
<li>The recommendation is was to start their name with &quot;X-&quot;. E.g. X-Forwarded-For, X-Requested-With</li>
</ul>
</blockquote>
<ul>
<li>On June 2012, the deprecation of recommendation to use the &quot;X-&quot; prefix has become official as RFC 6648. <ul>
<li>결론은, &quot;X-&quot; prefixed headers를 계속 사용해도 좋지만, 더 이상 공식적으로 권고하는 방식은 아니다.</li>
</ul>
</li>
</ul>
<h3 id="2-공통-api-응답-포맷">2. 공통 API 응답 포맷</h3>
<ul>
<li>모든 응답에 대해서 클라이언트에게 보내기 전에 ApiResponse라는 클래스를 통해서 매핑하는 과정을 추가했었다.</li>
</ul>
<pre><code class="language-java">public class ApiResponse&lt;T&gt; {
    private T data;
    private ApiResponse() { }
}</code></pre>
<pre><code class="language-java">@GetMapping(&quot;/github&quot;)
public ApiResponse&lt;GitHubUserResponse&gt; githubLogin(@RequestParam String code) {
     GitHubUserResponse response = loginService.login(code);
     return ApiResponse.ok(response);
}</code></pre>
<ul>
<li><p>그런데 ApiResponse 를 사용하는 것이 레거시 느낌이 강하게 나는 패턴이라는 리뷰를 받았다. 이것을 사용했을 때와 사용하지 않았을 때를 구분해서 생각해보시면 좋을 것 같다고 말씀해주셨다.</p>
</li>
<li><p>흠.. 근데! 통신을 할 때 공통 포맷이 있다면 서버와 클라이언트가 좀 더 쉽게 소통할 수 있지 않을까라는 생각?</p>
</li>
<li><p><a href="https://stackoverflow.com/a/23708903">구글 json 가이드에서 YouTube JSON API</a>를 보면 error를 리턴하는 형태가 다르다는 것만 제외하면, data 필드 아래에 실제 데이터를 래핑해서 응답을 보내는 형식은 같은데.. 훔 어떤게 맞는건지 잘 모르겠다;;😂 스터디에서 같이 이야기해봐야지</p>
</li>
</ul>
<h3 id="3-profile-값-받기">3. Profile 값 받기</h3>
<ul>
<li>기존에는 생성자 주입을 통해 Environment 빈을 받고, getProperty()메소드를 활용해서 profile에 있는 값을 가져왔었다</li>
<li>이번에 받은 리뷰에서는 @Value 어노테이션을 통해서 profile 값을 가져오는 방식을 추천해주셨는데 아직 이점에 대해서는 정확하게는 잘 모르겠다.</li>
<li>추측하기로는 Environment 객체에 의존적이지 않는 코드를 만들어 최대한 클래스간 결합도를 낮추기 위한 방식이기 때문이 아닐까</li>
</ul>
<pre><code class="language-java">// Environment 빈을 사용해서 주입하는 방식
public LoginController(Environment environment) {
        this.CLIENT_ID = environment.getProperty(&quot;github.client.id&quot;);
        this.CLIENT_ID_IOS = environment.getProperty(&quot;github.client.id.ios&quot;);
    }

// @Value 어노테이션을 사용해 특정 값을 주입받는 형식
 public LoginController(@Value(&quot;github.client.id&quot;) String clientId, @Value(&quot;github.client.id.ios&quot;) String iOSClientId) {
        this.CLIENT_ID = environment.getProperty(&quot;github.client.id&quot;);
        this.CLIENT_ID_IOS = environment.getProperty(&quot;github.client.id.ios&quot;);
    }</code></pre>
<h3 id="4-필드-인젝션-vs-생성자-인젝션">4. 필드 인젝션 VS 생성자 인젝션</h3>
<ul>
<li>현재 코드에서는 필드 인젝션을 사용하고 있다</li>
<li>필드 인젝션을 사용할 경우 외부에서 변경이 불가능하므로 테스트가 힘들 수도 있다</li>
<li>물론 지금의 경우에는 상속관계에 놓여있는 클래스 타입이 아니라 String이라서 괜찮을 수도 있겠지만!! 그래도 다른 코드와 통일성을 지켜준다는 측면에서는 </li>
<li>예를 들어 필드 인젝션의 대상이 Repsitory와 같이 DB에 종속적인 타입일 때, 개발자가 개발단계에서는 MainRepostory를 사용하고 테스트 환경에서는 MinorRepository를 사용하는 전략을 취할 수 없다.</li>
</ul>
<pre><code class="language-java">@Configuration
public class AwsConfig {

    @Value(&quot;${cloud.aws.s3.access-key}&quot;)
    private String accessKey;

    @Value(&quot;${cloud.aws.s3.secret-key}&quot;)
    private String secretKey;

    @Value(&quot;${cloud.aws.s3.region}&quot;)
    private String region;

    @Value(&quot;${cloud.aws.s3.bucket}&quot;)
    private String bucket;

    @Bean
    public S3Client s3Client() {
        final AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
        final AmazonS3 amazonS3 = AmazonS3ClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();

        return S3Client.create(amazonS3, region, bucket);

    }
}
</code></pre>
]]></description>
        </item>
    </channel>
</rss>