<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Peter의 우아한 프로그래밍</title>
    <link>https://gracefulprograming.tistory.com/</link>
    <description>IT 정보 공유, 
프로그래밍 지식 공유
</description>
    <language>ko</language>
    <pubDate>Sat, 30 May 2026 12:30:36 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Peter Ahn</managingEditor>
    <image>
      <title>Peter의 우아한 프로그래밍</title>
      <url>https://t1.daumcdn.net/cfile/tistory/237AB437581F6B0F15</url>
      <link>https://gracefulprograming.tistory.com</link>
    </image>
    <item>
      <title>NestJS: 현대적인 Node.js 백엔드 개발의 게임 체인저</title>
      <link>https://gracefulprograming.tistory.com/136</link>
      <description>&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;모듈러 아키텍처와 타입스크립트의 만남, NestJS로 백엔드 개발을 혁신하다&lt;/span&gt;&lt;/h2&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Node.js는 지난 몇 년간 백엔드 개발에서 큰 인기를 끌어온 플랫폼입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;많은 프레임워크들이 Node.js 위에서 발전해왔지만, 그중에서도 특히 눈에 띄는 것이 있습니다. 바로 NestJS입니다. NestJS는 현대적인 웹 애플리케이션 개발을 위한 게임 체인저로 평가받고 있으며, 타입스크립트와 모듈러 아키텍처를 활용하여 코드의 유지보수성과 확장성을 대폭 향상시켰습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 글에서는 NestJS가 왜 백엔드 개발자들 사이에서 주목받고 있는지, 어떤 장점을 제공하는지에 대해 자세히 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nestjs.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4jMkw/btsKLlljADr/zhi3xCpLvwpHY9oUyH7Np1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4jMkw/btsKLlljADr/zhi3xCpLvwpHY9oUyH7Np1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4jMkw/btsKLlljADr/zhi3xCpLvwpHY9oUyH7Np1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4jMkw%2FbtsKLlljADr%2Fzhi3xCpLvwpHY9oUyH7Np1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;575&quot; data-filename=&quot;nestjs.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. NestJS 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 홈페이지: &lt;a href=&quot;https://nestjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nestjs.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731832496987&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NestJS - A progressive Node.js framework&quot; data-og-description=&quot;NestJS is a framework for building efficient, scalable Node.js web applications. It uses modern JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Progr&quot; data-og-host=&quot;nestjs.com&quot; data-og-source-url=&quot;https://nestjs.com/&quot; data-og-url=&quot;https://nestjs.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cICvAj/hyXzQ5VqV6/2Uso70e3WkxUR2DeK0m9RK/img.png?width=820&amp;amp;height=429&amp;amp;face=0_0_820_429&quot;&gt;&lt;a href=&quot;https://nestjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nestjs.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cICvAj/hyXzQ5VqV6/2Uso70e3WkxUR2DeK0m9RK/img.png?width=820&amp;amp;height=429&amp;amp;face=0_0_820_429');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NestJS - A progressive Node.js framework&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;NestJS is a framework for building efficient, scalable Node.js web applications. It uses modern JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Progr&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nestjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 Node.js를 기반으로 한 오픈 소스 백엔드 프레임워크로, &lt;b&gt;Angular&lt;/b&gt;에서 영감을 받아 구조화된 아키텍처를 제공합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 &lt;b&gt;타입스크립트&lt;/b&gt;를 중심으로 설계되었기 때문에 정적 타이핑을 통한 오류 감소와 더 나은 코드 자동 완성 기능을 제공합니다. NestJS의 주된 목표는 유지보수성과 확장성을 고려한 애플리케이션을 쉽게 개발할 수 있도록 돕는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS의 가장 큰 특징 중 하나는 &lt;b&gt;의존성 주입(Dependency Injection)&lt;/b&gt;을 지원한다는 점입니다. 이는 Angular에서 사용하는 방식과 매우 유사하며, 이를 통해 복잡한 의존 관계를 보다 쉽게 관리할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한, NestJS는 모듈 단위로 코드를 작성할 수 있는 구조를 제공해 프로젝트 규모가 커지더라도 코드의 분리를 명확히 하고, 재사용성을 높일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 코드의 일관성과 통일성을 유지하기 위해 설계된 수많은 유틸리티와 장치들을 제공합니다. 예를 들어, NestJS CLI를 사용하면 새로운 모듈이나 서비스를 쉽게 생성할 수 있으며, 이러한 구조화된 도구들은 개발 속도를 크게 향상시킵니다. 또한, 코드의 일관성을 유지함으로써 협업 환경에서도 생산성을 극대화할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. NestJS를 사용해야 하는 이유&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 TypeScript 지원&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타입스크립트는 NestJS의 또 다른 강력한 무기입니다. 타입스크립트는 자바스크립트의 상위 집합으로, 정적 타입 검사와 더불어 코드의 안정성을 크게 향상시킵니다. NestJS는 기본적으로 타입스크립트를 사용하도록 설계되어 있으며, 이를 통해 개발자들은 코드 작성 시 더 나은 개발 경험을 누릴 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타입스크립트는 코드 자동 완성과 타입 오류 검출 기능을 통해 코드의 품질을 높입니다. 이는 NestJS 애플리케이션을 더욱 견고하게 만들며, 버그 발생 가능성을 줄여줍니다. 또한, 타입 정의 덕분에 코드 가독성 역시 크게 향상되어 팀원 간의 협업이 훨씬 원활해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타입스크립트는 대규모 프로젝트에서도 효율적입니다. 각 객체와 함수의 타입이 명확하게 정의되어 있어, 새로 팀에 합류한 개발자들도 코드의 의도를 쉽게 이해할 수 있습니다. 이는 코드 리뷰와 유지보수 작업에서 큰 이점을 제공하며, 타인의 코드를 수정할 때 발생할 수 있는 실수를 방지합니다. 또한, 타입스크립트의 정적 분석 도구를 활용하면 코드의 취약점을 사전에 발견하고 해결할 수 있어 더욱 안전한 애플리케이션을 개발할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 모듈화된 아키텍처&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS의 핵심 개념 중 하나는 바로 &lt;/span&gt;&lt;span&gt;&lt;b&gt;모듈러 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다. 모듈을 사용하면 기능별로 코드가 분리되어 관리됩니다. 예를 들어, 사용자 인증 관련 기능을 하나의 모듈로 구성하고, 데이터베이스 접근을 또 다른 모듈로 분리할 수 있습니다. 이렇게 모듈화된 구조는 팀 내 개발자들이 특정 기능에 집중할 수 있도록 돕고, 협업을 원활하게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모듈 구조는 특히 대규모 애플리케이션 개발에 유리합니다. 코드가 분리되어 있을수록 새로운 기능을 추가하거나 기존 기능을 수정할 때 전체 애플리케이션에 미치는 영향을 최소화할 수 있기 때문입니다. NestJS는 이러한 모듈화 작업을 매우 간단하게 만들며, 이를 통해 대규모 프로젝트에서도 효율적인 코드 관리를 가능하게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모듈러 아키텍처는 단순한 코드 분리 이상의 장점을 제공합니다. 각 모듈은 독립적으로 개발되고 유지될 수 있어, 특정 기능에 대한 변경이 다른 부분에 영향을 미치지 않게 합니다. 또한, 이는 테스트 효율성 향상에도 기여합니다. 각 모듈을 독립적으로 테스트할 수 있기 때문에 애플리케이션 전체를 테스트하지 않고도 특정 기능만의 동작을 보장할 수 있습니다. 이를 통해 개발자들은 자신이 담당한 기능이 전체 시스템에서 원활하게 작동하는지 확인하는 과정을 간소화할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3&amp;nbsp;&lt;span&gt;REST API 및 GraphQL 지원&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;REST API&lt;/b&gt;&lt;/span&gt;&lt;span&gt;뿐만 아니라 &lt;/span&gt;&lt;span&gt;&lt;b&gt;GraphQL&lt;/b&gt;&lt;/span&gt;&lt;span&gt;도 기본적으로 지원합니다. 이를 통해 개발자는 프로젝트 요구 사항에 맞춰 적절한 API 기술을 선택할 수 있습니다. REST API는 전통적인 방식으로 여전히 널리 사용되고 있으며, GraphQL은 클라이언트에게 필요한 데이터만 요청할 수 있는 효율적인 방법으로 각광받고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 이러한 다양한 옵션을 제공함으로써 다양한 프로젝트에 유연하게 대응할 수 있도록 합니다. 또한, GraphQL을 사용할 때도 NestJS의 모듈러 아키텍처와 의존성 주입을 그대로 활용할 수 있어, 코드의 일관성을 유지하면서 복잡한 기능을 구현할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GraphQL의 장점은 데이터 요청의 효율성에 있습니다. 클라이언트는 필요한 데이터만 정확하게 요청할 수 있기 때문에 네트워크 부하를 줄일 수 있으며, 이를 통해 애플리케이션 성능을 최적화할 수 있습니다. NestJS는 GraphQL 서버 구축을 간편하게 도와주는 도구들을 제공하며, 이를 통해 개발자들은 복잡한 데이터 구조도 쉽게 처리할 수 있습니다. 또한, REST와 GraphQL을 동시에 사용하는 하이브리드 구조도 지원하기 때문에 다양한 요구 사항을 가진 프로젝트에서 큰 유연성을 발휘할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 &lt;span&gt;테스트와 유지보수&lt;/span&gt;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 개발자가 &lt;/span&gt;&lt;span&gt;&lt;b&gt;테스트 가능성&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 높이기 위한 기능들을 제공합니다. 의존성 주입을 통해 각 컴포넌트의 독립성을 확보하고, 이를 통해 단위 테스트를 쉽게 작성할 수 있습니다. 또한, 모듈 단위로 기능이 분리되어 있기 때문에 특정 모듈만 테스트할 수 있어, 테스트 효율성이 크게 향상됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 테스트 용이성 덕분에, NestJS는 유지보수 측면에서도 큰 강점을 가집니다. 유지보수는 모든 소프트웨어의 생명주기에서 중요한 요소이며, NestJS는 구조화된 아키텍처와 타입스크립트를 활용해 유지보수 비용을 최소화합니다. 또한, 테스트가 쉬워지면서 코드 변경 시 발생할 수 있는 문제를 사전에 방지할 수 있어, 제품의 신뢰성을 높이는 데 기여합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 또한 통합 테스트와 기능 테스트도 쉽게 작성할 수 있도록 지원합니다. 다양한 모듈을 조합하여 애플리케이션의 전반적인 흐름을 테스트할 수 있으며, 이를 통해 배포 전에 발생할 수 있는 문제를 조기에 발견할 수 있습니다. 이는 프로덕션 환경에서 발생할 수 있는 문제를 최소화하고, 최종 사용자에게 더욱 안정적인 서비스를 제공하는 데 중요한 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5 커뮤니티와 생태계&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 최근 몇 년간 급성장하며 활발한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;커뮤니티와 생태계&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 형성하고 있습니다. 이는 다양한 플러그인과 라이브러리를 통해 NestJS를 더욱 강력하게 만들어줍니다. 또한, 많은 개발자들이 NestJS를 기반으로 하는 프로젝트를 공유하고, 문제 해결을 위한 도움을 제공하고 있어, 개발자들은 NestJS를 배우고 사용하는 데 큰 장벽을 느끼지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS의 커뮤니티는 지속적으로 성장하고 있으며, 이는 곧 더 많은 학습 자료와 튜토리얼이 존재한다는 것을 의미합니다. GitHub, Stack Overflow 같은 플랫폼에서는 활발한 논의가 이루어지고 있으며, 공식 문서도 매우 상세하고 이해하기 쉽게 작성되어 있습니다. 이러한 커뮤니티의 지원 덕분에 새로운 개발자들도 쉽게 NestJS를 배우고 활용할 수 있습니다. 더 나아가, 오픈 소스 프로젝트에 기여함으로써 개인의 역량을 키우고 커뮤니티의 일원이 될 수 있는 기회도 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. NestJS 설치 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 Ubuntu에서 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ubuntu에서 NestJS를 설치하려면 다음 명령어를 사용합니다&lt;/p&gt;
