<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://bbubbush.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://bbubbush.github.io//" rel="alternate" type="text/html" /><updated>2020-01-20T07:50:34+00:00</updated><id>https://bbubbush.github.io//feed.xml</id><title type="html">제 컴에서는 되는데요? - 모두의 컴퓨터에서 되길 바랍니다;)</title><subtitle>넓고 얕은 Full-Stack 개발자 입니다</subtitle><author><name>bbubbush</name></author><entry><title type="html">Chapter9. 리두와 언두의 동작</title><link href="https://bbubbush.github.io//book_review/2020/01/17/Book_Review" rel="alternate" type="text/html" title="&lt;그림으로 공부하는 오라클구조&gt; Chapter9. 리두와 언두의 동작" /><published>2020-01-17T00:00:00+00:00</published><updated>2020-01-17T00:00:00+00:00</updated><id>https://bbubbush.github.io//book_review/2020/01/17/Book_Review</id><content type="html" xml:base="https://bbubbush.github.io//book_review/2020/01/17/Book_Review">&lt;h3 id=&quot;리두와-언두를-왜-배워야-하는가&quot;&gt;리두와 언두를 왜 배워야 하는가?&lt;/h3&gt;
&lt;p&gt;트랜잭션은 “ACID” 라는 특성을 만족합니다. 이 특성을 만족시키기 위해 리두(redo)와 언두(undo)는 빠질 수 없으므로 이들을 통해 트랜잭션의 특성을 깊게 이해할 수 있습니다. 우선 ACID가 무엇인지 살펴보겠습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Atomicity(원자성)&lt;/li&gt;
  &lt;li&gt;Consistency(일관성)&lt;/li&gt;
  &lt;li&gt;Isolation(고립성)&lt;/li&gt;
  &lt;li&gt;Durabliity(지속성)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위 4종류의 특성이 만족해야만 비로소 트랜잭션이라 할 수 있습니다. 조금 더 세부적으로 살펴보겠습니다.&lt;/p&gt;

&lt;h5 id=&quot;atomicity원자성&quot;&gt;Atomicity(원자성)&lt;/h5&gt;
&lt;p&gt;한 문장으로 이야기 하면 ‘All or nothing’ 입니다. 즉, 데이터가 변경된다면 전부 완료가 되거나 모두 실패해야한다는 뜻입니다. 예를 들어 회원가입할 때, 회원정보를 DB에 입력하는 것이 하나의 트랜잭션이라면 이름, 주소를 잘 입력했어도 휴대폰번호에 문자가 있어 오류가 발생했다면 이름과 주소 역시 입력되지 말아야 합니다.&lt;br /&gt;
따라서 &lt;strong&gt;원자성은 데이터 변경의 최소단위&lt;/strong&gt;라고 할 수 있습니다.&lt;/p&gt;

&lt;h5 id=&quot;consistency일관성&quot;&gt;Consistency(일관성)&lt;/h5&gt;
&lt;p&gt;데이터 모델 간의 일관성이 유지되어야 한다는 의미입니다. EMP 테이블과 SALARY 테이블이 EMP_ID로 연결되어 있을 때, EMP_ID의 타입이 NUMBER에서 VARCHAR2로 변경 된다면 두 테이블 모두 동일하게 변경된 내용이 적용되어야 합니다.&lt;/p&gt;

&lt;h5 id=&quot;isolation고립성&quot;&gt;Isolation(고립성)&lt;/h5&gt;
&lt;p&gt;트랜잭션 간 서로 독립적이여야 합니다. 회원가입 트랜잭션이 게시판 글쓰기 트랜잭션과 동시에 진행된다고 해서 회원가입 트랜잭션 결과에 영향이 있어서는 안되는 것 처럼 말입니다. 단, DBMS에 따라 고립의 레벨을 선택할 수 있습니다.&lt;/p&gt;

&lt;h5 id=&quot;durability지속성&quot;&gt;Durability(지속성)&lt;/h5&gt;
&lt;p&gt;커밋한 트랜잭션은 장애가 발생하더라도 데이터는 반드시 복구(지속)되어야 한다는 의미입니다. 커밋이 완료된 트랜잭션에 대해 신뢰할 수 있는 기반이 됩니다.&lt;/p&gt;

&lt;h3 id=&quot;지속성을-구현하기-위해서는&quot;&gt;지속성을 구현하기 위해서는&lt;/h3&gt;
&lt;p&gt;먼저 간단한 질문을 해보겠습니다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;“커밋한 데이터를 즉시 디스크에 기록하고 이력을 남겨둔다면 데이터의 지속성을 지킬 수 있지 않을까요?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;위 질문에 대해 전 “그렇다” 라고 생각합니다. 커밋하기 전에 이력을 남기고 디스크에 기록한다면 어떤 시점에 장애가 발생해도 지속성을 지킬 수 있다고 생각이 듭니다.&lt;/p&gt;

&lt;p&gt;하지만 책에서는 디스크의 특성을 들어 위 방법의 단점을 이야기합니다. 디스크 I/O는 대부분의 시간을 트랙을 찾는데 사용합니다. 그래서 변경이 있을 때 마다 디스크에 기록하면 커밋에 많은 시간을 소요하게 됩니다. 따라서 오라클은 이력을 보다 적극적으로 사용하여 성능과 지속성이라는 두 마리 토끼를 모두 잡는 노력을 합니다.&lt;/p&gt;

&lt;p&gt;어떤 방법으로 구현하는지는 아래 &lt;a href=&quot;#리두의-아키텍처&quot;&gt;리두의 아키텍처&lt;/a&gt;에서 자세히 설명하도록 하겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;리두와-언두의-개념&quot;&gt;리두와 언두의 개념&lt;/h3&gt;
&lt;p&gt;데이터를 복구한다는 것은 두 가지 입장에서 생각해 볼 수 있습니다. 하나는 데이터 변경이 일어났으나 과거의 데이터로 돌리는 경우이고, 다른 하나는 데이터 변경이 일어났으나 반영이 되지 않아 다시 적용시키는 경우입니다. 간단한 예를 들어보겠습니다.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;새해가 되어 기존 직원들의 연봉을 올려야 하니 SALARY 테이블의 연봉을 모두 500만원씩 올리려고 했는데, 실수로 5000만원씩 올리고 커밋이 되었다.&lt;/li&gt;
    &lt;li&gt;새해가 되어 기존 직원들의 연봉을 올려야 하니 SALARY 테이블의 연봉을 모두 500만원씩 올리려고 했는데, 반영되지 않아 1월달 급여가 작년도 기준으로 책정되어 있다.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;1번 상황을 롤백, 2번 상황을 롤포워드 라고 하며 롤백에는 언두 로그가, 롤포워드에는 리두 로그가 각각 필요합니다.&lt;br /&gt;
