Docker. Docker Desktop 실습해보기

설치하기 공식 문서에 설치 가이드 설명 잘 되어있으니 알아서… 첫 번째 컨테이너 실행하기 docker run -d -p 8080:80 docker/welcome-to-docker http://localhost:8080 에서 이 컨테이너의 프론트엔드 방문 가능. Docker Desktop 사용해보기 컨테이너 탭 Logs — docker logs <container-name> 컨테이너 내부에서 실행 중인 프로세스의 표준 출력을 그대로 보여줌. 디버깅할 때 많이 사용하는 부분 Inspect — docker inspect <container-name> 컨테이너의 환경 변수, 포트 바인딩, 실행 명령, 마운트 경로, 네트워크, 상태 등 메타데이터를 JSON으로 보여줌 Bind mounts 로컬 호스트와 컨테이너 사이의 폴더 연결 정보를 보여줌 ex) -v ~/project:/app → 내 컴퓨터의 ~/project 폴더가 컨테이너 내부 /app에 연결됨. 로컬 파일 수정 시 컨테이너에 즉시 반영되기 때문에 개발할 때 자주 사용 Exec — docker exec -it <container-name> 실행 중인 컨테이너 내부에 직접 명령어를 입력할 수 있는 쉘 세션을 엶. 컨테이너 내부 구조 탐색, 빠른 테스트, 수동 디버깅에 사용 Files — docker cp, docker exec ls 컨테이너 내부의 파일 시스템 탐색 호스트 ↔ 컨테이너 간 파일을 복사할 수 있음 Stats: docker stats <container-name> 컨테이너의 실시간 리소스 사용량(CPU, 메모리, 네트워크, I/O) 등을 모니터링 성능 문제나 리소스 병목을 추적할 때 사용 여러 컨테이너 동시 모니터링 가능 직접 컨테이너를 사용해서 개발해보기 0. 프로젝트 클론 우선 Docker에서 제공하는 예제 앱 가져오기 ...

October 8, 2025

JavaScript. 모듈 시스템

프로젝트가 커질수록 모든 코드를 하나의 파일에 작성하기는 어렵다. 그래서 JavaScript는 기능별로 코드를 여러 파일로 나누어 관리하며, 각각의 파일을 모듈(Module)이라고 한다. 모듈 시스템은 이러한 모듈을 다른 파일에서 가져오고 내보내는 방법을 정의한다. 주요 모듈 시스템 CommonJS (CJS) CommonJS는 Node.js 초창기부터 사용된 모듈 시스템이다. require로 다른 모듈을 가져오고, module.exports로 외부에 공개할 값을 내보낸다. // math.js function add(a, b) { return a + b; } module.exports = { add }; // main.js const math = require('./math'); console.log(math.add(2, 3)); 위 예시에서 module.exports는 add 함수를 다른 파일에서도 사용할 수 있도록 내보낸다. main.js에서는 require를 통해 해당 모듈을 가져와 math.add()를 호출한다. ...

October 7, 2025

Node. Node.js 소개

Node.js는 브라우저 밖에서도 JavaScript를 실행할 수 있게 해주는 런타임이다. 구조 Node.js를 설치하면 JavaScript 런타임 하나만 설치되는 것이 아닌, 프로젝트 관리, 외부 라이브러리, 개발 도구를 실행하기 위한 여러 구성 요소가 함께 설치된다. Node JavaScript 실행 환경이다. 브라우저 외부에서 JS를 실행할 수 있게 해준다. 간단한 파일은 다음처럼 직접 실행할 수도 있다. (다른 언어들과 비슷하다.) node <FILE-NAME>.js npm(Node Package Manager) Node 프로젝트의 패키지 관리자이다. 외부 라이브러리를 설치하고, 제거하고, 프로젝트의 의존성을 관리한다. 외부 라이브러리를 설치할 때는 다음 명령을 사용한다. ...

October 5, 2025

