Java Keywords

Keyword 키워드들은 Java 언어의 기본 구성 요소이며, 각각이 특정한 프로그래밍 목적을 위해 설계되었다. 변수, 메서드, 클래스, 제어문 등 다양한 요소를 정의하고 제어하는 데 필수적인 역할을 한다. 이들을 올바르게 이해하고 사용하는 것이 효과적인 Java 프로그래밍의 기초가 된다. 각 키워드의 특징과 주의사항: 모든 키워드는 소문자로만 작성된다. 키워드는 식별자(변수명, 메서드명 등)로 사용할 수 없다. 일부 키워드는 특정 컨텍스트에서만 의미를 가진다. 예약어 중 일부는 현재 사용되지 않지만 향후 사용을 위해 예약되어 있다. 데이터 타입 키워드 키워드 설명 예시 byte 8비트 정수형 (-128 ~ 127) byte b = 100; short 16비트 정수형 (-32,768 ~ 32,767) short s = 1000; int 32비트 정수형 int i = 10000; long 64비트 정수형 long l = 100000L; float 32비트 단정도 실수형 float f = 3.14f; double 64비트 배정도 실수형 double d = 3.14159; boolean 논리형 (true/false) boolean flag = true; char 16비트 유니코드 문자 char c = 'A'; void 반환값이 없음을 나타냄 void method() {} 제어문 키워드 키워드 설명 예시 if 조건문 시작 if (x > 0) {} else if문의 대안 경로 else {} switch 다중 분기문 시작 switch(value) {} case switch문의 각 경우 case 1: default switch문의 기본 경우 default: for 반복문 for (int i = 0; i < n; i++) while 조건 기반 반복문 while (condition) do do-while 반복문 시작 do {} while(); break 반복문/switch문 탈출 break; continue 현재 반복 건너뛰기 continue; return 메소드에서 값 반환/종료 return value; 클래스 관련 키워드 키워드 설명 예시 class 클래스 정의 public class MyClass {} interface 인터페이스 정의 interface MyInterface {} extends 클래스/인터페이스 상속 class Child extends Parent {} implements 인터페이스 구현 class MyClass implements Interface {} enum 열거형 정의 enum Direction {NORTH, SOUTH} this 현재 인스턴스 참조 this.value = value; super 상위 클래스 참조 super.method(); new 객체 생성 new Object(); instanceof 객체 타입 검사 obj instanceof String 접근 제어 키워드 키워드 설명 예시 public 전체 접근 허용 public class Public {} private 클래스 내부만 접근 가능 private int value; protected 패키지와 자식 클래스 접근 가능 protected void method() {} default 패키지 내부만 접근 가능 int value; (키워드 생략) 제어자 키워드 키워드 설명 예시 static 클래스 레벨 멤버 정의 static int count; final 변경 불가 선언 final int MAX = 100; abstract 추상 클래스/메소드 선언 abstract class Abstract {} synchronized 스레드 동기화 synchronized void method() {} volatile 메모리 직접 접근 변수 volatile boolean flag; transient 직렬화 제외 필드 transient int temp; native 네이티브 메소드 선언 native void method(); strictfp 엄격한 부동소수점 연산 strictfp class Math {} 예외 처리 키워드 키워드 설명 예시 try 예외 발생 가능 블록 try {} catch 예외 처리 블록 catch (Exception e) {} finally 항상 실행되는 블록 finally {} throw 예외 발생 throw new Exception(); throws 예외 선언 void method() throws Exception {} assert 조건 검증 assert x > 0; 패키지 관련 키워드 키워드 설명 예시 package 패키지 선언 package com.example; import 클래스 임포트 import java.util.List; 리터럴 키워드 키워드 설명 예시 true 논리 참 값 boolean t = true; false 논리 거짓 값 boolean f = false; null 참조 없음 Object obj = null; 예약된 키워드 (미사용) 키워드 설명 const 상수 (사용되지 않음) goto 이동 (사용되지 않음) 참고 및 출처

November 20, 2024 · 3 min · Me

Back Pressure

Back Pressure 1. 주제의 분류 적합성 “Back Pressure(배압)” 는 시스템 설계 (System Design) 에서 비동기 (Asynchronism) 및 흐름 제어 (Flow Control) 의 핵심 개념으로, “Computer Science and Engineering > System Design > Fundamentals > Asynchronism” 분류가 매우 적절합니다. 실제로 네트워크, 분산 시스템, 리액티브 프로그래밍 등 다양한 IT 인프라와 소프트웨어 아키텍처에서 필수적으로 다루는 기본 원리입니다 [1][2][3][15]. 1. 주제 분류 검토 현재 분류: “Computer Science and Engineering” > “System Design” > “Fundamentals” > “Asynchronism” ...