추가적으로 오라클은 시간의 흐름을 SCN(System Change Number)라는 개념으로 관리하고 있습니다. 따라서 SCN과 현재 데이터 정보, 리두, 언두 정보를 기반으로 데이터의 복구가 진행됩니다.&lt;/p&gt;

&lt;h3 id=&quot;리두의-아키텍처&quot;&gt;리두의 아키텍처&lt;/h3&gt;
&lt;p&gt;데이터의 변경은 캐시 위에서 이루어 집니다. 동시에 리두 로그 데이터가 생성되면 &lt;strong&gt;캐시 안의 리두로그버퍼에 쌓고&lt;/strong&gt; 커밋이 되지 않았어도 블록의 데이터 변경이 일어납니다. 이는 지속성을 구현하는 방법이며 동시에, 성능의 단점도 개선할 수 있습니다. 책의 그림을 먼저 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/book_review/01_oracle_architecture/2020-01-20_oracle_01.jpg&quot; alt=&quot;리두로그의 아키텍처&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;우선 LGWR, ARCH, 아카이브 리두 로그 파일 등 낯선 용어에 대해 설명하겠습니다.
LGWR는 리두 로그를 디스크에 기록하는 역할을 합니다. ARCH 프로세스는 리두 로그 파일이 가득 차기 전에 비교적 장기간 보관할 수 있는 아카이브 리두 로그 파일에 옮기는 역할을 합니다. 마지막으로 아카이브 리두 로그 파일은 리두 로그를 장기간 보관하기 위한 파일입니다.&lt;/p&gt;

&lt;p&gt;위 내용을 바탕으로 리두 아키텍처를 요약해본다면 데이터의 변경이 일어나면 캐시 내 리두 로그 버퍼에 쌓입니다. 리두 로그 버퍼에 특정 조건이 만족하면 LGWR가 디스크 내의 리두 로그 파일에 로그를 쌓습니다. 리두 로그 파일은 캐시보다 안전하지만 방대한 양의 로그를 쌓기에는 적합하지 않습니다. 따라서 장기간 보관할 수 있는 아카이브 리두 로그 파일로 데이터를 옮겨야 합니다. 이 작업은 ARCH 프로세스가 담당하여 진행합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;단, 성능의 단점을 개선하기 위해 위 프로세스는 커밋과 연동하여 진행하지 않습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;언두의-아키텍처&quot;&gt;언두의 아키텍처&lt;/h3&gt;
&lt;p&gt;과거의 상태로 데이터를 돌리기 위한 언두는 수동과 자동이 있습니다. 자동 언두가 편리하면서 자주 사용되므로 이를 중심으로 기술하겠습니다.&lt;/p&gt;

&lt;p&gt;데이터가 변경되면 언두 정보가 생성되어 세그먼트에 보관됩니다. 해당 세그먼트를 관리하는 테이블 스페이스를 언두 테이블 스페이라고 합니다. 
언두 테이블 스페이스는 다른 테이블 스페이스와 달리 구조가 독특합니다. 링 버퍼 형태로 순차적으로 데이터를 쌓는데 링이 가득 차면 가장 처음 입력된 데이터의 버퍼에 덮어씌웁니다. 다만, 커밋하지 않은 데이터는 덮지 않습니다.&lt;/p&gt;

&lt;p&gt;위와 같은 방식으로 언두는 과거의 데이터로 돌아갈 수 있게 됩니다.&lt;/p&gt;

&lt;h3 id=&quot;요약&quot;&gt;요약&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;리두는 오래된 데이터를 최신 데이터로 만들기 위해 존재합ㄴ다.&lt;/li&gt;
  &lt;li&gt;언두는 최신 데이터를 오래된 데이터로 만들기 위해 존재한다.&lt;/li&gt;
  &lt;li&gt;읽기 일관성을 위해 언두를 사용한다.&lt;/li&gt;
  &lt;li&gt;ORA-1555 오류가 발생하면 우선적으로 undo_retention이나 언두 테이블 스페이스 크기를 튜닝할 것을 검토한다.&lt;/li&gt;
  &lt;li&gt;장비에 장애가 발생하거나 인스턴스가 비정상 종료했을 경우, 리두와 언두를 사용해 데이터를 복구하고 커밋하지 않은 데이터의 롤백을 수행한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/book_review/01_oracle_architecture/2020-01-20_oracle_02.jpg&quot; alt=&quot;요약&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;오늘도 어김없이 감사합니다 ;)&lt;/p&gt;</content><author><name>bbubbush</name></author><category term="Book_Review" /><summary type="html">리두와 언두를 왜 배워야 하는가? 트랜잭션은 “ACID” 라는 특성을 만족합니다. 이 특성을 만족시키기 위해 리두(redo)와 언두(undo)는 빠질 수 없으므로 이들을 통해 트랜잭션의 특성을 깊게 이해할 수 있습니다. 우선 ACID가 무엇인지 살펴보겠습니다.</summary></entry><entry><title type="html">Chapter4. 결과를 전달하는 HTTP 상태 코드</title><link href="https://bbubbush.github.io//book_review/2019/12/24/Book_Review" rel="alternate" type="text/html" title="&lt;그림으로 배우는 Http Network Basic&gt; Chapter4. 결과를 전달하는 HTTP 상태 코드" /><published>2019-12-24T00:00:00+00:00</published><updated>2019-12-24T00:00:00+00:00</updated><id>https://bbubbush.github.io//book_review/2019/12/24/Book_Review</id><content type="html" xml:base="https://bbubbush.github.io//book_review/2019/12/24/Book_Review">&lt;p&gt;“404” 를 보시면 어떤 생각이 드시나요? 개발자는 물론이고 개발에 관심 없는 분이여도 숫자 4가 주는 부정한 기운에 선뜻 좋은 의미로 느껴지진 않습니다. 하지만 어떤 미신이든 유래를 알고 나면 시시해지기 마련입니다.&lt;/p&gt;

&lt;p&gt;한자에서는 4는 ‘죽은 사’와 동일한 발음으로 사용되어 부정적인 의미로 사용되며, 한자 문화권인 한국 역시 동일하게 생각하였습니다. 일본에서도 4는 ‘시’로 발음이 되며 이는 죽음을 의미하는 단어와 같은 발음으로 읽힙니다.&lt;/p&gt;

&lt;p&gt;마찬가지로 개발을 처음 할 때 느끼는 404에 대한 두려움은 원인을 이해함으로써 극복할 수 있습니다.&lt;/p&gt;

