취업·면접 · 실무
개발자 실무 면접 - 질문의 의도와 모범 답안
면접은 무엇을 확인하는가 - 평가 기준과 준비 지도
서류·코딩 테스트·기술·인성·최종 면접 단계별로 면접관이 확인하는 것, 직무 기술서 읽고 예상 질문 뽑기, 답변 구조(결론→근거→경험→한계), 모르는 질문에 답하는 법, 준비 일정표, 완성 코드는 직무 기술서 문장에서 키워드를 뽑아 예상 질문 목록과 준비 점검표를 출력한다
개발자KR · 원고 갱신
이 장에서 배우는 것
가상의 중고 거래 서비스 팀에 지원한 지원자는 상품 등록과 검색 기능을 만든 경험이 있다. 그런데 면접 준비를 시작하자 공부할 항목이 끝없이 늘어난다. 자료구조를 다시 읽다가 프로젝트 설명이 걱정되고, 프로젝트를 정리하다가 모르는 질문을 받을 상황이 떠오른다. 필요한 것은 모든 내용을 같은 깊이로 공부하는 일이 아니라, 지원한 역할이 요구하는 것과 자신이 보여 줄 수 있는 근거를 연결하는 일이다.
이 장에서는 면접을 정답을 많이 맞히는 시험으로만 보지 않고, 함께 일할 때의 판단과 행동을 확인하는 과정으로 살펴본다. 직무 기술서(Job Description)의 문장을 준비 항목으로 바꾸고, 답변에 근거와 한계를 붙이는 방법을 익힌다. 마지막에는 Python 프로그램으로 이 준비 과정을 작게 재현한다.
- 서류부터 최종 면접까지 각 단계에서 확인할 수 있는 근거를 구분한다.
- 직무 기술서에서 요구사항을 찾아 예상 질문과 준비 항목으로 바꾼다.
- 결론, 근거, 경험, 한계의 순서로 답변을 구성한다.
- 모르는 질문에서 아는 범위와 확인할 부분을 구분해 말한다.
- 준비 일정과 점검표를 만들어 준비 누락을 확인한다.
문제 상황
지원자는 중고 거래 과제 프로젝트의 서버 개발을 담당했다. 지원하려는 팀의 채용 안내에는 Python 웹 개발, 데이터베이스 활용, 테스트 작성, 팀 협업이 적혀 있다. 지원자는 해당 단어를 모두 공부 목록에 넣었지만, 면접 연습에서 “그 경험으로 무엇을 확인했나요?”라는 질문을 받자 설명을 이어 가지 못한다.
문제는 경험이 부족하다는 사실 하나로 정리되지 않는다. 구현한 기능, 그때 내린 판단, 판단을 뒷받침하는 자료가 서로 연결되어 있지 않다. “검색을 만들었다”는 기능 설명이고, “검색 결과가 기대와 같은지 입력 사례를 나누어 확인했다”는 검증 행동이다. 면접관은 기능 이름을 출발점으로 삼아 지원자가 어디까지 직접 이해하고 수행했는지 확인할 수 있다.
이 장의 작은 실험은 채용 안내 문장을 입력으로 받아 예상 질문을 출력한다. 준비 근거가 등록된 항목과 아직 없는 항목도 함께 표시한다. 프로그램이 면접을 예측하거나 합격 가능성을 계산하는 것은 아니다. 사람이 하던 준비 과정을 명시적인 규칙으로 바꾸어, 무엇을 찾았고 무엇을 놓쳤는지 살펴보는 실험이다.
면접 단계마다 확인하는 근거가 다르다
면접관은 지원자의 머릿속을 직접 볼 수 없다. 서류의 문장, 문제를 푸는 과정, 설명의 구체성, 협업 사례처럼 관찰할 수 있는 자료를 통해 판단한다. 따라서 “성실하다”는 자기평가보다 일정이 밀렸을 때 어떤 정보를 공유하고 어떤 행동을 바꾸었는지 설명하는 편이 평가 근거를 제공한다.
다음 표는 이 책의 가상 채용 과정에 적용한 준비 지도다. 실제 채용에서는 단계가 합쳐지거나 순서가 달라질 수 있다. 같은 단계라도 지원 직무에 따라 질문의 비중이 달라지므로, 지원 공고에 적힌 전형 안내를 먼저 읽는다.
| 단계 | 확인하려는 것 | 준비할 근거 | 주의할 점 |
|---|---|---|---|
| 서류 | 지원 역할과 경험의 연결 | 담당 범위, 구현 결과, 확인 방법 | 팀 전체 성과와 개인 기여를 구분한다. |
| 코딩 테스트 | 문제를 해석하고 제약 안에서 해결하는 과정 | 접근 이유, 경계 사례, 실행 비용 설명 | 통과 여부 외에 선택 이유도 복기한다. |
| 기술 면접 | 개념 이해와 구현 판단의 근거 | 직접 작성한 부분, 비교한 대안, 검증 자료 | 용어를 나열한 뒤 설명을 멈추지 않는다. |
| 인성 면접 | 함께 일할 때 반복될 행동 | 정보 공유, 의견 조정, 피드백 이후의 변화 | 성격 평가 대신 실제 행동을 말한다. |
| 최종 면접 | 역할 기대와 일하는 조건의 접점 | 기여 가능한 범위, 학습 과제, 확인할 조건 | 기술 질문이 다시 나올 가능성도 고려한다. |
예를 들어 기술 면접에서 답을 수정하는 행동은 이해도를 보여 줄 수 있다. 처음부터 맞혔는지만 확인하는 것이 아니라, 새로운 조건을 듣고 자신의 판단을 조정할 수 있는지도 살펴볼 수 있기 때문이다. 다만 평가 의도를 미리 단정해서는 안 된다. 아래 질문 표의 의도는 준비를 돕는 가설이며, 실제 대화에서는 질문의 범위와 조건을 듣고 조정한다.
이 장의 면접 질문 지도
| 질문 | 의도 | 답변 핵심 | 꼬리 질문 |
|---|---|---|---|
| 이번 면접에서 무엇을 보여 주려 하나요? | 역할과 경험을 연결하는지 확인 | 직무 요구와 직접 수행한 근거를 연결한다. | 그 근거를 어디서 확인할 수 있나요? |
| 직무 기술서를 어떻게 읽었나요? | 요구사항 해석 방식 확인 | 필수·우대를 구분하고 행동 단위로 바꾼다. | 어떤 항목을 먼저 준비했나요? |
| 코딩 테스트 뒤에는 무엇을 복기하나요? | 결과에서 학습하는 방식 확인 | 오독, 접근, 구현, 검증의 문제를 나눈다. | 시간이 부족했다면 무엇을 바꾸나요? |
| 경험이 적은 기술을 요구하면 어떻게 하나요? | 경험 범위와 학습 판단 확인 | 직접 경험과 유사 경험을 구분한다. | 언제까지 무엇을 확인할 수 있나요? |
| 그 선택이 적절했다고 보는 근거는 무엇인가요? | 주장과 증거의 연결 확인 | 조건, 관찰 자료, 대안을 설명한다. | 다른 조건에서도 같을까요? |
| 모르는 질문을 받으면 어떻게 하나요? | 불확실성을 다루는 태도 확인 | 모르는 범위와 추론의 전제를 밝힌다. | 추론이 틀렸는지 어떻게 확인하나요? |
| 팀 과제에서 본인이 한 일은 무엇인가요? | 개인 기여 범위 확인 | 작성, 검토, 공동 결정의 범위를 나눈다. | 직접 결정하지 않은 부분은 무엇인가요? |
| 피드백으로 준비 방식을 바꾼 적이 있나요? | 피드백 이후 행동 변화 확인 | 받은 의견과 수정한 행동을 연결한다. | 변화가 있었는지 어떻게 알았나요? |
| 남은 기간을 어떻게 사용하겠나요? | 우선순위와 실행 가능성 확인 | 중요도와 근거의 빈틈으로 순서를 정한다. | 일정이 밀리면 무엇을 줄이나요? |
| 최종 면접에서도 기술 준비가 필요한가요? | 전형을 단순화하지 않는지 확인 | 역할 기대와 기존 설명의 일관성을 준비한다. | 이전 답변의 오류를 발견하면 어떻게 하나요? |
직무 기술서를 질문과 준비 일정으로 바꾼다
직무 기술서를 읽을 때 기술 이름에만 밑줄을 그으면 공부 목록이 넓어진다. 먼저 문장을 “무엇을 사용하는가”, “무슨 일을 하는가”, “어떤 수준을 요구하는가”로 나눈다. “Python 사용 경험”과 “Python으로 서비스를 운영한 경험”은 같은 기술 이름을 포함하지만 준비할 근거의 범위는 다르다.
필수 요건과 우대 사항은 원문에 표시된 구분을 따른다. 표시가 없다면 기술 이름만 보고 필수라고 판단하지 않는다. 또한 “테스트를 작성하고 결과를 공유한다”라는 문장은 작성 능력과 결과 전달이라는 두 행동을 포함한다. 예상 질문도 “테스트가 무엇인가요?”에서 끝내지 않고 “어떤 사례를 골랐으며 결과를 어떻게 설명했나요?”로 바꿀 수 있다.
예상 질문마다 증거 하나를 붙인다. 증거는 공개 가능한 코드 위치, 직접 작성한 점검 기록, 과제 회고처럼 다시 확인할 수 있는 자료다. 자료가 있다는 사실만으로 답변 준비가 끝나지는 않는다. 그 자료에서 자신의 행동과 판단을 설명할 수 있어야 한다. 팀 자료를 사용할 때는 공유 가능한 범위를 지키고, 자신의 기여를 별도로 표시한다.
깊게 보기: 직무 기술서를 어떻게 읽었나요?
| 수준 | 답변 | 면접관이 이어서 확인할 점 |
|---|---|---|
| 나쁜 답 | 적힌 기술을 모두 사용할 수 있어서 지원했다. | 경험 범위가 과장되었는지 확인하게 된다. |
| 보통 답 | Python과 데이터베이스가 중요하다고 보고 관련 내용을 공부했다. | 어떤 요구를 어떤 경험으로 설명할지 남아 있다. |
| 좋은 답 | 필수 항목의 행동을 먼저 정리하고, 각 행동에 직접 수행한 근거를 붙였다. | 문장 해석과 근거의 실제 내용을 확인할 수 있다. |
필수 항목의 행동을 제가 수행한 경험과 연결해 읽었다. 같은 기술 이름이라도 구현과 운영은 요구하는 경험이 다르기 때문이다. 이번 공고의 테스트 작성 요구에는 상품 등록 입력을 나누어 점검한 기록을 연결했다. 운영 경험은 과제 실행 범위에 그쳐 별도로 표시했다. 표시가 불분명한 요구는 임의로 필수라고 정하지 않고 면접에서 기대 범위를 확인하겠다.
이 답변은 결론을 먼저 말하고, 그 분류가 필요한 이유와 자신의 사례를 붙인다. 마지막에는 경험의 한계와 확인할 대안을 제시한다. “운영 경험이 부족하면 지원 요건을 충족하지 못한 것 아닌가요?”라는 꼬리 질문에는 공고의 필수 조건을 다시 기준으로 삼는다. 필수 경험을 충족하지 못했다면 그 사실을 인정해야 하며, 짧은 학습으로 같은 경험을 쌓았다고 주장해서는 안 된다.
면접관 반응: 공고에서 테스트 작성이라는 표현을 보고 어떤 자료를 준비했는지 구체적으로 설명해 달라.
깊게 보기: 남은 기간을 어떻게 사용하겠나요?
준비 순서는 공고에서의 중요도와 현재 근거의 빈틈을 함께 보고 정한다. 이미 설명할 수 있는 항목을 계속 읽는 동안 필수 요구의 빈 항목이 남을 수 있다. 반대로 낯선 기술이라는 이유만으로 우대 사항에 시간을 몰아주면, 직접 수행한 프로젝트의 설명이 부족해질 수 있다.
다음은 하루에 집중할 수 있는 시간이 약 두 시간인 지원자의 일주일 예시다. 실제 일정에는 확보 가능한 시간을 먼저 적는다. “데이터베이스 공부”처럼 끝을 알 수 없는 항목보다, 준비가 끝났는지 확인할 수 있는 결과물을 정한다.
| 시점 | 할 일 | 완료 기준 | 밀렸을 때의 조정 |
|---|---|---|---|
| 첫째 날 | 공고 문장과 경험 연결 | 필수·우대 구분과 근거 없는 항목 목록 | 필수 항목부터 정리한다. |
| 둘째 날 | 개인 기여 확인 | 직접 작성한 부분과 공동 작업 구분 | 대표 경험 두 개를 먼저 확인한다. |
| 셋째 날 | 기술 설명 연습 | 핵심 질문 세 개를 근거와 함께 설명 | 용어 범위보다 근거의 정확성을 우선한다. |
| 넷째 날 | 문제 풀이 복기 | 오답 원인과 수정 행동 한 쌍씩 기록 | 대표적인 실패 사례부터 복기한다. |
| 다섯째 날 | 협업 사례 정리 | 상황, 자신의 행동, 이후 변화 확인 | 확인 가능한 사례 하나를 정리한다. |
| 여섯째 날 | 질문을 섞어 답변 연습 | 근거 없는 주장과 장황한 부분 표시 | 녹음 한 차례와 수정에 집중한다. |
| 일곱째 날 | 설명과 자료 대조 | 오류 수정, 준비 누락, 확인할 조건 정리 | 새 항목 추가를 줄이고 기존 답을 검토한다. |
나쁜 답은 “잠을 줄여서 전부 공부하겠다”다. 보통 답은 “부족한 부분부터 공부하겠다”다. 좋은 답은 부족함을 판단하는 기준과 줄일 작업까지 말한다.
남은 기간에는 필수 요구 중 설명 근거가 없는 항목을 먼저 준비하겠다. 준비 시간이 제한되어 있으므로 중요도와 빈틈을 함께 봐야 하기 때문이다. 현재는 테스트를 작성한 기록은 있지만 사례를 고른 이유가 정리되지 않아, 그 판단을 먼저 복기하겠다. 일주일 안에 새로운 운영 경험까지 확보하기는 어렵다. 그 부분은 미경험으로 밝히고, 확인할 개념과 학습 결과를 구분해 준비하겠다.
“계획이 하루 밀리면 무엇을 줄이나요?”에는 공고에서 비중이 낮은 추가 학습을 줄이되, 답변과 실제 자료를 대조하는 검토는 남긴다고 답할 수 있다. 자신의 설명에 오류가 있는 상태에서 새로운 항목만 늘리지 않겠다는 판단이다.
답변은 결론에서 시작하고 한계까지 닫는다
답변 구조는 결론, 근거, 경험, 한계의 순서로 잡는다. 결론은 질문에 대한 직접적인 답이다. 근거는 왜 그렇게 판단했는지 설명하고, 경험은 그 판단이 자신의 행동과 연결되는 지점을 보여 준다. 한계에서는 적용 조건, 직접 확인하지 못한 범위, 다른 선택을 고려할 상황을 말한다.
네 요소를 모든 답변에 같은 길이로 넣을 필요는 없다. 짧은 사실 확인에는 직접 답한 뒤 멈추고, 선택 이유나 경험을 묻는 질문에는 구조를 넓힌다. 첫 답변에 모든 세부 사항을 넣기보다 핵심 근거를 제시하고 꼬리 질문에서 필요한 부분을 확장한다.
깊게 보기: 그 선택이 적절했다고 보는 근거는 무엇인가요?
나쁜 답은 “보통 그렇게 하니까 적절하다”다. 보통 답은 “직접 해 보니 잘 동작했다”다. 좋은 답은 어떤 조건에서 무엇을 확인했는지 말하고, 그 확인으로 주장할 수 있는 범위를 제한한다.
과제에서 정한 입력 범위에 대해서는 그 선택이 적절했다고 판단했다. 상품 등록의 필수 입력이 빠진 경우와 정상 입력을 나누어 기대 결과와 비교했기 때문이다. 제가 맡은 부분에서는 각 입력과 결과를 점검 기록으로 남겼고, 수정한 뒤 같은 사례를 다시 확인했다. 다만 이 확인만으로 많은 사용자가 동시에 쓰는 상황까지 검증했다고 말할 수는 없다. 그런 조건이 요구되면 별도 검증과 대안 비교가 필요하다.
“그렇다면 적절하다는 표현이 너무 넓지 않나요?”라는 꼬리 질문에는 문장의 범위를 수정한다. “맞다. 서비스 전체에 적절하다고 표현하기보다, 과제의 기능 요구와 확인한 입력 범위를 충족했다고 말하겠다”처럼 답할 수 있다. 처음 표현을 지키기 위해 근거 없는 설명을 덧붙이지 않는다.
면접 연습에서는 결론과 증거 사이를 살펴본다. 증거가 기능 동작만 보여 주는데 결론이 성능이나 안정성까지 포함하면 주장의 범위가 넓다. 이 간격을 줄이는 것이 표현을 유창하게 만드는 일보다 먼저다.
깊게 보기: 모르는 질문을 받으면 어떻게 하나요?
모른다는 말 이후에는 질문에 따라 할 수 있는 행동이 달라진다. 특정 명칭이나 정확한 규칙을 모르면 확인이 필요하다고 밝힌다. 설계 판단을 묻는 질문이라면 조건을 확인하고, 알고 있는 원리에서 출발해 가정을 붙여 추론할 수 있다. 사실을 기억하지 못하는 상황과 조건을 바탕으로 판단하는 상황을 구분한다.
| 수준 | 답변 | 남는 문제 또는 장점 |
|---|---|---|
| 나쁜 답 | 이름을 들어 봤으므로 사용할 수 있다고 생각한다. | 인지 여부를 사용 경험으로 확대한다. |
| 보통 답 | 잘 모르겠다. 공부하겠다. | 정직하지만 아는 범위와 확인 방법이 드러나지 않는다. |
| 좋은 답 | 직접 사용한 경험은 없다. 관련 원리는 여기까지 알고 있으며, 이 조건을 가정하면 이렇게 추론할 수 있다. | 사실, 경험, 추론을 구분해 검토할 수 있다. |
그 도구를 직접 사용한 경험은 없어 구체적인 동작을 단정하기 어렵다. 제가 아는 범위는 요청을 여러 작업으로 나누면 완료 순서가 달라질 수 있다는 점이다. 과제에서는 순차 처리만 구현했으므로 이 경험을 해당 도구의 사용 경험으로 설명할 수는 없다. 완료 순서가 중요하다는 조건이라면 순서를 보장하는 방식부터 확인하겠다. 정확한 보장 범위는 문서와 작은 실행 예제로 검증해야 한다.
“지금 확인할 수 없다면 어떻게 답하겠나요?”라는 꼬리 질문에는 가정을 붙여 답하거나 판단을 유보한다. 예를 들어 “순서를 보장하지 않는다고 가정하면 결과를 입력과 다시 연결하는 장치가 필요하다고 생각한다. 다만 실제 제공 기능은 확인이 필요하다”라고 말할 수 있다. 추론을 요구받았다는 이유로 확인하지 않은 제품 기능까지 만들어 말하지 않는다.
질문을 다시 묻는 것도 방법이지만, 자신이 아는 주제로 바꾸기 위한 질문은 피한다. “정확한 내부 동작을 묻는 것인지, 사용 시 고려할 조건을 묻는 것인지 확인하고 싶다”처럼 답변 범위를 분명히 하는 데 사용한다.
완성 코드
아래 프로그램은 공고의 세 문장에서 다섯 가지 주제를 찾는다. 영문 키워드는 대소문자를 구분하지 않으며, 같은 주제가 반복되어도 한 번만 출력한다. 키워드가 하나도 연결되지 않은 문장은 수동 검토 대상으로 남긴다. 준비 근거가 등록된 주제도 검토 대상이며, 근거가 있다는 이유만으로 답변 준비가 끝났다고 표시하지 않는다.
입력은 코드 안에 고정되어 있고 외부 파일, 현재 시각, 난수를 사용하지 않는다. 규칙의 순서대로 출력하므로 실행 결과도 일정하다. 다음 내용을 main.py로 저장한다.
import re
from dataclasses import dataclass
@dataclass(frozen=True)
class Rule:
topic: str
keywords: tuple[str, ...]
question: str
task: str
RULES = (
Rule(
"Python",
("python",),
"직접 작성한 Python 코드의 판단 근거는 무엇인가?",
"담당 코드와 선택 이유를 연결한다.",
),
Rule(
"데이터베이스",
("데이터베이스", "sql"),
"데이터 저장 작업에서 직접 확인한 범위는 어디까지인가?",
"확인한 자료와 미확인 범위를 구분한다.",
),
Rule(
"테스트",
("테스트", "test"),
"테스트 사례를 고른 이유를 설명할 수 있는가?",
"입력 사례와 기대 결과를 정리한다.",
),
Rule(
"협업",
("협업", "코드 리뷰"),
"다른 사람의 의견으로 작업을 바꾼 근거는 무엇인가?",
"의견과 변경 행동을 연결한다.",
),
Rule(
"운영",
("운영", "배포"),
"직접 수행한 운영 작업과 미경험 영역은 무엇인가?",
"직접 수행한 범위와 학습 과제를 나눈다.",
),
)
JOB_SENTENCES = (
"필수: Python으로 기능을 만들고 SQL로 데이터를 다룬다.",
"필수: 테스트를 작성하고 코드 리뷰로 협업한다.",
"우대: 사용자의 불편을 관찰해 개선한다.",
)
EVIDENCE = {
"Python": "상품 등록 코드의 담당 범위 메모",
"테스트": "입력 사례별 기대 결과 기록",
}
def contains_keyword(sentence: str, keyword: str) -> bool:
text = sentence.casefold()
word = keyword.casefold()
if word.isascii() and word.isalpha():
pattern = rf"(?<![a-z0-9_]){re.escape(word)}(?![a-z0-9_])"
return re.search(pattern, text) is not None
return word in text
def collect_topics(
sentences: tuple[str, ...],
) -> tuple[dict[str, list[int]], list[int]]:
sources: dict[str, list[int]] = {}
unmatched: list[int] = []
for number, sentence in enumerate(sentences, start=1):
matched = False
for rule in RULES:
if any(
contains_keyword(sentence, keyword)
for keyword in rule.keywords
):
sources.setdefault(rule.topic, []).append(number)
matched = True
if not matched:
unmatched.append(number)
return sources, unmatched
def main() -> None:
sources, unmatched = collect_topics(JOB_SENTENCES)
selected = tuple(rule for rule in RULES if rule.topic in sources)
print("직무 기술서 준비 지도")
print(
f"입력 문장: {len(JOB_SENTENCES)}개 / "
f"찾은 주제: {len(selected)}개"
)
print("\n[예상 질문]")
for number, rule in enumerate(selected, start=1):
source = ", ".join(str(value) for value in sources[rule.topic])
print(f"{number}. {rule.topic} | 문장 {source} | {rule.question}")
print("\n[준비 점검표]")
missing = 0
for rule in selected:
evidence = EVIDENCE.get(rule.topic)
if evidence:
print(f"- {rule.topic}: 근거 검토 | {evidence}")
else:
missing += 1
print(f"- {rule.topic}: 근거 보완 | {rule.task}")
print("\n[수동 검토]")
for number in unmatched:
print(f"- 문장 {number}: {JOB_SENTENCES[number - 1]}")
if not unmatched:
print("- 연결되지 않은 문장 없음")
print(f"\n근거 보완: {missing}개 / 수동 검토 문장: {len(unmatched)}개")
print("주의: 키워드 연결은 요구 수준이나 준비 완료를 판정하지 않는다.")
if __name__ == "__main__":
main()
줄별 해설
처음 두 줄은 문자열 검색에 사용할 re와 규칙을 묶을 dataclass를 가져온다. 외부 패키지를 설치할 필요는 없다. Rule은 주제, 키워드 묶음, 예상 질문, 준비 행동을 한데 보관한다. frozen=True는 만든 규칙의 필드를 실수로 다시 대입하지 못하게 한다.
RULES의 각 항목은 키워드를 면접 준비 행동으로 바꾸는 작은 규칙이다. 예를 들어 SQL이라는 단어를 찾으면 데이터베이스 주제로 묶고, 직접 확인한 범위를 설명하는 질문을 만든다. 기술 개념의 정답을 출력하는 대신 경험의 범위를 확인하게 한 이유는 이 장의 목적이 준비 지도 작성이기 때문이다.
JOB_SENTENCES는 실험에 사용할 공고 문장이다. 필수와 우대라는 표현을 포함하지만, 프로그램은 그 구분을 해석하지 않는다. EVIDENCE는 주제에 연결한 자료의 이름이다. 자료 이름은 자료의 내용이나 품질을 보증하지 않으므로 출력에서도 “근거 검토”라고 표시한다.
contains_keyword는 먼저 casefold로 비교용 문자열을 만든다. 영문 알파벳 키워드는 앞뒤에 영문자, 숫자, 밑줄이 없는지 확인한다. 이에 따라 contest에 들어 있는 test를 테스트 주제로 잘못 연결하는 사례를 줄인다. 한국어는 조사와 붙는 경우를 처리하려고 부분 문자열로 찾는다. 따라서 이 함수는 언어의 의미를 이해하는 분석기가 아니다.
collect_topics는 문장을 1번부터 순회한다. 한 규칙의 여러 키워드가 같은 문장에 등장해도 any의 결과는 하나이므로 해당 문장 번호를 한 번만 붙인다. sources에는 주제별 근거 문장 번호가 들어가고, unmatched에는 규칙이 연결되지 않은 문장 번호가 들어간다. 원문을 다시 살펴볼 연결 고리를 남기는 셈이다.
main의 selected는 RULES를 순회해 만든다. 공고에 등장한 순서가 바뀌어도 주제 출력은 규칙 순서를 따른다. 예상 질문에는 원문 번호를 붙이고, 준비 점검표에서는 근거 등록 여부에 따라 검토와 보완을 나눈다. missing은 자료가 등록되지 않은 주제 수이며, 모르는 개념의 수나 불합격 위험을 뜻하지 않는다.
마지막 조건문은 파일을 직접 실행했을 때 main을 호출한다. 함수 정의만 두고 호출하지 않아 출력이 없는 실수를 막는다. 전체 프로그램의 흐름은 문장 읽기, 규칙 연결, 근거 대조, 미연결 문장 출력으로 이어진다.
실행 결과
macOS 또는 Linux에서 파일을 저장한 디렉터리로 이동한 뒤 실행한다. Python 3.12 이상에서 다음 명령을 사용한다.
python3 main.py
예상 출력은 다음과 같다.
직무 기술서 준비 지도
입력 문장: 3개 / 찾은 주제: 4개
[예상 질문]
1. Python | 문장 1 | 직접 작성한 Python 코드의 판단 근거는 무엇인가?
2. 데이터베이스 | 문장 1 | 데이터 저장 작업에서 직접 확인한 범위는 어디까지인가?
3. 테스트 | 문장 2 | 테스트 사례를 고른 이유를 설명할 수 있는가?
4. 협업 | 문장 2 | 다른 사람의 의견으로 작업을 바꾼 근거는 무엇인가?
[준비 점검표]
- Python: 근거 검토 | 상품 등록 코드의 담당 범위 메모
- 데이터베이스: 근거 보완 | 확인한 자료와 미확인 범위를 구분한다.
- 테스트: 근거 검토 | 입력 사례별 기대 결과 기록
- 협업: 근거 보완 | 의견과 변경 행동을 연결한다.
[수동 검토]
- 문장 3: 우대: 사용자의 불편을 관찰해 개선한다.
근거 보완: 2개 / 수동 검토 문장: 1개
주의: 키워드 연결은 요구 수준이나 준비 완료를 판정하지 않는다.
첫째 문장에서는 Python과 SQL이 각각 다른 주제에 연결된다. 둘째 문장의 코드 리뷰와 협업은 같은 규칙에 속하므로 협업 질문 하나만 나온다. 셋째 문장은 등록된 키워드가 없어 수동 검토 대상으로 남는다. 사용자 관찰이라는 요구가 중요하지 않아서 빠진 것이 아니라, 현재 규칙이 찾지 못했기 때문이다.
이 결과를 보고 지원자는 데이터베이스와 협업의 근거를 보완하고, 셋째 문장을 직접 읽어 새 준비 항목이 필요한지 판단한다. 네 주제를 찾았다는 결과를 공고 전체를 이해했다는 결론으로 확대하지 않는 것이 실험의 핵심이다.
실무에서 자주 틀리는 것
영문 키워드의 일부만 맞아도 연결한다
다음 코드는 contest를 테스트와 관련된 단어로 판단한다. 준비 목록에 잘못 들어온 항목이 늘면 우선순위를 정하기 어려워진다.
sentence = "contest 경험을 설명한다."
matched = "test" in sentence.casefold()
print(matched)
완성 코드의 함수를 사용하면 영문 키워드의 앞뒤 경계를 확인할 수 있다. 앞 코드는 True를, 고친 코드는 False를 출력한다.
sentence = "contest 경험을 설명한다."
matched = contains_keyword(sentence, "test")
print(matched)
이 수정도 모든 표기를 처리하지는 못한다. pytest처럼 관련성이 있지만 규칙에 없는 표현은 별도 키워드로 등록해야 한다. 부분 일치를 줄이는 일과 관련 표현을 넓게 찾는 일 사이에는 조정이 필요하다.
같은 주제를 여러 번 출력한다
키워드를 찾을 때마다 질문을 붙이면 코드 리뷰와 협업이 한 문장에 있다는 이유로 같은 질문을 반복할 수 있다.
questions = []
sentence = "코드 리뷰로 협업한다."
for rule in RULES:
for keyword in rule.keywords:
if contains_keyword(sentence, keyword):
questions.append(rule.question)
고친 코드는 규칙별로 한 번만 추가한다. 문장 여러 개를 합칠 때의 중복은 완성 코드처럼 주제를 키로 묶어 처리한다.
questions = []
sentence = "코드 리뷰로 협업한다."
for rule in RULES:
if any(contains_keyword(sentence, word) for word in rule.keywords):
questions.append(rule.question)
자료가 있으면 답변도 준비되었다고 본다
파일을 만들었다는 사실과 그 내용을 설명할 수 있다는 사실은 다르다. 이름만 등록해 두고 완료로 표시하면 빈틈이 가려진다.
topic = "테스트"
status = "준비 완료" if EVIDENCE.get(topic) else "준비 필요"
상태 표현을 바꾸면 다음 행동이 남는다. 검토할 때는 자료가 자신의 기여와 판단을 실제로 보여 주는지 확인한다.
topic = "테스트"
status = "근거 검토" if EVIDENCE.get(topic) else "근거 보완"
키워드를 못 찾은 문장을 버린다
규칙에 없는 문장을 제거하면 도구가 놓친 요구를 사람이 검토할 기회도 사라진다. 특히 한 문장 안에서 일부 키워드만 잡힌 경우에는 문장의 나머지 의미가 가려질 수 있다.
sources, unmatched = collect_topics(JOB_SENTENCES)
print("찾은 주제:", len(sources))
고친 코드는 연결되지 않은 문장도 보여 준다. 다만 미연결 목록이 비었다고 원문 검토를 생략해서는 안 된다. 일부만 연결된 문장은 이 목록에 나타나지 않기 때문이다.
sources, unmatched = collect_topics(JOB_SENTENCES)
print("찾은 주제:", len(sources))
for number in unmatched:
print(number, JOB_SENTENCES[number - 1])
한눈에 보기
| 준비 대상 | 할 일 | 확인 기준 | 남겨 둘 한계 |
|---|---|---|---|
| 전형 단계 | 단계별로 필요한 근거를 연결한다. | 주장마다 확인 가능한 행동이 있다. | 같은 단계명이라도 평가 범위가 다를 수 있다. |
| 직무 기술서 | 기술 이름을 요구 행동으로 바꾼다. | 예상 질문을 원문으로 되돌려 볼 수 있다. | 키워드만으로 필수 여부를 정하지 않는다. |
| 답변 | 결론, 근거, 경험, 한계를 연결한다. | 근거가 결론의 범위를 뒷받침한다. | 확인하지 않은 조건으로 확대하지 않는다. |
| 모르는 질문 | 사실, 경험, 가정에 따른 추론을 구분한다. | 어디부터 확인이 필요한지 드러난다. | 추론을 확인된 기능처럼 말하지 않는다. |
| 준비 일정 | 중요도와 근거의 빈틈으로 순서를 정한다. | 각 작업에 검토 가능한 결과물이 있다. | 시간 안에 얻기 어려운 경험은 구분한다. |
| 준비 도구 | 예상 질문과 누락 후보를 출력한다. | 중복을 줄이고 원문 번호를 남긴다. | 출력은 의미 이해나 준비 완료 판정이 아니다. |
연습 문제
- JOB_SENTENCES의 둘째 문장을 “필수: 테스트를 작성하고 코드 리뷰로 협업하며 Python을 사용한다.”로 바꾼다. 주제 수, Python의 근거 문장 번호, 근거 보완 수가 어떻게 되는지 실행 전에 예상한다.
- 현재 코드가 “필수: 운영 경험은 요구하지 않는다.”를 운영 주제로 연결하는 이유를 설명한다. 해당 문장을 무조건 삭제하는 방식에는 어떤 문제가 있는지도 적는다.
- “열심히 준비했고 대부분 알고 있다”를 결론, 근거, 경험, 한계의 구조로 바꾼다. 실제 경험이 없다면 가상의 연습 답변임을 밝히고 작성한다.
- 준비가 사흘 남았다고 가정한다. 필수 요구의 근거 없는 항목 두 개, 이미 설명 가능한 항목 세 개, 우대 항목 한 개가 있다. 준비 순서와 완료 기준, 줄일 작업을 정한다.
정답과 해설
- 주제 수는 4개로 유지된다. Python은 이미 첫째 문장에서 발견되었으므로 새로운 주제가 추가되지 않는다. Python의 근거 표시는 “문장 1, 2”가 된다. EVIDENCE를 바꾸지 않았으므로 근거 보완 수도 데이터베이스와 협업의 2개로 유지된다. 언급 횟수와 준비 근거의 유무는 서로 다른 값이다.
- contains_keyword는 운영이라는 문자열이 있는지만 확인하며 부정 표현을 해석하지 않는다. 따라서 요구하지 않는다는 의미를 놓친다. 문장을 삭제하면 “운영 경험은 요구하지 않지만 배포 절차 이해는 필요하다”처럼 다른 요구를 함께 담은 문장도 잃을 수 있다. 원문을 남기고 요구 여부를 사람이 검토하는 절차가 필요하다. 문장이 일부 연결된 경우에도 전체 문장을 읽어야 한다.
- 가상의 연습 답변 예시는 다음과 같다. “필수 요구 중 직접 수행한 항목은 근거를 붙여 설명할 수 있게 준비했다. 기술 이름을 아는 것과 수행 범위를 설명하는 것은 다르기 때문이다. 상품 등록 코드에는 담당 범위를 표시했고, 테스트 기록에는 입력을 고른 이유를 덧붙였다. 다만 운영 경험은 없으므로 해당 항목을 준비 완료로 보지 않는다. 지금 설명할 수 있는 범위와 추가 확인할 범위를 나누어 말하겠다.” 실제 면접에서는 이 문장에 들어갈 자료와 행동을 자신의 것으로 바꾸어야 한다.
- 첫날에는 필수 요구의 빈 항목 두 개를 살펴보고, 기존 경험에서 확보할 수 있는 근거와 새 확인이 필요한 부분을 구분한다. 둘째 날에는 핵심 답변을 말로 설명하고 자료와 대조한다. 셋째 날에는 질문을 섞어 연습하면서 오류와 누락을 수정한다. 완료 기준은 읽은 분량보다 근거를 제시하고 한계를 설명할 수 있는지로 잡는다. 일정이 밀리면 우대 항목의 추가 학습을 줄인다. 사흘 안에 얻을 수 없는 실무 경험은 학습 결과로 바꾸어 주장하지 않는다.
준비 지도가 생기면 다음에는 그중 어떤 경험을 짧은 첫 발언에 담을지 선택할 수 있다. 자기소개와 지원 동기도 여기서 정리한 역할, 근거, 경험의 범위를 바탕으로 구성한다.
READER FEEDBACK
질문·의견
내용에 관한 질문이나 더 나은 설명을 위한 의견을 남겨 주세요. 오탈자는 위의 제보 양식이 더 빨리 반영됩니다. 이 댓글은 원래 게시글과 같은 자리에 쌓입니다.
댓글 0
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.