November 17, 2024 · 31 min · Me

Black-box Test and White-box Test

Black-box Test and White-box Test Black-box Testing(블랙박스 테스팅)은 소프트웨어의 내부 구조나 동작 원리를 모르는 상태에서 진행하는 테스트 방식이다. 마치 불투명한 상자 안을 들여다볼 수 없는 것처럼, 테스터는 입력값을 넣고 그에 따른 출력값만을 확인한다. 예를 들어, 계산기 애플리케이션을 테스트할 때 “2+2"를 입력했을 때 “4"가 출력되는지만 확인하고, 그 계산 과정이 어떤 알고리즘으로 이루어지는지는 고려하지 않는다. Black-box Testing의 주요 특징은 다음과 같다: 사용자 관점에서의 테스트가 가능하다. 실제 사용자들이 소프트웨어를 사용하는 방식과 유사하게 테스트할 수 있다. 테스터가 코드에 대한 지식이 없어도 테스트를 수행할 수 있다. 경계값 분석, 동등 분할, 결정 테이블 등의 기법을 활용할 수 있다. 반면 White-box Testing(화이트박스 테스팅)은 소프트웨어의 내부 로직을 알고 있는 상태에서 진행하는 테스트이다. 투명한 상자처럼 내부 구조를 모두 볼 수 있어, 코드의 특정 부분이 어떻게 작동하는지 세세하게 테스트할 수 있다. 예를 들어, 로그인 기능을 테스트할 때 비밀번호 암호화 과정, 데이터베이스 접근 방식, 예외 처리 등의 내부 로직을 모두 확인한다. ...

November 5, 2024 · 4 min · Me

Fakes

Fakes Fakes는 Test Double 기법 중 하나로, 실제 객체의 간단한 구현을 제공하는 테스트용 객체. 목적 실제 구현체를 단순화하여 테스트 환경에서 사용한다. 외부 의존성을 제거하고 테스트 속도를 향상시킨다. 실제 객체와 유사한 동작을 제공하여 현실적인 테스트 환경을 구성한다. 장점 테스트 실행 속도가 빠르다. 실제 구현체보다 구성이 간단하다. 테스트 간 재사용이 용이하다. 실제 객체와 유사한 동작으로 신뢰성 있는 테스트가 가능하다. 단점 실제 구현체와 동작이 완전히 일치하지 않을 수 있다. Fake 객체 구현에 추가적인 시간과 노력이 필요하다. Fake 객체 자체의 유지보수가 필요할 수 있다. 예시 Python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class RealDatabase: def connect(self): # 실제 데이터베이스 연결 로직 pass def fetch_data(self): # 실제 데이터 조회 로직 return "Real data" class FakeDatabase: def connect(self): # 연결 시뮬레이션 pass def fetch_data(self): # 가짜 데이터 반환 return "Fake data" class DataService: def __init__(self, database): self.database = database def get_data(self): self.database.connect() return self.database.fetch_data() # 테스트 fake_db = FakeDatabase() data_service = DataService(fake_db) result = data_service.get_data() assert result == "Fake data" JavaScript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class RealDatabase { connect() { // 실제 데이터베이스 연결 로직 } fetchData() { // 실제 데이터 조회 로직 return "Real data"; } } class FakeDatabase { connect() { // 연결 시뮬레이션 } fetchData() { // 가짜 데이터 반환 return "Fake data"; } } class DataService { constructor(database) { this.database = database; } getData() { this.database.connect(); return this.database.fetchData(); } } // 테스트 const fakeDb = new FakeDatabase(); const dataService = new DataService(fakeDb); const result = dataService.getData(); console.assert(result === "Fake data"); 참고 및 출처

November 1, 2024 · 2 min · Me

Dummy Objects