SwiftUI 상태 관리

상태를 누가 소유하고 어떻게 전달해야 하는가 SwiftUI에서는 상태를 저장하거나 다른 뷰에 전달할 때 프로퍼티 래퍼를 사용한다. 이 상태를 현재 뷰가 직접 가지고 있는지, 부모 뷰에서 전달받는지, 아니면 별도의 객체가 관리하는지에 따라 사용하는 래퍼가 달라진다. 상위 뷰 → 하위 뷰 @State → @Binding 상위 뷰가 상태를 소유하고, 하위 뷰는 해당 상태를 수정할 수 있도록 @Binding으로 전달받는다. 뷰 모델 → 뷰 → 하위 뷰 ObservableObject 프로토콜을 채택한 뷰 모델에서는, 변경을 알려야 하는 값을 @Published 프로퍼티로 선언한다.(이 뷰 모델을 뷰에서 주입받아 사용할 때는 보통 @ObservedObject로 관찰함) ...

September 25, 2025

Swift Concurrency. Behind the Scenes - WWDC21

Threading model 뉴스 피드 리더 앱을 예로 들어보자. 앱의 상위 컴포넌트는 다음과 같이 나눌 수 있다. 사용자 인터페이스를 담당하는 메인 스레드 사용자가 구독한 뉴스 피드를 추적하는 데이터베이스 최신 콘텐츠를 가져오는 네트워킹 서브시스템 사용자가 최신 뉴스를 요청하면 다음과 같은 흐름으로 처리할 수 있다. 메인 스레드에서 이벤트 제스처 처리 데이터베이스 작업을 처리하는 직렬 큐로 요청을 비동기적으로 디스패치 작업을 다른 큐로 보내면 메인 스레드는 데이터베이스 작업을 기다리지 않고 사용자 입력에 계속 반응할 수 있다. 직렬 큐가 상호 배제를 보장하므로 데이터베이스 접근을 순서대로 처리할 수 있다. 데이터베이스 큐에선 사용자가 구독한 피드에 URLSession을 통해 콘텐츠를 다운로드하는 네트워크 요청을 스케줄링 결과가 도착하면 URLSession의 콜백이 Delegate Queue 위에서 호출되어서 각 결과의 Completion Handler가 동기적으로 데이터베이스를 업데이트한다. MainThread를 깨워서 UI를 리프레시한다. 보기에는 합리적인 방법이다. 메인 스레드를 블록하지 않으면서 네트워크 요청을 동시에 처리할 수 있기 때문이다. ...

August 25, 2025

The Swift Programming Language. Macro (2)

Macro Expansion 매크로를 사용한 Swift 코드를 빌드 할 때, 코드를 확장하기 위해 매크로의 구현을 불러오게 된다. 구체적으로 Swift는 다음과 같은 방법으로 매크로를 확장한다: 컴파일러가 코드를 읽어, 구문의 in-memory 표현을 만든다. 컴파일러가 이 in-memory 표현의 일부를 매크로를 확장시키는 매크로 구현부에 보낸다. 컴파일러가 매크로 호출을 확장된 형태로 대체한다. 컴파일러가 확장된 소스 코드를 사용하여 컴파일을 계속 진행한다. 구체적인 단계들을 살펴보기 위해, 다음을 생각해보자: let magicNumber = #fourCharacterCode("ABCD") #fourCharacterCode 매크로는 4개의 캐릭터로 구성된 문자열을 받아, 그 문자열의 ASCII 값들을 이어 붙인 32비트 언사인드 인티저를 리턴한다. 일부 파일 포맷은 데이터를 식별하기 위해 이런 형태의 인티저를 사용하는데, 컴팩트 하면서도 디버거에서 읽을 수 있기 때문이다. 아래의 Implementing a Macro 섹션에서 이 매크로를 구현하는 방법을 보여준다. ...

August 15, 2025

The Swift Programming Language. Macro (1)

