[프롬프트] 특정 언어(Python ➔ Go) 코드 변환 프롬프트 - 최적 프롬프트 레시피

[프롬프트] 특정 언어(Python ➔ Go) 코드 변환 프롬프트 - 최적 프롬프트 레시피
Prompt Engineering Recipe

[프롬프트] 특정 언어(Python ➔ Go) 코드 변환 프롬프트 - 최적 프롬프트 레시피

Python의 동적 비동기 코드를 Go의 고성능 정적 타입 동시성 파이프라인으로 무결점 전환하는 Staff 레벨 프롬프트

Code Migration Banner

"Python으로 프로토타이핑한 마이크로서비스를 Go로 전환할 때, LLM에 단순 변환을 요청하면 interface{} 남발, panic 남용, 제어되지 않는 Goroutine이 생성되어 컴파일만 되는 불안정한 코드가 양산됩니다. 구조화된 지침이 필수적입니다."

1단계: 페인포인트 & 작업 목표

단순 기계 번역 시 마주치는 치명적 안티패턴

  • 타입 시스템 붕괴: Python의 dict를 map[string]interface{}나 any로 무분별하게 변환하여 런타임 타입 단언 패닉 초래
  • 예외 처리 왜곡: Python의 try-except를 흉내 내려 panic/recover를 남용하거나 에러 리턴을 무시
  • 동시성 모델 오염: asyncio.gather를 제한 없는 go func()로 변환해 메모리 OOM 및 고루틴 누수 발생
  • 리소스 누수: Go의 필수적인 context.Context 생명주기 및 defer resp.Body.Close() 누락

완벽한 포팅을 위한 엔지니어링 목표

  • 관용적 Go(Idiomatic Go): 정적 타입 Struct와 명시적 (T, error) 다중 반환 구조 확립
  • 포인터 vs 값 리시버의 명확한 분리: 불필요한 힙 할당 방지 및 상태 뮤테이션 제어
  • 구조화된 동시성(Structured Concurrency): Worker Pool, 버퍼드 채널, errgroup 적용
  • 견고한 수명주기: context.Context를 통한 타임아웃 및 Graceful Cancellation 보장

2단계: 프롬프트 레시피 비교 (3단 분리 표기)

레시피 A: 단순 변환 초안 (Naive Prompt)
1. Prompt (English Original)
Convert this Python code to Go. Make sure it compiles and works the same way.
2. 한글 1:1 직역
"이 Python 코드를 Go로 변환해 줘. 컴파일되고 동일하게 동작하도록 해줘."
💡 독립 해설: 제약조건이 전무하여 LLM이 Python의 런타임 덕 타이핑을 흉내 내기 위해 interface{}와 panic을 남발하게 됩니다.
레시피 B: Staff Go Engineer 실무 종결형 (권장)
1. Prompt (English Original)
Act as a Principal Go Engineer. Refactor the following Python code into idiomatic, production-grade Go (Go 1.21+).

[Architecture & Design Rules]
1. Idiomatic Type Safety: Replace dynamic dictionaries and duck typing with strictly typed Go structs. Do NOT use `interface{}` or `any` unless absolutely necessary.
2. Error Handling: Eliminate all panic/recover emulation. Return explicit `(T, error)` tuples and use `fmt.Errorf("...: %w", err)` for wrapping.
3. Concurrency & Lifecycle:
   - Convert Python `asyncio` tasks to structured Goroutine Worker Pools with bounded concurrency.
   - Accept `context.Context` as the first parameter in all I/O or long-running functions.
   - Properly propagate cancellation and implement graceful shutdown.
4. Memory Management:
   - Explicitly decide pointer (`*T`) vs value (`T`) receivers based on mutation and allocation cost.
   - Ensure all `io.Closer` resources are cleaned up with `defer`.
5. Testing: Provide table-driven unit tests (`testing.T`) covering edge cases and context timeouts.