&lt;p&gt;서버에서 전달되는 response에는 status 라는 결과의 상태를 표시하는 값이 있습니다. 404로 이에 대한 한 종류에 속합니다. 아래는 각 상태값의 대분류와 소분류의 의미들을 표기한 내용입니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;1xx : request를 처리하는 중&lt;/p&gt;

  &lt;p&gt;2xx : request를 정상적으로 처리&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;200 OK: request를 정상적으로 처리&lt;/li&gt;
    &lt;li&gt;204 Not Content : request를 정상적으로 처리하였으나 돌려줄 response body 값이 없음&lt;/li&gt;
    &lt;li&gt;206 Partial Content : 서버가 부분적인 request를 받았을 경우, 해당 상태로 응답&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;3xx : request를 완료하기 위해 브라우저 측에서 추가 작업이 필요&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;301 Moved Permanently : request 된 URI가 새로운 URI로 ‘완전히’ 변경된 경우&lt;/li&gt;
    &lt;li&gt;302 Found : request 된 URI가 새로운 URI로 ‘임시적인’ 변경이 된 경우&lt;/li&gt;
    &lt;li&gt;303 See Other : 302와 동일하지만, ‘redirect 장소를 GET으로 얻어야 한다고 명확하게 정의’ 된 점이 다름&lt;/li&gt;
    &lt;li&gt;304 Not Modified : 이전의 동일한 요청과 비교하여 변화가 없는 경우. 단 시간의 반복적인 요청에 대한 해결방법이 된다.&lt;/li&gt;
    &lt;li&gt;307 Temporary Redirect : 302와 동일하나 Method의 변경을 금지&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;4xx : 클라이언트의 잘못된 요청&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;400 Bad Request : request가 잘못 요청된 경우. 브라우저는 200과 동일하게 취급&lt;/li&gt;
    &lt;li&gt;401 Unauthorized : request에 HTTP 인증 정보가 필요한 경우&lt;/li&gt;
    &lt;li&gt;404 Not Found : request한 리소스가 없는 경우&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;5xx : 서버의 처리 중 오류가 발생&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;500 Internal Server Error : 서버에서 처리하는 중 에러가 발생한 경우&lt;/li&gt;
    &lt;li&gt;503 Service Unavaliable : 서버가 과부하거나 점검 중이여서 request를 처리할 수 없는 경우&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;포스팅의 서두에 언급된 404 상태코드는 &lt;strong&gt;Request에 요청된 리소스가 없는 경우&lt;/strong&gt; 입니다. 즉, 요청하는 URI정보를 검토해보거나, 서버측헤 해당 URI가 존재하는지 확인해보는 방법을 통해 해결할 수 있습니다. 뿐만 아니라 위 상태 코드들은 개발하면서 자주 만나게 될 테니 본인만의 방법으로 기억해두면 트러블 슈팅을 보다 빠르게 할 수 있습니다.&lt;/p&gt;

&lt;h5 id=&quot;결론&quot;&gt;결론&lt;/h5&gt;

&lt;p&gt;웹 개발 시에 오류가 발생하면 [개발자 도구 - 네트워크] 탭을 통해 각 request와 response의 상태값을 확인하여 무엇이 문제인지 유추하는 습관을 기르면 좋다!!&lt;/p&gt;

&lt;p&gt;오늘도 읽어주셔서 감사합니다 : )&lt;/p&gt;</content><author><name>bbubbush</name></author><category term="Book_Review" /><summary type="html">“404” 를 보시면 어떤 생각이 드시나요? 개발자는 물론이고 개발에 관심 없는 분이여도 숫자 4가 주는 부정한 기운에 선뜻 좋은 의미로 느껴지진 않습니다. 하지만 어떤 미신이든 유래를 알고 나면 시시해지기 마련입니다.</summary></entry><entry><title type="html">URL과 URI의 차이점을 무엇일까?</title><link href="https://bbubbush.github.io//tip/2019/12/19/Tip" rel="alternate" type="text/html" title="&lt;개발 Tip&gt; URL과 URI의 차이점을 무엇일까?" /><published>2019-12-19T00:00:00+00:00</published><updated>2019-12-19T00:00:00+00:00</updated><id>https://bbubbush.github.io//tip/2019/12/19/Tip</id><content type="html" xml:base="https://bbubbush.github.io//tip/2019/12/19/Tip">&lt;p&gt;최근에 부족한 네트워크의 기초를 공부하다 URL과 URI의 차이를 알게되어 공유하고 자 글을 남기게 되었습니다.&lt;/p&gt;

&lt;p&gt;우선 각 용어의 약어는 아래와 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;URL : Uniform Resouce Locator&lt;/p&gt;

  &lt;p&gt;URI : Uniform Resouce Identifier&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;굳이 해석을 하자면 ‘통일된 자원 위치’와 ‘통일된 자원 식별자’ 따위로 해석된다.&lt;/p&gt;

&lt;p&gt;따라서 URL은 자원의 위치를 기존의 정해논 규칙대로 표시하는 방법이고, URI는 자원의 구분자를 정해진 형태논 규칙대로 표시하는 방법이다.&lt;/p&gt;

&lt;p&gt;정리하자면 URL은 단순히 파일의 위치를 표시한다면, URI는 파일의 위치일수도, 이름일수도 있는 파일의 식별자를 표시한다. &lt;strong&gt;URI가 URL을 포함하는 개념&lt;/strong&gt;이라고 생각하면 좋다. URI에 포함 되는 식별자는 구글링을 조금 더 하면 확인 할 수 있다.&lt;/p&gt;

&lt;p&gt;끝!!&lt;/p&gt;</content><author><name>bbubbush</name></author><category term="Tip" /><summary type="html">최근에 부족한 네트워크의 기초를 공부하다 URL과 URI의 차이를 알게되어 공유하고 자 글을 남기게 되었습니다.</summary></entry><entry><title type="html">무상태 프로토콜이란 무엇인가?</title><link href="https://bbubbush.github.io//tip/2019/12/18/Tip" rel="alternate" type="text/html" title="&lt;개발 Tip&gt; 무상태 프로토콜이란 무엇인가?" /><published>2019-12-18T00:00:00+00:00</published><updated>2019-12-18T00:00:00+00:00</updated><id>https://bbubbush.github.io//tip/2019/12/18/Tip</id><content type="html" xml:base="https://bbubbush.github.io//tip/2019/12/18/Tip">&lt;p&gt;‘무상태 프로토콜은 무엇입니까??’&lt;/p&gt;

&lt;p&gt;올해 TOPCIT 문제 중 하나였다. 듣기는 했는데 어떻게 설명해야 할지 몰라 답을 비우고 나오게 되었다. 시간이 흘러 최근에 네트워크 기초에 대해 공부하며 알게된 지식을 남기기 위해 포스팅을 하게 되었다.&lt;/p&gt;