&lt;pre id=&quot;code_1686901234567&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt update
sudo apt install nodejs npm
npm install -g @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 Mac에서 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mac에서 NestJS를 설치하려면 다음 명령어를 사용합니다&lt;/p&gt;
&lt;pre id=&quot;code_1686901234568&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew update
brew install node
npm install -g @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 개발환경 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 프로젝트를 시작하려면 다음 단계를 따르세요:&lt;/p&gt;
&lt;pre id=&quot;code_1686901234569&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nest new project-name
cd project-name
npm run start:dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 http://localhost:3000에서 애플리케이션이 실행됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 간단한 사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS에서 간단한 컨트롤러를 만들어 보겠습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1686901234570&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컨트롤러는 '/cats' 경로로 GET 요청이 오면 'This action returns all cats'라는 문자열을 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다 자세한 사용법은 앞으로 실제 사용이 가능한 API Service 를 만들어보는 예제를 통해서 소개드리겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6.&amp;nbsp;&lt;span&gt;결론: 왜 NestJS인가?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;NestJS&lt;/b&gt;는 모듈러 아키텍처, 타입스크립트, 의존성 주입 등을 통해 Node.js 백엔드 개발을 새로운 수준으로 끌어올립니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;REST API와 GraphQL을 모두 지원하며, 테스트와 유지보수가 용이한 구조를 제공합니다. 이러한 점에서 NestJS는 현대적인 웹 애플리케이션 개발을 위한 게임 체인저로 자리 잡고 있습니다. 앞으로의 프로젝트에서 더욱 효율적이고 강력한 백엔드 개발을 원한다면, NestJS를 고려해보세요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NestJS는 개발자가 직면하는 여러 문제를 해결할 수 있는 다양한 도구와 기능을 제공하며, 팀 협업에서 발생할 수 있는 비효율성을 최소화합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모듈러 아키텍처와 타입스크립트를 기반으로 한 견고한 구조는 프로젝트의 복잡도가 증가할 때에도 코드의 품질을 유지할 수 있도록 도와줍니다. 현대적인 웹 애플리케이션을 구축하려는 모든 개발자들에게 NestJS는 강력하고 신뢰할 수 있는 선택지임이 분명합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Javascript</category>
      <category>backend</category>
      <category>Nestjs</category>
      <category>nodejs</category>
      <category>restfulapi</category>
      <category>typescript</category>
      <category>마이크로서비스</category>
      <category>백엔드개발</category>
      <category>웹개발</category>
      <category>웹프레임워크</category>
      <category>의존성주입</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/136</guid>
      <comments>https://gracefulprograming.tistory.com/136#entry136comment</comments>
      <pubDate>Fri, 15 Nov 2024 16:53:40 +0900</pubDate>
    </item>
    <item>
      <title>Flet: Python으로 만드는 멀티플랫폼 앱의 혁명</title>
      <link>https://gracefulprograming.tistory.com/135</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;flet.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbefF0/btsKKgC3fsA/O73aN5lFQKpmkyFbk3Po2K/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbefF0/btsKKgC3fsA/O73aN5lFQKpmkyFbk3Po2K/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbefF0/btsKKgC3fsA/O73aN5lFQKpmkyFbk3Po2K/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbefF0%2FbtsKKgC3fsA%2FO73aN5lFQKpmkyFbk3Po2K%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;443&quot; height=&quot;443&quot; data-filename=&quot;flet.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Flet 소개&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Flet은 Python 개발자들에게 새로운 가능성을 열어주는 혁신적인 프레임워크입니다. 이 프레임워크를 사용하면 웹, 데스크톱, 모바일 애플리케이션을 단일 Python 코드베이스로 개발할 수 있습니다. Flet은 Flutter를 기반으로 하여 아름답고 반응성 높은 사용자 인터페이스를 제공하면서도, Python의 간결함과 생산성을 유지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 홈페이지: &lt;a href=&quot;https://flet.dev&quot;&gt;https://flet.dev&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731586542042&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Build multi-platform apps in Python powered by Flutter | Flet&quot; data-og-description=&quot;Build multi-platform apps in Python powered by Flutter.&quot; data-og-host=&quot;flet.dev&quot; data-og-source-url=&quot;https://flet.dev&quot; data-og-url=&quot;https://flet.dev/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rx9N6/hyXzVTelfo/PbKMM7NNOmd2YkTW7V1gTk/img.png?width=1626&amp;amp;height=1457&amp;amp;face=0_0_1626_1457&quot;&gt;&lt;a href=&quot;https://flet.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://flet.dev&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rx9N6/hyXzVTelfo/PbKMM7NNOmd2YkTW7V1gTk/img.png?width=1626&amp;amp;height=1457&amp;amp;face=0_0_1626_1457');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Build multi-platform apps in Python powered by Flutter | Flet&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Build multi-platform apps in Python powered by Flutter.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;flet.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서: &lt;a href=&quot;https://flet.dev/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://flet.dev/docs/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731586556945&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introduction | Flet&quot; data-og-description=&quot;What is Flet?&quot; data-og-host=&quot;flet.dev&quot; data-og-source-url=&quot;https://flet.dev/docs/&quot; data-og-url=&quot;https://flet.dev/docs/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/beYreA/hyXwkf5dtY/PPuyxq2DTQpeSS1pPl28Z1/img.png?width=1424&amp;amp;height=1170&amp;amp;face=0_0_1424_1170,https://scrap.kakaocdn.net/dn/bKPNv1/hyXzTOEux3/6of9RT7sYr4k6MGX0kUHGK/img.png?width=1372&amp;amp;height=824&amp;amp;face=0_0_1372_824,https://scrap.kakaocdn.net/dn/Z2ySH/hyXwvBT0Gr/oMthXWkWMjlKy4K76DKvO1/img.png?width=990&amp;amp;height=814&amp;amp;face=0_0_990_814&quot;&gt;&lt;a href=&quot;https://flet.dev/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://flet.dev/docs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/beYreA/hyXwkf5dtY/PPuyxq2DTQpeSS1pPl28Z1/img.png?width=1424&amp;amp;height=1170&amp;amp;face=0_0_1424_1170,https://scrap.kakaocdn.net/dn/bKPNv1/hyXzTOEux3/6of9RT7sYr4k6MGX0kUHGK/img.png?width=1372&amp;amp;height=824&amp;amp;face=0_0_1372_824,https://scrap.kakaocdn.net/dn/Z2ySH/hyXwvBT0Gr/oMthXWkWMjlKy4K76DKvO1/img.png?width=990&amp;amp;height=814&amp;amp;face=0_0_990_814');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Introduction | Flet&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;What is Flet?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;flet.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flet을 사용해야 하는 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단일 언어로 멀티플랫폼 개발:&lt;/b&gt; Python 하나로 웹, 데스크톱, 모바일 앱을 모두 개발할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 개발 속도:&lt;/b&gt; 복잡한 프론트엔드 기술을 배울 필요 없이 Python만으로 UI를 구축할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아름다운 UI:&lt;/b&gt; Flutter 기반의 위젯을 사용하여 세련된 디자인의 앱을 만들 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간 업데이트:&lt;/b&gt; 상태 변경 시 UI가 자동으로 업데이트되어 반응형 앱 개발이 용이합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성:&lt;/b&gt; Python의 풍부한 라이브러리 생태계를 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설치 방법 (Ubuntu, Mac)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flet을 설치하기 전에 pyenv를 사용하여 가상 환경을 만들어 보겠습니다. 이렇게 하면 프로젝트별로 독립적인 Python 환경을 유지할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Flet 설치&lt;/h3&gt;
&lt;pre id=&quot;code_1729204155004&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install flet
    &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flet 은 pip 를 통해 간편하게 설치 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 이전에 소개해드렸던 pyenv 를 활용해서 가상환경을 만들고 설치하는 것을 권장드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/134&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://gracefulprograming.tistory.com/134&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731586658190&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;pyenv: 파이썬 버전 관리의 마법사&quot; data-og-description=&quot;pyenv란 무엇인가?pyenv는 파이썬 개발자들의 필수 도구로 자리잡은 강력한 버전 관리 시스템입니다. 이 도구를 사용하면 여러 버전의 파이썬을 시스템에 설치하고 프로젝트별로 다른 버전을 사용&quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/134&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/134&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d5aW27/hyXzRpLqDN/QAQpVip32zwRmSlVLVJBmk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bhFNEL/hyXzONlvDX/uBkCcCo2FU3c4l9vkDjpi1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/134&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/134&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d5aW27/hyXzRpLqDN/QAQpVip32zwRmSlVLVJBmk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bhFNEL/hyXzONlvDX/uBkCcCo2FU3c4l9vkDjpi1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;pyenv: 파이썬 버전 관리의 마법사&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;pyenv란 무엇인가?pyenv는 파이썬 개발자들의 필수 도구로 자리잡은 강력한 버전 관리 시스템입니다. 이 도구를 사용하면 여러 버전의 파이썬을 시스템에 설치하고 프로젝트별로 다른 버전을 사용&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;간단한 사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flet을 사용하여 간단한 카운터 앱을 만들어 보겠습니다&lt;/p&gt;
&lt;pre id=&quot;code_1729204155005&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import flet as ft

def main(page: ft.Page):
    page.title = &quot;Flet 카운터 예제&quot;

    counter = ft.Text(&quot;0&quot;)

    def increment(e):
        counter.value = str(int(counter.value) + 1)
        page.update()

    page.add(
        counter,
        ft.ElevatedButton(&quot;증가&quot;, on_click=increment)
    )

ft.app(target=main)
    &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 화면에 숫자와 버튼을 표시하며, 버튼을 클릭할 때마다 숫자가 증가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행은 아래 명령어로 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731586731985&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;flet your_script.py&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;활용 사례&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대시보드 애플리케이션:&lt;/b&gt; 데이터 시각화와 실시간 업데이트가 필요한 비즈니스 인텔리전스 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토타입 개발:&lt;/b&gt; 아이디어를 빠르게 구현하고 테스트하기 위한 도구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교육용 애플리케이션:&lt;/b&gt; 학생들이 상호작용하며 학습할 수 있는 교육 플랫폼&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IoT 컨트롤 패널:&lt;/b&gt; 스마트 홈 기기를 제어하는 인터페이스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;크로스 플랫폼 유틸리티 앱:&lt;/b&gt; 파일 관리, 메모, 일정 관리 등 다양한 플랫폼에서 동작하는 유틸리티 애플리케이션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flet은 Python 개발자들에게 새로운 가능성을 열어주는 강력한 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹, 데스크톱, 모바일 애플리케이션을 하나의 코드베이스로 개발할 수 있어 시간과 비용을 절약할 수 있습니다. 또한, Python의 간결함과 Flutter의 아름다운 UI를 결합하여 사용자 경험이 뛰어난 애플리케이션을 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flet을 사용하여 여러분의 아이디어를 현실로 만들어보세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/135</guid>
      <comments>https://gracefulprograming.tistory.com/135#entry135comment</comments>
      <pubDate>Thu, 14 Nov 2024 21:19:54 +0900</pubDate>
    </item>
    <item>
      <title>pyenv: 파이썬 버전 관리의 마법사</title>
      <link>https://gracefulprograming.tistory.com/134</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DALL&amp;amp;middot;E 2024-11-14 20.52.31 - 1. A sleek, minimalistic illustration of a developer's workspace featuring a terminal with the text 'pyenv install 3.10.0', a Python logo, and a lapto.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUPyti/btsKKp0XDQo/chW87UiOQ3EK0tU6X5ZEfk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUPyti/btsKKp0XDQo/chW87UiOQ3EK0tU6X5ZEfk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUPyti/btsKKp0XDQo/chW87UiOQ3EK0tU6X5ZEfk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUPyti%2FbtsKKp0XDQo%2FchW87UiOQ3EK0tU6X5ZEfk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;547&quot; data-filename=&quot;DALL&amp;middot;E 2024-11-14 20.52.31 - 1. A sleek, minimalistic illustration of a developer's workspace featuring a terminal with the text 'pyenv install 3.10.0', a Python logo, and a lapto.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pyenv란 무엇인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pyenv는 파이썬 개발자들의 필수 도구로 자리잡은 강력한 버전 관리 시스템입니다. 이 도구를 사용하면 여러 버전의 파이썬을 시스템에 설치하고 프로젝트별로 다른 버전을 사용할 수 있습니다. pyenv를 통해 개발자들은 파이썬 버전 충돌 문제에서 해방되어 더욱 효율적인 개발 환경을 구축할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 pyenv를 사용해야 할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pyenv를 사용해야 하는 이유는 다음과 같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버전 충돌 방지:&lt;/b&gt; 여러 프로젝트에서 서로 다른 파이썬 버전을 요구할 때 발생할 수 있는 충돌을 예방합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트별 환경 설정:&lt;/b&gt; 각 프로젝트에 적합한 파이썬 버전을 쉽게 설정하고 관리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 파이썬 보호:&lt;/b&gt; 시스템에 설치된 기본 파이썬을 건드리지 않고 다양한 버전을 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간편한 버전 전환:&lt;/b&gt; 명령어 하나로 전역 또는 로컬 파이썬 버전을 쉽게 전환할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 Anaconda 를 통해 프로젝트별 환경 구성을 하는 경우가 많았는데 200명 이상인 경우 라이선스 구입이 필수가 되었기 때문에 pyenv 와 같은 다른 도구로 전환이 되고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; Anaconda is a commercial distribution of Python with the most popular python libraries, you are not permitted to use Anaconda in an organisation with more than 200 employees. - Anaconda &lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pyenv 설치 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Ubuntu에서 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ubuntu에서는 다음 명령어를 사용하여 pyenv를 설치할 수 있습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1700046001&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

curl https://pyenv.run | bash
    &lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;macOS에서 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macOS에서는 Homebrew를 사용하여 pyenv를 쉽게 설치할 수 있습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1700046002&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew update
brew install pyenv
    &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pyenv 기본 사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pyenv의 기본적인 사용법은 다음과 같습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1700046003&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 사용 가능한 파이썬 버전 목록 확인
pyenv install --list

# 특정 버전의 파이썬 설치
pyenv install 3.9.5

# 전역 파이썬 버전 설정
pyenv global 3.9.5

# 특정 디렉토리에 로컬 파이썬 버전 설정
pyenv local 3.8.10