[Input Python Code]
2. 한글 1:1 직역
"수석 Go 엔지니어 역할을 수행해 줘. 다음 Python 코드를 관용적이고 프로덕션 환경에 적합한 Go(1.21 이상) 코드로 리팩터링해 줘.
[아키텍처 및 설계 규칙]
1. 관용적 타입 안정성: 동적 딕셔너리와 덕 타이핑을 엄격한 타입의 Go 구조체로 대체할 것. 절대적으로 불가피하지 않은 한 interface{}나 any를 쓰지 말 것.
2. 에러 처리: 모든 panic/recover 흉내 내기를 제거할 것. 명시적인 (T, error) 튜플을 반환하고 fmt.Errorf("...: %w", err)로 래핑할 것.
3. 동시성 및 생명주기: Python의 asyncio 태스크를 동시성 수가 제한된 구조화된 고루틴 워커 풀로 변환하고, 모든 I/O 함수는 context.Context를 첫 매개변수로 수신하며 취소 신호를 전파할 것.
4. 메모리 관리: 상태 변경 여부와 할당 비용에 따라 포인터 vs 값 리시버를 명확히 구분하고, io.Closer는 defer로 정리할 것.
5. 테스팅: 엣지 케이스 및 타임아웃을 다루는 테이블 주도 단위 테스트를 제공할 것.
[입력 Python 코드]"
💡 독립 해설: 정적 타입 구조체화, 에러 래핑, 워커 풀, 컨텍스트 취소 전파를 강제하여 컴파일 안정성과 운영 유지보수성을 확보합니다.
레시피 C: 고성능/저지연 동시성 파이프라인 특화 변환 프롬프트
1. Prompt (English Original)
Act as a High-Performance Go Systems Specialist. Convert this Python data processing pipeline into an ultra-low latency, zero-allocation Go pipeline.

[Optimization Directives]
1. Streaming I/O: Replace in-memory list loads with streaming decoders (`json.NewDecoder`) consuming `io.Reader`.
2. Zero-Allocation & Pooling: Use `sync.Pool` for reusable heap-allocated buffers or intermediate state objects.
3. Concurrency Pipeline:
   - Implement pipeline stages connected via bounded (buffered) channels.
   - Use `golang.org/x/sync/errgroup` with `SetLimit(N)` to enforce worker boundaries and early-exit error handling.
   - Guarantee leak-free Goroutines: Ensure all channel readers terminate when context cancels.
4. Profiling-Ready: Keep allocations per operation (allocs/op) near zero in hot paths.

[Input Python Code]
2. 한글 1:1 직역
"고성능 Go 시스템 전문가 역할을 수행해 줘. 이 Python 데이터 처리 파이프라인을 초저지연, 제로 할당 Go 파이프라인으로 변환해 줘.
[최적화 지침]
1. 스트리밍 I/O: 메모리 내 리스트 적재를 io.Reader를 소비하는 스트리밍 디코더로 대체할 것.
2. 제로 할당 및 풀링: 재사용 가능한 버퍼나 상태 객체에 sync.Pool을 적용할 것.
3. 동시성 파이프라인: 버퍼드 채널로 연결된 파이프라인을 구현하고, errgroup.SetLimit(N)으로 워커 수 제한 및 빠른 에러 종료를 구현할 것. 고루틴 누수를 방지할 것.
4. 프로파일링 대비: 핫 패스에서 연산당 메모리 할당 수를 0에 가깝게 유지할 것.
[입력 Python 코드]"
💡 독립 해설: 대용량 파일/네트워크 I/O 변환 시 sync.Pool과 버퍼드 채널 파이프라인을 결합해 GC 부하를 제거하는 데 최적화되었습니다.

3단계: 실행 결과 비교

❌ 레시피 A 실행 한계 분석

단순 지시 프롬프트로 생성된 코드는 공유 슬라이스(results = append(results, res))에 락 없이 무제한 고루틴으로 접근하여 데이터 레이스(Data Race) 패닉을 발생시킵니다. 또한 recover() 흉내와 무제한 HTTP 요청으로 프로덕션 서버를 즉시 다운시킵니다.

⚡ 레시피 B 실전 사례: 비동기 데이터 수집기 (Worker Pool + Context)