Dummy Objects 테스트 과정에서 실제로는 사용되지 않지만 메서드의 파라미터를 채우기 위해 전달되는 객체 Dummy Objects는 Test Double 기법 중 하나로, 테스트에 필요하지만 실제로 사용되지 않는 객체를 의미합니다. 목적 테스트 대상 코드의 인터페이스 요구사항을 충족시키기 위해 사용된다. 테스트 실행을 위해 필요하지만 테스트 자체와는 관련이 없는 객체를 대체한다. 장점 테스트 코드를 단순화하고 가독성을 높인다. 불필요한 객체 생성을 피해 테스트 성능을 향상시킨다. 테스트 대상 코드를 외부 의존성으로부터 격리시킨다. 단점 실제 객체의 동작을 정확히 반영하지 않을 수 있다. 과도한 사용 시 테스트의 현실성이 떨어질 수 있다. 예시 Python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 # 실제 이메일 서비스 클래스 class EmailService: def __init__(self, smtp_server, port): self.smtp_server = smtp_server self.port = port def send_notification(self, user, message): # 실제로는 이메일을 보내는 복잡한 로직이 있을 것입니다 print(f"Sending email to {user.email}: {message}") # 사용자 클래스 class User: def __init__(self, name, email, notification_service): self.name = name self.email = email self.notification_service = notification_service def notify_login(self): self.notification_service.send_notification( self, f"New login detected for {self.name}" ) # Dummy 객체 class DummyEmailService: def __init__(self, smtp_server=None, port=None): pass # 아무것도 하지 않음 def send_notification(self, user, message): pass # 아무것도 하지 않음 # 테스트 코드 def test_user_creation(): # Dummy 이메일 서비스 사용 dummy_email_service = DummyEmailService() # 실제로 테스트하고 싶은 것은 사용자 생성 로직입니다 user = User("John Doe", "john@example.com", dummy_email_service) assert user.name == "John Doe" assert user.email == "john@example.com" JavaScript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 // 실제 로깅 서비스 클래스 class LoggerService { constructor(logLevel) { this.logLevel = logLevel; } log(message) { // 실제로는 로그를 저장하는 복잡한 로직이 있을 것입니다 console.log(`[${this.logLevel}] ${message}`); } } // 사용자 관리 클래스 class UserManager { constructor(logger) { this.logger = logger; this.users = []; } addUser(user) { this.users.push(user); this.logger.log(`User ${user.name} added`); return this.users.length; } } // Dummy 로거 class DummyLogger { constructor(logLevel) { // 아무것도 저장하지 않음 } log(message) { // 아무것도 하지 않음 } } // 테스트 코드 describe('UserManager', () => { it('should add a new user correctly', () => { // Dummy 로거 사용 const dummyLogger = new DummyLogger(); const userManager = new UserManager(dummyLogger); // 실제로 테스트하고 싶은 것은 사용자 추가 로직입니다 const userCount = userManager.addUser({ name: 'John' }); expect(userCount).toBe(1); expect(userManager.users.length).toBe(1); }); }); 참고 및 출처

November 1, 2024 · 2 min · Me

Spies