&lt;p&gt;HTTP는 기본적으로 무상태 프로토콜을 기반으로 한다. 프로토콜은 ‘규약’, ‘약속’인데 무상태는 그럼 무엇인가?&lt;/p&gt;

&lt;p&gt;통신은 기본적으로 클라이언트와 서버가 필요하다. 양 측이 통신을 하며 서로에 대한 상태정보, 세션 등을 요구하지 않는 것이 무상태의 정의가 된다. 이는 서버 디자인을 단순하게 만들어 주며, 리소스의 소비를 억제해준다. 다만 인증정보에 대해 매 요청마다 인증을 해야하는 불편이 발생할 수 있다.&lt;/p&gt;

&lt;p&gt;무상태 프로토콜의 이런 단점은 쿠키를 통해 극복한다. HTTP 통신을 할 때, 최초에 서버가 response를 보낼 때 쿠키정보를 클라이언트에게 전달하고, 클라이언트는 서버와 다시 통신할 때 쿠키정보를 헤더에 담아 전달한다. 서버는 이를 통해 클라이언트의 정보를 확인하게 된다.&lt;/p&gt;

&lt;h5 id=&quot;결론--무상태-프로토콜은-별도로-상태값을-관리하지-않아-리소스-입장에서-유리하지만-이전-상태값을-기억못하므로-발생하는-인증-등의-단점이-발생한다--이를-쿠키로-극복하는-것이-무상태-프로토콜이다&quot;&gt;결론 : 무상태 프로토콜은 별도로 상태값을 관리하지 않아 리소스 입장에서 유리하지만, 이전 상태값을 기억못하므로 발생하는 인증 등의 단점이 발생한다.  이를 쿠키로 극복하는 것이 무상태 프로토콜이다.&lt;/h5&gt;</content><author><name>bbubbush</name></author><category term="Tip" /><summary type="html">‘무상태 프로토콜은 무엇입니까??’</summary></entry><entry><title type="html">Chapter8. 오라클의 대기와 락</title><link href="https://bbubbush.github.io//book_review/2019/12/12/Book_Review" rel="alternate" type="text/html" title="&lt;그림으로 공부하는 오라클구조&gt; Chapter8. 오라클의 대기와 락" /><published>2019-12-12T00:00:00+00:00</published><updated>2019-12-12T00:00:00+00:00</updated><id>https://bbubbush.github.io//book_review/2019/12/12/Book_Review</id><content type="html" xml:base="https://bbubbush.github.io//book_review/2019/12/12/Book_Review">&lt;p&gt;데이터 관리에 있어 대게 두 가지 의견이 상충됩니다. 하나는 데이터 변경에 대한 유연한 공간확보이고, 다른 하나는 잉여공간의 관리 입니다. 예를 들어 100개의 데이터를 배열에 담아야 한다면 여러분은 배열의 크기를 어떻게 설정하시겠습니까? 혹은 어떤 방법을 사용해서 자료구조를 만드시겠습니까? 100개의 데이터가 줄어들수도, 늘어날수도, 변경될 수도 있다면 더 깊게 고민해봐야 할 것입니다.&lt;/p&gt;

&lt;p&gt;아래는 오라클이 사용하는 데이터 구조입니다. 작은 단위에서 큰 단위로 흘러가고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;물리구조 : Block -&amp;gt; Data File&lt;/p&gt;

  &lt;p&gt;논리구조 : Block(물리) -&amp;gt; Oracle Block -&amp;gt; Extent -&amp;gt; Segment -&amp;gt; Table Space&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/book_review/01_oracle_architecture/2019-12-11_oracle_01.png&quot; alt=&quot;오라클 자료구조&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;h5 id=&quot;block&quot;&gt;Block&lt;/h5&gt;

&lt;p&gt;위 스크린샷만 이해하면 이번 챕터를 졸업한 것 입니다. 블록의 크기는 2KB, 4KB, 8KB 등으로 설정 되며, 내부에는 관리용 공간과 데이터 저장공간을 분리하여 사용합니다. 특히 데이터를 저장할 때는 여분의 공간을 비워 데이터 변경에 대해 유연함을 확보하고 있습니다.&lt;/p&gt;

&lt;h5 id=&quot;extent&quot;&gt;Extent&lt;/h5&gt;

&lt;p&gt;여러개의 블록은 하나의 익스텐트를 구성합니다(그림 ‘오라클 자료구조’ 하단 참조). 익스텐트는 ‘연속된 블록’의 집합이라는 것이 중요합니다. 블록 내부에는 빈 공간이 존재하지만 블록을 연속적으로 관리함으로 인해 불필요한 I/O를 줄일 수 있습니다. 또한 각 익스텐트의 첫 위치와 블록의 개수만 파악해도 데이터를 관리할 수 있어 최소한의 관리정보를 유지하게 됩니다.&lt;/p&gt;

&lt;p&gt;#####Segment&lt;/p&gt;

&lt;p&gt;세그먼트는 넓은 의미에서는 설명하면 여러 익스텐트의 집합이지만, 좁은 의미에서는 테이블이나 인덱스가 관리되는 공간으로 사용됩니다. 따라서 사용자가 직접적인 조작이 가능하며(Ex 테이블의 생성과 삭제) 이에 따라 세그먼트를 관리하는 테이블 스페이스의 공간이 변화하게 됩니다.  또한 데이터를 정렬하는 세그먼트, 과거 데이터를 보관하는 세그먼트 등도 존재합니다. 테이블의 정보가 서로 다른 테이블 스페이스에 나눠 기록될 수 없듯, 세그먼트는 하나의 테이블 스페이스에 속하게 됩니다.&lt;/p&gt;

&lt;h5 id=&quot;table-space&quot;&gt;Table Space&lt;/h5&gt;

&lt;p&gt;연관되어 있는 세그먼트의 집합입니다. 리두, 언두 세그먼트를 관리하는 테이블 스페이스, 데이터를 관리하는 테이블 스페이스, 데이터베이스를 관리하는 테이블 스페이스 등 다양한 형태로 나눠져 있습니다. 실제 물리적인 파일(.dbf .ora 등)은 테이블스페이스와 대응이 됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;테이블스페이스 + 리두 로그 파일 + 컨트롤파일 = 데이터베이스&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;결론&quot;&gt;결론&lt;/h3&gt;

