TRENDSHIFT 딥다이브 · 2026-06-02

developer-portfolios 딥다이브
— 개발자 1,800여 명의 포트폴리오를 모은 '살아있는' 카탈로그

전 세계 개발자들이 직접 만든 포트폴리오 웹사이트 1,800여 개(시점에 따라 변함)를 한 장의 README.md에 알파벳순으로 모아 둔 거대한 큐레이티드 리스트입니다. 흥미로운 건 정작 코드는 README가 아니라 그것을 '관리'하는 src/ 폴더의 파이썬에 있다는 점 — 1,600줄짜리 목록을 사람 손으로 정렬·중복 제거하는 건 불가능하니까요. 이 글은 단순 소개를 넘어, "거대한 크라우드소싱 목록을 어떻게 자동화로 유지하는가"를 해부합니다. (저장소: emmabostian/developer-portfolios · Markdown + Python · ★약 24k · TrendShift 6위 · 명시적 LICENSE 파일 없음)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

이 레포가 무엇을 하는 물건인가.

핵심 메시지

"포트폴리오를 만들기 전에,
남들은 어떻게 만들었나 1,800여 개를 한눈에."

개발자가 자기 이력·프로젝트·연락처를 보여주려고 만든 개인 웹사이트(포트폴리오)들을 한곳에 모아 둔 영감용 목록입니다. 새 포트폴리오를 만들 때 "다른 사람들은 어떤 구성·디자인·기술을 썼나"를 둘러보는 출발점이 됩니다.

구조 자체는 단순합니다. README.md 파일 하나에 - [이름](포트폴리오 주소) [직함 | 전문 분야] 형식의 줄이 1,800여 개 들어 있고, 알파벳 A부터 Z까지 섹션으로 나뉘어 있습니다. 누구나 자기 포트폴리오를 PR (Pull Request, 코드 병합 요청)로 추가할 수 있습니다.

하지만 이 레포가 공부 자료로 가치 있는 진짜 이유는 따로 있습니다. 1,800여 개의 줄을 사람이 알파벳순으로 유지하고 중복을 걸러내는 건 불가능합니다. 그래서 이 레포는 src/ 폴더에 그 일을 대신 해 주는 파이썬 자동화 스크립트를 두고 있습니다. 즉 "콘텐츠는 마크다운, 엔지니어링은 파이썬"인 셈이죠.

용어
큐레이티드 리스트 / awesome list (curated list, 선별 목록)
특정 주제(여기선 '개발자 포트폴리오')에 대해 사람이 직접 골라 모은 링크 모음. GitHub에는 이런 목록 레포가 수천 개 있고, 보통 awesome-*라는 이름을 씁니다. 도서관 사서가 좋은 책만 골라 진열대를 만드는 것과 비슷합니다.

2왜 주목받는가

트렌딩 이유 · 비슷한 목록과 다른 점.

이 레포는 2019년 개발자 Emma Bostian이 동료 Ali Spittel의 트윗("포트폴리오 좀 보여줄 사람?")에서 영감을 받아 시작했습니다. 그 뒤 전 세계 개발자들이 자기 포트폴리오를 PR로 보태면서 1,800여 개까지 불어난 거대한 크라우드소싱 자료가 되었습니다. 인기 비결은 세 가지입니다.

첫째, 구직·이직 시즌의 실용성. "나도 포트폴리오를 만들어야 하는데 뭘 넣지?"라는 막막함을 1,800여 개의 실제 사례로 단번에 풀어 줍니다. 둘째, 오픈소스 입문자의 첫 PR 연습장. 코드를 몰라도 마크다운 한 줄만 추가하면 되니, 생애 첫 기여를 여기서 해 보는 사람이 많습니다. 셋째 — 그리고 이 글의 초점 — 거대 목록을 자동화로 유지하는 모범 사례라는 점입니다.

비교 항목보통의 awesome 목록이 레포의 접근
정렬기여자가 알아서 알맞은 위치에 끼워 넣기(자주 깨짐)alphabetical.py가 전체를 다시 정렬
중복리뷰어가 눈으로 확인URL을 정규화해 자동 탐지·제거
표기 통일제각각(대소문자·이모지·공백)타이틀 케이스·이모지 제거 자동 적용
데이터 활용마크다운 그대로feed.json으로 기계가 읽을 형태 제공
수동 유지의 한계
사람이 1,800여 줄을 손으로 관리하면