# 현재 사용 중인 파이썬 버전 확인
pyenv version
    &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pyenv 활용 사례&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pyenv는 다양한 상황에서 유용하게 활용될 수 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;레거시 프로젝트 유지보수:&lt;/b&gt; 오래된 파이썬 2.x 버전으로 작성된 프로젝트를 현대적인 3.x 버전 프로젝트와 함께 관리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최신 기능 테스트:&lt;/b&gt; 새로운 파이썬 버전의 기능을 기존 환경에 영향을 주지 않고 테스트할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CI/CD 파이프라인:&lt;/b&gt; 여러 파이썬 버전에서 코드를 테스트하는 CI/CD 환경을 쉽게 구축할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교육 및 학습:&lt;/b&gt; 다양한 파이썬 버전을 쉽게 설치하고 전환하며 학습할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pyenv를 사용하면 파이썬 개발 환경을 더욱 유연하고 효율적으로 관리할 수 있습니다. 여러 프로젝트를 동시에 진행하는 개발자나 다양한 파이썬 버전을 다루어야 하는 팀에게 특히 유용한 도구입니다. pyenv를 통해 파이썬 버전 관리의 복잡성을 줄이고, 개발에 더 집중할 수 있는 환경을 만들어보세요.&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>conda</category>
      <category>pyenv</category>
      <category>python</category>
      <category>python version</category>
      <category>venv</category>
      <category>virtualenv</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/134</guid>
      <comments>https://gracefulprograming.tistory.com/134#entry134comment</comments>
      <pubDate>Thu, 14 Nov 2024 21:01:45 +0900</pubDate>
    </item>
    <item>
      <title>C 언어와 C++ 의 차이</title>
      <link>https://gracefulprograming.tistory.com/132</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;안녕하세요 &lt;b&gt;피터&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;많은 분들이 C 언어를 배우고 나서 C++ 를 배우기 시작 할 때 어려움을 겪곤 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;제 주변에도 그런 분들이 있어서 어떤 점 때문에 어려운지 물어봤더니 &lt;span style=&quot;color: #006dd7;&quot;&gt;어디서부터 어떻게 시작해야 될 지 모르겠다&lt;/span&gt;는 답변이 가장 많았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어쩌면 당연한 일인지도 모르겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;비교적 간단한 문법 체계를 갖고 있는 C 언어와 달리 C++ 은 굉장히 &lt;b&gt;다양한 패러다임&lt;/b&gt;이 녹아있으며 방대한 스케일을 자랑하는 언어이기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(물론 그렇다고 해서 C 언어가 가볍고 만만한 프로그래밍 언어라는 말은 아닙니다. 오히려 그 반대로 처음엔 쉬워보이지만 알면 알수록 어려워지는 언어입니다. C 언어는 역사가 긴 만큼 괴수 분들이 많이 서식하고 계십니다 :D)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 우선은 &lt;b&gt;C &lt;/b&gt;언어와 &lt;b&gt;C++&lt;/b&gt; 두 언어가 어떤 부분이 다른지 간단하게 살펴보고 넘어가겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 617px; height: 124px;&quot; border=&quot;1&quot; width=&quot;2673&quot; data-ke-style=&quot;style1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Feature&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;C&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;C++&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Paradigm&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;Procedural Language &lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Multi-Paradigm Language&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Approach&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;Top down&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Bottom up&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Namespace&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Inheritance&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Overloading&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Polymorphism&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Template&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;reference&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;struct constructor&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 10px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Memory allocation&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 10px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;malloc(), calloc(), realloc()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 10px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;new&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 14px;&quot;&gt;
&lt;td style=&quot;width: 217.663px; height: 14px;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span&gt;Memory deallocation&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 176.175px; height: 14px;&quot; height=&quot;104&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;free()&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 171.163px; height: 14px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;delete&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러 차이점들이 있지만 눈여겨 볼 만한 부분은 C++ 의 &lt;b&gt;Multi-paradigm&lt;/b&gt; 이라는 부분입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;절차지향 프로그래밍(Procedure-Oriented Programming)&lt;/b&gt;&lt;/span&gt;을 지원하는 C 언어와 달리 C++ 은 C 언어의 절차지향 프로그래밍을 그대로 승계한 동시에 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체지향 프로그래밍(Object-Oriented Programming)&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;일반화 프로그래밍(Generic Programming)&lt;/b&gt;&lt;/span&gt;을 모두 지원하는 언어입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;C 언어의 문법을 그대로 계승했기 때문에 얼핏 보면 큰 차이가 없어 보여 쉽게 접근했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코딩을 하면 할 수록 내가 알던 그 언어와 비슷하면서도 &lt;u&gt;뭔가 잘못되고 있다는 느낌&lt;/u&gt;을 받게 되죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(내거인듯 내거아닌 내거같은 너...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇게 느낄 수 밖에 없는 것이 객체지향 프로그래밍에 대한 개념을 모르는 상태에서는 C++에서 새롭게 등장하는 객체지향 문법들을 온전히 이해 할 수 없기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;게다가 처음보는&amp;nbsp;&lt;b&gt;템플릿(template) &lt;/b&gt;문법은 외계어에 가깝게 느껴집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;C++은 이처럼 여러 가지 패러다임을 지원하는 언어이니 만큼 제대로 사용하기 위해서 배워야 할 개념들이 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 배우면 배울 수록 겸손해지는 언어이기도 하죠.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;span style=&quot;color: #666666;&quot;&gt;괜히 개발자들 사이에서 본인이 C++ 고수라고 하는 사람은 상종도 하지 말라는 말이 있는 게 아닙니다...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇다면 C++을 어떻게 배우는 것이 좋을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선은 기존의 &lt;b&gt;Top-down&lt;/b&gt; 방식으로 사고를 했던 것에서 벗어나 &lt;b&gt;Bottom-up&lt;/b&gt; 방식의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체지향 개념&lt;/b&gt;&lt;/span&gt;을 먼저 익히는 것이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1598429112771&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[객체지향] Object-Oriented Programming 핵심 개념의 이해&quot; data-og-description=&quot;배경 데이터 흐름(Flow)에 기반한 절차지향적 프로그래밍 방법은 복잡한 로직을 갖는 큰 규모의 소프트웨어 개발에는 적합하지 않습니다. 하드웨어 성능이 폭발적으로 성장하면서 요구되어지는 &quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/130&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/130&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Fmh8e/hyHh8Vn1sj/PIq1vLVGiRGTu0IHX7fZVK/img.png?width=411&amp;amp;height=211&amp;amp;face=0_0_411_211,https://scrap.kakaocdn.net/dn/bfNKEl/hyHgHrAbcD/DpU5mqOHsJfurQ6vSBPN91/img.png?width=411&amp;amp;height=211&amp;amp;face=0_0_411_211,https://scrap.kakaocdn.net/dn/eBUHb/hyHiiDHCOx/WSKZK0KsmCcTXEg6aAKCb1/img.png?width=1000&amp;amp;height=539&amp;amp;face=0_0_1000_539&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/130&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/130&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Fmh8e/hyHh8Vn1sj/PIq1vLVGiRGTu0IHX7fZVK/img.png?width=411&amp;amp;height=211&amp;amp;face=0_0_411_211,https://scrap.kakaocdn.net/dn/bfNKEl/hyHgHrAbcD/DpU5mqOHsJfurQ6vSBPN91/img.png?width=411&amp;amp;height=211&amp;amp;face=0_0_411_211,https://scrap.kakaocdn.net/dn/eBUHb/hyHiiDHCOx/WSKZK0KsmCcTXEg6aAKCb1/img.png?width=1000&amp;amp;height=539&amp;amp;face=0_0_1000_539');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[객체지향] Object-Oriented Programming 핵심 개념의 이해&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;배경 데이터 흐름(Flow)에 기반한 절차지향적 프로그래밍 방법은 복잡한 로직을 갖는 큰 규모의 소프트웨어 개발에는 적합하지 않습니다. 하드웨어 성능이 폭발적으로 성장하면서 요구되어지는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체지향 개념을 이해하고 나서 문법적인 면에서는 &lt;b&gt;클래스(class)&lt;/b&gt;와 &lt;b&gt;접근 제한자(access modifier), new, delete&lt;/b&gt; 등의 문법을 숙지하셔야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존 C언어에서&lt;b&gt; malloc(), free()&lt;/b&gt; 대신 &lt;b&gt;new, delete&lt;/b&gt; 를 사용하면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성자(constructor)/소멸자(destructor)&lt;/b&gt;&lt;/span&gt;가 호출되는데 이러한 개념도 익혀두셔야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;간단한 프로그램을 &lt;/span&gt;객체지향적으로 설계하고 구현하는 것을 반복적으로 하다 보면 이제 Bottom-up 방식으로 사고 하는 것이 어느정도 익숙해지게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 슬슬 &lt;b&gt;템플릿(template)&lt;/b&gt;을 배워보도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;템플릿은 &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;일반화 프로그래밍(generic programming)&lt;/b&gt;&lt;/span&gt; 패러다임으로 데이터 처리하는 로직을 데이터 타입에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비종속적&lt;/b&gt;&lt;/span&gt;으로 구현할 수 있게 해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(컴파일 타임에 주어진 타입 별로 클래스들이 분화됩니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;템플릿 문법을 직접 사용해보는 것도 좋지만 &lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;STL(Strandard Template Library)&lt;/b&gt;&lt;/span&gt;을 잘 다루는 것이 매우 중요하기 때문에 STL의 컨테이너(container)들을 활용하는 연습을 많이 하는 것이 좋습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;vector, list, map&lt;/span&gt; 등의 주요 컨테이너들을 능숙하게 다룰 수 있게 되면 특별한 경우를 제외하면 대부분의 로직을 구현할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/C++</category>
      <category>c vs c++</category>
      <category>C++</category>
      <category>C++ 공부법</category>
      <category>C++ 특징</category>
      <category>c++ 패러다임</category>
      <category>C와 C++ 차이</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/132</guid>
      <comments>https://gracefulprograming.tistory.com/132#entry132comment</comments>
      <pubDate>Wed, 26 Aug 2020 17:43:14 +0900</pubDate>
    </item>
    <item>
      <title>[Linux] nohup 세션이 끊겨도 계속 실행되도록 해보자</title>
      <link>https://gracefulprograming.tistory.com/128</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;br /&gt;개요&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;nohup&lt;/b&gt; 명령어는 리눅스에서 프로세스를 실행한 터미널의 세션 연결이 끊어지더라도 지속적으로 동작 할 수 있게 해주는 명령어입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;기본적으로 터미널에서 세션&amp;nbsp;&lt;b&gt;로그아웃(logout)&lt;/b&gt;이 발생하면&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;리눅스는 해당 터미널에서 실행한 프로세스들에게 &lt;b&gt;HUP signal&lt;/b&gt; 이 전달하여 종료시키게 되는데,&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;이 HUP signal을 프로세스가 &lt;b&gt;무시(ignore)&lt;/b&gt;하도록 하는 명령어라서 &lt;b&gt;nohup&lt;/b&gt; 이라는 이름인 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 결과적으로 터미널에서 연결이 끊기거나 터미널을 종료해도 실행했던 프로세스들이 계속 실행될 수 있는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한 nohup 명령어는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;표준 출력(standard output)&lt;/b&gt;&lt;/span&gt;을 &lt;b&gt;nohup.out&lt;/b&gt; 파일로 &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;재지향(redirection)&lt;/b&gt; &lt;/span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;터미널이 종료되어도 표준 출력은 nohup.out 파일에 계속해서 기록되기 때문에 프로세스의 상태를 확인하는데 유용 할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;그러나 필요 이상의 로그를 화면에 계속해서 출력하게 되면 nohup.out 파일의 용량이 매우 커지기 때문에&amp;nbsp; 디스크 공간을 낭비하게 될 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;따라서 꼭 필요한 로그만 출력하거나 로그를 남기는 것이 불필요한 경우 재지향을 통해 nohup.out 파일을 생성하지 않도록 하는 것이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;사용법&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;nohup 명령어의 사용법은 매우 단순합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597685790492&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nohup [프로세스] &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;[프로세스] 부분에 실행하고자 하는 프로그램이나 스크립트를 지정하면 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;여러분이 작성한 스크립트를 넣어도 되는데 스크립트 파일의 권한이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;755&lt;/b&gt;&lt;/span&gt; 이상이어야 합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;일반적으로 nohup 명령어를 사용할 때는 백그라운드 작업으로 실행하는 경우가 많기 때문에 뒤에 &lt;b&gt;&amp;amp;&lt;/b&gt; 를 붙여서 백그라운드 실행이라는 것을 명시해 줍니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;nohup.out 파일을 생성하지 않으려면 표준출력과 표준에러를 /dev/null 로 재지향 해주면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597686044108&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nohup [프로세스] 1&amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;i&gt;1&amp;gt;/dev/null&lt;/i&gt; 은 표준 출력을 사용하지 않겠다는 의미이고, &lt;i&gt;2&amp;gt;&amp;amp;1&lt;/i&gt; 은 표준 에러를 표준 출력과 같게 만드는 명령어입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;nohup 으로 실행한 프로세스를 종료하려면 먼저 ps 명령어로 PID를 식별한 다음,&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;kill 명령어를 사용하여 해당 프로세스에 종료 시그널을 보내서 종료해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597686604818&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ps -ef | grep [프로세스명]

# PID 식별 후
kill -15 [PID]

# 종료되지 않으면 강제 종료 (비권장)
kill -9 [PID]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;위에서 사용된 재지향, kill, ps 명령어 등은 아래 글들을 참고해주세요.&lt;/p&gt;
&lt;figure id=&quot;og_1597686621470&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Linux] 재지향(Redirection)에 대한 이해&quot; data-og-description=&quot;안녕하세요 피터입니다. 오늘은 리눅스의 I/O 재지향(redirection)에 대해서 설명드리겠습니다. 재지향은 파이프(pipe)와 더불어 리눅스의 명령어들을 훨씬 강력하게 무장시켜주는 역할을 하는 핵심 &quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/100&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/100&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcqDy6/hyG9wcFMrk/TGVLEx22IK8qqTa1eJLzOK/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/chNgBr/hyHbalwKa9/hl7gSr8o8jGbTeMyu84wak/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/brzzo1/hyHbd3CVoh/7sVuabmcvsRwkgTiOgc0J1/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/100&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/100&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcqDy6/hyG9wcFMrk/TGVLEx22IK8qqTa1eJLzOK/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/chNgBr/hyHbalwKa9/hl7gSr8o8jGbTeMyu84wak/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/brzzo1/hyHbd3CVoh/7sVuabmcvsRwkgTiOgc0J1/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Linux] 재지향(Redirection)에 대한 이해&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 피터입니다. 오늘은 리눅스의 I/O 재지향(redirection)에 대해서 설명드리겠습니다. 재지향은 파이프(pipe)와 더불어 리눅스의 명령어들을 훨씬 강력하게 무장시켜주는 역할을 하는 핵심&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1597686311677&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Linux] kill  프로세스를 '안전하게' 종료시켜보자&quot; data-og-description=&quot;개요 kill 명령어는 이름 때문에 프로세스를 강제로 종료시키는 명령어로 오해를 사기 쉬운데 실제로는 프로세스에 시그널(signal)을 보내는 명령어입니다. 이름이 kill 인 이유는 어떤 시그널을 보&quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/127&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/127&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c8CstC/hyHa4FBZvS/sRqv9RPlwVxrHUWLJ89vmK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/c2TYvb/hyHa885mHo/LLJR9D878GvD7QvpwIjY4k/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/dmOZgt/hyHbeIdPRf/t2ysqYKbOrnKoR7cNkBVA0/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/127&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/127&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c8CstC/hyHa4FBZvS/sRqv9RPlwVxrHUWLJ89vmK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/c2TYvb/hyHa885mHo/LLJR9D878GvD7QvpwIjY4k/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/dmOZgt/hyHbeIdPRf/t2ysqYKbOrnKoR7cNkBVA0/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Linux] kill 프로세스를 '안전하게' 종료시켜보자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 kill 명령어는 이름 때문에 프로세스를 강제로 종료시키는 명령어로 오해를 사기 쉬운데 실제로는 프로세스에 시그널(signal)을 보내는 명령어입니다. 이름이 kill 인 이유는 어떤 시그널을 보&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1597686654954&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Linux] ps 로 실행 중인 프로세스 확인하기&quot; data-og-description=&quot;개요 ps 명령어는 리눅스에서 현재 실행중인 프로세스를 확인하는 명령어 입니다. Process Status에서 따온 이름이죠. 이름 그대로 명령어를 실행하면 현재 실행되고 있는 프로세스들의 정보를 화면&quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/126&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/126&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QXMza/hyG9Dixv9h/sEFWXity0pJBWyrICzusl0/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/eym5J/hyHa3fE0mD/uDId3lDvSXEHPEE3A0sPN0/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/c9s3bZ/hyHbenUJ47/6kFZYgkg5jZrH9YOSsYqvk/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/126&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/126&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QXMza/hyG9Dixv9h/sEFWXity0pJBWyrICzusl0/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/eym5J/hyHa3fE0mD/uDId3lDvSXEHPEE3A0sPN0/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/c9s3bZ/hyHbenUJ47/6kFZYgkg5jZrH9YOSsYqvk/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Linux] ps 로 실행 중인 프로세스 확인하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 ps 명령어는 리눅스에서 현재 실행중인 프로세스를 확인하는 명령어 입니다. Process Status에서 따온 이름이죠. 이름 그대로 명령어를 실행하면 현재 실행되고 있는 프로세스들의 정보를 화면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <category>linux nohup</category>
      <category>nohup</category>
      <category>nohup 명령어</category>
      <category>리눅스 노헙</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/128</guid>
      <comments>https://gracefulprograming.tistory.com/128#entry128comment</comments>
      <pubDate>Tue, 18 Aug 2020 02:46:07 +0900</pubDate>
    </item>
    <item>
      <title>[bash 쉘 스크립트] 변수 할당(assignment)과 치환(substitution)</title>
      <link>https://gracefulprograming.tistory.com/131</link>
      <description>&lt;h2&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;안녕하세요&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;피터&lt;/b&gt;입니다.&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;오늘은 Bash 쉘 스크립트에서 사용되는 &lt;b&gt;변수(variable)&lt;/b&gt;에 대해서 설명드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변수는 모든 프로그래밍 언어와 스크립트 언어에서 핵심적인 기능을 합니다. 데이터를 조작하기 위한 연산이나 문자열을 파싱(parsing)하는데 있어서 없어서는 안될 꼭 필요한 존재입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변수는 단지 데이터를 담고 있는 메모리상의 위치를 나타내는데 어떤 변수에 어떤 데이터가 담겨있는지 쉽게 알 수 있게 이름을 붙여놓은 것입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변수 할당(assignment)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터를 담는 공간인 변수를 사용하려면 먼저 변수를 &lt;b&gt;할당(assignment)&lt;/b&gt; 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수는 할당 연산자 &lt;b&gt;=&lt;/b&gt; 를 사용해서 할당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597669774929&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a=100