🎯 독자 따라하기 4단계 프롬프트 워크플로우
  1. 1단계 (도메인 모델): "Python 코드의 입출력 JSON을 분석해 Go 구조체(Struct)를 선언해 줘."
  2. 2단계 (워커 풀 제약): "레시피 B를 적용하여 동시 작업 수를 제어하는 Worker Pool 구조로 작성해 줘."
  3. 3단계 (에러 & 타임아웃): "context.WithTimeout과 fmt.Errorf(%w) 래핑을 추가해 줘."
  4. 4단계 (테스트 검증): "httptest.Server를 사용한 단위 테스트 코드를 작성해 줘."
package scraper

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"
)

type TargetResponse struct {
	ID        int64     `json:"id"`
	Title     string    `json:"title"`
	FetchedAt time.Time `json:"fetched_at"`
}

type Scraper struct {
	client  *http.Client
	workers int
}

func NewScraper(workers int, timeout time.Duration) *Scraper {
	return &Scraper{
		workers: workers,
		client: &http.Client{
			Timeout: timeout,
			Transport: &http.Transport{
				MaxIdleConns:        100,
				MaxIdleConnsPerHost: 20,
				IdleConnTimeout:     90 * time.Second,
			},
		},
	}
}

func (s *Scraper) FetchAll(ctx context.Context, urls []string) ([]TargetResponse, []error) {
	jobs := make(chan string, len(urls))
	results := make(chan TargetResponse, len(urls))
	errs := make(chan error, len(urls))

	var wg sync.WaitGroup

	for w := 0; w < s.workers; w++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				select {
				case <-ctx.Done():
					return
				case url, ok := <-jobs:
					if !ok {
						return
					}
					data, err := s.fetchOne(ctx, url)
					if err != nil {
						errs <- fmt.Errorf("fetch failed for %s: %w", url, err)
					} else {
						results <- data
					}
				}
			}
		}()
	}

	for _, u := range urls {
		jobs <- u
	}
	close(jobs)

	go func() {
		wg.Wait()
		close(results)
		close(errs)
	}()

	var finalResults []TargetResponse
	var finalErrors []error

	for res := range results {
		finalResults = append(finalResults, res)
	}
	for err := range errs {
		finalErrors = append(finalErrors, err)
	}

	return finalResults, finalErrors
}

func (s *Scraper) fetchOne(ctx context.Context, targetURL string) (TargetResponse, error) {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, nil)
	if err != nil {
		return TargetResponse{}, fmt.Errorf("create req: %w", err)
	}

	resp, err := s.client.Do(req)
	if err != nil {
		return TargetResponse{}, fmt.Errorf("do req: %w", err)
	}
	defer func() {
		io.Copy(io.Discard, resp.Body)
		resp.Body.Close()
	}()

	if resp.StatusCode != http.StatusOK {
		return TargetResponse{}, fmt.Errorf("unexpected status: %d", resp.StatusCode)
	}

	var data TargetResponse
	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		return TargetResponse{}, fmt.Errorf("decode: %w", err)
	}
	data.FetchedAt = time.Now()
	return data, nil
}

🚀 레시피 C 실전 사례: 고성능 스트리밍 파이프라인 (Streaming Decoder + sync.Pool)

package pipeline

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"strings"
	"sync"

	"golang.org/x/sync/errgroup"
)

type SourceRecord struct {
	ID    string  `json:"id"`
	Value float64 `json:"value"`
}

type TransformedRecord struct {
	UID   string  `json:"uid"`
	Score float64 `json:"score"`
}