기여자마다 "Aaron"을 'B' 섹션에 넣거나, 같은 사이트를 두 번 올리거나, 이름에 이모지를 붙입니다. 리뷰어가 매번 눈으로 잡아야 하고, 목록이 커질수록 무조건 깨집니다.

자동화의 해결
규칙을 코드로 못 박으면

PR이 들어올 때마다 스크립트가 정렬·중복 제거·표기 통일을 결정론적으로 처리합니다. 사람은 "이 사이트가 진짜 포트폴리오인가"라는 판단에만 집중하면 됩니다.

3기술 스택 전체 지도

콘텐츠 · 자동화 · 데이터 · CI 한눈에.

화려한 프레임워크는 없습니다. 핵심은 파이썬 표준 라이브러리만으로 짠 텍스트 처리 파이프라인 — 외부 패키지 설치가 전혀 필요 없다는 점이 오히려 배울 만합니다.

레이어기술 / 도구역할
콘텐츠Markdown (README.md)1,800여 개 포트폴리오 항목을 담는 단일 원본.
자동화Python 3 (re·urllib.parse·unicodedata·json·collections)정렬·중복 제거·표기 통일·피드 생성.
데이터JSON (feed.json)마크다운에서 추출한 기계 판독용 구조화 데이터.
테스트unittest (run_tests.py)tests/ 폴더를 자동 탐색해 실행.
CIGitHub Actions (link-checker.yml + parking-redirect-checker.yml)죽은 링크(404) 및 파킹 도메인 리다이렉트 자동 점검.
용어
CI (Continuous Integration, 지속적 통합)
코드나 콘텐츠가 바뀔 때마다 정해진 검사를 자동으로 돌려 주는 장치. 여기선 GitHub Actions가 "추가된 링크가 살아 있나"를 사람 대신 확인합니다. 공장의 자동 품질검사 라인을 떠올리면 됩니다.

덤: 1,800여 개가 실제로 어디에 호스팅돼 있나

목록의 포트폴리오 주소들을 직접 집계해 봤습니다(약 1,000개 표본 기준 — 전체 1,800여 개의 일부라 비율은 근사값입니다). 실제 개발자들이 개인 사이트를 어디에 올리는지 보여 주는 살아있는 데이터입니다.

호스팅 플랫폼대략 비중특징
Vercel (*.vercel.app)약 200건 (최다)Next.js·React 배포에 강한 무료 정적/서버리스 호스팅.
GitHub Pages (*.github.io)약 108건깃허브 저장소를 그대로 웹사이트로. 가장 전통적인 무료 선택지.
Netlify (*.netlify.app)약 68건정적 사이트·JAMstack 배포의 대표 주자.
Firebase (*.web.app)약 10건구글의 호스팅 + 백엔드 서비스.
Render·Cloudflare Pages 등각 수 건onrender.com·pages.dev 등 신흥 무료 호스팅.
커스텀 도메인나머지 다수.dev·.me·.com 직접 구매. is-a.dev 같은 무료 서브도메인도 인기.
읽는 법

"포트폴리오 = 정적 사이트 한 장"이라는 공식이 데이터로 드러납니다. 무거운 서버 없이 HTML/CSS/JS를 빌드해 CDN에 올리는 Vercel·Netlify·GitHub Pages가 압도적입니다. 즉 입문자가 "포트폴리오 어디에 올리지?"를 고민한다면, 이 셋 중 하나면 충분하다는 뜻입니다.

4아키텍처 심화 분석

PR 한 건이 들어오면 무엇이 어떤 순서로 도는가.

이 레포의 "아키텍처"는 서버 구조가 아니라 데이터(=README) 가공 파이프라인입니다. 먼저 전체 그림을 보고, 그다음 줄 한 개가 어떻게 처리되는지 끝까지 따라가 보겠습니다.

┌──────────────────────────────────────────────────────────┐ │ developer-portfolios 파이프라인 │ │ │ │ 기여자 PR ──▶ README.md (1,800여 줄 원본) │ │ │ │ │ ▼ │ │ ┌───────────────────────┐ │ │ │ src/alphabetical.py │ ← 핵심 엔진 ★ │ │ │ (9단계 순차 처리) │ │ │ └───────────┬───────────┘ │ │ │ │ │ ┌─────────────────┼─────────────────┐ │ │ ▼ ▼ ▼ │ │ 정렬된 README feed.json README.md.bak │ │ (A~Z 재정렬) (구조화 데이터) (되돌리기용 백업) │ │ │ │ ─ 별도로 ─ │ │ GitHub Actions(link-checker.yml) ──▶ 죽은 링크 404 점검 │ └──────────────────────────────────────────────────────────┘