b=&quot;hello&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주의 해야 할 것은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;할당 연산자 앞뒤로 공백이 없어야 한다는 것&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;입니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(또한 테스트 연산자도&amp;nbsp;&lt;b&gt;= &lt;/b&gt;심볼을 쓰기 때문에 헷갈리지 말아야 합니다. 상황에 따라 해석이 달라지니 주의해주세요. 이 부분은 나중에 테스트 연산자 설명드릴 때 다시 말씀드리겠습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Bash 는 다른 프로그래밍 언어들과는 달리, 변수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;타입&quot;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;으로 구분하지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Bash 변수는 본질적으로 문자열이지만 Bash 가 문맥에 따라서 정수 연산이나 변수를 비교해 줍니다. 이 동작을 결정짓는 요소는 &lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그 변수값이 숫자로만 되어 있는냐 아니냐&lt;/b&gt;&lt;/span&gt;&lt;/u&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;let&lt;/b&gt; 명령어로 할당 할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;let은 bash 의 내장 명령어 중에 하나로 간단한 산술식을 수행 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597669789089&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let a=1000+4
let &quot;a = 1000 + 4&quot;   # 위와 같음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;가독성을 위해서는 &lt;b&gt;&quot; &quot;&lt;/b&gt; 를 이용해서 &lt;b&gt;쿼우팅(quoting)&lt;/b&gt; 하고 연산자 사이에 빈칸(space)을 넣어주는게 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수를 할당 할 때는 위의 숫자 &lt;b&gt;100&lt;/b&gt;이나 문자열 &lt;b&gt;&quot;hello&quot;&lt;/b&gt;와 같은 &lt;b&gt;리터럴 상수(literal constant)&lt;/b&gt; 뿐만 아니라 명령어의 결과를 할당 할 수도 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;바로 &lt;b&gt;명령어 치환(command substitution)&lt;/b&gt;을 사용하는 방법인데요.&amp;nbsp; &lt;b&gt;역따옴표(` `) -&lt;/b&gt;&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;백틱(backticks)으로 명령어를 감싸면 해당 명령어의 결과로 치환되어 그 결과를 변수에 바로 할당 할 수가 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597671005617&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ret=`ls -l`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;명령어 치환에 대해서는 다룰 내용이 좀 더 많기 때문에 나중에 포스팅을 추가로 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변수 치환(&lt;span style=&quot;color: #000000;&quot;&gt;substitution)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수는 데이터를 담고 있는 그릇 역할을 하므로, 할당하였으면 이제 변수에 담겨있는 데이터를 사용 할 수 있어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수에는 어떤 계산을 하기 위해 임시로 저장한 중간값이나 특정 명령어의 결과값 등이 저장되어 있는데 이 값들을 확인하거나 적절히 활용하기 위해서는 &lt;b&gt;치환(substitution)&lt;/b&gt;을 통해 변수의 데이터를 참조해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;치환은 &lt;b&gt;${variable}&lt;/b&gt; 구문을 이용하여 사용하는데 &lt;b&gt;$variable&lt;/b&gt; 로 줄여 쓸 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;참조되는 값을 &lt;b&gt;큰따옴표(&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;)&lt;/b&gt;로 묶어도 변수 치환이 일어나는 것을 막지 못합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;부분적 쿼우팅(partial quoting)&lt;/b&gt;&lt;/span&gt;이나&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;약한 쿼우팅(weak quoting)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이라고 합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;작은따옴표를 쓰게 되면 변수 이름이 그냥 문자 그대로 해석되어 아무런 일도 일어나지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;완전한 쿼우팅(full quoting)&lt;/b&gt;&lt;/span&gt;이나&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;강한 쿼우팅(strong quoting)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597669680917&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

a=1004
echo &quot;$a&quot;  # $a 변수 치환이 일어남 
echo '$a'  # $a를 문자 그대로 해석 


실행 결과
100
$a
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수를 할당하지 않고 참조하게 되면 문제가 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변수에 어떤 값을 처음 할당 하는 것을 초기화(initialize)라고 하는데,&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;초기화가 안 된 변수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;null&quot;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;값을 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는 값이 할당 안 된 것이지 0 이라는 값을 갖는다는 이야기가 아닙니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;변수를 참조하기 전에 반드시 할당을 먼저 해주시기 바랍니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 남겨주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Bash</category>
      <category>bash</category>
      <category>bash script</category>
      <category>bash variable</category>
      <category>bash 변수</category>
      <category>substitution</category>
      <category>변수</category>
      <category>치환</category>
      <category>할당</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/131</guid>
      <comments>https://gracefulprograming.tistory.com/131#entry131comment</comments>
      <pubDate>Mon, 17 Aug 2020 22:49:43 +0900</pubDate>
    </item>
    <item>
      <title>[객체지향] Object-Oriented Programming 핵심 개념의 이해</title>
      <link>https://gracefulprograming.tistory.com/130</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데이터 흐름(Flow)&lt;/b&gt;에 기반한 절차지향적 프로그래밍 방법은 복잡한 로직을 갖는 큰 규모의 소프트웨어 개발에는 적합하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하드웨어 성능이 폭발적으로 성장하면서 요구되어지는 소프트웨어는 점점 복잡해지고 거대해졌는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존의 전통적인 &lt;b&gt; &lt;span&gt;절차지향 개발 방법&lt;/span&gt; &lt;/b&gt;으로는 소프트웨어를 설계 및 구현하는데 많은 어려움이 생긴 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;(사실 소프트웨어 공학 - software engineering 이라는 개념도 생소할 시기였습니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한 문제를 해결하기 위해 프로그램을 &lt;b&gt;함수(procedure)&lt;/b&gt; 단위로 나누어 구조화하는 구조적 프로그래밍 방법이 대두되었는데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;상위로부터 하위로 쪼개나가는 방식이기 때문에 &lt;b&gt;Top-Down &lt;/b&gt;방식이라고도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만&amp;nbsp;&lt;span&gt;함수는 데이터를 처리하는 부분은 구조화할 수 있었지만 데이터는 구조화하지 못해&amp;nbsp;&lt;/span&gt; &lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;전역 네임스페이스 포화 문제&lt;/span&gt;를 유발하게 되었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;image2019-11-20_0-53-1.png&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;424&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc7dfr/btqGn0TgFV5/XhuGNqKgdMzvJ6o5WYLJF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc7dfr/btqGn0TgFV5/XhuGNqKgdMzvJ6o5WYLJF1/img.png&quot; data-alt=&quot;출처: IT World&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc7dfr/btqGn0TgFV5/XhuGNqKgdMzvJ6o5WYLJF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc7dfr%2FbtqGn0TgFV5%2FXhuGNqKgdMzvJ6o5WYLJF1%2Fimg.png&quot; data-filename=&quot;image2019-11-20_0-53-1.png&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;424&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: IT World&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또한 데이터의 상태에 따라 다르게 동작하는 함수들이 많아지면서 각 함수들로 전달되는 변수들이 적절한 값을 갖는지 확인하는 코드가 늘어났으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;문제가 발생했을 때 함수에 영향을 주는 변수를 추적하는 것이 프로그램의 규모가 커질 수록 어려워졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로그램에 버그가 있는 경우 원인을 분석하는데 그만큼 많은 시간과 노력이 더 필요해지는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, 소프트웨어의 유지 관리 비용이 규모에 따라 대폭 증가하는 문제가 발생합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이것이 하드웨어가 &lt;b&gt;무어의 법칙&lt;/b&gt;(&lt;span&gt;Moore's law)&lt;/span&gt;대로 폭발적으로 성장 하던 시기에 소프트웨어의 위기(&lt;span&gt;software crisis)&lt;/span&gt;를 초래한 가장 큰 이유 중에 하나입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한 문제들을 해결하기 위해 등장한 것이 &lt;span&gt; &lt;b&gt;객체지향 프로그래밍&lt;/b&gt;(&lt;b&gt;O&lt;/b&gt;bject-&lt;b&gt;O&lt;/b&gt;riented &lt;b&gt;P&lt;/b&gt;rogramming) &lt;/span&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;(줄여서 &lt;b&gt;OOP&lt;/b&gt; 라고도 많이 불립니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체지향 프로그래밍은 큰 문제를 작게 쪼개는 방식이 아니라 작은 문제들을 해결할 수 있는 객체들을 만든 뒤,&amp;nbsp;이 객체들을 조합해서 큰 문제를 해결하는 &lt;b&gt;Bottom-Up&lt;/b&gt; 방식을 지향합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각각의 객체들은 다른 객체들과 독립적으로 운용이 가능하며 객체 외부에서 접근이 가능한 인터페이스를 제한하여 잘못 사용되어지는 경우를 최소화 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;독립적&lt;/b&gt;이라는 것은 다른 객체와의 &lt;b&gt;의존성(dependency)&lt;/b&gt;이 낮다는 의미인데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하나의 객체의 코드를 수정했을 때 해당 객체를 사용하는 객체는 코드를 수정하지 않아도 되면 의존성이 낮은 &lt;span style=&quot;color: #006dd7;&quot;&gt;약한 결합 관계(weak coupling)&lt;/span&gt;이고, 반대로 다른 객체의 코드도 수정해야 되는 경우는 의존성이 &lt;span style=&quot;color: #ee2323;&quot;&gt;높은 강한 결합 관계(strong coupling)&lt;/span&gt;라고 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체간 독립성이 높계 설계되어 있다면 요구사항 변경 등의 이유로 코드 수정이 필요할 때 상대적으로 적은 범위의 코드만 수정해도 되기 때문에 유지 관리 비용을 낮출 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또한 외부에서 사용하는 인터페이스 외에는 객체 내부로 숨겨(information hiding) 객체의 기능(method)이나 속성(property)이 설계와 다르게 동작할 위험을 최소화 할 수 있기 때문에 &lt;b&gt;신뢰성&lt;/b&gt;이 높습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체들의 독립성/신뢰성을 높게 설계 해 놓으면 별다른 수정 없이 재사용 할 수 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;요구사항이 변경되어 코드를 수정하게 되도 제한된 영역만 수정하면 되기 때문에 개발 기간과 유지관리 비용을 비약적으로 줄일 수 있게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체지향 핵심 개념&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;객체지향(Object-Oriented)&lt;/b&gt;이라고 하면 객체를 지향한다는 말이 선뜻 이해가 되지 않을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;원문의 oriented를 지향(&lt;span style=&quot;color: #000000;&quot;&gt;志向)이라고 바꾸지 않고 그대로의 의미를 한번 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAinoA/btqGuN73a3D/xMy79ONhZkVE5xwOM6psg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAinoA/btqGuN73a3D/xMy79ONhZkVE5xwOM6psg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAinoA/btqGuN73a3D/xMy79ONhZkVE5xwOM6psg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAinoA%2FbtqGuN73a3D%2FxMy79ONhZkVE5xwOM6psg0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;-Oriented&lt;/b&gt; 를 [&lt;i&gt;~에 주된 관심을 두다], [~를 주된 관심으로 삼다]&lt;/i&gt; 정도로 해석하면 좀 더 이해가 쉽습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, 객체지향 프로그래밍은 &lt;span style=&quot;color: #006dd7;&quot;&gt;객체(object)를 주된 관심으로 삼는 프로그래밍 방법론&lt;/span&gt;을 뜻하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇다면 객체는 무엇을 말하는 걸까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기에서 말하는 객체를 이해하려면 먼저 &lt;span style=&quot;color: #333333;&quot;&gt;객체 지향의 핵심 개념 중에 하나인 &lt;/span&gt;&lt;b&gt;추상화&lt;/b&gt;라는 개념을 이해해야 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추상화 (abstraction)&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;추상화&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #5733b1;&quot;&gt;(抽象化 : abstraction)&lt;/span&gt;란 현실 세계에서 특정한 대상을 관찰하여 핵심적이고 특징적인 공통점들을 뽑아내는 과정을 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;피카소는 &lt;span style=&quot;color: #006dd7;&quot;&gt;추상화&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(抽象畫 : abstract painting)&lt;/span&gt;의 대가입니다. 피카소의 그림들은 얼핏 단조로워 보일 수 있지만 핵심적인 특징들이 매우 잘 나타나 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이것은 그가 그림을 그리기 전에 오랜 기간 대상을 관찰하였기 때문에 가능했던 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래의 &lt;/span&gt;그림은 오랜 기간 황소를 관찰하고 그림을 그리면서 핵심적인 특징만 남겨두고 제거해나간 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마지막 황소 그림을 보면 단순한 선 몇 개로 황소를 표현하였지만 특징이 잘 나타나 있어 한눈에 봐도 황소라는 것을 알 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/45WA6/btqGted0tak/jbfqnXlVLWJkBVtt9R8Awk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/45WA6/btqGted0tak/jbfqnXlVLWJkBVtt9R8Awk/img.png&quot; data-alt=&quot;황소 (피카소), 1945&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/45WA6/btqGted0tak/jbfqnXlVLWJkBVtt9R8Awk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F45WA6%2FbtqGted0tak%2FjbfqnXlVLWJkBVtt9R8Awk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;황소 (피카소), 1945&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;추상화&lt;span style=&quot;color: #000000;&quot;&gt;(abstraction)&lt;/span&gt;에서 핵심적인 특징이라는 것은 대상에 대한 &lt;u&gt;현재 내가 구현하고자 하는 프로그램에서의 관심사&lt;/u&gt;라고 할 수 있습니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 외의 특징들은 어떤 관점에서는 중요한 특징들일지 몰라도 현재 프로그램을 구현하는데 불필요하기 때문입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 줄이고 줄여서 뽑아낸 공통적인 특징들은 크게 &lt;b&gt;속성(attribute)&lt;/b&gt;와 &lt;b&gt;행위(behavior)&lt;/b&gt;로 나뉘게 되는데 이것들을 관련있는 것들끼리 묶어놓은 것을 &lt;b&gt;캡슐화(encapsulation)&lt;/b&gt;라고 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그리고 관련있는 것들을 하나로 묶는 개념적(추상적)인 주체가 바로 &lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;클래스(class)&lt;/b&gt;&lt;/span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size18&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;attribute = property = member variable = field = state&lt;br /&gt;behavior = method = member function = operation&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;객체(object)&lt;/b&gt;는 클래스로부터 실체화된 것을 말합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;클래스는 추상적이기 때문에 눈에 보이지 않고 개념적으로만 존재하지만 객체는 눈에 보이는 실체가 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&quot;바나나&quot;&lt;/b&gt;&lt;/span&gt;라는 클래스가 있다고 하면 우리는 개념적으로 &lt;span style=&quot;color: #f89009;&quot;&gt;바나나&lt;/span&gt;가 갖고 있는 특징들을 떠올릴 수 있습니다. 껍질은 노란색이고 속은 하얗고 맛은 달고 길쭉한 모양이라는 특징들을요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만 실제로 &lt;span style=&quot;color: #006dd7;&quot;&gt;바나나&lt;/span&gt;를 먹기 위해서는 마트에 가서 진열대에 놓여있는 실제의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;바나나(object)&quot;&lt;/b&gt;&lt;/span&gt; 사와야 합니다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;마트 직원에게 &quot;&lt;span style=&quot;color: #f89009;&quot;&gt;바나나&lt;/span&gt; 어디 있나요?&quot; 라고 물어볼 때 마트 직원이 안내를 해 줄 수 있는 것은 나와 마트 직원이 모두 &lt;span style=&quot;color: #f89009;&quot;&gt;바나나&lt;/span&gt;라는 추상적인 개념을 알고 있기 때문에 가능한 것입니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;진열대에는 &lt;span style=&quot;color: #006dd7;&quot;&gt;바나나&lt;/span&gt;가 여러 개 있을 수 있죠. 그 중에 내가 어떤 &lt;span style=&quot;color: #006dd7;&quot;&gt;바나나&lt;/span&gt;를 사서 먹었다면 그 &lt;span style=&quot;color: #006dd7;&quot;&gt;바나나&lt;/span&gt;는 다른 &lt;span style=&quot;color: #006dd7;&quot;&gt;바나나들&lt;span style=&quot;color: #000000;&quot;&gt;과&lt;/span&gt;&lt;/span&gt;&amp;nbsp;구별되는 유일한 실체입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 예문에서 글씨색으로 클래스와 객체를 구분해놓았는데 차이를 아시겠지요?&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;개(dog)&lt;/span&gt;라는 클래스가 있다면 우리집 강아지 &lt;span style=&quot;color: #006dd7;&quot;&gt;로이&lt;/span&gt;, 옆집 강아지 &lt;span style=&quot;color: #006dd7;&quot;&gt;초코&lt;/span&gt;는 객체인 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;캡슐화(encapsulation)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 설명드린대로 캡슐화란 속성과 행위들을 관련있는 것끼리 묶는 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 때 중요한 것은 외부에서 접근이 필요한 부분을 제외하고는 내부로 &lt;u&gt;숨기는 것&lt;/u&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우리가 알약을 먹을 때 중요한 것은 약의 성분이 인체에 미치는 영향이지 약의 맛이나 식감이 아니기 때문에 캡슐 속으로 숨기는 것과 마찬가지이죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wELoV/btqGxPqpCix/xVwXhWy8Q8NOrXQj3K0IGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wELoV/btqGxPqpCix/xVwXhWy8Q8NOrXQj3K0IGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wELoV/btqGxPqpCix/xVwXhWy8Q8NOrXQj3K0IGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwELoV%2FbtqGxPqpCix%2FxVwXhWy8Q8NOrXQj3K0IGK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 외부로부터 세부적인 내용을 숨기는 것을 &lt;b&gt;정보 은닉(information hiding)&lt;/b&gt;이라고 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;세부 구현을 숨기는 목적은 클래스 내부 구현의&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 응집도(cohesion)&lt;/b&gt;&lt;/span&gt;를 높이고 외부 다른 클래스와의 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;결합도(coupling)&lt;/b&gt;&lt;/span&gt;을 낮추는 데 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일반적인 객체지향 언어에서는 이 때문에 &lt;b&gt;접근제한자(access modifier)&lt;/b&gt;라는 문법을 지원합니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;public&lt;/b&gt; : 클래스 외부에서 제한 없이 접근 가능 (nobody)&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;private&lt;/b&gt; : 클래스 외부에서 접근 불가 (클래스 내부에서만 접근 가능)&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;protected&lt;/b&gt; : 상속한 하위 클래스에서만 접근 가능&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상속(inheritance)&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;상속은 객체지향의 핵심 기능 중에 하나로 대상이 되는 클래스의 모든 특징들을 물려 받는 것을 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 임의의 클래스 B가 다른 클래스 A를 상속 받게 되면 A 클래스의 속성과 행위들을 모두 물려받게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 때 클래스 A와 B는 &lt;b&gt;상속 관계&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;(inheritance relation)&lt;/b&gt;에 있다고 하며 클래스 A&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;를 &lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;부모 클래스(parent class)&lt;/b&gt;&lt;/span&gt;, 클래스 B를 &lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;자식 클래스(child class)&lt;/b&gt;&lt;/span&gt;라고 부릅니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;717&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYdzOY/btqGvcUpV3g/L8IDMoZOz5HXZlm8IUYkP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYdzOY/btqGvcUpV3g/L8IDMoZOz5HXZlm8IUYkP1/img.png&quot; data-alt=&quot;Vehicle hirerachi&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYdzOY/btqGvcUpV3g/L8IDMoZOz5HXZlm8IUYkP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYdzOY%2FbtqGvcUpV3g%2FL8IDMoZOz5HXZlm8IUYkP1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;717&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Vehicle hirerachi&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 클래스를 이미 상속 받은 클래스를 다시 다른 클래스가 상속을 받을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;WheeledVehicle&lt;/b&gt; 클래스는 &lt;b&gt;Vehicle&lt;/b&gt; 클래스의 &lt;b&gt;Child&lt;/b&gt; 클래스인 동시에 &lt;b&gt;Bicycle&lt;/b&gt;이나 &lt;b&gt;Car&lt;/b&gt; 클래스의 &lt;b&gt;Parent&lt;/b&gt; 클래스가 되는 것이죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇게 되면 &lt;span style=&quot;color: #333333;&quot;&gt;클래스 간의 관계가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;위와 같은&lt;span style=&quot;color: #409d00;&quot;&gt; &lt;b&gt;계층형 구조(hierachical structure)&lt;/b&gt;&lt;/span&gt;를 형성하게 되는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 형태의 관계에서는 아래로 내려갈수록 &lt;b&gt;구체화(specialize)&lt;/b&gt;된다고 하고 위로 갈수록 &lt;b&gt;일반화(generalize)&lt;/b&gt;된다고 표현합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;클래스가 구체화 될수록 고유의 특징들이 더 많이 생겨나게 되고, 일반화 될수록 더 많은 객체에 영향을 주게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;부모 클래스로부터 특징들을 물려받게 되면 이미 구현된 세부 내용을 다시 구현할 필요가 없기 때문에 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드의 재사용성(resusability)&lt;/b&gt;&lt;/span&gt;이 향상됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;많은 분들이 클래스 간의 상속 관계를 형성 할 때 이처럼 코드의 재사용성에 주안점을 두게 되는데 자칫하면 더 큰 혼란을 야기할 수 있어 주의가 필요합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;상속 관계가 성립하려면 두 클래스 간의 관계가&lt;b&gt; is-a&lt;/b&gt; 관계여야 합니다.&amp;nbsp; is-a 관계란 &lt;i&gt;[~은 ~이다]&lt;/i&gt; 라고 부를 수 있는 관계입니다. &lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;(예를들면&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;바나나&lt;/span&gt;는 &lt;span style=&quot;color: #a6bc00;&quot;&gt;과일&lt;/span&gt;이다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, 자식 클래스가 들어간 문장이 있을 때 자식 클래스를 부모 클래스로 대체하여도 의미가 성립되어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 그림에 있는 WheeledVehicle 은 &quot;바퀴가 있는 탈 것&quot;이라는 뜻입니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자동차(Car)는 WheeledVehicle 이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자전거(Bicycle)은 WheeledVehicle 이다.&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;li data-ke-size=&quot;size18&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;보트(Boat)는 Vehicle 이다.&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;세 문장 모두 is-a 관계에 있기 때문에 제대로 된 상속 관계라고 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일반적으로 가장 많이 하는 실수는 &lt;b&gt;has-a&lt;/b&gt; 관계인 클래스를 상속하는 경우입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;has-a 관계는 사람-팔, 자동차-바퀴, 새-날개 등을 예로 들 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉, 하나의 클래스가 다른 클래스의 일부로 속할 때 has-a 관계가 성립됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한 has-a 관계의 클래스를 코드 재사용성 측면만 고려하여 상속을 하게 되면 자연스러운 모델링이 되지 못하고 큰 혼란을 불러 올 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇다면 상속은 어떠한 경우에 사용하는 것이 좋을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;바로 다음에 설명드릴 &lt;b&gt;다형성&lt;/b&gt;을 구현하기 위해서 사용하는 것을 권장드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;물론 기본적으로 is-a 관계가 성립되어야 겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다형성(polymorphism)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다형성은 그리스어에서 기원된 단어의 합성어로 &lt;span style=&quot;color: #006dd7;&quot;&gt;'여러 형태가 존재한다&lt;/span&gt;' 라는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;객체지향에서 다형성이란 하나의 속성이나 행위가 &lt;b&gt;상황에 따라 다른 의미로 해석&lt;/b&gt;될 수 있는 특징을 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다형성이야말로 &lt;span style=&quot;color: #a6bc00;&quot;&gt;객체지향의 꽃&lt;/span&gt;이라고 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그만큼 중요하고 핵심이 되는 개념 중에 하나입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다향성을 구현하는 방법 중에 대표적인 방법이 바로 위에서 설명드린 &lt;b&gt;상속(inheritance)&lt;/b&gt;을 이용한 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;상위 클래스의 메소드를 하위 클래스에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;재정의(override)&lt;/b&gt;&lt;/span&gt;하여 상위 클래스의 참조변수가 어떠한 하위 클래스의 &lt;b&gt;인스턴스&lt;/b&gt;를 &lt;b&gt;참조&lt;/b&gt;하느냐에 따라 동작이 달라지는 개념으로 이러한 방식으로 구현되는 다형성을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;서브타입 다형성(subtype polymorphism)&lt;/b&gt;&lt;/span&gt; 이라고 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예를들어 &lt;b&gt;이동(move)&lt;/b&gt;라는 행위는 여러 가지 형태를 가질 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&quot;현재 위치에서 특정 위치로 옮겨간다&quot; 라는 목적은 같지만 실제로 이동하는 대상에 따라서 이동하는 방식이 달라질 수 있는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;직립보행을 하는 사람은 두 발로 걷거나 뛸 수 있으며 자동차나 자전거 등의 이동 수단을 사용 할 수도 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;개나 고양이 같은 동물들은 네 발로 이동을 하고 새나 날개가 있는 곤충들은 날아서 이동 할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이처럼 이동(move)이라는 행위에 대해 여러 가지 형태가 존재하기 때문에 전통적인 프로그래밍 방법으로는 &lt;b&gt;if&lt;/b&gt; 구문이 반복적으로 사용되는 복잡한 코드가 생겨날 가능성이 높습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;oop_polymorphism.png&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;431&quot; width=&quot;541&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PsSBc/btqGCMUKszI/xtTcC8OMthSOAKALeDGQ4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PsSBc/btqGCMUKszI/xtTcC8OMthSOAKALeDGQ4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PsSBc/btqGCMUKszI/xtTcC8OMthSOAKALeDGQ4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPsSBc%2FbtqGCMUKszI%2FxtTcC8OMthSOAKALeDGQ4k%2Fimg.png&quot; data-filename=&quot;oop_polymorphism.png&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;431&quot; width=&quot;541&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체지향에서는 &lt;b&gt;상속(inheritance)&lt;/b&gt;과 &lt;b&gt;재정의(override)&lt;/b&gt;를 통해 효과적으로 구현해낼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;클래스간의 관계가 위와 같고 하위 클래스에서 &lt;b&gt;Move()&lt;/b&gt; 메소드를 재정의 하고 있다고 전제하면 아래와 같이 &lt;span style=&quot;color: #f89009;&quot;&gt;Animal&lt;/span&gt; 클래스 타입의 참조로 다형성을 구현해 낼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597378019257&quot; class=&quot;cs&quot; data-ke-language=&quot;cs&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Animal&amp;gt; animals = new List&amp;lt;Animal&amp;gt;();

animals.add(new Human());
animals.add(new Dog());
animals.add(new Bird());

foreach(Animal animal in animals)
{
	animal.Move();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 코드는 이해를 돕기 위해 C#으로 간단하게 작성한 코드입니다. 실제 구현은 세부적인 내용이 더 늘어나겠지만 전체적인 맥락은 크게 변하지 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;animals List에 들어 있는 객체(instance)들은 각각 &lt;span style=&quot;color: #006dd7;&quot;&gt;Human, Dog, Bird&lt;/span&gt; 타입의 인스턴스지만 &lt;span style=&quot;color: #f89009;&quot;&gt;Animal&lt;/span&gt; 타입으로 참조하고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;Animal&lt;/span&gt; 타입으로 일반화 하여 Move() 메소드를 호출하면 &lt;span style=&quot;color: #f89009;&quot;&gt;Animal&lt;/span&gt; 클래스에 정의되어 있는 Move()가 실행되는 것이 아니라 각각의&lt;span style=&quot;color: #006dd7;&quot;&gt; 하위 클래스&lt;/span&gt;에 구현된 Move() 메소드가 호출됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이렇게 비즈니스 로직(bussiness logic)을 일반화된 코드로 구현해놓으면 여러 가지 장점이 생깁니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;요구사항(requirements)&lt;/b&gt;이 변경되어 코드를 수정해야 하는 경우에 위처럼 일반화된 코드는 변경하지 않고 기존 클래스의 Move() 메소드만 수정하거나 &lt;span style=&quot;color: #333333;&quot;&gt;클래스를 추가 구현하는 것으로 해결할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한 코드의 &lt;b&gt;가독성(&lt;span style=&quot;color: #000000;&quot;&gt;readability)&lt;/span&gt;&lt;/b&gt;이 높아지고 일관성이 생기기 때문에 개발자의 실수를 줄일 수 있게 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;지금까지 객체지향 개념이 만들어지게 된 배경과 핵심 개념에 대해서 설명드렸습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체지향 프로그래밍을 한다는 것은 단순히 객체지향 언어를 사용하여 개발을 하는 것을 뜻하지는 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;많은 분들이 객체지향을 공부 할 때 객체지향을 지원하는 언어(C#이나 Java 등)의 도서를 구매하여 문법이나 언어적인 특성을 익히는 것으로 시작하는데 문법 보다는 &lt;b&gt;개념&lt;/b&gt;과 &lt;b&gt;원리&lt;/b&gt;를 이해는 것이 우선입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래야만 객체지향적으로 사고 할 수 있으며 보다 유연하고 안정적인 프로그램을 설계 할 수 있는 능력을 배양 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 글을 읽으신 분들께 객체지향을 이해하는 데 도움이 되었길 바라며 앞으로 객체지향 원칙, UML, 디자인 패턴(design patterns) 등의 글들을 써나갈 계획입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>객체지향/개념과 원리</category>
      <category>abstraction</category>
      <category>encapulation</category>
      <category>Inheritance</category>
      <category>OOP 개념</category>
      <category>Polymorphism</category>
      <category>객체지향</category>
      <category>객체지향 개념</category>
      <category>다형성</category>
      <category>추상화</category>
      <category>캡슐화</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/130</guid>
      <comments>https://gracefulprograming.tistory.com/130#entry130comment</comments>
      <pubDate>Fri, 14 Aug 2020 13:39:27 +0900</pubDate>
    </item>
    <item>
      <title>[Linux] kill  프로세스를 '안전하게' 종료시켜보자</title>
      <link>https://gracefulprograming.tistory.com/127</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;kill&lt;/b&gt; 명령어는 이름 때문에 프로세스를 강제로 종료시키는 명령어로 오해를 사기 쉬운데 실제로는 프로세스에 &lt;b&gt;시그널(signal)&lt;/b&gt;을 보내는 명령어입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이름이 kill 인 이유는 어떤 시그널을 보낼 지 지정하지 않으면 기본적으로 &lt;b&gt;SIGTERM&lt;/b&gt; 시그널을 보내게 되는데 SIGTERM의 기본 동작이 프로그램 종료이기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;물론 프로세스에 &lt;b&gt;SIGKILL&lt;/b&gt;&amp;nbsp;시그널을 보내 강제로 종료시킬 수도 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇지만 일반적인 상황에서 SIGKILL 시그널을 보내는 것은 권장되지 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;본래 프로그램을 설계 할 때 대부분의 경우 &lt;b&gt;종료 시그널&lt;/b&gt;을 받았을 때 처리하고 있던 데이터가 안전하게 정리 될 수 있도록 설계합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SIGTERM, SIGINT&lt;/b&gt; 등의 종료 시그널에 대해 &lt;b&gt;시그널 핸들러(handler)&lt;/b&gt;를 등록하여 시그널이 수신되었을 때 연결된 Socket 또는 File을 close 하거나 Queue에 적재된 데이터를 File로 Dump하기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;처리 중이던 데이터를 안전하게 정리/보관하여 데이터 유실을 방지하고 다시 실행하였을 때 기존 작업을 이어나갈 수 있게 하기 위함입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그런데 &lt;b&gt;SIGKILL&lt;/b&gt; 시그널은 프로그램에서 핸들러를 만들 수 없는 시그널이기 때문에 위와 같은 처리들을 구현 할 수 없습니다. 따라서 SIGKILL 시그널을 통해 프로세스를 강제로 종료해버리면 데이터 유실과 같은 문제가 생길 우려가 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596774958245&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kill -KILL PID

or

kill -9 PID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로세스를 안전하게 종료시키려면 위와 같이 SIGKILL을 통한 종료는 가급적 사용하지 않는게 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시그널(signal)&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596775276323&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev dev]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;kill 명령어에&lt;b&gt; -l&lt;/b&gt; 옵션을 주면 위와 같이 시그널의 숫자(number)와 이름이 출력됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;시그널을 보낼 때는 &lt;b&gt;kill -(보낼 시그널) PID&lt;/b&gt; 이렇게 사용하는데, 지정된 PID를 갖는 프로세스에 지정된 시그널이 전달되는 구조입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;시그널은 숫자로 지정해도 되고 앞에 SIG를 빼고 이름을 넣어도 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596775470615&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kill -INT PID

or

kill -2 PID&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위에서 언급한 대로 아무런 시그널을 지정하지 않고 &lt;b&gt;kill PID&lt;/b&gt; 이라고만 하면 &lt;b&gt;SIGTERM&lt;/b&gt; 이 전달됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;특정 이름의 프로세스 모두 종료하기&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596776541514&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kill `ps -ef | grep 프로세스이름 | grep -v grep | awk '{print $2}'`&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;파이프&lt;/b&gt;와 &lt;b&gt;grep, awk, 역따옴표(backticks : 백틱)&lt;/b&gt;을 조합하면 특정 이름의 프로세스를 모두 찾아서 종료 시킬 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;파이프와 &lt;b&gt;grep&lt;/b&gt;은 리눅스에서 가장 많이 사용되는 명령어 조합 중에 하나로 이전 스트림의 출력값에 원하는 형식으로 필터링을 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 스크립트에서 프로세스이름 부분에 와일드카드 문자나 정규표현식도 사용 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;grep -v&lt;/b&gt; 은 지정된 패턴과 일치하는 항목을 제외할 때 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기서는 &lt;span style=&quot;color: #1a5490;&quot;&gt;&quot;grep 프로세스이름&quot;&lt;/span&gt; 도 하나의 명령어기 때문에 &lt;span style=&quot;color: #1a5490;&quot;&gt;&quot;ps -ef | grep 프로세스이름&quot;&lt;/span&gt; 의 결과에 포함되는데 kill 명령어에서 이를 제외시키기 위함입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;awk&lt;/b&gt; 명령어는 입력 값(record : 레코드)을 공백 문자로 분리하여 필드(field) 단위로 처리 할 수 있게 해주는 명령어입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기서는 ps -ef 명령어의 결과에서 PID를 추출하기 위해 사용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마지막으로 &lt;b&gt;`명령어` 백틱(backticks)&lt;/b&gt;은 치환 명령어라고도 하는데 &lt;b&gt;` ` &lt;/b&gt;로 감싼 부분의 실행 결과로 &lt;b&gt;치환&lt;/b&gt;됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결과적으로 kill &lt;span style=&quot;color: #1a5490;&quot;&gt;`ps -ef | grep 프로세스이름 | grep -v grep | awk '{print $2}'`&lt;/span&gt; 에서 &lt;span style=&quot;color: #333333;&quot;&gt;`&lt;span style=&quot;color: #0593d3;&quot;&gt;ps -ef | grep 프로세스이름 | grep -v grep | awk '{print $2}'`&lt;/span&gt; 부분이 실행된 결과로 치환되어&lt;b&gt; kill PID&lt;/b&gt; 형태로 실행이 되는 것입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1596776661859&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Linux] 파이프(pipe)에 대한 이해&quot; data-og-description=&quot;안녕하세요 피터입니다. 오늘은 리눅스의 파이프(pipe)에 대해서 설명드리겠습니다. 파이프는 재지향(redirection)과 더불어 리눅스의 명령어들을 훨씬 강력하게 무장시켜주는 역할을 하는 핵심 기�&quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/92&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/92&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/baCAqd/hyG33NxMS9/ja4aRoEwQabzq58sk4Ob5K/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/bPoI3H/hyG2wcKFt9/OTvhORAsvGz2ZkJ4cnz0K1/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/VTcQ7/hyG34ZZsM4/HYi4AVuIi04LmMN3JPB3A1/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/92&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/baCAqd/hyG33NxMS9/ja4aRoEwQabzq58sk4Ob5K/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/bPoI3H/hyG2wcKFt9/OTvhORAsvGz2ZkJ4cnz0K1/img.jpg?width=500&amp;amp;height=340&amp;amp;face=0_0_500_340,https://scrap.kakaocdn.net/dn/VTcQ7/hyG34ZZsM4/HYi4AVuIi04LmMN3JPB3A1/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Linux] 파이프(pipe)에 대한 이해&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;안녕하세요 피터입니다. 오늘은 리눅스의 파이프(pipe)에 대해서 설명드리겠습니다. 파이프는 재지향(redirection)과 더불어 리눅스의 명령어들을 훨씬 강력하게 무장시켜주는 역할을 하는 핵심 기�&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1596778403810&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Linux] ps 로 실행 중인 프로세스 확인하기&quot; data-og-description=&quot;개요 ps 명령어는 리눅스에서 현재 실행중인 프로세스를 확인하는 명령어 입니다. Process Status에서 따온 이름이죠. 이름 그대로 명령어를 실행하면 현재 실행되고 있는 프로세스들의 정보를 화면&quot; data-og-host=&quot;gracefulprograming.tistory.com&quot; data-og-source-url=&quot;https://gracefulprograming.tistory.com/126&quot; data-og-url=&quot;https://gracefulprograming.tistory.com/126&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tNEYK/hyG3VosWKQ/KRjDQ6Z9eIab3VoveBk8LK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/cNLyDY/hyG36XO5El/LqxHeCUyxFrAy60EK2PknK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/eROZN/hyG2lCipeV/xQsnjyeWlgEFjwEZnJoKa0/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384&quot;&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/126&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gracefulprograming.tistory.com/126&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tNEYK/hyG3VosWKQ/KRjDQ6Z9eIab3VoveBk8LK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/cNLyDY/hyG36XO5El/LqxHeCUyxFrAy60EK2PknK/img.jpg?width=500&amp;amp;height=316&amp;amp;face=0_0_500_316,https://scrap.kakaocdn.net/dn/eROZN/hyG2lCipeV/xQsnjyeWlgEFjwEZnJoKa0/img.jpg?width=619&amp;amp;height=842&amp;amp;face=249_153_460_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Linux] ps 로 실행 중인 프로세스 확인하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;개요 ps 명령어는 리눅스에서 현재 실행중인 프로세스를 확인하는 명령어 입니다. Process Status에서 따온 이름이죠. 이름 그대로 명령어를 실행하면 현재 실행되고 있는 프로세스들의 정보를 화면&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;gracefulprograming.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분의 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <category>kill -9</category>
      <category>linux kill</category>
      <category>linux 이름으로 프로세스 종료</category>
      <category>linux 프로세스 강제 종료</category>
      <category>linux 프로세스 종료</category>
      <category>리눅스 kill</category>
      <category>리눅스 프로세스 종료</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/127</guid>
      <comments>https://gracefulprograming.tistory.com/127#entry127comment</comments>
      <pubDate>Fri, 7 Aug 2020 14:24:03 +0900</pubDate>
    </item>
    <item>
      <title>[Linux] ps 로 실행 중인 프로세스 확인하기</title>
      <link>https://gracefulprograming.tistory.com/126</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ps 명령어는 리눅스에서 현재 실행중인 프로세스를 확인하는 명령어 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Process Status&lt;/b&gt;에서 따온 이름이죠. 이름 그대로 명령어를 실행하면 &lt;span style=&quot;color: #5733b1;&quot;&gt;현재 실행되고 있는 프로세스들의 정보&lt;/span&gt;를 화면에 출력합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;윈도우에서 특정 프로세스가 실행 중인지 확인하거나 강제 종료하기 위해 작업 관리자를 사용하듯이 리눅스에서는 ps 명령어가 자주 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;특히 GUI를 사용하지 않는 서버 환경에서는 대부분의 프로세스들이 백그라운드에서 동작하기 때문에 특정 프로세스가 동작 중인지 확인하기 위해서 많이 쓰입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;bash 스크립트(script)를 통한 자동화에도 ps 명령어가 자주 사용되는데요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주로 특정 프로세스에 시그널(signal)을 보내야 할 때 &lt;b&gt;PID(process id)&lt;/b&gt;를 식별하기 위해서 쓰이기도 하고, 프로세스가 중단되면 다시 실행시키기 위해 감시하는 목적으로 쓰이기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용법&lt;/h2&gt;
&lt;pre id=&quot;code_1596555944953&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ps --help all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;shell에서 위와 같이 help 명령어를 실행하면 ps 명령어에 대한 자세한 도움말을 볼 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596554739012&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Usage:
 ps [options]

Basic options:
 -A, -e               all processes
 -a                   all with tty, except session leaders
  a                   all with tty, including other users
 -d                   all except session leaders
 -N, --deselect       negate selection
  r                   only running processes
  T                   all processes on this terminal
  x                   processes without controlling ttys

Selection by list:
 -C &amp;lt;command&amp;gt;         command name
 -G, --Group &amp;lt;GID&amp;gt;    real group id or name
 -g, --group &amp;lt;group&amp;gt;  session or effective group name
 -p, p, --pid &amp;lt;PID&amp;gt;   process id
        --ppid &amp;lt;PID&amp;gt;  parent process id
 -q, q, --quick-pid &amp;lt;PID&amp;gt;
                      process id (quick mode)
 -s, --sid &amp;lt;session&amp;gt;  session id
 -t, t, --tty &amp;lt;tty&amp;gt;   terminal
 -u, U, --user &amp;lt;UID&amp;gt;  effective user id or name
 -U, --User &amp;lt;UID&amp;gt;     real user id or name

  The selection options take as their argument either:
    a comma-separated list e.g. '-u root,nobody' or
    a blank-separated list e.g. '-p 123 4567'

Output formats:
 -F                   extra full
 -f                   full-format, including command lines
  f, --forest         ascii art process tree
 -H                   show process hierarchy
 -j                   jobs format
  j                   BSD job control format
 -l                   long format
  l                   BSD long format
 -M, Z                add security data (for SELinux)
 -O &amp;lt;format&amp;gt;          preloaded with default columns
  O &amp;lt;format&amp;gt;          as -O, with BSD personality
 -o, o, --format &amp;lt;format&amp;gt;
                      user-defined format
  s                   signal format
  u                   user-oriented format
  v                   virtual memory format
  X                   register format
 -y                   do not show flags, show rss vs. addr (used with -l)
     --context        display security context (for SELinux)
     --headers        repeat header lines, one per page
     --no-headers     do not print header at all
     --cols, --columns, --width &amp;lt;num&amp;gt;
                      set screen width
     --rows, --lines &amp;lt;num&amp;gt;
                      set screen height

Show threads:
  H                   as if they were processes
 -L                   possibly with LWP and NLWP columns
 -m, m                after processes
 -T                   possibly with SPID column

Miscellaneous options:
 -c                   show scheduling class with -l option
  c                   show true command name
  e                   show the environment after command
  k,    --sort        specify sort order as: [+|-]key[,[+|-]key[,...]]
  L                   show format specifiers
  n                   display numeric uid and wchan
  S,    --cumulative  include some dead child process data
 -y                   do not show flags, show rss (only with -l)
 -V, V, --version     display version information and exit
 -w, w                unlimited output width

        --help &amp;lt;simple|list|output|threads|misc|all&amp;gt;
                      display help and exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;가장 흔하게 사용되는 옵션은 &lt;b&gt;-e&lt;/b&gt; 와 &lt;b&gt;-f&lt;/b&gt; 옵션입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-e 옵션은 전체 프로세스를 보겠다는 옵션인데 이 옵션을 사용하지 않으면 현재 로그인된 shell에서 실행 중인 프로세스만 표시되기 때문에 대부분의 경우 -e 옵션을 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-A 로도 동일하게 사용 가능하지만 대문자 A보다는 소문자 e가 사용하기 좀 더 편합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1596556162408&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev ~]# ps
  PID TTY          TIME CMD
  756 pts/0    00:00:00 ps