&lt;p&gt;오라클의 자료구조는 &lt;strong&gt;‘최소한의 공간 낭비로 최대의 데이터의 유연성을 확보하는 것’&lt;/strong&gt;에 초점을 두었다고 생각합니다. 책에는 ROW ID에 대한 설명, 실제로 테이블 스페이스부터 만드는 과정 들이 포함되어 있지만 결국, 오라클 자료구조가 어떻게 동작하는지 설명하기 위한 수단에 지나지 않습니다. 블록부터 테이블 스페이스까지의 개념을 이해하면 해당 챕터를 이해했다고 생각해도 됩니다.&lt;/p&gt;

&lt;p&gt;오늘도 어김없이 감사합니다 ;)&lt;/p&gt;</content><author><name>bbubbush</name></author><category term="Book_Review" /><summary type="html">데이터 관리에 있어 대게 두 가지 의견이 상충됩니다. 하나는 데이터 변경에 대한 유연한 공간확보이고, 다른 하나는 잉여공간의 관리 입니다. 예를 들어 100개의 데이터를 배열에 담아야 한다면 여러분은 배열의 크기를 어떻게 설정하시겠습니까? 혹은 어떤 방법을 사용해서 자료구조를 만드시겠습니까? 100개의 데이터가 줄어들수도, 늘어날수도, 변경될 수도 있다면 더 깊게 고민해봐야 할 것입니다.</summary></entry><entry><title type="html">Chapter7. 오라클의 데이터 구조</title><link href="https://bbubbush.github.io//book_review/2019/12/11/Book_Review" rel="alternate" type="text/html" title="&lt;그림으로 공부하는 오라클구조&gt; Chapter7. 오라클의 데이터 구조" /><published>2019-12-11T00:00:00+00:00</published><updated>2019-12-11T00:00:00+00:00</updated><id>https://bbubbush.github.io//book_review/2019/12/11/Book_Review</id><content type="html" xml:base="https://bbubbush.github.io//book_review/2019/12/11/Book_Review">&lt;p&gt;데이터 관리에 있어 대게 두 가지 의견이 상충됩니다. 하나는 데이터 변경에 대한 유연한 공간확보이고, 다른 하나는 잉여공간의 관리 입니다. 예를 들어 100개의 데이터를 배열에 담아야 한다면 여러분은 배열의 크기를 어떻게 설정하시겠습니까? 혹은 어떤 방법을 사용해서 자료구조를 만드시겠습니까? 100개의 데이터가 줄어들수도, 늘어날수도, 변경될 수도 있다면 더 깊게 고민해봐야 할 것입니다.&lt;/p&gt;

&lt;p&gt;아래는 오라클이 사용하는 데이터 구조입니다. 작은 단위에서 큰 단위로 흘러가고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;물리구조 : Block -&amp;gt; Data File&lt;/p&gt;

  &lt;p&gt;논리구조 : Block(물리) -&amp;gt; Oracle Block -&amp;gt; Extent -&amp;gt; Segment -&amp;gt; Table Space&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/book_review/01_oracle_architecture/2019-12-11_oracle_01.png&quot; alt=&quot;오라클 자료구조&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;h5 id=&quot;block&quot;&gt;Block&lt;/h5&gt;

&lt;p&gt;위 스크린샷만 이해하면 이번 챕터를 졸업한 것 입니다. 블록의 크기는 2KB, 4KB, 8KB 등으로 설정 되며, 내부에는 관리용 공간과 데이터 저장공간을 분리하여 사용합니다. 특히 데이터를 저장할 때는 여분의 공간을 비워 데이터 변경에 대해 유연함을 확보하고 있습니다.&lt;/p&gt;

&lt;h5 id=&quot;extent&quot;&gt;Extent&lt;/h5&gt;

&lt;p&gt;여러개의 블록은 하나의 익스텐트를 구성합니다(그림 ‘오라클 자료구조’ 하단 참조). 익스텐트는 ‘연속된 블록’의 집합이라는 것이 중요합니다. 블록 내부에는 빈 공간이 존재하지만 블록을 연속적으로 관리함으로 인해 불필요한 I/O를 줄일 수 있습니다. 또한 각 익스텐트의 첫 위치와 블록의 개수만 파악해도 데이터를 관리할 수 있어 최소한의 관리정보를 유지하게 됩니다.&lt;/p&gt;

&lt;h5 id=&quot;segment&quot;&gt;Segment&lt;/h5&gt;

&lt;p&gt;세그먼트는 넓은 의미에서는 설명하면 여러 익스텐트의 집합이지만, 좁은 의미에서는 테이블이나 인덱스가 관리되는 공간으로 사용됩니다. 따라서 사용자가 직접적인 조작이 가능하며(Ex 테이블의 생성과 삭제) 이에 따라 세그먼트를 관리하는 테이블 스페이스의 공간이 변화하게 됩니다.  또한 데이터를 정렬하는 세그먼트, 과거 데이터를 보관하는 세그먼트 등도 존재합니다. 테이블의 정보가 서로 다른 테이블 스페이스에 나눠 기록될 수 없듯, 세그먼트는 하나의 테이블 스페이스에 속하게 됩니다.&lt;/p&gt;

&lt;h5 id=&quot;table-space&quot;&gt;Table Space&lt;/h5&gt;

&lt;p&gt;연관되어 있는 세그먼트의 집합입니다. 리두, 언두 세그먼트를 관리하는 테이블 스페이스, 데이터를 관리하는 테이블 스페이스, 데이터베이스를 관리하는 테이블 스페이스 등 다양한 형태로 나눠져 있습니다. 실제 물리적인 파일(.dbf .ora 등)은 테이블스페이스와 대응이 됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;테이블스페이스 + 리두 로그 파일 + 컨트롤파일 = 데이터베이스&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;결론&quot;&gt;결론&lt;/h3&gt;

&lt;p&gt;오라클의 자료구조는 &lt;strong&gt;‘최소한의 공간 낭비로 최대의 데이터의 유연성을 확보하는 것’&lt;/strong&gt;에 초점을 두었다고 생각합니다. 책에는 ROW ID에 대한 설명, 실제로 테이블 스페이스부터 만드는 과정 들이 포함되어 있지만 결국, 오라클 자료구조가 어떻게 동작하는지 설명하기 위한 수단에 지나지 않습니다. 블록부터 테이블 스페이스까지의 개념을 이해하면 해당 챕터를 이해했다고 생각해도 됩니다.&lt;/p&gt;