핵심 엔진 alphabetical.py의 9단계 (해피 패스)

이 스크립트의 main()은 README를 읽어 아래 순서로 가공한 뒤 다시 저장합니다. "줄 하나"가 거치는 여정을 따라가 봅시다.

① 원본 읽기 + README.md.bak 백업 생성 ② convert_to_title_case() : "[aaron dunphy]" ─▶ "[Aaron Dunphy]" (단, DevOps·GitHub·API 같은 고유 대문자는 그대로 보존) ③ 대괄호 안 끝 공백 정리 : "[Name ]" ─▶ "[Name]" ④ 설명 표기 통일 : "Full-Stack"·"FullStack" ─▶ "Full Stack" ⑤ remove_duplicate_urls() : 같은 주소(정규화 후) 두 번째부터 삭제 ⑥ 줄 단위 완전 중복 제거 (앞뒤 공백 무시, 대소문자 구분) ⑦ validate_section_placement() : 'A'로 시작하는데 'B' 섹션에 있으면 ─▶ 'A'로 이동 ⑧ sort_lists_alphabetically() : 섹션 안에서 알파벳 정렬 + URL 끝 / 제거 ⑨ remove_exact_duplicate_links() : 정렬 후 인접한 똑같은 줄 합치기 ─▶ 마지막에 create_feed_json()으로 feed.json까지 생성

여기서 가장 영리한 부분은 ⑤ 중복 판단입니다. https://Me.com/http://me.com은 글자만 보면 다르지만 사실 같은 사이트죠. 그래서 비교 전에 URL 정규화를 거칩니다 — 대소문자를 낮추고, :80/:443 같은 기본 포트를 떼고, 끝의 /를 제거해 "같은 주소"로 만든 뒤 비교합니다.

설계 패턴
정규화(normalization)와 멱등성(idempotent)
정규화는 "겉모습이 달라도 본질이 같은 것"을 한 가지 표준 형태로 맞추는 것(대소문자·슬래시 통일). 멱등성은 "같은 작업을 몇 번 돌려도 결과가 같다"는 성질입니다. 이 파이프라인은 이미 정리된 README에 다시 돌려도 변화가 없어야 합니다 — 자판기에 정리된 돈을 다시 넣어도 더 흐트러지지 않는 것과 같죠.
왜 순서가 중요한가

중복 제거(⑤⑥)를 먼저 하고 정렬(⑧)을 한 뒤, 정렬로 나란히 붙게 된 중복을 한 번 더 잡는(⑨) 2단 구조입니다. 책장을 정리할 때 "먼저 명백한 중복을 버리고 → 가나다순으로 꽂고 → 나란히 선 같은 책을 마지막에 한 번 더 확인"하는 것과 똑같은 순서입니다.

5디렉토리 구조 해부

어떤 파일이 무슨 일을 하나.

developer-portfolios/ ├── README.md 1,800여 개 포트폴리오 항목 원본 ★ ├── CONTRIBUTING.md 기여 방법(포크→브랜치→PR) 안내 ├── feed.json README에서 추출한 구조화 데이터(자동 생성) ├── run_tests.py 경량 테스트 실행기 (루트 — tests/ 디렉토리 discovery) ├── assets/ │ └── ASpittel_tweet.png 레포의 기원이 된 트윗 이미지 ├── src/ 자동화 엔진 ★ │ ├── alphabetical.py 정렬·중복제거·표기통일·피드생성 (핵심) │ ├── check_parking_redirects.py 파킹 도메인 리다이렉트 감지 │ ├── generate_feed.py README ─▶ feed.json 단독 생성기 │ ├── remove_emoji_in_readme.py 이름·설명에서 이모지 제거 │ ├── run_dup_report.py 중복만 '리포트'(수정 없이 점검) │ └── run_tests.py tests/ 폴더 자동 탐색 후 단위 테스트 실행 ├── tests/ 단위 테스트 모음 └── .github/ └── workflows/ ├── link-checker.yml 죽은 링크 자동 점검 CI └── parking-redirect-checker.yml 파킹 리다이렉트 자동 점검 CI
파일/폴더역할
README.md단 하나의 진실 원본(single source of truth). 1,800여 개 포트폴리오 항목이 모두 여기서 나온다.
src/alphabetical.py레포의 심장. 정렬·중복 제거·표기 통일·피드 생성을 한 번에 처리.
src/run_dup_report.py파일을 고치지 않고 중복 현황만 출력. "수정 전 미리보기" 역할.
src/remove_emoji_in_readme.py이모지 제거. dry_run(미리보기)·.bak 백업 옵션 내장.
feed.json{"name","url","tagline"} 배열. 다른 앱이 목록을 읽어 쓰기 좋게.
.github/workflows/GitHub Actions 설정. 링크 생존 여부를 자동 검사.
한눈에

