<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jiwon_choi.log</title>
        <link>https://velog.io/</link>
        <description>개발 공부합니다. 파이팅!</description>
        <lastBuildDate>Tue, 20 Sep 2022 13:26:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jiwon_choi.log</title>
            <url>https://images.velog.io/images/jiwon_choi/profile/ea877863-048b-411d-a464-1a7166e49c52/KakaoTalk_20220127_153005847.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jiwon_choi.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jiwon_choi" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[티스토리로 이사]]></title>
            <link>https://velog.io/@jiwon_choi/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC%EB%A1%9C-%EC%9D%B4%EC%82%AC</link>
            <guid>https://velog.io/@jiwon_choi/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC%EB%A1%9C-%EC%9D%B4%EC%82%AC</guid>
            <pubDate>Tue, 20 Sep 2022 13:26:57 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/e97e2310-3f8e-428b-8d11-185a465c1d4b/image.png" alt=""></p>
<p>작년 12월, 나는 티스토리에서 벨로그로 기술 블로그 플랫폼을 옮겼다.
<a href="https://velog.io/@jiwon_choi/velog-%EC%8B%9C%EC%9E%91">나의 벨로그 첫 글</a>에서도 언급한 사항이다.</p>
<p>하지만 나는 다시 티스토리로 되돌아가려고 한다.
벨로그와 티스토리를 모두 써본 입장에서 둘은 각각의 장단점이 있었지만...
나에게는 티스토리가 더 편한 것 같다.</p>
<p>며칠에 걸쳐 벨로그에 써 온 약 90개의 글을 티스토리로 옮기는 작업을 완료했다. 하지만 일단 벨로그의 글들은 비공개 처리하지 않고 두려고 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 입문2]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-lwm2ph4t</link>
            <guid>https://velog.io/@jiwon_choi/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-lwm2ph4t</guid>
            <pubDate>Wed, 14 Sep 2022 12:56:30 GMT</pubDate>
            <description><![CDATA[<p>스프링 웹 개발에는 세가지가 있다.</p>
<ul>
<li>정적 컨텐츠</li>
<li>mvc와 템플릿 엔진</li>
<li>api</li>
</ul>
<h3 id="정적-컨텐츠">정적 컨텐츠</h3>
<p>정적 컨텐츠는 말 그대로 그냥 파일을 때려박는다는 뜻..
<img src="https://velog.velcdn.com/images/jiwon_choi/post/3822cab5-58fb-46c5-8be0-9708d7175b92/image.png" alt="">
이런 애들이다. 그냥 고정된 웹페이지들</p>
<h3 id="mvc와-템플릿-엔진">mvc와 템플릿 엔진</h3>
<p><strong>mvc: model, view, controller</strong></p>
<p>컨트롤러</p>
<pre><code class="language-java">@Controller
public class HelloController {
 @GetMapping(&quot;hello-mvc&quot;)
 public String helloMvc(@RequestParam(&quot;name&quot;) String name, Model model) {
 model.addAttribute(&quot;name&quot;, name);
 return &quot;hello-template&quot;;
 }
}</code></pre>
<p>뷰</p>
<pre><code>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;body&gt;
&lt;p th:text=&quot;&#39;hello &#39; + ${name}&quot;&gt;hello! empty&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p><img src="https://velog.velcdn.com/images/jiwon_choi/post/e420b90c-3699-4842-8b12-c166f295d307/image.png" alt="">
위 화면에서 파라미터로 넘겨준 것에 주의.
컨트롤러에서 파라미터로 받도록 작성했기 때문.</p>
<h3 id="api">api</h3>
<pre><code class="language-java">@GetMapping(&quot;hello-string&quot;)
    @ResponseBody //http의 body에 이 데이터를 내가 직접 넣어줄게
    public String helloString(@RequestParam(&quot;name&quot;) String name) {
        return &quot;hello &quot; + name;
    }</code></pre>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/c37cb851-35be-49cd-91b1-7c9c1a324075/image.png" alt=""></p>
<p>실행해보면 그냥 넣어준 값이 냅다 화면에 나타난다.
화면에 있는 뭔가를 조작하는게 아니라 그냥 때려박는 느낌?</p>
<pre><code class="language-java">@GetMapping(&quot;hello-string&quot;)
    @ResponseBody //http의 body에 이 데이터를 내가 직접 넣어줄게
    public String helloString(@RequestParam(&quot;name&quot;) String name) {
        return &quot;&lt;html&gt;hello &quot; + name+&quot;&lt;/html&gt;&quot;;
    }</code></pre>
<p>화면조작으로 하려면 이런식으로 해야하는데..굳이 이렇게할 이유가 없음.</p>
<pre><code class="language-java">@GetMapping(&quot;hello-string&quot;)
    @ResponseBody //http의 body에 이 데이터를 내가 직접 넣어줄게
    public String helloString(@RequestParam(&quot;name&quot;) String name) {
        return &quot;&lt;html&gt;hello &quot; + name+&quot;&lt;/html&gt;&quot;;
    }
    @GetMapping(&quot;hello-api&quot;)
    @ResponseBody
    public Hello helloApi(@RequestParam(&quot;name&quot;) String name) {
        Hello hello = new Hello();
        hello.setName(name);
        return hello;
    }
    static class Hello {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }</code></pre>
<p>Hello 라는 객체를 만들어서 써먹어 보자.
<img src="https://velog.velcdn.com/images/jiwon_choi/post/5bc15b68-dc68-4699-990e-c7d4ec45031c/image.png" alt="">
비로소 평소에 아는 api같이 생긴게 나온다.
문자열이 아닌 객체가 반환이되면, 디폴트가 json방식으로 반환하는게 기본 정책이다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/917d94f5-79b1-4cbd-8ea1-9c794bc84b44/image.png" alt=""></p>
<p>동작방식은 위와 같다. 템플릿 엔진과의 가장 큰 차이점이 <code>@ResponseBody</code>의 존재인데 얘를 눈여겨 보자.</p>
<p><code>@ResponseBody</code>를 사용하면...</p>
<ul>
<li>HTTP의 BODY에 문자 내용을 직접 반환</li>
<li>viewResolver 대신에 HttpMessageConverter 가 동작
기본 문자처리: StringHttpMessageConverter
기본 객체처리: MappingJackson2HttpMessageConverter</li>
<li>byte 처리 등등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 입문]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8</link>
            <guid>https://velog.io/@jiwon_choi/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8</guid>
            <pubDate>Mon, 12 Sep 2022 13:37:48 GMT</pubDate>
            <description><![CDATA[<h3 id="view-환경설정">view 환경설정</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/42703e47-58a9-42ee-8762-3fe639b8cd80/image.png" alt="">
<img src="https://velog.velcdn.com/images/jiwon_choi/post/d594d3f7-a59f-4e8b-b474-b1edf6c3bd0c/image.png" alt=""></p>
<p>스프링 부트 스타터 사이트에서 스프링 프로젝트를 생성하고 IntelliJ에서 연다.</p>
<p>staic 폴더 아래에 기본적인 웰컴페이지 html 파일을 작성하고 실행하면 위 화면을 볼 수 있다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/5674f7dc-92e5-4121-ae65-f95d6c73542b/image.png" alt="">
관련 설명을 공식 페이지에서 볼 수 있다. 
링크는 <a href="https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-welcome-page">여기</a></p>
<h3 id="tymeleaf-템플릿-엔진">tymeleaf 템플릿 엔진</h3>
<p>Thymeleaf 는 웹을 위한 server-side Java template engine이다.
<a href="https://www.thymeleaf.org/">Thymeleaf 공식 페이지</a></p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/8c2472f4-79b6-4822-a4a4-b23c0304a2fa/image.png" alt="">
얘에 대한 설명도 스프링 공식 페이지에서 볼 수 있다.</p>
<p>controller라는 패키지를 만들고 <code>HelloController</code> 라는 파일을 작성해보자.</p>
<pre><code class="language-java">package hello.hellospring.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {
    //웹 어플리케이션에서 /hello 가 들어오면 스프링은 이 메서드를 호출한다.
    @GetMapping(&quot;hello&quot;)
    public String hello(Model model) {
        model.addAttribute(&quot;data&quot;, &quot;hello!!&quot;);
        return &quot;hello&quot;;
    }
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/409812b6-0130-424b-b7bb-7efedd31e98f/image.png" alt="">
그리고 templates 폴더 밑에 hello.html을 작성한다.</p>
<pre><code>&lt;!DOCTYPE HTML&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
 &lt;title&gt;Hello&lt;/title&gt;
 &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p th:text=&quot;&#39;안녕하세요. &#39; + ${data}&quot; &gt;안녕하세요. 손님&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p><img src="https://velog.velcdn.com/images/jiwon_choi/post/3521857b-747f-45e0-9f0d-382a410b1747/image.png" alt=""></p>
<p>그리고 다시 실행하면 이 화면이 나온다.
hello.html 의 data에 &quot;hello!&quot;라는 값을 넣은 것..
 <img src="https://velog.velcdn.com/images/jiwon_choi/post/2ef00e84-5983-44a9-b3f5-9fd82c2c8d9a/image.png" alt="">
컨트롤러에서 리턴 값으로 문자를 반환하면 viewResolver가 화면을 찾아서 처리하는 것이다. </p>
<p>이것이 바로 템플릿 엔진이 동작하는 방식이다.</p>
<h3 id="빌드하기">빌드하기</h3>
<ol>
<li>./gradlew build</li>
<li>cd build/libs</li>
<li>java -jar hello-spring-0.0.1-SNAPSHOT.jar
순서로 빌드할 수 있다.</li>
</ol>
<p>해당 디렉터리 내의 모든 파일을 보는 <code>ls -arlth</code>를 치면
<img src="https://velog.velcdn.com/images/jiwon_choi/post/510596dd-b25b-452c-92bb-b06f13156cb6/image.png" alt="">
이렇게 파일이 쭉 뜨는데 (위 사진은 builds/libs 내의 상황) 이 jar 파일을 실행한 것이다.</p>
<p>이렇게 하면 스프링이 실행되면서 아까 그 hello 페이지와 웰컴 페이지를 localhost:8080 에서 볼 수 있다.</p>
<p>이게 된다는 말은 즉..서버에 jar 파일 띡 올려놓고 실행하면 된다는 뜻이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[카카오 맵 api 예제들]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A7%B5-api-%EC%98%88%EC%A0%9C%EB%93%A4</link>
            <guid>https://velog.io/@jiwon_choi/%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A7%B5-api-%EC%98%88%EC%A0%9C%EB%93%A4</guid>
            <pubDate>Tue, 06 Sep 2022 06:58:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/758df566-6cd7-4c57-a4e5-9384262ca0db/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/cb0adc44-f996-4f7a-97a0-cfbe3bcadb76/image.png" alt=""></p>
<p><a href="https://apis.map.kakao.com/web/sample/">카카오 공식 api 가이드 사이트</a>에 정말 예제가 많다! 바로 구글링부터 하지 말고 위 사이트를 참고해서 만들면 좋을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[부트스트랩 개요]]></title>
            <link>https://velog.io/@jiwon_choi/%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@jiwon_choi/%EB%B6%80%ED%8A%B8%EC%8A%A4%ED%8A%B8%EB%9E%A9-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Fri, 02 Sep 2022 07:48:25 GMT</pubDate>
            <description><![CDATA[<p>보통 프로젝트할때 스타일을 한땀한땀 전부 만드는 경우는 없다. </p>
<p>과거를 돌이켜보면 <a href="https://www.w3schools.com/css/css_rwd_templates.asp">이런 css 템플릿 사이트</a>에서 스타일을 가져다 붙이는 경우가 많았던 것 같다.</p>
<p>이 분야의 유명인사는 부트스트랩이다. 
부트스트랩은 디자인을 잘 할 수 있도록 도와준다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/ae7495ed-aa30-47b9-ad8d-5b3ff79c9ae0/image.png" alt="">
내 과거 프로젝트에서 부트스트랩을 사용한 적이 있었다. 기억이 증발해서 처음보는 것처럼 느껴졌을 뿐...부트스트랩은 템플릿도 있고 개별 요소도 있는데 위 사진은 개별 요소로 가져다 쓴 예이다. </p>
<p>이러한 개별 요소에 대한 사용법은 <a href="https://getbootstrap.kr/docs/5.1/getting-started/introduction/">부트스트랩 사이트</a>에서 확인할 수 있다.</p>
<pre><code>&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;!-- Required meta tags --&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;

    &lt;!-- Bootstrap CSS --&gt;
    &lt;link href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot; integrity=&quot;sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3&quot; crossorigin=&quot;anonymous&quot;&gt;

    &lt;title&gt;Hello, world!&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello, world!&lt;/h1&gt;

    &lt;!-- Optional JavaScript; choose one of the two! --&gt;

    &lt;!-- Option 1: Bootstrap Bundle with Popper --&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

    &lt;!-- Option 2: Separate Popper and Bootstrap JS --&gt;
    &lt;!--
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js&quot; integrity=&quot;sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js&quot; integrity=&quot;sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
    --&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>위 사이트에서 확인할 수 있는 스타터 개요이다. js 플러그인과 css들을 불러온다.</p>
<p>이렇게 하고 나면 개별 요소를 하나하나 디자인 하는 대신, 부트스트랩에서 소개하는 클래스 이름을 사용함으로써 예쁜 요소들을 쉽게 만들 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/9128ecda-5112-4bb0-8bb5-30593b4115c4/image.png" alt="">
이렇게 공식문서에 소개된 클래스 이름을 그냥 복사해서 쓰면 된다.
버튼 뿐만 아니라 div 같은 컨테이너나 그리드, 열을 만들기 위한 틀도 제공한다.</p>
<p>부트스트랩의 디자인에 내 디자인을 추가로 입힐 수도 있다.</p>
<pre><code>&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;link
      href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css&quot;
      rel=&quot;stylesheet&quot;
      integrity=&quot;sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3&quot;
      crossorigin=&quot;anonymous&quot;
    /&gt;
    &lt;link href=&quot;./assets/css/app.css&quot; rel=&quot;stylesheet&quot; /&gt;
    &lt;title&gt;SSAFY&lt;/title&gt;
  &lt;/head&gt;</code></pre><p>위 코드에서 <code>&lt;link href=&quot;./assets/css/app.css&quot; rel=&quot;stylesheet&quot; /&gt;</code> 를 통해 내가 작성한 css 파일 또한 참조하도록 하였다.</p>
<p>부트스트랩은 예쁜 템플릿도 많다. 아래는 참고할 만한 부트스트랩 사이트들이다.<br><a href="https://www.bootstrapzero.com/">사이트1</a>
<a href="https://startbootstrap.com/themes/">사이트2</a>
<a href="https://templatemag.com/bootstrap-templates/">사이트3</a>
<a href="https://themehunt.com/">사이트4</a>
<a href="https://bootstrapmade.com/">사이트5</a>
<a href="https://bootstrapmade.com/bootstrap-4-templates/">사이트6</a>
zip으로 다운 받은 후 내 편집기에서 열 수 있다.
<img src="https://velog.velcdn.com/images/jiwon_choi/post/c7bb4d47-c01b-4be2-aa34-b5587baae651/image.png" alt="">
간단한 걸 만들 때는 개별 요소를 조합하여 디자인하는대신 템플릿을 다운 받아놓고 조금만 고쳐쓰면 편리할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바에서 순열과 조합]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%EC%88%9C%EC%97%B4%EA%B3%BC-%EC%A1%B0%ED%95%A9-e0utv9d4</link>
            <guid>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%EC%88%9C%EC%97%B4%EA%B3%BC-%EC%A1%B0%ED%95%A9-e0utv9d4</guid>
            <pubDate>Fri, 12 Aug 2022 03:06:47 GMT</pubDate>
            <description><![CDATA[<p>요즘은 자바로 코테를 준비하고 있는데 매 순간이 경악의 연속이다. 자바는 놀랍게도 순열, 조합 라이브러리가 없어서 파이썬이면 1줄만에 끝나는 뽑기를 직접 한땀한땀 구현해야 한다.  </p>
<p>아무튼 몇 번 자바로 이런 문제를 풀다보니 손에 익은 풀이가 생겨서 정리하려고 한다. 인터넷 허용 안되는 시험이라면 그때그때 상황에 맞게 효율적으로 짜겠지만...인터넷 허용이라면 이 포스팅의 순열,조합 함수를 긁어 쓸 생각이다.^_^ </p>
<p>뭘 뽑을지는 문제마다 다르므로 차라리 사용할 인덱스만 뽑아서 output 배열에 넣는게 다양한 문제에 적용하기 좋을 것 같다.(0,1,2...~n중 r개를 뽑기) </p>
<h3 id="순열">순열</h3>
<pre><code class="language-java">
import java.util.*;
import java.io.*;

public class Main {
    public static int [] index;
    public static int [] output;
    public static int n,r;
    public static boolean [] visited;
    public static void main(String[] args) throws Exception {
        //n개 중 r개를 뽑는다. 문제에 따라 바꿔 주기.
         n=3;
         r=2;
         output=new int[r];
         visited=new boolean[n];

         perm(0);
    }
    //순열
    public static void perm(int cnt) {
        if(cnt==r) {
            //뽑힌 인덱스의 목록
            System.out.println(Arrays.toString(output));
            return;
        }
        for(int i=0;i&lt;n;i++) {
            if(visited[i]) continue; 
            output[cnt]=i;
            visited[i]=true;
            perm(cnt+1);
            visited[i]=false;
        }
    }

}</code></pre>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/7019d51e-bb78-440f-b55e-c5254a3bfba4/image.png" alt=""></p>
<h3 id="조합">조합</h3>
<pre><code class="language-java">import java.util.*;
import java.io.*;

public class Main {
    public static int [] index;
    public static int [] output;
    public static int n,r;
    public static void main(String[] args) throws Exception {
        //n개 중 r개를 뽑는다. 문제에 따라 바꿔 주기.
         n=3;
         r=2;
         output=new int[r];
         combi(0,0);
    }
    //조합
    public static void combi(int cnt,int start) {
        if(cnt==r) {
            //뽑힌 인덱스의 목록
            System.out.println(Arrays.toString(output));
            return;
        }
        for(int i=start;i&lt;n;i++) {         
            output[cnt]=i;
            combi(cnt+1,i+1);

        }
    }

}</code></pre>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/b0e4a34d-a416-43f4-be81-9d5ebd27f636/image.png" alt=""></p>
<p>조합은 start 인덱스를 두고 거기서부터 탐색하므로 방문체크가 필요 없다. </p>
<h3 id="순열과-조합의-시간복잡도">순열과 조합의 시간복잡도</h3>
<p>순열의 시간복잡도는 O(n!) 이고 조합의 시간복잡도는 O(2^n) 이다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/74c41a28-effc-4cdd-99b5-0bbc5185d1e7/image.png" alt="">
그리고 얘네들은 흔히 볼 수 있는 시간복잡도 그래프에서 거의 직선을 그리고 있다. 둘 다 O(n^2)보다 비효율적이다.</p>
<p>예를 들어 순열의 경우...12!정도만 되어도 5억이다. n이 10이 넘어간다면 순열, 조합 문제가 맞는지 다시 한 번 생각해봐야 한다. 조합은 순열보단 상황이 낫지만 30/15 정도만 되어도 터진다고 보는게 맞다.</p>
<p>단 r이 단 2개..이런식으로 정해져있는 경우에는 n이 10을 넘어도 순열, 조합 문제가 맞을 수도 있다. 마지노선을 1억정도로 잡고 상황에 따라 시간복잡도를 생각해 보는게 바람직할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바 우선순위큐- 배열 넣기]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%ED%81%90-%EB%B0%B0%EC%97%B4-%EB%84%A3%EA%B8%B0</link>
            <guid>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%ED%81%90-%EB%B0%B0%EC%97%B4-%EB%84%A3%EA%B8%B0</guid>
            <pubDate>Tue, 09 Aug 2022 07:47:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/25a36cf9-446d-4390-86d3-f65d9e542bfc/image.png" alt=""></p>
<pre><code class="language-java">package backjoon;

import java.util.*;
import java.io.*;


public class Main {

        public static void main(String [] args) throws Exception{
             PriorityQueue &lt;Integer&gt; q=new PriorityQueue&lt;&gt;();
             q.add(3);
             q.add(5);
             q.add(2);
             //2 3 5 출력
             while(!q.isEmpty()) {
                 System.out.println(q.poll());
             }
        }

}</code></pre>
<p>자바에서 우선순위 큐는 낮은 값부터 뱉는다.</p>
<pre><code class="language-java">package backjoon;

import java.util.*;
import java.io.*;


public class Main {

        public static void main(String [] args) throws Exception{
             PriorityQueue &lt;Integer&gt; q=new PriorityQueue&lt;&gt;(new Comparator&lt;Integer&gt;() {

                @Override
                public int compare(Integer o1, Integer o2) {
                    // TODO Auto-generated method stub
                    return o2-o1;
                }

             });
             q.add(3);
             q.add(5);
             q.add(2);
             //5 3 2출력
             while(!q.isEmpty()) {
                 System.out.println(q.poll());
             }
        }

}</code></pre>
<p>정렬에 여러 조건을 붙일때와 마찬가지로, <code>Comparator</code>를 이용하면 우선순위를 바꿀 수 있다.</p>
<pre><code class="language-java">PriorityQueue &lt;int []&gt; q=new PriorityQueue&lt;&gt;(new Comparator&lt;int []&gt;() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    // TODO Auto-generated method stub
                    if (o1[0]==o2[0]) return o1[1]-o2[1];
                    return o1[0]-o2[0];
                }
             });</code></pre>
<p>특히 유의해야할 점은!! 우선순위큐에 배열을 넣는 경우, 반드시 <code>Comparator</code>를 써야 한다는 것이다. <code>PriorityQueue &lt;int []&gt; q=new PriorityQueue&lt;&gt;();</code> 하게 되면 add하는 과정에서 에러가 발생한다. </p>
<p>참고로 1에서 2빼면 오름차순(1,2,3...)이고 2에서 1빼면 내림차순(3,2,1..)이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[개인 토이 프로젝트- 레시피 앱]]></title>
            <link>https://velog.io/@jiwon_choi/%EA%B0%9C%EC%9D%B8-%ED%86%A0%EC%9D%B4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A0%88%EC%8B%9C%ED%94%BC-%EC%95%B1</link>
            <guid>https://velog.io/@jiwon_choi/%EA%B0%9C%EC%9D%B8-%ED%86%A0%EC%9D%B4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A0%88%EC%8B%9C%ED%94%BC-%EC%95%B1</guid>
            <pubDate>Thu, 23 Jun 2022 14:54:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/7f585d26-0061-4ce0-a669-2de10fb7ce14/image.png" alt=""></p>
<h3 id="개요">개요</h3>
<p>자바 기반 안드로이드 앱을 몇 번 개발하다보니 코틀린도 써보고 싶어졌다. 이런 목적으로 개발할 때는 요리 레시피나 레스토랑 리뷰 서비스를 만드는게 만만하고 딱 좋다.  </p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/093399b3-649f-4919-a03b-591a682c1327/image.gif" alt="">
간단하게 레시피 목록이 나오고, 특정 레시피를 클릭하면 그 레시피의 정보가 나오는 간단한 앱을 만들었다.  </p>
<h3 id="개발">개발</h3>
<p>액티비티를 남발하며 마구잡이로 개발하지 않기로 다짐..나름 폴더를 나눠가고 공유 뷰 모델과 데이터 클래스도 만들어가면서 구조를 어떻게 짤지 열심히 고민했다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/3666e65e-8713-47b5-bd96-ee1dd1f5af6b/image.png" alt="">
이게 정답인지는 모르겠다...하지만 확실한건 옛날 보다는 발전했다는 것이다.</p>
<p>데이터는 <a href="https://www.data.go.kr/data/15060073/openapi.do">공공 데이터포탈</a>에서 제공하는 api를 사용했다. </p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/f89ae91c-84ff-45fe-9c5c-3b1b24ade9df/image.png" alt="">
이런식으로 반환되는 json 데이터다. 이런 데이터 받아올때 항상 그렇듯, 레트로핏 라이브러리를 사용하여 데이터를 가져왔다.</p>
<p>api에 내가 안 쓸것같은 정보도 많이 포함되어 있어서...내가 쓸 정보만 골라서 데이터 클래스 <code>recipeItem</code>를 만들었다.</p>
<pre><code class="language-kotlin">data class recipeItem (
    var recipeNum:Int,
    var recipeName:String,
    var ingredient:String,
    val manuals: List&lt;String&gt;,
    val imgs: List&lt;String&gt;
)</code></pre>
<p>처음 받아올때 공유 뷰모델에 이 <code>recipeItem</code> 으로 이루어진 리스트를 저장하여 어떤 프래그먼트든 쉽게 꺼내 쓸 수 있도록 했다.
또한 뷰 모델에 <code>selectedNum</code>이라는 변수를 둬서, 레시피 상세를 보여주는 프래그먼트가 어떤 레시피를 보여줄지 알 수 있도록 했다. </p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/3ede483d-8cad-41a5-a6a7-b2a528294d61/image.png" alt="">
원활한 뒤로가기를 위해 navigation 그래프도 사용했다. 뒤로가기 버튼을 누르면 편리하게 이전 프래그먼트로 이동한다. 프래그먼트가 많지 않아서 의미 없어보이지만,이는 실전(?)에서 navigation를 첫사용한 것이므로 거기에 의의가 있다고 본다^^..</p>
<p>부끄럽지만 나는 처음 안드로이드 개발할 때 view binding, navigation 없이 개발했다. findviewbyId를 난사했고 뒤로가기는 헤더에 화살표 버튼을 붙여 만드는 줄 알았다... 하지만 그만큼 새 기능을 알게됐을때 경악하며 그 사기성을 실감할 수 있는 것이다. jetpack은 혁명이나 다름없다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/a7f5b100-bb1c-40b8-b7e7-60499091724b/image.png" alt="">
목록 화면은 간단히 리사이클러뷰를 사용해 구현했다. <code>app:cardElevation=&quot;4dp&quot;</code> 와 <code>app:cardCornerRadius=&quot;4dp&quot;</code>를 이용하여 나름 ui를 다듬어봤는데...흠..ui는 솔직히 갈길이 멀다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/982691dc-df75-4a43-8a3b-96f34668599c/image.png" alt="">
레시피 상세 화면이다. 레시피 번호, 레시피 이름, 준비물, 만드는 방법(글+사진)으로 이루어져 있다. 사진 데이터의 경우 url로 정보를 제공하고 있어서, 해당 주소에서 사진을 가져오기 위해 glide 라이브러리를 사용했다. 비트맵을 사용하는 것도 가능하지만 체감상 glide가 더 빨랐다. </p>
<p>이 화면을 개발할 때 스크롤 문제로 살짝 문제를 겪었었다. 레시피 번호+이름+준비물은 스크롤을 내리면 같이 위로 올라갔으면 해서 스크롤뷰 안에 텍스트뷰들을 넣고 그 아래에 리사이클러 뷰를 넣었는데, 이랬더니 스크롤뷰와 리사이클러 뷰의 스크롤이 따로따로 움직였기 때문이다. 스크롤뷰 대신 <code>NestedScrollView</code>를 사용하고, 리사이클러뷰에서 <code>android:nestedScrollingEnabled=&quot;false&quot;</code>를 추가해서 해결할 수 있었다.</p>
<h3 id="후기">후기</h3>
<p>간단하게 동작하는 앱인데도 개발하면서 많이 성장했다고 느꼈다. 하지만 아쉬운 점도 많이 있어서 계속해서 기능을 추가하고 고쳐나가지 않을까 싶다. 기능을 추가함에 따라 startFragment에 관련 버튼을 추가하고 싶어서 startFragment를 상당히 빈 상태로 남겨두기도 했다. 여유가 있으면 ui랑 기존 구조도 더 다듬고... 앞으로 공부하면서 실제로 개발해보고 싶은 것이 생길 때마다 추가해 나가도 좋을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배낭문제]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%9E%98-%EC%95%8C%EB%A0%A4%EC%A7%84-dp-%EB%AC%B8%EC%A0%9C%EB%93%A4</link>
            <guid>https://velog.io/@jiwon_choi/%EC%9E%98-%EC%95%8C%EB%A0%A4%EC%A7%84-dp-%EB%AC%B8%EC%A0%9C%EB%93%A4</guid>
            <pubDate>Mon, 13 Jun 2022 07:00:40 GMT</pubDate>
            <description><![CDATA[<p>나는 프로그래머스에서 문제를 많이 풀었다. 프로그래머스는 딱히 알고리즘 분류가 되어있지 않은데...아무거나 골라잡아 풀다보니 구현,그래프 문제만 왕창 푼 것 같다.  아무튼 최근에는 웰노운이지만 코테에는 잘 안나와서(나오긴 하지만 구현,그래프보단 비중 적음) 소홀해진 알고리즘을 볼려고 한다. 평소에 알고리즘은 눈으로 슥 보고 음~그렇군 하고 넘어가는데..아무래도 이렇게 하니까 기억에서 증발되는 경우가 많은 것 같다. 그나마 블로그에 적으면 장기기억이 되는 듯하고, 오늘 볼 배낭 문제는 유명한 문젠데 척 보고 뭔소리야?가 절로 나왔던 문제이기 때문에...반성하며 블로그에 정리해본다.</p>
<h3 id="직접-풀어보자">직접 풀어보자.</h3>
<p><a href="https://www.acmicpc.net/problem/12865">백준 12865</a>을 보며 공부해보자. 아주 클래식한 배낭 문제이다. 참고로 배낭에 넣을 물품을 쪼갤 수 있는 경우에는 그리디로 풀 수 있는데, 이 문제의 경우에는 물품을 쪼갤 수 없으므로(0-1 배낭문제) dp로 풀어야 한다.
<img src="https://velog.velcdn.com/images/jiwon_choi/post/14cdfc8d-e367-4a02-9d0d-8aa0269fbf92/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/3938a0a7-465c-42ba-8931-66a63806d12b/image.png" alt="">
잘 알려진 문제다 보니 검색하면 풀이법이 많이 나온다. 이런 그래프가 많이 나온다. 이 그래프가 어떻게 나왔는지 알아보자.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/8911777f-e3c3-4c12-8367-83c398ad3a51/image.png" alt="">
먼저 물품번호의 뜻은 다음과 같다. <strong>i번째 물품을 추가했을때</strong> 어떻게 되느냐...를 의미한다고 보면 된다. 세로 순서로, 무게가 작은 순으로 채워 나간다. (위 그림에 표시한 순서대로)</p>
<p>추가할 i번째 물품이 무게 제한 w보다 무겁다면 그냥 dp[i-1]를 가져오면 될 것이다.(바로 위의 값) 그렇지 않다면, </p>
<ul>
<li>i번째 보석을 일단 넣고, 무게제한w에서 i무게를 뺐을때의 무게 k에서 서의 최적값을 테이블에서 가져와서 더하기</li>
<li>i번째 보석을 넣지 않고, dp[i-1]의 값 (바로 위의 값)을 가져오기</li>
</ul>
<p>둘 중에서 더 가치가 큰 경우를 선택하면 될 것 이다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/2e33348c-9419-474e-8d99-a04f9f2b8b06/image.png" alt="">
한 칸을 잡고 예를 들면 다음과 같다. 13과 14를 비교하면 14가 더 크므로 14를 채워 넣는다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/d102d490-4dfb-4029-828c-c45241fe6e11/image.png" alt="">
위 그래프 채워넣는 로직을 점화식으로 세우면 다음과 같다. </p>
<pre><code class="language-python">n,k=list(map(int,input().split()))
items=[(0,0)]
W=[0]
V=[0]
for i in range(n):
  w,v=list(map(int,input().split())) #무게,가치
  W.append(w)
  V.append(v)
dp=[[0]*(k+1) for _ in range(n+1)]

for item in range(1,n+1):  
  for kg in range(1,k+1):   
    if W[item]&gt;kg:
      dp[item][kg]=dp[item-1][kg]
    else:
      dp[item][kg]=max(dp[item-1][kg], V[item]+dp[item-1][kg-W[item]])
print(dp[n][k])</code></pre>
<blockquote>
<p>참고: <a href="https://st-lab.tistory.com/141">https://st-lab.tistory.com/141</a>
<a href="https://velog.io/@lre12/%EB%B0%B1%EC%A4%80-12865%EB%B2%88-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD">https://velog.io/@lre12/%EB%B0%B1%EC%A4%80-12865%EB%B2%88-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[코루틴 이해하기]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jiwon_choi/%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 27 May 2022 07:26:28 GMT</pubDate>
            <description><![CDATA[<p>아아...코루틴... 많이 들어봤고 중요한 내용인건 알지만 코루틴이 뭐냐고 물어보면 일목요연하게 답변할 자신은 없다. 하지만 놀랍게도 내가 직접 관련 내용에 대해 정리한 글이 존재한다. ...인간의 기억력이란 뭘까? </p>
<ul>
<li><a href="https://velog.io/@jiwon_choi/Unit-4-1">처음 배운 코루틴의 개념</a></li>
<li><a href="https://velog.io/@jiwon_choi/Unit-4-2">화성 이미지 표시 앱 만들기</a></li>
</ul>
<p>비록 기억이 증발했다곤 하나 내가 직접 정리한 글을 보니 무슨 개념이었는지 금방 상기할 수 있었다. 역시 정리글은 꾸준히 써야한다. 게다가 그때는 보이지 않았던 부분도 좀 보이는 듯 하다. 그때는 그냥 음 그렇구나 정도였는데, 이제는 아 이때 그랬던게 그래서였어? 하는 감상도 추가된 그런... 어쨌든 좀 더 코루틴에 집중한 정리글을 이 포스트에 추가로 작성해보자. </p>
<h3 id="비동기-처리">비동기 처리</h3>
<p>비동기 처리란 동시에 여러가지 한다는 뜻이다. 때때로 스레드 여러 개를 두고 비동기적으로 처리를 해야 할 때가 있다. 예를 들어 api 호출 같은 경우가 대표적이다. 특히 저 위에 있는 화성 앱같은 경우에는 이미지를 서버로부터 받아온다. 이미지를 다운로드하는데는 시간이 걸린다. 만약 UI 스레드(메인스레드)에서 다운로드를 하게 된다면 다운로드하는 시간만큼 UI가 멈추게 될 것이다. 그래서 UI 스레드가 아닌 다른 스레드로 다운로드를 처리하고 비동기적으로 결과를 처리해야 한다.</p>
<h3 id="그래서-코루틴이란">그래서 코루틴이란?</h3>
<p>이러한 비동기적인 일처리, 동시 실행 코드 작성을 편하게 하기 위해서 사용되는 실행 설계 패턴이 바로 코루틴이다.</p>
<p>사용 예시를 보자. </p>
<pre><code class="language-kotlin">private fun getMarsPhotos() {
        //launch 함수 호출해 코루틴 실행.
        viewModelScope.launch {
            try {
                //MarsApiService에서 정의한 함수를 호출
                val listResult = MarsApi.retrofitService.getPhotos()
                //서버에서 받은 결과를 변수에 저장
                _status.value = &quot;Success: ${listResult.size} Mars photos retrieved&quot;
            }
            catch (e: Exception) { //인터넷에 연결 안된 사용자가 튕기지 않도록..
                _status.value = &quot;Failure: ${e.message}&quot;
            }
        }
    }</code></pre>
<p>이건 내가 안드로이드 강의 들을때 작성했던 코드이다. </p>
<pre><code class="language-kotlin">fun getJson(path: String, params: Map&lt;String, Any&gt;, completed: (Result&lt;String&gt;) -&gt; Unit) {
        GlobalScope.launch(Dispatchers.IO) {
            var queryParams = if (params.isNotEmpty()) params
                .map { entry -&gt; &quot;${entry.key}=${entry.value}&quot; }
                .reduce { s1, s2 -&gt; &quot;${s1}&amp;${s2}&quot; }
            else &quot;&quot;

            if (queryParams.isNotEmpty()) queryParams = &quot;?${queryParams}&quot;

            val url = if (path.startsWith(&quot;http&quot;)) URL(path + queryParams)
            else URL(baseUrl + path + queryParams)

            val json = url.readText(Charsets.UTF_8)
            completed(Result.success(json))
        }
    }</code></pre>
<p>이건 프로그래머스 과제관의 케이묵 문제의 초기 스켈레톤 코드에 포함되어 있는 코드이다.</p>
<p>위 코드를 보면 알겠지만, 코루틴은 launch 혹은 aync로 시작이 가능하다. aync으로 시작하는 건 처음 들어보는데..launch는 상태를 관리할 수 있고, async는 상태를 관리+결과 반환까지 된다고 한다.</p>
<h3 id="scope">Scope</h3>
<p>위에 보면 launch 앞에 붙은 <code>~Scope</code>가 있다. 얘네는 상황에 따라 다르게 골라서 사용하는데, Scope의 종류는 아래와 같다.</p>
<ul>
<li>GlobalScope - 특정 액티비티나 프래그먼트의 생명주기와 함께 동작해서 실행 도중 별도 생명주기 관리가 필요없다. 시작부터 종료까지 실행 시간이 비교적 긴 코루틴의 경우에 적합하다.</li>
<li>CoroutineScope - 필요할때만 열고 완료되면 닫아주는 코루틴 스코프에 사용하기 적합하다.</li>
<li>ViewModelScope - 뷰모델 컴포넌트를 사용한다면, ViewModel 인스턴스에서 사용하기 위해 제공되는 스코프이다. GlobalScope와 비슷하게, 뷰모델 인스턴스가 소멸될 때 자동으로 소멸되고 작업도 자연스럽게 취소된다.</li>
</ul>
<h3 id="suspend">Suspend</h3>
<p>코루틴 얘기 나올때마다 <code>suspend</code>가 꼭 등장하는데... 그 이유는 코루틴의 주요 기능 중 하나가 상태를 저장하여 중단했다가 재개할 수 있다는 것이기 때문이다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/90576df6-b92f-4733-b7db-43412d784788/image.png" alt="">
이해를 위해 위 그림을 보자. 상황은 다음과 같다.</p>
<ul>
<li>코루틴1은 메인스레드에서 작업1을 하고 있었다. </li>
<li>근데 하다보니 코루틴3의 작업3 결과값이 필요해졌다. 얘는 IO 스레드라 코루틴 1보다 느릿느릿 결과를 처리하고 있다.</li>
<li>코루틴 1은 어차피 코루틴3의 작업이 끝나길 기다려야 한다.. 그러므로 일시중지한다.</li>
<li>메인스레드는 코루틴1이 중지됐다고 빈둥거리지 않는다. 코루틴2가 메인스레드를 점유하여 작업2를 끝낸다. </li>
<li>그러는 동안 코루틴3의 작업3이 완료되었다. 코루틴1은 작업3의 결과를 받고 작업1을 재개한다.</li>
</ul>
<p>비동기 작업을 하다보면 이런 일이 많이 생기는데, 이때 코루틴은 자신의 작업을 일시정지한다. 때문에 일시 중단 할 가능성이 있는 함수는 코루틴 블록 내부에서 수행되어야 한다. 코루틴 블록 내부에서 하기 싫으면? 그때는 <code>suspend</code> 키워드를 붙여서 정지함수로 만들어야 한다. </p>
<pre><code class="language-kotlin">//기본 URL(Retrofit 빌더에서 정의함)에 엔드포인트 photos를 추가해서 가져옴.
interface MarsApiService {
    @GET(&quot;photos&quot;)
    suspend fun getPhotos(): List&lt;MarsPhoto&gt; //변경
    //참고-suspend 키워드를 붙여서 정지함수로 만들면 코루틴 내에서 이 메서드 호출 가능
}</code></pre>
<p>화성이미지 예제에서는 위 인터페이스를 만들때 정지함수를 선언하였다.</p>
<h3 id="복기자바에서는">(복기)자바에서는?</h3>
<p>난 졸업 프로젝트로 자바 기반 안드로이드 앱을 만들 때 아두이노 센서로부터 블루투스 통신으로 값 받아오는 것도 해봤고, 파이어베이스에서 이미지 받아서 띄우는 것도 해봤다. 이거 둘다 비동기 처리가 필요해보이는데...어떻게 했는가? </p>
<p>블루투스 통신하는 건 스레드를 따로 구현했다. 이후 이 스레드를 <code>new 어쩌구스레드()</code> 이렇게 선언할때,  소켓 변수 하나를 파라미터로 넣어줬다. 그래서 워커 스레드는 수시로 소켓의 Input Stream을 확인하며 수신한 값이 있으면 가져오는 역할을 할 수 있었다. </p>
<p>파이어베이스에서 이미지 받아오는 건 glide 라이브러리를 사용했다. 사실 냅다 glide 부터 사용한 건 아니고... 얘도 스레드를 직접 구현해서 하는 방식으로 해봤는데, glide가 로딩되는 속도도 빠르고 코드도 간결해서 glide를 선택했다. </p>
<p>어쨌든 둘 다 코루틴은 안썼다. 의문이 들었다. 자바에는 코루틴이 없나...? 찾아봐도 잘 안나오고, 난 학교 선배 등 물어볼 수 있는 사람 1도 없고 오로지 솔플을 하고 있기에... sns에서 가볍게 물어봤는데 감사하게도 답을 얻을 수 있었다. 자바에는 코루틴 같이 편리하게 쓸 수 있는건 없고, 내가 했던것처럼 직접 구현하거나 프레임워크에서 지원하는 스프링의 Async 같은걸 사용한다고 한다. 코틀린과 자바의 차이점을 또 하나 알게 되었다..</p>
<h3 id="마치며">마치며</h3>
<p>드디어 코루틴에 대해 좀 알게 된 느낌이다. 혹시 까먹더라도, 내가 들은 강의, 내가 쓴 코드와 주석, 내 식대로 바꾼 설명으로 구구절절 열심히 설명했으니....다시 읽어보면 기억이 잘 날것이라고 생각한다. </p>
<blockquote>
<p>참고: <a href="https://android-uni.tistory.com/m/33">https://android-uni.tistory.com/m/33</a>
<a href="https://prgms.tistory.com/87">https://prgms.tistory.com/87</a>
<a href="https://kotlinworld.com/144">https://kotlinworld.com/144</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[투 포인터에 대해]]></title>
            <link>https://velog.io/@jiwon_choi/%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%97%90-%EB%8C%80%ED%95%B4</link>
            <guid>https://velog.io/@jiwon_choi/%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%97%90-%EB%8C%80%ED%95%B4</guid>
            <pubDate>Tue, 17 May 2022 09:08:37 GMT</pubDate>
            <description><![CDATA[<p><code>이것이 코딩테스트다</code>는 정말 도움이 되는 책이다. 하지만 난 이 책을 처음 볼 때 상당히 조급한 상태였고, 빨리 이론을 훑고나서 그래프, 구현 등 메이저한 실전 문제를 풀고 싶었다. 그래서 부록을 공부하지 않고 건너뛰는 무참한 실수를 벌이고 말았다.. 지금 다시 펼쳐보니 부록에 있는 건 이제 대부분 아는 내용이긴 하다. 그런데 생소한 게 하나 있었는데, 바로 <code>투포인터</code>에 대한 내용이다.</p>
<h3 id="투-포인터">투 포인터</h3>
<p>투 포인터란 리스트에 순차적으로 접근해야 할 때 2개의 점의 위치를 기록하면서 처리하는 알고리즘을 의미한다. 예를 들어 1~10번 학생이 있을 때, &quot;2번부터 7번까지 나와&quot; 라고 하면 2번과 7번이라는 2개의 점을 이용해서 접근할 데이터의 범위를 표현한 것으로 볼 수 있다. 솔직히 이름 보면 이런 알고리즘이구나 정도는 예측 가능하다. </p>
<h3 id="특정한-합을-가지는-연속-수열-찾기">특정한 합을 가지는 연속 수열 찾기</h3>
<p>그치만 투 포인터를 이용해 특정한 합을 가지는 연속 수열 찾기를 할 수 있는 건 꽤 신박하다.(양의 정수로 구성된 리스트 한정)
<img src="https://velog.velcdn.com/images/jiwon_choi/post/8213da07-ee82-44fb-866d-7ce7c39ae24c/image.png" alt=""></p>
<p>예를 들어 위와 같은 문제들을 말한다. 위 예제의 경우 답은 3이다. </p>
<h3 id="어떻게-푸는가">어떻게 푸는가?</h3>
<p>구체적인 알고리즘은 다음과 같다.</p>
<ol>
<li>시작점(start)과 끝점(end)이 첫 번째 원소의 인덱스(0)을 가리키도록 한다.</li>
<li>현재 부분합이 M과 같다면 카운트한다.</li>
<li>현재 부분합이 M보다 작으면 end를 1 증가시킨다.</li>
<li>현재 부분합이 M보다 크거나 같으면 start를 1 증가시킨다.</li>
<li>모든 경우를 확인할 때까지 2번부터 4번까지의 과정을 반복한다.</li>
</ol>
<p>이 문제를 투 포인터 알고리즘으로 해결할 수 있는 이유는 기본적으로 시작점을 오른쪽으로 이동시키면 항상 합이 감소하고, 끝점을 오른쪽으로 이동시키면 항상 합이 증가하기 때문이다. 그러므로 <strong>원소 내 음수 데이터가 포함되어 있는 경우 투 포인터 알고리즘으로 문제를 해결할 수 없다.</strong></p>
<p>이런 건 한번 풀어봐야 각이 서는 법이다. 위 예제와 정확히 똑같은 문제가 있다. <a href="https://www.acmicpc.net/problem/2003">백준 2003</a>을 풀어보자. </p>
<pre><code class="language-python">n,m=list(map(int,input().split())) #데이터의 갯수, 부분합 M
data=list(map(int,input().split())) #전체 수열

count=0
interval_sum=0
end=0

#start를 차례대로 증가시키며 반복
#start 증가=interval_sum 감소
for start in range(n):
  #해당 start를 고정시켜놓고, end를 가능한만큼 이동시키기
  while interval_sum&lt;m and end&lt;n:
    interval_sum+=data[end]
    end+=1
  #부분합이 m일때 카운트 증가
  if interval_sum==m:
    count+=1
  #for문 돌면서 start를 1 증가시킬거니까 다음 반복문을 위해 마이너스
  interval_sum-=data[start]

print(count)</code></pre>
<p>이후 응용문제인 <a href="https://www.acmicpc.net/problem/1806">백준 1806</a>도 풀어보자.</p>
<pre><code class="language-python">#백준 1806
#합이 s 이상인 가장 짧은 수열의 길이 구하기!
n,s=list(map(int,input().split())) #데이터의 갯수, 부분합 M
data=list(map(int,input().split())) #수열 데이터

end=0
interval_sum=0  
answer=n+1 #길이

for start in range(n):
  while end&lt;n and interval_sum&lt;s:   
    interval_sum+=data[end]
    end+=1
  if interval_sum&gt;=s:
    answer=min(answer,end-start)

  interval_sum-=data[start]

if answer==n+1:
  print(0)
else:
  print(answer)
</code></pre>
<blockquote>
<p>참고: 이코테 472p</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[우테캠 5기 지원 후기]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%9A%B0%ED%85%8C%EC%BA%A0-5%EA%B8%B0-%EC%A7%80%EC%9B%90-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@jiwon_choi/%EC%9A%B0%ED%85%8C%EC%BA%A0-5%EA%B8%B0-%EC%A7%80%EC%9B%90-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sun, 15 May 2022 16:56:02 GMT</pubDate>
            <description><![CDATA[<h3 id="우테캠-5기-안드로이드-지원">우테캠 5기 안드로이드 지원</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/adbb94b7-c0b8-442a-a1e2-14bf15d2f4f1/image.jpg" alt="">
2차 코테를 망치고 머릿속에서 지워버리려고 했으나... 자려고 누웠더니 자꾸만 생각나서 이불 속에서 폰으로 작성하는 후기. 안드로이드 모집은 이번이 처음이었으니 언젠가 6기 지원자들이 이 글을 발굴해낸다면 도움이 될지도...?</p>
<h3 id="1차-코딩테스트">1차 코딩테스트</h3>
<p>솔직히 난 1차가 붙을거라고도 생각 못했다. 난 파이썬으로 코테를 준비해 왔는데 코테 언어가 자바/코틀린으로 제한되었기 때문이다... 그치만 못먹어도 고니까 지원했다ㅎㅎ 파이썬으로 갈아타고 광명얻기 전 2개월 정도 자바로 알고리즘을 풀어온 적이 있었기 때문에 코테용 자바를 급하게 복습했다. 다행히 문제가 어렵지 않아 4문제 중 3문제를 풀 수 있었다. 람다식써서 정렬하는게 정확히 기억이 안나서 이 경우 저 경우 대입해보며 뻘짓하느라 시간을 좀 날리는 바람에 4번은 제대로 보지도 못했다. 3번까지의 난이도는 백준 실버1~2정도. 파이썬이었다면 4번까지 풀 수 있지 않았을까 싶다..   </p>
<h3 id="2차-과제테스트">2차 과제테스트</h3>
<p>필수로 구현해야 하는 액티비티가 2개, 선택 액티비티가 1개 있었다. 필수 액티비티 하나를 간신히 휘갈겨 놓으니 시간이 종료되었다. 시작하기 전에는 뷰모델, 데이터 바인딩 등 써서 똑똑하게 코딩해야지!! 하고 마음먹었는데 시간모자라서 구조고 나발이고 setText를 남발하는 자신의 모습을 볼 수 있었다.</p>
<p>2차테스트 들어가기 전에 프로그래머스 과제관에 있는 문제를 대충 훑어보고 들어갔는데, 구현해야 하는 화면과 기능은 꽤 비슷했던 것 같다...그치만 주어지는 초기 골격 자체가 너무 달라서 크게 도움되진 않았다. 그치만...대충 훑어보는게 아니라 직접 풀어보고 하나하나 꼼꼼히 분석했다면 도움됐을지도? 개인적으로 과제관 문제보단 쉬웠다. 탈락했지만 그래도 오랜만에 빡 집중해서 개발하니 좋았다. 취준하면서는 개발이랑 별 상관없어 보이는 것들을 준비해야 할 때가 많았어서... </p>
<p>새벽이라 글이 술술써지네...앞으로 회고는 새벽에 써야겠다. 벨로그도 빨리 앱이 개발되었으면 좋겠다. 웹 폰타자라 손가락이 아프다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVVM 패턴이란?]]></title>
            <link>https://velog.io/@jiwon_choi/MVVM-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jiwon_choi/MVVM-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sat, 14 May 2022 07:01:35 GMT</pubDate>
            <description><![CDATA[<p>MVVM 패턴은 프로그램을 설계하기 위한 하나의 방법론이다. 과거 구글의 코틀린 강좌를 들을 때도, 대놓고 MVVM 패턴이라고 명명해주진 않았지만 이 패턴을 사용해서 예제 앱을 만들었었다. </p>
<h3 id="mvvm의-구성-요소">MVVM의 구성 요소</h3>
<ul>
<li><p><code>Model</code>:데이터와 데이터에 관련된 행위를 모두 합쳐 Model이라 부른다.</p>
</li>
<li><p><code>View</code>: 사용자에게 화면으로 보여지는 모든 구조, 레이아웃을 View라 부른다. </p>
</li>
<li><p><code>View Model</code>: View Model은 View 에 보여져야하는 데이터와 명령들을 가지고 있다. View 가 ViewModle 을 observe(관찰) 하는 형태로 binding 되어 있기 때문에, data 의 갱신을 View 가 자동으로 받을 수 있게 되어있다. </p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/f04e0ca7-f06d-4966-ada0-c22d650a838a/image.png" alt=""></p>
</li>
</ul>
<h3 id="안드로이드에서의-mvvm">안드로이드에서의 MVVM</h3>
<p>ViewModel 과 View 는 MVP 패턴과 다르게 Many to One 관계를 가질 수 있다. 즉, 여러개의 Fragment 가 하나의 ViewModel 을 가질 수 있다...공유 뷰 모델 뭐 이런 개념이 있는 걸 생각하면 당연한 말 같기도 하다.</p>
<p>뷰가 사용자에게 보여지는 화면, 모델이 데이터라고 했을때, 중간에 낀 뷰 모델은 모델에서 가져온 데이터를 뷰가 사용할 수 있도록 가공하는 역할이다. 뷰는 뷰모델과의 DataBinding으로 인해 자동 갱신되므로 매우 편리하다. 
<img src="https://velog.velcdn.com/images/jiwon_choi/post/dfbd2e42-a873-4ebe-b7d3-0c0bbf2fadfb/image.png" alt="">
여기서 View가 ViewModel을 관찰할 때 그 관찰 대상이 되는 데이터 홀더 클래스가 LiveData이다. 위 그림을 보면 더 잘 이해할 수 있다.</p>
<h3 id="주의할-점">주의할 점</h3>
<p>뷰 모델은 Activity, Fragment, Context를 참조하면 안 된다. 뷰 모델은 액티비티나 프래그먼트보다 긴 생명주기를 가지고 있기 때문에, 이미 없어진 액티비티나 프래그먼트를 계속 참조하는 사태가 발생할 수 있기 때문이다. 쓸데없이 메모리를 차지하고 있게 되는 것이다.</p>
<h3 id="마치며">마치며..</h3>
<p>뷰 모델은 UI컨트롤러의 과도한 책임을 분담하여 클래스가 거대해지는 것을 방지하고, 유지보수, 재사용성 그리고 테스트 등을 용이하게 만들어 준다. 또한 뷰와 뷰모델을 바인딩하기 때문에 코드의 양이 줄어든다. </p>
<p>사실 MVVM은 강좌들으면서 개발했던 예제 앱과 개인 독학 프로젝트정도에서만 사용해봤는데, 실제 팀프로젝트에서도 어서 사용해보고 싶다. 개인적으로는 이번 GDSC의 여름 해커톤에서 기회가 있지 않을까 기대하고 있다.</p>
<blockquote>
<p>참고: <a href="https://salix97.tistory.com/266">https://salix97.tistory.com/266</a>
<a href="https://todaycode.tistory.com/33">https://todaycode.tistory.com/33</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[클린코드 17장 (끝)]]></title>
            <link>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-17%EC%9E%A5</link>
            <guid>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-17%EC%9E%A5</guid>
            <pubDate>Mon, 09 May 2022 05:55:52 GMT</pubDate>
            <description><![CDATA[<h1 id="17장-냄새와-휴리스틱">17장 냄새와 휴리스틱</h1>
<h2 id="🔎주석">🔎주석</h2>
<h3 id="부적절한-정보">부적절한 정보</h3>
<p>이슈 추적, 소스코드 관리 등 다른 시스템에 저장할 정보는 주석으로 적절하지 않다. 이러한 내용은 괜히 소스 코드만 번잡하게 만든다.</p>
<h3 id="쓸모-없는-주석">쓸모 없는 주석</h3>
<p>주석은 빨리 낡는다. 추후 쓸모 없어질 주석은 아예 달지 않는 편이 좋고, 쓸모 없어진 주석은 빨리 삭제해야 한다. </p>
<h3 id="중복된-주석">중복된 주석</h3>
<p>코드만으로 충분한데 구구절절 설명하는 주석이 중복된 주석이다. 이런 주석은 필요가 없다.</p>
<h3 id="주석-처리된-코드">주석 처리된 코드</h3>
<p>이런 주석이 나오면 신경이 아주 거슬린다. 누군가에게 필요한 코드라고 생각해서 아무도 삭제하지 않고, 주석코드는 그 자리에서 하루하루 낡아간다...흉물 그 자체다! 얼른 지워버리자.(아무리 그래도 흉물이라니..이 책 넘 막말심함ㅠㅠ)</p>
<h2 id="🔎환경">🔎환경</h2>
<h3 id="여러-단계의-빌드">여러 단계의 빌드</h3>
<p>필요한 파일을 찾느라 여기저기 뒤적일 필요가 없어야 한다. 한 명령으로 전체를 체크아웃해서 한 명령으로 빌드할 수 있어야 한다.</p>
<h3 id="여러-단계의-테스트">여러 단계의 테스트</h3>
<p>모든 단위 테스트는 한 명령으로 돌려야 한다. IDE에서 버튼 하나로 모든 테스트를 돌린다면 가장 이상적이다.</p>
<h2 id="🔎함수">🔎함수</h2>
<h3 id="너무-많은-인수">너무 많은 인수</h3>
<p>함수에서 인수 개수는 작을수록 좋다.</p>
<h3 id="출력-인수">출력 인수</h3>
<p>출력 인수는 직관을 정면으로 해친다. 쓰지 말자.</p>
<p><strong>※출력 인수란..?</strong>
내가 코테볼때마다 배열 값 변경 등에 매우매우 많이 썼다고 볼 수 있을 것 같은데...쉽게 말하면 변수 등을 인자로 받은 다음에 그 변수의 값을 함수에서 변경하는 것이다. </p>
<h3 id="플래그-인수">플래그 인수</h3>
<p>플래그 인수는 혼란을 초래하므로 피해야 마땅하다.
<del>얘도 코테칠때 참 많이 썼는데😂</del></p>
<h3 id="죽은-함수">죽은 함수</h3>
<p>아무도 호출하는 함수는 삭제한다. 소스 코드 관리 시스템이 모두 기억하므로 걱정할 필요 없다. </p>
<h2 id="🔎일반">🔎일반</h2>
<h3 id="한-소스-파일에-여러-언어를-사용한다">한 소스 파일에 여러 언어를 사용한다</h3>
<p>소스 파일 하나에 언어 하나만 사용하는 방식이 가장 좋다. 현실적으로는 여러 언어를 써야만 하는 일이 있지만...그래도 최대한 줄이도록 애써야 한다.</p>
<h3 id="당연한-동작을-구현하지-않는다">당연한 동작을 구현하지 않는다.</h3>
<p>당연한 동작을 구현하지 않으면 코드를 읽거나 사용하는 ㅏ람이 더 이상 함수 이름만으로 기능을 직관적으로 예상하기 어렵다. 최소 놀람의 원칙에 의거하여 함수나 클래스는 다른 프로그래머가 당연하게 여길 동작과 기능을 제공해야 한다. </p>
<h3 id="안전-절차-무시">안전 절차 무시</h3>
<p>안전 절차를 무시하면 위험하다. 예를 들어 컴파일러 경고 일부를 꺼버리면 빌드가 쉬워질지 모르지만 자칫하면 끝없는 디버깅에 시달릴 수 있다.</p>
<h3 id="중복">중복</h3>
<p>코드에서 중복을 발견할 때마다 추상화할 기회로 간주하라. 어디서든 중복을 발견하면 없애라.</p>
<h3 id="추상화-수준이-올바르지-못하다">추상화 수준이 올바르지 못하다.</h3>
<p>추상화로 개념을 분리할 때는 철저해야 한다. 모든 저차원 개념은 파생 클래스에 넣고, 모든 고차원 개념은 기초 클래스에 넣는다. 세부 구현과 관련한 변수, 함수 등은 기초 클래스에 넣으면 안된다. 기초 클래스는 구현 정보에 무지해야 한다. </p>
<h3 id="기초-클래스가-파생-클래스에-의존한다">기초 클래스가 파생 클래스에 의존한다.</h3>
<p>개념을 기초 클래스와 파생 클래스로 나누는 가장 흔한 이유는 두 개념을 분리해 독립성을 보장하기 위해서이다. 그러므로 기초 클래스가 파생 클래스를 사용한다면 뭔가 문제가 있다는 말이다. 기초 클래스는 파생 클래스를 아예 모르는 것이 바람직하다.</p>
<h3 id="과도한-정보">과도한 정보</h3>
<p>인터페이스를 매우 작게 그리고 매우 깐깐하게 만들어라. 정보를 제한해 결합도를 낮춰라.</p>
<h3 id="죽은-코드">죽은 코드</h3>
<p>죽은 코드란 실행되지 않는 코드를 가리킨다. 죽은 코드는 설계가 변해도 제대로 수정되지 않고 갈수록 악취를 풍긴다. 빨리 제거해주자.</p>
<h3 id="수직-분리">수직 분리</h3>
<p>변수와 함수는 사용되는 위치에 가깝게 정의한다. 지역 변수는 처음으로 사용되기 직전에 선언하며 수직으로 가까운 곳에 위치해야 한다. 선언한 위치로부터 몇백 줄 아래에서 사용하면 안된다. 비공개 함수 또한 호출하는 위치와 정의하는 위치를 가깝게 해야한다.</p>
<h3 id="일관성-부족">일관성 부족</h3>
<p>어떤 개념을 특정 방식으로 구현했다면 유사한 개념도 같은 방식으로 구현한다. 표기법은 신중하게 선택하며, 일단 선택한 표기법은 신중하게 따른다.</p>
<h3 id="잡동사니">잡동사니</h3>
<p>아무도 사용하지 않는 변수, 함수, 쓰레기 주석들은 코드만 복잡하게 만든다. 이러한 잡동사니는 깔끔하게 정리하자.</p>
<h3 id="인위적-결합">인위적 결합</h3>
<p>서로 무관한 개념을 인위적으로 결합하지 않는다. 예를 들어 일반적인 enum은 특정 클래스에 속할 이유가 없다. 함수, 상수, 변수를 선언할 때는 시간을 들여 올바른 위치를 고민한다. 그저 당장 편한 곳에 선언하고 내버려두면 안된다.</p>
<h3 id="기능-욕심">기능 욕심</h3>
<p>클래스 메서드는 자기 클래스의 변수와 함수에 관심을 가져야지 다른 클래스의 변수와 함수에 관심을 가져서는 안된다. </p>
<h3 id="선택자-인수">선택자 인수</h3>
<p><code>함수명(false)</code> 이런식으로 해서 인자값이 false냐 true냐에 따라 다르게 동작하게 하는거...별로라고 한다. 이렇게 구현하고 중복 없앴다구 좋아한적 많은디...( ._.) 암튼 이렇게 하지 말고 함수 여러개로 쪼개는 것이 바람직하다. 함수를 잘게 조사버리면 따로 구현한다고 해도 중복이 없을 것이다. </p>
<h3 id="모호한-의도">모호한 의도</h3>
<p>코드를 짤 때는 의도를 최대한 분명히 밝힌다. </p>
<h3 id="잘못-지운-책임">잘못 지운 책임</h3>
<p>코드 설계 시 코드 배치 위치를 결정하는 것은 중요하다.코드는 독자가 자연스럽게 기대할 위치에 배치한다. 때때로 개발자에게 편한 위치에 배치하기도 한다.</p>
<h3 id="부적절한-static-함수">부적절한 static 함수</h3>
<p>static 함수란? 재정의 불가능한 함수.
그런데 우리는 간혹 static으로 정의하면 안 되는 함수를 static으로 정의한다. static 함수를 정의할 때는 재정의할 가능성은 없는지 꼼꼼히 따져봐야 한다. </p>
<h3 id="서술적-변수">서술적 변수</h3>
<p>서술적인 변수 이름은 썩 괜찮다. 좋은 변수 이름은 어렵던 모듈을 읽기 쉽게 만들어 준다. </p>
<h3 id="이름과-기능이-일치하는-함수">이름과 기능이 일치하는 함수</h3>
<p>이름에 기능이 드러나도록 적절히 이름을 지어야 한다. </p>
<h3 id="알고리즘을-이해해라">알고리즘을 이해해라</h3>
<p>대다수 괴상한 코드는 사람들이 알고리즘을 충분히 이해하지 않은채 여기저기 if문과 플래그문을 난사해 코드를 돌린 탓이다. 구현이 끝났다고 선언하기 전에 함수가 돌아가는 방식을 확실히 이해하는지 확인하라.</p>
<h3 id="논리적-의존성은-물리적으로-드러내라">논리적 의존성은 물리적으로 드러내라.</h3>
<p>한 모듈이 다른 모듈에 의존한다면 물리적인 의존성도 있어야 한다.의존하는 모든 정보를 명시적으로 요청하는 편이 좋다. </p>
<h3 id="ifelse-혹은-switchcase문보다-다형성을-사용하라">If/Else 혹은 Switch/Case문보다 다형성을 사용하라.</h3>
<p>대다수 개발자가 switch 문을 사용하는 이유는 올바르기보다는 손쉬운 선택이기 때문이다. 따라서 그 이전에 다형성을 먼저 고려하라는 의미다.</p>
<h3 id="표준-표기법을-따르라">표준 표기법을 따르라</h3>
<p>팀은 업계 표준에 기반한 구현 표준을 따라야 하고, 팀이 정한 표준은 팀원들 모두가 따라야 한다. </p>
<h3 id="매직-숫자는-명명된-상수로-교체하라">매직 숫자는 명명된 상수로 교체하라.</h3>
<p>일반적으로 코드에서 숫자를 사용하지 말라는 규칙이다. 1,2,3같은 애들은 괜찮다. 하지만 3.141592...보다는 Math.PI가 낫다. </p>
<h3 id="정확하라">정확하라</h3>
<p>코드에서 뭔가를 결정할 때는 정확히 결정한다. 대충 결정해서는 안된다. 예를 들어 함수가 null을 반환할지도 모른다면 반드시 점검해야한다.</p>
<h3 id="관례보다-구조를-사용하라">관례보다 구조를 사용하라</h3>
<p>설계 결정을 강제할 때는 규칙보다 관례를 사용한다. 명명 관례도 좋지만 구조 자체로 강제하는게 더 좋다.  </p>
<h3 id="조건을-캡슐화하라">조건을 캡슐화하라</h3>
<p>if 문 안에 구구절절 넣지 말고 조건의 의도를 분명히 밝히는 함수로 표현하라.</p>
<h3 id="부정-조건은-피하라">부정 조건은 피하라</h3>
<p>부정 조건은 긍정 조건보다 이해하기 어렵다. 가능하면 긍정 조건으로 표현한다. </p>
<h3 id="함수는-한-가지만-해야-한다">함수는 한 가지만 해야 한다.</h3>
<p>함수는 한 가지만 수행해야 한다. 만약 함수가 여러가지 일을 한다면, 한 가지만 수행하는 좀 더 작은 함수 여럿으로 나눠야 마땅하다.</p>
<h3 id="숨겨진-시간적인-결합">숨겨진 시간적인 결합</h3>
<p>어떤 경우에는 함수들이 실행되는 순서가 중요하다. 이런 경우 함수 인수를 적절히 배치해 함수가 호출되는 순서를 명백히 드러낼 수 있도록 하자.</p>
<h3 id="일관성을-유지하라">일관성을 유지하라</h3>
<p>코드 구조를 잡을 때는 이유를 고민하라. 구조에 일관성이 없어 보인다면 남들이 맘대로 바꿔도 괜찮다고 생각한다. 시스템 전반에 걸쳐 구조가 일관성이 있다면 남들도 일관성을 따르고 보존한다.</p>
<h3 id="경계-조건을-캡슐화하라">경계 조건을 캡슐화하라.</h3>
<p>경계 조건은 코드 여기저기에서 처리하지 말고 한 곳에서 별도로 처리한다. 다시 말해, 코드 여기저기에 +1이나 -1을 흩어놓지 않는다.</p>
<h3 id="함수는-추상화-수준을-한-단계만-내려가야-한다">함수는 추상화 수준을 한 단계만 내려가야 한다.</h3>
<p>함수 내 모든 문장은 추상화 수준이 동일해야 한다. 그리고 그 추상화 수준은 함수 이름이 의미하는 작업보다 한 단계만 낮아야 한다. 추상화 수준이 막 뒤섞여 있다면 차근차근 분리해주자.</p>
<h3 id="설정-정보는-최상위-단계에-둬라">설정 정보는 최상위 단계에 둬라</h3>
<p>추상화 최상위 단계에 둬야 할 기본값 상수나 설정 관련 상수를 저차원 함수에 숨겨서는 안 된다. 대신 고차원 함수에서 저차원 함수를 호출할 때 인수로 넘긴다. </p>
<h3 id="추이적-탐색을-피하라">추이적 탐색을 피하라</h3>
<p>일반적으로 한 모듈은 주변 모듈을 모를수록 좋다.내가 아는 모듈이 연이어 자신이 아는 모듈을 따라가며 시스템 전체를 휘저을 필요가 없다. 자신이 직접 사용하는 모듈만 알면 충분하다.</p>
<h2 id="🔎자바">🔎자바</h2>
<h3 id="긴-import-목록을-피하고-와일드-카드를-사용하라">긴 import 목록을 피하고 와일드 카드를 사용하라</h3>
<p>패키지에서 클래스를 둘 이상 사용한다면 와일드 카드를 사용해 패키지 전체를 가져오라.</p>
<pre><code class="language-java">import package.*;</code></pre>
<p>당연한 소리같지만 경고메세지를 더블클릭해가며 임포트하다보면 쉽게 어기곤 하는 규칙이다...ㅋㅋㅋ</p>
<h3 id="상수는-상속하지-않는다">상수는 상속하지 않는다.</h3>
<p>어떤 프로그래머는 상수를 인터페이스에 넣은 다음 그 인터페이스를 상속해 해당 상수를 사용한다. 별로다... 차라리 static import를 사용하라.</p>
<p>※static import?
일반적인 import와는 다르게 메소드나 변수를 패캐지, 클래스명없이 접근가능하게 해준다.</p>
<h3 id="상수-대-enum">상수 대 Enum</h3>
<p>자바5는 enum을 제공한다. 마음껏 활용하라! public static final int라는 옛날 기교를 더 이상 사용할 필요가 없다.</p>
<h2 id="🔎이름">🔎이름</h2>
<h3 id="서술적인-이름을-사용하라">서술적인 이름을 사용하라</h3>
<p>이름은 성급하게 정하면 안된다. 서술적인 이름을 신중하게 골라라. 대충 정하기에 이름은 너무나도 중요하다..</p>
<h3 id="적절한-추상화-수준에서-이름을-선택하라">적절한 추상화 수준에서 이름을 선택하라</h3>
<p>구현을 드러내는 이름은 피하라. 작업 대상 클래스나 함수가 위치하는 추상화 수준을 반영하는 이름을 선택하라.</p>
<h3 id="가능하다면-표준-명명법을-사용하라">가능하다면 표준 명명법을 사용하라</h3>
<p>기존 명명법을 사용하는 이름은 이해하기 더 쉽다. 프로젝트에 유효한 의미가 담긴 이름을 많이 사용할수록 독자가 코드를 이해하기 쉬워진다.</p>
<h3 id="명확한-이름">명확한 이름</h3>
<p>함수나 변수의 목적을 명확히 밝히는 이름을 선택해라. </p>
<h3 id="긴-범위는-긴-이름을-사용하라">긴 범위는 긴 이름을 사용하라</h3>
<p>이름 길이는 범위 길이에 비례해야 한다. 범위가 5줄 안팍이라면 int i 같은 애들도 괜찮다. 오히려 이런애들이 긴 이름을 가지면 헷갈리기만 한다. 반대로 범위가 길어지면 긴 이름을 사용해야 한다.</p>
<h3 id="인코딩을-피해라">인코딩을 피해라</h3>
<p>인코딩=암호화
이름에 유형 정보나 범위 정보를 넣어서는 안된다. 오늘날 개발 환경에서는 이름 앞에 m_ 이나 f와 같은 접두어가 불필요하다.요즘은 세상이 좋아져서 IDE가 색깔 등으로 구분해준다.</p>
<p>저런 접두어를 붙여본적이 없는데...색깔이 없는 자바라니 대체 얼마나 옛날인거지!?</p>
<h3 id="이름으로-부수-효과를-설명하라">이름으로 부수 효과를 설명하라</h3>
<p>이름에 부수 효과를 숨기지 않는다. 실제로 여러 작업을 수행하는 함수에다 동사 하나만 달랑 사용하면 곤란하다.</p>
<h2 id="🔎테스트">🔎테스트</h2>
<h3 id="불충분한-테스트">불충분한 테스트</h3>
<p>테스트는 몇 개나 만들어야 충분할까? 불행히도 많은 프로그래머들이 <code>이 정도면 충분하지 않을까</code> 척도를 사용한다. 테스트 케이스는 잠재적으로 깨질 만한 부분을 모두 테스트해야 한다.</p>
<h3 id="커버리지-도구를-사용하라">커버리지 도구를 사용하라</h3>
<p>커버리지 도구는 테스트가 빠뜨리는 공백을 알려준다. 예를 들어 절대 실행되지 않는 if 블럭 같은 애들을 색깔로 표시해준다. </p>
<h3 id="사소한-테스트를-건너뛰지-마라">사소한 테스트를 건너뛰지 마라</h3>
<p>사소한 테스트는 짜기 쉽다. 사소한 테스트가 제공하는 문서적 가치는 구현에 드는 비용을 넘어선다.</p>
<h3 id="무시한-테스트는-모호함을-뜻한다">무시한 테스트는 모호함을 뜻한다.</h3>
<p>때로는 요구사항이 불분명하기에 프로그램이 돌아가는 방식을 확신하기 어렵다. 불분명한 요구사항은 테스트 케이스를 주석으로 처리하거나 테스트 케이스에 @Ignore를 붙여 표현한다. 불분명한 요구사항을 판별하는 기준은 테스트 케이스의 컴파일 여부에 달려있다.</p>
<h3 id="경계-조건을-테스트하라">경계 조건을 테스트하라</h3>
<p>경계 조건은 각별히 신경 써서 테스트한다. 알고리즘의 중앙 조건은 올바로 짜 놓고 경계 조건에서 실수하는 경우가 흔하다.</p>
<h3 id="버그-주변은-철저히-테스트하라">버그 주변은 철저히 테스트하라</h3>
<p>버그는 서로 모이는 경향이 있다. 한 함수에서 버그를 발견했다면 그 함수를 철저히 테스트하는 편이 좋다. </p>
<h3 id="실패-패턴을-살펴라">실패 패턴을 살펴라</h3>
<p>때로는 테스트 케이스가 실패하는 패턴으로 문제를 진단할 수 있다. 테스트 케이스를 최대한 꼼꼼히 짜라는 이유도 여기에 있다. </p>
<h3 id="테스트-커버리지-패턴을-살펴라">테스트 커버리지 패턴을 살펴라</h3>
<p>통과하는 테세트가 실행하는 코드들, 혹은 실행하지 않는 코드들을 살펴보면 실패하는 테스트 케이스의 실패 원인이 드러난다. 이 코드를 실행하면 실패하는군...을 알 수 있게 된다는 뜻.</p>
<h3 id="테스트는-빨라야-한다">테스트는 빨라야 한다.</h3>
<p>느린 테스트 케이스는 실행하지 않게 된다. 일정이 촉박하면 얘네들을 막 건너뛸 확률이 높다. 그러므로 테스트케이스가 빨리 돌아가게 최대한 노력한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs 정리]운영체제]]></title>
            <link>https://velog.io/@jiwon_choi/cs-%EC%A0%95%EB%A6%AC%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</link>
            <guid>https://velog.io/@jiwon_choi/cs-%EC%A0%95%EB%A6%AC%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C</guid>
            <pubDate>Mon, 02 May 2022 07:47:28 GMT</pubDate>
            <description><![CDATA[<h2 id="1-운영체제란-무엇인지-설명해주세요">1. 운영체제란 무엇인지 설명해주세요</h2>
<blockquote>
<p>운영체제 ( Operating System )는 컴퓨터 하드웨어와 소프트웨어 <strong>자원을 관리</strong>하는 시스템 소프트웨어입니다. Windows, Linux, Mac 등이 운영체제에 속합니다. </p>
</blockquote>
<h2 id="2-프로세스와-스레드의-차이를-설명해주세요">2. 프로세스와 스레드의 차이를 설명해주세요</h2>
<blockquote>
<p>프로세스는 운영체제로부터 자원을 할당받은 작업의 단위를 말합니다. 반면 스레드는 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위를 말합니다. 프로세스는 다른 프로세스의 메모리 공간에 접근할 수 없으나, 스레드는 Code, Data, Heap영역은 공유한다.(stack은 공유x)</p>
</blockquote>
<p>🔎스레드가 스택만 공유 안하는 이유는, 후입 선출이라는 스택의 특성상 공유했다가 너무 복잡해지기 때문이라고 한다..</p>
<h3 id="운영체제로부터-자원을-할당받은-작업의-단위">운영체제로부터 자원을 할당받은 작업의 단위</h3>
<p>cpu 스케줄링 처음 배울때 &#39;화장실에 줄 선 사람&#39; 비유를 통해 배웠다.</p>
<ul>
<li>교수님: 화장실 이용이 빠른 사람 먼저 화장실을 사용한다면, 화장실이 이용이 느린 사람은 영영 화장실을 이용 못 할지도 모릅니다... </li>
</ul>
<p>여기서 화장실이 자원, 사람이 프로세스이다.</p>
<h3 id="프로세스의-메모리-할당">프로세스의 메모리 할당</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/5181136c-28b1-4eeb-be9c-9a60c893e529/image.png" alt=""></p>
<h3 id="스레드의-메모리-할당">스레드의 메모리 할당</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/e9e2df61-39b0-4073-bb12-01d40ea0e8b8/image.png" alt=""></p>
<h2 id="3-멀티-스레딩의-장점과-단점을-설명해주세요">3. 멀티 스레딩의 장점과 단점을 설명해주세요</h2>
<blockquote>
<p>멀티 스레딩을 사용하면 자원 공유를 더 효율적으로 할 수 있습니다. 하지만, 단일 스레드에 비해 더 테스트, 디버깅이 어렵고 동기화에 주의하여 구현해야 합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/1d7bcf30-2565-4364-9c8a-e0d8732e7f35/image.png" alt="">
멀티 스레딩 : 하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 향상 시키는 것</p>
<h3 id="장점">장점</h3>
<ul>
<li>응답성: 응답 시간 단축</li>
<li>경제성: 자원 공유로 경제성 ↑</li>
<li>프로세스 간 통신 방법에 비해 스레드 간의 통신 방법이 훨씬 간단 </li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>단일 프로세스 시스템에선 효과 기대하기 힘듦</li>
<li>임계영역으로 인한 오류 가능성</li>
</ul>
<h2 id="4-멀티-프로세싱과-멀티-프로그래밍의-차이는">4. 멀티 프로세싱과 멀티 프로그래밍의 차이는?</h2>
<blockquote>
<p>다수의 프로세서가 서로 협력적으로 일을 처리하는 것이 멀티 프로세싱입니다. 하나의 프로세서가 하나의 프로세스를 수행하는 동안 다른 프로세스에 접근할 수 있도록 하는 방법이 멀티 프로그래밍입니다.</p>
</blockquote>
<h3 id="멀티-프로세싱">멀티 프로세싱</h3>
<p>다수의 <strong>프로세서</strong>가 서로 협력적으로 일을 처리하는 것
❗프로세스가 아니라 프로세서이다❗ 
프로세서는 cpu 등의 하드웨어를 의미하며, 프로세스는 프로세서에 의해 실행되고 있는 프로그램을 말한다. </p>
<h3 id="멀티-프로그래밍">멀티 프로그래밍</h3>
<p>하나의 프로세서가 하나의 프로세스를 수행하는 동안 다른 프로세스에 접근할 수 있도록 하는 방법. 멀티 프로그래밍은 입출력이 완료될 때까지 기다리는 시간을 버리지 말고 다른 프로세스를 처리할 수 있도록 해주는 것이다.</p>
<h2 id="5-스케줄러에-대해-설명해주세요">5. 스케줄러에 대해 설명해주세요</h2>
<blockquote>
<p>스케줄러란 어떤 프로세스에게 자원을 할당할지를 결정하는 운영체제 커널의 모듈을 지칭합니다. 스케줄러에는 장기, 단기, 중기 스케줄러가 있습니다. </p>
</blockquote>
<h3 id="장기-스케줄러">장기 스케줄러</h3>
<p>작업 스케줄러라고도 부름. 디스크에서 하나의 프로그램을 가져와 커널에 등록하면 프로세스가 되는데 이때 디스크에서 어떤 프로그램을 가져와 준비 큐에 넣을지 결정</p>
<h3 id="중기-스케줄러">중기 스케줄러</h3>
<p>메모리에 공간이 부족한 경우 어떤 프로세스를 swap out(메모리를 통째로 빼앗아 그 내용을 디스크의 스왑 영역에 저장)할지 결정</p>
<h3 id="단기-스케줄러">단기 스케줄러</h3>
<p>cpu 스케줄러라고도 부름. 다음으로 어떤 프로세스를 실행시킬지 결정</p>
<h2 id="6-context-switching이란-무엇인지-설명해주세요">6. Context Switching이란 무엇인지 설명해주세요</h2>
<blockquote>
<p>현재 진행하고 있는 Task의 상태를 저장하고 다음 진행할 Task의 상태 값을 읽어 적용하는 과정을 말합니다.</p>
</blockquote>
<h2 id="7-semaphore에-대해-설명해주세요">7. semaphore에 대해 설명해주세요</h2>
<blockquote>
<p>공유된 자원 속 하나의 데이터는 한 번에 하나의 프로세스만 접근할 수 있도록 제한해야 하는데, 이를 위해 고안된 것이 세마포어입니다. 세마포어는 세마포어는 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성합니다.</p>
</blockquote>
<p>동기화를 잘못하면 임계구역(Critical Section)에서 다양한 문제가 발생할 수 있다. (ex: 여러 스레드들의 읽기와 쓰기 작업이 겹쳐서 이상하게 꼬인다든지) 이를 위해 고안된 것이 바로 세마포어와 뮤텍스이다.</p>
<h3 id="뮤텍스">뮤텍스</h3>
<p>Key를 기반으로 한 상호배제기법
화장실 예제로 비유하자면... 공유 화장실에 들어가기 위해선 key가 필요하다. key를 가진 사람만 화장실에 들어갈 수 있고, 화장실 문짝에 키가 안달려 있으면 다른 사람은 대기해야 한다. </p>
<h3 id="세마포어">세마포어</h3>
<p>공통으로 관리하는 하나의 값을 이용해 상호배제를 달성
화장실 예제로 비유하자면... 화장실이 한 3개 있다고 치면, 문짝 앞 전광판에 사용 가능한 화장실의 수가 크게 나와있다. 사람들은 화장실 사용 가능 숫자가 1 이상이면 전광판의 숫자를 -1 하고 화장실에 들어가고, 나올때 전광판의 숫자를 +1 해준다.  </p>
<h2 id="8-힙-영역과-스택-영역의-차이점을-설명해주세요">8. 힙 영역과 스택 영역의 차이점을 설명해주세요</h2>
<blockquote>
<p>스택은 빠르지만, 메모리 제한이 있습니다. 힙은 메모리 크기 제한은 없으나, 메모리를 직접 관리해야하고 상대적으로 느립니다.</p>
</blockquote>
<h2 id="9-메모리-관리-전략에-대해-설명해주세요">9. 메모리 관리 전략에 대해 설명해주세요</h2>
<blockquote>
<p>메모리를 관리 기법 중 불연속 메모리 관리 기법으로 페이징과 세그멘테이션이 있습니다. 페이징은 페이지라는 고정 크기로 logical memory를 분리하고, 페이지와 같은 크기의 프레임으로 physical memory를 분리합니다.페이징을 통해 논리 메모리는 물리 메모리에 저장될 때 연속되어 저장될 필요가 없고 물리 메모리의 남는 프레임에 적절하게 배치됨으로 외부 단편화 해결합니다. 세그멘테이션은 페이징과는 달리 서로 다른 크기의 논리적 단위인 세그먼트로 메모리를 분리합니다. 메모리 사용 효율이 개선되고 동적 분할을 통한 오버헤드가 감소합니다. </p>
</blockquote>
<h3 id="단편화">단편화</h3>
<p>메모리 공간이 충분함에도 불구하고 프로세스가 메모리에 적재되지 못해 메모리가 낭비되는 현상</p>
<ul>
<li>외부 단편화: 가변 분할 방식에서 여유 공간들이 조각조각 흩어져 있어 낭비되는 현상</li>
<li>내부 단편화: 고정 분할 방식에서 프로세스가 실제 사용해야할 메모리보다 더 큰 메모리를 할당받아 메모리가 낭비되는 현상</li>
</ul>
<h3 id="메모리-관리-전략">메모리 관리 전략</h3>
<ul>
<li>연속 메모리 할당: 단편화 문제 발생<ul>
<li>최초 적합(가장 먼저 만나는 빈 공간에 적재)</li>
<li>최적 적합(가장 딱 맞는 빈 공간에 할당)</li>
</ul>
</li>
<li>불연속 메모리 할당<ul>
<li>페이징(외부 단편화 해소)</li>
<li>세그멘테이션(내부 단편화 해소)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바에서 큐의 사용]]></title>
            <link>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%ED%81%90%EC%9D%98-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@jiwon_choi/%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%ED%81%90%EC%9D%98-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Mon, 02 May 2022 05:33:31 GMT</pubDate>
            <description><![CDATA[<p>자바는 코테용으로 쓰는것도 아니고, 개발할 때는 큐를 쓸 일이 지금까지 별로 없었어서 사용법을 잘 모르고 있었는데 이참에 정리해본다.</p>
<pre><code class="language-java"> Queue&lt;int[]&gt; queue = new LinkedList&lt;&gt;(); //int 배열형 큐 선언(코테에서 가장 많이쓰게 될것...)
 Queue&lt;Integer&gt; queue = new LinkedList&lt;&gt;(); //int형 queue 선언 
Queue&lt;String&gt; queue = new LinkedList&lt;&gt;(); //String형 queue 선언</code></pre>
<p>값 추가하기</p>
<pre><code class="language-java">queue.add(1);
queue.add(new int [] {i,j});</code></pre>
<p>값 가져오기</p>
<pre><code class="language-java">int temp []=q.poll();</code></pre>
<p>큐에 값이 있는 동안 반복</p>
<pre><code class="language-java">while(!queue.isEmpty()) {
}</code></pre>
<p>일단은 요정도 알면 사용할 수 있을 듯하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[defaultdict이란? ]]></title>
            <link>https://velog.io/@jiwon_choi/defaultdict%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jiwon_choi/defaultdict%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 01 May 2022 11:36:26 GMT</pubDate>
            <description><![CDATA[<p>오늘은 고수가 23줄만에 푼 문제를 1시간 반 넘게 붙잡고 뻘짓한 슬픈 날이다. 나는 dfs 문제에 좀 약한 것 같다.... 아무튼 고수들의 코드를 보니 하나같이 defaultdict를 쓴 것을 볼 수 있었다. 나는 그냥 dict을 썼다가 key error를 213539번 마주한 상태였다. dict이면 dict이지 defaultdict는 대체 무엇이란 말인가?</p>
<h3 id="그래서-defaultdict이란">그래서 defaultdict이란?</h3>
<p>객체의 기본값을 미리 지정해 놓을 수 있는 딕셔너리이다.
그러니까 이걸 쓰면 그런 키 값 없어! 하고 뱉는 keyerror로부터 자유로워질 수 있다는 말이다. </p>
<pre><code class="language-python">from collections import defaultdict
data = defaultdict(int)</code></pre>
<p>예를 들어 이렇게 사용하면 값이 지정되지 않은 키의 값은 0으로 초기화된다.</p>
<pre><code class="language-python">from collections import defaultdict
data = defaultdict(list)</code></pre>
<p>list를 줬다면 빈 리스트로 초기화된다.</p>
<h3 id="참고">참고</h3>
<pre><code class="language-python">    r = defaultdict(list)
     #프로그래머스 고득점 kit-여행경로
    #i 항공에서 갈 수 있는 애들을 r[i]에 저장
    for i,j in tickets:
        r[i].append(j)</code></pre>
<p>딕셔너리 값으로 리스트를 넣어서 활용해본 적은 별로 없는 것 같은데, 오늘 다른사람들이 푼 걸 보니 이런 풀이도 코테에 꽤 유용한것 같다.</p>
<p><strong>+22.06.45 추가</strong>
defaultdict은 혁명이다. 실전 코딩테스트에서 정말 여러번 써먹었다. 고수들의 풀이를 안봤다면 무슨 일이 일어났을지...풀었다고 휙 치워버리지말고 고수의 풀이를 보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클린코드 16장]]></title>
            <link>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-16%EC%9E%A5</link>
            <guid>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-16%EC%9E%A5</guid>
            <pubDate>Tue, 26 Apr 2022 16:51:48 GMT</pubDate>
            <description><![CDATA[<h1 id="16장-serialdate-리팩터링">16장 SerialDate 리팩터링</h1>
<p>SerialDate는 날짜를 표현하는 자바 클래스다. 이 장에서는 SerialDate 클래스를 리팩터링한다.</p>
<h3 id="첫째-돌려보자">첫째, 돌려보자.</h3>
<p>SerialDateTest라는 클래스는 단위 테스트 케이스 몇 개를 포함한다. 돌려보면 실패하는 테스트 케이스는 없지만 살펴보면 모든 케이스를 점검하지 않는다. 그래서 저자는 독자적으로 단위 테스트 케이스를 구현한다. 그러자 경계 조건 오류가 존재하며, 논리적 오류로 인하여 결코 실행되지 않는 코드도 존재한다는 사실이 밝혀진다...해당 오류들을 모두 고쳐 테케를 모두 통과하게 만든 후 리팩터링에 들어가자.</p>
<h3 id="둘째-고쳐보자">둘째, 고쳐보자.</h3>
<h4 id="변경-이력-없애기">변경 이력 없애기</h4>
<p>이제는 소스 코드 제어 도구를 사용하므로 변경 이력은 없애도 좋다.</p>
<h4 id="import문-줄이기">import문 줄이기</h4>
<p>import 문들을 java.util.* 등으로 합쳐서 줄이자.</p>
<h4 id="javadoc-주석">javadoc 주석</h4>
<p>한 소스코드에 HTML 태그 등을 섞어서 사용하는게 못마땅하다. 차라리 주석 전부를 <code>&lt;pre&gt;</code>로 감싸는 게 좋다.</p>
<h4 id="서술적인-용어-사용하기">서술적인 용어 사용하기</h4>
<p>클래스 이름이 SerialDate인 이유는 &#39;일련번호(serial number)&#39;를 사용해 클래스를 구현했기 때문이다. 일련번호라는 정확하지 못하다. 차라리 &#39;상대 오프셋(relative offeset)&#39;이 낫다. 아니면 &#39;서수(ordinal)&#39;도 괜찮다. 또한 SerialDate라는 이름은 구현을 암시하는데 실상은 추상 클래스다. 그냥 Date가 더 적절하지만... Date라는 이름은 자바에 이미 너무 많으므로 앞으로는 SerialDate 대신 DayDate라는 이름을 사용한다.</p>
<h4 id="상수-열거형-보다-enum-사용">상수 열거형 보다 Enum 사용</h4>
<p>MonthConstants 를 상속하고 있는데 static final 상수 모음에 불과하다. Enum으로 바꿔서 사용하자.</p>
<h4 id="serialversionuid-삭제">serialVersionUID 삭제</h4>
<p>이 변수 값을 변경하면 이전 소프트웨어 버전에서 직렬화한 DayDate를 더 이상 인식하지 못한다. 그래서 일단인 이 변수를 없애기로 결정한다. </p>
<h4 id="주석-삭제하기">주석 삭제하기</h4>
<p>불필요한 주석들은 자리차지만 한다. 삭제한다.</p>
<h4 id="변수-위치-올바르게-변경">변수 위치 올바르게 변경</h4>
<p>변수들은 이상한 위치에 있지 말고 자신과 관련있는 클래스로 옮겨가야 한다. </p>
<h4 id="기반-클래스와-파생-클래스">기반 클래스와 파생 클래스</h4>
<p>일반적으로 부모 클래스는 자식 클래스를 몰라야 바람직하다. 그런데 원본 코드에서는 뭔가 이상하게 꼬여서 이 법칙이 지켜지지 않는다. 이를 고치기 위해 ABSTRACT FACTORY 패턴을 적용해 DayCateFactory를 만들었다. </p>
<h4 id="접근-제한자-변경">접근 제한자 변경</h4>
<p>굳이 공개할 필요 없는 pulbic 변수들을 private으로 변경한다. </p>
<h4 id="기본-생성자-삭제">기본 생성자 삭제</h4>
<p>기본 생성자는 이제 컴파일러가 기본으로 생성해준다. 필요없으니 삭제하자.</p>
<h4 id="final-키워드-제거">final 키워드 제거</h4>
<p>저자는 final 키워드가 코드를 복잡하게 만든다고 주장한다. 저자는 final 키워드가 잡아낼 오류를 다른 방법으로 잡아냈기 때문에, final이 남아있을 필요가 없다. 삭제한다.</p>
<h4 id="중첩-if-문-통합">중첩 if 문 통합</h4>
<p>if 문이 중첩되어 나올 경우 || 등으로 합친다.</p>
<h4 id="플래그-인수-삭제">플래그 인수 삭제</h4>
<p>한 메서드가 다른 메서드를 호출하며 플래그를 넘기는 부분이 있다. 일반적으로 메서드 인수로 플래그 인수는 바람직하지 못하다. 그래서 두 메서드 이름을 변경하고, 단순화하고, Month enum으로 옮긴다.</p>
<h4 id="모호한-이름-바꾸기">모호한 이름 바꾸기</h4>
<p>코드를 읽는 사람은 addDay(날짜)가 date 변수를 바꾸는 함수라고 생각할 확률이 높다. 이러한 모호함을 해결하기 위해 plusDays 와 plusMonth라는 이름을 선택한다. </p>
<h4 id="테스트-케이스에서만-호출-한다면-제거">테스트 케이스에서만 호출 한다면 제거</h4>
<p>테스트케이스에서만 사용되는 메서드가 있었다...테케와 메서드 모두 제거해준다.</p>
<h3 id="결론">결론</h3>
<p>우리는 또다시 보이스카우트 규칙을 지켰다. 테스트 커버리지가 증가했으며, 버그 몇 개를 고쳤고, 코드 크기도 줄었고, 코드가 더 명확해졌다. 시간이 걸렸지만 충분히 가치있는 작업이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클린코드 15장]]></title>
            <link>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-15%EC%9E%A5</link>
            <guid>https://velog.io/@jiwon_choi/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C-15%EC%9E%A5</guid>
            <pubDate>Mon, 25 Apr 2022 14:46:27 GMT</pubDate>
            <description><![CDATA[<h1 id="15장-junit-들여다보기">15장 JUnit 들여다보기</h1>
<blockquote>
<p>이 장에서는 JUnit 프레임워크에서 가져온 코드를 평가한다.</p>
</blockquote>
<h3 id="junit-프레임워크">JUnit 프레임워크</h3>
<p>우리가 살펴볼 모듈은 문자열 비교 오류를 파악할 때 유용한 <code>ComparisionCompactor</code>라는 모듈로, 두 문자열을 받아 차이를 반환한다. 예를 들어, ABCDE와 ABXDE를 받아 &lt;..B[x]D..&gt;를 반환한다.</p>
<pre><code class="language-java">package junit.framework;

public class ComparisonCompactor {

    private static final String ELLIPSIS = &quot;...&quot;;
    private static final String DELTA_END = &quot;]&quot;;
    private static final String DELTA_START = &quot;[&quot;;

    private int fContextLength;
    private String fExpected;
    private String fActual;
    private int fPrefix;
    private int fSuffix;

    public ComparisonCompactor(int contextLength, String expected, String actual) {
        fContextLength = contextLength;
        fExpected = expected;
        fActual = actual;
    }

    public String compact(String message) {
        if (fExpected == null || fActual == null || areStringsEqual()) {
            return Assert.format(message, fExpected, fActual);
        }

        findCommonPrefix();
        findCommonSuffix();
        String expected = compactString(fExpected);
        String actual = compactString(fActual);
        return Assert.format(message, expected, actual);
    }

    private String compactString(String source) {
        String result = DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
        if (fPrefix &gt; 0) {
            result = computeCommonPrefix() + result;
        }
        if (fSuffix &gt; 0) {
            result = result + computeCommonSuffix();
        }
        return result;
    }

    private void findCommonPrefix() {
        fPrefix = 0;
        int end = Math.min(fExpected.length(), fActual.length());
        for (; fPrefix &lt; end; fPrefix++) {
            if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) {
                break;
            }
        }
    }

    private void findCommonSuffix() {
        int expectedSuffix = fExpected.length() - 1;
        int actualSuffix = fActual.length() - 1;
        for (; actualSuffix &gt;= fPrefix &amp;&amp; expectedSuffix &gt;= fPrefix; actualSuffix--, expectedSuffix--) {
            if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) {
                break;
            }
        }
        fSuffix = fExpected.length() - expectedSuffix;
    }

    private String computeCommonPrefix() {
        return (fPrefix &gt; fContextLength ? ELLIPSIS : &quot;&quot;) + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
    }

    private String computeCommonSuffix() {
        int end = Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
        return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 &lt; fExpected.length() - fContextLength ? ELLIPSIS : &quot;&quot;);
    }

    private boolean areStringsEqual() {
        return fExpected.equals(fActual);
    }
}
</code></pre>
<p>전반적으로 훌륭한 모듈이다. 그렇지만 보이스카우트 규칙에 따르면 우리는 처음 왔을 때보다 더 깨끗하게 해놓고 떠나야 한다. 위 코드를 개선해 보자.</p>
<h3 id="접두어-없애기">접두어 없애기</h3>
<pre><code class="language-java">private int contextLength;
private String expected;
private String actual;
private int prefix;
private int suffix;</code></pre>
<p><code>private int fContextLength;</code> 오늘 날의 개발환경에서는 이렇게 f를 붙여서 변수 이름에 범위를 명시할 필요가 없다. 그러므로 접두어 f를 모두 제거하자.</p>
<h3 id="조건문을-캡슐화하자">조건문을 캡슐화하자.</h3>
<pre><code class="language-java">if (Expected == null || Actual == null || areStringsEqual()) {
            return Assert.format(message, Expected, Actual);
        }</code></pre>
<p>조건문을 메소드로 뽑아내 적절한 이름을 붙이자.</p>
<pre><code class="language-java">if (shouldNotCompact()) {
    return Assert.format(message, expected, actual);
}</code></pre>
<h3 id="이름을-명확히-붙이자">이름을 명확히 붙이자.</h3>
<pre><code class="language-java">String expected = compactString(fExpected);
String actual = compactString(fActual);</code></pre>
<p>이전</p>
<pre><code class="language-java">String compactExpected = compactString(expected);
String compactActual = compactString(actual);</code></pre>
<p>이후</p>
<h3 id="부정문을-긍정문으로-표현하자">부정문을 긍정문으로 표현하자.</h3>
<pre><code class="language-java">public String compact(String message) {
    if (canBeCompacted()) { //긍정문으로 바꿈
        findCommonPrefix();
        findCommonSuffix();
        String compactExpected = compactString(expected);
        String compactActual = compactString(actual);
        return Assert.format(message, compactExpected, compactActual);
} else {
    return Assert.format(message, expected, actual);
  }
}
private boolean canBeCompacted() {
    return expected != null &amp;&amp; actual != null &amp;&amp; !areStringsEqual();
}

</code></pre>
<h3 id="적절한-함수-이름을-붙이자">적절한 함수 이름을 붙이자.</h3>
<pre><code class="language-java">public String formatCompatedComparison(String message) {
}</code></pre>
<p><code>compact</code>보다는 <code>formatCompatedComparison</code>이라는 이름이 더 저갑하다.</p>
<h3 id="함수는-한-가지-일만-한다">함수는 한 가지 일만 한다.</h3>
<p><code>formatCompatedComparison</code>는 지금 여러 가지 일을 하고 있다.(형식 맞추기+압축하기) 한 가지 일만 하도록 함수를 둘로 쪼개자.</p>
<pre><code class="language-java">public String formatCompactedComparison(String message) {
    if (canBeCompacted()) {
        compactExpectedAndActual();
        return Assert.format(message, compactExpected, compactActual);
    } else {
        return Assert.format(message, expected, actual);
    }       
}

private compactExpectedAndActual() {
    findCommonPrefix();
    findCommonSuffix();
    compactExpected = compactString(expected);
    compactActual = compactString(actual);
}</code></pre>
<h3 id="함수를-일관적으로-사용하자">함수를 일관적으로 사용하자.</h3>
<pre><code class="language-java">private compactExpectedAndActual() {
    prefixIndex = findCommonPrefix();
    suffixIndex = findCommonSuffix();
    String compactExpected = compactString(expected);
    String compactActual = compactString(actual);
}

private int findCommonPrefix() {
    int prefixIndex = 0;
    int end = Math.min(expected.length(), actual.length());
    for (; prefixIndex &lt; end; prefixIndex++) {
        if (expected.charAt(prefixIndex) != actual.charAt(prefixIndex)) {
            break;
        }
    }
    return prefixIndex;
}

private int findCommonSuffix() {
    int expectedSuffix = expected.length() - 1;
    int actualSuffix = actual.length() - 1;
    for (; actualSuffix &gt;= prefixIndex &amp;&amp; expectedSuffix &gt;= prefix; actualSuffix--, expectedSuffix--) {
        if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix)) {
            break;
        }
    }
    return expected.length() - expectedSuffix;
}</code></pre>
<p>새 함수에서 마지막 두 줄은 변수를 반환하지만 첫째 줄과 둘째 줄은 반환값이 없다. 함수 사용 방식이 일관적이지 못하므로 <code>findCommonPrefix</code>와 <code>findCommonSuffix</code>를 변경해 접두어 값과 접미어 값을 반환한다.</p>
<h3 id="숨겨진-시각적인-결합">숨겨진 시각적인 결합</h3>
<pre><code class="language-java">private compactExpectedAndActual() {
    prefixIndex = findCommonPrefix();
    suffixIndex = findCommonSuffix(prefixIndex);
    String compactExpected = compactString(expected);
    String compactActual = compactString(actual);
}

private int findCommonSuffix(int prefixIndex) {
    int expectedSuffix = expected.length() - 1;
    int actualSuffix = actual.length() - 1;
    for (; actualSuffix &gt;= prefixIndex &amp;&amp; expectedSuffix &gt;= prefix; actualSuffix--, expectedSuffix--) {
        if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix)) {
            break;
        }
    }
    return expected.length() - expectedSuffix;
}</code></pre>
<p>만약 <code>findCommonPrefix</code>와 <code>findCommonSuffix</code>를 잘못된 순서로 호출하면 밤샘 디버깅이라는 고생문이 열린다. 그러므로 시간 결합을 외부에 노출하고자 <code>findCommonSuffix</code>를 고쳐 <code>prefixIndex</code>를 인수로 넘겼다.</p>
<h3 id="일관성을-유지하라">일관성을 유지하라</h3>
<pre><code class="language-java">private void findCommonPrefixAndSuffix() {
    findCommonPrefix();
    int suffixLength = 1;
    for (; suffixOverlapsPrefix(suffixLength); suffixLength++) {
        if (charFromEnd(expected, suffixLength) != charFromEnd(actual, suffixLength)) {
            break;
        }
    }
    suffixIndex = suffixLength;
}

private char charFromEnd(String s, int i) {
    return s.charAt(s.length() - i);
}

private boolean suffixOverlapsPrefix(int suffixLength) {
    return actual.length() = suffixLength &lt; prefixLength || expected.length() - suffixLength &lt; prefixLength;
}</code></pre>
<p>그런데 생각해보니 위의 방식이 지저분해 보여서 썩 마음에 들지 않는다..<code>findcommonPrefix</code>와 <code>findCommonSuffix</code>를 원래대로 되돌리고 <code>findCommonSuffix</code>라는 이름을 <code>findCommonPrefixSuffix</code>로 바꾸고, <code>findCOmmonPrefixAndSuffix</code>에서 가장 먼저 <code>findCommonPrefix</code>를 호출한다. 그러면 두 함수를 호출하는 순서가 앞서 고친 코드보다 훨씬 더 명확해진다.</p>
<h3 id="경계-조건을-캡슐화하라">경계 조건을 캡슐화하라</h3>
<p>코드를 고치고 나니까 suffixIndex가 실제로는 접미어 길이라는 사실이 드러난다. 이름이 적절하지 못하다는 말이다. 실제로 suffixIndex는 0에서 시작하지 않고 1에서 시작하므로 &quot;
length&quot;가 더 합당하다.</p>
<blockquote>
<p>코드 참고: <a href="https://han.gl/draPe">https://han.gl/draPe</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs 정리] 데이터베이스]]></title>
            <link>https://velog.io/@jiwon_choi/cs-%EC%A0%95%EB%A6%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@jiwon_choi/cs-%EC%A0%95%EB%A6%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Mon, 25 Apr 2022 06:39:30 GMT</pubDate>
            <description><![CDATA[<h2 id="1-정규화-과정에-대해-설명해주세요">1. 정규화 과정에 대해 설명해주세요</h2>
<blockquote>
<p>관계형 데이터베이스의 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스를 정규화라고 합니다. 보통 제 3정규형 과정까지 완료되었으면 정규화 되었다고 말합니다. 제 1 정규형은 도메인이 원자값만을 포함하게 만듭니다. 제 2 정규형은 부분적 함수 종속을 제거합니다. 제 3 정규형은 기본키에 대해 이행적 종속을 제거합니다. </p>
</blockquote>
<h3 id="제-1-정규형1nf-first-normal-form">제 1 정규형(1NF; First Normal Form)</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/43aedba8-7a10-4800-b96a-404dd74d04d4/image.png" alt="">
1NF를 만족하려면 도메인이 원자값이어야 한다. 위 테이블은 수강자 속성이 원자값이 아니어서 1NF가 아니다. </p>
<h3 id="제-2-정규형2nf-second-normal-form">제 2 정규형(2NF; Second Normal Form)</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/1add4c37-8722-4fc5-af6b-08c7ca0bba44/image.png" alt="">
2NF를 만족하려면 부분적 함수 종속을 제거해야 한다. 즉 완전 함수 종속이 되도록 해야 한다. 위 테이블은 2NF를 만족하지 않는다. 소속학과에는 어차피 학과장이 한 명씩 있다. 즉 학과장은 소속학과에 종속된다.</p>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/bb83bcd5-7be1-497a-9939-522fb4efcd6b/image.png" alt="">
이렇게 릴레이션을 구성하는게 바람직하다. (2NF 만족)</p>
<h3 id="제-3-정규형3nfthird-normal-form">제 3 정규형(3NF;Third Normal Form)</h3>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/7952b31e-98d3-4030-bfb0-ef3b7764386d/image.png" alt="">
🔎<strong>이행적 함수 종속</strong>: A→B 이고 B→C 일 때 A→C 인 관계
위 학과장-소속학과 같은 종속 관계가 한다리 건너 있는걸 이행적 함수 종속이라고 한다. 위 릴레이션 같은 경우에는 홍길동 → 컴퓨터과이고 컴퓨터과→공대일 때, 홍길동→공대인 관계가 성립하므로 이행적 함수 종속이 존재한다. <img src="https://velog.velcdn.com/images/jiwon_choi/post/1fadb74f-ec79-428b-9bdc-7a1aa265b941/image.png" alt="">
이렇게 쪼개주자.</p>
<p>참고-<a href="https://itwiki.kr/w/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4_%EC%A0%95%EA%B7%9C%ED%99%94">IT위키</a></p>
<h2 id="2-트랜잭션transaction이란-무엇인지-설명해주세요">2. 트랜잭션(Transaction)이란 무엇인지 설명해주세요</h2>
<blockquote>
<p>데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위를 트랜잭션이라고 합니다. </p>
</blockquote>
<h2 id="3-트랜잭션의-acid란">3. 트랜잭션의 ACID란?</h2>
<blockquote>
<p>트랜잭션은 ACID라는 4가지 특징을 가집니다. A는 Atomicity(원자성), C는 Consistency(일관성), I는 Isolation(독립성, 격리성), D는 Durability(지속성)을 의미합니다.</p>
</blockquote>
<h3 id="atomicity원자성">Atomicity(원자성)</h3>
<p>트랜잭션의 연산은 모두 반영되어야하며, 하나라도 실패하면 모두 취소되어야한다.</p>
<h3 id="consistency일관성">Consistency(일관성)</h3>
<p>트랜잭션을 성공하면 언제나 일관성있는 데이터베이스 상태로 변화한다.</p>
<h3 id="isolation독립성-격리성">Isolation(독립성, 격리성)</h3>
<p>둘 이상의 트랜잭션이 동시에 수행되는 경우 다른 트랜잭션의 연산에 끼어들수없다.</p>
<h3 id="durability지속성">Durability(지속성)</h3>
<p>완료된 트랜잭션은 영구적으로 반영되어야한다.</p>
<h2 id="4-sql-injection이-무엇인지-설명해주세요">4. SQL Injection이 무엇인지 설명해주세요</h2>
<blockquote>
<p>SQL Injection이란 해커에 의해 조작된 쿼리문이 DB에 그대로 전달되어 비정상적 명령을 실행시키는 공격 기법입니다.</p>
</blockquote>
<h2 id="5-데이터베이스에서-index란-무엇인지-설명">5. 데이터베이스에서 Index란 무엇인지 설명</h2>
<blockquote>
<p>인덱스란 추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/07df8faf-646e-4b21-b86e-626aaf9851f2/image.png" alt=""></p>
<h3 id="인덱스의-장점">인덱스의 장점</h3>
<ul>
<li>테이블을 조회하는 속도와 그에 따른 성능을 향상시킬 수 있다.</li>
<li>전반적인 시스템의 부하를 줄일 수 있다.<h3 id="인덱스의-단점">인덱스의 단점</h3>
</li>
<li>인덱스를 관리하기 위해 DB의 약 10%에 해당하는 저장공간이 필요하다.</li>
<li>인덱스를 관리하기 위해 추가 작업이 필요하다.</li>
<li>인덱스를 잘못 사용할 경우 오히려 성능이 저하되는 역효과가 발생할 수 있다.</li>
</ul>
<h2 id="6-rdbms와-nosql-의-차이를-설명하고-어떤-상황에서-사용하면-좋을지-예시를-들어주세요">6. RDBMS와 NoSQL 의 차이를 설명하고, 어떤 상황에서 사용하면 좋을지 예시를 들어주세요.</h2>
<blockquote>
<p>RDBMS는 관계형 데이터베이스 관리 시스템을 의미합니다. 반면 NoSQL은 테이블 간 관계를 정의하지 않습니다. RDBMS는 데이터 구조가 명확하여 변경될 여지가 없고 명확한 스키마가 중요한 경우 많이 사용합니다. NoSQL은 정확한 데이터 구조를 알 수 없고 데이터가 변경, 확장될 수 있는 경우 많이 사용합니다. </p>
</blockquote>
<p>🔎NoSQL은 key-value쌍으로 데이터를 저장한다. JSON 형식과 유사하다. 파이어베이스 또한 NoSQL의 일종이라 볼 수 있다. </p>
<h2 id="7-optimzer-란-무엇인가요">7. Optimzer 란 무엇인가요?</h2>
<blockquote>
<p>옵티마이저는 가장 효율적인 방법으로 SQL을 수행할 최적의 처리 경로를 생성해주는 DBMS의 핵심 엔진입니다. 개발자가 SQL을 작성하면, 옵티마이져는 여러 실행계획을 세운 뒤 가장 효율적인 실행계획으로 개발자의 SQL문을 재작성합니다. </p>
</blockquote>
<h2 id="8-샤딩sharding에-대해서-설명해주세요">8. 샤딩(Sharding)에 대해서 설명해주세요.</h2>
<blockquote>
<p>샤딩이란, 트래픽을 줄이기 위해 테이블을 수평으로 쪼개는 것을 의미합니다. 하지만 프로그래밍, 운영적인 복잡도는 더 높아지는 단점이 있어 주의해서 사용해야 합니다. </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiwon_choi/post/d867aa41-79c2-4c90-b186-83460d38cace/image.png" alt=""></p>
<h2 id="9-객체-관계-매핑-orm-이란-무엇인지-설명하고-장단점에-대해-설명해주세요">9. 객체 관계 매핑 (ORM) 이란 무엇인지 설명하고, 장단점에 대해 설명해주세요.</h2>
<blockquote>
<p>ORM이란, Object Relational Mapping, 즉 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해주는 것을 말합니다. ORM의 장점은, 개발자가 객체 지향 프로그래밍 하는데만 집중할수 있도록 하며 재사용성 및 유지보수의 편리성이 증가한다는 것입니다. ORM의 단점은, 사용하기는 편하지만 설계는 매우 신중하게 해야 하며 프로젝트의 복잡성이 커질 경우 난이도 또한 올라갈 수 있다는 점입니다. </p>
</blockquote>
<h3 id="🔎객체와-관계형-데이터베이스의-연결">🔎객체와 관계형 데이터베이스의 연결?</h3>
<ul>
<li>객체 지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용한다.</li>
<li>객체 모델과 관계형 모델 간에 불일치가 존재한다.</li>
<li>ORM을 통해 객체 간의 관계를 바탕으로 SQL을 자동으로 생성하여 불일치를 해결한다.</li>
</ul>
<h2 id="10-클러스터링과-리플리케이션-replication을-비교해주세요">10. 클러스터링과 리플리케이션 (Replication)을 비교해주세요.</h2>
<blockquote>
<p>클러스터링이란 여러 개의 DB를 수평적인 구조로 구축하는 방식입니다. 동기 방식으로 노드들 간의 데이터를 동기화합니다. 반면 리플리케이션은 여러 개의 DB를 권한에 따라 수직적인 구조(Master-Slave)로 구축하는 방식입니다. 비동기 방식으로 노드들 간의 데이터를 동기화합니다.</p>
</blockquote>
<h3 id="클러스터링clustering이란">클러스터링(Clustering)이란?</h3>
<p>여러 개의 DB를 수평적인 구조로 구축하는 방식이다.<br>동기화 방식(=데이터를 복제한 후 결과를 확인)이라 데이터 누락이 발생하지 않는다.</p>
<p><strong>장점</strong></p>
<ul>
<li>노드들 간의 데이터를 동기화하여 항상 일관성있는 데이터를 얻을 수 있다.</li>
<li>1개의 노드가 죽어도 다른 노드가 살아 있어 시스템을 계속 장애없이 운영할 수 있다.</li>
<li><em>단점*</em></li>
<li>여러 노드들 간의 데이터를 동기화하는 시간이 필요하므로 Replication에 비해 쓰기 성능이 떨어진다.</li>
<li>장애가 전파된 경우 처리가 까다로우며, 데이터 동기화에 의해 스케일링에 한계가 있다.</li>
</ul>
<h3 id="리플리케이션replication이란">리플리케이션(Replication)이란?</h3>
<p>여러 개의 DB를 권한에 따라 수직적인 구조(Master-Slave)로 구축하는 방식이다. 
비동기화 방식 (=Master에 수정사항을 반영하고 Slave에 데이터를 복사)라 누락이 발생할 수 있다.</p>
<p><strong>장점</strong></p>
<ul>
<li>DB 요청의 60~80% 정도가 읽기 작업이기 때문에 Replication만으로도 충분히 성능을 높일 수 있다.</li>
<li>비동기 방식으로 운영되어 지연 시간이 거의 없다.</li>
<li><em>단점*</em></li>
<li>노드들 간의 데이터 동기화가 보장되지 않아 일관성있는 데이터를 얻지 못할 수 있다.</li>
<li>Master 노드가 다운되면 복구 및 대처가 까다롭다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>