Spies Spies는 Test Double 기법 중 하나로, 실제 객체의 메서드 호출을 추적하고 기록하는 데 사용된다. 목적 메서드 호출 여부, 횟수, 전달된 인자 등을 검증한다. 실제 구현을 변경하지 않고 메서드의 동작을 관찰한다. 코드의 상호작용을 분석하고 테스트한다. 장점 비침투적: 실제 객체의 동작을 변경하지 않고 관찰할 수 있다. 유연성: 다양한 정보를 수집하고 검증할 수 있다. 상세한 검증: 메서드 호출의 세부 사항을 정확히 확인할 수 있다. 단점 복잡성: 과도한 사용 시 테스트 코드가 복잡해질 수 있다. 오버스펙: 구현 세부사항에 너무 의존적인 테스트를 작성할 위험이 있다. 성능: 많은 spy를 사용할 경우 테스트 실행 속도가 느려질 수 있다. 예시 예시 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 from typing import Dict, Optional from datetime import datetime # 실제 데이터베이스 리포지토리 class UserRepository: def __init__(self, database_connection): self.db = database_connection def save(self, user_id: str, user_data: Dict): # 실제로는 데이터베이스에 SQL 쿼리를 실행할 것입니다 self.db.execute( "INSERT INTO users (id, data, created_at) VALUES (?, ?, ?)", [user_id, user_data, datetime.now()] ) def find_by_id(self, user_id: str) -> Optional[Dict]: # 실제로는 데이터베이스에서 조회할 것입니다 result = self.db.execute( "SELECT * FROM users WHERE id = ?", [user_id] ) return result.fetchone() # Fake 리포지토리 class FakeUserRepository: def __init__(self): # 데이터베이스 대신 딕셔너리를 사용 self.users: Dict[str, Dict] = {} def save(self, user_id: str, user_data: Dict): # 메모리에 직접 저장 self.users[user_id] = { 'data': user_data, 'created_at': datetime.now() } def find_by_id(self, user_id: str) -> Optional[Dict]: # 메모리에서 직접 조회 return self.users.get(user_id) # 사용자 서비스 class UserService: def __init__(self, user_repository): self.repository = user_repository def create_user(self, user_id: str, name: str, email: str): user_data = {'name': name, 'email': email} self.repository.save(user_id, user_data) def get_user(self, user_id: str): return self.repository.find_by_id(user_id) # 테스트 코드 def test_user_service(): # Fake 리포지토리 사용 fake_repository = FakeUserRepository() user_service = UserService(fake_repository) # 사용자 생성 테스트 user_service.create_user('user1', 'John Doe', 'john@example.com') # 사용자 조회 테스트 user = user_service.get_user('user1') assert user['data']['name'] == 'John Doe' assert user['data']['email'] == 'john@example.com' JavaScript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 // 실제 외부 API 서비스 class WeatherService { async getTemperature(city) { // 실제로는 외부 API를 호출할 것입니다 const response = await fetch( `https://api.weather.com/${city}/temperature` ); return response.json(); } } // Fake 날씨 서비스 class FakeWeatherService { constructor() { // 미리 정의된 도시별 온도 데이터 this.temperatureData = { 'Seoul': { temperature: 25 }, 'New York': { temperature: 20 }, 'London': { temperature: 15 } }; } async getTemperature(city) { // 실제 API 호출 대신 저장된 데이터 반환 return Promise.resolve(this.temperatureData[city] || { temperature: 0 }); } } // 날씨 알림 서비스 class WeatherAlertService { constructor(weatherService) { this.weatherService = weatherService; } async shouldSendAlert(city) { const data = await this.weatherService.getTemperature(city); return data.temperature > 30; } } // 테스트 코드 describe('WeatherAlertService', () => { it('should not send alert for normal temperature', async () => { // Fake 날씨 서비스 사용 const fakeWeatherService = new FakeWeatherService(); const alertService = new WeatherAlertService(fakeWeatherService); const shouldAlert = await alertService.shouldSendAlert('Seoul'); expect(shouldAlert).toBe(false); }); }); 참고 및 출처

November 1, 2024 · 3 min · Me

Stubs

Stubs Stubbing은 테스트에서 사용되는 기법으로, 실제 객체나 아직 구현되지 않은 코드를 대신하여 미리 정의된 응답을 제공하는 메커니즘 목적 의존성 격리: 실제 구현체로부터 테스트 대상을 분리하여 독립적인 테스트를 가능하게 합니다. 특정 시나리오 테스트: 다양한 상황에 대한 테스트를 용이하게 합니다. 미구현 코드 대체: 아직 개발되지 않은 부분을 임시로 대체할 수 있습니다. 테스트 속도 향상: 실제 리소스 접근 없이 빠른 테스트가 가능합니다. 특징 미리 정의된 응답(canned answer)을 제공합니다. 실제 코드의 동작을 단순화하여 모사합니다. 주로 상태 테스팅에 중점을 둡니다. 메서드 호출의 결과만 정의하며, 호출 여부는 검증하지 않습니다. 사용 사례 구현되지 않은 함수나 외부 라이브러리 함수를 사용할 때 복잡한 로직을 단순화하여 테스트하고자 할 때 특정 조건에서의 예외 상황을 테스트할 때 외부 의존성(예: 데이터베이스, 네트워크 요청)을 가진 코드를 테스트할 때 예시 Python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from unittest.mock import Mock, patch import pytest from datetime import datetime # 테스트할 실제 클래스 class PaymentService: def __init__(self, payment_gateway): self.payment_gateway = payment_gateway def process_payment(self, amount): if amount <= 0: raise ValueError("Amount must be positive") response = self.payment_gateway.charge(amount) if response['status'] == 'success': return True return False # 외부 결제 게이트웨이 클래스 (실제로는 외부 서비스) class PaymentGateway: def charge(self, amount): # 실제로는 외부 API를 호출하는 복잡한 로직 pass # Stub 예시 class PaymentGatewayStub: def charge(self, amount): # 항상 성공 응답을 반환하는 단순한 구현 return {'status': 'success', 'timestamp': datetime.now()} # 테스트 코드 def test_payment_service_with_stub(): # Stub 사용 gateway_stub = PaymentGatewayStub() payment_service = PaymentService(gateway_stub) assert payment_service.process_payment(100) == True Javascript 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 // Jest를 사용한 테스트 예시 const { jest } = require('@jest/globals'); // 테스트할 실제 클래스 class UserService { constructor(database) { this.database = database; } async getUserById(id) { const user = await this.database.findUser(id); if (!user) { throw new Error('User not found'); } return user; } async updateUserEmail(id, newEmail) { const user = await this.database.findUser(id); if (!user) { throw new Error('User not found'); } user.email = newEmail; await this.database.updateUser(id, user); return user; } } // Stub 예시 class DatabaseStub { constructor() { this.users = new Map([ [1, { id: 1, name: 'John Doe', email: 'john@example.com' }], [2, { id: 2, name: 'Jane Doe', email: 'jane@example.com' }] ]); } async findUser(id) { return this.users.get(id); } async updateUser(id, userData) { this.users.set(id, userData); return userData; } } // 테스트 코드 describe('UserService', () => { // Stub을 사용한 테스트 describe('with stub', () => { const dbStub = new DatabaseStub(); const userService = new UserService(dbStub); test('should return user when exists', async () => { const user = await userService.getUserById(1); expect(user.name).toBe('John Doe'); }); test('should throw error when user not found', async () => { await expect(userService.getUserById(999)) .rejects .toThrow('User not found'); }); }); }); 참고 및 출처