README.md원장(원본 데이터), src/는 그 원장을 깨끗하게 유지하는 사서 로봇들, feed.json은 외부에 내보내는 복사본입니다. 데이터는 한 곳(README)에만 있고 나머지는 거기서 파생됩니다 — 진실의 원본을 하나로 두는 깔끔한 설계입니다.

6학습 포인트 (기술별)

이 작은 레포에서 의외로 많이 배운다.

포인트 1

URL 정규화로 "같은 주소" 판별하기

_normalize_url()은 텍스트 비교의 함정을 보여 주는 좋은 예제입니다. 표준 라이브러리 urllib.parse로 URL을 부품(스킴·도메인·경로)으로 쪼갠 뒤 표준형으로 다시 조립합니다. src/alphabetical.py를 읽어 보세요.

핵심 로직은 이렇게 짧습니다(읽기 쉽게 단순화):

# 겉모습이 달라도 같은 사이트로 인식되게 표준형으로 변환
def _normalize_url(url):
    p = urlparse(url)                # URL을 부품으로 분해
    scheme = p.scheme.lower()        # http/https 소문자로
    netloc = p.netloc.lower()        # 도메인 소문자로
    path = p.path.rstrip('/')        # 끝의 / 제거 → 핵심!
    return urlunparse((scheme, netloc, path, '', p.query, p.fragment))

복사해서 그대로 돌려도 됩니다. https://Me.com/도, http://me.com도 모두 http(s)://me.com으로 맞춰져 "중복"으로 잡히는 원리입니다.

포인트 2

정규식으로 표기 통일하되 고유명사는 지키기

이름을 타이틀 케이스(aaron → Aaron)로 바꾸되 DevOps·GitHub·API처럼 대문자가 의미 있는 단어는 건드리지 않는 예외 처리가 핵심입니다. 무작정 .title()을 쓰면 Github·Api처럼 망가지죠.

# 두 번째 글자 이후에 대문자가 있거나(GitHub) 전부 대문자(API)면 그대로 둠
if len(token) > 1 and (any(c.isupper() for c in token[1:]) or token.isupper()):
    result.append(token)         # DevOps, GitHub, API → 보존
else:
    result.append(token.title()) # aaron → Aaron
포인트 3

유니코드 정규화로 악센트 문자 다루기

validate_section_placement()É로 시작하는 이름을 NFD 정규화로 분해해 기본 글자 E를 뽑아내고, 그 사람을 'E' 섹션에 배치합니다(unicodedata.normalize('NFD', ...)). 다국어 데이터를 다룰 때 반드시 만나는 문제입니다.

포인트 4

"수정"과 "리포트"를 분리하는 설계

run_dup_report.py는 파일을 고치지 않고 중복 현황만 보여 줍니다. remove_emoji_in_readme.py에도 dry_run 옵션과 .bak 백업이 있죠. "파괴적 작업은 항상 미리보기·되돌리기를 곁들인다"는 실무 습관을 작은 코드로 배울 수 있습니다.

포인트 5

테스트 + CI로 품질을 자동으로 지키기

run_tests.pyunittest 디스커버리로 tests/를 자동 실행하고, link-checker.yml은 GitHub Actions로 죽은 링크를 잡습니다. "사람이 매번 확인하지 않아도 규칙이 지켜지는" 구조를 직접 볼 수 있는 미니 사례입니다.

7시스템 요구사항

돌려 보려면 무엇이 필요한가 — 거의 아무것도 필요 없다.