23316 pts/0    00:00:01 bash
28992 pts/0    00:00:00 bash&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596556227527&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev ~]# ps -e
  PID TTY          TIME CMD
    1 ?        01:16:34 systemd
    2 ?        00:00:14 kthreadd
    3 ?        00:01:10 ksoftirqd/0
    5 ?        00:00:00 kworker/0:0H
    7 ?        00:00:00 migration/0
    8 ?        00:00:00 rcu_bh

...
...
...

 4982 ?        00:02:04 python
31680 ?        00:01:10 qmgr
32662 ?        00:00:00 pickup
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;-f&lt;/b&gt; 옵션은 프로세스의 상태 정보를 모두(full) 표시하겠다는 옵션입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596556337028&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev ~]# ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root       773 28992  0 15:51 pts/0    00:00:00 ps -f
root     23316 23302  0  2018 pts/0    00:00:01 /bin/bash
root     28992 28988  0 08:25 pts/0    00:00:00 -bash&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;프로세스를 실행한 &lt;b&gt;UID&lt;/b&gt;와 &lt;b&gt;PID&lt;/b&gt;, 그리고 부모 프로세스의 ID(&lt;b&gt;PPID&lt;/b&gt;)도 표시되며, 프로세스를 실행할 당시의 커맨드라인(command-line)도 표시 되기 때문에 자주 사용됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;같은 이름의 프로세스가 여러 개 실행 중일 때는 커맨드 라인으로 프로세스를 구분해야 하기 때문입니다. (nginx 같은 경우)&lt;/p&gt;
&lt;p&gt;여러 개의 옵션을 함께 사용할 때는 &lt;b&gt;-&lt;/b&gt; 기호는 한번만 써도 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1596556535744&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2018 ?        01:16:34 /usr/lib/systemd/systemd --system --deserialize 21
root         2     0  0  2018 ?        00:00:14 [kthreadd]
root         3     2  0  2018 ?        00:01:10 [ksoftirqd/0]
root         5     2  0  2018 ?        00:00:00 [kworker/0:0H]
root         7     2  0  2018 ?        00:00:00 [migration/0]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-u 옵션을 사용하면 특정 사용자 계정(UID)으로 실행되고 있는 프로세스만 볼 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596593589995&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@localhost ~]# ps -fu node_manager
UID         PID   PPID  C STIME TTY          TIME CMD
node_ma+ 183483      1  0  8월04 ?      00:09:22 java -jar -Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m node_manager-0.0.1-SNAP
node_ma+ 199085 199067  0  8월03 ?      00:00:00 sshd: node_manager@pts/3
node_ma+ 199086 199085  0  8월03 pts/3  00:00:00 -bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;ps -ef&lt;/b&gt; 명령어를 실행해보시면 아시겠지만 결과가 굉장히 많이 출력됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;당연하게도 전체 프로세스 정보를 출력하는 것이니 많을 수밖에요. 이렇다 보니 내가 확인하려고 하는 프로세스를 찾기 위해서는 뭔가 방법이 필요해 보입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이전 포스팅에서 &lt;b&gt;파이프(pipe)&lt;/b&gt;에 대해서 설명드린 적이 있는데요, 바로 지금이 파이프를 활용할 때입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gracefulprograming.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Linux] 파이프(pipe)에 대한 이해&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;만일 내가 찾고자 하는 프로세스 이름에 python 이라는 문자열이 들어간다고 하면 아래와 같이 찾을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596556936094&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@peterdev ~]# ps -ef | grep python
root       477     1  0  2018 ?        00:00:47 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
root       819     1  0  2018 ?        03:10:37 /usr/bin/python -Es /usr/sbin/tuned -l -P
root       847 28992  0 16:01 pts/0    00:00:00 grep --color=auto python
root      4982  4956  0  2019 ?        00:02:04 python ./get_pr.py
root     28692     1  0  2019 ?        00:00:00 python app.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이처럼 python 프로세스가 여러 개 실행 중인걸 확인 할 수 있는데요, 커맨드라인을 통해 어떤 스크립트를 실행하고 있는지 구별이 가능합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <category>linux ps</category>
      <category>pid</category>
      <category>ps -ef</category>
      <category>리눅스 ps</category>
      <category>프로세스 확인</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/126</guid>
      <comments>https://gracefulprograming.tistory.com/126#entry126comment</comments>
      <pubDate>Wed, 5 Aug 2020 01:08:04 +0900</pubDate>
    </item>
    <item>
      <title>[C#] 프로젝트에 log4net 적용하기</title>
      <link>https://gracefulprograming.tistory.com/122</link>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;안녕하세요&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;피터&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;오늘은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;C# 프로젝트&lt;/b&gt;에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;log4net&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;로그 시스템(log system)&lt;/span&gt;을 적용하는 방법을 알려드리겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;프로젝트를 진행하다 보면 로그 시스템이 절실할 때가 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;특정 상황에서 에러가 발생하는데 &lt;u&gt;어떤 절차에 의해 실행하면 에러가 발생하는지 추적이 어려울 때&lt;/u&gt;가 바로 그런 경우입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또한 개발을 진행할 때에는 세부적이고 자세한 로그를 기록하는 것이 도움이 되지만 실제로 사용자가 프로그램을 쓸 때에는 중요한 내용만 기록하는 것이 더 도움이 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 이유로&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;상황에 따라 어떤 수준의 로그를 기록&lt;/span&gt;할지 손쉽게 설정할 수 있는 로그 시스템이 필요합니다.&lt;/p&gt;
&lt;p&gt;C# 프로젝트에서는 log4net 라이브러리를 통해 이러한 기능을 쉽게 구현 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;로그시스템 적용&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;log4net 라이브러리 설치&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Visual studio&lt;/b&gt; 에서는 &lt;b&gt;nuget&lt;/b&gt;을 통해 손쉽게 라이브러리를 설치 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;먼저 로그시스템을 적용하고자 하는 프로젝트를 열고 nuget에서 log4net을 검색합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;image2019-9-19_10-18-26.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rzhpg/btqzsFIOt0P/KGjKaskLkabAvarAF9EDP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rzhpg/btqzsFIOt0P/KGjKaskLkabAvarAF9EDP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rzhpg/btqzsFIOt0P/KGjKaskLkabAvarAF9EDP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frzhpg%2FbtqzsFIOt0P%2FKGjKaskLkabAvarAF9EDP1%2Fimg.png&quot; data-filename=&quot;image2019-9-19_10-18-26.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;nuget&lt;/b&gt; 에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;log4net (Apach Software Foundation)&lt;/b&gt;&lt;/span&gt;을 검색하여 적용하고자 하는 프로젝트에 설치합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;log4net 환경설정 파일 추가&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;로그 시스템을 프로젝트에 원하는대로 적용하기 위해서는 &lt;b&gt;환경설정&lt;/b&gt; 파일이 필요합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;image2019-9-19_10-19-5.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYRZ0y/btqzsWQSc4i/C2TXzeLJtVCZTJu4UksYvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYRZ0y/btqzsWQSc4i/C2TXzeLJtVCZTJu4UksYvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYRZ0y/btqzsWQSc4i/C2TXzeLJtVCZTJu4UksYvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYRZ0y%2FbtqzsWQSc4i%2FC2TXzeLJtVCZTJu4UksYvK%2Fimg.png&quot; data-filename=&quot;image2019-9-19_10-19-5.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;[프로젝트] - [추가] - [새 항목]&lt;/b&gt; 클릭&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yMHrO/btqzs7q66Ta/GsTHH0VxuJ4tS6vBZ6mlzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yMHrO/btqzs7q66Ta/GsTHH0VxuJ4tS6vBZ6mlzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yMHrO/btqzs7q66Ta/GsTHH0VxuJ4tS6vBZ6mlzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyMHrO%2Fbtqzs7q66Ta%2FGsTHH0VxuJ4tS6vBZ6mlzK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;&quot;구성&quot;&lt;/b&gt; 을 키워드로 검색하여 &lt;b&gt;&quot;응용 프로그램 구성 파일&quot;&lt;/b&gt; (확장자가 &lt;span style=&quot;color: #333333;&quot;&gt;config)&lt;/span&gt;을 선택합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;파일명을 &lt;b&gt;log4net.config&lt;/b&gt; 로 변경한 다음 추가를 클릭합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;(파일명은 원하는대로 변경이 가능합니다. 설정파일을 읽어오는 부분도 동일하게 변경해주시면 됩니다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;예제)&amp;nbsp;log4net.config&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1572538590086&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;log4net&amp;gt;
    &amp;lt;root&amp;gt;
      &amp;lt;level value=&quot;ALL&quot;/&amp;gt;
      &amp;lt;appender-ref ref=&quot;console&quot;/&amp;gt;
      &amp;lt;appender-ref ref=&quot;file&quot;/&amp;gt;
      &amp;lt;appender-ref ref=&quot;fatal_file&quot;/&amp;gt;
    &amp;lt;/root&amp;gt;
    &amp;lt;appender name=&quot;console&quot; type=&quot;log4net.Appender.ConsoleAppender&quot;&amp;gt;
      &amp;lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&amp;gt;
        &amp;lt;conversionPattern value=&quot;%date %level %logger - %message%newline&quot; /&amp;gt;
      &amp;lt;/layout&amp;gt;
    &amp;lt;/appender&amp;gt;
    &amp;lt;appender name=&quot;file&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;&amp;gt;
      &amp;lt;file value=&quot;log\app.log&quot; /&amp;gt;
      &amp;lt;appendToFile value=&quot;true&quot; /&amp;gt;
      &amp;lt;rollingStyle value=&quot;Size&quot; /&amp;gt;
      &amp;lt;maxSizeRollBackups value=&quot;5&quot; /&amp;gt;
      &amp;lt;maximumFileSize value=&quot;100MB&quot; /&amp;gt;
      &amp;lt;staticLogFileName value=&quot;true&quot; /&amp;gt;
      &amp;lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&amp;gt;
        &amp;lt;conversionPattern value=&quot;%date [%thread] %level %logger - %message%newline&quot; /&amp;gt;
      &amp;lt;/layout&amp;gt;
    &amp;lt;/appender&amp;gt;
    &amp;lt;appender name=&quot;fatal_file&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;&amp;gt;
      &amp;lt;file value=&quot;log\fatal.log&quot; /&amp;gt;
      &amp;lt;appendToFile value=&quot;true&quot; /&amp;gt;
      &amp;lt;rollingStyle value=&quot;Size&quot; /&amp;gt;
      &amp;lt;maxSizeRollBackups value=&quot;5&quot; /&amp;gt;
      &amp;lt;maximumFileSize value=&quot;100MB&quot; /&amp;gt;
      &amp;lt;staticLogFileName value=&quot;true&quot; /&amp;gt;
      &amp;lt;filter type=&quot;log4net.Filter.LevelRangeFilter&quot;&amp;gt;
        &amp;lt;param name=&quot;LevelMin&quot; value=&quot;FATAL&quot; /&amp;gt;
        &amp;lt;param name=&quot;LevelMax&quot; value=&quot;FATAL&quot; /&amp;gt;
      &amp;lt;/filter&amp;gt;
      &amp;lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&amp;gt;
        &amp;lt;conversionPattern value=&quot;%date [%thread] %level %logger - %message%newline&quot; /&amp;gt;
      &amp;lt;/layout&amp;gt;
    &amp;lt;/appender&amp;gt;
  &amp;lt;/log4net&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;log4net의 설정에서는 &lt;b&gt;appender&lt;/b&gt;가 핵심적인 역할을 수행합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;appender의 종류에 따라 화면에 출력하거나 파일에 기록할 수 있으며, 이메일로도 로그를 전송할 수 있습니다.&lt;/p&gt;
&lt;p&gt;위에서 사용한 appender는 아래 2가지 입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;log4net.Appender.ConsoleAppender (화면에 출력하는 appender)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;log4net.Appender.RollingFileAppender (파일에 기록하는 appender)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;RollingFileAppender&lt;/span&gt;&lt;/b&gt;&lt;span&gt;에 대한 &lt;span&gt;위 설정은 설치파일경로\log\app.log 파일로 로그를 기록하며, 100MB 초과 시 5개까지 파일을 분기하는 설정입니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1572577172012&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;root&amp;gt;
  &amp;lt;level value=&quot;ALL&quot;/&amp;gt;
  &amp;lt;appender-ref ref=&quot;console&quot;/&amp;gt;
  &amp;lt;appender-ref ref=&quot;file&quot;/&amp;gt;
  &amp;lt;appender-ref ref=&quot;fatal_file&quot;/&amp;gt;
&amp;lt;/root&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;appender 들을 설정했으면 root 태그에 appender-ref 를 추가해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;log4net 라이브러리에서 발생한 로그들을 appender-ref 목록에 있는 appender 들에게 전달해주는데 만일&amp;nbsp;level을 지정하면 지정된 레벨 이상의 로그만 appender 로 전달할 수 있습니다.&lt;/p&gt;
&lt;p&gt;레벨에 설정 가능한 값&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ALL&lt;/li&gt;
&lt;li&gt;DEBUG&lt;/li&gt;
&lt;li&gt;INFO&lt;/li&gt;
&lt;li&gt;WARN&lt;/li&gt;
&lt;li&gt;ERROR&lt;/li&gt;
&lt;li&gt;FATAL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;appender 별로 로그 레벨을 지정하고자 할 때는 아래와 같이 appender 내부에 &lt;b&gt;filter&lt;/b&gt;를 사용하면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1572577573874&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;filter type=&quot;log4net.Filter.LevelRangeFilter&quot;&amp;gt;
    &amp;lt;param name=&quot;LevelMin&quot; value=&quot;FATAL&quot; /&amp;gt;
    &amp;lt;param name=&quot;LevelMax&quot; value=&quot;FATAL&quot; /&amp;gt;
&amp;lt;/filter&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;환경설정을 다 작성하였으면 &lt;b&gt;log4net.config&lt;/b&gt; 파일 속성의 고급에서 아래 내용을 변경해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;아래 속성을 지정해주지 않으면 빌드 시 환경설정 파일이 출력디렉토리에 복사되지 않기 때문에 실행했을 때 환경설정을 읽어오지 못하게 되니 반드시 적용해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;image2019-9-19_10-46-48.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qHlvW/btqzr7r2d87/Nun8SmYjbqnkQGFJIcVank/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qHlvW/btqzr7r2d87/Nun8SmYjbqnkQGFJIcVank/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qHlvW/btqzr7r2d87/Nun8SmYjbqnkQGFJIcVank/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqHlvW%2Fbtqzr7r2d87%2FNun8SmYjbqnkQGFJIcVank%2Fimg.png&quot; data-filename=&quot;image2019-9-19_10-46-48.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;빌드작업 - 내용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출력 디렉터리에 복사 - 항상 복사 (&quot;새버전이면 복사&quot;로 해도 무방합니다)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;환경설정 파일 로드&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIuCAy/btqzsVYJkpG/cGSNwtLg0arKSMrDCKVDK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIuCAy/btqzsVYJkpG/cGSNwtLg0arKSMrDCKVDK0/img.png&quot; data-alt=&quot;AssemblyInfo.cs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIuCAy/btqzsVYJkpG/cGSNwtLg0arKSMrDCKVDK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIuCAy%2FbtqzsVYJkpG%2FcGSNwtLg0arKSMrDCKVDK0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AssemblyInfo.cs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;프로젝트에서 환경설정 파일을 읽어올 수 있도록 &lt;b&gt;AssemblyInfo.cs&lt;/b&gt; 파일 하단에 코드를 추가해줍니다.&lt;/p&gt;
&lt;p&gt;위에서 파일 이름을 변경했다면 변경한 파일 이름으로 작성해주셔야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1572575256140&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[assembly: log4net.Config.XmlConfigurator(ConfigFile = &quot;log4net.config&quot;, Watch = true)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Watch = true&lt;/b&gt; 라는 옵션을 주면 프로그램 실행 중에 &lt;b&gt;config&lt;/b&gt; 파일을 수정해도 바로 반영됩니다.&lt;/p&gt;
&lt;p&gt;이 옵션은 상당히 유용한 옵션으로 프로그램을 재실행하지 않고도 로그 시스템의 설정을 바꿀 수 있기 때문에 사용을 권장드립니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로그 인터페이스 생성 및 로그 기록&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z8VT2/btqzrIsTa7E/N2Pl3QXOGsziQWAmvzYKI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z8VT2/btqzrIsTa7E/N2Pl3QXOGsziQWAmvzYKI0/img.png&quot; data-alt=&quot;App.xaml.cs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z8VT2/btqzrIsTa7E/N2Pl3QXOGsziQWAmvzYKI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ8VT2%2FbtqzrIsTa7E%2FN2Pl3QXOGsziQWAmvzYKI0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;App.xaml.cs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1572575886026&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using log4net;

    public partial class App : Application
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(App));

        protected override void OnStartup(StartupEventArgs e)
        {
            log.Info(&quot;=============  Started application  =============&quot;);
            base.OnStartup(e); 
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;App.xaml.cs&lt;/b&gt; 에 log4net 라이브러리를 추가하고 프로그램이 시작 할 때 로그를 기록해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;LogManager&lt;/b&gt;의 GetLogger 메소드를 통해 ILog 인터페이스를 얻어올 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;GetLogger에 파라미터로 넘겨주는 이름이 나중에 로그에 기록될 때 식별자로 기록됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 얻은 &lt;b&gt;ILog&lt;/b&gt; 인터페이스를 통해 로그를 기록 할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c63AZr/btqzsFozeNT/XkSpIh49fulKUI2QbWnaR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c63AZr/btqzsFozeNT/XkSpIh49fulKUI2QbWnaR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c63AZr/btqzsFozeNT/XkSpIh49fulKUI2QbWnaR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc63AZr%2FbtqzsFozeNT%2FXkSpIh49fulKUI2QbWnaR0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1572576691030&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
public MainWindow()
{
    InitializeComponent();
}
 
private void Button_Click(object sender, RoutedEventArgs e)
{
    log.Debug(&quot;Debug&quot;);
    log.Info(&quot;Info&quot;);
    log.Warn(&quot;Warn&quot;);
    log.Error(&quot;Error&quot;);
    log.Fatal(&quot;Fatal&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;ILog&lt;/b&gt; 인터페이스는 위와같이 레벨별 메소드들을 제공합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;작은 팁을 드리면 &lt;b&gt;Error&lt;/b&gt; 로그는 아래와 같이 &lt;b&gt;Exception&lt;/b&gt; 객체를 파라미터로 넘겨서 출력할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1572576630095&quot; class=&quot;c++ cpp arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try
{
    ;
}
catch (Exception ex)
{
    log.Error($&quot;An exception occurred from {MethodBase.GetCurrentMethod().Name}&quot;, ex);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;비즈니스 로직이 들어가는 코드를 위와 같이 작성해두면 나중에 에러가 발생했을 때 추적이 쉬워집니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로그 기록 확인&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yb0B7/btqzsEb5nBJ/9iEkOPL9s6sQ8DiTogAaQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yb0B7/btqzsEb5nBJ/9iEkOPL9s6sQ8DiTogAaQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yb0B7/btqzsEb5nBJ/9iEkOPL9s6sQ8DiTogAaQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyb0B7%2FbtqzsEb5nBJ%2F9iEkOPL9s6sQ8DiTogAaQk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위에서 설정한 대로 실행파일이 위치한 디렉토리 하위에 log 라는 디렉토리와 로그파일이 생성된 것을 확인 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;image2019-9-19_10-26-46.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HF6wY/btqzsVEpGV4/0tbwZolKf6xu4qinjkUInk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HF6wY/btqzsVEpGV4/0tbwZolKf6xu4qinjkUInk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HF6wY/btqzsVEpGV4/0tbwZolKf6xu4qinjkUInk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHF6wY%2FbtqzsVEpGV4%2F0tbwZolKf6xu4qinjkUInk%2Fimg.png&quot; data-filename=&quot;image2019-9-19_10-26-46.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;로그 파일을 열어보면 레벨별로 잘 기록된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-Peter의 우아한 프로그래밍&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러분의 공감과 댓글은 저에게 크나큰 힘이 됩니다. 오류 및 의견 주시면 감사하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C sharp</category>
      <category>C#</category>
      <category>c# log4net</category>
      <category>file log</category>
      <category>log file</category>
      <category>log level</category>
      <category>log management</category>
      <category>log system</category>
      <category>로그 시스템</category>
      <category>씨샾 로그</category>
      <author>Peter Ahn</author>
      <guid isPermaLink="true">https://gracefulprograming.tistory.com/122</guid>
      <comments>https://gracefulprograming.tistory.com/122#entry122comment</comments>
      <pubDate>Fri, 1 Nov 2019 12:06:29 +0900</pubDate>
    </item>
  </channel>
</rss>