「エンジニア不要論の真実!」を読んでみて
AIタグが付けられた新着記事 - Qiita
プログラミングスクールJISOUを運営している渡邉 臣さん(@Sicut_study )の以下記事を読んで率直に思った今の心境や、学び・気づいたこと、ネクストアクションをアウトプットします。 まず、自分はどんな人間なのか エンジニア歴は8年ほどで、現在はエンジニアチ...
Балл: 57.38Уверенность: 54%
ПодробнееЗагружаем каталог…
НАВИГАТОР ПО ВОЗМОЖНОСТЯМ ИИ
Найдите свой ИИ-инструмент. Бесплатный доступ, пробные периоды и кредиты — в одном месте.
AIタグが付けられた新着記事 - Qiita
プログラミングスクールJISOUを運営している渡邉 臣さん(@Sicut_study )の以下記事を読んで率直に思った今の心境や、学び・気づいたこと、ネクストアクションをアウトプットします。 まず、自分はどんな人間なのか エンジニア歴は8年ほどで、現在はエンジニアチ...
Балл: 57.38Уверенность: 54%
ПодробнееAIタグが付けられた新着記事 - Qiita
はじめに 2026年10月1日、東京ビッグサイトで開催された「テロ対策特殊装備展(SEECAT)2026」に参加しました。 SEECATは、テロ対策に関する特殊資機材・システム・サービスが集まる、関係者向けの専門展示会です。危機管理産業展(RISCON TOKYO)と同時...
Балл: 57.38Уверенность: 54%
ПодробнееAIタグが付けられた新着記事 - Qiita
はじめに 「KafkaからClaude Codeって繋げられるの?」という問いから始まりました。注文やステータス変更やSlackの発言がKafkaに流れてくる環境で、そのイベントをトリガーにClaude(やClaude Codeで作ったエージェント)を動かしたい。イベント...
Балл: 57.37Уверенность: 54%
Подробнее掘金
一、评估第一步:把标准答案整理成"题库" 要考试,先得有标准答案。build_dataset.mjs 就是建题库。 12 道客服题 这 12 条测试数据的设计水平很高,值得单独说一说。 完整清单: 问
Балл: 57.35Уверенность: 54%
Подробнее掘金
前言:Demo 跑通一次就够了,生产系统要跑一万次 前四篇我们讲的是 Agent 的“能力”。但能力和生产系统之间,隔着一条鸿沟。 一个 Demo 只需要跑通一次。一个生产系统需要: 可预测:同样的输
Балл: 57.34Уверенность: 54%
Подробнее掘金
备选标题(三选一) 1. 机器人防护等级跃迁:从 IP54 到 IP68 的密封设计实战 2. 机器人密封设计进阶:IP54 到 IP68 防护等级拆解 3. 机器人高防护等级密码:关节模组一体化密封
Балл: 57.33Уверенность: 54%
Подробнее掘金
本文介绍spring中使用Kafka的三种方式,其中container方式最灵活,但是开发相对较复杂,stream方式使用最简便,listener方式由于提供的最早,使用的较普遍。 具体的代码参照 示
Балл: 57.32Уверенность: 54%
Подробнее掘金
用 Codex 加速 Java 开发:从代码生成到测试覆盖的完整实战 背景 过去半年,我用 Codex 和 GPT-4 这类代码生成模型协作开发了几个 Java 项目。结果很直观:完成同样功能的时间从
Балл: 57.32Уверенность: 54%
Подробнееvelog
1. 트랜잭션은 왜 필요할까? A가 B에게 돈을 송금한다고 가정해보자. A에서 B에게 송금하려면 다음 두 과정이 필요하다. 1. A 계좌의 돈을 차감한다. 2. 차감한 금액을 B 계좌에 입금한다. 그런데 A 계좌의 돈이 차감된 직후 서버 오류가 발생해 B 계좌에 돈이 입금되지 않는다면 문제가 생긴다. 물론 A 계좌의 차감 작업 자체는 정상적으로 처리된 것 이라고 볼 수 있다. 하지만 우리가 원하는 것은 단순히 A 계좌의 돈을 줄이는 것이 아니라, A에서 B로 송금하는 것 이다. 송금은 두 과정이 모두 성공해야 완료된 것이기 때문에, 하나만 성공했다면 결과적으로 전체 송금은 실패한 것이다. 여러 작업 중 일부만 처리되어 데이터가 잘못된 상태로 남는 것을 막기 위해 트랜잭션이 필요하다. 2. 트랜잭션이란? 위의 송금 예제에서 A 계좌의 잔액을 줄이는 작업과 B 계좌의 잔액을 늘리는 작업은 각각 별개의 데이터베이스 작업이다. 하지만 실제 서비스에서는 두 작업을 합쳐 하나의 '송금' 으로 본다. 이처럼 여러 데이터베이스 작업을 하나의 논리적인 작업 단위로 묶어 처리하는 것 을 트랜잭션이라고 한다. 트랜잭션으로 묶인 작업은 일부만 성공한 상태로 끝나는 것이 아니라, 전체가 성공하거나 전체가 실패하도록 처리하는 것이 중요하다. 3. COMMIT과 ROLLBACK 트랜잭션으로 여러 작업을 하나로 묶었다면, 작업 결과를 최종적으로 반영할지 취소할지 결정해야 한다. COMMIT COMMIT 은 트랜잭션 안에서 수행한 작업을 최종적으로 반영하는 것 이다. A 계좌 -10,000원 성공 B 계좌 +10,000원 성공 ↓ COMMIT ↓ 변경 내용 최종 반영 즉, 송금이 정상적으로 끝났다면 COMMIT 을 통해 DB에 결과를 확정한다. ROLLBACK 반대로 ROLLBACK 은 트랜잭션을 처리하는 도중 문제가 발생했을 때, 해당 트랜잭션에서 수행한 변경을 취소하고 이전 상태로 되돌리는 것 이다. A 계좌 -10,000원 성공 B 계좌 +10,000원 실패 ↓ ROLLBACK ↓ A 계좌 차감도 취소 이렇게 되면 최종적으로는 송금 전 상태로 돌아가게 된다. COMMIT 은 변경 내용을 확정하고, ROLLBACK 은 해당 트랜잭션에서 수행한 변경을 취소한다. 4. ACID 트랜잭션이 신뢰할 수 있게 동작하기 위해서는 몇 가지 성질을 보장해야 한다. 이를 대표적으로 ACID 라고 한다. ACID = Atomicity + Consistency + Isolation + Durability Atomicity — 원자성 하나의 트랜잭션에 포함된 작업은 모두 성공하거나 모두 실패해야 한다 는 의미이다. 쉽게 말하면 All or Nothing 이다. 앞에서 본 송금 예제를 생각해보면, A 계좌의 차감 작업 자체는 성공했더라도 B 계좌에 입금되지 않았다면 송금 전체는 실패한 것이다. A 계좌 -10,000원 성공 B 계좌 +10,000원 실패 ↓ 송금 전체 실패 즉, 일부 작업만 성공한 상태로 끝나는 것이 아니라 모든 작업이 함께 성공하거나 함께 실패해야 한다. Consistency — 일관성 트랜잭션을 수행하기 전과 후에도 데이터가 정해진 규칙을 만족해야 한다 는 의미이다. 예를 들어 데이터베이스에 다음과 같은 규칙이 있다고 해보자. 계좌 ID는 중복될 수 없다. 존재하지 않는 계좌를 참조할 수 없다. 트랜잭션이 실행되었다고 해서 이런 규칙이 깨진 데이터가 만들어져서는 안 된다. 정상적인 DB 상태 ↓ 트랜잭션 실행 ↓ 정상적인 DB 상태 즉, 데이터가 지켜야 할 규칙은 트랜잭션 전후에도 유지되어야 한다. Isolation — 격리성 동시에 실행되는 여러 트랜잭션이 서로 함부로 영향을 주지 않도록 하는 성질 이다. 실제 서버에서는 하나의 트랜잭션만 실행되는 것이 아니라 여러 사용자가 동시에 주문하고, 송금하고, 데이터를 수정할 수 있다. 사용자 A의 트랜잭션 ─┐ ├→ 동시에 DB 사용 사용자 B의 트랜잭션 ─┘ 이때 한 트랜잭션이 처리되는 도중 다른 트랜잭션의 작업 때문에 결과가 이상해지는 것을 막을 필요가 있다. 이번 글에서는 격리 수준까지는 다루지 않고, 여러 트랜잭션이 동시에 실행될 때 서로의 작업에 영향을 주지 않도록 해야 한다 는 정도로 이해했다. Durability — 지속성 트랜잭션이 성공해서 COMMIT 까지 완료되었다면 그 결과가 유지되어야 한다 는 의미이다. 예를 들어 A에서 B로 송금이 완료된 뒤 COMMIT 까지 끝난 상태에서 서버 장애가 발생했다고 해보자. A → B 송금 성공 ↓ COMMIT ↓ 서버 장애 발생 ↓ 서버 다시 시작 ↓ 송금 결과는 그대로 유지 COMMIT 까지 완료했는데 서버를 다시 시작한 뒤 송금 기록이 사라진다면 데이터베이스를 신뢰하기 어렵다. 따라서 성공적으로 완료된 트랜잭션의 결과는 장애가 발생하더라도 보존되어야 한다. ACID 한눈에 간단히 이해하기 특성 의미 Atomicity 전부 성공하거나 전부 실패 Consistency 작업 전후에도 데이터 규칙 유지 Isolation 동시에 실행돼도 서로 함부로 간섭하지 않음 Durability COMMIT 된 결과는 계속 보존 5. 직접 실행해보기 앞에서 이해한 COMMIT 과 ROLLBACK 을 간단한 SQL로 직접 확인해봤다. 먼저 계좌 정보를 저장할 테이블을 만들었다. CREATE TABLE account ( id BIGINT PRIMARY KEY, name VARCHAR(20), balance INT ); 그리고 A와 B 계좌의 초기 데이터를 추가했다. INSERT INTO account VALUES (1, 'A', 50000); INSERT INTO account VALUES (2, 'B', 10000); COMMIT A 계좌에서 10,000원을 차감하고 B 계좌에 10,000원을 추가한 뒤 COMMIT 을 실행했다. START TRANSACTION; UPDATE account SET balance = balance - 10000 WHERE id = 1; UPDATE account SET balance = balance + 10000 WHERE id = 2; COMMIT; 결과는 다음과 같다. A : 50000 → 40000 B : 10000 → 20000 COMMIT 을 실행했기 때문에 트랜잭션에서 수행한 변경 내용이 최종적으로 반영되었다. ROLLBACK ROLLBACK 도 확인하기 위해 계좌 잔액을 다시 처음 상태인 A 50,000원, B 10,000원으로 되돌린 뒤 같은 작업을 진행했다. START TRANSACTION; UPDATE account SET balance = balance - 10000 WHERE id = 1; UPDATE account SET balance = balance + 10000 WHERE id = 2; ROLLBACK; ROLLBACK 을 실행하면 트랜잭션 안에서 수행했던 변경이 취소된다. A : 50000 B : 10000 즉, COMMIT 은 변경 내용을 확정하고 ROLLBACK 은 해당 트랜잭션에서 수행한 변경을 취소한다는 것을 직접 확인할 수 있었다. 6. 정리 트랜잭션이 중요하다는 말은 많이 들었지만, 정확히 왜 필요한지에 대해서는 잘 알지 못했다. 이번에 송금 예제와 COMMIT , ROLLBACK , ACID를 정리하면서 트랜잭션이 단순히 여러 SQL을 묶는 기능이 아니라, 여러 작업 중 일부만 처리되어 데이터가 잘못된 상태로 남는 것을 막기 위해 필요한 개념이라는 것을 알게 되었다. 아직 트랜잭션을 깊게 공부한 것은 아니지만, 이번 정리를 통해 기본적인 개념과 왜 중요한지는 어느 정도 이해할 수 있었다. 앞으로 데이터베이스와 Spring/JPA를 더 공부하면서 트랜잭션이 실제 애플리케이션에서 어떻게 사용되고 동작하는지도 더 깊게 공부해볼 예정이다.
velog
프로그래밍을 처음 배울 때 환경변수는 보통 코드 밖에 비밀번호나 API 키를 저장하는 변수라고 배운다. const databaseUrl = process.env.DATABASE_URL; 애플리케이션은 DATABASE_URL 이라는 이름으로 외부에서 전달된 데이터베이스 주소를 읽는다. 기본 개념을 이해하기에는 충분한 설명이다. 하지만 실제 서비스를 개발하면 값을 코드 밖으로 옮기는 것보다 더 많은 판단이 필요하다. 개발·테스트·스테이징·운영 환경은 어떤 설정을 다르게 가져야 하는가? 숫자나 불리언 설정을 문자열에서 어떻게 변환할 것인가? 필수 설정이 없을 때 기본값을 사용할 것인가, 실행을 중단할 것인가? 환경변수에 저장한 값은 자동으로 비밀이 되는가? 프론트엔드에 공개해도 되는 설정과 서버에만 있어야 하는 설정을 어떻게 구분하는가? 운영 중 자주 바뀌는 정책도 환경변수로 관리해야 하는가? 비밀값을 교체하면 실행 중인 애플리케이션은 언제 새 값을 읽는가? 환경변수는 비밀값을 저장하는 변수가 아니다. 환경변수는 같은 코드를 서로 다른 실행 환경에서 사용할 수 있도록 코드와 배포별 설정을 분리하는 경계다. 같은 기능이라도 실행 환경에 따라 연결 대상은 달라진다 크리스가 온라인 강의 서비스를 개발한다고 생각해 보자. 서비스는 강의 정보 데이터베이스, 동영상 저장소, 이메일 발송 시스템에 연결된다. 처음에는 개발 환경의 주소를 코드에 직접 작성할 수 있다. const databaseUrl = "postgres://localhost:5432/course_dev"; const courseAssetBaseUrl = "http://localhost:4000/videos"; 이 코드는 크리스의 컴퓨터에서는 동작한다. 그러나 테스트 환경과 운영 환경에서는 다른 데이터베이스와 저장소를 사용해야 한다. 환경마다 조건문을 추가하는 방식도 생각할 수 있다. const databaseUrl = process.env.NODE_ENV === "production" ? "postgres://production-db/course" : "postgres://localhost:5432/course_dev"; 이제 운영 인프라 주소가 코드 안에 들어왔다. 새로운 스테이징 환경이 생기면 조건을 더 추가해야 하고, 연결 주소를 변경하려면 코드를 다시 수정하고 배포해야 한다. 실행 환경에 따라 달라지는 값은 코드 바깥에서 전달하는 편이 낫다. const databaseUrl = process.env.DATABASE_URL; const courseAssetBaseUrl = process.env.COURSE_ASSET_BASE_URL; 같은 애플리케이션 코드가 개발 환경에서는 개발용 데이터베이스를, 운영 환경에서는 운영용 데이터베이스를 사용한다. 달라지는 것은 코드가 아니라 배포 시 전달되는 설정이다. 같은 애플리케이션 코드 + 개발 환경의 설정 → 개발 서비스 + 운영 환경의 설정 → 운영 서비스 코드와 환경 설정을 분리하면 환경을 추가하거나 연결 대상을 변경할 때 비즈니스 로직까지 수정하지 않아도 된다. 코드 밖에서 들어온 설정도 검증 전까지 신뢰할 수 없다 환경변수는 애플리케이션 안에서 직접 선언한 값이 아니다. 배포 시스템, 운영체제, 컨테이너 설정, CI/CD 파이프라인 등 프로세스 바깥에서 들어온다. 따라서 환경변수도 외부 입력이며 검증 전까지 신뢰할 수 없다. 다음 코드는 타입이 맞는 것처럼 보이지만 실제로는 그렇지 않다. const port = process.env.PORT; const trialEnabled = Boolean(process.env.ENABLE_TRIAL_COURSE); Node.js에서 환경변수 값은 문자열 또는 undefined 로 다뤄진다. PORT=4000 은 숫자 4000 이 아니라 문자열 "4000" 이다. Boolean("false") 도 true 가 된다. 비어 있지 않은 문자열이기 때문이다. 애플리케이션이 시작될 때 형식과 필수 여부를 검증할 수 있다. import { z } from "zod"; const EnvironmentSchema = z.object({ NODE_ENV: z.enum([ "development", "test", "staging", "production", ]), DATABASE_URL: z.string().min(1), COURSE_ASSET_BASE_URL: z.string().url(), EMAIL_API_KEY: z.string().min(1), PORT: z.coerce .number() .int() .min(1) .max(65535) .default(3000), ENABLE_TRIAL_COURSE: z .enum(["true", "false"]) .default("false") .transform((value) => value === "true"), }); const result = EnvironmentSchema.safeParse(process.env); if (!result.success) { throw new Error( `Invalid environment configuration: ${ result.error.message }` ); } export const environment = result.data; 이 코드는 문자열을 애플리케이션이 사용할 타입으로 변환하고, 필수 설정이 누락되거나 허용하지 않은 값이 들어오면 시작을 중단한다. 설정 오류를 첫 번째 사용자 요청이 들어온 뒤 발견하는 것보다 애플리케이션 시작 단계에서 발견하는 편이 낫다. 기본값은 편리하지만 잘못된 환경을 숨길 수도 있다 모든 설정에 기본값을 제공하면 애플리케이션은 쉽게 실행된다. const databaseUrl = process.env.DATABASE_URL ?? "postgres://localhost:5432/course_dev"; 개발 환경에서는 편리할 수 있다. 하지만 운영 배포에서 DATABASE_URL 전달을 빠뜨려도 애플리케이션이 실행될 수 있다. 운영 서버가 로컬 데이터베이스에 연결을 시도하거나, 더 위험하게는 의도하지 않은 공용 데이터베이스를 사용할 수 있다. 기본값의 적절성은 설정의 책임에 따라 달라진다. 설정 기본값 판단 로컬 개발 서버 포트 안전한 기본값을 둘 수 있다 로그 상세 수준 환경에 맞는 보수적 기본값을 검토할 수 있다 운영 데이터베이스 주소 누락 시 실행을 중단하는 편이 낫다 이메일 서비스 인증 키 누락 시 관련 기능 또는 실행을 명확히 실패시켜야 한다 결제·서명·암호화 키 임의의 기본값을 사용해서는 안 된다 선택적 실험 기능 비활성화 상태를 기본값으로 둘 수 있다 필수 인프라와 보안 설정에 조용한 기본값을 두면 배포 오류가 정상 실행처럼 보인다. function requireEnvironmentValue( name: string ): string { const value = process.env[name]; if (!value) { throw new Error( `Missing required environment variable: ${name}` ); } return value; } const databaseUrl = requireEnvironmentValue("DATABASE_URL"); 이 코드는 중요한 설정이 없을 때 추측하지 않는다. 애플리케이션을 명확히 실패시켜 잘못된 배포를 조기에 발견하게 한다. 모든 변경 가능한 값을 환경변수에 넣어야 하는 것은 아니다 환경변수는 코드 밖의 값이지만, 코드 밖에 있는 모든 값을 환경변수로 관리해야 한다는 뜻은 아니다. 온라인 강의 서비스에는 여러 종류의 설정이 존재한다. 값의 성격 적절한 관리 위치 배포마다 다른 데이터베이스 주소 환경변수 또는 배포 설정 서버가 사용하는 외부 서비스 인증 정보 비밀값 관리 시스템 강의 동영상 저장소 이름 환경변수 또는 배포 설정 무료 체험 기간 정책 데이터베이스 또는 운영 설정 시스템 사용자별 자막 언어 사용자 데이터베이스 일부 사용자에게만 공개할 기능 기능 플래그 시스템 강의 수료 조건 도메인 로직 또는 운영 정책 저장소 애플리케이션 모듈 연결 방식 코드 브라우저에 공개할 서비스 이름 공개 프론트엔드 설정 무료 체험 기간이 14일 에서 7일 로 자주 바뀌고 운영자가 직접 변경해야 한다면 환경변수는 불편한 저장 위치다. const trialPeriodDays = Number( process.env.TRIAL_PERIOD_DAYS ); 이 방식에서는 정책을 변경할 때 애플리케이션을 다시 시작하거나 배포해야 할 수 있다. 누가 언제 값을 바꿨는지 기록하기도 어렵다. 운영 정책으로 다루면 책임이 더 명확해진다. const trialPolicy = await coursePolicyRepository.getTrialPolicy(); const trialEndsAt = addDays( enrollment.startedAt, trialPolicy.periodDays ); 이 코드는 체험 기간을 배포 설정이 아니라 서비스가 관리하는 정책에서 읽는다. 변경 이력, 관리자 권한, 적용 시점도 함께 설계할 수 있다. 환경변수에 적합한 기준은 “변경 가능한가”가 아니다. 코드 배포와 독립적이면서도 실행 환경별로 달라지는 값인가를 먼저 물어야 한다. 환경변수라는 이름이 비밀을 보장하지는 않는다 API 키를 소스 코드에 직접 작성하는 것보다 환경변수로 분리하는 편이 낫다. const emailApiKey = process.env.EMAIL_API_KEY; 그러나 환경변수에 저장했다는 사실만으로 값이 안전해지는 것은 아니다. 환경변수는 다음 위치에서 노출될 수 있다. 배포 플랫폼의 설정 화면 잘못 구성된 CI/CD 로그 오류 보고서와 진단 정보 프로세스 정보나 디버깅 도구 전체 환경 객체를 출력한 애플리케이션 로그 접근 권한이 지나치게 넓은 운영 계정 프론트엔드 빌드 결과물 다음 로그는 설정 확인에 도움이 되는 것처럼 보이지만 비밀값 전체를 남길 수 있다. console.log("Environment:", process.env); 로그에는 데이터베이스 비밀번호, API 키, 서명 키가 포함될 수 있다. 환경 전체를 기록해서는 안 된다. 필요한 비밀값은 전용 시스템에서 관리하고 최소 권한으로 애플리케이션에 전달할 수 있다. const emailApiKey = await secretStore.get( "course-service/email-api-key" ); 비밀값 관리 시스템은 저장 위치만 제공하는 것이 아니다. 시스템에 따라 접근 제어, 감사 기록, 버전 관리, 교체, 만료와 폐기 과정을 지원할 수 있다. 환경변수는 비밀값의 전달 수단이 될 수 있지만 완전한 비밀값 관리 체계는 아니다. 브라우저에 전달된 환경변수는 더 이상 서버 비밀값이 아니다 프론트엔드 코드에서도 빌드 도구를 통해 환경 설정을 참조할 수 있다. const publicApiBaseUrl = import.meta.env.VITE_API_BASE_URL; 이 값이 브라우저용 번들에 포함되면 사용자가 내려받은 JavaScript에서 확인할 수 있다. 변수 이름에 API_KEY 나 SECRET 을 붙여도 비밀이 되지 않는다. 프론트엔드에 공개할 수 있는 설정과 서버에만 존재해야 하는 설정을 구분해야 한다. type PublicCourseConfig = { apiBaseUrl: string; supportEmail: string; }; type ServerCourseConfig = { databaseUrl: string; emailApiKey: string; sessionSigningKey: string; }; PublicCourseConfig 는 사용자가 확인해도 되는 값이다. ServerCourseConfig 는 브라우저 번들, HTML, 공개 API 응답에 포함되면 안 된다. 다음과 같은 구조는 피해야 한다. export const config = { publicApiBaseUrl: process.env.PUBLIC_API_BASE_URL, emailApiKey: process.env.PUBLIC_EMAIL_API_KEY, }; PUBLIC_ 같은 접두사는 값을 보호하지 않는다. 일부 빌드 시스템에서는 오히려 해당 값을 클라이언트 번들에 포함하라는 의미로 사용된다. 비밀값이 필요한 작업은 서버에서 수행하고 프론트엔드는 필요한 결과만 받아야 한다. 빌드 시점의 설정과 실행 시점의 설정은 생명주기가 다르다 서버 애플리케이션은 보통 프로세스가 시작될 때 환경변수를 읽는다. 프론트엔드 빌드는 다른 생명주기를 가질 수 있다. 빌드 도구가 환경변수 값을 JavaScript 파일에 삽입하면 그 값은 빌드 결과물에 고정된다. const apiBaseUrl = import.meta.env.VITE_API_BASE_URL; 이 코드가 빌드 시 "https://staging-api.example.com" 으로 치환되었다면, 같은 파일을 운영 환경으로 옮겨도 운영 API 주소로 자동 변경되지 않는다. 따라서 배포 방식을 먼저 정해야 한다. 환경마다 프론트엔드를 별도로 빌드할 것인가? 하나의 빌드 결과물을 여러 환경으로 승격할 것인가? 실행 시 공개 설정을 별도 엔드포인트에서 불러올 것인가? 설정 변경에 재빌드, 재배포, 프로세스 재시작 중 무엇이 필요한가? 하나의 결과물을 여러 환경에서 사용해야 한다면 공개 런타임 설정을 따로 제공할 수 있다. type RuntimePublicConfig = { apiBaseUrl: string; }; const runtimeConfig: RuntimePublicConfig = await fetch("/runtime-config.json") .then((response) => response.json()); 브라우저는 실행 시점에 현재 환경의 공개 설정을 불러온다. 이 파일에는 누구나 볼 수 있는 값만 포함해야 한다. 설정의 저장 위치뿐 아니라 값을 읽는 시점도 설계해야 한다. .env 파일은 로컬 개발 도구이지 비밀 저장소가 아니다 크리스는 로컬 개발을 위해 .env 파일을 사용할 수 있다. DATABASE_URL=postgres://localhost:5432/course_dev COURSE_ASSET_BASE_URL=http://localhost:4000/videos ENABLE_TRIAL_COURSE=true 이 파일은 반복해서 환경변수를 입력하지 않아도 되게 해준다. 그러나 .env 라는 이름이 파일을 암호화하거나 접근을 제한하지는 않는다. 실제 비밀값이 들어 있는 파일은 버전 관리 대상에서 제외해야 한다. .env .env.local .env.*.local 다만 .gitignore 는 앞으로의 추가를 막을 뿐 이미 커밋된 비밀값을 없애지 않는다. 비밀값이 저장소에 들어갔다면 기록에서 파일을 지우는 것만으로 끝내지 말고 해당 값을 폐기하고 새 값으로 교체해야 한다. 필요한 설정 이름은 예제 파일로 공유할 수 있다. # .env.example DATABASE_URL= COURSE_ASSET_BASE_URL= EMAIL_API_KEY= ENABLE_TRIAL_COURSE=false 예제 파일은 필요한 키와 안전한 예시만 설명한다. 실제 인증 정보는 포함하지 않는다. .env 파일은 로컬 환경변수를 편리하게 전달하는 형식이다. 운영 비밀값의 Source of Truth로 취급해서는 안 된다. 설정은 한 번 검증한 뒤 타입이 있는 객체로 전달하는 편이 낫다 애플리케이션 곳곳에서 process.env 를 직접 읽으면 어떤 설정이 필요한지 파악하기 어렵다. // course-service.ts const trialEnabled = process.env.ENABLE_TRIAL_COURSE === "true"; // email-service.ts const emailApiKey = process.env.EMAIL_API_KEY; // upload-service.ts const assetUrl = process.env.COURSE_ASSET_BASE_URL; 각 모듈이 문자열 변환과 누락 처리를 제각각 수행하게 된다. 테스트도 실행 중인 컴퓨터의 환경에 의존할 수 있다. 시작 단계에서 한 번 읽고 검증한 설정을 명시적으로 전달할 수 있다. export type CourseServiceConfig = { trialEnabled: boolean; courseAssetBaseUrl: string; emailApiKey: string; }; export function createCourseService( config: CourseServiceConfig ) { return new CourseService({ trialEnabled: config.trialEnabled, courseAssetBaseUrl: config.courseAssetBaseUrl, emailApiKey: config.emailApiKey, }); } 이제 CourseService 는 환경변수의 존재를 알 필요가 없다. 이미 검증된 애플리케이션 설정만 받는다. 테스트에서도 필요한 설정을 직접 전달할 수 있다. const courseService = createCourseService({ trialEnabled: true, courseAssetBaseUrl: "https://assets.test.example", emailApiKey: "test-key", }); 테스트 결과가 개발자의 컴퓨터에 우연히 설정된 환경변수에 좌우되지 않는다. 환경변수는 프로세스 경계에서 읽고, 내부에서는 의미가 분명한 타입으로 사용하는 편이 낫다. 설정의 Source of Truth와 전달된 복사본을 구분해야 한다 실행 중인 process.env 는 설정의 영구적인 원본이 아닐 수 있다. 배포 설정 또는 비밀값 관리 시스템 ↓ 프로세스에 환경변수로 전달 ↓ 시작 시 검증 ↓ 타입이 있는 애플리케이션 설정 ↓ 서비스 코드가 사용 이를 흐름으로 표현하면 다음과 같다. flowchart TD A[배포 설정] --> C[프로세스 환경] B[비밀값 관리 시스템] --> C C --> D[시작 시 검증] D --> E[타입이 있는 설정] E --> F[서비스 코드] 각 단계의 책임은 다르다. 배포 설정은 환경별 연결 주소와 실행 옵션의 Source of Truth가 될 수 있다. 비밀값 관리 시스템은 인증 정보와 키의 Source of Truth가 될 수 있다. 프로세스 환경은 현재 실행에 전달된 값의 복사본이다. 검증된 설정 객체는 애플리케이션 내부에서 사용하는 표현이다. 서비스 코드는 설정을 소비하지만 원본을 소유하지 않는다. 배포 플랫폼에서 값을 변경해도 이미 실행 중인 프로세스가 자동으로 새 값을 읽는다고 가정해서는 안 된다. 많은 환경에서는 재시작이나 재배포가 필요하다. 반대로 실행 중 즉시 바뀌어야 하는 운영 정책이라면 환경변수보다 데이터베이스나 동적 설정 시스템이 더 적합할 수 있다. 환경을 분리한다는 것은 이름만 다르게 붙이는 일이 아니다 개발, 테스트, 스테이징, 운영 환경에 서로 다른 이름을 붙였더라도 같은 인증 정보와 저장소를 공유하면 실제 경계는 약하다. 온라인 강의 서비스는 환경별로 다음 자원을 분리할 수 있다. 데이터베이스와 사용자 데이터 강의 동영상 저장소 이메일 발송 계정과 수신 대상 외부 결제·분석 시스템의 프로젝트 세션 서명 키 로그와 모니터링 대상 접근 가능한 운영 계정 예를 들어 스테이징 환경에서 실제 수강생에게 이메일이 발송되지 않도록 수신자를 제한할 수 있다. const recipient = environment.NODE_ENV === "production" ? student.email : environment.TEST_EMAIL_RECIPIENT; 이 코드는 비운영 환경의 이메일을 지정된 테스트 주소로 보낸다. 실제 구현에서는 발송 서비스 자체도 테스트 계정이나 샌드박스로 분리하는 편이 더 안전하다. 환경 분리는 설정값의 차이뿐 아니라 장애와 실수의 영향 범위를 제한하는 설계다. 비밀값은 생성부터 폐기까지 생명주기를 가진다 이메일 API 키를 환경변수로 전달하는 것만으로 비밀값 관리가 끝나지는 않는다. 비밀값에는 다음 과정이 존재한다. 안전한 방식으로 생성한다. 필요한 서비스만 읽을 수 있도록 권한을 제한한다. 전달 과정과 사용 기록을 관리한다. 정기적으로 또는 사고 발생 시 교체한다. 이전 값을 일정한 전환 기간 뒤 폐기한다. 노출 여부를 탐지하고 대응한다. 키를 교체할 때 두 값을 잠시 함께 허용해야 하는 시
velog
두 정수 a, b가 주어질 때 다음과 같은 형태의 계산식을 출력하는 코드를 작성해 보세요. 입출력 예 입력 #1 4 5 출력 #1 4 + 5 = 9 package code; import java.util.Scanner; public class ese { static void main(String[] args) { Scanner sc = new Scanner(System.in); int a = sc.nextInt(); int b = sc.nextInt(); System.out.printf("%d + %d = %d", a, b, a + b); } } 인텔리제이에 해놓고 실행을 해보았는데 왜 안되나 했더만 printf를 안했다 한 번 사용해 보았지만 까먹고 있었는데 다시 생각이 났다
Балл: 54.4Уверенность: 49%
Подробнееvelog
y_test = [2, 4, 7, 10] plt.plot( [y_test.min(), y_test.max()], [y_test.min(), y_test.max()], color="red" ) max_depth=60 (depth : 트리의 깊이) 시작 ← depth 0 / \ 조건 조건 ← depth 1 / \ / \ 조건 조건 조건 조건 ← depth 2 / \ 결과 결과 ← depth 3 min_samples_leaf=40 () Present_Price <= 10? / \ Yes No / \ Vehicle_Age <= 5? [Leaf] / \ [Leaf] [Leaf] [Leaf]에 도착하면 더 이상 질문하지 않고 가격을 예측 각 Leaf에는 최소 40개의 학습 데이터가 들어 있어야 함 전체 232개 / \ 120개 112개 / \ / \ 50개 70개 52개 60개 ↓ ↓ ↓ ↓ Leaf Leaf Leaf Leaf 머신러닝 라이브러리 from sklearn.tree import DecisionTreeRegressor : 결정 트리 모델 from sklearn.linear_model import LinearRegression : 선형회귀 모델 from sklearn.metrics import root_mean_squared_error : RMSE 계산 from sklearn.tree import plot_tree : 결정 트리 그림으로 표시
Балл: 54.4Уверенность: 49%
ПодробнееБалл: 54.4Уверенность: 49%
Балл: 54.4Уверенность: 49%