항목요구사항
런타임Python 3.6+ (f-string·표준 라이브러리만 사용)
외부 패키지없음pip install 불필요. re·json·urllib 등 내장 모듈만 사용.
도구Git, 텍스트 에디터(또는 GitHub 웹 편집기)
OSmacOS · Linux · Windows (플랫폼 무관)
기여 시GitHub 계정 (포크·PR용)

의존성이 0개라는 점은 그 자체로 학습 포인트입니다. "표준 라이브러리만으로 충분한 일에 굳이 패키지를 늘리지 않는다"는 절제를 보여 줍니다.

8직접 해볼 수 있는 실습 과제

읽기만 하지 말고 직접 돌려 보자.

실습 1

내 포트폴리오 추가 PR 보내기 난이도 ★☆☆ 입문

CONTRIBUTING.md대로 포크 → add/내이름 브랜치 생성 → README의 알맞은 알파벳 위치에 - [이름](주소) [직함] 한 줄 추가 → PR. 생애 첫 오픈소스 기여 연습으로 딱입니다.

실습 2

feed.json 직접 만들어 보기 난이도 ★★☆ 중급

레포를 클론한 뒤 python src/generate_feed.py 실행 → feed.json이 생성되는 걸 확인. 정규식이 - [name](url) [tagline]을 어떻게 파싱하는지 코드와 결과를 대조해 보세요.

실습 3

중복 리포트 돌려 보기 난이도 ★★☆ 중급

python -m src.run_dup_report로 현재 README의 중복 현황을 출력. URL 기반 중복과 인접 중복이 각각 몇 건인지 읽고, _normalize_url이 왜 필요한지 체감해 보세요.

실습 4

정규화 규칙 추가 + 테스트 작성 난이도 ★★★ 고급

_normalize_url에 "www. 접두사 제거" 규칙을 추가해 보고, tests/에 그 동작을 검증하는 단위 테스트를 작성한 뒤 python src/run_tests.py로 통과시켜 보세요.

실습 5

호스팅 통계 스크립트 직접 짜기 난이도 ★★★ 고급

이 글 3번 섹션의 "호스팅 분포"를 직접 재현해 보세요. README에서 URL을 뽑아 도메인을 집계하는 파이썬 스크립트를 짜면, 정규식·collections.Counter·데이터 집계를 한 번에 연습할 수 있습니다.

9관련 기술 심화 학습 로드맵

이 레포를 발판 삼아 한 주씩.

주차주제학습 자료 / 할 일
1주차Markdown + Git/PR 기초CONTRIBUTING.md 따라 실습 1 완료. 포크·브랜치·PR 흐름 체득.
2주차정규표현식 (re 모듈)alphabetical.py의 패턴 분석 + 파이썬 공식 re 문서.
3주차URL·유니코드 정규화urllib.parse·unicodedata 문서. 실습 4 진행.
4주차테스트(unittest) + CItests/ 읽기, GitHub Actions link-checker.yml 분석.
5주차내 포트폴리오 만들기Vercel/Netlify/GitHub Pages 중 하나로 정적 사이트 배포.

10핵심 키워드 사전

본문에 나온 용어 빠른 참조.

용어의미
큐레이티드 리스트사람이 직접 골라 모은 주제별 링크 모음. GitHub의 awesome-* 레포가 대표적.
PR (Pull Request)"내 변경분을 원본에 합쳐 달라"는 요청. 오픈소스 기여의 기본 단위.
정규화 (normalization)겉모습이 달라도 본질이 같은 값을 하나의 표준형으로 맞추는 것.
멱등성 (idempotent)같은 작업을 여러 번 해도 결과가 변하지 않는 성질.
타이틀 케이스각 단어 첫 글자를 대문자로(aaron → Aaron). 고유명사는 예외 처리 필요.
NFD 정규화유니코드를 "기본 글자 + 악센트 기호"로 분해하는 방식. É → E + ´.
정적 사이트 / JAMstack서버 없이 미리 만든 HTML/CSS/JS를 CDN에 올리는 웹사이트 방식.
CDNContent Delivery Network. 콘텐츠를 전 세계 서버에 복제해 빠르게 전달.
CIContinuous Integration. 변경마다 검사를 자동으로 돌려 품질을 지키는 장치.
dry run실제로 바꾸지 않고 "이렇게 바뀐다"만 미리 보여 주는 실행 모드.

11참고 링크