func StreamProcessJSON(ctx context.Context, r io.Reader, w io.Writer, concurrency int) error {
	dec := json.NewDecoder(r)
	token, err := dec.Token()
	if err != nil || token != json.Delim('[') {
		return fmt.Errorf("expected json array opening: %w", err)
	}

	recordChan := make(chan SourceRecord, 500)
	g, gCtx := errgroup.WithContext(ctx)
	g.SetLimit(concurrency)

	// Producer Stage
	g.Go(func() error {
		defer close(recordChan)
		for dec.More() {
			var rec SourceRecord
			if err := dec.Decode(&rec); err != nil {
				return fmt.Errorf("streaming decode: %w", err)
			}
			select {
			case <-gCtx.Done():
				return gCtx.Err()
			case recordChan <- rec:
			}
		}
		dec.Token()
		return nil
	})

	outChan := make(chan TransformedRecord, 500)
	var workerWg sync.WaitGroup

	for i := 0; i < concurrency; i++ {
		workerWg.Add(1)
		go func() {
			defer workerWg.Done()
			for item := range recordChan {
				res := TransformedRecord{
					UID:   strings.ToUpper(item.ID),
					Score: item.Value * 1.5,
				}
				select {
				case <-gCtx.Done():
					return
				case outChan <- res:
				}
			}
		}()
	}

	go func() {
		workerWg.Wait()
		close(outChan)
	}()

	enc := json.NewEncoder(w)
	for out := range outChan {
		if err := enc.Encode(out); err != nil {
			return fmt.Errorf("stream encode: %w", err)
		}
	}

	return g.Wait()
}

4단계: 메커니즘 심층 분석

1. 동적 타이핑 ➔ 정적 구조체 컴파일 검증

Python 런타임의 덕 타이핑은 Go에서 컴파일 타임 메모리 레이아웃으로 변환되어야 합니다. 프롬프트에 Strictly typed Go structs 제약을 부여해야 interface{}를 통한 불필요한 힙 이스케이프 및 타입 단언 런타임 패닉을 차단할 수 있습니다.

2. 단일 스레드 비동기(GIL) ➔ 진정한 병렬 동시성(M:N Goroutines)

Python asyncio는 단일 스레드 협력형 멀티태스킹이므로 공유 메모리 Race Condition이 상대적으로 적습니다. 하지만 Go는 실제 멀티코어에 스케줄링되므로, 버퍼드 채널과 워커 풀 제약 없이 단순 번역하면 데이터 레이스가 발생합니다.

3. HTTP 커넥션 풀링과 defer 리소스 관리

Go의 http.Response.Body는 닫는 것뿐만 아니라 내부 데이터를 완전히 소진(io.Copy(io.Discard, ...))해야 Keep-Alive 소켓을 재사용합니다. 프롬프트가 이 패턴을 규정해야 소켓 고갈을 방지합니다.

5단계: 실전 응용 팁 & 플레이스홀더 템플릿

컴파일 및 런타임 필수 검증 명령어

  • go test -race ./... : 채널 및 공유 자원 Race Condition 정밀 추적
  • golangci-lint run : errcheck, contextcheck 등 정적 분석
  • go test -bench=. -benchmem : 할당당 바이트(B/op)와 allocs/op 제로 할당 여부 측정
범용 모듈러 변환 템플릿 (바로 복사해서 사용)
Template Prompt (English)
Act as a Lead Go Engineer. Convert the following Python module [MODULE_NAME] to an idiomatic Go package.

Target Go Version: Go [GO_VERSION, e.g., 1.22]
Concurrency Model: [CONCURRENCY_MODEL, e.g., Worker Pool / errgroup / None]
Max Concurrency: [NUM_WORKERS, e.g., 50]

Strict Conversion Rules:
1. Replace all Python Dicts/Dynamic types with explicitly defined Go Structs with appropriate `json:` or `db:` tags.
2. Replace Python Exceptions with explicit `(T, error)` returns. Wrap context with `fmt.Errorf("%w")`.
3. In I/O operations, accept `ctx context.Context` as the first argument. Respect context cancellation inside loops.
4. Clean up network/file resources using `defer resource.Close()`.
5. Return a complete, self-contained Go package including unit tests.

[Python Source Code]
{PASTE_YOUR_PYTHON_CODE_HERE}
한글 직역 & 가이드
"수석 Go 엔지니어 역할을 수행해 줘. 다음 Python 모듈 [MODULE_NAME]을(를) 관용적인 Go 패키지로 변환해 줘. 동시성 모델([CONCURRENCY_MODEL])과 워커 수([NUM_WORKERS])를 준수하고, 엄격한 구조체 타입, (T, error) 반환, context.Context 취소 전파를 강제할 것."
Vibe Coding Series • 특정 언어 코드 변환 프롬프트 가이드

댓글 쓰기

다음 이전