<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hj-language.log</title>
        <link>https://velog.io/</link>
        <description>Backend Engineer</description>
        <lastBuildDate>Mon, 24 Mar 2025 17:53:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hj-language.log</title>
            <url>https://images.velog.io/images/hj-language/profile/ba9767bc-3e16-44de-9dd4-8b59f89589c7/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hj-language.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hj-language" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SOLID] 리스코프 치환 원칙(LSP) 위배 예제]]></title>
            <link>https://velog.io/@hj-language/SOLID-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99LSP%EC%9D%B4-%EB%AD%94%EB%8D%B0</link>
            <guid>https://velog.io/@hj-language/SOLID-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99LSP%EC%9D%B4-%EB%AD%94%EB%8D%B0</guid>
            <pubDate>Mon, 24 Mar 2025 17:53:28 GMT</pubDate>
            <description><![CDATA[<p>아래 코드를 살펴보자.</p>
<pre><code class="language-java">class Rectangle {
  int width;
  int height;

  public void setHeight(int value) {
    this.height = value;
  }
}

class Square extends Rectangle {
  @Override
  public void setHeight(int value) {
    this.height = value;
    this.width = value;
  }
}</code></pre>
<p>사각형 Rectangle이 있고, 정사각형 Square는 Rectangle을 상속받는다.
height를 바꾸려고 하면, 정사각형의 특성 상 height와 width를 모두 변경한다.</p>
<p>위 예제는 LSP를 위배할까?</p>
<p>정답은 &quot;위배한다&quot; 이다.</p>
<p>먼저 LSP(리스코프 치환 원칙)란, 다음과 같다.</p>
<blockquote>
<p>하위 클래스는 상위 클래스의 행위를 깨뜨리지 않으면서 상위 클래스를 대체할 수 있어야 한다.</p>
</blockquote>
<p>위배되는 이유는 다음과 같다.</p>
<h3 id="1-rectangle과-square의-행위가-다르다">1. Rectangle과 Square의 행위가 다르다.</h3>
<p>Rectangle에는 width, height를 독립적으로 설정할 수 있다.
하지만 Square는 height를 설정할 때 width도 동시에 변경된다.</p>
<pre><code class="language-java">Rectangle rect = new Square();
rect.setHeight(10);
System.out.println(rect.width); // 예상: 기본값(변경 X), 실제: 10</code></pre>
<p>이 경우 Rectangle의 기본 가정인 &quot;width, height를 독립적으로 설정할 수 있다.&quot;는 가정이 깨진다.
즉, Rectangle을 사용하는 코드에서 Square로 대체했을 때 예측하지 못한 동작이 발생할 수 있다.</p>
<h3 id="2-클라이언트-코드가-rectangle의-동작을-가정하고-있는-경우-문제">2. 클라이언트 코드가 Rectangle의 동작을 가정하고 있는 경우 문제</h3>
<pre><code class="language-java">public void resizeRectangle(Rectangle rect) {
    rect.setHeight(10);
    rect.setWidth(20);
    assertThat(rect.width * rect.height).isEqualTo(200);  // Error
}</code></pre>
<p>여기서는 setHeight(10), setWidth(20)을 적용하면 넓이가 200 이상이 될 것이라고 가정한다.
하지만 rect가 Square라면 setWidth(20) 호출 시 height도 20이 되어 예상과 다르게 동작한다.</p>
<h3 id="정리">정리</h3>
<ul>
<li>Square는 Rectangle이 가진 인터페이스인 &quot;독립적인 setHeight()와 setWidth()가 가능하다.&quot; 라는 가정을 깨버린다.</li>
<li>따라서 Square는 Rectangle을 완전히 대체할 수 없다. -&gt; 리스코프 치환 원칙을 위배한다.</li>
</ul>
<h3 id="여기서-lsp를-준수하려면">여기서 LSP를 준수하려면?</h3>
<p>인간이 개념적으로 이해하기로는 정사각형이 사각형의 한 종류라고 볼 수 있지만, 사실 Rectangle과 Square는 본질적으로 다르게 동작한다.
따라서 상속 관계를 제거하고 별개의 클래스로 만드는 것이 좋다.</p>
<pre><code class="language-java">class Rectangle {
    private int width;
    private int height;

    public int getArea() {
        return width * height;
    }
}

class Square {
    private int side;

    public int getArea() {
        return side * side;
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OAuth] 개념, 실습 (Kakao)]]></title>
            <link>https://velog.io/@hj-language/OAuth</link>
            <guid>https://velog.io/@hj-language/OAuth</guid>
            <pubDate>Tue, 12 Jul 2022 04:33:45 GMT</pubDate>
            <description><![CDATA[<h3 id="개념">개념</h3>
<p style="text-align: center;">
<img src='https://velog.velcdn.com/images/hj-language/post/d4595e11-fb6a-4a6d-9b73-3029ea6a04f2/image.png' style="width:50%; margin-bottom: 0;"> 이미지 출처: naver developer </img>
</p>
위같은 로그인 서비스들은 별도로 application에 회원가입하지 않아도 로그인을 할 수 있게 한다. 해당하는 플랫폼에 계정만 있다면 application의 서비스를 이용할 수 있다.
이렇게 외부 서비스에서도 인증을 가능하게 하고 그 서비스의 API들을 이용하게 해주는 것이 **OAuth**(Open Authorization)이다.

<p>현재 OAuth 2.0의 정확한 개념은 다양한 플랫폼 환경에서 권한 부여를 위한 산업 표준 프로토콜이다.</p>
<h3 id="배경">배경</h3>
<p>기존 비밀번호 인증 방식에서는 여러 문제가 있었는데, 다음과 같다.</p>
<ul>
<li>사용자가 제 3의 application에게 id/pw를 제공하기 꺼려한다.</li>
<li>각종 application에 id/pw를 계속 제공하는 경우 보안에 취약해진다.</li>
<li>Id/pw를 알고 있는 application은 모든 권한을 가지므로 위험 부담이 생긴다.</li>
<li>pw를 변경한다면 application은 동작할 수 없으며, 모든 application에 대해 갱신할 필요가 생긴다.</li>
</ul>
<p>예를 들어, 내가 사용하려는 app A가 있고, 여기서 facebook에 글을 올린다고 가정해보자.</p>
<ul>
<li>A에 내 facebook 계정의 id/pw를 저장해야 한다.</li>
<li>Facebook에 글을 저장하기 위해서는 글을 올리는 권한만 있으면 되는데, id/pw를 가지고 있으므로 그 외의 모든 권한을 갖게 된다.</li>
<li>App A 자체의 보안이 취약하다면 A 계정 뿐만 아니라 facebook의 id/pw도 보안에 위험해질 수 있다.</li>
<li>Facebook의 pw를 바꾼다면, A 계정에서도 갱신을 해주어야 하며, 갱신하지 않으면 원하는 동작이 수행되지 않는다.</li>
</ul>
<p>최초 OAuth(1.0a)에서는 구현이 복잡했고, access token이 만료되지 않았으며 HMAC을 통해 암호화하였다. 반면 OAuth 2.0에서는 기능을 단순화하였고, 암호화를 https에 맡기며 다양한 인증 방식을 지원한다.</p>
<h3 id="용어">용어</h3>
<p>OAuth에서 사용하는 주요 용어를 몇 가지 살펴 보자.</p>
<ul>
<li>Resource Owner: Client와 resource server를 사용하는 계정을 가지고 있는 개인</li>
<li>Client: Open API를 이용하여 개발된 OAuth를 사용하여 resource server에게 접근하는 웹사이트 또는 application</li>
<li>Resource Server: OAuth를 통해 접근을 지원하는 웹 application, Open API를 제공하는 서버</li>
<li>Authorization Server: 사용자의 동의를 받아서 권한을 부여하는 서버</li>
</ul>
<h3 id="인증-방식-종류">인증 방식 종류</h3>
<p>인증 방식 종류에는 다음 네 가지가 있는데, 주로 authorization code grant가 많이 사용된다고 한다.</p>
<ul>
<li>Authorization Code Grant</li>
<li>Implicit Grant</li>
<li>Resource Owner Password Credentials Grant</li>
<li>Client Credentials Grant</li>
</ul>
<h3 id="인증-프로세스">인증 프로세스</h3>
<h4 id="register">Register</h4>
<p>Client가 resource server를 이용하기 위해서는, resource server에 승인을 받아야 하는데 이 과정을 register라고 한다. 네 가지 인증 방식에서 공통적으로 아래 세 가지를 이용한다.</p>
<ul>
<li>Client ID: Client를 식별하는 식별자 (노출 상관 없음)</li>
<li>Client Secret: 식별자에 대한 비밀번호 (노출되면 안 됨)</li>
<li>Authorized redirect URI: Resource server가 authroized code를 전달할 URI<h4 id="authorization-code-grant-인증-프로세스">Authorization Code Grant 인증 프로세스</h4>
<p style="text-align: center;">
<img src='https://velog.velcdn.com/images/hj-language/post/da2f13cd-71a7-4e6b-8850-2f9fb59dea48/image.png' style="width:90%; margin-bottom: 0;"> 이미지 출처: https://cheese10yun.github.io/oauth2/ </img>
</p>
먼저 Client가 파라미터로 Client ID, Redirect URL, Response_type을 code로 지정하여 Authorization Server에 전달한다. 여기서 Response_type을 token으로 줄 수도 있는데, 이렇게 하면 Implicit Grant 방식이 된다고 한다.

</li>
</ul>
<p>정상적으로 인증이 되면, 권한 부여 코드를 Client에게 보낸다.</p>
<p>성공적으로 권한 부여 코드를 받은 Client는 이 코드를 이용하여 Access Token을 Authorization Server에 추가로 요청한다. 이 때 Client ID, Client Secret, Redirect URL, Grant type(인증 타입)을 보낸다.</p>
<p>마지막으로 Access token을 응답 받으면 Access token을 사용하여 Resource Server에 API를 호출할 수 있다.</p>
<h3 id="kakao-oauth-실습">Kakao Oauth 실습</h3>
<p style="text-align: center;">
<img src='https://velog.velcdn.com/images/hj-language/post/6feada89-6f51-4578-a815-49ffe48cc00f/image.png' style="width:80%; margin-bottom: 0;"> 이미지 출처: Kakao developers </img>
</p>
Request URL을 보면, GET방식으로 요청하며 oauth로 시작하는 것을 알 수 있다.

<p>위에서 register에는 client id와 client secret, redirect uri를 요구한다고 언급했는데,
실제로 request parameter에 필수 요소에 client id와 redirect uri가 들어가있는 것을 확인할 수 있다.</p>
<p>여기서 client secret이 없는 것은, client secret 개념이 client_id로 이용되며 client id 개념은 내 애플리케이션 정보에 들어가면 확인할 수는 있지만 굳이 사용하지 않는 것 같다.</p>
<p>그리고 Authorization Code Grant 방식에서는 response_type을 code로 고정하여 이용한다고 했는데, 카카오에서도 code로 고정하여 이용하는 것을 보면 authorization code grant 방식을 이용하는 것 같다.</p>
<p>이렇게 하면 인가 코드, 즉 아까 살펴본 개념에서의 용어로 권한 부여 코드를 받을 수 있다.</p>
<p style="text-align: center;">
<img src='https://velog.velcdn.com/images/hj-language/post/a4a37932-1d32-43b7-bb90-a02a6633a304/image.png' style="width:70%; margin-bottom: 0;"></img>
</p>

<p>python으로 간단히 구현한 코드를 돌려보면 응답으로 access token과 refresh token, access token과 refresh token의 유효기간, scope이 나오는 것을 알 수 있다.</p>
<p>scope라고 하는 것은 application에서 권한을 제어할 때 이용하는 기능이다. 여기서는 message 기능을 이용했기 때문에 이렇게 scope가 나온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 최대공약수와 최소공배수(2609) - Java]]></title>
            <link>https://velog.io/@hj-language/%EB%B0%B1%EC%A4%80-2609%EB%B2%88-%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98%EC%99%80-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98-java-%ED%92%80%EC%9D%B4</link>
            <guid>https://velog.io/@hj-language/%EB%B0%B1%EC%A4%80-2609%EB%B2%88-%EC%B5%9C%EB%8C%80%EA%B3%B5%EC%95%BD%EC%88%98%EC%99%80-%EC%B5%9C%EC%86%8C%EA%B3%B5%EB%B0%B0%EC%88%98-java-%ED%92%80%EC%9D%B4</guid>
            <pubDate>Sun, 31 Jan 2021 12:46:15 GMT</pubDate>
            <description><![CDATA[<p>백준 2609번을 풀다가 최대공약수를 구하는 새로운 알고리즘에 대해 공부하게 되었다. 명시적으로 기술된 가장 오래된 최대공약수 구하기 알고리즘이라고 한다.</p>
<h2 id="최대공약수-풀이">최대공약수 풀이</h2>
<h3 id="유클리드-호제법알고리즘">유클리드 호제법(알고리즘)</h3>
<p>2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a&gt;b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다. 이 성질에 따라, b를 r로 나눈 나머지 r&#39;를 구하고, 다시 r을 r&#39;로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다. - 출처 위키백과</p>
<h3 id="예시">예시</h3>
<p>1071과 1029의 최대공약수를 구하면,</p>
<p>1071은 1029로 나누어떨어지지 않기 때문에, 1071을 1029로 나눈 나머지를 구한다. ≫ 42
1029는 42로 나누어떨어지지 않기 때문에, 1029를 42로 나눈 나머지를 구한다. ≫ 21
42는 21로 나누어떨어진다.
따라서, 최대공약수는 21이다.</p>
<h3 id="적용---java">적용 - java</h3>
<pre><code class="language-java"> int getGcf(int n1, int n2) {
        if (n1 &lt; n2) {
            int tmp = n1;
            n1 = n2;
            n2 = tmp;
        }
        int tmp;
        while((tmp = n1%n2) != 0) {
            n1 = n2;
            n2 = tmp;
        }
        return n2;
    }</code></pre>
<p>tmp는 n1를 n2로 나눈 나머지를 저장하는 변수이다. tmp가 0이 될 때 까지 반복하여 나눈다.
나머지가 0이 되게 한 몫을 반환하면 그것이 최대공약수이다.</p>
<hr>
<h2 id="최소공배수-풀이">최소공배수 풀이</h2>
<p>최소공배수는 두 수를 곱하여 최대공약수로 나누면 된다.</p>
<pre><code class="language-java"> int getLcm(int n1, int n2) {
        int gcf = getGcf(n1, n2);
        return n1*n2/gcf;
    }</code></pre>
<hr>
<p>두 수 사이의 합을 구하는 등 수학적으로 접근하는 공부를 많이 해봐야겠다.</p>
]]></description>
        </item>
    </channel>
</rss>