&lt;p&gt;오늘도 어김없이 감사합니다 ;)&lt;/p&gt;</content><author><name>bbubbush</name></author><category term="Book_Review" /><summary type="html">데이터 관리에 있어 대게 두 가지 의견이 상충됩니다. 하나는 데이터 변경에 대한 유연한 공간확보이고, 다른 하나는 잉여공간의 관리 입니다. 예를 들어 100개의 데이터를 배열에 담아야 한다면 여러분은 배열의 크기를 어떻게 설정하시겠습니까? 혹은 어떤 방법을 사용해서 자료구조를 만드시겠습니까? 100개의 데이터가 줄어들수도, 늘어날수도, 변경될 수도 있다면 더 깊게 고민해봐야 할 것입니다.</summary></entry><entry><title type="html">Springboot - Intelli J로 간단한 스프링부트 프로젝트 만들기</title><link href="https://bbubbush.github.io//springboot/2019/05/16/Springboot" rel="alternate" type="text/html" title="Springboot - Intelli J로 간단한 스프링부트 프로젝트 만들기" /><published>2019-05-16T00:00:00+00:00</published><updated>2019-05-16T00:00:00+00:00</updated><id>https://bbubbush.github.io//springboot/2019/05/16/Springboot</id><content type="html" xml:base="https://bbubbush.github.io//springboot/2019/05/16/Springboot">&lt;p&gt;Spring을 공부할 겸 새롭게 시작하는 스터디에서 첫 과제로 Springboot로 구성한 환경에서 Hello world를 출력하여 가져오기로 하였습니다.&lt;/p&gt;

&lt;p&gt;간단한 과제인 만큼 포스팅해보는 것도 좋을 것 같아 진행한 순서대로 기록하고자 합니다.&lt;/p&gt;

&lt;p&gt;우선 본인은 IDE로 Intelli J(인텔리제이)를 사용하였습니다.&lt;/p&gt;

&lt;p&gt;먼저 프로젝트를 생성해보겠습니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-16_project_01.png&quot; alt=&quot;프로젝트만들기&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음으로 Spring Assistant를 선택하여 Spring boot 프로젝트를 만들겠습니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_02.png&quot; alt=&quot;새 프로젝트 생성&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;만약 왼쪽에 Spring Assistant 메뉴가 없다면 Preferences를 열어줍니다.(맥에서는 command + , 단축키로 열 수 있습니다.)
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_03.png&quot; alt=&quot;Preferences 찾기&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그 다음 plugins 메뉴에서 Spring Assistant를 검색하여 설치해줍니다. 전 이미 설치되어있기 때문에 Installed로 나오네요 : )
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_04.png&quot; alt=&quot;Plugins에 인스톨하기&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 다시 프로젝트를 만들어보겠습니다. 새로운 프로젝트는 꼭 Gradle project로 만들어 주세요.
&lt;a href=&quot;https://bkim.tistory.com/13&quot;&gt;참고자료: Maven vs Gradle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_05.png&quot; alt=&quot;프로젝트 정보입력&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;프로젝트를 구성할 dependency를 선택해줍니다. 저는 최소한으로 만들기 위해 아무것도 없이 next를 눌렀습니다. 그랬더니 최소 하나는 선택해달라고 하네요…ㅠ
그래서 Web을 선택하였습니다. 이런 편리함 때문에 Spring Assistant를 사용하게 되는 것 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_06.png&quot; alt=&quot;dependency 선택&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 생성할 프로젝트의 이름과 경로를 선택하시면 기나긴 프로젝트 생성이 마무리 됩니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_07.png&quot; alt=&quot;프로젝트명과 경로 설정&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;새로운 프로젝트가 만들어지면 아래와 같은 안내창이 뜹니다. 그러면 꼭 ‘Use default Gradle Wrapper’ 옵션을 선택해줍니다.
Gradle Wrapper는 운영체제에 맞게 Gradle 빌드를 수행하는 배치 스크립트입니다. 별도의 설정이 필요 없으므로 해당 옵션을 사용하길 권장합니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_08.png&quot; alt=&quot;gradle import&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;자, 여기까지 하고 나면 필요한 파일을 Gradle을 통해 다운로드 받을 수 있도록 기다려줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_09.png&quot; alt=&quot;file download&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 프로젝트를 실행할 수 있는 상태가 되었습니다. 우선 테스트파일을 통해 정상적으로 실행되는지 확인해보겠습니다.
기본으로 제공되는 테스트 메소드의 이름을 “헬로월드”로 바꿔주고 출력문도 하나 추가해줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_10.png&quot; alt=&quot;테스트 메소드 생성&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;메소드를 작성한 후 오른쪽 버튼을 눌러 [Run 헬로월드]를 실행해줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_11.png&quot; alt=&quot;테스트 메소드 실행&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;정상적으로 실행되었습니다. 짜잔! 드디어 스프링부트 프로젝트를 생성하였습니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_12.png&quot; alt=&quot;테스트 성공&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음으로는 실제로 내장WAS를 실행하여 결과를 확인해보겠습니다. 먼저 아래 그림과 같이 기본적인 패키지와 컨트롤러를 생성해줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_13.png&quot; alt=&quot;패키지 및 컨트롤러 생성&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;HelloController는 아래와 같이 만들어 기본적인 텍스트가 출력될 수 있게 코딩해줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_14.png&quot; alt=&quot;컨트롤러 내용&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 HelloApplication파일을 선택 후 오른쪽버튼을 누르면 [Run HelloApplication main()]이 있습니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_15.png&quot; alt=&quot;프로그램 실행&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이를 클릭한 후 웹사이트 주소창에 http://localhost:8080 이렇게 입력하면 아래처럼 Hello World를 출력해줍니다.
&lt;img src=&quot;/assets/img/springboot/2019-05-17_project_16.png&quot; alt=&quot;헬로 월드&quot; class=&quot;center img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이것으로 스터디 첫 번째 과제에 대한 포스팅과 더불어 스프링 부트 프로젝트 생성하기를 마치겠습니다.&lt;/p&gt;

&lt;h4 id=&quot;긴-글-읽어주셔서-감사합니다-&quot;&gt;긴 글 읽어주셔서 감사합니다 :)&lt;/h4&gt;</content><author><name>bbubbush</name></author><category term="Springboot" /><summary type="html">Spring을 공부할 겸 새롭게 시작하는 스터디에서 첫 과제로 Springboot로 구성한 환경에서 Hello world를 출력하여 가져오기로 하였습니다.</summary></entry><entry><title type="html">Programmers - 전화번호 목록</title><link href="https://bbubbush.github.io//algolism/2019/05/02/Algorithm" rel="alternate" type="text/html" title="Programmers - 전화번호 목록" /><published>2019-05-02T00:00:00+00:00</published><updated>2019-05-02T00:00:00+00:00</updated><id>https://bbubbush.github.io//algolism/2019/05/02/Algorithm</id><content type="html" xml:base="https://bbubbush.github.io//algolism/2019/05/02/Algorithm">&lt;h3 id=&quot;문제&quot;&gt;문제&lt;/h3&gt;
&lt;p&gt;[ 전화번호 목록 ]&lt;/p&gt;

