<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>och_changhoon.log</title>
        <link>https://velog.io/</link>
        <description>짝퉁 프로그래머</description>
        <lastBuildDate>Sun, 14 Aug 2022 09:32:08 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. och_changhoon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/och_changhoon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[react] 검색 API 사용할 때 딜레이 주기]]></title>
            <link>https://velog.io/@och_changhoon/react-%EA%B2%80%EC%83%89-API-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C-%EB%94%9C%EB%A0%88%EC%9D%B4-%EC%A3%BC%EA%B8%B0</link>
            <guid>https://velog.io/@och_changhoon/react-%EA%B2%80%EC%83%89-API-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C-%EB%94%9C%EB%A0%88%EC%9D%B4-%EC%A3%BC%EA%B8%B0</guid>
            <pubDate>Sun, 14 Aug 2022 09:32:08 GMT</pubDate>
            <description><![CDATA[<h3 id="prologue">Prologue</h3>
<p>Search API를 통해 검색을 하고있던 찰나였다. onChange가 하나하나 바뀔 때 마다 통신을 하니 웹페이지가 너무 버벅이길래, 사용자의 입력이 끝난 후 지정한 시간을 초과하고 나서 통신을 할 수 있도록 구현했다.</p>
<h3 id="what">What?</h3>
<p>setTimeout &amp; useEffect.</p>
<h3 id="how">How?</h3>
<p>useEffect 안에 setTimeout을 걸어놓고, 그 안에 실행되는 함수로써 request()를 넣어주면 완성!</p>
<pre><code>async function request() {
    const res = await fetch(
      `http://10.58.1.43:3000/search/products?keyword=${searchValue}`
    );
    const result = await res.json();
    setSearchedValue(result.result);
  }

  useEffect(() =&gt; {
    const timeoutExecute = setTimeout(() =&gt; request(), 500);
    return () =&gt; clearTimeout(timeoutExecute);
  }, [searchValue]);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[javascript]카카오 API로 로그인하기 - javascript, 액세스 토큰 받아오기]]></title>
            <link>https://velog.io/@och_changhoon/javascript%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%98%EA%B8%B0-javascript-%EC%95%A1%EC%84%B8%EC%8A%A4-%ED%86%A0%ED%81%B0-%EB%B0%9B%EC%95%84%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@och_changhoon/javascript%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%98%EA%B8%B0-javascript-%EC%95%A1%EC%84%B8%EC%8A%A4-%ED%86%A0%ED%81%B0-%EB%B0%9B%EC%95%84%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Sun, 14 Aug 2022 09:25:22 GMT</pubDate>
            <description><![CDATA[<h3 id="prologue">Prologue</h3>
<p>카카오 로그인을 구현하기 위해 연습용으로 javascript로 만들어보았다. 하지만 나는 react였기 떄문에 다시 만들어야만 했다고...
그래도 혹시 도움이 될까 싶어 이렇게 글을 남긴다!</p>
<h3 id="what">What?</h3>
<p>상기하였듯 카카오 API. 
대략적인 가이드 문서 : 
<a href="https://developers.kakao.com/docs/latest/ko/kakaologin/js">https://developers.kakao.com/docs/latest/ko/kakaologin/js</a>
<a href="https://developers.kakao.com/sdk/reference/js/release/Kakao.html">https://developers.kakao.com/sdk/reference/js/release/Kakao.html</a></p>
<h3 id="how">How?</h3>
<p>카카오 로그인 버튼을 클릭했을 때, KAKAO_AUTH_URL로 이동하게 되고, 카카오 API를 통해 후미에 인가 코드가 붙은 채로 리다이렉트된다.
그 후 화면이 재 렌더되고, 인가 코드를 저장한 후 서버로 발송하는 로직을 통해 구현했다.</p>
<h4 id="사용된-hooks">사용된 hooks</h4>
<pre><code>    &lt;script src=&quot;https://developers.kakao.com/sdk/js/kakao.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      window.Kakao.init(&quot;e4dae92fceb345887914a31277525c73&quot;);

      function kakaoLogin() {
        window.Kakao.Auth.login({
          scope: &quot;profile_nickname, profile_image, account_email&quot;,
          success: (authObj) =&gt; {
            console.log(&quot;authObj : &quot;);
            console.log(authObj);

            // 백한테 authobj 속 access토큰만 줌
            // 그 후 authorize를 통해 확인
            window.Kakao.API.request({
              url: &quot;/v2/user/me&quot;,
              success: (res) =&gt; {
                console.log(&quot;success: &quot;);
                console.log(res);
              },
              fail: (res) =&gt; {
                console.log(res);
              },
            });
          },
        });
      }

      function kakaoLogout() {
        if (!Kakao.Auth.getAccessToken()) {
          alert(&quot;Not logged in.&quot;);
          return;
        }
        Kakao.Auth.logout(function () {
          alert(&quot;logout ok\naccess token -&gt; &quot; + Kakao.Auth.getAccessToken());
        });
      }
    &lt;/script&gt;</code></pre><h4 id="html-코드">HTML 코드</h4>
<pre><code>
              &lt;a class=&quot;loginFacebook&quot; href=&quot;javascript:kakaoLogin();&quot;
                &gt;&lt;i class=&quot;fab fa-facebook-square&quot;&gt;&lt;/i&gt; Facebook으로 로그인
              &lt;/a&gt;
              &lt;a class=&quot;loginFacebook&quot; href=&quot;javascript:kakaoLogout();&quot;
                &gt;&lt;i class=&quot;fab fa-facebook-square&quot;&gt;&lt;/i&gt; Facebook으로 로그아웃
              &lt;/a&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[react] 카카오 API로 로그인하기 - REST API, 액세스 토큰 전달하기]]></title>
            <link>https://velog.io/@och_changhoon/react-%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%98%EA%B8%B0-REST-API-%EC%95%A1%EC%84%B8%EC%8A%A4-%ED%86%A0%ED%81%B0-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@och_changhoon/react-%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%98%EA%B8%B0-REST-API-%EC%95%A1%EC%84%B8%EC%8A%A4-%ED%86%A0%ED%81%B0-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 14 Aug 2022 09:15:22 GMT</pubDate>
            <description><![CDATA[<h3 id="prologue">Prologue</h3>
<p>소셜 로그인이라는 것을 한번 도전해보고 싶어 먼지쌓인 카카오 비즈니스 계정을 꺼냈...지만 정작 필요한건 카카오 디벨로퍼 계정이었다. 살짝 머쓱
하지만 당황하지 안코? 등록을 한 후 API 문서를 살펴보는데...
역시나 호락호락하게 API 사용법을 알려주진 않았다. 무조건 따라야하는 대충 사용하는 메서드의 정리 정도가 끝이었다...</p>
<p>마음 단단히 먹고 React로 새출발! 렛츠고!</p>
<h3 id="what">What?</h3>
<p>상기하였듯 카카오 API. 
대략적인 가이드 문서 : <a href="https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api">https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api</a></p>
<h3 id="how">How?</h3>
<p>카카오 로그인 버튼을 클릭했을 때, KAKAO_AUTH_URL로 이동하게 되고, 카카오 API를 통해 후미에 인가 코드가 붙은 채로 리다이렉트된다.
그 후 화면이 재 렌더되고, 인가 코드를 저장한 후 서버로 발송하는 로직을 통해 구현했다.</p>
<h4 id="사용된-hooks">사용된 hooks</h4>
<pre><code>const navigate = useNavigate();
const location = useLocation();
const params = new URLSearchParams(location.search);
const AUTH_CODE = params.get(&#39;code&#39;);
const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_REST_API_KEY}&amp;redirect_uri=${process.env.REACT_APP_REDIRECT_URI}&amp;response_type=code`;

 useEffect(() =&gt; {
    fetch(`https://kauth.kakao.com/oauth/token`, {
      method: &#39;POST&#39;,
      headers: { &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39; },
      body: `grant_type=authorization_code&amp;client_id=${process.env.REACT_APP_REST_API_KEY}&amp;redirect_uri=${process.env.REACT_APP_REDIRECT_URI}&amp;code=${AUTH_CODE}`,
    })
      .then(res =&gt; res.json())
      .then(data =&gt; {
        if (data.access_token) {
          console.log(data.access_token);
          fetch(&#39;http://10.58.4.207:8000/users/login&#39;, {
            method: &#39;GET&#39;,
            headers: {
              Authorization: data.access_token,
            },
          })
            .then(response =&gt; response.json())
            .then(result =&gt; {
              if (result.access_token) {
                localStorage.setItem(&#39;token&#39;, result.access_token);
                alert(&#39;WELCOME&#39;);
                navigate(&#39;/&#39;);
              } else {
                alert(&#39;NONONO&#39;);
                navigate(&#39;/users/login&#39;);
              }
            });
        }
      });
  }, []);</code></pre><h4 id="html-코드">HTML 코드</h4>
<pre><code>&lt;SignInContainer&gt;
  &lt;RightTop&gt;
    &lt;Logo&gt;
      &lt;img src=&quot;/images/logo.png&quot; alt=&quot;logo&quot; /&gt;
    &lt;/Logo&gt;
    &lt;Login onSubmit={goToMain}&gt;
      &lt;Input
             name=&quot;userId&quot;
             onChange={handleInput}
             type=&quot;text&quot;
             placeholder=&quot;이메일&quot;
             /&gt;
      &lt;Input
             name=&quot;userPw&quot;
             onChange={handleInput}
             type=&quot;password&quot;
             placeholder=&quot;비밀번호&quot;
             /&gt;
      &lt;LoginButton type=&quot;submit&quot; disabled={!isInputValid}&gt;
        로그인
      &lt;/LoginButton&gt;
    &lt;/Login&gt;
  &lt;/RightTop&gt;
  &lt;SignUp&gt;
    &lt;LoginKakao href={KAKAO_AUTH_URL}&gt;
      &lt;img src=&quot;/images/kakao_login_medium_narrow.png&quot; alt=&quot;loginKakao&quot; /&gt;
    &lt;/LoginKakao&gt;
  &lt;/SignUp&gt;
&lt;/SignInContainer&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[react] 카카오 API를 통해 로그인 구현하기! (with React)]]></title>
            <link>https://velog.io/@och_changhoon/react-%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A5%BC-%ED%86%B5%ED%95%B4-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-with-React</link>
            <guid>https://velog.io/@och_changhoon/react-%EC%B9%B4%EC%B9%B4%EC%98%A4-API%EB%A5%BC-%ED%86%B5%ED%95%B4-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-with-React</guid>
            <pubDate>Sun, 07 Aug 2022 14:42:30 GMT</pubDate>
            <description><![CDATA[<h3 id="prologue">Prologue</h3>
<p>소셜 로그인이라는 것을 한번 도전해보고 싶어 먼지쌓인 카카오 비즈니스 계정을 꺼냈...지만 정작 필요한건 카카오 디벨로퍼 계정이었다. 살짝 머쓱
하지만 당황하지 안코? 등록을 한 후 API 문서를 살펴보는데...
역시나 호락호락하게 API 사용법을 알려주진 않았다. 무조건 따라야하는 대충 사용하는 메서드의 정리 정도가 끝이었다...</p>
<p>마음 단단히 먹고 React로 새출발! 렛츠고!</p>
<h3 id="what">What?</h3>
<p>상기하였듯 카카오 API. 
대략적인 가이드 문서 : 
<a href="https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api">https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api</a></p>
<h3 id="how">How?</h3>
<p>카카오 로그인 버튼을 클릭했을 때, KAKAO_AUTH_URL로 이동하게 되고, 카카오 API를 통해 후미에 인가 코드가 붙은 채로 리다이렉트된다.
그 후 화면이 재 렌더되고, 인가 코드를 저장한 후 서버로 발송하는 로직을 통해 구현했다.
해당 코드는 이후 백에서 따로 카카오 API와 통신하는 프로세스가 필요하다!</p>
<h4 id="사용된-scripts-코드">사용된 scripts 코드</h4>
<pre><code>const navigate = useNavigate();
const location = useLocation();
const params = new URLSearchParams(location.search);
const AUTH_CODE = params.get(&#39;code&#39;);
const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_REST_API_KEY}&amp;redirect_uri=${process.env.REACT_APP_REDIRECT_URI}&amp;response_type=code`;

useEffect(() =&gt; {
  if (AUTH_CODE) {
    fetch(`{SERVER_IP}/users/login`, {
      method: &#39;POST&#39;,
      headers: {
        Authorization: AUTH_CODE,
      },
    })
      .then(response =&gt; response.json())
      .then(result =&gt; {
        console.log(result);
        if (result.access_token) {
          localStorage.setItem(&#39;token&#39;, result.access_token);
          alert(&#39;WELCOME&#39;);
          navigate(&#39;/&#39;);
        } else {
          alert(&#39;NONONO&#39;);
          navigate(&#39;/users/login&#39;);
        }
      });
  }

  navigate(&#39;/users/login&#39;);
}, []);</code></pre><h4 id="html-코드">HTML 코드</h4>
<pre><code>&lt;SignInContainer&gt;
  &lt;RightTop&gt;
    &lt;Logo&gt;
      &lt;img src=&quot;/images/logo.png&quot; alt=&quot;logo&quot; /&gt;
    &lt;/Logo&gt;
    &lt;Login onSubmit={goToMain}&gt;
      &lt;Input
             name=&quot;userId&quot;
             onChange={handleInput}
             type=&quot;text&quot;
             placeholder=&quot;이메일&quot;
             /&gt;
      &lt;Input
             name=&quot;userPw&quot;
             onChange={handleInput}
             type=&quot;password&quot;
             placeholder=&quot;비밀번호&quot;
             /&gt;
      &lt;LoginButton type=&quot;submit&quot; disabled={!isInputValid}&gt;
        로그인
      &lt;/LoginButton&gt;
    &lt;/Login&gt;
  &lt;/RightTop&gt;
  &lt;SignUp&gt;
    &lt;LoginKakao href={KAKAO_AUTH_URL}&gt;
      &lt;img src=&quot;/images/kakao_login_medium_narrow.png&quot; alt=&quot;loginKakao&quot; /&gt;
    &lt;/LoginKakao&gt;
  &lt;/SignUp&gt;
&lt;/SignInContainer&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[react] 제한된 영역을 클릭했을 때 좌표값을 구하는 방법 (feat. useRef, offsetX, offsetY)]]></title>
            <link>https://velog.io/@och_changhoon/react-%EC%A0%9C%ED%95%9C%EB%90%9C-%EC%98%81%EC%97%AD%EC%9D%84-%ED%81%B4%EB%A6%AD%ED%96%88%EC%9D%84-%EB%95%8C-%EC%A2%8C%ED%91%9C%EA%B0%92%EC%9D%84-%EA%B5%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-feat.-useRef-offsetX-offsetY</link>
            <guid>https://velog.io/@och_changhoon/react-%EC%A0%9C%ED%95%9C%EB%90%9C-%EC%98%81%EC%97%AD%EC%9D%84-%ED%81%B4%EB%A6%AD%ED%96%88%EC%9D%84-%EB%95%8C-%EC%A2%8C%ED%91%9C%EA%B0%92%EC%9D%84-%EA%B5%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-feat.-useRef-offsetX-offsetY</guid>
            <pubDate>Sun, 07 Aug 2022 14:26:14 GMT</pubDate>
            <description><![CDATA[<h3 id="prologue">Prologue</h3>
<p>이미지를 업로드 하고 난 후, 클릭을 통해 해당 위치에 (+) 아이콘을 만들려고 했다. (마치 지도에서 핑을 찍듯!)
그러려면 일단 해당 사진에서 좌표를 구하는 일이 먼저라고 생각했기에, 좌표를 구하는 방법을 찾아봤다. 생각보다 금방 나오던데?</p>
<h3 id="what">What?</h3>
<p>우리가 사용할 것은 <code>useRef()</code>와 <code>offsetX</code>, <code>offsetY</code> 이다!
offsetX와 offsetY는 이벤트 대상 객체에서의 상대적 좌표값을 반환해주는 내장 객체이다.</p>
<p>이 값은 offset 뿐만이 아니라 client, page, screen 또한 존재하는데,
상세한 내용은 <a href="http://megaton111.cafe24.com/2016/11/29/clientx-offsetx-pagex-screenx%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90/">http://megaton111.cafe24.com/2016/11/29/clientx-offsetx-pagex-screenx%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90/</a> 를 참조하면 좋을 것 같다!</p>
<h3 id="how">How?</h3>
<p>간단하다. X좌표와 Y좌표를 저장할 객체 state와, 그 좌표쌍을 저장할 배열 state를 준비하면 된다.
그 후, onClick 이벤트가 일어날 대상에 useRef()를 심어주면 끝!</p>
<h4 id="사용된-hooks와-function들">사용된 hooks와 function들</h4>
<pre><code>const [onClickCoordinate, setOnClickCoordinate] = useState({
  coordinateX: &#39;&#39;,
  coordinateY: &#39;&#39;,
});
const [coordinatesList, setCoordinatesList] = useState([]);

const imageOverlay = e =&gt; {
  setOnClickCoordinate(prev =&gt; ({
    ...prev,
    coordinateX:
      ((e.nativeEvent.offsetX - 12) / photoOverlay.current.offsetWidth) * 100,
    coordinateY:
      ((e.nativeEvent.offsetY - 12) / photoOverlay.current.offsetHeight) *
      100,
  }));
};


console.log(coordinatesList)</code></pre><h4 id="html-코드">HTML 코드</h4>
<pre><code>&lt;img
  src={imageInfo.previewURL}
  alt=&quot;previewImage&quot;
  ref={imageOverlay}
  onClick={imageOverlayOnClick}
/&gt;</code></pre><p>위 코드는 이미지 태그 위에서 일어나는 onClick 이벤트에서 좌표값을 저장한 후 console.log() 를 찍는 코드이다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] div를 input태그로 만들기 (feat. useRef())]]></title>
            <link>https://velog.io/@och_changhoon/react-div%EB%A5%BC-input%ED%83%9C%EA%B7%B8%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat.-useRef</link>
            <guid>https://velog.io/@och_changhoon/react-div%EB%A5%BC-input%ED%83%9C%EA%B7%B8%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat.-useRef</guid>
            <pubDate>Sun, 07 Aug 2022 14:08:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/och_changhoon/post/071a48eb-7ff0-40aa-8fbb-f4f5b69ac812/image.png" alt=""></p>
<h2 id="prologue">Prologue</h2>
<p>파일 업로드 버튼을 만드는 도중에, 상단의 이미지와 같이 디자인을 넣고 싶었다.
하지만 input 태그는 저런 느낌으로 꾸며줄 수가 없었고...
여러가지 방법을 생각해냈지만 순수 자바스크립트 문법으로는 전부 실패해버렸다.
그러다 마지막에 떠오른게 이 친구였다.</p>
<h2 id="what">What?</h2>
<p>바로 <code>useRef()</code>! useRef를 통해 div가 브로커 행세를 할 수 있게 된다.</p>
<h2 id="how">How?</h2>
<p>해결법은 간단했다.</p>
<ol>
<li>이미지 업로드용 <code>&lt;input type=&quot;file&quot;&gt;</code>에 useRef()를 걸어주고 { display: none } 처리한다.</li>
<li>그 후 <code>&lt;ImageStandBy&gt;</code> 에서 onClick 이벤트가 발생할 때 useRef()를 통해 <code>&lt;input&gt;</code>이 실행되게 만든 후,</li>
<li><code>&lt;input type=&quot;file&quot;&gt;</code>의 onChange 이벤트에서 setter 함수를 실행하여 state를 변경할 수 있도록 해주면 된다!</li>
</ol>
<p>뭔 개소린지 모르겠다면 코드를 봐보도록 하자!</p>
<h4 id="사용한-hooks와-function들">사용한 hooks와 function들</h4>
<pre><code>const [imageInfo, setImageInfo] = useState({
   file: null,
   previewURL: &#39;&#39;,
 });
const photoInput = useRef();

const imageUploadOnClick = e =&gt; {
   e.preventDefault();
   photoInput.current.click();
 };

const imageInputOnChange = e =&gt; {
 setImageInfo({
   file: e.target.files[0],
   previewURL: URL.createObjectURL(e.target.files[0]),
 });
};</code></pre><h4 id="html-코드">HTML 코드</h4>
<pre><code>&lt;ImageUploadContainer&gt;                                // div
  {imageInfo.file === null ? (
    &lt;ImageStandBy onClick={imageUploadOnClick}&gt;        // div or button
      &lt;AiFillCamera /&gt;                                // react-icons 아이콘
      &lt;p&gt;사진 올리기&lt;/p&gt;
      &lt;p&gt;(* 최대 10장까지)&lt;/p&gt;
    &lt;/ImageStandBy&gt;
  ) : (
      &lt;img
        src={imageInfo.previewURL}
        alt=&quot;previewImage&quot;
        ref={imageOverlay}
        onClick={imageOverlayOnClick}
      /&gt;
  )}
  &lt;input
    type=&quot;file&quot;
    accept=&quot;image/jpg, image/jpeg, image/png&quot;
    multiple
    ref={photoInput}
    onChange={imageInputOnChange}
    style={{ display: &#39;none&#39; }}
  /&gt;
&lt;/ImageUploadContainer&gt;</code></pre><p>위 코드는
&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp<code>조건부 렌더링을 통해 ? (이미지 업로드 버튼을 출력하거나) : (업로드된 이미지를 보여주는)</code>
코드이다.
스타일드 컴포넌트를 이용했기에 태그가 보이지 않는 점은 양해 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS 란]]></title>
            <link>https://velog.io/@och_changhoon/AWS-%EB%9E%80</link>
            <guid>https://velog.io/@och_changhoon/AWS-%EB%9E%80</guid>
            <pubDate>Sun, 31 Jul 2022 14:32:24 GMT</pubDate>
            <description><![CDATA[<p>일단, AWS(Amazon Web Services)란 무엇일까?</p>
<h2 id="what">What</h2>
<p>아마존(Amazon)닷컴에서 개발한 <strong>클라우드 컴퓨팅 플랫폼</strong>으로, 네트워킹을 기반한 가상 컴퓨터와 스토리지, 네트워크 인프라 등 다양한 서비스를 제공하고 있다.
 현재 소규모 일반 소비자와 법인들을 아우르는  다양한 사용자들이 사용하고 있으며, 특히 <strong>클라우드 컴퓨팅</strong>의 장점을 이용하기 위해 많은 거대 기업에서도 활용하고 있다.
 그렇다면, 클라우드 컴퓨팅은 무엇일까?
 </p>
<hr>
<p><strong>- 클라우드 컴퓨팅(Cloud computing)</strong></p>
<p>기존의 서버가 물리적으로 구축되어있어야 했다면, 이제는 네트워크 기반 서비스 형태로 제공하는 것이다! 즉, 사용자로 하여금 네트워크 상에서 클라우드 서비스의 자원을 사용하는 것이다.</p>
<p>이는 크게 다음과 같이 3가지로 분류된다
 
<strong>▶ IaaS(Infrastructure as a Service)</strong>
 
AWS, 네이버플랫폼 과 같은 인프라스트럭쳐를 제공하는 서비스로, 가상 서버 또는 스토리지, 가상 네트워크 등의 리소스를 서비스 형태로 제공한다. 사용자는 물리적인 하드웨어를 직접 관리할 필요가 없으며, 직접적으로 서비스 이용을 통해 컴퓨터 리소스를 사용 할 수 있다.</p>
<p> - 클라우드 IT의 기본 구성 요소
&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp(네트워킹, 컴퓨터, 데이터 스토리지 공간)
 
 
<strong>▶ PaaS(Platform as a Service)</strong>
 
DB 또는 Application 서버 등의 이미 미들웨어를 제공한다. 하드웨어/OS/미들웨어 에 대한 관리는 서비스 제공자가 하며, 사용자는 제공된 미들웨어만 사용 할 수 있다. 주로 개발 환경과 관련한 서비스를 제공하며, 기본 인프라를 관리할 필요 없이 애플리케이션을 실행할 수 있게 해준다.
 
<strong>▶ SaaS(Software as a Service)</strong>
 
 
소프트웨어 또는 애플리케이션의 기능만 제공하는 서비스. 네이버클라우드, 웹 메일, ERP 등과 같은 형태의 서비스를 사용자에게 제공한다.</p>
<hr>
<p> </p>
<h2 id="why">Why</h2>
<p><strong>AWS 클라우드 컴퓨팅의 장점</strong></p>
<p>그렇다면, 기업들은 왜 클라우드 컴퓨팅을 사용하는 것일까?
 
<strong>1. 저렴한 비용</strong>
AWS는 계약금이나 약정이 불필요하며 저렴한 종량제 방식으로 운영된다.
확장형 글로벌 인프라를 구축 및 관리하고, 더 저렴한 요금의 형태로 사용자에게 비용 절감 혜택을 고스란히 돌려준다.
가변적으로 관리하여 시간대별로도 자원을 끌수있다는 장점이 있다.
 
<strong>2. 빠른 속도와 높은 자유도</strong>
몇분만에 전세계에 배포할 수 있는 수준인 AWS는 언어 및 운영 체제에 구애받지 않는 플랫폼이다. 따라서 사용자의 비즈니스에 가장 적합한 개발 플랫폼 또는 프로그래밍 모델을 선택할 수 있다. 사용할 서비스를 한 개 또는 여러 개 선택하고, 그 사용 방식도 선택할 수 있다.
 
<strong>3. 민첩성, 즉각적 융통성</strong>
서버를 증축하거나 추가하려면 몇 주 또는 몇 개월 동안 서버를 구축하길 기다려야 한다.
하지만 AWS는 그 즉시 새로운 앱을 배포할 수 있고, 수요를 기준으로 다운사이징할 수도 있다. 필요한 가상 서버가 한 대든 아니면 수천 대든, 가상 서버가 필요한 시간이 몇 시간이든 사용한 양만큼 비용이 청구된다. 즉 한 줄로 요약하면 설치가 빠르고 관리가 편하다는 것이다.
 
<strong>4. 용량 추정 과정 자체가 불필요</strong>하며 데이터 센터 운영 및 유지관리에 <strong>비용 투자 또한 불필요</strong>하기 때문이다.
 - 규모의 경제로 얻게되는 이점
 - 몇 분 만에 전 세계에 배포 가능 등</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 5. Cleanup Function]]></title>
            <link>https://velog.io/@och_changhoon/5-cleanUp-Function</link>
            <guid>https://velog.io/@och_changhoon/5-cleanUp-Function</guid>
            <pubDate>Sun, 31 Jul 2022 14:28:49 GMT</pubDate>
            <description><![CDATA[<h2 id="what">What</h2>
<p>useEffect 의 콜백 함수에서 side effect를 만들면 뒷정리가 필요한 경우가 종종 있었는데,
이럴 때 우리는 <strong>콜백 함수를 이용</strong>해 리턴 값으로 그 <strong>뒷정리를 하는 함수를 리턴</strong>할 수 있었다.</p>
<p>여기서 뒷정리를 위해 return한 함수를 우리는  <code>Cleanup Function</code>이라고 한다.</p>
<p>예로, 이미지 미리보기를 구현하려고 한다면,  Object URL을 만들어서 브라우저의 메모리를 할당(createObjectURL) 해야한다. 그 후엔 정리 함수를 통해 이때 할당한 메모리를 다시 해제(revokeObjectURL)해줘야 하는 것이다.</p>
<h2 id="why">Why</h2>
<p>쉽게 말해, <code>callback</code> 한번에 <code>Cleanup Function</code>도 한번. 이렇게 생각하면 편하다.</p>
<p>정확히는, </p>
<ol>
<li>callback 함수가 호출 되기 전에 실행되거나/</li>
<li>컴포넌트가 화면에서 사라질 때 그 직전에/
정리 함수가 실행된다.</li>
</ol>
<p>즉, 정리 함수가 실행되기 직전에 실행된 callback의 side effect를 정리하기 위해 실행되는 것이다.</p>
<p>그 예시는 다음과 같다:</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 4. sideEffect와 useEffect]]></title>
            <link>https://velog.io/@och_changhoon/React-4.-sideEffect%EC%99%80-useEffect</link>
            <guid>https://velog.io/@och_changhoon/React-4.-sideEffect%EC%99%80-useEffect</guid>
            <pubDate>Sun, 31 Jul 2022 14:28:03 GMT</pubDate>
            <description><![CDATA[<h2 id="what">What</h2>
<p><code>side effect</code>가 뭘까? 다들 잘 알듯이, <strong>부작용</strong>이라는 뜻이다.</p>
<p>현실에서와 프로그래밍에서의 부작용의 뜻이 약간 다른데, 프로그래밍에선 말 그대로 <strong>내가 의도치 않은 부수적인 작용이 일어나는 것</strong>을 말한다.</p>
<p>예를 들자면,</p>
<pre><code>let count = 0

function greetWithSideEffect(name) { // Input
  count = count + 1 // Side Effect!

  return `${name}님 안녕하세요!` // Output
}</code></pre><p><code>greetWithSideEffect()</code> 라는 함수는 이름을 받아 인삿말을 리턴하는 함수이다.</p>
<p>하지만 이 함수는 단순히 input과 output만 존재하는 함수가 아니다. 실행하는 중간에 함수 스코프 외부에 있는 count 변수의 값을 변경하는 프로세스가 섞여있다. 이는 함수의 결과값 이외의 다른 상태를 변경시키는 행위에 해당하므로 Side Effect 가 있다고 할 수 있는 것이다.</p>
<p>이러한 예시 말고도, 우리에게 아주 친숙한 예로 <code>console.log</code> 등이 있다!
<code>console.log</code> 함수를 사용하면 값을 계산해서 리턴하는 게 아니라 콘솔 창에 문자열을 출력하게 되는데, 이 자체가 외부 상태를 변경해서 문자열을 출력하는 것이다.</p>
<p>이렇게 <strong>함수 내부에서 함수 외부에 있는 값 또는 상태를 변경하는 행위</strong>를 &#39;<strong>side effect</strong>&#39;라고 한다.</p>
<h2 id="why">Why</h2>
<p>하지만 이 side effect가 단어 뜻 그대로 나쁘기만한 순수 쓰레기같은 친구인가 하면<del>~</del>
그건 또 아니다.</p>
<p>useEffect 는 리액트 컴포넌트 함수 안에서 이 side effect를 실행하고 싶을 때 사용하는 함수이기 때문이다.</p>
<p>DOM 노드를 직접 변경하기도 하며,
브라우저에 데이터를 저장할 수도 있고,
네트워크 통신 요청를 보내는 것처럼 말이다.</p>
<p>상기하였듯, 주로 리액트 외부에 있는 데이터나 상태를 변경할 때 사용하는데,
간단한 예시를 보면 이해에 좀 더 좋을 것 같다.</p>
<pre><code>페이지 내 데이터 변경
useEffect(() =&gt; {
  document.title = title;
}, [title]);


네트워크 요청
useEffect(() =&gt; {
  fetch(&#39;https://alpha.bravo/delta&#39;)
    .then((res) =&gt; res.json())
    .then((result) =&gt; setData(result));
}, [])


데이터 저장
useEffect(() =&gt; {
  localStorage.setItem(&#39;Echo&#39;, Echo);
}, [Echo]);


타이머
useEffect(() =&gt; {
  const tikTok = setInterval(() =&gt; {
    setSecond((prevSec) =&gt; prevSec + 1);
  }, 1000);

  return () =&gt; {
    clearInterval(tikTok);
  }
}, []);</code></pre><h2 id="how">How</h2>
<p>useEffect는 보통 &#39;<strong>동기화</strong>&#39;에 쓰면 유용한 경우가 많다. 여기서 동기화란, 컴포넌트 내부의 데이터와 그 외부에 있는 데이터를 일치시키는 것을 의미한다.</p>
<p>이게 뭔 개소리요 싶으실텐데, 어떤 의미인지 이번에도 간단한 예시를 가져왔다.</p>
<pre><code>import { useEffect, useState } from &#39;react&#39;;

const TITLE = &#39;Untitled&#39;;

export default function ChangeTitle() {
  const [title, setTitle] = useState(Title);

  const titleChangeHandler = (e) =&gt; {
    const inputText = e.target.value;
    setTitle(inputText);
  };

  const titleClearHandler = () =&gt; {
    setTitle(TITLE);
  };

  useEffect(() =&gt; {
    document.title = title;
  }, [title]);

  return (
    &lt;div&gt;
      &lt;input value={title} onChange={titleChangeHandler} /&gt;
      &lt;button onClick={titleClearHandler}&gt;RESET&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>상단의 <code>ChangeTitle</code>컴포넌트는 입력 값에 따라 페이지 타이틀을 바꾸는 컴포넌트이다.</p>
<p>만약 이 코드를 핸들러 함수만 사용해서 처리를 하려 했다면, 핸들러마다</p>
<pre><code>document.title = inputText or TITLE;</code></pre><p>을 포함하는 코드가 있었어야 할 것이다.</p>
<p>하지만 우리는 useEffect를 사용함으로써 document.title이라는 side effect를 다루는 부분만 따로 처리할 수 있었고, 
document.title 을 변경하는 코드를 신경 쓰지 않고 사용할 수 있어 편리해 질 수 있겠다!</p>
<p>즉, useEffect 를 사용했을 때 반복되는 코드를 줄이고, 동작을 쉽게 예측할 수 있는 코드를 작성할 수 있게 되는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 3. 참조형 데이터를 state로 사용하고 싶을 때]]></title>
            <link>https://velog.io/@och_changhoon/React-3-%EC%B0%B8%EC%A1%B0%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-state%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B3%A0-%EC%8B%B6%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@och_changhoon/React-3-%EC%B0%B8%EC%A1%B0%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-state%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B3%A0-%EC%8B%B6%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Sun, 24 Jul 2022 14:59:08 GMT</pubDate>
            <description><![CDATA[<pre><code>본 내용은 이전의 React - State의 기초 와 이어집니다</code></pre><p>자바스크립트의 자료형은 크게 기본형(Primitive type)과 참조형(Reference type)이 있다는 건 모두가 알고 있을 것이다.</p>
<p>기본형은 별거 없는데 문제는 바로 참조형.
참조형 값들은 그 특성들이 좀 독특해서 변수로 다룰 때도 조금 주의해 주어야 하는데, 이것은 state를 활용할 때도 마찬가지이다.</p>
<p>아래 코드는, 로그인 히스토리에 로그를 추가하려는 한 참조형알못의 코드이다.</p>
<hr>
<pre><code>  const [loginHistory, setLoginHistory] = useState([]);

  const historyHandler = () =&gt; {
    loginHistory.push(log);
    setLoginHistory(loginHistory);
  };
  // 실행 안됨 ㅎ</code></pre><hr>
<p>위 코드처럼, 배열 값을 가진 <code>loginHistory</code> state에 <code>push()</code>를 통해 배열의 값을 변경한 다음, 변경된 배열을 <code>setLoginHistory</code> setter 함수로 state를 변경하려고 하면 코드가 제대로 동작하지 않는다.</p>
<p>왜일까?</p>
<p><code>LoginHistory</code> state는 배열 값 자체를 가지고 있는 게 아니라,
<strong>그 배열의 주솟값을 참조하고 있기 때문</strong>이다.
그렇기 때문에 <code>push()</code>로 백날 배열 안에 요소를 바꿔준다고 하더라도 결과적으로 참조하는 배열의 주솟값은 변경된 것이 아니게 된다는 것이다.</p>
<p>결과적으로 react 입장에서는, <code>loginHistory</code> State가 참조하는 주솟값은 응당 똑같기 때문에, State가 바뀌었다고 판단하지 않는 것이다!</p>
<p>결론은, 참조형인 state를 사용할 때에는 반드시 새로운 참조형 값을 만들어 state를 변경해야 한다.</p>
<p>그 중 가장 간단한 방법은 Spread 문법(...) 을 활용하는 것이다. 어떻게? 아래처럼!</p>
<hr>
<pre><code>  const [loginHistory, setLoginHistory] = useState([]);

  const historyHandler = () =&gt; {
    setGameHistory([...gameHistory, nextNum]);
  };
  // 실행 잘됨!</code></pre><hr>
<p>이 참조형 state의 특성을 이해하지 못하면, 간혹 state가 제대로 변경되지 않는 버그가 발생했을 때 원인을 제대로 찾지 못하는 경우가 발생할 수도 있다.</p>
<p>참조형 state를 활용할 땐 반드시 <strong>새로운 참조형 값을 만들어서 state를 변경해야 한다는 점</strong>. 꼭 기억해 두길 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 2. State의 기초]]></title>
            <link>https://velog.io/@och_changhoon/React-State</link>
            <guid>https://velog.io/@och_changhoon/React-State</guid>
            <pubDate>Sun, 24 Jul 2022 14:42:16 GMT</pubDate>
            <description><![CDATA[<p>react를 공부해보셨다면, state는 진짜 한평생 쓴다고 봐도 무방하다는 말에 동의하실 것이다.
그러면 이제 react의 핵심, State가 무엇인가에 대해 한번 끄적여 보겠다.</p>
<h2 id="what">What</h2>
<p>그렇다면 State란 뭘까? State를 네이버 사전에서 찾아보았다.
<img src="https://velog.velcdn.com/images/och_changhoon/post/e8cb9850-0092-40b0-abf2-ca6bf6cf3e7a/image.png" alt="">
그렇다. State는 상태였다. 누가 모를까.
중요한건, react에서의 state도 그 의미가 크게 다르지 않다는 점인데,
이 &quot;상태&quot;가 바뀔 때마다 <strong>화면을 새롭게 그려내는 방식</strong>으로 동작을 한다는 것을 알면 좋을 것이다.</p>
<h2 id="when">When</h2>
<p>값이 동적으로 변화하고 그 변화에 맞게 새롭게 렌더링이 되어야 할 때 사용된다.
즉, 위에서 이야기했듯, 동적으로 데이터를 관리하고 화면을 그려내야할 때 사용된다는 것이다.</p>
<h2 id="how-to-use-usestate">How to use useState()</h2>
<p>일단,
<strong>&quot;상태&quot;를 만들어야 하고</strong>, (State)
<strong>상황에 맞게 &quot;상태&quot;를 바꿔줄 수 있어야</strong> 하겠죠? (Setter)
결론은 간단하다. useState라는 함수를 활용하면 된다.
이 함수를 통해, State를 선언하고, State값을 Set 해주는 Setter를 만들 수 있다.</p>
<hr>
<pre><code>import { useState } from &#39;react&#39;;

  const [num, setNum] = useState(1);</code></pre><hr>
<p>아주 간단하죠?</p>
<p>위 코드에 사용된 문법은 Destructuring 문법이라는 것인데, 궁금하다면 한번 찾아보고 오는 것을 추천한다. </p>
<p>말로 풀자면, <code>num</code>이라는 State와, <code>setNum</code>이라는 Setter 함수를 선언하고,
1이라는 초깃값을 <code>num</code>에 할당한 것인데~</p>
<p>이렇게 사용하는 이유는,
<code>useState</code> 함수가 초깃값을 인자로 받고, 그에 따른 return 값으로 2개의 요소를 포함한 배열을 뱉기 때문이다.</p>
<p>이때 뱉는 첫 번째 요소가 <code>State</code>, 두 번째 요소가 이 state를 바꾸는 <code>Setter</code> 함수인 것이다.</p>
<p>그렇다면 각각 요소들의 네이밍은 어떻게 할까? 간단하다.
변하는 값의 특성에 맞게 <code>State</code>의 이름(여기선 num)을 붙이고,
<code>Setter</code> 함수는 state 이름 앞에 set을 붙인 다음 카멜 케이스로 사용하는 것(여기선 setNum)이다.</p>
<p>State는 변수에 새로운 값을 할당하는 방식으로 변경하는 것이 아니라, 이 Setter 함수를 활용해야 한다. 꼭! Setter 함수를 통해 argument 값을 전달하여 state 값을 변경해 주자.</p>
<h2 id="how-to-use-setter">How to use Setter()</h2>
<p>그럼 이렇게 강조하는 Setter는 어떻게 사용하는 것일까?
그래서 코드를 준비했다!</p>
<hr>
<pre><code>import { useState } from &#39;react&#39;;
import Button from &#39;./Button&#39;;
import Dice from &#39;./Dice&#39;;

function App() {
  const [num, setNum] = useState(1);

  const diceRollHandler = () =&gt; {
    setNum(3); 
  };

  const diceClearHandler = () =&gt; {
    setNum(1);
  };

  return (
    &lt;div&gt;
      &lt;Button onClick={diceRollHandler}&gt;던지기&lt;/Button&gt;
      &lt;Button onClick={diceClearHandler}&gt;초기화&lt;/Button&gt;
      &lt;Dice num={num} /&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre><hr>
<p>이벤트 핸들러에 Setter 함수를 세팅해 둔 후, Button의 onClick이라는 이벤트가 발생할 때마다 State의 값이 변하면서 화면이 새로 그려지는 것이다!</p>
<p>...</p>
<p>이제 대략적인 State에 대한 설명이 끝났다. 잘 이해가 되는 글인가? 라고 스스로에게 물었을 때,
그렇지만은 않다. 라고 대답할 수 있을 것 같다.
다음번엔 state를 참조형으로 사용할 때 유의해야할 점에 대하여 다뤄보겠다.</p>
<p>총총.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 02-05]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-02-05</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-02-05</guid>
            <pubDate>Sun, 24 Jul 2022 13:27:02 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><img src="https://velog.velcdn.com/images/och_changhoon/post/3aa5c609-74ae-4b29-bf04-c79d392793d5/image.png" alt="">
인자인 height는 숫자로 이루어진 배열입니다.
그래프로 생각한다면 y축의 값이고, 높이 값을 갖고 있습니다.
상단 이미지는 배열 [1, 8, 6, 2, 5, 4, 8, 3, 7]을 받았을 때를 상정한 그래프 입니다.
저 그래프에 물을 담는다고 생각하고, 물을 담을 수 있는 가장 넓은 면적의 값을 반환해주세요.</p>
</blockquote>
<pre><code>function getMaxArea(height) {
  result = 0

  copyHeight = height
  let compObj = {};

  for (var i = 0; i &lt; height.length; i++) {
    compObj[i] = copyHeight[i];
  }

  let compVals = Object.values(compObj)

  for (var i = compVals.length; i &gt;= 0; i--) {
    for (var j = compVals.length - 1; j &gt;= 0; j--) {
      width = i - j
      height = compVals[i] &gt;= compVals[j] ? compVals[j] : compVals[i]
      if (width &gt; 0 &amp;&amp; width * height &gt; result) {
        result = width * height
      }
    }
  }
  return result
}</code></pre><p>머리가 안좋아서 매우 멍청하게 객체로 만들어서 풀었다.
배열만으로도 결과 도출이 가능했을 것 같은데, 풀은 내가 봐도 왜 이렇게 풀었는지 이해가 안될 지경이다.
아마 이전에 작성한 코드를 재활용하고 싶었던 것이리라.</p>
<p>일단, height의 값을 객체의 key와 value로 저장한 후,
values의 길이를 구한다. 그리고 반복문으로 전체탐색을 하는데,
돌때마다 가로길이와 세로길이의 최댓값을 찾아내 부피의 최대값을 갱신해준다.</p>
<p>솔직히 이건 개못짰네 ㄹㅇㅋㅋ
인정합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 02-04]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-02-04</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-02-04</guid>
            <pubDate>Sun, 17 Jul 2022 15:00:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>숫자 배열을 인자로 받았을 때, 가장 자주 등장한 숫자를 k 개수만큼 return해주세요.</p>
</blockquote>
<pre><code>nums = [1,1,1,2,2,3], k = 2 일 때
return: [1,2]
nums = [1], k = 1 일 때
return: [1]</code></pre><pre><code>function FrequentIntCount(nums, k) {
                                              // console.log(nums)
  let incomeObj = new Set(nums)                // console.log(incomeObj)
  let incomeArray = Array.from(incomeObj)    // console.log(incomeArray)
  let compObj = {}

  // compObj 초기값 형성
  incomeObj.forEach((num) =&gt; {
    compObj[num] = 0;
  });                                        // console.log(compObj)

  // compObj value 변경
  let numsLen = nums.length
  for (var i = 0; i &lt; numsLen; i++) {
    compObj[nums.shift()] += 1;
  }                                            // console.log(compObj)

  // 해시테이블화
  compArr = Object.values(compObj)
  let alpha = new Array(compArr.length + 1);
  for (var i = 0; i &lt; compArr.length; i++) {
    alpha[compArr[i]] = incomeArray[i]
  }                                            // console.log(alpha)

  let result = []
  for (var i = 0; i &lt; k; i++) {
    result.push(alpha.pop())                // console.log(result)
  }
  return result;
}</code></pre><p>이걸 찾아볼 사람은 매우 특정적이기에 이야기하자면, Week 02 - 02번 문제와 로직이 흡사하다.
하지만, 로직 자체는 여전히 단순하기에, 코드가 매우 길다.. 로직은 다음과 같다.</p>
<blockquote>
<p>인자로 받은 숫자들의 배열인 nums의 중복제거한 인자들을 key값으로,
nums 속 해당 인자들의 갯수를 value값으로 객체를 선언한 후
해당 값들을 해시테이블 화 하여 정렬하고 출력하는 코드이다.</p>
</blockquote>
<ol>
<li>먼저 <code>let incomeObj = new Set(nums)</code>을 통해 중복제거한 nums 배열을 incomeObj에 복사하는데, 여기서 set 함수는 객체를 반환하므로 <code>let incomeArray = Array.from(incomeObj)</code>를 통해 배열로 변환해준다.</li>
</ol>
<ol start="2">
<li><p>그 후 비교용 객체 <code>compObj</code>를 선언하여 상기하였듯 key와 value 쌍을 추가해주는 과정.
초기값 형성과 value 변경이 여기에 속한다.</p>
</li>
<li><p>그 다음은 해시테이블화인데, 이 부분은 스스로 직접 이해해 보는 편이 좋을 것 같다.</p>
<p>힌트를 주자면, key값을 alpha배열의 index로, 해당하는 index의 값을 value로 사용하여
2차원으로써 그려져야 할 데이터쌍을 1차원으로 구현한 것이다. 해시테이블 변수 명은 alpha.
당연히 key값을 index로 사용해야 하기 때문에, 배열의 길이가 1 더 늘어난다는 점 참고해주면 좋겠다.</p>
</li>
</ol>
<ol start="4">
<li>그 후, 역순으로 정렬된 해시테이블을 뒤에서부터 팝!하여 k개만큼 출력해주면 문제는 끝!</li>
</ol>
<hr>
<p>여기서 해시테이블이 무엇이고 왜 사용하는가에 대해 궁금한 사람들은 아래 유튜브를 시청하고 오면 좋다!
<a href="https://www.youtube.com/watch?v=xls6jEZNA7Y">https://www.youtube.com/watch?v=xls6jEZNA7Y</a>
광고아니에요 저 아닙니다 그냥그렇다고요</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 02-01]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-02-01</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-02-01</guid>
            <pubDate>Sun, 17 Jul 2022 14:58:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>1~3999 사이의 로마자를 의미하는 문자열을 받았을 때, 그에 해당하는 숫자를 반환해주세요. 로마 숫자를 숫자로 표기하면 다음과 같습니다.
I: 1,
V: 5,
X: 10,
L: 50,
C: 100,
D: 500,
M: 1000
유의할 점은 4를 표현할 때는 IIII가 아니라 IV, 9를 표현할 때는 VIIII가 아니라 IX 입니다. 뒤의 숫자에서 앞의 숫자를 빼주면 쉽게 구현할 수 있습니다.</p>
<pre><code>const romeToInt = strs =&gt; {
  const romeNum = {
    &#39;I&#39;: 1,
    &#39;V&#39;: 5,
    &#39;X&#39;: 10,
    &#39;L&#39;: 50,
    &#39;C&#39;: 100,
    &#39;D&#39;: 500,
    &#39;M&#39;: 1000
  }
  let result = 0
  const romeArrStr = strs.split(&quot;&quot;)
  const romeArrInt = []

  for(i in romeArrStr){
    romeArrInt.push(romeNum[romeArrStr[i]])
  }

  for(let i=0; i&lt;romeArrInt.length; i++){
    if(romeArrInt[i+1] &gt; romeArrInt[i]){
      result -= romeArrInt[i]
    } else {
      result += romeArrInt[i]
    }
  }
  return result
}</code></pre><p>생각 외로 단순했던 문제였던 것 같다.</p>
<p>로마자를 key값으로, 아라비아 숫자를 value값으로 가지는 객체를 선언한다.
그 후 인자로 받은 strs를 쪼갈라 배열로써 저장하고, 각 글자마다 해당하는 데이터쌍으로 변환을 해준다.</p>
<p>그 후 for문을 돌려 찢어진 숫자들을 한데 모으는 작업을 하게 되는데, 이 때 문제에 명시된 개꿀팁인 <strong>뒤의 숫자에서 앞의 숫자를 빼주면 쉽게 구현할 수 있다</strong>는 특성을 이용해 자신 바로 뒤에 있는 수가 자신보다 크다면 스스로를 결과값에서 제하는 로직을 구현했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 1. Props & Children]]></title>
            <link>https://velog.io/@och_changhoon/React-Props-Children</link>
            <guid>https://velog.io/@och_changhoon/React-Props-Children</guid>
            <pubDate>Sun, 17 Jul 2022 14:40:33 GMT</pubDate>
            <description><![CDATA[<h1 id="props-properties">Props (Properties)</h1>
<p>JSX 문법에서는, 컴포넌트를 호출할 때 <strong>해당 컴포넌트에서 사용할 속성값을 넣어서 보내줄 수 있는데</strong>, 그렇게 컴포넌트에 넣어준 속성들을 <strong>Props</strong>라고 부른다.</p>
<p>컴포넌트에 넣어준 속성들은 하나의 객체로 묶여서 컴포넌트를 정의한 함수의 파라미터 값으로 전달된다.</p>
<h4 id="parentjs">Parent.js</h4>
<pre><code>import React, { useState } from &#39;react&#39;;
import Child from &#39;../pages/Child/Child&#39;;

function Parent() {
  const [color, setColor] = useState(&#39;red&#39;);

  return (
    &lt;div&gt;
      &lt;h1&gt;Parent Component&lt;/h1&gt;
      &lt;Child titleColor={color} /&gt;
    &lt;/div&gt;
  );

export default Parent;</code></pre><hr>
<h4 id="childjs">Child.js</h4>
<pre><code>import React from &#39;react&#39;;

function Child(props) {
  // console.log(props);

  return (
    &lt;div&gt;
      &lt;h1 style={{color : props.titleColor}}&gt;Child Component&lt;/h1&gt;
    &lt;/div&gt;
  );
}

export default Child;</code></pre><p>위 예시 코드처럼, Parent 함수에서 Child 컴포넌트를 호출함과 동시에 titleColor라는 속성을 red로 지정해주고, Child 함수 내부에서 props라는 파라미터를 하나 만들어 출력해보면 브라우저 콘솔에는 다음과 같은 객체 형태의 값을 볼 수 있다.</p>
<pre><code>{ titleColor: &quot;red&quot; }</code></pre><p>즉, props를 활용하면 <strong>사용할 속성 값들을 다양하게 전달해주면서 컴포넌트를 활용할 수 있는데</strong>, 똑같은 컴포넌트라도 전달된 속성값에 따라 서로 다른 모습을 그려낼 수도 있게 된다는 뜻이다!</p>
<p>참고로, props는 객체 형태를 띠고 있어 Child.js에서 호출할 땐 props.[키 이름] 등으로 호출하여야 한다. 상단의 Child.js에서는 props.titleColor가 그 예시가 되겠다.</p>
<p>이 때에는 <strong>Destructuring 문법</strong>을 활용해서 조금 더 간결하게 코드를 작성할 수도 있는데, Destructing 문법에 대해서는 한번 찾아보는 것도 추천한다.</p>
<h1 id="children">Children</h1>
<p>props에는 <strong>children</strong>이라는 조금 특별한 props가 있다.</p>
<p>JSX 문법으로 컴포넌트를 작성할 때 컴포넌트를 단일 태그가 아니라 여는 태그와 닫는 태그의 형태로 작성하면, 그 안에 작성된 코드가 바로 이 children 값에 담기게 됩니다.</p>
<h4 id="buttonjs">Button.js</h4>
<pre><code>function Button({ children }) {
  return &lt;button&gt;{children}&lt;/button&gt;;
}

export default Button;</code></pre><hr>
<h4 id="appjs">App.js</h4>
<pre><code>import Button from &#39;./Button&#39;;
import Dice from &#39;./Dice&#39;;

function App() {
  return (
    &lt;div&gt;
      &lt;div&gt;
        &lt;Button&gt;던지기&lt;/Button&gt;
        &lt;Button&gt;처음부터&lt;/Button&gt;
      &lt;/div&gt;
      &lt;Dice color=&quot;red&quot; num={2} /&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre><p>그래서 JSX 문법으로 컴포넌트를 작성할 때
어떤 정보를 전달할 때는 일반적인 props의 속성값을 주로 활용하고,
화면에 보여질 모습을 조금 더 직관적인 코드로 작성하고자 할 때 children 값을 활용할 수가 있다.</p>
<p>참고로 이 children은 단순히 텍스트만 작성하는 걸 넘어서 컴포넌트 안에 컴포넌트를 작성할 수도 있고, 컴포넌트 안에 복잡한 태그들을 더 작성할 수도 있다고 하니 이 값을 어떻게 활용하면 좋을지 우리 다같이 한번 생각해 보는 것도 좋을 것 같다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 01-05]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-01-05</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-01-05</guid>
            <pubDate>Sun, 10 Jul 2022 14:55:04 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>단어가 담긴 strs 배열을 받았을 때, 공통된 시작 단어(prefix)를 반환해주세요.
strs = [&#39;start&#39;, &#39;stair&#39;, &#39;step&#39;]일 때, return: &#39;st&#39;
strs = [&#39;start&#39;, &#39;wework&#39;, &#39;today&#39;]일 때, return: &#39;&#39;</p>
</blockquote>
<pre><code>const getPrefix = strs =&gt; {
  let result = &quot;&quot;

  for (var i = 0; i &lt; strs.length; i++) {
    let count = 0
    let comp = strs[0].charAt(i)
    for (var j = 0; j &lt; strs.length; j++) {
      if (comp == strs[j].charAt(i)) {
        count++
      }
    }
    if (count == strs.length) {
      result = result + comp
    } else {
      return result
    }
  }
  return result
}</code></pre><p>이번에도 코드를 최적화하지 못하고 생각 그대로의 날것이 만들어져버렸다.
최적화, 재능없을지도..?</p>
<p>간단한 로직:</p>
<blockquote>
<p>항상 똑같지만, 나의 국밥 해결방법인 전체 탐색 되시겠다.
우리가 할 것은 배열에 담긴 값 하나하나씩 글자단위로 비교하여
상황에 따라 결과값에 append하여 출력할 예정이다.
오디션 프로그램에서 심사위원들의 따봉을 받으면 통과하는 것 처럼,
그 과정에서 전체 배열의 갯수만큼 따봉을 받으면 합격! 결과값에 추가된다.
단, 조건은 만장일치의 따봉을 받아야 한다는 것.</p>
</blockquote>
<p>코드 해석:</p>
<blockquote>
<p>결과값이 되어 줄 result를 선언함과 동시에 초기화. for문으로 쑝.
심사위원들의 따봉 갯수를 선언한다. 변수명은 count.
오와 열은 항상 해당 열 첫번째 훈련병이 담당한다. strs[0]의 i번째 글자를 comp(are할) 값으로 가져온다.
다시 for문 입성. strs배열 속 모든 요소들의 i번째 글자가 comp와 동일한지 검사한다, 동일하다면 따봉의 갯수를 ++.
군장검사가 끝났다면, 이제 따봉의 갯수를 비교할 차례다.
따봉의 갯수가 머릿수와 같다면, 해당 글자를 result에 추가하고
그렇지 못하다면 그대로 game over 시켜준다.</p>
</blockquote>
<p>생각의 흐름을 따라 코드를 작성하긴 했지만, 잘 작동하면 그걸로 만사오케이가 아닐까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 01-03, 04]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-01-03</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-01-03</guid>
            <pubDate>Sun, 10 Jul 2022 14:36:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>숫자배열과 목표 정수값을 인자로 받았을 때, 배열 속 중복되지 않은 두 정수를 더해 &#39;목표 정수값&#39;이 나오게 하는 배열의 index를 return해 주세요.
예를 들어,
nums: [4, 9, 11, 14], target: 13 일 때
return값은 [0, 1]이 되어야 합니다.
String 값을 인자로 받았을 때, 중복되지 않은 알파벳으로 이루어진 제일 긴 단어의 길이를 반환해주세요.
str = &quot;abcabcabc&quot;일 때, return: 3 =&gt;   // &#39;abc&#39;
str = &quot;aaaaa&quot;일 때, return: 1 =&gt;       // &#39;a&#39;
str = &quot;sttrg&quot;일 때, return: 3 =&gt;       // &#39;trg&#39;</p>
<pre><code>const getLengthOfStr = str =&gt; {
  let maxCnt = 0
  let tempCnt = 0

  for (var j = 0; j &lt; str.length; j++) {
    let strArr = []
    for (i = j; i &lt; str.length; i++) {
      if (strArr.indexOf(str[i]) == -1) {
        strArr.push(str[i])
      } else {
        strArr = []
        strArr.push(str[i])
      }
      tempCnt = strArr.length
      if (maxCnt &lt; tempCnt) {
        maxCnt = tempCnt
      }
    }
  }
  return maxCnt
}</code></pre><p>오. 이 친구는 예외사항이 아주 많아 매우매우매우매우 귀찮았다.</p>
<p>maxCnt는 return할 최종 값이 저장될 변수, tempCnt는 maxCnt와 비교할 변수.
strArr는 str의 글자 하나하나를 분해해 넣어볼 그릇이다.</p>
<p>2중 for문 중, 내부 for문 먼저 알아보자.</p>
<pre><code>strArr에 str[i]가 없을 경우, str[i]를 삽입한다.
maxCnt와의 비교를 위해 strArr의 길이를 tempCnt에 저장한 후
if문을 통해 우위를 가리고 승자가 maxCnt가 된다.

strArr에 str[i]가 있을 경우, strArr를 초기화 한 후 str[i]를 삽입한다.
maxCnt와의 비교를 위해 strArr의 길이를 tempCnt에 저장한 후
if문을 통해 우위를 가리고 승자가 maxCnt가 된다.

str의 길이 만큼 반복한다.</code></pre><p>그 후, 내부 for문이 종료되고 외부 for문이 돌아가는데</p>
<pre><code>strArr를 초기화한 후, index를 한자리 뒤로 땡겨서 다시 탐색한다.
이후 내부 for문 실행.</code></pre><p>strArr를 내부for문 밖에서 초기화해주는 이유는,
내부 for문이 끝날 때, &#39;<strong>가장 긴, 중복되지 않은 문자열</strong>&#39;이 str의 최후열에 있을 경우 미처 초기화되지 못한 strArr를 위해서이다.
이 과정을 통해, 전체 탐색을 해줌으로써 길이가 &#39;<strong>가장 긴, 중복되지 않은 문자열</strong>&#39;이 문자열 어디에서부터 시작되든 찾아낼 수 있게 된다.
이 과정이 필요한 이유는 &#39;atbctefgth&#39;를 str로서 사용해보면 알게 된다.</p>
<hr>
<blockquote>
<p>정수값을 인자로 받았을 때, 해당 인자의 회문(palindrome) 여부를 boolean 값을 통해 반환해주세요.
num: 123일 때, return: false =&gt; 뒤집은 모양이 321 이기 때문
num: 1221일 때, return: true =&gt; 뒤집은 모양이 1221 이기 때문
num: -121일 때, return: false =&gt; 뒤집은 모양이 121- 이기 때문
num: 10일 때, return: false =&gt; 뒤집은 모양이 01 이기 때문</p>
</blockquote>
<pre><code>const sameReverse = num =&gt; {
  return num.toString() == num.toString().split(&quot;&quot;).reverse().join(&quot;&quot;)
}</code></pre><p>예전에 사용했던 꼼수 문법과 굉장히 유사하다.
솔직히 좀 날먹이었달까(쑻)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Code Kata] Week 01-01, 02]]></title>
            <link>https://velog.io/@och_changhoon/Code-Kata-Week-1</link>
            <guid>https://velog.io/@och_changhoon/Code-Kata-Week-1</guid>
            <pubDate>Sun, 10 Jul 2022 14:11:14 GMT</pubDate>
            <description><![CDATA[<h3 id="week01---01">Week01 - 01</h3>
<blockquote>
<p>숫자배열과 목표 정수값을 인자로 받았을 때, 배열 속 중복되지 않은 두 정수를 더해 &#39;목표 정수값&#39;이 나오게 하는 배열의 index를 return해 주세요.
예를 들어,
nums: [4, 9, 11, 14], target: 13 일 때
return값은 [0, 1]이 되어야 합니다.</p>
</blockquote>
<pre><code>const twoSum = (nums, target) =&gt; {
  for (var i = 0; i &lt; nums.length; i++) {
    for (var j = i + 1; j &lt; nums.length; j++) {
        if (nums[i] + nums[j] == target) {
          return [i, j]
        }
    }
  }
}</code></pre><p>target 값이 도출될 때 까지 모든 정수를 하나하나씩 더해보면 답이 나오겠다 싶어서 
해당 문제는 전체 탐색을 하는 방향으로 이차원 배열로써 해결했다.
해결하지 못한 점은 조합이 2개 이상일 때를 대비하지 못한 것이다.</p>
<hr>
<h3 id="week01---02">Week01 - 02</h3>
<blockquote>
<p>정수를 인자로 받았을 때, 그 숫자를 뒤집어서 return해주세요.
음수의 경우, 해당 부호가 유지되어야 합니다.
x: 1234일 때, return: 4321
x: -1234일 때, return: -4321
x: 1230일 때, return: 321</p>
</blockquote>
<pre><code>const reverse = (x) =&gt; {
  let arr = x.toString().split(&quot;&quot;).reverse();
  if (arr.includes(&quot;-&quot;)) {
    arr.pop();
    arr.unshift(&quot;-&quot;);
  }
  return Number(arr.join(&quot;&quot;));
}</code></pre><p>해당 문제는 정공법이 아닌 꼼수를 통해 해결했다.
받은 인티저값을 int -&gt; string -&gt; array 순으로 쪼갈라서 뒤집은 후
다시 string으로 재조립하는 과정을 통해 해결했다.
수취한 값이 음수일 경우엔 pop()과 unshift() 메소드를 통해 부호를 맨 앞으로 이동시켜 주었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스에 대한 고찰(3) - KEY]]></title>
            <link>https://velog.io/@och_changhoon/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B03-KEY</link>
            <guid>https://velog.io/@och_changhoon/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B03-KEY</guid>
            <pubDate>Sun, 03 Jul 2022 14:48:56 GMT</pubDate>
            <description><![CDATA[<p>이번에는 KEY와 관련된 이야기를 풀어보고자 한다. 이해를 돕기 위해 인터넷에서 예시 이미지를 추가했는데, 도움이 되었으면 좋겠다.</p>
<h3 id="key의-종류">KEY의 종류</h3>
<ol>
<li>슈퍼 키 (Super Key)<ul>
<li>테이블에서 <strong>각 행을 유일하게 식별할 수 있는 하나 또는 그 이상의 속성들의 집합</strong>이다. 유일성만 만족하게 되면 누구나 슈퍼 키가 될 수 있는데, 여기서 유일성이란 하나의 키로 특정 행을 바로 찾아낼수 있는 데이터 속성을 말한다.
여러가지 속성 값들을 묶어 중복값이 안나오게 서로 구별만 할 수 있으면 누구나 슈퍼 키가 될 수 있다. 대표적인 예시로 주민등록번호가 있겠다.
<img src="https://velog.velcdn.com/images/och_changhoon/post/510b85ed-70a4-471d-910d-f7b69c2e6336/image.png" alt=""></li>
</ul>
</li>
</ol>
<pre><code>        어떻게 묶던 중복값만 나오지 않으면 상관없다!</code></pre><ol start="3">
<li><p>후보 키 (Candidate Key)</p>
<ul>
<li>한 테이블 내에서 각 튜플 값들을 유일하게 식별할 수 있게 하는 속성 값들 전체를 뜻한다. 즉, 기본 키가 될 수 있는 후보들인 셈이다. 이 중, 선택받은 자는 기본 키가 되고, 그렇지 못한 자들은 대체키가 되는데...
<img src="https://velog.velcdn.com/images/och_changhoon/post/90d61e80-4e08-4120-b4d1-9e616a92b9ad/image.png" alt=""><pre><code>  후보 키는 단일 속성으로 유일성과 최소성을 확보해야 하기 때문에,
  위의 이름+나이 조합으로는 후보키가 될 수 없다는 말이다.</code></pre></li>
</ul>
</li>
<li><p>기본 키 (Primary Key)</p>
<ul>
<li>한 테이블 내에서 각 튜플 값들을 유일하게 식별할 수 있게 하는 속성 값 중,</li>
<li><em>기준으로 선택한 키*</em>를 뜻한다. 당연히 한 테이블 아래 두개의 기본 키는 존재할 수 없다! 유일하게 식별할 수 있어야 한다는 특성에 의해 <strong>NULL 값을 가질 수 없고</strong>, 기본 키로 정의된 속성에는 <strong>중복이 허용되지 않는다</strong>는 특성이 있다.
대표적인 예시로 학번이 있겠다.
<img src="https://velog.velcdn.com/images/och_changhoon/post/07df77d3-da58-44eb-a868-8f24b9b76c2c/image.png" alt=""></li>
</ul>
</li>
</ol>
<blockquote>
<p>여기서 잠깐, 기본 키와 후보 키가 되기 위해서 만족해야 하는 조건이 있는데,
그것은 바로 <strong>유일성</strong>과 <strong>최소성</strong>이다.</p>
</blockquote>
<ul>
<li>유일성: 하나의 키값으로 하나의 튜플을 인식할 수 있어야 함</li>
<li>최소성: 특정 값을 유일하게 식별할 수 있는 필수적인 속성으로만 구성되어야 함</li>
</ul>
<ol start="4">
<li>대체 키 (Alternate Key)<ul>
<li>한 테이블 내에서 각 튜플 값들을 유일하게 식별할 수 있게 하는 속성 값 중,</li>
<li><em>기준으로 선택되지 못한 키*</em>를 뜻한다. 기본 키로 선택되지 못한 낙동강 오리알 신세이지만, 낙심하지 말자! 기본 키인 학번이 사라지면 주민번호가 기본 키 자리를 대체할 수 있게 된다.
<img src="https://velog.velcdn.com/images/och_changhoon/post/20df5706-75f4-4cb3-afc5-b3e4d8216d07/image.png" alt=""></li>
</ul>
</li>
</ol>
<ol start="5">
<li>외래 키 (Foreign Key)<ul>
<li>다른 테이블을 참조 및 연계하여 데이터를 처리해야 할 때 사용되는 키로,
외래키는 참조하는 테이블의 기본 키를 가르키는 동시에 해당 키의 속성을 가진다. 
<img src="https://velog.velcdn.com/images/och_changhoon/post/59efd4f9-152e-4463-a19b-0dc6fde6a754/image.png" alt=""></li>
</ul>
</li>
</ol>
<hr>
<p>RDBMS의 제약 조건도 다뤄보고 싶었지만, 시간 관계상 나중에 포스팅을 하든, 추후 수정을 하든 해야할 것 같다. 응애미안 ㅎ
핵심적으로 다루게 될 내용은 무결성 제약 조건인데, 그 중 개체 무결성과 참조 무결성에 대해 다뤄보겠다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스에 대한 고찰(2) - DB의 장/단점]]></title>
            <link>https://velog.io/@och_changhoon/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B02-DB%EC%9D%98-%EC%9E%A5%EB%8B%A8%EC%A0%90</link>
            <guid>https://velog.io/@och_changhoon/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B02-DB%EC%9D%98-%EC%9E%A5%EB%8B%A8%EC%A0%90</guid>
            <pubDate>Sun, 03 Jul 2022 13:48:53 GMT</pubDate>
            <description><![CDATA[<p>헬?루
거두절미하고 담백하게 장/단점에 대해 알아보자.
결단코 머릿글을 쓰는게 귀찮아서가 아니다.</p>
<h3 id="데이터베이스의-장점-및-단점">데이터베이스의 장점 및 단점</h3>
<pre><code>- 장점
    1. 파일 시스템과 달리 중복을 피할 수 있다.
    2. 데이터의 일관성 및 무결성을 보장 가능하다.
    3. 데이터의 논리적, 물리적 독립성이 보장된다.
    4. DB 안의 자료를 여럿이서 같이 사용할 수 있다.
    5. 자료 상태를 최신으로 관리하기 쉽다.
    6. 데이터의 표준화가 가능하다.</code></pre><ol>
<li>파일 시스템이란, 뭔가 대단한 단어가 아니다. 디스크 파티션을 관리하는 하나의 체계인데,</li>
</ol>
<p> <strong>응용프로그램 별로</strong> 필요한 데이터들을 파일로 관리할 수 있도록 하는 기능을 제공한다. 
 여기에서 핵심은 <strong>응용 프로그램 별로 파일을 유지</strong>한다는 점인데, 즉 같은 데이터가 여러 파일에 중복되어 저장될 수 있다는 것이다.
 하지만, DBMS는 DB에 데이터를 통합하여 관리하기 때문에 중복문제를 쉽게 해결할 수 있다.</p>
<ol start="2">
<li>앞서 이야기했듯, 중앙집중식으로 데이터를 통합하여 관리하기 때문에 데이터의 중복 제어가 보다 쉬워 일관성을 유지하기 편리하고, DB를 사용하여 명령을 처리할 때 마다 유효성을 검사하기 때문에 무결성 또한 쉽게 보장할 수 있다.</li>
</ol>
<ol start="6">
<li><p>데이터 표준화란 무엇일까. 
 &quot; 현실 세계의 정보를 컴퓨터로 관리하기 위해 DB에 저장하는 정보 항목의 종류, 명칭, 형식, 유효값, 관리절차 등을 특정 기준에 따라 표준을 만드는 일&quot; 을 뜻한다.
 우리는 데이터 표준화를 통해 다음과 같은 효과를 기대할 수 있겠다.</p>
<ul>
<li>데이터 중복성을 낮춰 지속적으로 증가하는 유지보수 비용을 절감하고</li>
<li>데이터 복잡도를 낮추며 중복된 데이터를 줄일 수도 있으며,</li>
<li>사용자에게 출력되는 UI와 데이터베이스 간에 서로 독립성을 유지할 수 있게 된다!</li>
</ul>
</li>
</ol>
<hr>
<p>하지만, 볕이 있으면 그늘도 있는 법. 상술한 장점을 위해 감수해야 할 단점들도 알아보자.</p>
<pre><code>- 단점
1. 자료의 전산화에 있어 인력과 비용이 발생한다.
2. 자료를 보호하기 위해 백업이 필수적이며, 훼손 시 복구가 어렵다.
3. 체계적으로 설계하지 못하면 매우 복잡해진다.</code></pre><ol>
<li><p>설명이 필요한가?
DB가 저장될 서버 및 네트워크 장비도 필요하지,
DBMS를 관리하는 DBA도 채용해야하지, 
서버 가동 후에 생기는 서비스 장애 대응이나 프로그램 수정과 확장 축소 등
초기비용뿐만 아니라 추후 들어가는 운영비용 또한 무시하지 못한다.</p>
</li>
<li><p>체계적인 관리는 가능하나, 만에하나 DB가 손상되거나 유실될 시 복구 작업이 매우 까다롭다.</p>
</li>
<li><p>초기에 DB설계를 제대로 하지 못하면 추후 사업의 확장성을 고려할 때 매우 골머리를 썩게 된다. 이것저것 살이 붙게 되면 매우 복잡하고 효율적이지 못한 DB로 변모하기 떄문.</p>
</li>
</ol>
<hr>
<p>기본적인 사항들에 대한 것은 대충 기술한 것 같다. 다음엔 뭘 쓸까?<img src="https://velog.velcdn.com/images/och_changhoon/post/c043c99f-dc58-42c7-a6ed-8b94996696ac/image.png" alt=""></p>
<p>몰?루~</p>
]]></description>
        </item>
    </channel>
</rss>