데이시스
경력근거: 위 과정에서 만들어진 아키텍처와 파이프라인을 재사용 가능한 형태로 정리하여
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고가 주요 업무 마지막에 '위 과정에서 만들어진 아키텍처와 파이프라인을 재사용 가능한 형태로 정리하여, 다른 고객에게도 제공할 수 있는 스케일 가능한 솔루션 자산으로 전환합니다' 를 적었습니다. 프로젝트가 끝난 뒤 무엇을 자산으로 남길지 가르는 일이 이 포지션의 자리이고, 이 포트폴리오는 그 판단을 신호 사전과 규칙으로 옮깁니다. '고객사 현장(데이터 인프라, 프로세스, 조직 구조 등)을 깊이 이해하고, 실제 문제를 정확히 진단' 한다는 대목도 남의 파이프라인을 읽는 같은 자리를 가리킵니다. 이 포트폴리오가 보여주는 것은 신호 사전을 데이터로 두고 본문과 맞춰 재사용 여부를 가르는 기술이며, Databricks 운영 경험이나 게임·의료·제조 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
'재사용 가능한 형태로 정리하여, 다른 고객에게도 제공할 수 있는 스케일 가능한 솔루션 자산으로 전환'. 이 판정이 그 정리의 첫 단계입니다.
'고객사 현장(데이터 인프라, 프로세스, 조직 구조 등)을 깊이 이해하고, 실제 문제를 정확히 진단'. 파견 현장에서 받는 자료가 남의 파이프라인입니다.
'Python, SQL에 능숙하고, 데이터 엔지니어링 경험'. 단계 본문을 읽어 신호를 찾는 일이 그 기본기입니다.
파이프라인 단계를 다른 고객에게도 다시 쓸 수 있는지 가릅니다. 고객 고유 신호 사전을 두고 단계 본문에서 신호를 찾아, 차단 신호가 걸리면 그 고객 전용으로, 값만 밖으로 빼면 되는 신호면 파라미터화 대상으로, 아무 신호도 없으면 그대로 재사용으로 정합니다. 본문이 비어 있으면 판정하지 않고 원본을 다시 받게 하며, 사전에 없는 오퍼레이터는 미매핑으로 남겨 규칙을 먼저 채우게 합니다. 여러 프로젝트에 같은 이름과 같은 본문이 있으면 한 벌로 묶어 중복을 줄입니다. 단계 정의는 실 고객사 저장소 대신 지원자가 공개 Airflow 예제 DAG 를 고쳐 만든 것을 가정합니다.
고객사를 옮겨 다니며 데이터 파이프라인을 짜고, 프로젝트가 끝나면 그중 무엇을 회사 자산으로 남길지 정하는 자리에 앉는 FDE 입니다. 어느 단계가 다음 고객에게도 통하는지를 매번 본문을 처음부터 읽어 가려내던 사람입니다.
고객 고유 신호를 사전으로 두고 단계 본문에서 찾으면, 재사용과 전용이 규칙으로 갈리고 파라미터화만 하면 되는 단계가 따로 드러난다는 가정입니다. 사전에 없는 오퍼레이터는 미매핑으로 빠지므로 아직 규칙이 없는 구간이 그대로 보입니다.
단계 정의와 신호 사전을 받아 단계마다 재사용·파라미터화·전용을 판정하고, 걸렸으면 본문의 어느 대목이 어느 신호에 걸렸는지 붙여 프로젝트별로 묶은 판정 리포트를 터미널과 Markdown 파일로 내는 CLI 가 도는 완결품입니다.
공개 예제에서 고쳐 만든 단계 80건에 손으로 붙인 정답 판정과 대조해 일치율을 내고, 미매핑이 몰리는 오퍼레이터를 모아 사전에 없는 구간을 목록으로 냅니다.
재사용과 파라미터화로 갈린 단계를 모아 대체할 값을 붙여 자산 후보 목록을 조립하고, 중복으로 묶인 단계는 대표 하나만 남기는 단계입니다.
FDE 가 단계 정의와 신호 사전을 넣으면 단계마다 재사용 여부와 걸린 신호가 프로젝트별로 묶여 나오는 과정을 시연합니다.
공개 예제에서 고쳐 만든 단계 80건과 손으로 붙인 정답 판정을 대조해 일치율을 냅니다. 단, 정답과 단계 정의를 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
본문이 비었거나 오퍼레이터 표기가 흔들리거나 사전에 없는 오퍼레이터가 섞인 입력 30종을 넣어도 출력 형식이 안 깨지고 사유별로 빠지는 비율을 보여줍니다.
신호 사전을 고쳤을 때 옛 판정이 어떻게 뒤집히는지 회귀로 확인합니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 작성자가 만든 단계의 자가채점이며, 실제 자산화 판단은 데이시스 고객사의 실 파이프라인과 실 재사용 기준이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 붙였으니 잘 맞는 게 당연하므로, 본문 결측과 사전에 없는 오퍼레이터를 일부러 섞어 쉬운 단계만 푸는 함정을 피합니다.
이 포트폴리오가 보여주는 것은 신호 사전을 데이터로 두고 본문과 맞춰 재사용 여부를 가르는 기술이며, Databricks 운영 경험이나 게임·의료·제조 도메인 전문성은 주장하지 않습니다. 판정은 신호 대조가 하고 LLM 은 파라미터 이름 후보만 맡습니다.
신호가 안 걸렸다고 다음 고객에게 그대로 돈다는 뜻은 아니어서, 판정에 본문 전문을 함께 실어 담당자가 한 번 더 읽게 둡니다.
실제 도입 때는 고객사마다 금지 신호와 계정 규칙이 다르므로, 사전을 새로 채우는 일을 도입 단계 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
프로젝트별 파이프라인 단계 정의입니다. 단계 이름 원문과 오퍼레이터 표기 원문, 본문, 다루는 데이터셋, 앞 단계를 한 행에 둡니다. 오퍼레이터 표기는 저장소마다 손으로 적어 'PythonOperator'와 'python_operator'처럼 흔들립니다. 본문이 비어 있는 단계, 사전에 없는 오퍼레이터를 쓴 단계, 여러 프로젝트에 같은 이름과 같은 본문으로 있는 단계를 일부러 섞어 두어 사유가 갈리게 둡니다.
| task_no | project_code | task_name_raw | operator_raw | body_text | dataset_name | upstream_task_no |
|---|---|---|---|---|---|---|
| PT-1001 | GAME-A | load_orders_daily | PythonOperator | SELECT * FROM raw.orders WHERE dt = '{… | orders | — |
| PT-1002 | GAME-A | mask_user_email | PythonOperator | UPDATE stg.users SET email = sha2(emai… | users | PT-1001 |
| PT-1003 | GAME-A | push_to_gamecorp_bucket | python_operator | aws s3 cp out/ s3://gamecorp-prod-dw/d… | — | PT-1002 |
| PT-1004 | MED-B | load_orders_daily | PythonOperator | SELECT * FROM raw.orders WHERE dt = '{… | orders | — |
| PT-1005 | MED-B | normalize_dept_code | PythonOperator | SELECT dept, upper(trim(dept)) AS dept… | visits | PT-1004 |
아래 JSON Schema 를 그대로 만족하는 파이프라인 단계 행을 60개 더 만들어 주세요. 프로젝트를 네댓 개로 나누고 오퍼레이터 표기를 'PythonOperator'와 'python_operator'처럼 흔들어 적습니다. 2할은 본문을 비우고, 몇 건은 여러 프로젝트에 같은 이름과 같은 본문으로 두며, 몇 건은 신호 사전에 없는 오퍼레이터를 씁니다. 재사용 여부나 걸린 신호는 넣지 마세요.
{"type": "object", "properties": {"task_no": {"type": "string"}, "project_code": {"type": "string"}, "task_name_raw": {"type": "string"}, "operator_raw": {"type": "string"}, "body_text": {"type": ["string", "null"]}, "dataset_name": {"type": ["string", "null"]}, "upstream_task_no": {"type": ["string", "null"]}}, "required": ["task_no", "project_code", "task_name_raw", "operator_raw", "body_text"]}{"type": "object", "properties": {"task_no": {"type": "string"}, "project_code": {"type": "string"}, "task_name_raw": {"type": "string"}, "operator_raw": {"type": "string"}, "body_text": {"type": ["string", "null"]}, "dataset_name": {"type": ["string", "null"]}, "upstream_task_no": {"type": ["string", "null"]}}, "required": ["task_no", "project_code", "task_name_raw", "operator_raw", "body_text"]}고객 고유 신호 사전입니다. 신호 이름과 적용 오퍼레이터 표기, 찾을 방식과 패턴, 차단 여부, 담당을 한 행에 둡니다. 차단 신호와 권장 신호를 섞어 두어 걸림이 곧 전용인지 파라미터화인지가 갈립니다. 단계 정의에 나오는 오퍼레이터 중 일부는 일부러 넣지 않아 미매핑이 도출되게 둡니다.
| rule_no | signal_name | operator_raw | match_kind | pattern | blocking | owner_name |
|---|---|---|---|---|---|---|
| RR-1001 | 고객사 이름 하드코딩 | PythonOperator | regex | (gamecorp|medcenter|fincorp) | true | 솔루션 아키텍트 |
| RR-1002 | 계정 프로필 지정 | PythonOperator | literal | --profile | true | 플랫폼 |
| RR-1003 | 버킷 경로 고정 | PythonOperator | regex | s3://[a-z0-9-]+-prod | true | 플랫폼 |
| RR-1004 | 고객사 도메인 호출 | HttpOperator | regex | https://api\.[a-z]+\.co\.kr | true | 연동 담당 |
| RR-1005 | 테넌트 식별자 | HttpOperator | literal | tenant= | false | 연동 담당 |
아래 JSON Schema 를 그대로 만족하는 신호 사전 행을 30개 더 만들어 주세요. 차단 신호와 권장 신호를 섞고 찾을 방식을 두 값으로 고루 씁니다. 단계 정의에 나오는 오퍼레이터 중 일부는 일부러 넣지 마세요 — 미매핑이 있어야 사전의 구멍이 드러납니다.
{"type": "object", "properties": {"rule_no": {"type": "string"}, "signal_name": {"type": "string"}, "operator_raw": {"type": "string"}, "match_kind": {"type": "string", "enum": ["literal", "regex"]}, "pattern": {"type": "string"}, "blocking": {"type": "boolean"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "signal_name", "operator_raw", "match_kind", "pattern", "blocking"]}{"type": "object", "properties": {"rule_no": {"type": "string"}, "signal_name": {"type": "string"}, "operator_raw": {"type": "string"}, "match_kind": {"type": "string", "enum": ["literal", "regex"]}, "pattern": {"type": "string"}, "blocking": {"type": "boolean"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "signal_name", "operator_raw", "match_kind", "pattern", "blocking"]}| Python | 단계 본문에서 신호를 찾고 재사용 여부를 정하는 판정기를 맡습니다. |
| SQL | 본문이 쿼리인 단계에서 참조 테이블과 스키마 접두를 뽑아 신호와 맞춥니다. |
| Databricks | 단계 정의가 나오는 원천으로 가정합니다. 판정 자체는 플랫폼에 기대지 않습니다. |
| Markdown | 프로젝트별로 묶은 판정 리포트와 자산 후보 목록을 파일로 냅니다. |
✗ fail → 미매핑이 절반을 넘으면 사전을 먼저 채웁니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 유형을 모아 차단 신호의 경계를 다시 봅니다.
✓ pass → 3주차 자산 목록 조립으로 넘어갑니다.
단계 하나가 신호 사전과 만나는 자리마다 다시 쓸 수 있는지를 정합니다. 걸렸으면 어느 신호에 어느 대목이 걸렸는지 싣고, 본문이 비면 판정하지 않고 따로 뺍니다. 화면과 리포트는 이 사유 코드로 묶습니다.
{"type": "object", "properties": {"verdict_no": {"type": "string"}, "task_no": {"type": "string"}, "project_code": {"type": "string"}, "hit_rule_no": {"type": ["string", "null"]}, "signal_name": {"type": ["string", "null"]}, "reuse_code": {"type": "string", "enum": ["reusable", "needs_parameterize", "customer_specific", "duplicate_of_task", "body_missing", "operator_unmapped"]}, "twin_task_no": {"type": ["string", "null"]}, "blocking": {"type": ["boolean", "null"]}, "owner_name": {"type": ["string", "null"]}, "evidence": {"type": "array", "items": {"type": "object", "properties": {"field": {"type": "string"}, "agg": {"type": ["string", "null"]}, "value": {}}, "required": ["field", "value"]}}, "summary": {"type": "string"}, "hedge": {"type": ["string", "null"]}}, "required": ["verdict_no", "task_no", "reuse_code", "evidence", "summary"]}[
{
"verdict_no": "RV-001",
"task_no": "PT-1008",
"project_code": "MFG-C",
"hit_rule_no": null,
"signal_name": null,
"reuse_code": "reusable",
"twin_task_no": null,
"blocking": null,
"owner_name": null,
"evidence": [
{
"field": "body_text",
"agg": null,
"value": "df.set_index('ts').resample('1H').mean()"
},
{
"field": "rule_no",
"agg": "count",
"value": 0
}
],
"summary": "본문에서 고객 고유 신호가 하나도 걸리지 않아 그대로 다시 쓸 수 있습니다.",
"hedge": null
},
{
"verdict_no": "RV-002",
"task_no": "PT-1005",
"project_code": "MED-B",
"hit_rule_no": null,
"signal_name": null,
"reuse_code": "reusable",
"twin_task_no": null,
"blocking": null,
"owner_name": null,
"evidence": [
{
"field": "body_text",
"agg": null,
"value": "SELECT dept, upper(trim(dept)) AS dept_code FROM raw.visits"
},
{
"field": "task_name_raw",
"agg": null,
"value": "normalize_dept_code"
}
],
"summary": "부서 표기를 접는 단계라 고객 고유 신호가 없어 그대로 다시 쓸 수 있습니다.",
"hedge": "스키마 접두 raw 는 차단 신호가 아니라 옮길 때 이름만 바꾸면 됩니다."
},
{
"verdict_no": "RV-003",
"task_no": "PT-1007",
"project_code": "MFG-C",
"hit_rule_no": "RR-1008",
"signal_name": "인코딩 고정",
"reuse_code": "needs_parameterize",
"twin_task_no": null,
"blocking": false,
"owner_name": "데이터 엔지니어",
"evidence": [
{
"field": "body_text",
"agg": null,
"value": "pd.read_csv(path, encoding='cp949', names=SENSOR_COLS)"
},
{
"field": "pattern",
"agg": null,
"value": "encoding='cp949'"
}
],
"summary": "인코딩이 cp949 로 박혀 있어 값을 밖으로 빼면 다시 쓸 수 있습니다.",
"hedge": null
},
{
"verdict_no": "RV-004",
"task_no": "PT-1003",
"project_code": "GAME-A",
"hit_rule_no": "RR-1002",
"signal_name": "계정 프로필 지정",
"reuse_code": "customer_specific",
"twin_task_no": null,
"blocking": true,
"owner_name": "플랫폼",
"evidence": [
{
"field": "body_text",
"agg": null,
"value": "aws s3 cp out/ s3://gamecorp-prod-dw/daily/ --profile gamecorp-fde"
},
{
"field": "rule_no",
"agg": "count",
"value": 3
}
],
"summary": "고객사 이름과 계정 프로필, 운영 버킷 경로가 함께 박혀 있어 이 프로젝트 밖으로 옮기지 못합니다.",
"hedge": null
},
{
"verdict_no": "RV-005",
"task_no": "PT-1004",
"project_code": "MED-B",
"hit_rule_no": null,
"signal_name": null,
"reuse_code": "duplicate_of_task",
"twin_task_no": "PT-1001",
"blocking": null,
"owner_name": null,
"evidence": [
{
"field": "task_name_raw",
"agg": null,
"value": "load_orders_daily"
},
{
"field": "task_no",
"agg": "count",
"value": 3
}
],
"summary": "같은 이름과 같은 본문의 단계가 세 프로젝트에 있어 한 벌로 묶습니다.",
"hedge": "이름이 같아도 뒤에 붙는 단계가 달라 묶기 전에 하류 단계를 함께 봅니다."
},
{
"verdict_no": "RV-006",
"task_no": "PT-1011",
"project_code": "FIN-D",
"hit_rule_no": null,
"signal_name": null,
"reuse_code": "body_missing",
"twin_task_no": null,
"blocking": null,
"owner_name": null,
"evidence": [
{
"field": "body_text",
"agg": null,
"value": null
},
{
"field": "dataset_name",
"agg": null,
"value": null
}
],
"summary": "본문이 비어 있어 무엇을 하는 단계인지 읽을 수 없으므로 원본을 다시 받습니다.",
"hedge": null
},
{
"verdict_no": "RV-007",
"task_no": "PT-1009",
"project_code": "MFG-C",
"hit_rule_no": null,
"signal_name": null,
"reuse_code": "operator_unmapped",
"twin_task_no": null,
"blocking": null,
"owner_name": null,
"evidence": [
{
"field": "operator_raw",
"agg": null,
"value": "SparkSubmitOperator"
},
{
"field": "rule_no",
"agg": "count",
"value": 12
}
],
"summary": "신호 사전 열두 행에 이 오퍼레이터가 없어 미매핑으로 남기고 규칙을 먼저 채웁니다.",
"hedge": null
}
][자동 검증 · 코드가 판정합니다] 1. reuse_code 가 enum 여섯 값 중 하나인지 확인합니다. 2. verdict_no·task_no·reuse_code·evidence·summary 가 모두 채워졌는지 확인합니다. 3. task_no 가 단계 정의에 실재하는 번호인지 대조합니다. 4. hit_rule_no 가 있으면 신호 사전에 실재하는 행 번호인지 대조합니다. 5. hit_rule_no 가 있으면 signal_name·blocking·owner_name 이 그 사전 행의 값과 같은지 대조합니다. 6. reuse_code 가 customer_specific 이면 차단 신호가 본문에 실제로 걸리는지 패턴을 다시 돌려 확인합니다. 7. reuse_code 가 needs_parameterize 이면 걸린 신호가 모두 권장 신호인지 다시 확인합니다. 8. reuse_code 가 reusable 이면 어느 신호도 걸리지 않는지 패턴을 전부 다시 돌립니다. 9. body_text 가 비어 있으면 reuse_code 가 body_missing 인지 확인합니다. 10. operator_raw 를 공백·기호를 지워 접은 뒤 사전의 오퍼레이터와 맞고, 맞는 행이 없으면 reuse_code 가 operator_unmapped 인지 확인합니다. 11. reuse_code 가 duplicate_of_task 이면 twin_task_no 의 단계와 이름·본문이 같은지 대조합니다. 12. evidence 의 field 이름이 단계 정의와 신호 사전에 실재하는 컬럼인지 대조합니다. 13. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 14. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 공개 예제에서 고쳐 만든 단계 80건에 손으로 붙인 정답 판정과 대조해 일치율과 사유 코드별 분포를 내고, 미매핑이 몰리는 오퍼레이터를 모아 사전에 없는 구간을 목록으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 차단 신호와 권장 신호를 어디서 가를지 담당자가 정합니다. 2. 중복으로 묶인 단계에서 어느 쪽을 대표로 남길지 담당자가 하류 단계를 보고 정합니다.
근거: 위 과정에서 만들어진 아키텍처와 파이프라인을 재사용 가능한 형태로 정리하여