매크로는 컴파일할 때 소스 코드를 변환하여, 반복적인 코드를 직접 작성하지 않게 해준다. 컴파일하는 동안, Swift는 평상시처럼 코드를 빌드하기 전에 매크로들을 확장한다. 매크로를 확장하는 것은 항상 추가하는(additive) 작업이다: 매크로는 새로운 코드를 더하지만, 기존에 존재하는 코드를 삭제하거나 수정하지 않는다. 매크로 입력과, 매크로 확장의 출력 둘 다 구문적으로 유효한 Swift 코드인지 체크된다. 마찬가지로, 매크로에 전달되는 값과 매크로로 생성된 코드 안의 값이 정확한 타입인지 검사된다. 추가적으로, 매크로를 확장할 때 구현부에서 에러를 마주치면, 컴파일러는 이를 컴파일 에러로 처리한다. 이러한 보장은 매크로를 사용하는 코드를 더 쉽게 이해하게 해주고, 매크로를 잘못 사용하거나 매크로의 구현에 버그가 있는 이슈들을 더 쉽게 알아차리게 해준다. ...

August 14, 2025

Swift Concurrency. 01. 도입 배경

Swift Concurrency는 Swift 5.5에서 도입된 기능이다. Foundation을 import 해야 쓸 수 있는 GCD와 다르게, Swift 언어 자체에 내장된 동시성 모델이다. Swift Concurrency는 크게 두 가지 부분으로 나뉘어진다. async, await 로 작성하는 새로운 동시성 모델 애플리케이션을 여러 동시성 태스크로 분할하는 Actor 이 포스트에서는 Swift Concurrency의 도입 배경을 알아본다. GCD의 한계 GCD는 Objective-C에서부터 사용해온 애플이 만든 비동기 API다. Queue 기반으로 작업을 스케줄링 하고, 스레드 위에서 추상화 되어있기 때문에 스레드를 직접 생성하거나 관리할 필요가 없다. ...

August 3, 2025

iOS. 파일 시스템과 샌드박스

앱은 종료된 뒤에도 데이터를 유지하기 위해 파일 시스템을 사용한다. iOS, macOS 같은 애플 플랫폼에서는 APFS(Apple File System)라는 파일 시스템을 쓴다. 애플은 사용자 파일과 앱 내부 파일을 분리해서 관리하는 것을 목표로 한다. 개발자 문서에서는 파일 시스템의 목표를 다음과 같이 제시한다. 사용자 파일은 쉽게 찾을 수 있도록 한다. 앱 내부적으로 사용하는 파일은 사용자 눈에 띄지 않도록 한다. 많은 파일 시스템처럼 APFS도 디렉토리 구조를 통해 계층적으로 파일을 관리한다. 모든 디스크가 ‘단일 파일 컬렉션’을 구성한다는 점이 특징이다. 즉, 여러 디스크를 연결해도 사용자에게는 하나의 계층에 있는 것처럼 보인다. ...

July 21, 2025

Algorithm. Bit masking

기본 소개 비트 마스킹은 비트 연산을 활용해서 집합을 구현하는 방법이다. 각 자리수의 비트는 하나의 원소를 나타내며, 이 원소들이 모여서 집합을 구성하게 된다. 예를 들어, 원소 A, B, C, D를 각각 다음과 같이 표현할 수 있다: let A = 0b0001 // 1 let B = 0b0010 // 2 let C = 0b0100 // 4 let D = 0b1000 // 8 혹은 쉬프트 연산을 활용해서 표현할 수도 있다. 이 방법이 조금 더 직관적이고 단순하다: let A = 1 << 0 let B = 1 << 1 let C = 1 << 2 let D = 1 << 3 이렇게 원소들을 정의하게 되면, 각 원소들이 각각의 자릿수를 점유하고 있기 때문에 겹칠 일이 없다. 따라서 2진수로 쉽게 집합을 표현할 수 있다. ...

June 12, 2025