&lt;p&gt;전화번호부에 적힌 전화번호 중, 한 번호가 다른 번호의 접두어인 경우가 있는지 확인하려 합니다. 전화번호가 다음과 같을 경우, 구조대 전화번호는 영석이의 전화번호의 접두사입니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;구조대 : 119
박준영 : 97 674 223
지영석 : 11 9552 4421
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때, 어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성해주세요.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;제한 사항
phone_book의 길이는 1 이상 1,000,000 이하입니다.
각 전화번호의 길이는 1 이상 20 이하입니다.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;입력 예제)
phone_book  : [&quot;119&quot;, &quot;97674223&quot;, &quot;1195524421&quot;]

phone_book  : [&quot;123&quot;, &quot;456&quot;, &quot;789&quot;]

phone_book  : [&quot;12&quot;, &quot;123&quot;, &quot;1235&quot;, &quot;567&quot;, &quot;88&quot;]


출력 예제)
false   (문제 예시)

true    (한 번호가 다른 번호의 접두사인 경우가 없으므로 true)

false   (&quot;12&quot; 번호가 &quot;123&quot;, &quot;1235&quot;의 접두사가 됩니다)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;접근방법&quot;&gt;접근방법&lt;/h3&gt;
&lt;p&gt;해시 문제이기 때문에 HashMap 혹은 HashSet을 써야할 것만 같아 이래저래 고민을 해봤습니다만, 활용방법이 도무지 떠오르지 않았습니다. 그래서 일단 직관적으로 문제를 풀어봤습니다.
접근한 순서는 아래와 같습니다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;입력된 배열의 맨 처음 값을 비교하는 문자열로 선택합니다.&lt;/li&gt;
  &lt;li&gt;입력된 배열의 두 번째 값을 비교를 당할 문자열을 선택합니다.&lt;/li&gt;
  &lt;li&gt;만약 비교 문자열이 비교당할 문자열보다 길다면 둘을 반대로 저장합니다.&lt;/li&gt;
  &lt;li&gt;비교할 문자열을 비교하는 문자열의 길이만큼 잘라 서로 같은지 비교합니다.&lt;/li&gt;
  &lt;li&gt;비교가 끝나면 순차적으로 비교를 당할 문자열을 변경하고, 해당 작업이 끝나면 비교하는 문자열을 다음 문자열로 변경합니다.&lt;/li&gt;
  &lt;li&gt;모든 작업이 끝나면 true를 리턴하고 4)의 과정에서 같은 문자열을 발견할 경우 false를 리턴합니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;처음엔 3)의 조건에서 비교 문자열 길이 &amp;gt; 비교할 문자열 인 경우에 비교할 문자열을 그냥 넘겼습니다. 이런 경우에 비교 문자열이 길고, 비교할 문자열이 짧은 케이스 중에서 발생하는 포함관계를 찾지 못했습니다.&lt;/p&gt;

&lt;p&gt;여담으로 다른 분의 풀이중에는 애초에 길이 상관없이 두 경우를 번갈아가며 비교하는 코드도 있었습니다. 코드는 간결하나 두 문자열이 포함관계에 없는 경우 중복된 연산을 두번 반복하기 때문에 비용이 더 높다고 판단되었습니다.&lt;/p&gt;

&lt;p&gt;마지막으로 작성한 코드를 보고 오늘의 알고리즘 풀이도 마무리 하겠습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-{.java}&quot;&gt;class Solution {
    public boolean solution(String[] phone_book) {
        for (int i = 0; i &amp;lt; phone_book.length; i++) {
            for (int j = i+1; j &amp;lt; phone_book.length; j++) {
                String target = phone_book[i];      // 비교 기준
                String eqStr = phone_book[j];       // 비교당하는 문자열
                // 비교하려는 전화번호보다 짧으면 타겟을 변경
                if (target.length() &amp;gt; eqStr.length()) {
                    target = eqStr;
                    eqStr = phone_book[i];
                }

                // if (eqStr.startsWith(target)) {
                //     return false;
                // }

                // 비교하는 대상에서 필요한 만큼만 잘라서 비교(substring 대신 위와 같이 startsWith 메서드를 쓸 수 있습니다)
                if (target.equals(eqStr.substring(0, target.length()))) {
                    return false;
                }
            }
        }
        return true;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;좋은밤-되세요--&quot;&gt;좋은밤 되세요 : )&lt;/h5&gt;</content><author><name>bbubbush</name></author><category term="Algolism" /><summary type="html">문제 [ 전화번호 목록 ]</summary></entry><entry><title type="html">Programmers - 완주하지못한 선수</title><link href="https://bbubbush.github.io//algolism/2019/04/26/Algorithm" rel="alternate" type="text/html" title="Programmers - 완주하지못한 선수" /><published>2019-04-26T00:00:00+00:00</published><updated>2019-04-26T00:00:00+00:00</updated><id>https://bbubbush.github.io//algolism/2019/04/26/Algorithm</id><content type="html" xml:base="https://bbubbush.github.io//algolism/2019/04/26/Algorithm">&lt;h3 id=&quot;문제&quot;&gt;문제&lt;/h3&gt;
&lt;p&gt;[ 완주하지못한 선수 ]&lt;/p&gt;

&lt;p&gt;수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.&lt;/p&gt;

&lt;p&gt;마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;입력 예제)
participant : [leo, kiki, eden]
completion  : [eden, kiki]

participant : [marina, josipa, nikola, vinko, filipa]
completion  : [josipa, filipa, marina, nikola]

participant : [mislav, stanko, mislav, ana]
completion  : [stanko, ana, mislav]

출력 예제)
leo

vinko

mislav  (동명이인이 참가하여 한 사람만 완주함)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;접근방법&quot;&gt;접근방법&lt;/h3&gt;
&lt;p&gt;문제에서 단 한명의 선수만 완주하지 못한다고 명시했습니다. 따라서 간단하게 완주자 명단에 없는 한 명을 찾으면 됩니다.&lt;/p&gt;

&lt;p&gt;혹시 배열로 데이터가 입력되니깐 배열에서 찾아 바로 제거해야겠다는 생각을 한다면 시간초과로 인해 이 문제를 풀 수 없을 것입니다.&lt;/p&gt;

&lt;p&gt;배열에서 데이터를 찾는 속도는 O(n) (n은 배열의 크기) 이기 때문에 완주자를 일일이 찾게 된다면 O(n^2)의 시간이 걸리게 됩니다. (한 명의 완주자를 찾는데 O(n), 이를 완주자 명단만큼 반복하기 때문)&lt;/p&gt;

