2019년 개발 연대기: 개발 흐름이 저장소에 모이고 인공지능이 Python답게 바뀌다
React Hooks 안정판, TensorFlow 2.0, GitHub Actions, WebAuthn, Kotlin-first Android, Kubernetes의 성숙, 국내 5G 스마트폰 상용화와 오픈뱅킹으로 2019년의 개발 흐름을 살펴봅니다.
2019년에는 개발자가 코드를 작성한 뒤 거치는 여러 단계가 하나의 흐름으로 연결됐다. GitHub Actions는 source repository 안의 설정으로 build, test, deployment를 자동화했고, Kubernetes는 Windows workload와 custom resource를 안정 기능으로 끌어올렸다. 코드를 보관하는 곳, 검증하는 곳, 실행 환경을 선언하는 곳의 경계가 가까워졌다.
프로그래밍 모델도 사용 경험을 중심으로 재정리됐다. React Hooks는 함수 컴포넌트에 상태와 효과를 결합했고, TensorFlow 2.0은 graph와 Session을 먼저 구성하던 방식에서 Python 코드를 즉시 실행하는 방식으로 기본값을 바꿨다. Google은 Android 개발을 점차 Kotlin-first로 전환하겠다고 밝혔다. W3C는 WebAuthn을 권고안으로 확정해 password 외의 공개 키 기반 인증을 웹의 표준 API로 만들었다.
국내에서는 5G 스마트폰 서비스가 시작되며 전년의 기업용 개통이 소비자 서비스로 이어졌다. 은행과 fintech 기업이 공동 결제망의 표준화된 API를 사용하는 오픈뱅킹도 시범 운영을 거쳐 전면 시행됐다. 네트워크의 속도뿐 아니라 금융 기반 시설의 접근 방식까지 서비스 개발의 조건이 달라지고 있었다.
2019년을 보여주는 장면
| 분야 | 주요 변화 | 개발자에게 생긴 의미 |
|---|---|---|
| 웹 UI | React 16.8에 Hooks 포함 | 함수 컴포넌트에서 상태·효과·재사용 로직을 조합 |
| 기계학습 | TensorFlow 2.0 출시 | eager execution과 Keras를 기본으로 학습·배포 API를 재정리 |
| 개발 자동화 | GitHub Actions 일반 제공 | 저장소의 event와 YAML workflow로 CI/CD를 구성 |
| 웹 보안 | WebAuthn Level 1 권고 | 공개 키 자격 증명과 authenticator를 웹 표준 API로 사용 |
| Android | Kotlin-first 방침 발표 | 새 Jetpack API와 문서가 Kotlin을 우선하는 방향으로 이동 |
| container | Windows node·CRD 안정화 | Kubernetes가 더 다양한 workload와 확장 API를 수용 |
| 국내 통신 | 5G 스마트폰 상용 서비스 | 일반 이용자가 5G 단말과 요금제로 이동통신망에 접속 |
| 국내 금융 | 오픈뱅킹 전면 시행 | 은행별 제휴 대신 공동 API로 조회·이체 서비스를 개발 |
React 16.8, Hooks가 안정판에 들어오다
React는 2월 6일 React 16.8을 출시하며 Hooks를 안정 기능으로 제공했다. 2018년 10월 conference에서 제안되고 alpha로 검증되던 API가 운영 애플리케이션에서 사용할 수 있는 단계에 도달한 것이다.
useState는 함수 컴포넌트의 호출 사이에 상태를 보존했고, useEffect는 rendering 결과가 화면에 반영된 뒤 외부 시스템과 동기화하는 코드를 실행했다. custom Hook은 상태를 저장하는 별도 공간이 아니라 다른 Hook을 조합한 함수였다. 이를 통해 구독, form 상태, network 요청 같은 동작을 컴포넌트 계층을 늘리지 않고 공유할 수 있었다.
import { useEffect, useState } from "react";
function Repository({ name }) {
const [stars, setStars] = useState(null);
useEffect(() => {
let active = true;
fetch(`https://api.github.com/repos/${name}`)
.then((response) => response.json())
.then((data) => active && setStars(data.stargazers_count));
return () => {
active = false;
};
}, [name]);
return <p>{stars === null ? "불러오는 중" : `${stars} stars`}</p>;
}
Hooks에는 호출 순서가 보존돼야 한다는 규칙이 따랐다. 조건문이나 반복문 안에서 Hook을 호출하지 않고 React 함수의 최상위에서 호출해야 상태가 올바른 위치와 대응했다. eslint-plugin-react-hooks는 이 호출 규칙과 effect dependency 누락을 검사했다. 새 API는 자유로운 함수 호출처럼 보였지만 안정성을 위해 정적 검사와 convention이 함께 필요했다.
React 팀은 class component를 제거하지 않았고 기존 코드를 모두 Hooks로 바꾸라고 요구하지도 않았다. 2019년의 변화는 class 문법의 단순한 대체보다, 관련 있는 상태와 부수 효과를 기능 단위로 묶어 조합하는 설계 방식이 안정적인 선택지가 됐다는 데 있었다.
TensorFlow 2.0, graph 우선에서 Python 실행 우선으로
Google은 9월 30일 TensorFlow 2.0 최종판을 공개했다. 1.x에서는 placeholder와 연산 graph를 정의한 뒤 Session.run으로 실행하는 방식이 중심이었다. 2.0은 eager execution을 기본으로 삼아 일반 Python 코드처럼 값을 즉시 계산하고 debugger로 실행 과정을 따라갈 수 있게 했다.
고수준 모델 API는 tf.keras로 통합됐다. 단순한 순차 모델부터 함수형 API와 model subclassing까지 하나의 계층 안에서 구성하고 fit, evaluate, predict로 실행할 수 있었다.
import tensorflow as tf
model = tf.keras.Sequential([
tf.keras.layers.Dense(16, activation="relu"),
tf.keras.layers.Dense(1),
])
model.compile(optimizer="adam", loss="mse")
model.fit(features, labels, epochs=10)
즉시 실행이 기본이라고 계산 graph가 사라진 것은 아니었다. 성능 최적화나 배포가 필요할 때 @tf.function이 Python 함수를 graph로 변환했다. AutoGraph는 Python의 조건문과 반복문을 TensorFlow 연산으로 바꿨고, distribution strategy는 한 장비의 여러 GPU나 여러 장비에 학습을 분산하는 공통 API를 제공했다.
SavedModel은 cloud, server, browser, mobile과 embedded 환경으로 모델을 옮기는 표준 저장 형식이 됐다. TensorFlow Serving, Lite, TensorFlow.js가 같은 생태계 안에서 학습 결과를 소비할 수 있도록 한 것이다.
2.0은 호환성이 유지되는 작은 개선이 아니었다. 중복 API가 제거·이동되고 기본 동작이 달라져 1.x codebase에는 migration 작업이 필요했다. Google은 tf_upgrade_v2 변환 도구와 migration guide를 제공했지만, 자동 변환만으로 실행 의미까지 모두 보장할 수는 없었다. 2019년은 기계학습 framework도 API의 능력만큼 개발자 경험과 운영까지 이어지는 경로를 중요하게 다루기 시작한 해였다.
GitHub Actions, 저장소의 event가 CI/CD를 실행하다
GitHub은 8월에 CI/CD 기능을 갖춘 새로운 GitHub Actions beta를 공개하고 11월 11일 일반 제공을 발표했다. 2018년에 공개한 초기 Actions가 container 단위의 작업 연결에 초점을 맞췄다면, 2019년의 새 체계는 build와 test, release, deployment를 표현하는 workflow와 job을 중심으로 다시 설계됐다.
개발자는 .github/workflows 아래 YAML 파일을 두고 push, pull request, schedule, release 같은 repository event에 반응하도록 설정했다. Linux, Windows, macOS runner와 여러 언어 버전을 조합한 matrix build도 저장소 안에서 선언할 수 있었다.
name: test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm ci
- run: npm test
위 예제의 action version과 Node 12는 2019년 당시의 형태를 보여준다. 현재 workflow에 그대로 권장되는 최신 설정이라는 뜻은 아니다.
소스와 자동화 정의, code review 결과가 같은 repository와 pull request 화면에 모이면서 CI/CD를 시작하는 장벽이 낮아졌다. 공개 repository에는 무료로 제공됐고 private repository도 요금제별 실행 시간과 저장 공간을 받았다. 자체 runner를 연결해 기업 내부 환경에서 job을 실행하는 선택지도 beta로 제공됐다.
편의성은 새로운 보안 책임도 만들었다. workflow가 repository secret과 배포 권한을 사용할 수 있으므로 외부 action의 code와 version을 검토하고, pull request에서 신뢰하지 않는 code가 어떤 권한으로 실행되는지 통제해야 했다. 저장소 설정이 곧 공급망과 운영 권한의 일부가 됐다.
WebAuthn, password를 넘어서는 웹 인증 표준
W3C는 3월 4일 Web Authentication Level 1을 권고안으로 확정했다. WebAuthn은 웹 애플리케이션이 공개 키 기반 자격 증명을 만들고 인증에 사용할 수 있는 browser API를 정의했다. FIDO2 규격의 핵심 구성요소로서 보안 키, 단말의 생체인증이나 PIN으로 사용자의 동의를 확인할 수 있었다.
등록할 때 authenticator는 사이트별 공개 키와 private key 쌍을 만든다. 서버는 공개 키를 저장하고 private key는 authenticator 밖으로 내보내지 않는다. 로그인할 때 서버가 보낸 challenge에 서명하고 서버가 이를 검증한다. 비밀번호처럼 서버가 알고 있는 공통 secret을 전송하거나 보관하지 않으므로 database 유출과 phishing에 대한 위험을 줄일 수 있었다.
그러나 ‘passwordless’라는 표현이 모든 서비스에서 즉시 비밀번호가 사라졌다는 뜻은 아니었다. browser와 운영체제 지원, account recovery, 여러 기기 등록, authenticator 분실 대응을 제품이 함께 설계해야 했다. 많은 서비스는 WebAuthn을 두 번째 인증 수단으로 먼저 도입했다. 표준 API의 완성은 배포의 끝이 아니라 상호운용 가능한 출발점이었다.
Android는 Kotlin-first로, Kotlin 전용이라는 뜻은 아니었다
Google은 5월 Google I/O에서 Android 개발이 점차 Kotlin-first가 될 것이라고 발표했다. 2017년 Kotlin을 공식 지원 언어로 추가한 데서 더 나아가, 새 Jetpack API와 기능을 Kotlin에 먼저 제공하고 새 project에는 Kotlin 사용을 권장한다는 방향이었다.
Kotlin coroutine은 callback이 겹치는 asynchronous code를 순차적인 형태로 표현했고, Android KTX는 기존 Android API를 Kotlin extension으로 더 간결하게 사용할 수 있게 했다. Jetpack Compose도 그해 초기 preview로 공개되며 Kotlin으로 UI를 선언하는 미래 방향을 보여줬다. 다만 Compose의 안정판은 2021년이므로 2019년에 운영 UI toolkit이 완성됐다고 표현해서는 안 된다.
Kotlin-first는 Java 지원 중단이나 Kotlin-only를 뜻하지 않았다. 기존 Android framework와 방대한 application은 Java에 기반했고 두 언어는 같은 project에서 함께 사용할 수 있었다. 정책의 의미는 documentation, sample, tool과 신규 API 설계의 기준 언어가 Kotlin 쪽으로 이동했다는 데 있었다.
Kubernetes, 더 많은 workload와 확장을 안정 영역으로
Kubernetes는 2019년에 1.14부터 1.17까지 네 차례 minor release를 내놓았다. 1.14에서는 Windows node 지원이 안정 단계에 올라 Windows Server container를 Linux control plane이 있는 cluster에 worker workload로 배치할 수 있게 됐다. 모든 Kubernetes 기능이 Windows에 동일하게 제공된 것은 아니었지만, 기존 Windows application의 container 전환 경로가 공식 지원 범위로 들어왔다.
1.16에서는 CustomResourceDefinition, CRD가 일반 제공 단계에 도달했다. 운영자는 Kubernetes API에 자신만의 resource type을 추가하고 controller가 desired state를 actual state에 맞추도록 만들 수 있었다. database, message system, certificate 같은 domain-specific operation을 Kubernetes resource와 reconciliation loop로 표현하는 operator 생태계가 성장했다.
성숙에는 정리도 따랐다. 1.16은 오래전에 deprecated된 일부 API version 제공을 중단했다. 예를 들어 Deployment를 extensions/v1beta1로 제출하면 거부되고 안정판인 apps/v1을 사용해야 했다. cluster upgrade 전에 manifest와 client가 제거 대상 API를 사용하는지 확인하는 일이 운영 절차가 됐다.
Kubernetes가 확장 가능한 공통 platform으로 자리 잡을수록 version과 API lifecycle 관리의 중요성도 커졌다. container를 배치하는 도구를 넘어 조직의 deployment와 operation 규칙을 custom resource와 controller로 구현하는 기반이 되고 있었다.
국내: 스마트폰으로 열린 5G 서비스
국내 이동통신 3사는 4월 3일 밤 일반 가입자를 대상으로 5G 스마트폰 개통을 시작했다. 2018년 12월 기업용 router 단말로 시작한 상용 서비스가 스마트폰과 요금제를 사용하는 소비자 영역으로 넓어진 것이다. 초기 단말은 삼성전자의 Galaxy S10 5G였고, 정부와 통신업계는 이를 세계 최초 스마트폰 기반 5G 상용화로 발표했다.
개통 시각을 앞당긴 경쟁만으로 실제 이용 경험이 완성된 것은 아니었다. 초기에는 coverage가 수도권과 주요 도시에 집중됐고 건물 안에서는 LTE로 전환되는 경우가 많았다. 단말 전력 소비, 망 품질과 요금도 해결해야 할 과제였다. 애플리케이션 개발자는 5G 연결을 항상 사용할 수 있다고 가정하기보다 네트워크 변화와 불안정성에 대응해야 했다.
한편 고속·저지연 망은 실감형 media, cloud game, 고화질 live streaming과 산업용 edge service에 대한 투자를 자극했다. 2019년의 핵심은 5G가 명세와 실증을 넘어 일반 이용자가 비용을 지불하는 제품 환경으로 들어왔다는 사실이었다.
국내: 오픈뱅킹, 은행 공동망을 API로 열다
금융위원회는 2월 금융결제 기반 시설 혁신 방안을 발표하고 오픈뱅킹 구축을 추진했다. 10월 30일 10개 은행이 시범 운영을 시작했으며, 12월 18일에는 16개 은행과 31개 fintech 기업 등 47개 기관이 참여하는 전면 시행으로 확대됐다.
기존에는 fintech 사업자가 여러 은행의 계좌 조회와 이체 기능을 제공하려면 은행마다 계약하고 서로 다른 연결 방식을 구현해야 했다. 오픈뱅킹은 금융결제원의 공동망과 표준 API를 통해 잔액·거래 내역 조회, 입금·출금 이체 같은 기능을 제공했다. 이용자는 하나의 application에서 여러 은행 계좌를 등록해 조회하고 자금을 이동할 수 있었다.
공통 API는 금융 product를 만들기 쉽게 했지만 호출만 연결하면 끝나는 일은 아니었다. 이용자 동의와 인증, token과 key 관리, 거래 한도, 중복 요청 방지, 장애 시 원장 상태 확인, 이상 거래 탐지와 개인정보 보호가 함께 필요했다. 이체 요청이 timeout됐을 때 단순 재시도하면 이중 출금으로 이어질 수 있으므로 idempotency와 reconciliation이 특히 중요했다.
오픈뱅킹은 은행의 모든 내부 system과 data를 공개한 제도가 아니었다. 정해진 참가 자격과 기능, 보안 기준 아래 공동 결제망을 개방한 것이었다. 그럼에도 금융회사가 독점하던 연결 기반 시설을 fintech 기업도 같은 API로 사용할 수 있게 되면서 금융 서비스의 경쟁 단위가 지점과 계좌에서 application 경험으로 더 빠르게 이동했다.
2019년의 의미
2019년의 공통된 방향은 복잡한 기반 기술을 개발자가 다룰 수 있는 일관된 interface로 바꾸는 것이었다. TensorFlow 2.0은 즉시 실행과 Keras로 기계학습 code를 Python의 흐름에 가깝게 만들었고, React Hooks는 UI 상태와 effect를 함수 조합으로 표현했다. WebAuthn은 hardware authenticator와 공개 키 인증을 browser API 뒤에 연결했다.
GitHub Actions는 repository event와 CI/CD를 하나의 workflow로 묶었고 Kubernetes의 CRD는 application 운영 규칙을 API resource로 확장할 수 있게 했다. Android의 Kotlin-first 방침은 platform이 언어와 tool의 우선순위를 명시해 개발 경험을 이끄는 모습을 보여줬다.
국내의 5G 스마트폰 개통은 새 network가 실제 소비자 환경에 들어온 사건이었고, 오픈뱅킹은 금융 공동망을 application이 사용할 수 있는 API로 바꾼 사건이었다. 2020년에는 코로나19로 remote work와 online service 수요가 급격히 커지는 가운데, 이 자동화·cloud·API 기반이 예상보다 훨씬 큰 규모의 사회 활동을 떠받치게 된다.
참고 자료
- React, React v16.8: The One With Hooks
- React, Rules of Hooks
- TensorFlow Blog, TensorFlow 2.0 is now available
- TensorFlow Blog, What’s coming in TensorFlow 2.0
- GitHub, GitHub Actions is generally available
- GitHub, GitHub Actions now supports CI/CD
- W3C, W3C and FIDO Alliance Finalize Web Standard for Secure, Passwordless Logins
- W3C, Web Authentication Level 1 publication history
- Android Developers Blog, Google I/O 2019: Empowering developers to build the best experiences on Android and Play
- Android Developers Blog, Android’s commitment to Kotlin
- Kubernetes, Kubernetes 1.14 release announcement
- Kubernetes, Kubernetes 1.16: Custom Resources, Overhauled Metrics, and Volume Extensions
- 대한민국 정책브리핑, 혁신성장 실현을 위한 5G+ 전략
- 금융위원회, 은행과 핀테크 기업 모두가 참여하는 오픈뱅킹 서비스가 전면 시행됩니다
- 금융위원회, Open Banking Launched in Banking Sector