흩어진 정부지원사업 공고를 한 목록으로 모으는 일
핵심 요약
- 공고는 출처마다 형식과 필드, 갱신 주기가 다릅니다. 한 목록으로 합치려면 먼저 공통의 언어로 번역해야 합니다.
- 가장 까다로운 건 '지금 모집 중인가'를 판정하는 일입니다. 마감이 날짜가 아니라 문장으로 적힌 공고가 많습니다.
- 여러 곳에서 데이터를 만지면 정보가 어긋납니다. 갱신을 책임지는 곳을 하나로 정하는 것이 핵심이었습니다.
지원사업을 찾는 창업자가 겪는 일은 대체로 비슷합니다. 어떤 공고는 한 기관 사이트에, 어떤 공고는 다른 통합 포털에 있습니다. 같은 사업인데 두 곳에 조금씩 다른 형태로 올라와 있기도 합니다. 마감일을 믿고 준비했는데 알고 보니 연장되어 있거나, 반대로 예산이 소진돼 조기 마감되어 있기도 합니다. 이 흩어짐과 어긋남을 창업자가 매번 손으로 훑는 대신, 한 화면에서 정리해 보여주고 싶었습니다.
말로 하면 간단합니다. 여러 곳의 공고를 모아서 한 목록으로 보여준다. 그런데 실제로 만들어 보면 '모은다'는 단어 하나에 여러 문제가 겹쳐 있습니다. 이 글은 그 문제들을 하나씩 풀어 온 과정을, 특정 도구가 아니라 설계 원칙의 관점에서 적었습니다.
왜 공고는 한곳에 모이지 않는가
공고를 내는 주체가 여럿이기 때문입니다. 부처가 다르고, 이를 집계하는 포털도 여럿이고, 개별 기관이 자기 사이트에만 올리는 경우도 있습니다. 각 출처는 자기 사정에 맞는 형식을 씁니다. 어떤 곳은 마감일을 날짜 필드로 내려주고, 어떤 곳은 공고 본문 안에 문장으로만 적어 둡니다. 사업 분야를 분류하는 코드 체계도 출처마다 다릅니다.
그래서 여러 출처를 한 화면에 그냥 이어 붙이면, 목록은 만들어지지만 검색과 정렬이 되지 않습니다. 마감 임박순으로 정렬하려는데 어떤 공고는 마감일이 날짜가 아니라 문장이고, 분야로 거르려는데 같은 분야를 출처마다 다른 이름으로 부릅니다. 합치기 전에 먼저 공통의 언어로 번역하는 단계가 필요합니다.
출처별 어댑터와 공통 스키마
우리가 택한 구조는 두 층으로 나뉩니다. 바깥층은 출처마다 하나씩 두는 어댑터입니다. 어댑터의 일은 단순합니다. 그 출처가 주는 형식을 읽어서, 우리가 정한 공통 형태로 바꿔 내놓는 것입니다. 출처가 마감일을 어떤 필드에 담든, 분야를 어떤 코드로 부르든, 그 방언을 아는 건 해당 어댑터 하나뿐입니다.
안쪽층은 모든 어댑터가 똑같이 채워야 하는 공통 스키마입니다. 제목, 마감 정보, 분야, 지역, 원문 링크처럼 목록과 검색에 필요한 필드를 여기서 정의합니다. 새로운 출처가 늘어도 안쪽은 건드리지 않습니다. 그 출처의 방언을 공통 스키마로 옮기는 어댑터 하나만 새로 쓰면 됩니다. 이 경계 덕분에 출처가 늘어날 때 드는 비용이 예측 가능해졌습니다.
같은 공고를 두 번 세지 않기
여러 출처를 모으면 같은 사업이 둘 이상 들어오는 일이 생깁니다. 한 포털에도 올라오고 기관 사이트에도 올라온 공고를 그대로 두면 목록에 두 번 뜹니다. 그래서 '이 둘은 같은 공고다'를 판정하는 기준이 필요합니다.
제목이 비슷하다는 것만으로는 부족합니다. 해마다 반복되는 사업은 제목이 거의 같지만 서로 다른 회차입니다. 반대로 같은 공고인데 한쪽은 제목을 줄여 적기도 합니다. 그래서 출처가 부여하는 고유 식별자를 우선으로 삼고, 그것만으로 부족한 부분을 다른 필드로 보완하는 방식으로 판정 키를 잡았습니다. 판정이 틀리면 두 방향의 실수가 납니다. 서로 다른 공고를 하나로 합쳐 버리거나, 같은 공고를 둘로 남기거나. 둘 다 창업자에게는 혼란이라, 이 규칙은 지금도 실제 데이터를 보며 다듬고 있습니다.
'모집 중'을 판정하는 일의 어려움
공고 목록에서 창업자가 가장 먼저 걸러 내는 조건은 '지금 지원할 수 있는가'입니다. 당연해 보이지만, 이걸 자동으로 판정하는 게 이 파이프라인에서 가장 손이 많이 간 부분이었습니다.
마감일이 날짜로 적힌 공고는 오늘과 비교하면 됩니다. 문제는 마감이 문장으로 적힌 공고입니다. '예산 소진 시까지', '상시 모집' 같은 표현은 날짜가 없습니다. 이런 공고를 날짜 기준 필터로만 거르면 목록에서 통째로 사라집니다. 실제로는 지금 지원할 수 있는데도 말입니다. 그래서 마감을 날짜형과 텍스트형으로 나눠 다루고, 텍스트형은 별도의 신호로 열림과 닫힘을 판단하도록 했습니다.
날짜가 없는 마감을 다루는 원칙
- 마감이 날짜인 공고는 날짜로 판정한다.
- 마감이 문장인 공고는 날짜 비교에서 빼고, 출처가 주는 '모집 진행 여부' 신호를 유일한 만료 근거로 삼는다.
- 둘 중 어느 쪽으로도 확신이 서지 않으면 목록에서 지우기보다 남겨 두고, 원문 링크로 확인을 넘긴다.
이렇게 나누고 나서야 상시로 열려 있는 공고들이 목록에 제대로 올라왔습니다. 날짜만 보던 시절에는 이 공고들이 조용히 빠져 있었습니다. 데이터를 다루다 보면, 없는 게 아니라 안 보이던 것이 꽤 있다는 걸 자주 느낍니다.
갱신을 책임지는 곳은 하나여야 한다
공고는 한 번 모으고 끝이 아닙니다. 마감이 연장되고, 예산이 소진돼 닫히고, 내용이 수정됩니다. 이 변화를 따라가려면 주기적으로 다시 확인해야 합니다. 초기에는 여러 곳에서 각자 필요할 때 데이터를 손보게 두었는데, 여기서 정보가 어긋나기 시작했습니다. 한쪽은 마감을 연장으로 반영했는데 다른 쪽은 옛 날짜를 그대로 들고 있는 식이었습니다.
그래서 원칙을 하나로 세웠습니다. 공고 데이터를 실제로 갱신하는 주체는 하나뿐이다. 나머지는 그 결과를 읽기만 한다. 갱신 책임이 한곳에 모이자 '어느 게 맞는 값인가'를 두고 헷갈릴 일이 사라졌습니다. 여러 곳이 같은 데이터를 고칠 수 있으면 편할 것 같지만, 실제로는 그 편함의 대가를 한참 뒤에 어긋난 값으로 치르게 됩니다.
모은 다음에 남는 것
이 파이프라인의 목표는 화려한 게 아니었습니다. 창업자가 여러 사이트를 돌지 않아도, 한 화면에서 지금 지원 가능한 공고를 마감 임박순으로 보고, 분야와 지역으로 좁혀 갈 수 있게 하는 것. 그 뒤에는 출처를 번역하는 어댑터, 중복을 거르는 판정 키, 텍스트 마감을 다루는 분기, 갱신을 책임지는 단일 주체가 있습니다.
지금 어떤 공고가 열려 있는지는 공고 모아보기에서 마감 임박순으로 볼 수 있습니다. 목록에 올라온 공고 하나하나가, 위에서 적은 단계들을 통과해 온 결과입니다.
지금 모집 중인 공고를 한 목록에서 확인해 보세요
공고 모아보기JulianProduct Owner
genDOC의 프로덕트 오너이자 개발자. 공고 데이터 파이프라인부터 문서 편집기까지 제품을 직접 만들고 있습니다.
이 글은 Julian이 작성하고 genDOC 팀이 함께 검수했습니다.