November 1, 2024 · 3 min · Me

코드 크기 메트릭(Lines of Code, LOC)

코드 크기 메트릭(Lines of Code, LOC) 이 메트릭은 프로그램의 크기를 코드 라인 수로 표현하며, 소프트웨어 개발 프로젝트의 규모 추정, 생산성 측정, 품질 관리 등에 활용된다. 코드 크기는 다양한 방식으로 측정될 수 있으며, 각각의 측정 방식은 서로 다른 목적과 의미를 가진다. 특징과 기능 프로젝트 규모 추정: LOC는 소프트웨어 프로젝트의 크기를 추정하는 데 사용된다. 생산성 측정: 개발자나 팀의 생산성을 LOC를 기준으로 평가할 수 있다. 비용 산정: LOC를 기반으로 프로젝트 비용과 개발 노력을 추정할 수 있다. 복잡성 지표: 코드의 양이 많을수록 일반적으로 복잡성이 높아진다. 유형 물리적 코드 라인(Physical Lines of Code, LOC): 이는 가장 단순한 형태의 측정 방식으로, 파일의 전체 라인 수를 세는 것이다. 다음은 물리적 코드 라인의 예시입니다: ...

October 28, 2024 · 4 min · Me

유지보수성 지수 (Maintainability Index)

유지보수성 지수 (Maintainability Index) 유지보수성 지수는 코드를 얼마나 쉽게 유지보수할 수 있는지를 나타내는 0에서 100 사이의 수치이다. 이 지수가 높을수록 코드의 유지보수가 더 쉽다는 것을 의미한다. 유지보수성 지수의 계산 유지보수성 지수는 다음과 같은 요소들을 고려하여 계산된다: Halstead Volume (HV): 코드의 복잡도를 수학적으로 계산한 값 Cyclomatic Complexity (CC): 코드의 논리적 복잡도 Lines of Code (LOC): 코드의 총 라인 수 주석 비율 (선택적) 기본적인 계산 공식은 다음과 같다: $$ MI = MAX(0, (171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln(LOC)) * 100 / 171) $$ ...

October 28, 2024 · 2 min · Me

응집도(Cohesion)

응집도(Cohesion) 응집도는 하나의 모듈이 얼마나 단일한 목적에 집중되어 있는지를 나타낸다. 모듈 내부의 요소들이 서로 얼마나 밀접하게 관련되어 있는지를 측정하는 척도이다. 높은 응집도는 모듈이 하나의 명확한 책임을 가지고 있음을 의미하며, 이는 좋은 설계의 특징이다. 특징 및 기능 모듈의 독립성을 나타냄 유지보수성과 재사용성 향상에 기여 모듈의 품질을 평가하는 지표로 사용 응집도의 종류 낮은 응집도부터 높은 응집도 순 우연적 응집도(Coincidental Cohesion): 서로 관련 없는 기능들이 한 모듈에 모여있는 경우. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // 우연적 응집도의 예 class Utility { public void calculateTax() { } public void formatDate() { } public void validateEmail() { } public void connectToDatabase() { } } // 개선된 버전 - 각 책임을 분리 class TaxCalculator { public void calculateTax() { } } class DateFormatter { public void formatDate() { } } class EmailValidator { public void validateEmail() { } } 논리적 응집도(Logical Cohesion): 논리적으로 비슷한 기능을 수행하지만 실제로는 다른 작업들을 하나의 모듈에서 처리하는 경우. ...

October 28, 2024 · 4 min · Me