&lt;p&gt;그래서 해시를 사용해서 풀었습니다. 해시는 탐색 시 O(1)의 속도가 걸리기 때문에 배열에 비해 월등히 빠릅니다.
풀이 순서는 아래와 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;참가자 명단을 HashMap에 이름을 key로, 등장횟수를 value로 입력한다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;참가자 명단을 입력한 HashMap에서 완주자 명단의 이름을 key로 찾아 해당 값을 -1 해준다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;HashMap을 돌면서 value가 0 보다 큰 데이터를 찾아 key를 return한다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;마지막으로 코드를 보겠습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-{.java}&quot;&gt;import java.util.HashMap;
import java.util.Optional;

class Solution {
    public String solution(String[] participant, String[] completion) {
        HashMap&amp;lt;String, Integer&amp;gt; players = new HashMap&amp;lt;&amp;gt;();
        // 참가자 명단에 있는 선수들을 HashMap에 담아 이름의 등장횟수 세기
        for(String player : participant) {
            int countName = Optional.ofNullable(players.get(player)).orElse(0);
            players.put(player, ++countName);
        }
        // HashMap에서 완주자 명단의 이름을 찾아 value를 -1 하기
        for(String player : completion) {
            int countName = Optional.ofNullable(players.get(player)).orElse(0);
            players.put(player, --countName);
        }
        // HashMap을 돌면서 value가 0 보다 큰 데이터 찾기
        for (String key: players.keySet()) {
            if (players.get(key) &amp;gt; 0) {
                return key;
            }
        }
        return &quot;&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;오랜만에-포스팅이라-매끄럽지-않은-글은-양해-부탁드릴게요--&quot;&gt;오랜만에 포스팅이라 매끄럽지 않은 글은 양해 부탁드릴게요 ; )&lt;/h5&gt;</content><author><name>bbubbush</name></author><category term="Algolism" /><summary type="html">문제 [ 완주하지못한 선수 ]</summary></entry><entry><title type="html">나만의 기술면접 질문리스트 만들기</title><link href="https://bbubbush.github.io//diary/2019/04/20/Diary" rel="alternate" type="text/html" title="&lt;일기&gt; 나만의 기술면접 질문리스트 만들기" /><published>2019-04-20T00:00:00+00:00</published><updated>2019-04-20T00:00:00+00:00</updated><id>https://bbubbush.github.io//diary/2019/04/20/Diary</id><content type="html" xml:base="https://bbubbush.github.io//diary/2019/04/20/Diary">&lt;p&gt;오늘 스터디를 진행하면서 준비했었던 기술면접리스트다. 이렇게라도 적어놓지 않으면 스처지나가지 않을까 싶어 기록해 놓는다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. GET / POST 방식의 차이점은 무엇인가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;GET: HTTP 프로토콜의 전송방식의 하나. URL에 파라미터가 전달되어 보안에 취약하다는 특징이 있다.
REST API에 따라 최근에는 조회에 사용되는 전송방식으로 굳어지고 있다. URL을 통해 전달하다보니 전달 가능한 데이터에 제약이 있다.&lt;/li&gt;
  &lt;li&gt;POST: HTTP 프로토콜의 전송방식의 하나. 파라미터를 Body 영역에 보관하여 전달하기 때문에 URL에 노출되지 않고, 데이터의 제약이 없다.
REST API에 따라 입력데이터 전송에 사용하고 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. JVM이란 무엇인가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;Java Byte Code를 해석하는 컴파일러. OSMU을 수행하게 하는 자바의 핵심 기술이라고 생각한다.
.java 파일을 바이트 코드 형태의 .class 파일로 컴파일하고(자바 컴파일러) .class파일을 읽어 프로그램을 수행하는 역할을 JVM이 담당한다.
Heap 영역, Stack 영역, Static 영역 등이 있고 GC컴파일러를 포함한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. 좋은 코드란 무엇인가?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;성능, 가독성, 유지보수 용이 등 다양한 관점으로 생각할 수 있지만, 제가 생각하는 좋은 코드는 ‘어떤 개발자가 보아도 쉽게 이해가 가는 코드’를 대 전제로 생각한다.
여기에 상황에 따라 가독성이 낮아도 성능을 더 필요로 하는 기능에는 성능을 우선하고, 변경이 자주 일어나는 기능에는 유지보수 및 확장성이 우선되어야 한다.&lt;/li&gt;
  &lt;li&gt;실제로 업무를 하다보면 다른 사람의 코드를 보는 경우가 많은데 주석이 한 줄도 없으면 이해하는데 많은 시간을 쏟는다.
더구나 코드의 가독성 마저 떨어지면 내가 이해한 내용이 맞는지 의구심마저 들게 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. 반대로 나쁜 코드는 무엇인가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;설명 한 줄 없는 코드가 가장 나쁘다고 생각한다. ‘나 혼자만 이해하면 괜찮다’ 라는 생각이 반영되어 다른 개발자를 배려하지 않았다는 생각이 들기 때문이다.&lt;/li&gt;
  &lt;li&gt;주석이 과하면 코드의 가독성을 해치지만, 아예 없는 것 보다는 과한 것이 낫다고 생각한다.
다만 깔끔한 주석을 달기 위해서는 많은 고민을 해봐야 한다고 생각한다. 프로세스를 간략하게 명시하는 방법도 있고, 핵심 데이터에 포커스를 두고 흐름을 나타낼 수도 있고, 간결한 문장으로 설명할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. SPA(Single Page Application)는 무엇인가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;하나의 페이지에서 변경이 일어나는 부분만 변화시키는 방식이다. 기존의 웹은 요청이 있을 때 마다 전체 리소스를 제공하였다면, SPA는 실제 데이터가 변화는 영역(body)만 제공하여 속도를 개선할 수 있다.&lt;/li&gt;
  &lt;li&gt;등장배경에는 모바일 인터넷의 사용빈도가 증가하면서 낮은 컴퓨팅파워에서도 잘 돌아가는 웹사이트가 필요해졌기 때문이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Q. 본인은 어떤 개발자인가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;넓고 얕게 아는 개발자입니다. 다양한 것을 좋아해 다방면으로 개발해보고 싶다는 욕심이 있습니다. 넓게 공부하다보면 깊이도 자연스럽게 깊어질 것이라 믿고 있습니다.&lt;/li&gt;
&lt;/ul&gt;</content><author><name>bbubbush</name></author><category term="Diary" /><summary type="html">오늘 스터디를 진행하면서 준비했었던 기술면접리스트다. 이렇게라도 적어놓지 않으면 스처지나가지 않을까 싶어 기록해 놓는다.</summary></entry></feed>