diff --git a/404.html b/404.html index a77c7aef..c1c9a109 100644 --- a/404.html +++ b/404.html @@ -18,8 +18,8 @@
Skip to content

404

PAGE NOT FOUND

But if you don't change your direction, and if you keep looking, you may end up where you are heading.
- + \ No newline at end of file diff --git a/AoC/2022/day1.html b/AoC/2022/day1.html index 3b85baab..b41016a8 100644 --- a/AoC/2022/day1.html +++ b/AoC/2022/day1.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 1

javascript

problem 1

javascript
Math.max(...$('pre').textContent.split('\n\n').map(elfCalories => elfCalories.split('\n').map(Number).reduce((a, b) => a + b)))

problem 2

javascript
input.split('\n\n').map(elfCalories => elfCalories.split('\n').map(Number).reduce((a, b) => a + b)).sort((a, b) => a - b).slice(-3).reduce((a, b) => a + b)

rust

rust
use std::fs;
+    
Skip to content
On this page

day 1

javascript

problem 1

javascript
Math.max(...$('pre').textContent.split('\n\n').map(elfCalories => elfCalories.split('\n').map(Number).reduce((a, b) => a + b)))

problem 2

javascript
input.split('\n\n').map(elfCalories => elfCalories.split('\n').map(Number).reduce((a, b) => a + b)).sort((a, b) => a - b).slice(-3).reduce((a, b) => a + b)

rust

rust
use std::fs;
 
 fn main(){
     let contents = fs::read_to_string("./day1-1.txt")
@@ -53,8 +53,8 @@
 
     println!("{max_calory}");
 }
- + \ No newline at end of file diff --git a/AoC/2022/day2.html b/AoC/2022/day2.html index 79e991f1..cde00512 100644 --- a/AoC/2022/day2.html +++ b/AoC/2022/day2.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 2

problem 1

javascript
$('pre').textContent.trim().split('\n').map(calculateScore).reduce((x, y) => x + y)
+    
Skip to content
On this page

day 2

problem 1

javascript
$('pre').textContent.trim().split('\n').map(calculateScore).reduce((x, y) => x + y)
 
 function calculateScore(input){
     const scores = {
@@ -90,8 +90,8 @@
             return 'Y'
     }
 }
- + \ No newline at end of file diff --git a/AoC/2022/day3.html b/AoC/2022/day3.html index 8a18d9a1..2c5de65e 100644 --- a/AoC/2022/day3.html +++ b/AoC/2022/day3.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 3

problem 1

javascript
function getScore(char){
+    
Skip to content
On this page

day 3

problem 1

javascript
function getScore(char){
     const rawAsciiCode = char.charCodeAt(0);
 
     if (rawAsciiCode > 96){
@@ -45,8 +45,8 @@
 $('pre').textContent.match(/([a-zA-Z]*?\n){3}/g).map(s => s.trim().split('\n').reduce((a, c) => {
     return c.match(new RegExp(`[${a}]`, 'g')).join('')
 })).map(s => s[0]).map(getScore).reduce((a, b) => a + b)
- + \ No newline at end of file diff --git a/AoC/2022/day4.html b/AoC/2022/day4.html index 7529d923..caa0134d 100644 --- a/AoC/2022/day4.html +++ b/AoC/2022/day4.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 1

problem 1

javascript
function getIfFullContains(s){
+    
Skip to content
On this page

day 1

problem 1

javascript
function getIfFullContains(s){
     const [f, b] = s.split(',');
     const longest = Math.max(...[f, b].map(s => s.split('-').map(Number).reduce((a, b) => b - a)))
     const minMin = Math.min(...[f, b].map(s => s.split('-').map(Number)[0]))
@@ -46,8 +46,8 @@
 }
 
 $('pre').textContent.trim().split('\n').filter(_ => _).map(getIfOverlapped).filter(_ => _).length
- + \ No newline at end of file diff --git a/AoC/2022/day5.html b/AoC/2022/day5.html index 5d7cf216..a182a1f7 100644 --- a/AoC/2022/day5.html +++ b/AoC/2022/day5.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 5

problem 1

javascript
const [stacks, inputs] = $('pre').textContent.split('\n\n');
+    
Skip to content
On this page

day 5

problem 1

javascript
const [stacks, inputs] = $('pre').textContent.split('\n\n');
 
 const rearrangedStacks = stacks.split('\n').map(line => line.split('').reduce((acc, cur, idx) => {
     if (idx % 4 === 0){
@@ -147,8 +147,8 @@
 
 
 instances.map(s => s.pop()).join('')
- + \ No newline at end of file diff --git a/AoC/2022/day6.html b/AoC/2022/day6.html index be85daf7..b129fab0 100644 --- a/AoC/2022/day6.html +++ b/AoC/2022/day6.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

day 6

problem 1

javascript
function main(signal) {
+    
Skip to content
On this page

day 6

problem 1

javascript
function main(signal) {
     for (let i = 3; i < signal.length; i++){
         const cSet = new Set();
         for (let j = i - 3; j <= i; j++){
@@ -57,8 +57,8 @@
 }
 
 main($('pre').textContent);
- + \ No newline at end of file diff --git a/AoC/2022/index.html b/AoC/2022/index.html index e984cde3..0959f2e9 100644 --- a/AoC/2022/index.html +++ b/AoC/2022/index.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Advent of Code 2022

- +
Skip to content
On this page

Advent of Code 2022

+ \ No newline at end of file diff --git a/archive.html b/archive.html index 5496a523..c442629d 100644 --- a/archive.html +++ b/archive.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

🏛 보관소

개발 소식지

스터디

공간

글, 기사

Tech

Web

Metaverse, Blockchain, Cryptocurrency, NFT, ...

Science

Etc (미분류 포함)

강의

서비스

미분류

Color

Illustration

Editor

Headless CMS

No Code, Low Code

Data

AI

Startups

- +
Skip to content
On this page

🏛 보관소

개발 소식지

스터디

공간

글, 기사

Tech

Web

Metaverse, Blockchain, Cryptocurrency, NFT, ...

Science

Etc (미분류 포함)

강의

서비스

미분류

Color

Illustration

Editor

Headless CMS

No Code, Low Code

Data

AI

Startups

+ \ No newline at end of file diff --git a/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.js b/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.js new file mode 100644 index 00000000..f3fad223 --- /dev/null +++ b/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.js @@ -0,0 +1,23 @@ +import{_ as s,o as a,c as n,O as o}from"./chunks/framework.acd5de9c.js";const h=JSON.parse('{"title":"Next.js 앱 라우터 마이그레이션: 좋은 점, 나쁜 점, 그리고 최악인 점","description":"","frontmatter":{"feArticle":true},"headers":[],"relativePath":"log/nextjs-app-router-migration-the-good-bad-and-ugly.md","filePath":"log/nextjs-app-router-migration-the-good-bad-and-ugly.md","lastUpdated":1709137046000}'),t={name:"log/nextjs-app-router-migration-the-good-bad-and-ugly.md"},e=o(`

Next.js 앱 라우터 마이그레이션: 좋은 점, 나쁜 점, 그리고 최악인 점

원문: https://www.flightcontrol.dev/blog/nextjs-app-router-migration-the-good-bad-and-ugly

29.01.24 | Brandon Bayer

지난해 저희는 Next.js 앱 라우터를 사용하여 Flightcontrol 대시보드를 처음부터 다시 구축했습니다. 이전 대시보드는 Next.js 페이지 라우터로 구축했습니다. 이전 대시보드도 제 기능을 수행했지만, 엔지니어인 제가 디자인한 UI는 프로토타입처럼 느껴졌습니다. 이제 진정한 디자인 재능을 끌어들여 좀 더 성장할 때였습니다.

그래서 Overnice와 협력해 전체 UI를 다시 디자인했습니다. 그들은 놀라운 예술 작품을 디자인했습니다. 저희는 디자인이 마음에 들었지만 Next.js 페이지 라우터로는 구축할 수 없었기 때문에 몇 가지 큰 변경이 필요했습니다. 다시 말해, 중첩 라우팅과 공유 레이아웃이 필요했습니다.

전면적인 재작성이 필요했기 때문에 당시(2023년 4월) 모든 리액트 선택지를 고려했습니다. 선택지로 Next.js 앱 라우터, 리믹스, 진정한 단일 페이지 앱(SPA) 아키텍처를 위한 TanStack Router가 있었습니다. 앱 라우터와 리액트 서버 컴포넌트(RSC)는 리액트의 일부라는 면에서 미래의 기술처럼 느껴졌고, Next.js는 가장 인기 있는 프레임워크였습니다. 아직 최신 기술이지만 장기적으로 가장 안전한 선택지처럼 보였습니다.

RSC는 복잡하고 서버와 클라이언트가 혼합되어 있기 때문에 전통적인 SPA 접근법 또한 매력적입니다. 순수한 클라이언트를 가지면서 백엔드로부터의 명확히 분리하는 건 명백한 이점을 가집니다. 저희는 타입 안전성에 대해 매우 신경을 썼기 때문에, TanStack Router가 유일한 옵션이었습니다. 매우 유망해 보였지만, 당시에는 여전히 알파 단계였고 언제 운영 가능할지 여부도 불분명했습니다.

불행히도, 저희는 Remix를 거의 고려하지 않았습니다. 부분적으로는 이미 Blitz.js 인증과 RPC를 사용하고 있었기 때문입니다. Remix로 이동하려면 Next.js를 사용하면 유지될 수 있는 이 두 부분에서 변경이 필요했습니다.

Next.js 앱 라우터를 선택한 후 작업을 시작했습니다.

Next.js 앱 라우터로 마이그레이션 하기

이어지는 내용은 웹 앱 대시보드에서 직접 앱 라우터를 사용한 경험에 관한 것입니다. 그리고 분명 저희와 다른 사용 사례에서 좋고 나쁜 점들이 더 있을 것입니다.

좋은 점: 레이아웃

저희는 앱을 개발하는 과정에서 오른쪽 사이드 패널 UI와 같이 탐색을 위한 중첩 레이아웃이 필요했습니다. /environment/[envId]는 환경 세부 정보를 보여주고, /environment/[envId]/deployment/[deployId]는 환경 세부 정보 옆에 사이드 패널을 열어주는 스펙이었습니다.

대시보드 UI

이는 페이지 라우터로는 구축할 수 없었지만 앱 라우터에서는 가능했습니다. 각 레이아웃이 유지되므로 형제 페이지 간 탐색 시 부모 레이아웃을 마운트 해제했다가 다시 마운트 하지 않습니다.

그러나 페이지를 중첩할 수 없기 때문에 이 UI를 구축하는 것이 어색하기도 했습니다. 환경 UI는 환경 layout.tsx 안에 있어야 하며, 환경 page.tsx에는 return null만 포함되어야 합니다.

좋은 점: 로딩 상태의 유연성

새 페이지로 이동할 때 리액트 서스펜스를 사용하면, 원하는 사용자 경험에 따라 이전 UI 또는 새 UI에 로딩 스피너를 표시할 수 있습니다. 이 기능은 리액트 기능이며 앱 라우터에서 지원하므로 Next.js에서 사용할 수 있습니다.

새로운 경로로 이동하는 경우의 기존 로딩 스피너는 <Suspense> 경계를 설정하면 쉽게 구현할 수 있습니다.

탐색 후 스피너가 있는 대시보드

새로운 가능성은 링크에 React.useTransition()을 사용하여 기존 UI에 스피너를 표시하는 것입니다. 새 UI가 로드되면 UI가 즉시 전환됩니다. 새 페이지가 백그라운드에서 로드되는 동안 사용자가 유용한 정보를 계속 볼 수 있다는 이점이 있습니다.

탐색 전 스피너가 있는 대시보드

결과적으로 UX는 좋지만, 개발자 경험은 다소 불편합니다.

tsx
import {useTransition} from "react"
+import Link from "next/link"
+import {useRouter} from "next/navigation"
+
+function NavLink() {
+  const [isPending, startTransition] = useTransition()
+  const router = useRouter()
+
+  return <Link 
+            href="/about" 
+            onClick={() => startTransition(() => router.push("/about"))} 
+          >
+            About
+            {isPending && <Spinner />}
+          </Link>
+}

사용자가 브라우저 북마크 등을 통해 해당 페이지로 직접 이동하는 경우 해당 페이지에 스피너를 표시하려면 페이지 주위에 <Suspense>가 필요하다는 점에 유의하세요.

좋은 점: 서버에서 초기 데이터 로딩의 개발자 경험(DX)

리액트 서버 컴포넌트는 주로 초기 데이터 로딩의 DX에 유용하다는 것이 입증되었습니다. 저희는 기본적으로 모든 페이지가 데이터를 로드하고 이를 클라이언트 컴포넌트로 전달하는 서버 컴포넌트로 구성된 패턴을 사용하고 있습니다.

tsx
// page.tsx
+import {ProjectPage} from './ProjectPage'
+import {getProjectData} from '@/domain/project'
+
+export default async function Page() {
+  const projectData = await getProjectData(/*args*/)
+  return <ProjectPage initialData={projectData} />
+}

그런 다음 클라이언트 컴포넌트에서 TanStack Query를 사용하여 폴링을 통한 실시간 데이터 업데이트를 수행합니다. 초기 데이터는 initialData 옵션을 통해 useQuery() 훅에 전달됩니다.

크게 강조했던 것처럼 초기 로드 성능이 더 좋을 것으로 예상했습니다. 하지만 실제로는 이것과 클라이언트 측 데이터 로딩의 차이를 구분할 수 없었습니다.

결국 이 DX는 클라이언트에서 useQuery()가 초기 데이터 가져오기를 수행하는 것보다 약간 더 나쁠 수 있습니다. 클라이언트에서 useQuery()가 초기 데이터 가져오기를 수행하면 initialData를 명시적으로 처리할 필요가 없기 때문입니다.

나쁜 점: 실시간 UI 업데이트를 위해 클라이언트 측 데이터 가져오기를 추가해야 합니다

서버 컴포넌트가 TanStack Query 및 폴링과 동일한 stale-while-revalidate 시맨틱을 지원할 수 있어야 한다고 보입니다. 하지만 Next.js에서는 그렇지 않습니다.

이를 위해 클라이언트 측 데이터 가져오기를 추가해야 합니다. 그리고 저희는 UI의 거의 모든 부분에 이 기능을 원합니다. 이에 따라 서버 측 데이터 로딩에 대한 이전 섹션에서 언급했듯이 많은 중복이 발생합니다.

나쁜 점: 서버 측 오류가 쉽게 무시되거나 숨겨집니다

서버에서 오류가 발생했는데 적절한 위치에 <ErrorBoundary />를 추가하지 않은 경우, 서버는 대신 서스펜스 폴백을 렌더링하고 클라이언트에서 해당 페이지를 다시 렌더링 하려고 시도합니다.

이로 인해 오류가 발생하고 기록되지만 UI는 정상적으로 작동하는 것처럼 보입니다. 전반적으로 매우 혼란스럽고 추적하기 어렵습니다.

나쁜 점: 경로 이동 종료 애니메이션을 구현할 수 없습니다

저희는 Framer Motion을 사용해 애니메이션을 구현하고 있습니다. 진입 애니메이션에는 잘 작동하지만, 종료 애니메이션의 경우 Next.js가 완전히 강제 종료됐습니다.

Framer Motion은 제 역할을 하고 있지만, Next.js는 이전 레이아웃 id를 유지하지 않고 자식 컴포넌트를 너무 일찍 제거합니다.

나쁜 점: 라우팅 타입 안전성 부족합니다

Next.js에는 실험적으로 타입 안전성이 내장되어 있지만 많은 제한이 있습니다.

다행히도 사용자 환경에서 이를 구현하는 것은 그리 어렵지 않습니다. 다른 게시물을 통해 전체 라우팅 유형 안전을 위한 전체 복사 붙여 넣기가 가능한 구현을 공유합니다.

최악인 점: 개발 서버 성능이 형편없습니다

9개월 전보다는 훨씬 나아졌지만, 여전히 용납할 수 없을 정도로 느립니다.

한 엔지니어는 "개발 서버 성능이 너무 나빠서, 좋은 기능을 모두 포기하고 싶은 정도입니다. Next.js 개발 서버를 피하고자 다른 프레임워크로 전환할 수도 있습니다. 심지어 다른 언어로 전환할 수도 있습니다. 그만큼 Next.js의 앱 라우터 사용이 싫습니다."

최악인 점: 개발 서버 메모리 누수

20분마다 개발 서버가 강제 종료되어 다시 시작해야 합니다. 그리고 강제 종료되기 전에도 변경 사항을 만들면 점점 느려집니다.

최악인 점: 오류를 추적하기 어렵습니다

오류가 발생하는 경우 대부분 매우 모호하고 추적할 수 있는 호출 스택이 없습니다. 한 번에 앱의 절반을 삭제하는 바이너리 검색과 같은 식으로 시도해 봐야 합니다.

next.js 하이드레이션 오류

next.js 동적 서버 사용 오류

최악인 점: 프로덕션 마케팅의 시기상조

실제로 운영 환경에서 사용할 수 있게 되기 위해서 운영 준비가 완료된 후 거의 1년이 지나야 했습니다. 초기에는 버그와 문제가 너무 많았어요. 정말 비참한 상황이었죠. 다행히 지금은 많은 부분이 수정되었지만 아직 씁쓸함이 남아있습니다.

최악인 점: 지나치게 복잡하고 불투명함

위의 모든 것을 종합해 보면 Next.js는 지나치게 복잡하고 불투명하다는 결론에 도달하게 됩니다. 문제가 발생하면 그 이유나 해결 방법을 파악할 방법이 없습니다.

저희는 이 문제를 해결하느라 많은 회사 비용을 낭비한 것이 분명합니다.

주의: 저희는 아직 Next.js 13.5.4를 사용 중입니다

Next.js 14를 사용해 보았지만, 문제가 발생하여 아직 이 업그레이드의 우선순위를 정하지 못했습니다. 14 버전에서 번들링이 크게 변경되어 많은 분이 업그레이드에 어려움을 겪고 있는 것 같습니다.

과거에는 주요 버전 업그레이드가 원활하게 진행되었지만, 이번 버전은 그렇지 않았습니다.

다시 돌아갈 수 있다면 Remix를 선택하겠습니다

훨씬 더 나은 개발 성능 외에도 Remix의 아키텍처와 추상화가 더 뛰어나다고 생각합니다. 예를 들어, Remix에서는 사용자가 클라이언트와 서버 진입점을 소유합니다. 하지만 Next.js는 모든 것을 소유하며, 명시적으로 허용하지 않는 작업은 npm 패치를 사용하지 않는 한 할 수 없었고, 저희는 지속해서 그렇게 해야 했습니다.

물론 Remix에도 나름의 단점이 있긴 하지만, 저희 Next.js 사용자가 처리해야 하는 문제를 보며 Remix 사용자가 믿을 수 없어 하는 모습을 계속 보았습니다. 바라건대 Next.js가 개선 되기를 바랍니다.

리액트 만세!

`,64),l=[e];function p(r,c,i,D,F,y){return a(),n("div",null,l)}const u=s(t,[["render",p]]);export{h as __pageData,u as default}; diff --git a/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.lean.js b/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.lean.js new file mode 100644 index 00000000..4eefe7cb --- /dev/null +++ b/assets/log_nextjs-app-router-migration-the-good-bad-and-ugly.md.5294381e.lean.js @@ -0,0 +1 @@ +import{_ as s,o as a,c as n,O as o}from"./chunks/framework.acd5de9c.js";const h=JSON.parse('{"title":"Next.js 앱 라우터 마이그레이션: 좋은 점, 나쁜 점, 그리고 최악인 점","description":"","frontmatter":{"feArticle":true},"headers":[],"relativePath":"log/nextjs-app-router-migration-the-good-bad-and-ugly.md","filePath":"log/nextjs-app-router-migration-the-good-bad-and-ugly.md","lastUpdated":1709137046000}'),t={name:"log/nextjs-app-router-migration-the-good-bad-and-ugly.md"},e=o("",64),l=[e];function p(r,c,i,D,F,y){return a(),n("div",null,l)}const u=s(t,[["render",p]]);export{h as __pageData,u as default}; diff --git a/debt.html b/debt.html index d2cf9763..6ae336d0 100644 --- a/debt.html +++ b/debt.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

🧱 부채

기술글

글감

Vue.js Google Tag Manager, Google Analytics, UserID 적용

카톡 썸네일, 설명 적용하기

Vue.js use both inline and external SVGs

useEffect 훅에서 async await 문법을 어떻게 사용할지 결정하는 방법

iOS React Native Webview에서 캐시 갱신이 안되는 문제

@media print로 페이지를 프린트에 적합하도록 하기

Vue.js + prettier에서 의도치 않게 생성되는 공백 제거하기 (WhitespaceSensitivity)

heroku + node.js app + google chart로 Vuepress 블로그에 실시간 주식 차트 그리기

Promise, async await등 ES6이상 문법들의 ES5 polyfill과 성능 측정

git alias를 이용한 빠른 핫픽스 브랜치 생성 및 package.json, package-lock.json 버전 업데이트

[alias]

hf = "!function hf(){ git checkout master && v=$(cat package.json | grep -m 1 version | sed 's/[^0-9.]//g'); p=${v##*.}; uP=$((p+1)); mV=${v%.*}.$uP; sed -i '' 's/\"version\": \"'$v'\"/\"version\": \"'$mV'\"/g' package*.json; git checkout -b hotfix/$mV;}; hf"

  • 사내에서 반복적으로 사용하는 hotfix 브랜치 생성 및 package.json 버전 수정을 스크립트화
참고

vite + vue github pages에 배포하기

multiline truncate + with more text

수량 입력 input Vue 컴포넌트 만들기

  • input event 활용
  • DOM에 직접 접근, 값이 변경된 후 발생하는 input 이벤트에서 변경된 값을 덮어주는 방식
  • 실제 데이터, 보여지는 값 2가지 상태를 정의

checklist

  • [ ] 입력되어 있는 값을 지울 수 있다.
  • [ ] 0으로 시작하지 않는 숫자, 빈 값만 입력 가능하다.
  • [ ] 변경 중에는 데이터에 반영되지 않는다.
  • [ ] focus가 벗어날 때 데이터에 반영된다.
  • [ ] 최대 구매 수량을 초과한 경우, 최소 구매 수량 미만인 경우 tooltip message 를 띄우도록 한다.
  • [ ] 최대 구매 수량을 초과한 경우 focus를 벗어날 때 최대 구매 수량으로 변경된다.
  • [ ] 최소 구매 수량 미만인 경우 focus를 벗어날 때 최소 구매 수량으로 변경된다.

참고

strapi aws에 구성하기

ec2, postgres rds, s3 bucket

mix-blend-mode 속성 사용하기

svg에 gradient 색상 적용하기

Vue 3 프로덕션 적용기

AWS Lambda + Puppteeer (with Serverless Framework)로 주기적인 Scraping하기

How to deploy fastify server to fly.io (fly.io에 fastify 서버 배포하는 방법)

follow the instructions

  1. install flyctl

https://fly.io/docs/hands-on/install-flyctl/

bash
curl -L https://fly.io/install.sh | sh

or (Mac OS)

bash
brew install flyctl
  1. create or login to fly.io account

https://fly.io/docs/speedrun/

bash
fly auth signup

or

bash
fly auth login
  1. launch
bash
flyctl launch

you can choose app name, region.

bash
? Choose an app name (leave blank to generate one): [your-app-name]
+    
Skip to content
On this page

🧱 부채

기술글

글감

Vue.js Google Tag Manager, Google Analytics, UserID 적용

카톡 썸네일, 설명 적용하기

Vue.js use both inline and external SVGs

useEffect 훅에서 async await 문법을 어떻게 사용할지 결정하는 방법

iOS React Native Webview에서 캐시 갱신이 안되는 문제

@media print로 페이지를 프린트에 적합하도록 하기

Vue.js + prettier에서 의도치 않게 생성되는 공백 제거하기 (WhitespaceSensitivity)

heroku + node.js app + google chart로 Vuepress 블로그에 실시간 주식 차트 그리기

Promise, async await등 ES6이상 문법들의 ES5 polyfill과 성능 측정

git alias를 이용한 빠른 핫픽스 브랜치 생성 및 package.json, package-lock.json 버전 업데이트

[alias]

hf = "!function hf(){ git checkout master && v=$(cat package.json | grep -m 1 version | sed 's/[^0-9.]//g'); p=${v##*.}; uP=$((p+1)); mV=${v%.*}.$uP; sed -i '' 's/\"version\": \"'$v'\"/\"version\": \"'$mV'\"/g' package*.json; git checkout -b hotfix/$mV;}; hf"

  • 사내에서 반복적으로 사용하는 hotfix 브랜치 생성 및 package.json 버전 수정을 스크립트화
참고

vite + vue github pages에 배포하기

multiline truncate + with more text

수량 입력 input Vue 컴포넌트 만들기

  • input event 활용
  • DOM에 직접 접근, 값이 변경된 후 발생하는 input 이벤트에서 변경된 값을 덮어주는 방식
  • 실제 데이터, 보여지는 값 2가지 상태를 정의

checklist

  • [ ] 입력되어 있는 값을 지울 수 있다.
  • [ ] 0으로 시작하지 않는 숫자, 빈 값만 입력 가능하다.
  • [ ] 변경 중에는 데이터에 반영되지 않는다.
  • [ ] focus가 벗어날 때 데이터에 반영된다.
  • [ ] 최대 구매 수량을 초과한 경우, 최소 구매 수량 미만인 경우 tooltip message 를 띄우도록 한다.
  • [ ] 최대 구매 수량을 초과한 경우 focus를 벗어날 때 최대 구매 수량으로 변경된다.
  • [ ] 최소 구매 수량 미만인 경우 focus를 벗어날 때 최소 구매 수량으로 변경된다.

참고

strapi aws에 구성하기

ec2, postgres rds, s3 bucket

mix-blend-mode 속성 사용하기

svg에 gradient 색상 적용하기

Vue 3 프로덕션 적용기

AWS Lambda + Puppteeer (with Serverless Framework)로 주기적인 Scraping하기

How to deploy fastify server to fly.io (fly.io에 fastify 서버 배포하는 방법)

follow the instructions

  1. install flyctl

https://fly.io/docs/hands-on/install-flyctl/

bash
curl -L https://fly.io/install.sh | sh

or (Mac OS)

bash
brew install flyctl
  1. create or login to fly.io account

https://fly.io/docs/speedrun/

bash
fly auth signup

or

bash
fly auth login
  1. launch
bash
flyctl launch

you can choose app name, region.

bash
? Choose an app name (leave blank to generate one): [your-app-name]
 automatically selected personal organization: [your-username]
 ? Choose a region for deployment:  [Use arrows to move, type to filter]
   Ashburn, Virginia (US) (iad)
@@ -43,8 +43,8 @@
   try {
     await fastify.listen(8080,"0.0.0.0")
 ...
  1. 🎉 deploy
flyctl deploy

- + \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index bb467ebb..ffdb7dcc 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"index.md":"c414429b","aoc_2022_day3.md":"3873e731","aoc_2022_day4.md":"403106cd","aoc_2022_index.md":"0f06f334","aoc_2022_day5.md":"da6816e9","aoc_2022_day1.md":"8e47c488","log_experimenting-with-measuring-soft-navigations.md":"c4fb68a8","aoc_2022_day2.md":"d790b2ab","debt.md":"4c88fb36","log_short_ndc-keynotes-evolution-of-blockchain-and-virtual-reality.md":"c8fd0a43","log_making-cloudflare-for-web.md":"bb51efba","log_short_four-eras-of-javascript-frameworks.md":"07770183","log_short_prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.md":"4b9acc76","log_announcing-vue-3-4.md":"ba12bae4","aoc_2022_day6.md":"da2bb4a5","log_short_og-image-generation.md":"b0478e21","log_making-javascript-run-fast-on-webassembly.md":"3483ffd1","log_how-core-web-vital-affect-seo.md":"9f9dff93","log_fully-typed-web-apps.md":"be74a8bd","log_the-saga-of-the-closure-compiler-and-why-typescript-won.md":"7c176b0c","log_short_toss-slash22-react-native-for-super-high-productivity.md":"1eb658a8","log_patterns-for-reactivity-with-modern-vanilla-javascript.md":"db6c5f87","posts_how-to-apply-utterances-on-vitepress.md":"42fe356f","archive.md":"998f7bb8","log_virtual-dom-back-in-block.md":"9270ada7","log_short_state-of-vue-2022-amsterdam-recap.md":"679f2865","log_why-you-should-be-using-vue-new-composition-api.md":"6029c5d3","log_what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.md":"6c76c40b","log_things-you-forgot-or-never-knew-because-of-react.md":"f0c56b30","log_avoid-these-common-pitfalls-of-react-usestate.md":"7b868ac9","log_what-if-we-had-local-first-software.md":"e3ef9bb6","log_why-we-create-the-composition-api.md":"96e275de","study_refactoring_chapter10.md":"51cb07d9","reading.md":"caf68390","log_web-push-for-web-apps-on-ios-and-ipados.md":"8dbd1e5f","study_refactoring_chapter11.md":"df5e9bc6","study_refactoring_chapter12.md":"1d68ac01","study_leetcode.md":"a8e54567","posts_how-to-generate-sitemap-xml-for-vitepress.md":"bc2c0daf","study_refactoring_chapter1.md":"93fff564","study_brilliant.md":"edcc04b3","study_refactoring_chapter2.md":"2a48a1e8","study_refactoring_chapter3.md":"c0af36f2","study_refactoring_chapter4.md":"d74935fb","study_refactoring_chapter8.md":"79a1800e","study_refactoring_intro.md":"ff4f7ede","vim.md":"06042b5c","study_refactoring_chapter6.md":"1ff45830","study_함께자라기.md":"c352e63e","study_자바스크립트 알고리즘 문제풀이.md":"88843ece","study_클린 코드.md":"d76170cd","study_누구나 자료구조와 알고리즘.md":"0f5daad4","study_refactoring_chapter7.md":"bbd604bd"} +{"aoc_2022_index.md":"0f06f334","log_announcing-vue-3-4.md":"ba12bae4","aoc_2022_day6.md":"da2bb4a5","aoc_2022_day1.md":"8e47c488","aoc_2022_day2.md":"d790b2ab","log_short_four-eras-of-javascript-frameworks.md":"07770183","archive.md":"998f7bb8","debt.md":"4c88fb36","log_making-javascript-run-fast-on-webassembly.md":"3483ffd1","aoc_2022_day4.md":"403106cd","aoc_2022_day3.md":"3873e731","index.md":"c414429b","log_nextjs-app-router-migration-the-good-bad-and-ugly.md":"5294381e","log_short_prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.md":"4b9acc76","log_short_toss-slash22-react-native-for-super-high-productivity.md":"1eb658a8","log_short_state-of-vue-2022-amsterdam-recap.md":"679f2865","log_the-saga-of-the-closure-compiler-and-why-typescript-won.md":"7c176b0c","log_why-we-create-the-composition-api.md":"96e275de","log_what-if-we-had-local-first-software.md":"e3ef9bb6","log_things-you-forgot-or-never-knew-because-of-react.md":"f0c56b30","log_virtual-dom-back-in-block.md":"9270ada7","log_why-you-should-be-using-vue-new-composition-api.md":"6029c5d3","study_refactoring_chapter10.md":"51cb07d9","study_leetcode.md":"a8e54567","study_refactoring_chapter4.md":"d74935fb","study_refactoring_chapter1.md":"93fff564","study_refactoring_chapter11.md":"df5e9bc6","study_refactoring_chapter2.md":"2a48a1e8","study_refactoring_chapter3.md":"c0af36f2","aoc_2022_day5.md":"da6816e9","study_refactoring_chapter7.md":"bbd604bd","log_experimenting-with-measuring-soft-navigations.md":"c4fb68a8","log_how-core-web-vital-affect-seo.md":"9f9dff93","log_making-cloudflare-for-web.md":"bb51efba","log_short_ndc-keynotes-evolution-of-blockchain-and-virtual-reality.md":"c8fd0a43","log_fully-typed-web-apps.md":"be74a8bd","log_short_og-image-generation.md":"b0478e21","posts_how-to-apply-utterances-on-vitepress.md":"42fe356f","study_brilliant.md":"edcc04b3","log_what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.md":"6c76c40b","reading.md":"caf68390","log_web-push-for-web-apps-on-ios-and-ipados.md":"8dbd1e5f","study_refactoring_chapter12.md":"1d68ac01","study_refactoring_chapter8.md":"79a1800e","study_함께자라기.md":"c352e63e","study_refactoring_intro.md":"ff4f7ede","study_누구나 자료구조와 알고리즘.md":"0f5daad4","study_클린 코드.md":"d76170cd","vim.md":"06042b5c","posts_how-to-generate-sitemap-xml-for-vitepress.md":"bc2c0daf","log_patterns-for-reactivity-with-modern-vanilla-javascript.md":"db6c5f87","study_자바스크립트 알고리즘 문제풀이.md":"88843ece","study_refactoring_chapter6.md":"1ff45830","log_avoid-these-common-pitfalls-of-react-usestate.md":"7b868ac9"} diff --git a/index.html b/index.html index 12ed90ea..c25930c0 100644 --- a/index.html +++ b/index.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

bohyeon.dev


36개월
동안 웹 프론트엔드 개발자로 일했습니다.

진지하고 깊이 고민하는 성격입니다. 길게 성공하는 서비스에는 좋은 개발환경이 필요하다고 믿습니다.

책과 영화, 게임을 좋아합니다.

- +
Skip to content
On this page

bohyeon.dev


36개월
동안 웹 프론트엔드 개발자로 일했습니다.

진지하고 깊이 고민하는 성격입니다. 길게 성공하는 서비스에는 좋은 개발환경이 필요하다고 믿습니다.

책과 영화, 게임을 좋아합니다.

+ \ No newline at end of file diff --git a/log/announcing-vue-3-4.html b/log/announcing-vue-3-4.html index c8796756..147e6a0f 100644 --- a/log/announcing-vue-3-4.html +++ b/log/announcing-vue-3-4.html @@ -20,14 +20,14 @@ -
Skip to content
On this page

Vue 3.4 발표

원문: https://blog.vuejs.org/posts/vue-3-4

오늘 Vue 3.4 "🏀 슬램덩크"의 출시를 발표하게 되어 기쁩니다!

이번 릴리스에는 상당한 내부 개선이 이루어졌습니다. 특히 템플릿 구문 분석기는 다시 작성되어 2배 빨라졌으며, 이펙트 트리거를 더 정확하고 효율적으로 만드는 리팩터링 된 반응형 시스템을 재구성 했습니다. 또한 defineModel의 안정화, 프로퍼티 바인딩 시 동일한 이름의 새로운 축약어 같은 여러 가지 편의 기능 API 개선 사항도 포함되어 있습니다.

이 글에서는 3.4의 주요 기능에 대한 개요를 소개합니다. 변경 사항의 전체 목록은 Github상의 전체 변경 로그를 참조하세요.


필요한 조치

  1. 3.4의 새로운 기능을 최대한 활용하려면 3.4로 업그레이드할 때 다음 종속성도 함께 업데이트하는 것이 좋습니다.

    • Volar / vue-tsc@^1.8.27 (필수)
    • @vitejs/plugin-vue@^5.0.0 (Vite를 사용하는 경우)
    • nuxt@^3.9.0 (Nuxt를 사용하는 경우)
    • vue-loader@^17.4.0 (웹팩 또는 vue-cli를 사용하는 경우)
  2. Vue와 함께 TSX를 사용하는 경우, 제거됨: 글로벌 JSX 네임스페이스에서 필요한 조치를 확인하세요.

  3. 더 이상 사용되지 않는 기능을 사용하고 있지 않은지 확인하세요(사용하고 있었다면 콘솔에서 이를 알리는 경고를 받았을 것입니다). 이런 기능들은 3.4에서 제거되었을 수 있습니다.

핵심 변경 사항

2배 빨라진 구문 분석기 및 향상된 SFC 빌드 성능

내용: PR#9674

3.4에서는 템플릿 구문 분석기를 완전히 재작성했습니다. 이전에는 많은 정규식과 선행 검색에 의존하는 재귀적 하강 구문 분석기를 사용했습니다. 새로운 구문 분석기는 전체 템플릿 문자열을 한 번만 반복하는 htmlparser2의 토크나이저를 기반으로 하는 상태 머신 토크나이저를 사용합니다. 그 결과 모든 크기의 템플릿에서 일관되게 두 배 빠른 구문 분석기가 탄생했습니다. 광범위한 테스트 사례와 ecosystem-ci 덕분에 Vue 최종 사용자를 위한 100% 이전 버전과 호환됩니다.

새로운 구문 분석기를 시스템의 다른 부분과 통합하는 동안 전반적인 SFC 컴파일 성능을 더욱 향상할 수 있는 몇 가지 기회도 발견했습니다. 벤치마크에 따르면 소스 맵을 생성하는 동안 Vue SFC의 스크립트 및 템플릿 부분을 컴파일할 때 약 44% 개선된 것으로 나타났으므로 3.4를 사용하면 Vue SFC를 사용하는 대부분의 프로젝트에서 빌드 속도가 빨라질 것입니다. 하지만 실제 프로젝트에서 Vue SFC 컴파일은 전체 빌드 프로세스의 한 부분일 뿐이라는 점에 유의하세요. 종단 간 빌드 시간의 최종 개선 효과는 분리된 벤치마크에 비해 훨씬 작을 수 있습니다.

Vue 코어 외에도 새로운 구문 분석기는 Volar/Vue-tsc 및 Vue SFC 또는 템플릿을 구문 분석해야 하는 커뮤니티 플러그인(예: Vue 매크로)의 성능에도 도움이 될 것입니다.

더 효율적인 반응형 시스템

내용: PR#5912

3.4에서는 computed 프로퍼티의 재계산 효율성을 개선하기 위해 반응형 시스템을 대폭 리팩터링 했습니다.

개선된 내용을 설명하기 위해 다음 시나리오를 예로 들어보겠습니다.

js
const count = ref(0)
+    
Skip to content
On this page

Vue 3.4 발표

원문: https://blog.vuejs.org/posts/vue-3-4

오늘 Vue 3.4 "🏀 슬램덩크"의 출시를 발표하게 되어 기쁩니다!

이번 릴리스에는 상당한 내부 개선이 이루어졌습니다. 특히 템플릿 구문 분석기는 다시 작성되어 2배 빨라졌으며, 이펙트 트리거를 더 정확하고 효율적으로 만드는 리팩터링 된 반응형 시스템을 재구성 했습니다. 또한 defineModel의 안정화, 프로퍼티 바인딩 시 동일한 이름의 새로운 축약어 같은 여러 가지 편의 기능 API 개선 사항도 포함되어 있습니다.

이 글에서는 3.4의 주요 기능에 대한 개요를 소개합니다. 변경 사항의 전체 목록은 Github상의 전체 변경 로그를 참조하세요.


필요한 조치

  1. 3.4의 새로운 기능을 최대한 활용하려면 3.4로 업그레이드할 때 다음 종속성도 함께 업데이트하는 것이 좋습니다.

    • Volar / vue-tsc@^1.8.27 (필수)
    • @vitejs/plugin-vue@^5.0.0 (Vite를 사용하는 경우)
    • nuxt@^3.9.0 (Nuxt를 사용하는 경우)
    • vue-loader@^17.4.0 (웹팩 또는 vue-cli를 사용하는 경우)
  2. Vue와 함께 TSX를 사용하는 경우, 제거됨: 글로벌 JSX 네임스페이스에서 필요한 조치를 확인하세요.

  3. 더 이상 사용되지 않는 기능을 사용하고 있지 않은지 확인하세요(사용하고 있었다면 콘솔에서 이를 알리는 경고를 받았을 것입니다). 이런 기능들은 3.4에서 제거되었을 수 있습니다.

핵심 변경 사항

2배 빨라진 구문 분석기 및 향상된 SFC 빌드 성능

내용: PR#9674

3.4에서는 템플릿 구문 분석기를 완전히 재작성했습니다. 이전에는 많은 정규식과 선행 검색에 의존하는 재귀적 하강 구문 분석기를 사용했습니다. 새로운 구문 분석기는 전체 템플릿 문자열을 한 번만 반복하는 htmlparser2의 토크나이저를 기반으로 하는 상태 머신 토크나이저를 사용합니다. 그 결과 모든 크기의 템플릿에서 일관되게 두 배 빠른 구문 분석기가 탄생했습니다. 광범위한 테스트 사례와 ecosystem-ci 덕분에 Vue 최종 사용자를 위한 100% 이전 버전과 호환됩니다.

새로운 구문 분석기를 시스템의 다른 부분과 통합하는 동안 전반적인 SFC 컴파일 성능을 더욱 향상할 수 있는 몇 가지 기회도 발견했습니다. 벤치마크에 따르면 소스 맵을 생성하는 동안 Vue SFC의 스크립트 및 템플릿 부분을 컴파일할 때 약 44% 개선된 것으로 나타났으므로 3.4를 사용하면 Vue SFC를 사용하는 대부분의 프로젝트에서 빌드 속도가 빨라질 것입니다. 하지만 실제 프로젝트에서 Vue SFC 컴파일은 전체 빌드 프로세스의 한 부분일 뿐이라는 점에 유의하세요. 종단 간 빌드 시간의 최종 개선 효과는 분리된 벤치마크에 비해 훨씬 작을 수 있습니다.

Vue 코어 외에도 새로운 구문 분석기는 Volar/Vue-tsc 및 Vue SFC 또는 템플릿을 구문 분석해야 하는 커뮤니티 플러그인(예: Vue 매크로)의 성능에도 도움이 될 것입니다.

더 효율적인 반응형 시스템

내용: PR#5912

3.4에서는 computed 프로퍼티의 재계산 효율성을 개선하기 위해 반응형 시스템을 대폭 리팩터링 했습니다.

개선된 내용을 설명하기 위해 다음 시나리오를 예로 들어보겠습니다.

js
const count = ref(0)
 const isEven = computed(() => count.value % 2 === 0)
 
 watchEffect(() => console.log(isEven.value)) // true라고 로그에 기록됩니다.
 
 count.value = 2 // 다시 true라고 로그에 기록됩니다.

3.4 이전에는 계산된 결과가 동일하게 유지되더라도 count.value가 변경될 때마다 watchEffect의 콜백이 실행되었습니다. 3.4 이후 최적화를 통해 이제 계산된 결과가 실제로 변경된 경우에만 콜백이 실행됩니다.

또한 3.4에서는

  • 여러 개의 computed 의존성 변경이 동기 효과를 단 한 번만 트리거합니다.
  • 배열의 shift, unshift, splice 메서드도 동기 효과를 단 한 번만 트리거합니다.

이러한 변경사항은 벤치마크에서 보이는 성능 향상 외에도, 이전 버전과 호환을 완벽하게 유지하면서도 많은 시나리오에서 불필요한 컴포넌트 재렌더링을 줄일 것입니다.

defineModel이 안정화되었습니다.

내용: RFC#503

defineModelv-model을 지원하는 컴포넌트의 구현을 간소화하기 위한 새로운 <script setup> 매크로입니다. 3.3에서 실험적 기능으로 제공되었고 3.4에서 안정적인 상태로 업그레이드되었습니다. 이제 v-model 수정자와 함께 사용할 수 있도록 더 나은 지원을 제공합니다.

관련 문서:

v-bind 동일 명칭 축약어

내용: PR#9451

이제 아래와 같은 코드를 더 간결하게 단축할 수 있습니다.

html
<img :id="id" :src="src" :alt="alt">

단축하면 아래와 같이 표현됩니다.

html
<img :id :src :alt>

이 기능은 과거에 자주 요청되었던 기능입니다. 원래는 부울 속성과 혼동될 수 있다는 우려가 있었습니다. 그러나 이 기능을 다시 검토한 결과, v-bind의 동적 특성을 고려할 때 기본 속성보다 자바스크립트처럼 동작하는 것이 더 합리적이라고 판단했습니다.

하이드레이션 불일치 오류 개선

내용: PR#5953

3.4 버전에서는 하이드레이션 불일치 오류 메시지가 여러 면에서 개선되었습니다.

  1. 표현의 명확성이 개선되었습니다(서버에서 렌더링 되는 것과 클라이언트에서 예상되는 것).
  2. 이제 메시지에 해당 DOM 노드가 포함되어 페이지 또는 요소 패널에서 해당 노드를 빠르게 찾을 수 있습니다.
  3. 이제 클래스, 스타일 및 기타 동적으로 바인딩된 속성에 대해서도 하이드레이션 불일치 검사가 적용됩니다.

또한 3.4에는 새로운 컴파일 타임 플래그인 __VUE_PROD_HYDRATION_MISMATCH_DETAILS__가 추가되어 운영 환경에서도 하이드레이션 불일치 오류에 전체 세부 정보를 포함하도록 강제할 수 있습니다.

오류 코드 및 컴파일 시간 플래그 참조

번들 크기를 줄이기 위해 Vue는 운영 환경 빌드 시 긴 오류 메시지 문자열을 삭제합니다. 이것은 Vue의 소스 코드를 자세히 살펴보지 않고는 해독하기 어려운 짧은 오류 코드가 운영 환경에서 오류 핸들러에 의해 포착된다는 것을 의미합니다.

이를 개선하기 위해 문서에 운영 오류 참조 페이지를 추가했습니다. 오류 코드는 최신 버전의 Vue 안정 릴리스에서 자동으로 생성됩니다.

또한 다양한 빌드 도구에 대해 이러한 플래그를 구성하는 방법에 대한 지침이 포함된 컴파일 시간 플래그 참조를 추가했습니다.

사용되지 않는 기능 제거

전역 JSX 네임스페이스

3.4부터 Vue는 더 이상 글로벌 JSX 네임스페이스를 기본적으로 등록하지 않습니다. 이는 리액트와의 글로벌 네임스페이스 충돌을 방지하여 두 라이브러리의 JSX가 동일한 프로젝트에 공존할 수 있도록 하기 위해 필요합니다. 이는 최신 버전의 Volar를 사용하는 SFC 전용 사용자에게는 영향을 미치지 않습니다.

TSX를 사용하는 경우에는 두 가지 옵션이 있습니다.

  1. 3.4로 업그레이드하기 전에 tsconfig.json에서 jsxImportSource'vue'로 명시적으로 설정합니다. 또는 파일 상단에 /* @jsxImportSource vue */ 주석을 추가하여 파일별로 옵트인(opt-in)할 수도 있습니다.

  2. 전역 JSX 네임스페이스의 존재 여부에 따라 달라지는 코드(예: JSX.Element 등의 유형 사용)가 있는 경우 전역 JSX 네임스페이스를 등록하는 vue/jsx를 명시적으로 참조하여 3.4 이전의 전역 동작을 유지할 수 있습니다.

이 변경사항은 마이너 릴리스에서의 타입스크립트에만 호환성이 손상되는 변경사항(breaking changes)으로, 우리의 릴리스 정책을 준수합니다.

기타 제거된 기능

  • 반응형 변환(Reactivity Transform)은 3.3에서 더 이상 사용되지 않는 것으로 표시되었고, 3.4에서 제거되었습니다. 이 기능은 실험적인 기능이기 때문에 메이저 변경이 필요하지 않습니다. 이 기능을 계속 사용하려는 사용자는 Vue 매크로 플러그인을 통해 사용할 수 있습니다.
  • app.config.unwrapInjectedRef가 제거되었습니다. 이 기능은 3.3에서 더 이상 사용되지 않으며 기본적으로 활성화되었습니다. 3.4에서는 더 이상 이 동작을 비활성화할 수 없습니다.
  • 템플릿의 @vnodeXXX 이벤트 리스너는 이제 더 이상 사용되지 않음을 경고하는 것이 아니라 컴파일러 오류가 발생합니다. 대신 @vue:XXX 리스너를 사용하세요.
  • v-is 지시어가 제거되었습니다. 3.3에서 더 이상 사용되지 않습니다. 대신 vue: 접두사가 있는 is 속성을 사용하세요.
- + \ No newline at end of file diff --git a/log/avoid-these-common-pitfalls-of-react-usestate.html b/log/avoid-these-common-pitfalls-of-react-usestate.html index 4f9100e0..5bf050f6 100644 --- a/log/avoid-these-common-pitfalls-of-react-usestate.html +++ b/log/avoid-these-common-pitfalls-of-react-usestate.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

리액트에서 useState를 사용하면서 저지를 수 있는 흔한 실수들

원문: https://profy.dev/article/react-usestate-pitfalls

useState는 가장 자주 사용하는 리액트 훅입니다. 자주 사용하기 때문에 몇 가지 흔한 실수를 경험하곤 합니다.

당신은 아마도 그중 일부를 경험했을 것입니다 (인지하지 못했더라도). 불필요하거나, 중복되거나, 모순되는 상태를요. 이 때문에 실제로는 쓸모없는 useEffect가 존재할 수도 있습니다. 그리고 이 모든 결합은 유지 관리가 불가능하고 읽기 어려운 코드로 만드는 큰 함정이 될 수 있습니다.

이런 함정들에 대해 알면 다음과 같은 도움이 됩니다.

  • 코드를 더 쉽게 읽고 유지 관리할 수 있습니다.
  • 버그가 덜 발생하는 코드를 생성할 수 있습니다.
  • 많은 코드 복잡성을 제거할 수 있습니다.

잊지 마세요. 채용 과정의 코딩 과제에서 난처한 함정에 쉽게 빠진다는 의미는 아닙니다. 문제는 useState와 관련된 잠재적인 문제들을 피하기 위해서는 먼저 그에 대해 인식하고 있어야 한다는 점입니다.

따라서 이 페이지에서는 리액트에서 상태와 관련하여 가장 일반적인 함정을 살펴보겠습니다. 그들 각각에 대해 아래와 같이 내용을 구성했습니다.

  • 코드 예제
  • 자세한 문제 설명
  • 해결책 및
  • 실제 리팩토링 연습

이 글을 읽고 연습을 거친 후에는 자신의 코드를 다른 방식으로 보게 될 것입니다.

불필요한 상태

필요하지 않은 상태 변수는 주니어 개발자가 작성한 코드에서 가장 흔한 문제 중 하나입니다. 하나의 상태가 다른 상태 변수에 종속될 때 주로 발생합니다.

간단한 예시를 드는 것이 상황을 설명하는 가장 좋은 방법일 것입니다. 그러면 바로 들어가 보겠습니다.

코드 예제

다음은 사용자가 이름과 성을 편집할 수 있는 간단한 컴포넌트입니다. 입력값에 따라 전체 이름이 렌더링 됩니다.

불필요한 상태를 발견하셨나요?

jsx
import { useState } from "react";
+    
Skip to content
On this page

리액트에서 useState를 사용하면서 저지를 수 있는 흔한 실수들

원문: https://profy.dev/article/react-usestate-pitfalls

useState는 가장 자주 사용하는 리액트 훅입니다. 자주 사용하기 때문에 몇 가지 흔한 실수를 경험하곤 합니다.

당신은 아마도 그중 일부를 경험했을 것입니다 (인지하지 못했더라도). 불필요하거나, 중복되거나, 모순되는 상태를요. 이 때문에 실제로는 쓸모없는 useEffect가 존재할 수도 있습니다. 그리고 이 모든 결합은 유지 관리가 불가능하고 읽기 어려운 코드로 만드는 큰 함정이 될 수 있습니다.

이런 함정들에 대해 알면 다음과 같은 도움이 됩니다.

  • 코드를 더 쉽게 읽고 유지 관리할 수 있습니다.
  • 버그가 덜 발생하는 코드를 생성할 수 있습니다.
  • 많은 코드 복잡성을 제거할 수 있습니다.

잊지 마세요. 채용 과정의 코딩 과제에서 난처한 함정에 쉽게 빠진다는 의미는 아닙니다. 문제는 useState와 관련된 잠재적인 문제들을 피하기 위해서는 먼저 그에 대해 인식하고 있어야 한다는 점입니다.

따라서 이 페이지에서는 리액트에서 상태와 관련하여 가장 일반적인 함정을 살펴보겠습니다. 그들 각각에 대해 아래와 같이 내용을 구성했습니다.

  • 코드 예제
  • 자세한 문제 설명
  • 해결책 및
  • 실제 리팩토링 연습

이 글을 읽고 연습을 거친 후에는 자신의 코드를 다른 방식으로 보게 될 것입니다.

불필요한 상태

필요하지 않은 상태 변수는 주니어 개발자가 작성한 코드에서 가장 흔한 문제 중 하나입니다. 하나의 상태가 다른 상태 변수에 종속될 때 주로 발생합니다.

간단한 예시를 드는 것이 상황을 설명하는 가장 좋은 방법일 것입니다. 그러면 바로 들어가 보겠습니다.

코드 예제

다음은 사용자가 이름과 성을 편집할 수 있는 간단한 컴포넌트입니다. 입력값에 따라 전체 이름이 렌더링 됩니다.

불필요한 상태를 발견하셨나요?

jsx
import { useState } from "react";
 
 function RedundantState() {
   const [firstName, setFirstName] = useState("");
@@ -445,8 +445,8 @@
   };
 
   ...

이제 ID로 올바른 항목을 찾고 배열에서 교체하기는 쉽습니다.

연습 문제


- + \ No newline at end of file diff --git a/log/experimenting-with-measuring-soft-navigations.html b/log/experimenting-with-measuring-soft-navigations.html index b9e5dca5..947c920b 100644 --- a/log/experimenting-with-measuring-soft-navigations.html +++ b/log/experimenting-with-measuring-soft-navigations.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

소프트 내비게이션 측정 실험하기

원문: https://developer.chrome.com/blog/soft-navigations-experiment/

2023년 2월 1일에 게시됨, 2023년 9월 20일에 업데이트됨

업데이트
소프트 내비게이션 오리진 평가판은 1차 평가판의 피드백을 반영하여 크롬 117에서 두 번째 오리진 평가판을 시작했습니다.

코어 웹 바이탈(Core Web Vitals) 이니셔티브는 출시 이후 웹사이트가 생성되거나 로드되는 방식에 대한 기술적 세부 사항보다는 웹사이트의 실제 사용자 경험을 측정하기 위해 노력해 왔습니다. 코어 웹 바이탈의 세 가지 지표는 사용자가 페이지의 성능을 인지하는 방식과 무관한 시간을 측정하는 DOMContentLoadedload와 같은 기존 기술 지표에서 발전한 사용자 중심 지표로 만들어졌습니다. 따라서 사이트가 잘 작동한다면 사이트 구축에 사용된 기술이 점수에 영향을 미치지 않아야 합니다.

현실은 이상보다 항상 조금 더 까다롭고, 인기 있는 단일 페이지 애플리케이션(Single Page Application) 아키텍처는 코어 웹 바이탈 지표에 의해 완전히 지원된 적이 없습니다. 이러한 웹 애플리케이션은 사용자가 사이트를 탐색할 때 개별 웹 페이지를 로드하는 대신 자바스크립트를 통해 페이지 콘텐츠를 변경하는 이른바 "소프트 내비게이션"을 사용합니다. 이러한 애플리케이션에서는 URL을 변경하고 브라우저의 기록에서 이전 URL을 푸시하여 사용자가 기대하는 대로 뒤로 가기 및 앞으로 가기 버튼이 작동하도록 함으로써 기존 웹 페이지 아키텍처의 환상을 유지합니다.

많은 자바스크립트 프레임워크가 이 모델을 사용하지만 각기 다른 방식으로 사용합니다. 이는 브라우저가 전통적으로 "페이지"로 이해하는 범위를 벗어나기 때문에 이를 측정하는 것은 항상 어려웠습니다. 현재 페이지의 상호작용과 새로운 페이지로 간주하는 것 사이의 경계선을 어디로 설정해야 할까요?

크롬 팀은 이 문제를 오랫동안 고민해 왔으며, "소프트 내비게이션"이 무엇인지에 대한 정의를 표준화하고, 전통적인 다중 페이지 아키텍처(MPA)로 구현된 웹사이트를 측정하는 것과 유사한 방식으로 코어 웹 바이탈 측정 방법을 표준화하기 위해 노력하고 있습니다. 아직 초기 단계에 머물러 있지만, 팀은 이제 이미 구현된 기능을 사이트에서 실험할 수 있도록 더 광범위하게 제공할 준비가 되었습니다. 이를 통해 사이트들은 지금까지의 접근 방식에 대한 피드백을 제공할 수 있을 것입니다.

소프트 내비게이션이란 무엇인가요?

저희는 소프트 내비게이션에 대해 다음과 같은 정의를 내렸습니다.

  • 내비게이션은 사용자의 행동에 의해 시작됩니다.
  • 내비게이션은 사용자에게 URL 변경과 방문 기록(history) 변경을 가져옵니다.
  • 내비게이션은 DOM 변화를 가져옵니다.

일부 사이트의 경우 이러한 휴리스틱이 거짓 긍정(사용자가 실제로 "내비게이션"이 발생한 것으로 간주하지 않는 경우) 또는 거짓 부정(사용자가 위의 기준을 충족하지 않음에도 불구하고 "내비게이션"이 발생한 것으로 간주하는 경우)을 초래할 수 있습니다. 소프트 내비게이션 사양 저장소에서 휴리스틱에 대한 피드백을 환영합니다.

크롬에서는 소프트 내비게이션을 어떻게 구현하나요?

소프트 내비게이션 휴리스틱이 활성화되면(다음 섹션에서 자세히 설명) 크롬에서는 일부 성능 지표를 보고하는 방식이 변경됩니다.

  • 소프트 내비게이션이 감지될 때마다 soft-navigation PerformanceTiming 이벤트가 전송됩니다.
  • 성능 API는 위의 PerformanceTiming 이벤트에서 발생하는 soft-navigation 타이밍 항목에 대한 액세스를 제공합니다.
  • First Paint (FP), First Contentful Paint (FCP), Largest Contentful Paint (LCP) 지표는 초기화되며, 다음 적절한 경우에 다시 발생합니다. (참고: FP 및 FCP는 아직 구현되지 않았습니다.)
  • First Input Delay (FID)가 재설정되고 첫 번째 입력 시 다시 전송됩니다(참고: 아직 구현되지 않았습니다).
  • 이벤트와 관련된 내비게이션 항목에 해당하는 각 성능 타이밍(first-paint, first-contentful-paint, largest-contentful-paint, first-input-delay, eventlayout-shift)에 navigationId 속성이 추가되어 Cumulative Layout Shift (CLS)Interaction to Next Paint (INP)이 계산될 수 있게 됩니다.

이러한 변경 사항을 통해 코어 웹 바이탈 및 일부 관련 진단 지표를 페이지 내비게이션별로 측정할 수 있지만, 고려해야 할 몇 가지 미묘한 차이가 있습니다.

크롬에서 소프트 내비게이션을 활성화하면 어떤 영향이 있나요?

다음은 이 기능을 사용 설정한 후 사이트 소유자가 고려해야 할 몇 가지 변경사항입니다.

  • 소프트 내비게이션을 통해 추가 FP, FCP, LCP 및 FID 이벤트가 다시 전송될 수 있습니다. 크롬 사용자 경험 보고서(CrUX)는 이러한 추가 값을 무시하지만, 사이트의 실제 사용자 측정(RUM) 모니터링에 영향을 줄 수 있습니다. 소프트 내비게이션을 위한 코어 웹 바이탈 측정에 관한 아래 섹션을 참조하세요.
  • 성능 항목의 새로운(그리고 선택 사항인) navigationID 속성은 이러한 항목을 사용하는 애플리케이션 코드에서 고려해야 할 수 있습니다.
  • 이 새로운 모드는 Chromium 기반 브라우저만 지원합니다. 많은 최신 지표는 Chromium 기반 브라우저에서만 사용할 수 있지만, 일부 지표(FCP, FID)는 다른 브라우저에서도 사용할 수 있으며 모든 사용자가 최신 버전의 Chromium 기반 브라우저로 업그레이드한 것은 아닐 수 있습니다. 따라서 일부 사용자는 소프트 내비게이션 지표를 보고하지 않을 수 있다는 점에 유의하세요.
  • 이 기능은 기본적으로 활성화되지 않는 실험적인 새 기능으로, 사이트에서는 의도하지 않은 다른 부작용이 없는지 이 기능을 테스트해야 합니다.

소프트 내비게이션 지표를 측정하는 방법에 대한 자세한 내용은 아래를 참조하세요.

크롬에서 소프트 내비게이션을 사용 설정하려면 어떻게 해야 하나요?

소프트 내비게이션은 크롬에서 기본적으로 활성화되어 있지 않지만, 크롬 110에서 이 기능을 명시적으로 활성화하여 실험용으로 사용할 수 있습니다.

개발자의 경우 chrome://flags/#enable-experimental-web-platform-features에서 실험용 웹 플랫폼 기능 플래그를 사용 설정하거나 크롬을 실행할 때 --enable-experimental-web-platform-features 커맨드 인수를 사용하여 이 기능을 활성화할 수 있습니다.

모든 방문자가 이 기능을 사용하도록 설정하여 영향을 확인하려는 웹사이트의 경우 크롬 117에서 실행되는 오리진 평가판을 신청하고 HTML 또는 HTTP 헤더에 오리진 평가판 토큰이 포함된 메타 요소를 포함시켜 사용하도록 설정할 수 있습니다. 자세한 내용은 오리진 평가판 시작하기 게시물을 참조하세요.

사이트 소유자는 모든 사용자 또는 일부 사용자에 대해서만 페이지에 오리진 평가판을 포함하도록 선택할 수 있습니다. 특히 많은 사용자에 대해 오리진 평가판을 사용하도록 설정하는 경우, 지표 보고 방식이 어떻게 변경되는지 위의 영향도 섹션을 참고하시기 바랍니다. CrUX는 이 소프트 내비게이션 설정과 관계없이 기존 방식으로 계속해서 지표를 보고하므로 이러한 변경의 영향을 받지 않습니다. 또한 오리진 평가판은 14일 동안의 중앙값을 기준으로 전체 크롬 페이지 로드의 최대 0.5%에서만 실험적 기능을 사용하도록 제한되지만, 이는 매우 큰 규모의 사이트에서만 문제가 될 수 있다는 점에 유의해야 합니다.

소프트 내비게이션을 측정하려면 어떻게 해야 하나요?

소프트 내비게이션 실험이 활성화되면 평소와 같이 PerformanceObserver API를 통해 지표가 보고됩니다. 그러나 이러한 지표에 대해 고려해야 할 몇 가지 추가 고려 사항이 있습니다.

참고: 소프트 내비게이션에 대해 현재 FP와 FCP가 보고되지 않으며, FID도 보고되지 않습니다.

소프트 내비게이션 보고하기

PerformanceObserver를 사용하여 소프트 내비게이션을 관찰할 수 있습니다. 다음은 buffered 옵션을 통해 이 페이지의 이전 소프트 내비게이션을 포함하여 소프트 내비게이션 항목을 콘솔에 기록하는 코드 스니펫의 예시입니다.

jsx
const observer = new PerformanceObserver(console.log);
+    
Skip to content
On this page

소프트 내비게이션 측정 실험하기

원문: https://developer.chrome.com/blog/soft-navigations-experiment/

2023년 2월 1일에 게시됨, 2023년 9월 20일에 업데이트됨

업데이트
소프트 내비게이션 오리진 평가판은 1차 평가판의 피드백을 반영하여 크롬 117에서 두 번째 오리진 평가판을 시작했습니다.

코어 웹 바이탈(Core Web Vitals) 이니셔티브는 출시 이후 웹사이트가 생성되거나 로드되는 방식에 대한 기술적 세부 사항보다는 웹사이트의 실제 사용자 경험을 측정하기 위해 노력해 왔습니다. 코어 웹 바이탈의 세 가지 지표는 사용자가 페이지의 성능을 인지하는 방식과 무관한 시간을 측정하는 DOMContentLoadedload와 같은 기존 기술 지표에서 발전한 사용자 중심 지표로 만들어졌습니다. 따라서 사이트가 잘 작동한다면 사이트 구축에 사용된 기술이 점수에 영향을 미치지 않아야 합니다.

현실은 이상보다 항상 조금 더 까다롭고, 인기 있는 단일 페이지 애플리케이션(Single Page Application) 아키텍처는 코어 웹 바이탈 지표에 의해 완전히 지원된 적이 없습니다. 이러한 웹 애플리케이션은 사용자가 사이트를 탐색할 때 개별 웹 페이지를 로드하는 대신 자바스크립트를 통해 페이지 콘텐츠를 변경하는 이른바 "소프트 내비게이션"을 사용합니다. 이러한 애플리케이션에서는 URL을 변경하고 브라우저의 기록에서 이전 URL을 푸시하여 사용자가 기대하는 대로 뒤로 가기 및 앞으로 가기 버튼이 작동하도록 함으로써 기존 웹 페이지 아키텍처의 환상을 유지합니다.

많은 자바스크립트 프레임워크가 이 모델을 사용하지만 각기 다른 방식으로 사용합니다. 이는 브라우저가 전통적으로 "페이지"로 이해하는 범위를 벗어나기 때문에 이를 측정하는 것은 항상 어려웠습니다. 현재 페이지의 상호작용과 새로운 페이지로 간주하는 것 사이의 경계선을 어디로 설정해야 할까요?

크롬 팀은 이 문제를 오랫동안 고민해 왔으며, "소프트 내비게이션"이 무엇인지에 대한 정의를 표준화하고, 전통적인 다중 페이지 아키텍처(MPA)로 구현된 웹사이트를 측정하는 것과 유사한 방식으로 코어 웹 바이탈 측정 방법을 표준화하기 위해 노력하고 있습니다. 아직 초기 단계에 머물러 있지만, 팀은 이제 이미 구현된 기능을 사이트에서 실험할 수 있도록 더 광범위하게 제공할 준비가 되었습니다. 이를 통해 사이트들은 지금까지의 접근 방식에 대한 피드백을 제공할 수 있을 것입니다.

소프트 내비게이션이란 무엇인가요?

저희는 소프트 내비게이션에 대해 다음과 같은 정의를 내렸습니다.

  • 내비게이션은 사용자의 행동에 의해 시작됩니다.
  • 내비게이션은 사용자에게 URL 변경과 방문 기록(history) 변경을 가져옵니다.
  • 내비게이션은 DOM 변화를 가져옵니다.

일부 사이트의 경우 이러한 휴리스틱이 거짓 긍정(사용자가 실제로 "내비게이션"이 발생한 것으로 간주하지 않는 경우) 또는 거짓 부정(사용자가 위의 기준을 충족하지 않음에도 불구하고 "내비게이션"이 발생한 것으로 간주하는 경우)을 초래할 수 있습니다. 소프트 내비게이션 사양 저장소에서 휴리스틱에 대한 피드백을 환영합니다.

크롬에서는 소프트 내비게이션을 어떻게 구현하나요?

소프트 내비게이션 휴리스틱이 활성화되면(다음 섹션에서 자세히 설명) 크롬에서는 일부 성능 지표를 보고하는 방식이 변경됩니다.

  • 소프트 내비게이션이 감지될 때마다 soft-navigation PerformanceTiming 이벤트가 전송됩니다.
  • 성능 API는 위의 PerformanceTiming 이벤트에서 발생하는 soft-navigation 타이밍 항목에 대한 액세스를 제공합니다.
  • First Paint (FP), First Contentful Paint (FCP), Largest Contentful Paint (LCP) 지표는 초기화되며, 다음 적절한 경우에 다시 발생합니다. (참고: FP 및 FCP는 아직 구현되지 않았습니다.)
  • First Input Delay (FID)가 재설정되고 첫 번째 입력 시 다시 전송됩니다(참고: 아직 구현되지 않았습니다).
  • 이벤트와 관련된 내비게이션 항목에 해당하는 각 성능 타이밍(first-paint, first-contentful-paint, largest-contentful-paint, first-input-delay, eventlayout-shift)에 navigationId 속성이 추가되어 Cumulative Layout Shift (CLS)Interaction to Next Paint (INP)이 계산될 수 있게 됩니다.

이러한 변경 사항을 통해 코어 웹 바이탈 및 일부 관련 진단 지표를 페이지 내비게이션별로 측정할 수 있지만, 고려해야 할 몇 가지 미묘한 차이가 있습니다.

크롬에서 소프트 내비게이션을 활성화하면 어떤 영향이 있나요?

다음은 이 기능을 사용 설정한 후 사이트 소유자가 고려해야 할 몇 가지 변경사항입니다.

  • 소프트 내비게이션을 통해 추가 FP, FCP, LCP 및 FID 이벤트가 다시 전송될 수 있습니다. 크롬 사용자 경험 보고서(CrUX)는 이러한 추가 값을 무시하지만, 사이트의 실제 사용자 측정(RUM) 모니터링에 영향을 줄 수 있습니다. 소프트 내비게이션을 위한 코어 웹 바이탈 측정에 관한 아래 섹션을 참조하세요.
  • 성능 항목의 새로운(그리고 선택 사항인) navigationID 속성은 이러한 항목을 사용하는 애플리케이션 코드에서 고려해야 할 수 있습니다.
  • 이 새로운 모드는 Chromium 기반 브라우저만 지원합니다. 많은 최신 지표는 Chromium 기반 브라우저에서만 사용할 수 있지만, 일부 지표(FCP, FID)는 다른 브라우저에서도 사용할 수 있으며 모든 사용자가 최신 버전의 Chromium 기반 브라우저로 업그레이드한 것은 아닐 수 있습니다. 따라서 일부 사용자는 소프트 내비게이션 지표를 보고하지 않을 수 있다는 점에 유의하세요.
  • 이 기능은 기본적으로 활성화되지 않는 실험적인 새 기능으로, 사이트에서는 의도하지 않은 다른 부작용이 없는지 이 기능을 테스트해야 합니다.

소프트 내비게이션 지표를 측정하는 방법에 대한 자세한 내용은 아래를 참조하세요.

크롬에서 소프트 내비게이션을 사용 설정하려면 어떻게 해야 하나요?

소프트 내비게이션은 크롬에서 기본적으로 활성화되어 있지 않지만, 크롬 110에서 이 기능을 명시적으로 활성화하여 실험용으로 사용할 수 있습니다.

개발자의 경우 chrome://flags/#enable-experimental-web-platform-features에서 실험용 웹 플랫폼 기능 플래그를 사용 설정하거나 크롬을 실행할 때 --enable-experimental-web-platform-features 커맨드 인수를 사용하여 이 기능을 활성화할 수 있습니다.

모든 방문자가 이 기능을 사용하도록 설정하여 영향을 확인하려는 웹사이트의 경우 크롬 117에서 실행되는 오리진 평가판을 신청하고 HTML 또는 HTTP 헤더에 오리진 평가판 토큰이 포함된 메타 요소를 포함시켜 사용하도록 설정할 수 있습니다. 자세한 내용은 오리진 평가판 시작하기 게시물을 참조하세요.

사이트 소유자는 모든 사용자 또는 일부 사용자에 대해서만 페이지에 오리진 평가판을 포함하도록 선택할 수 있습니다. 특히 많은 사용자에 대해 오리진 평가판을 사용하도록 설정하는 경우, 지표 보고 방식이 어떻게 변경되는지 위의 영향도 섹션을 참고하시기 바랍니다. CrUX는 이 소프트 내비게이션 설정과 관계없이 기존 방식으로 계속해서 지표를 보고하므로 이러한 변경의 영향을 받지 않습니다. 또한 오리진 평가판은 14일 동안의 중앙값을 기준으로 전체 크롬 페이지 로드의 최대 0.5%에서만 실험적 기능을 사용하도록 제한되지만, 이는 매우 큰 규모의 사이트에서만 문제가 될 수 있다는 점에 유의해야 합니다.

소프트 내비게이션을 측정하려면 어떻게 해야 하나요?

소프트 내비게이션 실험이 활성화되면 평소와 같이 PerformanceObserver API를 통해 지표가 보고됩니다. 그러나 이러한 지표에 대해 고려해야 할 몇 가지 추가 고려 사항이 있습니다.

참고: 소프트 내비게이션에 대해 현재 FP와 FCP가 보고되지 않으며, FID도 보고되지 않습니다.

소프트 내비게이션 보고하기

PerformanceObserver를 사용하여 소프트 내비게이션을 관찰할 수 있습니다. 다음은 buffered 옵션을 통해 이 페이지의 이전 소프트 내비게이션을 포함하여 소프트 내비게이션 항목을 콘솔에 기록하는 코드 스니펫의 예시입니다.

jsx
const observer = new PerformanceObserver(console.log);
 observer.observe({ type: "soft-navigation", buffered: true });

이를 사용하여 이전 내비게이션에 대한 전체 페이지 수명 주기 지표를 마무리지을 수 있습니다.

적절한 URL에 대해 지표 보고하기

소프트 내비게이션은 발생한 후에만 볼 수 있고, 현재 URL은 새 페이지의 업데이트된 URL을 반영하므로, 일부 지표는 이벤트가 마무리 된 다음 이전 URL을 기반으로 보고해야 합니다.

적절한 PerformanceEntrynavigationId 속성을 사용하여 이벤트를 올바른 URL에 연결할 수 있습니다. PerformanceEntry API를 통해 조회할 수 있습니다.

jsx
const softNavEntry =
   performance.getEntriesByType('soft-navigation').filter(
     (entry) => entry.navigationId === navigationId
@@ -70,8 +70,8 @@
 onCLS(doSoftNavProcessing, {reportSoftNavs: true});
 onFID(doSoftNavProcessing, {reportSoftNavs: true});
 onINP(doSoftNavProcessing, {reportSoftNavs: true});

지표가 위에서 언급한 대로 올바른 URL에 대해 보고되는지 확인하세요.

web-vitals 라이브러리는 현재 소프트 내비게이션에 대해 다음과 같은 지표를 보고합니다.

MetricDetails
TTFB0으로 보고됩니다.
FCP현재 web-vitals 라이브러리에서는 페이지의 첫 번째 FCP만 보고합니다.
LCP소프트 내비게이션 시작 시간을 기준으로 다음으로 큰 콘텐츠의 페인트 시간입니다. 이전 내비게이션에서 존재하는 기존 페인트는 고려되지 않습니다. 따라서 LCP는 >= 0이 됩니다. 평소와 같이 상호작용이 발생하거나 페이지가 백그라운드 처리될 때 보고되며, 그래야만 LCP가 최종 확정될 수 있기 때문입니다.
CLS내비게이션 시간 사이의 가장 큰 이동 창입니다. 평소와 같이, 페이지가 백그라운드 처리된 경우에 이 값이 보고됩니다. 0이 보고됩니다.
FID현재 web-vitals 라이브러리에서는 페이지의 첫 번째 FID만 보고합니다.
INP내비게이션 시간 사이의 INP입니다. 평소와 같이 상호 작용 시 또는 페이지가 백그라운드 처리될 때 보고되며, 그래야만 INP가 최종 확정될 수 있습니다. 0은 보고되지 않습니다.
경고
web-vitals 구현은 현재 개발 중이며 해당 브랜치에 새로운 변경 사항이 게시되면 변경될 수 있습니다. 현재로서는 소프트 내비게이션에서 FCP 및 FID를 지원하지 않는데, 이는 크롬에서 FCPFID를 측정하기 위해 더 많은 작업이 필요하기 때문입니다.
운영 사이트에서 web-vitals 자바스크립트 라이브러리를 사용하려는 경우 이 점을 인지하고 로컬 복사본을 가져와 해당 버전을 테스트하고 해당 브랜치에 변경 사항이 있는지 모니터링해야 합니다.

이러한 변화가 코어 웹 바이탈 측정의 일부가 되나요?

현재로서는 이 소프트 내비게이션 실험은 실험일 뿐입니다. 이 실험을 코어 웹 바이탈 이니셔티브에 통합할지 여부를 결정하기 전에 휴리스틱을 평가하고 사용자 경험을 더 정확하게 반영하는지 확인하고자 합니다. 이 실험의 가능성에 대해 매우 기대가 크지만, 이 실험이 현재의 측정치를 대체할지 여부와 시기에 대해서는 보장할 수 없습니다.

저희는 이 실험에 대한 웹 개발자의 피드백, 사용된 휴리스틱, 그리고 이 실험이 사용자 경험을 더 정확하게 반영한다고 생각하는지 여부에 대해 소중하게 생각합니다. 소프트 내비게이션 깃허브 리포지토리가 이러한 피드백을 제공하기에 가장 좋은 곳이지만, 크롬의 구현과 관련된 개별 버그는 크롬 이슈 트래커에서 제기해야 합니다.

CrUX에서 소프트 내비게이션은 어떻게 보고되나요?

이 실험이 성공할 경우 CrUX에서 소프트 내비게이션이 정확히 어떻게 보고될지 여부도 아직 결정되지 않았습니다. 현재의 "하드" 내비게이션과 동일하게 처리될 것이 반드시 보장되는 것은 아닙니다.

일부 웹 페이지에서는 소프트 내비게이션이 사용자에게 있어 전체 페이지 로딩과 거의 동일하며 단일 페이지 애플리케이션 기술의 사용은 구현 세부 사항일 뿐입니다. 다른 경우에는 추가 콘텐츠의 부분 로딩과 더 유사할 수 있습니다.

따라서 이러한 소프트 내비게이션을 CrUX에서 별도로 보고하거나 특정 페이지 또는 페이지 그룹에 대한 코어 웹 바이탈을 계산할 때 가중치를 부여할 수 있습니다. 또한 휴리스틱이 발전함에 따라 부분 로드 소프트 내비게이션을 완전히 제외할 수도 있습니다.

현재는 이 실험의 성공 여부를 판단할 수 있는 휴리스틱과 기술적 구현에 집중하고 있으므로 이러한 측면에 대한 결정은 아직 내려지지 않았습니다.

피드백

다음과 같은 곳에서 이 실험에 대한 피드백을 적극적으로 받고 있습니다.

결론

소프트 내비게이션 실험은 현재 지표에서 누락된 최신 웹의 일반적인 패턴을 측정하기 위해 코어 웹 바이탈 이니셔티브가 어떻게 발전할 수 있는지에 대한 흥미로운 접근 방식입니다. 이 실험은 아직 초기 단계이며 아직 해야 할 일이 많지만, 지금까지의 진행 상황을 광범위한 웹 커뮤니티에 공개하여 실험할 수 있도록 하는 것은 중요한 단계입니다. 이 실험에서 피드백을 수집하는 것도 이 실험의 중요한 부분이므로, 이 개발에 관심이 있는 분들께서는 이 기회를 통해 저희가 측정하고자 하는 바를 대표할 수 있는 API를 만드는 데 도움을 주실 것을 적극 권장합니다.

- + \ No newline at end of file diff --git a/log/fully-typed-web-apps.html b/log/fully-typed-web-apps.html index 2007472b..94c51199 100644 --- a/log/fully-typed-web-apps.html +++ b/log/fully-typed-web-apps.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

완전한 타입 안정성을 가진 웹 애플리케이션

원문: https://www.epicweb.dev/fully-typed-web-apps

타입스크립트는 웹 산업에서 큰 비중을 차지하고 있고 그럴 만한 이유가 있다고 생각합니다. 타입스크립트는 놀랍습니다. 타입 검사에 대한 이야기만 하려는 것이 아닙니다.

typescript
function add(a: number, b: number) {
+    
Skip to content
On this page

완전한 타입 안정성을 가진 웹 애플리케이션

원문: https://www.epicweb.dev/fully-typed-web-apps

타입스크립트는 웹 산업에서 큰 비중을 차지하고 있고 그럴 만한 이유가 있다고 생각합니다. 타입스크립트는 놀랍습니다. 타입 검사에 대한 이야기만 하려는 것이 아닙니다.

typescript
function add(a: number, b: number) {
   return a + b
 }
 
@@ -222,8 +222,8 @@
   //    ^? { serverFormInfo: ServerFormInfo<FormValidations> } | undefined
   return <div>{/* Workshop form */}</div>
 }

다시 말하지만, action이 반환하는 것은 결국 useActionData가 참조하는 (직렬화된) 타입이 됩니다. 이 경우에는 타입 안전적인 속성을 갖는 remix-validity-state를 사용하고 있습니다. 또한 제출된 데이터는 제공한 스키마에 따라 remix-validity-state에 의해 안전하게 구문 분석되므로 submittedFormData 타입은 모든 데이터가 구문 분석되고 사용할 준비가 되어 있습니다. 이 작업을 위한 다른 라이브러리도 있지만, 요점은 몇 가지 간단한 유틸리티를 사용하면 경계를 넘어 환상적인 타입 안전성을 확보하고 배포에 대한 자신감을 높일 수 있다는 것입니다. 유틸리티의 API는 간단합니다. 다만 유틸리티 자체는 때때로 꽤 복잡합니다 😅.

이 기능은 다른 Remix 유틸리티에서도 작동한다는 점을 언급해야 합니다. meta 내보내기는 useFetcheruseMatcher와 마찬가지로 완전히 타입 검증 될 수 있습니다. 정말 멋진 세상입니다.

정말, 그 loader는 놀랍습니다. 이것 좀 보세요!

네트워크 경계를 넘어 타입 안정적입니다.

하나의 파일로요. 멋지죠 🔥.

결론

제가 이 글을 통해 말하고자 한 요점은 타입 안전성은 가치 있을 뿐만 아니라 경계를 넘어 끝까지 달성할 수 있다는 것입니다. 마지막 로더 예제는 데이터베이스에서 UI까지 이어집니다. 이 데이터는 데이터베이스노드브라우저에서 타입 안전성이 보장되어 엔지니어로서 생산성을 엄청나게 높여줍니다. 어떤 프로젝트를 진행 중이시든, 여기에 제공된 몇 가지 제안을 사용하여 as Whatever 타입 형변환 거짓말을 삭제하고 보다 진정한 타입 안전성으로 변경할 수 있는 방법을 생각해 보세요. 나중에 스스로에게 감사하게 될 것입니다. 노력할 만한 가치가 있습니다!

앞선 예제들을 사용해 보고 싶으시다면 kentcdodds/fully-typed-web-apps-demo를 확인하세요.

- + \ No newline at end of file diff --git a/log/how-core-web-vital-affect-seo.html b/log/how-core-web-vital-affect-seo.html index 2895e24a..78bc81e8 100644 --- a/log/how-core-web-vital-affect-seo.html +++ b/log/how-core-web-vital-affect-seo.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

코어 웹 바이탈이 SEO에 미치는 영향

원문: https://vercel.com/blog/how-core-web-vitals-affect-seo

애플리케이션의 구글 페이지 경험 순위와 라이트하우스 점수 이해하기

코어 웹 바이탈은 구글에서 애플리케이션의 페이지 순위를 매기는 데 영향을 줍니다. 여기에서는 코어 웹 바이탈이 무엇인지, 어떻게 측정되는지, 그리고 이것이 사용자 및 검색 순위에 어떤 영향을 미치는지 자세히 살펴보겠습니다.

Malte Ubl은 Vercel의 CTO이자 전 구글 검색 디렉터로, 코어 웹 바이탈을 많이 활용하는 '페이지 경험' 순위 발표를 담당했습니다. 즉, 여기에 작성된 모든 내용은 공개적으로 문서화되어 있으며 적절한 경우 링크가 제공됩니다.

페이지 속도에 따라 구글이 순위를 매기는 방법

구글 검색에서 여러분의 사이트 순위는 구글의 코어 웹 바이탈 지표를 기반으로 사이트의 성능을 평가하는 구글의 페이지 경험 순위 시스템에 의해 영향을 받습니다.

구글은 실제 사용자가 웹사이트와 상호 작용하는 방식을 관찰하고 이를 다시 서버에 보고하는 방식으로 코어 웹 바이탈을 수집합니다 (작동 방식에 대한 자세한 내용은 아래 참조).

이러한 유형의 데이터를 현장 데이터 라고 하는데, 이는 사이트를 탐색하는 실제 사용자로부터 수집하기 때문입니다. 이는 사이트의 성능을 확인하기 위해 '실험실 환경'에서 실행한 테스트의 결과인 실험실 데이터 와는 다릅니다. 구글의 라이트하우스는 실험실 테스트의 한 예입니다.

이 글에서 가장 중요한 점은 바로 이것입니다.

구글은 사이트 순위를 매길 때 코어 웹 바이탈 현장 데이터 고려합니다. 구글은 검색 순위를 매길 때 라이트하우스 점수를 어떤 식으로든 고려하지 않습니다.

검색 순위 요소 맥락 파악하기

페이지 경험은 코어 웹 바이탈을 활용하여 다른 사이트와 비교해 웹사이트의 성능을 확인하는 구글 검색의 순위 결정 요소입니다. 페이지 경험은 구글 검색의 여러 순위 결정 요소 중 하나로, 검색 결과 페이지에서 사이트의 순위를 결정하기 위해 모두 합산됩니다.

검색어와의 관련성 및 콘텐츠의 품질은 페이지 경험보다 훨씬 더 중요한 요소입니다. 그러나 여러분과 경쟁업체의 관련성이 매우 유사한 경우에는 페이지 경험에 따라 순위가 결정될 수 있습니다.

페이지 경험과 코어 웹 바이탈의 다른 점은 바로 이 점입니다.

  • 사용자가 자신의 작업을 통해 이러한 지표를 개선할 수 있습니다.
  • 구글은 여러분이 얼마나 잘하고 있는지 투명하게 공개합니다.

코어 웹 바이탈은 다른 순위 결정 요소들보다 비교적 명확한 편입니다. 이를 최적화하는 것은 관련성을 개선하는 것보다 '추측'이 훨씬 덜 필요하며 콘텐츠 품질보다 측정하기 쉽습니다.

또한 코어 웹 바이탈을 개선하면 사용자 경험이 개선되어 전환을 유도할 수 있습니다.

애플리케이션의 코어 웹 바이탈을 확인하는 방법

페이지 경험 순위에 대한 전체 앱의 성능에 대한 권위 있는 데이터 소스는 구글 검색 콘솔입니다.

The Core Web Vitals page of Google Search Console.

구글 검색 콘솔의 코어 웹 바이탈 페이지

페이지별 데이터에 액세스하는 간단한 방법은 두 가지 주요 섹션(코어 웹 바이탈과 라이트하우스)으로 그룹화되어 있는 구글의 PageSpeed 인사이트입니다.

현장 데이터: 코어 웹 바이탈

"실제 사용자의 경험 알아보기"라는 레이블이 붙은 PageSpeed 인사이트의 상단 섹션에서 구글은 지난 28일 동안 크롬 브라우저(데스크톱 및 안드로이드 모바일 기기)에서 애플리케이션에 접속한 실제 사용자의 75번째 백분위수에 대한 글로벌 현장 데이터를 수집합니다.

구글은 이 실제 데이터의 첫 세 가지 지표인 최대 콘텐츠 렌더링 시간(LCP), 첫 입력 지연(FID), 레이아웃 변경 횟수(CLS)를 사용하여 점수에 따라 애플리케이션의 순위를 변경합니다. 2024년 3월에는 다음 페인트와의 상호작용(INP)이 FID를 대체합니다.

이 세 가지 코어 웹 바이탈은 웹 성능에 따라 앱의 순위에 영향을 미치는 데 구글이 사용하는 유일한 데이터이며, 여기에 표시된 점수는 애플리케이션의 비슷한 성능의 페이지와 함께 그룹으로 평균을 낸 것이지만 구글이 사용하는 수치와 정확히 일치합니다.

또한 데스크톱과 모바일용 탭이 모두 있는 것을 볼 수 있습니다. 이는 구글이 사이트의 모바일 버전과 데스크톱 버전을 각각 기준으로 모바일 사용자와 데스크톱 사용자에 대해 애플리케이션의 순위를 별도로 매기기 때문 입니다.

The mobile Core Web Vitals for google.com.

google.com에 대한 모바일 코어 웹 바이탈입니다.

코어 웹 바이탈 아래에 있는 세 가지 지표는 사용자 경험에 대한 추가 인사이트를 제공할 수 있지만 검색에서 애플리케이션의 순위에는 영향을 미치지 않습니다.

코어 웹 바이탈 현장 데이터에는 어떤 사용자가 포함되나요?

크롬 사용자경험보고서(CrUX)는 구글의 코어 웹 바이탈 프로그램의 공식 데이터세트이며, 수집 방법은 공개적으로 문서화되어 있습니다. 특히 보고서에 포함될 내용은 다음과 같습니다.

  • 페이지는 "충분한 인기"가 있어야 하고 "공개적으로 검색 가능"해야 합니다. 페이지가 인기 기준을 충족하는지 여부는 검색 콘솔의 CWV 보고서를 통해 확인할 수 있습니다.
  • 사용자는 사용량 통계 보고 사용을 활성화하고 브라우저 기록을 동기화('크롬'에 로그인한 상태)해야 하며 동기화 비밀번호를 설정하지 않아야 합니다.
  • 사용자는 데스크톱 또는 안드로이드에서 크롬을 사용해야 합니다.

이 마지막 글머리 기호는 아이폰 사용자는 집계되지 않는다는 의미입니다. 이는 일부 시장에서는 안드로이드폰이 아이폰보다 느리게 작동하므로 느리게 사이트를 방문하는 비율이 더 많이 계산될 수 있다는 점과 관련이 있을 수 있습니다.

애플리케이션에 실제 사용자 데이터가 충분하지 않은 경우 코어 웹 바이탈을 측정할 수 없으며 애플리케이션 순위를 매길 때 고려되지 않습니다.

사용자가 어디에서 오는지가 중요한가요?

또 다른 빈번한 질문은 '사용자가 어디에서 오는지가 중요한가요?' '인터넷 연결 속도가 느린 국가에 사용자가 많으면 불이익을 받나요?' 입니다.

사용자가 어디에서 오는지는 중요합니다. 현장 데이터의 핵심은 실제 사용자를 반영하며, 전 세계 모든 지역의 모든 사용자가 동등하게 집계된다는 점입니다.

좋은 소식은 인터넷 연결과 디바이스 성능이 전 세계적으로 향상되고 있으며, Vercel과 같은 에지 네트워크를 사용하면 지구상의 모든 사용자에게 뛰어난 성능을 제공할 수 있다는 것입니다.

주의: 28일간의 슬라이딩 윈도

구글은 28일 슬라이딩 윈도 방식으로 코어 웹 바이탈 데이터를 수집합니다. 점수는 기본적으로 지난 28일 동안의 평균 점수입니다. 개선 조치를 취했거나 상황을 악화시킨 경우 해당 조치의 전체 영향을 파악하려면 한 달이 지나야 합니다.

아래에서 Vercel의 속도 인사이트를 통해 업데이트된 CWV 데이터에 더 빠르게 액세스하여 실시간으로 변화에 대응하고 순위 하락을 방지할 수 있는 방법을 확인할 수 있습니다.

실험실 데이터: 라이트하우스

PageSpeed 인사이트의 두 번째 섹션인 '성능 문제 진단'에서는 크롬 개발자 도구에 있는 것과 동일한 도구인 라이트하우스 내에서 애플리케이션의 성능을 시뮬레이션합니다.

이는 위의 현장 데이터 점수와 완전히 별개의 항목으로, 실제 사용자에 대한 구글의 기준을 아직 충족하지 못하는 경우 개선 제안을 위한 것입니다.

다시 한번 말씀드리자면, 라이트하우스의 어떤 항목도 사이트의 검색 순위에 반영되지 않으며, 웹 앱 개발에서 흔히 발생하는 함정을 피하는 데 도움이 되는 선택적 지침을 제공합니다.

The mobile Lighthouse scores for google.com.

google.com에 대한 모바일 라이트하우스 점수입니다.

페이지에서 가장 눈에 띄는 숫자 중 하나인 라이트하우스 성능 점수는 FCP(First Contentful Paint), 속도 지표, LCP, TBT(총 차단 시간), CLS에 가중치를 부여한 점수입니다. 가중치를 적용한 후 실제 코어 웹 바이탈은 이 점수의 50%만 차지하며 FID/INP는 고려되지 않습니다.

이 결과는 쓰로틀링된 네트워크 연결로 모토 G 파워를 에뮬레이션 한 디바이스에서 얻은 결과이며, 실제 사용자의 디바이스와는 사양이 크게 다를 수 있습니다.

이 점과 기타 실험실 데이터와 관련된 문제(예: 사용자가 보고된 페이지로 이동하기 전에 어떤 페이지에서 왔는지 고려하지 않는 점)로 인해 라이트하우스 점수는 유일한 UX 지표로 적합하지 않습니다.

예를 들어, 지표로서의 총 차단 시간(TBT)은 실제 사용자 경험을 반영하지 못하는 경우가 많습니다. 이는 사용자 이벤트가 있는 경우 리액트와 같은 최신 프레임워크는 인터럽트 실행을 통해 좋은 FID와 INP를 제공하지만, 실험실 테스트에서는 실제 사용자 상호작용 없이 CPU 사용량을 관찰할 때 이를 알 수 없기 때문입니다.

라이트하우스 점수 해석하기

실험실 데이터에 대한 어려움에도 불구하고 라이트하우스는 여전히 유용한 정보를 제공하며, 특히 애플리케이션의 어느 부분이 사용자에게 문제를 일으킬 수 있는지 범위를 좁히는 데 유용합니다. 예를 들어

  • 성능 - 코어 웹 바이탈이 허용 범위에 속하지 않는 경우, 메인 스레드를 너무 오래 차단할 수 있는 스크립트를 링크해주는 등 문제가 있을법한 부분을 지적합니다. 또한 LCP를 유발하는 것으로 간주되는 정확한 요소도 표시합니다.
  • 접근성 - 이름 없는 링크나 레이블이 없는 폼 필드와 같은 일반적인 오류를 발견합니다. 또한 명암비가 충분히 높지 않은 요소나 탭할 공간이 충분하지 않은 링크를 스크린샷으로 찍을 수도 있습니다.
  • 모범 사례 - 이 라이트하우스 카테고리는 애플리케이션의 보안 및 사용성 개선을 위한 제안을 포괄적으로 담고 있습니다. 여기의 정보는 브라우저가 코드를 더 쉽게 구문 분석하고 XSS와 같은 일부(전부는 아니지만) 일반적인 취약점을 방지하는 데 도움이 됩니다.
  • SEO - 라이트하우스는 SEO의 기술적 부분에서 검색 엔진이 사이트를 크롤링하는 데 도움이 되는 기술적 방법에 대한 조언을 제공합니다. 이러한 점검은 사이트 순위가 예상대로 나오지 않는 이유를 디버깅하는 데 매우 유용할 수 있지만, 앱의 SEO에 영향을 미칠 수 있는 모든 요인을 완전히 해결하지는 못합니다.

코어 웹 바이탈을 더 빠르게 반복하는 방법: Vercel 속도 인사이트

구글의 데이터는 애플리케이션의 검색 순위와 실제 사용자의 성능을 확인할 수 있는 권위 있는 출처입니다. 하지만 위에서 언급했듯이 구글이 제공하는 데이터는 28일의 슬라이딩 윈도우를 사용합니다.

즉, 개선 또는 후퇴를 적용하면 전체 영향을 확인하려면 최대 한 달이 걸릴 수 있습니다. 또한 성능 저하에 대한 수정 사항을 제출해야 하는 경우 구글이 개선 사항을 반영하는 데 한 달이 더 걸릴 수 있습니다.

Vercel은 이터레이션 속도를 극대화하기 위해 속도 인사이트를 만들었습니다. 크롬 브라우저는 사용자가 사이트에 접속할 때 코어 웹 바이탈 지표를 노출하므로, 사이트에 설치된 속도 인사이트 패키지는 이 지표에 액세스하여 실시간 데이터를 보고합니다. 그러면 문제가 나타나는 즉시 발견하고 수정하여 신속하게 대응할 수 있습니다.

A snapshot of the Speed Insights tab from the project view.

프로젝트 보기의 속도 인사이트 탭 스냅샷

Vercel의 모든 기능이 무제한 불변 배포와 연계되어 있는 것처럼, 속도 인사이트도 배포 단위 또는 브랜치 단위로 볼 수 있어 각 git push가 애플리케이션 성능에 미치는 영향을 쉽게 확인할 수 있습니다.

구글의 PageSpeed 인사이트와 달리 지난 28일보다 더 작은 기간으로 데이터를 필터링할 수 있어 변경의 즉각적인 효과를 확인하거나 대규모 코드베이스 변경과 관련된 임의의 기간을 측정할 수 있습니다.

또한 애플리케이션의 개별 경로를 확인하고 사용자의 75번째 백분위수('구글 기준')와 90번째, 95번째, 99번째를 기준으로 데이터를 볼 수 있습니다.

또한 전 세계 지역별로 결과를 필터링할 수 있어 실제 사용자가 거주하는 지역에 리소스를 더 효과적으로 할당할 수 있습니다.

Geographic map of the P75 score where the color intensity indicates the relative amount of data points per country.

색상 강도가 국가별 데이터 포인트의 상대적 양을 나타내는 P75 점수의 지리적 지도.

전 세계의 다양한 규제 제한에 상관없이 속도 인사이트 기능을 사용할 수 있도록 개별 방문자나 IP 주소에 연결되거나 연관되지 않고 정보를 제공하도록 설계되었습니다.

더 읽어보기: 코어 웹 바이탈 최적화

이제 코어 웹 바이탈의 정의, 측정 방법, 애플리케이션에 미치는 영향에 대한 개요를 살펴보았으니 "각 지표를 최적화하려면 어떻게 해야 하나요?"라고 궁금해하실 수 있습니다.

조만간 이 주제에 대한 더 많은 콘텐츠를 게시할 예정이지만, 지금은 개별 지표 최적화에 대한 구글의 기술 가이드를 추천합니다: 최대 콘텐츠 렌더링 시간(LCP), 레이아웃 변경 횟수(CLS), 첫 입력 지연(FID), 다음 페인트와의 상호작용(INP).

요점

  • 코어 웹 바이탈을 개선하는 것은 구글이 사이트 순위를 매기는 데 사용하는 기본 데이터에 직접 액세스할 수 있기 때문에 구글 검색에서 가장 투명한 순위 결정 요소입니다.
  • 구글 검색 순위에는 코어 웹 바이탈만 반영됩니다. 라이트하우스 점수는 무시됩니다.
  • 구글의 데이터는 28일의 슬라이딩 윈도를 사용합니다. 더 빠른 이터레이션 속도로 사이트 속도를 개선하기 위해, Vercel의 속도 인사이트를 사용하면 코어 웹 바이탈에 실시간으로 쉽게 필터링할 수 있습니다.
- +
Skip to content
On this page

코어 웹 바이탈이 SEO에 미치는 영향

원문: https://vercel.com/blog/how-core-web-vitals-affect-seo

애플리케이션의 구글 페이지 경험 순위와 라이트하우스 점수 이해하기

코어 웹 바이탈은 구글에서 애플리케이션의 페이지 순위를 매기는 데 영향을 줍니다. 여기에서는 코어 웹 바이탈이 무엇인지, 어떻게 측정되는지, 그리고 이것이 사용자 및 검색 순위에 어떤 영향을 미치는지 자세히 살펴보겠습니다.

Malte Ubl은 Vercel의 CTO이자 전 구글 검색 디렉터로, 코어 웹 바이탈을 많이 활용하는 '페이지 경험' 순위 발표를 담당했습니다. 즉, 여기에 작성된 모든 내용은 공개적으로 문서화되어 있으며 적절한 경우 링크가 제공됩니다.

페이지 속도에 따라 구글이 순위를 매기는 방법

구글 검색에서 여러분의 사이트 순위는 구글의 코어 웹 바이탈 지표를 기반으로 사이트의 성능을 평가하는 구글의 페이지 경험 순위 시스템에 의해 영향을 받습니다.

구글은 실제 사용자가 웹사이트와 상호 작용하는 방식을 관찰하고 이를 다시 서버에 보고하는 방식으로 코어 웹 바이탈을 수집합니다 (작동 방식에 대한 자세한 내용은 아래 참조).

이러한 유형의 데이터를 현장 데이터 라고 하는데, 이는 사이트를 탐색하는 실제 사용자로부터 수집하기 때문입니다. 이는 사이트의 성능을 확인하기 위해 '실험실 환경'에서 실행한 테스트의 결과인 실험실 데이터 와는 다릅니다. 구글의 라이트하우스는 실험실 테스트의 한 예입니다.

이 글에서 가장 중요한 점은 바로 이것입니다.

구글은 사이트 순위를 매길 때 코어 웹 바이탈 현장 데이터 고려합니다. 구글은 검색 순위를 매길 때 라이트하우스 점수를 어떤 식으로든 고려하지 않습니다.

검색 순위 요소 맥락 파악하기

페이지 경험은 코어 웹 바이탈을 활용하여 다른 사이트와 비교해 웹사이트의 성능을 확인하는 구글 검색의 순위 결정 요소입니다. 페이지 경험은 구글 검색의 여러 순위 결정 요소 중 하나로, 검색 결과 페이지에서 사이트의 순위를 결정하기 위해 모두 합산됩니다.

검색어와의 관련성 및 콘텐츠의 품질은 페이지 경험보다 훨씬 더 중요한 요소입니다. 그러나 여러분과 경쟁업체의 관련성이 매우 유사한 경우에는 페이지 경험에 따라 순위가 결정될 수 있습니다.

페이지 경험과 코어 웹 바이탈의 다른 점은 바로 이 점입니다.

  • 사용자가 자신의 작업을 통해 이러한 지표를 개선할 수 있습니다.
  • 구글은 여러분이 얼마나 잘하고 있는지 투명하게 공개합니다.

코어 웹 바이탈은 다른 순위 결정 요소들보다 비교적 명확한 편입니다. 이를 최적화하는 것은 관련성을 개선하는 것보다 '추측'이 훨씬 덜 필요하며 콘텐츠 품질보다 측정하기 쉽습니다.

또한 코어 웹 바이탈을 개선하면 사용자 경험이 개선되어 전환을 유도할 수 있습니다.

애플리케이션의 코어 웹 바이탈을 확인하는 방법

페이지 경험 순위에 대한 전체 앱의 성능에 대한 권위 있는 데이터 소스는 구글 검색 콘솔입니다.

The Core Web Vitals page of Google Search Console.

구글 검색 콘솔의 코어 웹 바이탈 페이지

페이지별 데이터에 액세스하는 간단한 방법은 두 가지 주요 섹션(코어 웹 바이탈과 라이트하우스)으로 그룹화되어 있는 구글의 PageSpeed 인사이트입니다.

현장 데이터: 코어 웹 바이탈

"실제 사용자의 경험 알아보기"라는 레이블이 붙은 PageSpeed 인사이트의 상단 섹션에서 구글은 지난 28일 동안 크롬 브라우저(데스크톱 및 안드로이드 모바일 기기)에서 애플리케이션에 접속한 실제 사용자의 75번째 백분위수에 대한 글로벌 현장 데이터를 수집합니다.

구글은 이 실제 데이터의 첫 세 가지 지표인 최대 콘텐츠 렌더링 시간(LCP), 첫 입력 지연(FID), 레이아웃 변경 횟수(CLS)를 사용하여 점수에 따라 애플리케이션의 순위를 변경합니다. 2024년 3월에는 다음 페인트와의 상호작용(INP)이 FID를 대체합니다.

이 세 가지 코어 웹 바이탈은 웹 성능에 따라 앱의 순위에 영향을 미치는 데 구글이 사용하는 유일한 데이터이며, 여기에 표시된 점수는 애플리케이션의 비슷한 성능의 페이지와 함께 그룹으로 평균을 낸 것이지만 구글이 사용하는 수치와 정확히 일치합니다.

또한 데스크톱과 모바일용 탭이 모두 있는 것을 볼 수 있습니다. 이는 구글이 사이트의 모바일 버전과 데스크톱 버전을 각각 기준으로 모바일 사용자와 데스크톱 사용자에 대해 애플리케이션의 순위를 별도로 매기기 때문 입니다.

The mobile Core Web Vitals for google.com.

google.com에 대한 모바일 코어 웹 바이탈입니다.

코어 웹 바이탈 아래에 있는 세 가지 지표는 사용자 경험에 대한 추가 인사이트를 제공할 수 있지만 검색에서 애플리케이션의 순위에는 영향을 미치지 않습니다.

코어 웹 바이탈 현장 데이터에는 어떤 사용자가 포함되나요?

크롬 사용자경험보고서(CrUX)는 구글의 코어 웹 바이탈 프로그램의 공식 데이터세트이며, 수집 방법은 공개적으로 문서화되어 있습니다. 특히 보고서에 포함될 내용은 다음과 같습니다.

  • 페이지는 "충분한 인기"가 있어야 하고 "공개적으로 검색 가능"해야 합니다. 페이지가 인기 기준을 충족하는지 여부는 검색 콘솔의 CWV 보고서를 통해 확인할 수 있습니다.
  • 사용자는 사용량 통계 보고 사용을 활성화하고 브라우저 기록을 동기화('크롬'에 로그인한 상태)해야 하며 동기화 비밀번호를 설정하지 않아야 합니다.
  • 사용자는 데스크톱 또는 안드로이드에서 크롬을 사용해야 합니다.

이 마지막 글머리 기호는 아이폰 사용자는 집계되지 않는다는 의미입니다. 이는 일부 시장에서는 안드로이드폰이 아이폰보다 느리게 작동하므로 느리게 사이트를 방문하는 비율이 더 많이 계산될 수 있다는 점과 관련이 있을 수 있습니다.

애플리케이션에 실제 사용자 데이터가 충분하지 않은 경우 코어 웹 바이탈을 측정할 수 없으며 애플리케이션 순위를 매길 때 고려되지 않습니다.

사용자가 어디에서 오는지가 중요한가요?

또 다른 빈번한 질문은 '사용자가 어디에서 오는지가 중요한가요?' '인터넷 연결 속도가 느린 국가에 사용자가 많으면 불이익을 받나요?' 입니다.

사용자가 어디에서 오는지는 중요합니다. 현장 데이터의 핵심은 실제 사용자를 반영하며, 전 세계 모든 지역의 모든 사용자가 동등하게 집계된다는 점입니다.

좋은 소식은 인터넷 연결과 디바이스 성능이 전 세계적으로 향상되고 있으며, Vercel과 같은 에지 네트워크를 사용하면 지구상의 모든 사용자에게 뛰어난 성능을 제공할 수 있다는 것입니다.

주의: 28일간의 슬라이딩 윈도

구글은 28일 슬라이딩 윈도 방식으로 코어 웹 바이탈 데이터를 수집합니다. 점수는 기본적으로 지난 28일 동안의 평균 점수입니다. 개선 조치를 취했거나 상황을 악화시킨 경우 해당 조치의 전체 영향을 파악하려면 한 달이 지나야 합니다.

아래에서 Vercel의 속도 인사이트를 통해 업데이트된 CWV 데이터에 더 빠르게 액세스하여 실시간으로 변화에 대응하고 순위 하락을 방지할 수 있는 방법을 확인할 수 있습니다.

실험실 데이터: 라이트하우스

PageSpeed 인사이트의 두 번째 섹션인 '성능 문제 진단'에서는 크롬 개발자 도구에 있는 것과 동일한 도구인 라이트하우스 내에서 애플리케이션의 성능을 시뮬레이션합니다.

이는 위의 현장 데이터 점수와 완전히 별개의 항목으로, 실제 사용자에 대한 구글의 기준을 아직 충족하지 못하는 경우 개선 제안을 위한 것입니다.

다시 한번 말씀드리자면, 라이트하우스의 어떤 항목도 사이트의 검색 순위에 반영되지 않으며, 웹 앱 개발에서 흔히 발생하는 함정을 피하는 데 도움이 되는 선택적 지침을 제공합니다.

The mobile Lighthouse scores for google.com.

google.com에 대한 모바일 라이트하우스 점수입니다.

페이지에서 가장 눈에 띄는 숫자 중 하나인 라이트하우스 성능 점수는 FCP(First Contentful Paint), 속도 지표, LCP, TBT(총 차단 시간), CLS에 가중치를 부여한 점수입니다. 가중치를 적용한 후 실제 코어 웹 바이탈은 이 점수의 50%만 차지하며 FID/INP는 고려되지 않습니다.

이 결과는 쓰로틀링된 네트워크 연결로 모토 G 파워를 에뮬레이션 한 디바이스에서 얻은 결과이며, 실제 사용자의 디바이스와는 사양이 크게 다를 수 있습니다.

이 점과 기타 실험실 데이터와 관련된 문제(예: 사용자가 보고된 페이지로 이동하기 전에 어떤 페이지에서 왔는지 고려하지 않는 점)로 인해 라이트하우스 점수는 유일한 UX 지표로 적합하지 않습니다.

예를 들어, 지표로서의 총 차단 시간(TBT)은 실제 사용자 경험을 반영하지 못하는 경우가 많습니다. 이는 사용자 이벤트가 있는 경우 리액트와 같은 최신 프레임워크는 인터럽트 실행을 통해 좋은 FID와 INP를 제공하지만, 실험실 테스트에서는 실제 사용자 상호작용 없이 CPU 사용량을 관찰할 때 이를 알 수 없기 때문입니다.

라이트하우스 점수 해석하기

실험실 데이터에 대한 어려움에도 불구하고 라이트하우스는 여전히 유용한 정보를 제공하며, 특히 애플리케이션의 어느 부분이 사용자에게 문제를 일으킬 수 있는지 범위를 좁히는 데 유용합니다. 예를 들어

  • 성능 - 코어 웹 바이탈이 허용 범위에 속하지 않는 경우, 메인 스레드를 너무 오래 차단할 수 있는 스크립트를 링크해주는 등 문제가 있을법한 부분을 지적합니다. 또한 LCP를 유발하는 것으로 간주되는 정확한 요소도 표시합니다.
  • 접근성 - 이름 없는 링크나 레이블이 없는 폼 필드와 같은 일반적인 오류를 발견합니다. 또한 명암비가 충분히 높지 않은 요소나 탭할 공간이 충분하지 않은 링크를 스크린샷으로 찍을 수도 있습니다.
  • 모범 사례 - 이 라이트하우스 카테고리는 애플리케이션의 보안 및 사용성 개선을 위한 제안을 포괄적으로 담고 있습니다. 여기의 정보는 브라우저가 코드를 더 쉽게 구문 분석하고 XSS와 같은 일부(전부는 아니지만) 일반적인 취약점을 방지하는 데 도움이 됩니다.
  • SEO - 라이트하우스는 SEO의 기술적 부분에서 검색 엔진이 사이트를 크롤링하는 데 도움이 되는 기술적 방법에 대한 조언을 제공합니다. 이러한 점검은 사이트 순위가 예상대로 나오지 않는 이유를 디버깅하는 데 매우 유용할 수 있지만, 앱의 SEO에 영향을 미칠 수 있는 모든 요인을 완전히 해결하지는 못합니다.

코어 웹 바이탈을 더 빠르게 반복하는 방법: Vercel 속도 인사이트

구글의 데이터는 애플리케이션의 검색 순위와 실제 사용자의 성능을 확인할 수 있는 권위 있는 출처입니다. 하지만 위에서 언급했듯이 구글이 제공하는 데이터는 28일의 슬라이딩 윈도우를 사용합니다.

즉, 개선 또는 후퇴를 적용하면 전체 영향을 확인하려면 최대 한 달이 걸릴 수 있습니다. 또한 성능 저하에 대한 수정 사항을 제출해야 하는 경우 구글이 개선 사항을 반영하는 데 한 달이 더 걸릴 수 있습니다.

Vercel은 이터레이션 속도를 극대화하기 위해 속도 인사이트를 만들었습니다. 크롬 브라우저는 사용자가 사이트에 접속할 때 코어 웹 바이탈 지표를 노출하므로, 사이트에 설치된 속도 인사이트 패키지는 이 지표에 액세스하여 실시간 데이터를 보고합니다. 그러면 문제가 나타나는 즉시 발견하고 수정하여 신속하게 대응할 수 있습니다.

A snapshot of the Speed Insights tab from the project view.

프로젝트 보기의 속도 인사이트 탭 스냅샷

Vercel의 모든 기능이 무제한 불변 배포와 연계되어 있는 것처럼, 속도 인사이트도 배포 단위 또는 브랜치 단위로 볼 수 있어 각 git push가 애플리케이션 성능에 미치는 영향을 쉽게 확인할 수 있습니다.

구글의 PageSpeed 인사이트와 달리 지난 28일보다 더 작은 기간으로 데이터를 필터링할 수 있어 변경의 즉각적인 효과를 확인하거나 대규모 코드베이스 변경과 관련된 임의의 기간을 측정할 수 있습니다.

또한 애플리케이션의 개별 경로를 확인하고 사용자의 75번째 백분위수('구글 기준')와 90번째, 95번째, 99번째를 기준으로 데이터를 볼 수 있습니다.

또한 전 세계 지역별로 결과를 필터링할 수 있어 실제 사용자가 거주하는 지역에 리소스를 더 효과적으로 할당할 수 있습니다.

Geographic map of the P75 score where the color intensity indicates the relative amount of data points per country.

색상 강도가 국가별 데이터 포인트의 상대적 양을 나타내는 P75 점수의 지리적 지도.

전 세계의 다양한 규제 제한에 상관없이 속도 인사이트 기능을 사용할 수 있도록 개별 방문자나 IP 주소에 연결되거나 연관되지 않고 정보를 제공하도록 설계되었습니다.

더 읽어보기: 코어 웹 바이탈 최적화

이제 코어 웹 바이탈의 정의, 측정 방법, 애플리케이션에 미치는 영향에 대한 개요를 살펴보았으니 "각 지표를 최적화하려면 어떻게 해야 하나요?"라고 궁금해하실 수 있습니다.

조만간 이 주제에 대한 더 많은 콘텐츠를 게시할 예정이지만, 지금은 개별 지표 최적화에 대한 구글의 기술 가이드를 추천합니다: 최대 콘텐츠 렌더링 시간(LCP), 레이아웃 변경 횟수(CLS), 첫 입력 지연(FID), 다음 페인트와의 상호작용(INP).

요점

  • 코어 웹 바이탈을 개선하는 것은 구글이 사이트 순위를 매기는 데 사용하는 기본 데이터에 직접 액세스할 수 있기 때문에 구글 검색에서 가장 투명한 순위 결정 요소입니다.
  • 구글 검색 순위에는 코어 웹 바이탈만 반영됩니다. 라이트하우스 점수는 무시됩니다.
  • 구글의 데이터는 28일의 슬라이딩 윈도를 사용합니다. 더 빠른 이터레이션 속도로 사이트 속도를 개선하기 위해, Vercel의 속도 인사이트를 사용하면 코어 웹 바이탈에 실시간으로 쉽게 필터링할 수 있습니다.
+ \ No newline at end of file diff --git a/log/making-cloudflare-for-web.html b/log/making-cloudflare-for-web.html index 6f976a69..fa6c0346 100644 --- a/log/making-cloudflare-for-web.html +++ b/log/making-cloudflare-for-web.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Cloudflare를 웹 애플리케이션을 위한 최고의 장소로 만들기

원문: https://blog.cloudflare.com/making-cloudflare-for-web/

웹 개발자 여러분 안녕하세요! 최근 Cloudflare에서는 약간의 변화를 준비하고 있는데요. 이 글에서 저희가 무엇을 하고 어디로 가고 있는지 간단하게 알려드리려 합니다. 여러분들은 이미 Cloudflare를 웹 애플리케이션을 보호하거나, 속도를 높이거나, 확장할 수 있는 최고의 장소로 알고 계시겠지만, Cloudflare는 점점 더 애플리케이션을 배포하고 실행하는데도 최고의 장소가 되고 있습니다!

왜 애플리케이션을 Cloudflare에 배포해야 할까요? 두 가지 간단한 이유가 있습니다. 첫째, 여러 개별 시스템을 관리하는 번거로움을 줄여줍니다. 개발, 배포, 모니터링, 튜닝을 한곳에서 할 수 있습니다. 둘째, Cloudflare에 직접 배포함으로써 애플리케이션을 최적화할 수 있는 수단이 훨씬 더 많아지며, 그로 인해 애플리케이션을 사용자에게 더 빠르고 부드럽게 전달할 수 있습니다.

그래서 무엇이 바뀌는 건가요? 사실 꽤 많은 것이 바뀝니다. 저는 모든 세부 사항을 다시 이야기하며 여러분들을 지루하게 하지 않을 것입니다. 대신 제 뛰어난 동료들이 모든 세부 사항을 포함한 별도의 글을 작성했으니, 여기서는 대략적으로 파악해 보세요.

Cloudflare Workers + Pages = 멋진 개발 플랫폼

Cloudflare Pages와 Workers는 다음과 같은 서비스를 제공하는 통합된 개발 및 애플리케이션 호스팅 플랫폼으로 병합됩니다.

  • 전 세계적으로 매우 낮은 지연시간: 정적 자산과 컴퓨팅이 전 세계 인터넷 연결 인구의 95%에게 50ms 미만 거리에 있습니다.
  • 무료 정적 자산 호스팅을 포함한 무료 이그레스(egress, 역자 주: 서비스 경계 내부의 API 클라이언트 또는 리소스와 서비스 경계 외부의 리소스가 관련된 액세스를 의미합니다.).
  • 전 세계적으로 이미 초당 최대 1천만 건 이상의 요청을 처리하는 표준 기반 자바스크립트 및 WASM 런타임.
  • R2(S3 호환 API를 가진 오브젝트 저장소), 지연시간이 낮고 전 세계적으로 복제된 KV 저장소, , D1 데이터베이스 등의 강력한 기능에 대한 접근.
  • 개발 속도를 향상하는 GitOps 및 CI/CD 워크플로우와 미리 보기 환경 지원
  • ... 그리고 훨씬 더 많은 것들이 있습니다!

수학적으로는 틀렸다는 것이 증명되었지만, 저희는 1+1=3이라는 공식을 고집스럽게 믿고 있습니다. Cloudflare Pages + Workers가 각각의 합보다 훨씬 더 훌륭하다고 해석합니다. 실제로, 둘의 조합은 저희가 기대하며 개발하고 있는 독특한 개발 플랫폼의 훌륭한 기반입니다.

저희는 이 통합 여정을 몇 분기 전에 시작했으며, 초기부터 기존의 애플리케이션을 그대로 두지 않기로 합의했습니다. 대신, 이전의 애플리케이션을 새로운 세계로 옮겨갈 것입니다. 이제 점진적인 결과를 공유하기 시작하려고 합니다. 그리고 이번 분기 동안 훨씬 더 많은 것들이 출시될 예정입니다. 더 알고 싶으신가요? 제 동료 Nevi가 그녀의 블로그 게시물에 흥미진진한 세부 사항들을 공유했습니다.

Workers를 위한 스마트 배치는 우리를 더 멀리 나아가게 합니다!

간단히 말해서, 스마트 배치는 Cloudflare에 혁명을 가져왔습니다. 이 기능은 오늘날 다른 애플리케이션 호스팅 제공 업체도 따라올 수 없는 새로운 컴퓨팅 패러다임을 저희 플랫폼에서 가능하게 합니다. 인기 있는 여러 웹 프레임워크 중 하나로 만들어진 전형적인 풀스택 애플리케이션을 가지고 있나요? 그렇다면 이 기능은 바로 당신을 위한 것입니다! 그리고 이 기능은 Workers와 Pages 모두에서 작동합니다!

이전에는 항상 모든 애플리케이션을 저희 글로벌 네트워크의 "엣지", 즉 사용자에게 가능한 한 가까운 곳에서 실행했습니다. 스마트 배치를 사용하면 저희는 컴퓨팅(당신의 애플리케이션)이 실행되어야 하는 네트워크 내에서 최적의 위치를 지능적으로 결정합니다. 이는 애플리케이션의 동작과 애플리케이션이 상호작용하는 다른 네트워크 자원이나 엔드포인트를 관찰함으로써 이루어집니다. 그런 다음 일반적으로 데이터가 저장된 곳과 가까운 최적의 위치에 당신의 애플리케이션을 투명하게 생성하고, 저희의 네트워크를 통해 들어오는 요청을 해당 위치로 라우팅 합니다.

스마트 배치를 통해 애플리케이션을 작업을 수행하는데 필요한 데이터와 가까이에서 실행할 수 있습니다. 이는 데이터베이스, 오브젝트 저장소, 또는 다른 백엔드 엔드포인트와 상호작용하는 애플리케이션에 유용하며, 중앙집중식이고 글로벌하게 분산되어 있지 않은 경우에 특히 강력합니다.

사용자나 클라이언트의 요청은 여전히 285개가 넘는 데이터 센터 중 그들의 현재 위치에 가까운 한 곳의 초고속 네트워크로 전송됩니다. 하지만 애플리케이션을 바로 그곳에서 생성하는 대신, 애플리케이션과 통신하는 데이터나 백엔드 시스템과 가까운 최적의 데이터 센터로 요청을 라우팅 합니다.

그렇다고 엣지에서의 컴퓨팅이 더 이상 멋지지 않다는 의미는 아닙니다! 멋져요! 여전히 애플리케이션을 엣지에서 실행하는 것이 합당한 많은 사용 사례가 있으며 스마트 배치는 그 시나리오를 결정하고, 있어야 할 장소가 엣지라면 애플리케이션을 엣지에 유지합니다. A/B 테스팅, 현지화, 에셋 제공 등은 거의 항상 엣지에서 일어나야 할 사용 사례입니다.

흥미로우신가요? 이 시각적 데모를 확인하고, 제 동료인 Tanushree의 블로그 게시물에서 스마트 배치에 대해 자세히 알아보세요.

로컬 또는 브라우저에서 개발하세요!

초고속으로 전 세계에 분산된 애플리케이션 플랫폼에 직접 통합된, 최고의 개발 환경을 구축한다는 목표를 계속해서 실현하고 있습니다. 로컬 기본 개발 워크플로우를 완벽하게 지원하는 Wrangler v3를 출시합니다. 오픈소스 Cloudflare Workers 자바스크립트 런타임인 workerd를 기반으로 하는 이 변화는 개발 서버 시작 시각을 10배, 그리고 스크립트 재로드 시간을 60배 단축해 생산성을 높이고 흐름을 더 오래 유지할 수 있게 합니다.

대시보드에서는 업그레이드된, 훨씬 더 강력한 VSCode 기반의 온라인 편집기를 도입하고 있습니다. 이제 브라우저에서 여러 자바스크립트 모듈을 편집하고, 엣지 미리 보기를 정확히 확인할 수 있으며, 친절한 에러 페이지와 타입 검사를 할 수 있습니다!

마지막으로 대시보드 에디터와 Wrangler 모두에서 workerd 맞춤형 크롬 개발자 도구가 최신 버전으로 업데이트되어 어디서든 더욱 뛰어난 디버깅 및 프로파일링 기능을 제공합니다.

이는 저희의 개발 도구 영역 개선에 대한 첫 번째 물결에 불과하며, 앞으로 몇 분기 동안 이 공간에서는 저희가 계속해서 변화를 이루는 것을 볼 수 있을 것입니다. 그러나 그 사이에, Adam, Brendan, 그리고 Samuel로부터 Wrangler v3의 모든 세부 정보VSCode 및 대시보드 에디터 개선에 대한 심층적인 게시물을 확인하세요.

메모리, CPU, 애플리케이션 크기 제한 증가 및 가격 책정 간소화!

AI, WASM, 그리고 강력한 풀스택 애플리케이션의 시대에서, 저희는 개발자들이 저희의 현재 자원 한계에 더 자주 직면하고 있다는 것을 알아차렸습니다. 저희는 이러한 애플리케이션이 번창하고 개발자들이 더 크고 복잡한 애플리케이션을 구축할 수 있도록 하고 싶습니다. 그래서, 다음 주(2023.05.17. 기준) 내로 애플리케이션 크기 제한(JavaScript/WASM 번들 크기)을 10MB(gzip 이후)로 늘리고, 시작 지연 시간제한(스크립트 컴파일 시간)을 200ms에서 400ms로 늘릴 예정입니다.

개발자들에게 더 많은 권한을 부여하기 위해, 메모리 제한 등을 늘리기 위해 등급을 도입하면서 요금 모델을 통합하고 간소화하는 방법에 대해 고민하고 있습니다. 이에 대한 자세한 정보는 조만간 공개될 예정입니다!

이러한 변경으로 개발자들은 더 멋진 애플리케이션을 구축하고 더 적은 비용으로 운영할 수 있게 됩니다! 멋지지 않나요?!?

최신 빌드 이미지가 적용된 Pages CI를 만나보세요!

드디어 기다림이 끝났습니다! 이제 Pages에서 최신 빌드 이미지를 사용하여 CI 및 통합 빌드 시스템을 구동합니다. 이번 개선으로 마침내 최신 버전의 Node.js, pnpm 및 오늘날 개발자가 사용하는 기타 여러 도구를 사용할 수 있게 되었습니다.

이번 개선 사항을 제공하면서 향후에도 최신 상태로 유지하기가 훨씬 쉽게 만들었을 뿐만 아니라 빌드 캐싱과 같은 새로운 기능도 추가했습니다!

업데이트는 모든 새 프로젝트에 기본적으로 제공되며, 기존 프로젝트는 새로운 기본값을 선택할 수 있습니다. 마음에 드시나요? 그렇다면 Greg의 이 블로그 글에서 계속 읽어보세요.

이 정도면 충분하군요. 자, 이제 시작하겠습니다…! 당신이 원하는 프레임워크를 C3와 함께!

Cloudflare는 CDN이자 Worker 애플리케이션을 배포하는 장소일 뿐만 아니라 이제 풀스택 웹 애플리케이션을 실행하는 최고의 장소가 되고 있습니다. 여기에는 Angular, Astro, Next, Nuxt, Qwik, Remix, Solid, Svelte, Vue 등과 같은 모든 풀스택 웹 프레임워크가 포함됩니다.

저희의 큰 목표는 더 나은 인터넷을 구축하는 것이며, 이 사명에 대한 저희의 기여는 개발자뿐만 아니라 누구나 아이디어를 실시간으로 배포된 애플리케이션으로 전환할 수 있도록 지원하는 것입니다.

개발자들이 아이디어를 빠르게, 그리고 번거로움 없이 배포된 애플리케이션으로 전환할 수 있도록 두 가지를 구축했습니다.

첫째, 여러 웹 프레임워크 작성자들과 협력하여 모든 널리 사용되는 자바스크립트 웹 프레임워크에 대해 새로운 어댑터를 만들거나 기존 어댑터를 개선했습니다. 이 어댑터들은 애플리케이션이 저희 플랫폼에서 가장 효율적인 방식으로 실행되도록 보장하면서, 플랫폼의 모든 기능과 능력에 접근할 수 있게 합니다.

이러한 어댑터에는 요청이 많았던 Next.js 어댑터가 포함되어 있으며, 방금 프로덕션 준비를 완료하고 오늘 1.0.0을 출시합니다! 각 팀과 협력하여 AngularQwik을 위한 새로운 어댑터를 구축했으며, Astro, Nuxt, Solid 및 몇 가지를 개선했습니다.

둘째, 저희는 C3라고 부르는 새롭고 멋진 CLI를 개발했습니다. 이는 create-cloudflare CLI를 의미하는 단축어로, 저희의 기존 Wrangler CLI의 형제입니다. 만약 당신이 터미널이나 VSCode와 같은 로컬 에디터에서 대부분의 시간을 보내는 개발자라면, 이 CLI는 Cloudflare 우주로 진입하게 해주는 단일 진입점입니다.

C3 명령을 실행하면 시작할 수 있습니다. 저희는 사용자와 열심히 작업하는 프레임워크 작성자 사이에 있는 것을 원하지 않기 때문에, 사용자가 원하는 프레임워크를 선택하면 C3는 제어권을 선택한 프레임워크의 CLI에게 넘깁니다. 잠시 후 npm 의존성이 모두 설치되고 나면 애플리케이션이 배포된 URL을 받게 됩니다. 이게 다입니다. 거의 즉시 아이디어로부터 공유할 수 있는 URL까지! 와우.

웹 애플리케이션을 위한 최적의 장소

정리하자면, 풀스택 웹 프레임워크에 대한 최고 수준의 지원과 플랫폼의 짧은 대기 시간 및 비용 효율성, 풀스택 웹 애플리케이션의 백엔드가 최적의 위치에서 자동으로 실행되도록 하는 스마트 배치, 그리고 개발자 도구의 나머지 모든 중요한 개선 사항이 결합되어 Cloudflare를 웹 애플리케이션을 구축하고 호스팅 하기 위한 최고의 장소로 만들어줍니다. 이것이 저희가 더 나은 인터넷을 만들기 위한 사명에 대한 기여이며, 웹을 전진시키는 방법입니다.

저희는 사람들이 비즈니스를 하고자 할 때, 또는 단지 창의력을 발휘하고 아이디어를 탐구하며 재미있게 보내고 싶을 때 찾는 장소가 되길 희망합니다. 이는 긴 여정이며, 앞으로 저희가 마주하게 될 흥미로운 도전들이 많습니다. 당신의 의견이 저희를 안내하는 데 결정적인 역할을 할 것입니다. 저희 모두는 이 일부가 될 기회를 얻게 되어 흥분하고 있으며, 최선을 다해보려고 합니다. 당신도 이 여행에 참여할 수 있으며, 바로 시작할 수 있습니다.

bash
npm create cloudflare my-first-app
- +
Skip to content
On this page

Cloudflare를 웹 애플리케이션을 위한 최고의 장소로 만들기

원문: https://blog.cloudflare.com/making-cloudflare-for-web/

웹 개발자 여러분 안녕하세요! 최근 Cloudflare에서는 약간의 변화를 준비하고 있는데요. 이 글에서 저희가 무엇을 하고 어디로 가고 있는지 간단하게 알려드리려 합니다. 여러분들은 이미 Cloudflare를 웹 애플리케이션을 보호하거나, 속도를 높이거나, 확장할 수 있는 최고의 장소로 알고 계시겠지만, Cloudflare는 점점 더 애플리케이션을 배포하고 실행하는데도 최고의 장소가 되고 있습니다!

왜 애플리케이션을 Cloudflare에 배포해야 할까요? 두 가지 간단한 이유가 있습니다. 첫째, 여러 개별 시스템을 관리하는 번거로움을 줄여줍니다. 개발, 배포, 모니터링, 튜닝을 한곳에서 할 수 있습니다. 둘째, Cloudflare에 직접 배포함으로써 애플리케이션을 최적화할 수 있는 수단이 훨씬 더 많아지며, 그로 인해 애플리케이션을 사용자에게 더 빠르고 부드럽게 전달할 수 있습니다.

그래서 무엇이 바뀌는 건가요? 사실 꽤 많은 것이 바뀝니다. 저는 모든 세부 사항을 다시 이야기하며 여러분들을 지루하게 하지 않을 것입니다. 대신 제 뛰어난 동료들이 모든 세부 사항을 포함한 별도의 글을 작성했으니, 여기서는 대략적으로 파악해 보세요.

Cloudflare Workers + Pages = 멋진 개발 플랫폼

Cloudflare Pages와 Workers는 다음과 같은 서비스를 제공하는 통합된 개발 및 애플리케이션 호스팅 플랫폼으로 병합됩니다.

  • 전 세계적으로 매우 낮은 지연시간: 정적 자산과 컴퓨팅이 전 세계 인터넷 연결 인구의 95%에게 50ms 미만 거리에 있습니다.
  • 무료 정적 자산 호스팅을 포함한 무료 이그레스(egress, 역자 주: 서비스 경계 내부의 API 클라이언트 또는 리소스와 서비스 경계 외부의 리소스가 관련된 액세스를 의미합니다.).
  • 전 세계적으로 이미 초당 최대 1천만 건 이상의 요청을 처리하는 표준 기반 자바스크립트 및 WASM 런타임.
  • R2(S3 호환 API를 가진 오브젝트 저장소), 지연시간이 낮고 전 세계적으로 복제된 KV 저장소, , D1 데이터베이스 등의 강력한 기능에 대한 접근.
  • 개발 속도를 향상하는 GitOps 및 CI/CD 워크플로우와 미리 보기 환경 지원
  • ... 그리고 훨씬 더 많은 것들이 있습니다!

수학적으로는 틀렸다는 것이 증명되었지만, 저희는 1+1=3이라는 공식을 고집스럽게 믿고 있습니다. Cloudflare Pages + Workers가 각각의 합보다 훨씬 더 훌륭하다고 해석합니다. 실제로, 둘의 조합은 저희가 기대하며 개발하고 있는 독특한 개발 플랫폼의 훌륭한 기반입니다.

저희는 이 통합 여정을 몇 분기 전에 시작했으며, 초기부터 기존의 애플리케이션을 그대로 두지 않기로 합의했습니다. 대신, 이전의 애플리케이션을 새로운 세계로 옮겨갈 것입니다. 이제 점진적인 결과를 공유하기 시작하려고 합니다. 그리고 이번 분기 동안 훨씬 더 많은 것들이 출시될 예정입니다. 더 알고 싶으신가요? 제 동료 Nevi가 그녀의 블로그 게시물에 흥미진진한 세부 사항들을 공유했습니다.

Workers를 위한 스마트 배치는 우리를 더 멀리 나아가게 합니다!

간단히 말해서, 스마트 배치는 Cloudflare에 혁명을 가져왔습니다. 이 기능은 오늘날 다른 애플리케이션 호스팅 제공 업체도 따라올 수 없는 새로운 컴퓨팅 패러다임을 저희 플랫폼에서 가능하게 합니다. 인기 있는 여러 웹 프레임워크 중 하나로 만들어진 전형적인 풀스택 애플리케이션을 가지고 있나요? 그렇다면 이 기능은 바로 당신을 위한 것입니다! 그리고 이 기능은 Workers와 Pages 모두에서 작동합니다!

이전에는 항상 모든 애플리케이션을 저희 글로벌 네트워크의 "엣지", 즉 사용자에게 가능한 한 가까운 곳에서 실행했습니다. 스마트 배치를 사용하면 저희는 컴퓨팅(당신의 애플리케이션)이 실행되어야 하는 네트워크 내에서 최적의 위치를 지능적으로 결정합니다. 이는 애플리케이션의 동작과 애플리케이션이 상호작용하는 다른 네트워크 자원이나 엔드포인트를 관찰함으로써 이루어집니다. 그런 다음 일반적으로 데이터가 저장된 곳과 가까운 최적의 위치에 당신의 애플리케이션을 투명하게 생성하고, 저희의 네트워크를 통해 들어오는 요청을 해당 위치로 라우팅 합니다.

스마트 배치를 통해 애플리케이션을 작업을 수행하는데 필요한 데이터와 가까이에서 실행할 수 있습니다. 이는 데이터베이스, 오브젝트 저장소, 또는 다른 백엔드 엔드포인트와 상호작용하는 애플리케이션에 유용하며, 중앙집중식이고 글로벌하게 분산되어 있지 않은 경우에 특히 강력합니다.

사용자나 클라이언트의 요청은 여전히 285개가 넘는 데이터 센터 중 그들의 현재 위치에 가까운 한 곳의 초고속 네트워크로 전송됩니다. 하지만 애플리케이션을 바로 그곳에서 생성하는 대신, 애플리케이션과 통신하는 데이터나 백엔드 시스템과 가까운 최적의 데이터 센터로 요청을 라우팅 합니다.

그렇다고 엣지에서의 컴퓨팅이 더 이상 멋지지 않다는 의미는 아닙니다! 멋져요! 여전히 애플리케이션을 엣지에서 실행하는 것이 합당한 많은 사용 사례가 있으며 스마트 배치는 그 시나리오를 결정하고, 있어야 할 장소가 엣지라면 애플리케이션을 엣지에 유지합니다. A/B 테스팅, 현지화, 에셋 제공 등은 거의 항상 엣지에서 일어나야 할 사용 사례입니다.

흥미로우신가요? 이 시각적 데모를 확인하고, 제 동료인 Tanushree의 블로그 게시물에서 스마트 배치에 대해 자세히 알아보세요.

로컬 또는 브라우저에서 개발하세요!

초고속으로 전 세계에 분산된 애플리케이션 플랫폼에 직접 통합된, 최고의 개발 환경을 구축한다는 목표를 계속해서 실현하고 있습니다. 로컬 기본 개발 워크플로우를 완벽하게 지원하는 Wrangler v3를 출시합니다. 오픈소스 Cloudflare Workers 자바스크립트 런타임인 workerd를 기반으로 하는 이 변화는 개발 서버 시작 시각을 10배, 그리고 스크립트 재로드 시간을 60배 단축해 생산성을 높이고 흐름을 더 오래 유지할 수 있게 합니다.

대시보드에서는 업그레이드된, 훨씬 더 강력한 VSCode 기반의 온라인 편집기를 도입하고 있습니다. 이제 브라우저에서 여러 자바스크립트 모듈을 편집하고, 엣지 미리 보기를 정확히 확인할 수 있으며, 친절한 에러 페이지와 타입 검사를 할 수 있습니다!

마지막으로 대시보드 에디터와 Wrangler 모두에서 workerd 맞춤형 크롬 개발자 도구가 최신 버전으로 업데이트되어 어디서든 더욱 뛰어난 디버깅 및 프로파일링 기능을 제공합니다.

이는 저희의 개발 도구 영역 개선에 대한 첫 번째 물결에 불과하며, 앞으로 몇 분기 동안 이 공간에서는 저희가 계속해서 변화를 이루는 것을 볼 수 있을 것입니다. 그러나 그 사이에, Adam, Brendan, 그리고 Samuel로부터 Wrangler v3의 모든 세부 정보VSCode 및 대시보드 에디터 개선에 대한 심층적인 게시물을 확인하세요.

메모리, CPU, 애플리케이션 크기 제한 증가 및 가격 책정 간소화!

AI, WASM, 그리고 강력한 풀스택 애플리케이션의 시대에서, 저희는 개발자들이 저희의 현재 자원 한계에 더 자주 직면하고 있다는 것을 알아차렸습니다. 저희는 이러한 애플리케이션이 번창하고 개발자들이 더 크고 복잡한 애플리케이션을 구축할 수 있도록 하고 싶습니다. 그래서, 다음 주(2023.05.17. 기준) 내로 애플리케이션 크기 제한(JavaScript/WASM 번들 크기)을 10MB(gzip 이후)로 늘리고, 시작 지연 시간제한(스크립트 컴파일 시간)을 200ms에서 400ms로 늘릴 예정입니다.

개발자들에게 더 많은 권한을 부여하기 위해, 메모리 제한 등을 늘리기 위해 등급을 도입하면서 요금 모델을 통합하고 간소화하는 방법에 대해 고민하고 있습니다. 이에 대한 자세한 정보는 조만간 공개될 예정입니다!

이러한 변경으로 개발자들은 더 멋진 애플리케이션을 구축하고 더 적은 비용으로 운영할 수 있게 됩니다! 멋지지 않나요?!?

최신 빌드 이미지가 적용된 Pages CI를 만나보세요!

드디어 기다림이 끝났습니다! 이제 Pages에서 최신 빌드 이미지를 사용하여 CI 및 통합 빌드 시스템을 구동합니다. 이번 개선으로 마침내 최신 버전의 Node.js, pnpm 및 오늘날 개발자가 사용하는 기타 여러 도구를 사용할 수 있게 되었습니다.

이번 개선 사항을 제공하면서 향후에도 최신 상태로 유지하기가 훨씬 쉽게 만들었을 뿐만 아니라 빌드 캐싱과 같은 새로운 기능도 추가했습니다!

업데이트는 모든 새 프로젝트에 기본적으로 제공되며, 기존 프로젝트는 새로운 기본값을 선택할 수 있습니다. 마음에 드시나요? 그렇다면 Greg의 이 블로그 글에서 계속 읽어보세요.

이 정도면 충분하군요. 자, 이제 시작하겠습니다…! 당신이 원하는 프레임워크를 C3와 함께!

Cloudflare는 CDN이자 Worker 애플리케이션을 배포하는 장소일 뿐만 아니라 이제 풀스택 웹 애플리케이션을 실행하는 최고의 장소가 되고 있습니다. 여기에는 Angular, Astro, Next, Nuxt, Qwik, Remix, Solid, Svelte, Vue 등과 같은 모든 풀스택 웹 프레임워크가 포함됩니다.

저희의 큰 목표는 더 나은 인터넷을 구축하는 것이며, 이 사명에 대한 저희의 기여는 개발자뿐만 아니라 누구나 아이디어를 실시간으로 배포된 애플리케이션으로 전환할 수 있도록 지원하는 것입니다.

개발자들이 아이디어를 빠르게, 그리고 번거로움 없이 배포된 애플리케이션으로 전환할 수 있도록 두 가지를 구축했습니다.

첫째, 여러 웹 프레임워크 작성자들과 협력하여 모든 널리 사용되는 자바스크립트 웹 프레임워크에 대해 새로운 어댑터를 만들거나 기존 어댑터를 개선했습니다. 이 어댑터들은 애플리케이션이 저희 플랫폼에서 가장 효율적인 방식으로 실행되도록 보장하면서, 플랫폼의 모든 기능과 능력에 접근할 수 있게 합니다.

이러한 어댑터에는 요청이 많았던 Next.js 어댑터가 포함되어 있으며, 방금 프로덕션 준비를 완료하고 오늘 1.0.0을 출시합니다! 각 팀과 협력하여 AngularQwik을 위한 새로운 어댑터를 구축했으며, Astro, Nuxt, Solid 및 몇 가지를 개선했습니다.

둘째, 저희는 C3라고 부르는 새롭고 멋진 CLI를 개발했습니다. 이는 create-cloudflare CLI를 의미하는 단축어로, 저희의 기존 Wrangler CLI의 형제입니다. 만약 당신이 터미널이나 VSCode와 같은 로컬 에디터에서 대부분의 시간을 보내는 개발자라면, 이 CLI는 Cloudflare 우주로 진입하게 해주는 단일 진입점입니다.

C3 명령을 실행하면 시작할 수 있습니다. 저희는 사용자와 열심히 작업하는 프레임워크 작성자 사이에 있는 것을 원하지 않기 때문에, 사용자가 원하는 프레임워크를 선택하면 C3는 제어권을 선택한 프레임워크의 CLI에게 넘깁니다. 잠시 후 npm 의존성이 모두 설치되고 나면 애플리케이션이 배포된 URL을 받게 됩니다. 이게 다입니다. 거의 즉시 아이디어로부터 공유할 수 있는 URL까지! 와우.

웹 애플리케이션을 위한 최적의 장소

정리하자면, 풀스택 웹 프레임워크에 대한 최고 수준의 지원과 플랫폼의 짧은 대기 시간 및 비용 효율성, 풀스택 웹 애플리케이션의 백엔드가 최적의 위치에서 자동으로 실행되도록 하는 스마트 배치, 그리고 개발자 도구의 나머지 모든 중요한 개선 사항이 결합되어 Cloudflare를 웹 애플리케이션을 구축하고 호스팅 하기 위한 최고의 장소로 만들어줍니다. 이것이 저희가 더 나은 인터넷을 만들기 위한 사명에 대한 기여이며, 웹을 전진시키는 방법입니다.

저희는 사람들이 비즈니스를 하고자 할 때, 또는 단지 창의력을 발휘하고 아이디어를 탐구하며 재미있게 보내고 싶을 때 찾는 장소가 되길 희망합니다. 이는 긴 여정이며, 앞으로 저희가 마주하게 될 흥미로운 도전들이 많습니다. 당신의 의견이 저희를 안내하는 데 결정적인 역할을 할 것입니다. 저희 모두는 이 일부가 될 기회를 얻게 되어 흥분하고 있으며, 최선을 다해보려고 합니다. 당신도 이 여행에 참여할 수 있으며, 바로 시작할 수 있습니다.

bash
npm create cloudflare my-first-app
+ \ No newline at end of file diff --git a/log/making-javascript-run-fast-on-webassembly.html b/log/making-javascript-run-fast-on-webassembly.html index 48a02724..3a0df21b 100644 --- a/log/making-javascript-run-fast-on-webassembly.html +++ b/log/making-javascript-run-fast-on-webassembly.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

웹어셈블리에서 자바스크립트를 빠르게 실행하는 방법

원문 : https://bytecodealliance.org/articles/making-javascript-run-fast-on-webassembly

js-on-wasm

20년 전과 비교하면 브라우저에서 자바스크립트는 훨씬 더 빠르게 실행됩니다. 브라우저 벤더사가 집중적으로 성능 최적화 작업에 시간을 할애했기 때문입니다.

오늘 우리는 다른 규칙이 적용되는, 완전히 다른 환경에서 자바스크립트 성능을 최적화하는 작업을 시작합니다. 그리고 이것은 웹어셈블리 덕에 가능합니다.

먼저 확실히 해야 할 것이 있습니다. 브라우저에서 자바스크립트를 실행할 때는 간단히 자바스크립트를 배포하는 것이 가장 합리적인 선택입니다. 브라우저 내의 자바스크립트 엔진(JS 엔진)은 탑재된 자바스크립트를 실행하기 위해 고도로 조정되어 있기 때문입니다.

하지만 만약 서버리스 함수에서 자바스크립트를 실행하고 있다면 어떨까요? 또는 iOS나 게임 콘솔과 같이 일반적인 JIT(Just-In-Time) 컴파일을 허용하지 않는 환경에서 자바스크립트를 실행하고 싶다면요?

이와 같은 사례들의 경우, 오늘 알아볼 새로운 자바스크립트 최적화 물결에 주의를 기울여야 합니다. 이 작업은 또 비슷한 환경들에서 빠르게 실행되기를 원하는 Python, Ruby, Lua과 같은 다른 런타임들의 모델 역할을 할 수도 있습니다.

그러나 본격적으로 알아보기 전에, 기본적인 작동 방식을 살펴봐야 합니다.

어떻게 작동하나요?

자바스크립트를 실행하려면, 자바스크립트 소스 코드는 어떤 방법으로든 기계어로 번역돼 실행되어야 합니다. 번역된 기계어는 인터프리터나 JIT 컴파일러와 같은, 다양한 기술을 사용하는 JS 엔진에서 수행됩니다. (자세한 사항은 JIT(Just-In-Time) 컴파일러 집중 과정를 참조하세요.)

Personified JS engine looking at JS source code and speaking the equivalent bytes of machine code out loud

그러나 만약 실행하려는 플랫폼에 JS 엔진이 없다면 어떻게 해야할까요? 코드와 함께 JS 엔진을 배포해야 합니다.

이를 위해 JS 엔진을 웹어셈블리 모듈로 배포해 다양한 종류의 머신 아키텍처에서 이식될 수 있도록 했습니다. 그리고 WASI(웹어셈블리 시스템 인터페이스)를 사용하면 다른 운영 체제에도 이식될 수 있습니다.

이는 전체 자바스크립트 환경이 이 웹어셈블리 인스턴스에 묶인다는 것을 의미합니다. 그래서 일단 배포하고 나면, 자바스크립트 코드를 전달하기만 하면 해당 코드가 실행됩니다.

A box representing the Wasm engine wrapping a box representing the JS engine, with a JS file being passed through the Wasm engine to the JS engine.

그럼 기계의 메모리에서 직접 작업이 이뤄지는 대신, JS 엔진은 바이트코드부터 바이트코드가 조작하는 GCed(Garbage Collected) 객체까지 모든 것을 Wasm 모듈의 선형 메모리에 넣습니다.

The personified JS engine putting translated machine code bytes into the linear memory inside its box

JS 엔진으로는 Firefox에서 사용되는 SpiderMonkey를 사용했습니다. SpiderMonkey는 브라우저에서 숱한 테스트를 거친, 업계에서 가장 강력한 자바스크립트 VM 중 하나입니다. 신뢰할 수 없는 코드 또는 신뢰할 수 없는 입력을 처리하는 코드를 실행할 때 이런 종류의 보안 테스트 및 투자는 중요합니다.

SpiderMonkey는 또한 정밀 스택 스캔(precise stack scanning)이라는 기술을 사용합니다. 뒤에서 설명하겠지만, 이는 일부 최적화에 중요한 기술입니다. 또 이해하고 읽기 매우 쉬운 코드 베이스를 가지고 있는데, 이는 Fastly, Mozilla 및 Igalia 3개의 다른 조직의 구성원들이 협력하고 있는 상황이기 때문에 중요합니다.

지금까지 설명한 접근 방식에서 혁신적인 것은 없습니다. 사람들은 이미 몇 년 동안 이처럼 웹어셈블리로 자바스크립트를 실행해 왔습니다.

문제는 느리다는 것입니다. 웹어셈블리는 새로운 기계 코드를 동적으로 생성하고 순수한 웹어셈블리 코드 내에서 실행할 수 없습니다. 즉, JIT를 사용할 수 없습니다. 인터프리터만 사용할 수 있습니다.

이 제약 조건을 감안하면, 당신은 다음과 같이 질문할 수 있습니다...

그럼 대체 왜 하는 건가요?

JIT를 통해 브라우저가 자바스크립트를 빠르게 실행할 수 있기 때문에(그리고 웹어셈블리는 모듈 내부에서 JIT 컴파일을 할 수 없기 때문에) 웹어셈블리를 사용하는 것이 직관에 반하는 것처럼 보일 수 있습니다.

A horrified developer screaming "But Why!?"

하지만 만약 이런 상황에도 불구하고 자바스크립트를 빠르게 실행할 수 있다면 어떨까요?

이게 가능할 때, 유용할 수 있는 몇 가지 사례를 살펴보겠습니다.

iOS(및 기타 JIT 제한 환경)에서 자바스크립트 실행

보안 문제로 인해 JIT를 사용할 수 없는 곳들이 있습니다 (예: 권한이 없는 iOS 앱, 일부 스마트 TV 및 게임 콘솔).

An iPhone, a smart TV, and a gaming controller

이런 플랫폼에서는 인터프리터를 사용해야 합니다. 하지만 이런 플랫폼에서 실행되는 애플리케이션은 오래 실행되며 많은 코드가 필요합니다… 역사적으로, 이런 환경은 실행 속도를 훨씬 더 늦추기 때문에 인터프리터를 사용하고 싶지 않은 환경입니다.

만약 기존 접근 방식을 빠르게 만들 수 있다면, 개발자들은 지나친 성능 저하 없이도 JIT가 없는 플랫폼에서 자바스크립트를 사용할 수 있습니다.

서버리스를 위한 즉각적인 콜드 스타트

JIT가 문제가 아니지만 서버리스 함수와 같이 시작 시간이 문제인 것들도 있습니다. 여러분들도 한 번쯤은 들어봤을 콜드 스타트(cold-start) 지연 문제입니다.

A picture of a cloud with lots of edge network nodes around it

가장 잘 갖춰진 자바스크립트 환경(순수히 JS 엔진만 가동하는 격리 환경)을 사용하는 경우에도 시작 지연 시간이 최소 5밀리 초까지 걸릴 수 있습니다. 여기에는 응용 프로그램을 초기화하는 데 걸리는 시간은 포함되지도 않습니다.

시작 시간 지연을 숨기는 방법들이 있습니다. 그러나 QUIC과 같은 제안에서 네트워크 계층에서 연결 시간이 최적화되고 있으므로 이를 숨기기가 점점 더 어려워지고 있습니다. 또한 여러 서버리스 기능을 함께 연결하는 것과 같은 작업을 수행할 때 이를 숨기는 것은 더욱 어렵습니다.

지연 시간을 숨기기 위해 이러한 기술을 사용하는 플랫폼은 종종 다른 요청 간에 인스턴스를 재사용합니다. 이는 때에 따라 서로 다른 요청 간에 전역 상태를 관찰할 수 있음을 의미하며 보안상 위험합니다.

콜드 스타트 문제로 인해 개발자들은 종종 모범 사례를 따르지 않습니다. 하나의 서버리스 배포에 많은 기능을 포함합니다. 이에 따라 장애 범위가 더 커질 수 있는 또 다른 보안 문제가 발생합니다. 해당 서버리스 배포의 한 부분이 악용되면 공격자는 해당 배포의 모든 항목에 접근할 수 있습니다.

On the left, a cartoon captioned "Risk between requests". It shows burgalers in a room filled with papers saying "Oooh payday... check out what they left behind!" On the right, a cartoon captioned "Risk between modules". It shows a tree of modules with a module at the bottom being exploded and other modules in the tree getting hit by shrapnel.

그러나 이런 상황에서 자바스크립트 시작 시간을 충분히 빠르게 할 수 있다면, 갖가지 방법으로 시작 시간을 숨길 필요가 없습니다. 그저 마이크로초 안에 인스턴스를 시작하면 됩니다.

결과적으로 각 요청마다 새 인스턴스를 사용할 수 있습니다. 즉, 여러 요청 사이에 공유되는 상태가 존재하지 않습니다.

이 인스턴스들은 매우 가볍기 때문에 개발자는 자유롭게 코드를 세분화할 수 있고, 단일 코드 조각에 대한 장애 반경이 최소화됩니다.

On the left, a cartoon captioed "isolation between requests". It shows the same bugalers, but in a totally clean room saying "Nuthin'... they didn't leave nuthin' behind." On the right, a cartoon captioned "isolation between modules". It shows a module graph with each module having its own box around it, and the explosion from the exploding module being contained to its own box

이 접근 방식에는 또 다른 보안 이점이 있습니다. 단순히 경량화되고 세분화된 격리를 가능하게 하는 것 외에도, Wasm 엔진의 보안 경계는 더 신뢰할 수 있습니다.

격리를 생성하는 데 사용되는 기존 JS 엔진은 매우 복잡한 최적화를 수행하는 많은 저수준 코드를 포함하는 대규모 코드 베이스입니다. 때문에, 공격자가 VM을 탈출하고 VM이 실행 중인 시스템에 액세스 할 수 있도록 허용하는 버그가 발견되기도 쉽습니다. 이것이 바로 ChromeFirefox에서 각 사이트가 완전히 분리된 프로세스에서 실행되도록 최대한 노력하는 이유입니다.

이와 비교해서, Wasm 엔진은 훨씬 적은 코드가 필요하므로 검사하기가 더 쉽고, 많은 부분이 메모리 안전성이 보장된 언어인 Rust로 작성됩니다. 그리고 웹어셈블리 모듈에서 생성된 기본 바이너리의 메모리 격리는 검증할 수 있습니다.

Wasm 엔진 내부에서 JS 엔진을 실행함으로써 우리는 외부에 더 안전한 샌드박스 경계를 또 다른 방어선으로 갖게 됩니다.

앞선 사례들을 살펴보니 Wasm에서 자바스크립트를 빠르게 만드는 것에는 큰 이점이 있었습니다. 그래서 어떻게 할 수 있을까요?

이 질문에 답하려면, JS 엔진이 시간을 할애하는 영역을 이해해야 합니다.

JS 엔진이 시간을 보내는 두 영역

JS 엔진이 수행하는 작업은 대략 두 부분으로 나눌 수 있습니다: 초기화와 런타임.

저는 JS 엔진을 청부업자라고 생각합니다. 이 청부업자는 자바스크립트 코드를 실행하고 결과를 얻는 작업을 완료하기 위해 존재합니다.

The JS engine shaking hands with a JS file and saying "I'm looking forward to helping you with this project!"

초기화 단계

청부업자는 실제로 프로젝트 실행을 시작하기 전에 약간의 예비 작업을 수행해야 합니다. 초기화 단계에는 실행의 시작 단계에서 한 번만 실행되면 되는 모든 것들이 포함됩니다.

애플리케이션 초기화

모든 프로젝트에서 청부업자는 고객이 원하는 작업을 살펴본 다음, 해당 작업을 완료하는 데 필요한 리소스들을 설정합니다.

예를 들어, 청부업자는 프로젝트 브리핑 및 기타 문서들을 읽고 작업하기 쉬운 형식으로 변환합니다. 예를 들어 모든 문서를 저장하고 정리하면서 프로젝트 관리 시스템을 세팅합니다.

The JS engine sitting in its office with the JS file and saying "So tell me more about the work you want to get done"

JS 엔진의 경우 이 작업은 소스 코드의 최상위 레벨을 읽어가며 함수를 바이트 코드로 파싱 하고, 선언된 변수에 메모리를 할당하고, 이미 정의된 값들을 세팅하는 것과 비슷합니다.

엔진 초기화

서버리스와 같은 특정 환경에서는, 각 애플리케이션 초기화 전에 발생하는 또 다른 초기화 부분이 있습니다.

바로 엔진 초기화입니다. 먼저 JS 엔진 자체를 시작해야 하고 내장 함수들을 환경에 추가해야 합니다.

이는 작업을 시작하기 전에 이케아 의자와 테이블을 조립하는 것처럼 사무실 자체를 세팅하는 것과 비슷하다고 생각합니다.

The JS engine building the IKEA table for its office

이 작업은 상당한 시간이 걸릴 수 있으며 서버리스 사용 사례에서 콜드 스타트 문제를 만드는 원인이기도 합니다.

런타임 단계

초기화 단계가 완료되면 JS 엔진이 코드 실행 작업을 시작할 수 있습니다.

The JS engine moving cards across a Kanban board, all the way to the done position

이 영역의 속도를 스루풋(throughput)이라고 하며 이 스루풋은 다양한 변수의 영향을 받습니다. 예를 들어보면,

  • 사용하는 언어의 기능
  • JS 엔진의 관점에서 코드가 예측할 수 있게 동작하는지 여부
  • 어떤 종류의 데이터 구조가 사용되는지
  • 코드가 JS 엔진의 최적화 컴파일러를 활용할 수 있을 만큼 충분히 오래 실행되는지 여부

이것이 JS 엔진이 시간을 보내는 두 단계입니다.

A sequence of the three previous images, showing the office building and requirements gathering as initialization, and moving work across the Kanban board as runtime.

그럼 이 두 단계의 작업을 어떻게 더 빠르게 진행할 수 있을까요?

초기화 시간을 대폭 단축시키기

우리는 Wizer라는 도구로 초기화를 빠르게 만들기 시작했습니다. 천천히 설명하겠지만 성급하신 분들을 위해 먼저 보여드리겠습니다, 간단한 자바스크립트 애플리케이션을 실행할 때 아래와 같은 속도 향상이 있었습니다.

A graph showing startup latency times. JS isolate takes 5ms and JS on Wasm takes 0.36ms.

간단한 애플리케이션을 Wizer로 실행하면 0.36 밀리초(또는 360 마이크로초)밖에 걸리지 않았습니다. 이는 일반적인 자바스크립트 접근 방식에서보다 13배 이상 빠릅니다.

우리는 스냅샷이라는 것을 사용해 시작 시간을 향상시켰습니다. Nick Fitzgerald가 WebAssembly Summit talk about Wizer에서 자세히 설명했습니다.

그래서 어떻게 작동하냐구요? 코드가 배포되기 전 빌드 단계의 일환으로, 초기화가 끝날 때까지 JS 엔진을 사용하여 자바스크립트 코드를 실행합니다.

이 시점에 JS 엔진은 모든 자바스크립트를 파싱해 바이트코드로 전환하고, 이 바이트코드는 JS 엔진 모듈에 의해 선형 메모리에 저장됩니다. 또한 이 단계에서 엔진은 많은 메모리 할당 및 초기화를 수행합니다.

이 선형 메모리는 매우 독립적이기 때문에, 모든 값이 채워지면 그저 메모리를 가져와 데이터 섹션으로써 Wasm 모듈에 연결할 수 있습니다.

JS 엔진 모듈이 인스턴스화 되면, 데이터 섹션의 모든 데이터에 접근할 수 있습니다. 엔진이 어떤 데이터가 필요하다면 필요한 데이터 섹션(또는 그저 메모리 페이지를)을 자체 선형 메모리에 복사할 수 있습니다. 따라서 JS 엔진은 시작할 때 어떤 설정도 할 필요가 없습니다. 사전에 초기화된 모든 값이 준비되어 대기 중입니다.

A wasm file split between code and data sections, with the data section being poured into linear memory.

현재는 이 데이터 섹션을 JS 엔진과 동일한 모듈에 연결합니다. 하지만 앞으로 모듈 연결이 준비되면 데이터 섹션을 별도의 모듈로 이용할 수 있습니다. 그럼 JS 엔진 모듈을 다양한 자바스크립트 애플리케이션에서 재사용할 수 있습니다.

이렇게 되면 정말 깔끔한 분리가 가능합니다.

JS 엔진 모듈은 엔진용 코드만 포함하게 됩니다. 즉, 일단 컴파일되면 해당 코드를 효과적으로 캐시 하고 많은 다른 인스턴스 간에 재사용할 수 있습니다.

반면 애플리케이션 모듈에는 Wasm 코드가 포함되지 않습니다. 초기화된 나머지 JS 엔진 상태와 함께 자바스크립트 바이트코드를 포함하는 선형 메모리만 포함합니다. 이렇게 하면 이 메모리를 쉽게 필요한 곳으로 보낼 수 있습니다.

Two wasm files next to each other. The one for the JS engine module only has a code section, the other for the JS application module only has a data section

이건 마치 JS 엔진 청부업자에게 사무실이 전혀 필요하지 않은 것과 같습니다. 대신 여행용 케이스만 가지고 다닙니다. 여행용 케이스에는 전체 사무실이 있고, JS 엔진이 작동할 수 있도록 모든 설정과 준비도 되어 있습니다.

A personified Wasm engine placing a snapshot of the JS engine's office down inside of the Wasm engine and saying "I'll just set this down for you so you can get right to work"

그리고 이 방식의 가장 멋진 점은 자바스크립트에 의존적이지 않다는 것입니다. 웹어셈블리의 기존 속성을 사용하는 것뿐입니다. 따라서 Python, Ruby, Lua 또는 기타 런타임에서도 이와 동일한 기술을 사용할 수 있습니다.

다음 단계: 스루풋 개선

따라서 이 접근 방식을 사용해 매우 빠른 초기화 시간을 얻을 수 있습니다. 그럼 스루풋은요?

일부 사용 사례의 경우 스루풋이 그렇게 나쁘지 않습니다. 매우 짧게 실행되는 자바스크립트 조각인 경우, 어쨌든 JIT를 거치지 않고 전체가 인터프리터를 통해 실행됩니다. 따라서 이 경우 스루풋은 브라우저에서와 거의 동일하며, 기존의 JS 엔진이 초기화를 완료하기 전에 완료됩니다.

그러나 더 오래 실행되는 자바스크립트라면 JIT가 금방 작동하기 시작합니다. 일단 작동하기 시작하면 스루풋 차이가 분명해지기 시작합니다.

위에서 말했듯이 현재 순수한 웹어셈블리 내에서 코드를 JIT 컴파일하는 것은 불가능합니다. 다만 JIT에 적용되는 개념 중 일부를 Ahead-Of-Time 컴파일 모델에 적용할 수 있음이 밝혀졌습니다.

(프로파일링 없이) AOT 컴파일된 빠른 JS

JIT가 사용하는 한 가지 최적화 기술은 인라인 캐싱(Inline Caching, 이하 IC)입니다. 인라인 캐싱을 통해, JIT는 자바스크립트 바이트코드가 과거에 실행된 모든 방식에 대한 빠른 기계어 경로를 포함하는 스텁의 연결 리스트를 생성합니다. (자세한 사항은 JIT(Just-In-Time) 컴파일러 집중 과정 참고하세요)

The personified JS engine standing in front of a matrix of JS bytecode entries and creating machine code stubs for them based on frequency feedback from a monitor

이 리스트가 필요한 이유는 자바스크립트의 동적 타입 때문입니다. 코드 라인이 다른 타입을 사용할 때마다 새 스텁을 생성하고 목록에 추가해야 합니다. 그러나 이전에 같은 타입을 사용해 실행한 적이 있다면 이미 생성된 스텁을 사용할 수 있습니다.

인라인 캐싱은 일반적으로 JIT에서 사용되기 때문에, 인라인 캐싱이 매우 동적이고 프로그램마다 고유하다고 생각되는 경우가 많습니다. 그러나 AOT 환경에서도 적용될 수 있음이 밝혀졌습니다.

그리고 자바스크립트 코드를 살펴보지 않아도, 생성해야 할 많은 IC 스텁들을 알 수 있습니다. JS에는 많이 사용되는 패턴이 있기 때문입니다.

좋은 예는 객체의 속성에 접근하는 것입니다. 이는 많은 자바스크립트 코드에서 일어나며 IC 스텁을 사용해 속도를 높일 수 있습니다. 특정 "모양(shape)" 또는 "숨겨진 클래스"(즉, 동일한 방식으로 배치된 속성들)가 있는 객체의 경우 특정 속성에 접근할 때 해당 속성은 항상 동일한 오프셋에 있습니다.

전통적으로 JIT의 이러한 종류의 IC 스텁은 모양에 대한 포인터와 속성의 오프셋이라는 두 가지 값을 하드 코딩합니다. 이를 위해서는 사전에(Ahead-Of-Time)는 알 수 없는 정보가 필요합니다. 그러나 우리는 IC 스텁을 매개변수화 할 수 있습니다. 모양과 속성 오프셋을 스텁에 전달되는 변수로 취급할 수 있습니다.

이렇게 하면 메모리에서 값을 로드하는 단일 스텁을 생성한 다음, 모든 곳에서 이 스텁 코드를 사용할 수 있습니다. 자바스크립트 코드가 실제로 수행하는 작업과 관계없이 이러한 공통 패턴들에 대한 모든 스텁을 AOT 컴파일된 모듈에 만들어들 수 있습니다. 심지어 브라우저에서도 이 IC를 공유하면 유용할 수 있습니다. JS 엔진이 더 적은 기계어를 생성하게 돼 시작 시간과 명령 캐시 지역성(instruction-cache locality)을 개선하기 때문입니다.

이번 사례에서는 이 개념이 특히 중요합니다. 자바스크립트 코드가 실제로 수행하는 작업과 관계없이, 이러한 공통 패턴에 대한 모든 스텁을 AOT 컴파일된 모듈에 마련해둘 수 있음을 의미하기 때문입니다.

우리는 몇 킬로바이트의 IC 스텁으로 모든 자바스크립트 코드의 대부분을 다룰 수 있다는 것을 발견했습니다. 예를 들어 2KB의 IC 스텁으로 Google Octane 벤치마크에서 자바스크립트의 95%를 커버할 수 있습니다. 예비 테스트에서 이 비율은 일반적인 웹 브라우징에서도 유지되는 것으로 보입니다.

A small pile of stubs on the left and a large pile of JS files on the right

이런 종류의 최적화를 적용하면 초기 JIT와 동등한 스루풋에 도달할 수 있을 것입니다. 해당 작업을 완료하고 나면 브라우저의 JS 엔진 팀이 초기 JIT에서 그랬듯이, 더 디테일한 최적화를 추가하고 성능을 연마할 것입니다.

다음, 다음 단계: 약간의 프로파일링을 추가할 수 있을지도요?

앞서 말한 것들이 프로그램이 뭘 하고 어떤 타입들이 프로그램에서 사용되는지 알지 못한 채로, 미리(Ahead-Of-Time) 할 수 있는 것들입니다.

그러나 JIT가 가지고 있는 것과 같은 종류의 프로파일링 정보에 접근할 수 있다면 어떨까요? 그럼 코드를 완전히 최적화할 수 있습니다.

다만 여기에는 문제가 있습니다. 개발자는 종종 자신의 코드를 프로파일링하는 데 어려움을 겪습니다. 대표적인 샘플 워크로드를 찾는 건 어렵습니다. 따라서 좋은 프로파일링 데이터를 얻을 수 있을지 확신할 수 없습니다.

프로파일링을 위해 좋은 도구를 사용할 수 있는 방법을 알아낼 수만 있다면, 자바스크립트를 오늘날의 JIT만큼 빠르게 실행할 수도 있습니다 (그리고 이 방식에는 예열 시간도 필요 없습니다!).

당장 시작하는 방법

우리는 이 새로운 접근 방식에 대해 매우 기대가 크고, 어디까지 추진할 수 있을지 기대하고 있습니다. 또 다른 동적 타입 언어들이 같은 방식으로 웹어셈블리에 제공되는 것을 보기를 기대하고 있습니다.

당장 시작할 수 있는 몇 가지 방법이 있습니다. 궁금한 점이 있는 경우 Zulip에서 물어보세요.

자바스크립트를 지원하려는 다른 플랫폼의 경우

자체 플랫폼에서 자바스크립트를 실행하려면 WASI를 지원하는 웹어셈블리 엔진을 내장해야 합니다. 이를 위해 Wasmtime를 사용할 수 있습니다.

그런 다음 JS 엔진이 필요합니다. 이 작업의 일환으로 SpiderMonkey를 WASI로 컴파일하기 위해 Mozilla의 빌드 시스템에 대해 전폭적인 지원을 하고 있습니다. 그리고 Mozilla는 Firefox를 빌드하고 테스트하는 데 사용되는 것과 동일한 CI 설정에 SpiderMonkey용 WASI 빌드를 추가하려고 합니다. 이는 WASI가 SpiderMonkey의 프로덕션 목표 중 하나가 되게 하고, WASI 빌드가 시간이 지나도 계속 작동함을 보장합니다. 즉, 앞서 설명한 방식 그대로 SpiderMonkey를 사용할 수 있습니다.

마지막으로, 사용자가 사전 초기화된 JS를 가져와야 합니다. 이를 돕기 위해 Wizer를 오픈 소스화 했고, 이를 빌드 도구에 통합해 JS 엔진 모듈의 사전 초기화된 메모리를 채우는, 애플리케이션별 웹어셈블리 모듈을 생성할 수 있습니다.

이 접근 방식을 사용하려는 다른 언어의 경우

Python, Ruby, Lua 등과 같은 언어 커뮤니티의 일원이라면 해당 언어에 대한 버전도 빌드할 수 있습니다.

먼저, 앞서 SpiderMonkey를 이용했던 것처럼, 시스템 호출에는 WASI를 사용하여 런타임을 웹어셈블리로 컴파일해야 합니다. 그런 다음 스냅샷으로 빠른 시작 시간을 얻으려면 역시 앞서 설명한 것처럼 Wizer를 빌드 도구에 통합해 메모리 스냅샷을 생성할 수 있습니다.



- +
Skip to content
On this page

웹어셈블리에서 자바스크립트를 빠르게 실행하는 방법

원문 : https://bytecodealliance.org/articles/making-javascript-run-fast-on-webassembly

js-on-wasm

20년 전과 비교하면 브라우저에서 자바스크립트는 훨씬 더 빠르게 실행됩니다. 브라우저 벤더사가 집중적으로 성능 최적화 작업에 시간을 할애했기 때문입니다.

오늘 우리는 다른 규칙이 적용되는, 완전히 다른 환경에서 자바스크립트 성능을 최적화하는 작업을 시작합니다. 그리고 이것은 웹어셈블리 덕에 가능합니다.

먼저 확실히 해야 할 것이 있습니다. 브라우저에서 자바스크립트를 실행할 때는 간단히 자바스크립트를 배포하는 것이 가장 합리적인 선택입니다. 브라우저 내의 자바스크립트 엔진(JS 엔진)은 탑재된 자바스크립트를 실행하기 위해 고도로 조정되어 있기 때문입니다.

하지만 만약 서버리스 함수에서 자바스크립트를 실행하고 있다면 어떨까요? 또는 iOS나 게임 콘솔과 같이 일반적인 JIT(Just-In-Time) 컴파일을 허용하지 않는 환경에서 자바스크립트를 실행하고 싶다면요?

이와 같은 사례들의 경우, 오늘 알아볼 새로운 자바스크립트 최적화 물결에 주의를 기울여야 합니다. 이 작업은 또 비슷한 환경들에서 빠르게 실행되기를 원하는 Python, Ruby, Lua과 같은 다른 런타임들의 모델 역할을 할 수도 있습니다.

그러나 본격적으로 알아보기 전에, 기본적인 작동 방식을 살펴봐야 합니다.

어떻게 작동하나요?

자바스크립트를 실행하려면, 자바스크립트 소스 코드는 어떤 방법으로든 기계어로 번역돼 실행되어야 합니다. 번역된 기계어는 인터프리터나 JIT 컴파일러와 같은, 다양한 기술을 사용하는 JS 엔진에서 수행됩니다. (자세한 사항은 JIT(Just-In-Time) 컴파일러 집중 과정를 참조하세요.)

Personified JS engine looking at JS source code and speaking the equivalent bytes of machine code out loud

그러나 만약 실행하려는 플랫폼에 JS 엔진이 없다면 어떻게 해야할까요? 코드와 함께 JS 엔진을 배포해야 합니다.

이를 위해 JS 엔진을 웹어셈블리 모듈로 배포해 다양한 종류의 머신 아키텍처에서 이식될 수 있도록 했습니다. 그리고 WASI(웹어셈블리 시스템 인터페이스)를 사용하면 다른 운영 체제에도 이식될 수 있습니다.

이는 전체 자바스크립트 환경이 이 웹어셈블리 인스턴스에 묶인다는 것을 의미합니다. 그래서 일단 배포하고 나면, 자바스크립트 코드를 전달하기만 하면 해당 코드가 실행됩니다.

A box representing the Wasm engine wrapping a box representing the JS engine, with a JS file being passed through the Wasm engine to the JS engine.

그럼 기계의 메모리에서 직접 작업이 이뤄지는 대신, JS 엔진은 바이트코드부터 바이트코드가 조작하는 GCed(Garbage Collected) 객체까지 모든 것을 Wasm 모듈의 선형 메모리에 넣습니다.

The personified JS engine putting translated machine code bytes into the linear memory inside its box

JS 엔진으로는 Firefox에서 사용되는 SpiderMonkey를 사용했습니다. SpiderMonkey는 브라우저에서 숱한 테스트를 거친, 업계에서 가장 강력한 자바스크립트 VM 중 하나입니다. 신뢰할 수 없는 코드 또는 신뢰할 수 없는 입력을 처리하는 코드를 실행할 때 이런 종류의 보안 테스트 및 투자는 중요합니다.

SpiderMonkey는 또한 정밀 스택 스캔(precise stack scanning)이라는 기술을 사용합니다. 뒤에서 설명하겠지만, 이는 일부 최적화에 중요한 기술입니다. 또 이해하고 읽기 매우 쉬운 코드 베이스를 가지고 있는데, 이는 Fastly, Mozilla 및 Igalia 3개의 다른 조직의 구성원들이 협력하고 있는 상황이기 때문에 중요합니다.

지금까지 설명한 접근 방식에서 혁신적인 것은 없습니다. 사람들은 이미 몇 년 동안 이처럼 웹어셈블리로 자바스크립트를 실행해 왔습니다.

문제는 느리다는 것입니다. 웹어셈블리는 새로운 기계 코드를 동적으로 생성하고 순수한 웹어셈블리 코드 내에서 실행할 수 없습니다. 즉, JIT를 사용할 수 없습니다. 인터프리터만 사용할 수 있습니다.

이 제약 조건을 감안하면, 당신은 다음과 같이 질문할 수 있습니다...

그럼 대체 왜 하는 건가요?

JIT를 통해 브라우저가 자바스크립트를 빠르게 실행할 수 있기 때문에(그리고 웹어셈블리는 모듈 내부에서 JIT 컴파일을 할 수 없기 때문에) 웹어셈블리를 사용하는 것이 직관에 반하는 것처럼 보일 수 있습니다.

A horrified developer screaming "But Why!?"

하지만 만약 이런 상황에도 불구하고 자바스크립트를 빠르게 실행할 수 있다면 어떨까요?

이게 가능할 때, 유용할 수 있는 몇 가지 사례를 살펴보겠습니다.

iOS(및 기타 JIT 제한 환경)에서 자바스크립트 실행

보안 문제로 인해 JIT를 사용할 수 없는 곳들이 있습니다 (예: 권한이 없는 iOS 앱, 일부 스마트 TV 및 게임 콘솔).

An iPhone, a smart TV, and a gaming controller

이런 플랫폼에서는 인터프리터를 사용해야 합니다. 하지만 이런 플랫폼에서 실행되는 애플리케이션은 오래 실행되며 많은 코드가 필요합니다… 역사적으로, 이런 환경은 실행 속도를 훨씬 더 늦추기 때문에 인터프리터를 사용하고 싶지 않은 환경입니다.

만약 기존 접근 방식을 빠르게 만들 수 있다면, 개발자들은 지나친 성능 저하 없이도 JIT가 없는 플랫폼에서 자바스크립트를 사용할 수 있습니다.

서버리스를 위한 즉각적인 콜드 스타트

JIT가 문제가 아니지만 서버리스 함수와 같이 시작 시간이 문제인 것들도 있습니다. 여러분들도 한 번쯤은 들어봤을 콜드 스타트(cold-start) 지연 문제입니다.

A picture of a cloud with lots of edge network nodes around it

가장 잘 갖춰진 자바스크립트 환경(순수히 JS 엔진만 가동하는 격리 환경)을 사용하는 경우에도 시작 지연 시간이 최소 5밀리 초까지 걸릴 수 있습니다. 여기에는 응용 프로그램을 초기화하는 데 걸리는 시간은 포함되지도 않습니다.

시작 시간 지연을 숨기는 방법들이 있습니다. 그러나 QUIC과 같은 제안에서 네트워크 계층에서 연결 시간이 최적화되고 있으므로 이를 숨기기가 점점 더 어려워지고 있습니다. 또한 여러 서버리스 기능을 함께 연결하는 것과 같은 작업을 수행할 때 이를 숨기는 것은 더욱 어렵습니다.

지연 시간을 숨기기 위해 이러한 기술을 사용하는 플랫폼은 종종 다른 요청 간에 인스턴스를 재사용합니다. 이는 때에 따라 서로 다른 요청 간에 전역 상태를 관찰할 수 있음을 의미하며 보안상 위험합니다.

콜드 스타트 문제로 인해 개발자들은 종종 모범 사례를 따르지 않습니다. 하나의 서버리스 배포에 많은 기능을 포함합니다. 이에 따라 장애 범위가 더 커질 수 있는 또 다른 보안 문제가 발생합니다. 해당 서버리스 배포의 한 부분이 악용되면 공격자는 해당 배포의 모든 항목에 접근할 수 있습니다.

On the left, a cartoon captioned "Risk between requests". It shows burgalers in a room filled with papers saying "Oooh payday... check out what they left behind!" On the right, a cartoon captioned "Risk between modules". It shows a tree of modules with a module at the bottom being exploded and other modules in the tree getting hit by shrapnel.

그러나 이런 상황에서 자바스크립트 시작 시간을 충분히 빠르게 할 수 있다면, 갖가지 방법으로 시작 시간을 숨길 필요가 없습니다. 그저 마이크로초 안에 인스턴스를 시작하면 됩니다.

결과적으로 각 요청마다 새 인스턴스를 사용할 수 있습니다. 즉, 여러 요청 사이에 공유되는 상태가 존재하지 않습니다.

이 인스턴스들은 매우 가볍기 때문에 개발자는 자유롭게 코드를 세분화할 수 있고, 단일 코드 조각에 대한 장애 반경이 최소화됩니다.

On the left, a cartoon captioed "isolation between requests". It shows the same bugalers, but in a totally clean room saying "Nuthin'... they didn't leave nuthin' behind." On the right, a cartoon captioned "isolation between modules". It shows a module graph with each module having its own box around it, and the explosion from the exploding module being contained to its own box

이 접근 방식에는 또 다른 보안 이점이 있습니다. 단순히 경량화되고 세분화된 격리를 가능하게 하는 것 외에도, Wasm 엔진의 보안 경계는 더 신뢰할 수 있습니다.

격리를 생성하는 데 사용되는 기존 JS 엔진은 매우 복잡한 최적화를 수행하는 많은 저수준 코드를 포함하는 대규모 코드 베이스입니다. 때문에, 공격자가 VM을 탈출하고 VM이 실행 중인 시스템에 액세스 할 수 있도록 허용하는 버그가 발견되기도 쉽습니다. 이것이 바로 ChromeFirefox에서 각 사이트가 완전히 분리된 프로세스에서 실행되도록 최대한 노력하는 이유입니다.

이와 비교해서, Wasm 엔진은 훨씬 적은 코드가 필요하므로 검사하기가 더 쉽고, 많은 부분이 메모리 안전성이 보장된 언어인 Rust로 작성됩니다. 그리고 웹어셈블리 모듈에서 생성된 기본 바이너리의 메모리 격리는 검증할 수 있습니다.

Wasm 엔진 내부에서 JS 엔진을 실행함으로써 우리는 외부에 더 안전한 샌드박스 경계를 또 다른 방어선으로 갖게 됩니다.

앞선 사례들을 살펴보니 Wasm에서 자바스크립트를 빠르게 만드는 것에는 큰 이점이 있었습니다. 그래서 어떻게 할 수 있을까요?

이 질문에 답하려면, JS 엔진이 시간을 할애하는 영역을 이해해야 합니다.

JS 엔진이 시간을 보내는 두 영역

JS 엔진이 수행하는 작업은 대략 두 부분으로 나눌 수 있습니다: 초기화와 런타임.

저는 JS 엔진을 청부업자라고 생각합니다. 이 청부업자는 자바스크립트 코드를 실행하고 결과를 얻는 작업을 완료하기 위해 존재합니다.

The JS engine shaking hands with a JS file and saying "I'm looking forward to helping you with this project!"

초기화 단계

청부업자는 실제로 프로젝트 실행을 시작하기 전에 약간의 예비 작업을 수행해야 합니다. 초기화 단계에는 실행의 시작 단계에서 한 번만 실행되면 되는 모든 것들이 포함됩니다.

애플리케이션 초기화

모든 프로젝트에서 청부업자는 고객이 원하는 작업을 살펴본 다음, 해당 작업을 완료하는 데 필요한 리소스들을 설정합니다.

예를 들어, 청부업자는 프로젝트 브리핑 및 기타 문서들을 읽고 작업하기 쉬운 형식으로 변환합니다. 예를 들어 모든 문서를 저장하고 정리하면서 프로젝트 관리 시스템을 세팅합니다.

The JS engine sitting in its office with the JS file and saying "So tell me more about the work you want to get done"

JS 엔진의 경우 이 작업은 소스 코드의 최상위 레벨을 읽어가며 함수를 바이트 코드로 파싱 하고, 선언된 변수에 메모리를 할당하고, 이미 정의된 값들을 세팅하는 것과 비슷합니다.

엔진 초기화

서버리스와 같은 특정 환경에서는, 각 애플리케이션 초기화 전에 발생하는 또 다른 초기화 부분이 있습니다.

바로 엔진 초기화입니다. 먼저 JS 엔진 자체를 시작해야 하고 내장 함수들을 환경에 추가해야 합니다.

이는 작업을 시작하기 전에 이케아 의자와 테이블을 조립하는 것처럼 사무실 자체를 세팅하는 것과 비슷하다고 생각합니다.

The JS engine building the IKEA table for its office

이 작업은 상당한 시간이 걸릴 수 있으며 서버리스 사용 사례에서 콜드 스타트 문제를 만드는 원인이기도 합니다.

런타임 단계

초기화 단계가 완료되면 JS 엔진이 코드 실행 작업을 시작할 수 있습니다.

The JS engine moving cards across a Kanban board, all the way to the done position

이 영역의 속도를 스루풋(throughput)이라고 하며 이 스루풋은 다양한 변수의 영향을 받습니다. 예를 들어보면,

  • 사용하는 언어의 기능
  • JS 엔진의 관점에서 코드가 예측할 수 있게 동작하는지 여부
  • 어떤 종류의 데이터 구조가 사용되는지
  • 코드가 JS 엔진의 최적화 컴파일러를 활용할 수 있을 만큼 충분히 오래 실행되는지 여부

이것이 JS 엔진이 시간을 보내는 두 단계입니다.

A sequence of the three previous images, showing the office building and requirements gathering as initialization, and moving work across the Kanban board as runtime.

그럼 이 두 단계의 작업을 어떻게 더 빠르게 진행할 수 있을까요?

초기화 시간을 대폭 단축시키기

우리는 Wizer라는 도구로 초기화를 빠르게 만들기 시작했습니다. 천천히 설명하겠지만 성급하신 분들을 위해 먼저 보여드리겠습니다, 간단한 자바스크립트 애플리케이션을 실행할 때 아래와 같은 속도 향상이 있었습니다.

A graph showing startup latency times. JS isolate takes 5ms and JS on Wasm takes 0.36ms.

간단한 애플리케이션을 Wizer로 실행하면 0.36 밀리초(또는 360 마이크로초)밖에 걸리지 않았습니다. 이는 일반적인 자바스크립트 접근 방식에서보다 13배 이상 빠릅니다.

우리는 스냅샷이라는 것을 사용해 시작 시간을 향상시켰습니다. Nick Fitzgerald가 WebAssembly Summit talk about Wizer에서 자세히 설명했습니다.

그래서 어떻게 작동하냐구요? 코드가 배포되기 전 빌드 단계의 일환으로, 초기화가 끝날 때까지 JS 엔진을 사용하여 자바스크립트 코드를 실행합니다.

이 시점에 JS 엔진은 모든 자바스크립트를 파싱해 바이트코드로 전환하고, 이 바이트코드는 JS 엔진 모듈에 의해 선형 메모리에 저장됩니다. 또한 이 단계에서 엔진은 많은 메모리 할당 및 초기화를 수행합니다.

이 선형 메모리는 매우 독립적이기 때문에, 모든 값이 채워지면 그저 메모리를 가져와 데이터 섹션으로써 Wasm 모듈에 연결할 수 있습니다.

JS 엔진 모듈이 인스턴스화 되면, 데이터 섹션의 모든 데이터에 접근할 수 있습니다. 엔진이 어떤 데이터가 필요하다면 필요한 데이터 섹션(또는 그저 메모리 페이지를)을 자체 선형 메모리에 복사할 수 있습니다. 따라서 JS 엔진은 시작할 때 어떤 설정도 할 필요가 없습니다. 사전에 초기화된 모든 값이 준비되어 대기 중입니다.

A wasm file split between code and data sections, with the data section being poured into linear memory.

현재는 이 데이터 섹션을 JS 엔진과 동일한 모듈에 연결합니다. 하지만 앞으로 모듈 연결이 준비되면 데이터 섹션을 별도의 모듈로 이용할 수 있습니다. 그럼 JS 엔진 모듈을 다양한 자바스크립트 애플리케이션에서 재사용할 수 있습니다.

이렇게 되면 정말 깔끔한 분리가 가능합니다.

JS 엔진 모듈은 엔진용 코드만 포함하게 됩니다. 즉, 일단 컴파일되면 해당 코드를 효과적으로 캐시 하고 많은 다른 인스턴스 간에 재사용할 수 있습니다.

반면 애플리케이션 모듈에는 Wasm 코드가 포함되지 않습니다. 초기화된 나머지 JS 엔진 상태와 함께 자바스크립트 바이트코드를 포함하는 선형 메모리만 포함합니다. 이렇게 하면 이 메모리를 쉽게 필요한 곳으로 보낼 수 있습니다.

Two wasm files next to each other. The one for the JS engine module only has a code section, the other for the JS application module only has a data section

이건 마치 JS 엔진 청부업자에게 사무실이 전혀 필요하지 않은 것과 같습니다. 대신 여행용 케이스만 가지고 다닙니다. 여행용 케이스에는 전체 사무실이 있고, JS 엔진이 작동할 수 있도록 모든 설정과 준비도 되어 있습니다.

A personified Wasm engine placing a snapshot of the JS engine's office down inside of the Wasm engine and saying "I'll just set this down for you so you can get right to work"

그리고 이 방식의 가장 멋진 점은 자바스크립트에 의존적이지 않다는 것입니다. 웹어셈블리의 기존 속성을 사용하는 것뿐입니다. 따라서 Python, Ruby, Lua 또는 기타 런타임에서도 이와 동일한 기술을 사용할 수 있습니다.

다음 단계: 스루풋 개선

따라서 이 접근 방식을 사용해 매우 빠른 초기화 시간을 얻을 수 있습니다. 그럼 스루풋은요?

일부 사용 사례의 경우 스루풋이 그렇게 나쁘지 않습니다. 매우 짧게 실행되는 자바스크립트 조각인 경우, 어쨌든 JIT를 거치지 않고 전체가 인터프리터를 통해 실행됩니다. 따라서 이 경우 스루풋은 브라우저에서와 거의 동일하며, 기존의 JS 엔진이 초기화를 완료하기 전에 완료됩니다.

그러나 더 오래 실행되는 자바스크립트라면 JIT가 금방 작동하기 시작합니다. 일단 작동하기 시작하면 스루풋 차이가 분명해지기 시작합니다.

위에서 말했듯이 현재 순수한 웹어셈블리 내에서 코드를 JIT 컴파일하는 것은 불가능합니다. 다만 JIT에 적용되는 개념 중 일부를 Ahead-Of-Time 컴파일 모델에 적용할 수 있음이 밝혀졌습니다.

(프로파일링 없이) AOT 컴파일된 빠른 JS

JIT가 사용하는 한 가지 최적화 기술은 인라인 캐싱(Inline Caching, 이하 IC)입니다. 인라인 캐싱을 통해, JIT는 자바스크립트 바이트코드가 과거에 실행된 모든 방식에 대한 빠른 기계어 경로를 포함하는 스텁의 연결 리스트를 생성합니다. (자세한 사항은 JIT(Just-In-Time) 컴파일러 집중 과정 참고하세요)

The personified JS engine standing in front of a matrix of JS bytecode entries and creating machine code stubs for them based on frequency feedback from a monitor

이 리스트가 필요한 이유는 자바스크립트의 동적 타입 때문입니다. 코드 라인이 다른 타입을 사용할 때마다 새 스텁을 생성하고 목록에 추가해야 합니다. 그러나 이전에 같은 타입을 사용해 실행한 적이 있다면 이미 생성된 스텁을 사용할 수 있습니다.

인라인 캐싱은 일반적으로 JIT에서 사용되기 때문에, 인라인 캐싱이 매우 동적이고 프로그램마다 고유하다고 생각되는 경우가 많습니다. 그러나 AOT 환경에서도 적용될 수 있음이 밝혀졌습니다.

그리고 자바스크립트 코드를 살펴보지 않아도, 생성해야 할 많은 IC 스텁들을 알 수 있습니다. JS에는 많이 사용되는 패턴이 있기 때문입니다.

좋은 예는 객체의 속성에 접근하는 것입니다. 이는 많은 자바스크립트 코드에서 일어나며 IC 스텁을 사용해 속도를 높일 수 있습니다. 특정 "모양(shape)" 또는 "숨겨진 클래스"(즉, 동일한 방식으로 배치된 속성들)가 있는 객체의 경우 특정 속성에 접근할 때 해당 속성은 항상 동일한 오프셋에 있습니다.

전통적으로 JIT의 이러한 종류의 IC 스텁은 모양에 대한 포인터와 속성의 오프셋이라는 두 가지 값을 하드 코딩합니다. 이를 위해서는 사전에(Ahead-Of-Time)는 알 수 없는 정보가 필요합니다. 그러나 우리는 IC 스텁을 매개변수화 할 수 있습니다. 모양과 속성 오프셋을 스텁에 전달되는 변수로 취급할 수 있습니다.

이렇게 하면 메모리에서 값을 로드하는 단일 스텁을 생성한 다음, 모든 곳에서 이 스텁 코드를 사용할 수 있습니다. 자바스크립트 코드가 실제로 수행하는 작업과 관계없이 이러한 공통 패턴들에 대한 모든 스텁을 AOT 컴파일된 모듈에 만들어들 수 있습니다. 심지어 브라우저에서도 이 IC를 공유하면 유용할 수 있습니다. JS 엔진이 더 적은 기계어를 생성하게 돼 시작 시간과 명령 캐시 지역성(instruction-cache locality)을 개선하기 때문입니다.

이번 사례에서는 이 개념이 특히 중요합니다. 자바스크립트 코드가 실제로 수행하는 작업과 관계없이, 이러한 공통 패턴에 대한 모든 스텁을 AOT 컴파일된 모듈에 마련해둘 수 있음을 의미하기 때문입니다.

우리는 몇 킬로바이트의 IC 스텁으로 모든 자바스크립트 코드의 대부분을 다룰 수 있다는 것을 발견했습니다. 예를 들어 2KB의 IC 스텁으로 Google Octane 벤치마크에서 자바스크립트의 95%를 커버할 수 있습니다. 예비 테스트에서 이 비율은 일반적인 웹 브라우징에서도 유지되는 것으로 보입니다.

A small pile of stubs on the left and a large pile of JS files on the right

이런 종류의 최적화를 적용하면 초기 JIT와 동등한 스루풋에 도달할 수 있을 것입니다. 해당 작업을 완료하고 나면 브라우저의 JS 엔진 팀이 초기 JIT에서 그랬듯이, 더 디테일한 최적화를 추가하고 성능을 연마할 것입니다.

다음, 다음 단계: 약간의 프로파일링을 추가할 수 있을지도요?

앞서 말한 것들이 프로그램이 뭘 하고 어떤 타입들이 프로그램에서 사용되는지 알지 못한 채로, 미리(Ahead-Of-Time) 할 수 있는 것들입니다.

그러나 JIT가 가지고 있는 것과 같은 종류의 프로파일링 정보에 접근할 수 있다면 어떨까요? 그럼 코드를 완전히 최적화할 수 있습니다.

다만 여기에는 문제가 있습니다. 개발자는 종종 자신의 코드를 프로파일링하는 데 어려움을 겪습니다. 대표적인 샘플 워크로드를 찾는 건 어렵습니다. 따라서 좋은 프로파일링 데이터를 얻을 수 있을지 확신할 수 없습니다.

프로파일링을 위해 좋은 도구를 사용할 수 있는 방법을 알아낼 수만 있다면, 자바스크립트를 오늘날의 JIT만큼 빠르게 실행할 수도 있습니다 (그리고 이 방식에는 예열 시간도 필요 없습니다!).

당장 시작하는 방법

우리는 이 새로운 접근 방식에 대해 매우 기대가 크고, 어디까지 추진할 수 있을지 기대하고 있습니다. 또 다른 동적 타입 언어들이 같은 방식으로 웹어셈블리에 제공되는 것을 보기를 기대하고 있습니다.

당장 시작할 수 있는 몇 가지 방법이 있습니다. 궁금한 점이 있는 경우 Zulip에서 물어보세요.

자바스크립트를 지원하려는 다른 플랫폼의 경우

자체 플랫폼에서 자바스크립트를 실행하려면 WASI를 지원하는 웹어셈블리 엔진을 내장해야 합니다. 이를 위해 Wasmtime를 사용할 수 있습니다.

그런 다음 JS 엔진이 필요합니다. 이 작업의 일환으로 SpiderMonkey를 WASI로 컴파일하기 위해 Mozilla의 빌드 시스템에 대해 전폭적인 지원을 하고 있습니다. 그리고 Mozilla는 Firefox를 빌드하고 테스트하는 데 사용되는 것과 동일한 CI 설정에 SpiderMonkey용 WASI 빌드를 추가하려고 합니다. 이는 WASI가 SpiderMonkey의 프로덕션 목표 중 하나가 되게 하고, WASI 빌드가 시간이 지나도 계속 작동함을 보장합니다. 즉, 앞서 설명한 방식 그대로 SpiderMonkey를 사용할 수 있습니다.

마지막으로, 사용자가 사전 초기화된 JS를 가져와야 합니다. 이를 돕기 위해 Wizer를 오픈 소스화 했고, 이를 빌드 도구에 통합해 JS 엔진 모듈의 사전 초기화된 메모리를 채우는, 애플리케이션별 웹어셈블리 모듈을 생성할 수 있습니다.

이 접근 방식을 사용하려는 다른 언어의 경우

Python, Ruby, Lua 등과 같은 언어 커뮤니티의 일원이라면 해당 언어에 대한 버전도 빌드할 수 있습니다.

먼저, 앞서 SpiderMonkey를 이용했던 것처럼, 시스템 호출에는 WASI를 사용하여 런타임을 웹어셈블리로 컴파일해야 합니다. 그런 다음 스냅샷으로 빠른 시작 시간을 얻으려면 역시 앞서 설명한 것처럼 Wizer를 빌드 도구에 통합해 메모리 스냅샷을 생성할 수 있습니다.



+ \ No newline at end of file diff --git a/log/nextjs-app-router-migration-the-good-bad-and-ugly.html b/log/nextjs-app-router-migration-the-good-bad-and-ugly.html new file mode 100644 index 00000000..3f0424d3 --- /dev/null +++ b/log/nextjs-app-router-migration-the-good-bad-and-ugly.html @@ -0,0 +1,50 @@ + + + + + + Next.js 앱 라우터 마이그레이션: 좋은 점, 나쁜 점, 그리고 최악인 점 | bohyeon.dev + + + + + + + + + + + + + + + + +
Skip to content
On this page

Next.js 앱 라우터 마이그레이션: 좋은 점, 나쁜 점, 그리고 최악인 점

원문: https://www.flightcontrol.dev/blog/nextjs-app-router-migration-the-good-bad-and-ugly

29.01.24 | Brandon Bayer

지난해 저희는 Next.js 앱 라우터를 사용하여 Flightcontrol 대시보드를 처음부터 다시 구축했습니다. 이전 대시보드는 Next.js 페이지 라우터로 구축했습니다. 이전 대시보드도 제 기능을 수행했지만, 엔지니어인 제가 디자인한 UI는 프로토타입처럼 느껴졌습니다. 이제 진정한 디자인 재능을 끌어들여 좀 더 성장할 때였습니다.

그래서 Overnice와 협력해 전체 UI를 다시 디자인했습니다. 그들은 놀라운 예술 작품을 디자인했습니다. 저희는 디자인이 마음에 들었지만 Next.js 페이지 라우터로는 구축할 수 없었기 때문에 몇 가지 큰 변경이 필요했습니다. 다시 말해, 중첩 라우팅과 공유 레이아웃이 필요했습니다.

전면적인 재작성이 필요했기 때문에 당시(2023년 4월) 모든 리액트 선택지를 고려했습니다. 선택지로 Next.js 앱 라우터, 리믹스, 진정한 단일 페이지 앱(SPA) 아키텍처를 위한 TanStack Router가 있었습니다. 앱 라우터와 리액트 서버 컴포넌트(RSC)는 리액트의 일부라는 면에서 미래의 기술처럼 느껴졌고, Next.js는 가장 인기 있는 프레임워크였습니다. 아직 최신 기술이지만 장기적으로 가장 안전한 선택지처럼 보였습니다.

RSC는 복잡하고 서버와 클라이언트가 혼합되어 있기 때문에 전통적인 SPA 접근법 또한 매력적입니다. 순수한 클라이언트를 가지면서 백엔드로부터의 명확히 분리하는 건 명백한 이점을 가집니다. 저희는 타입 안전성에 대해 매우 신경을 썼기 때문에, TanStack Router가 유일한 옵션이었습니다. 매우 유망해 보였지만, 당시에는 여전히 알파 단계였고 언제 운영 가능할지 여부도 불분명했습니다.

불행히도, 저희는 Remix를 거의 고려하지 않았습니다. 부분적으로는 이미 Blitz.js 인증과 RPC를 사용하고 있었기 때문입니다. Remix로 이동하려면 Next.js를 사용하면 유지될 수 있는 이 두 부분에서 변경이 필요했습니다.

Next.js 앱 라우터를 선택한 후 작업을 시작했습니다.

Next.js 앱 라우터로 마이그레이션 하기

이어지는 내용은 웹 앱 대시보드에서 직접 앱 라우터를 사용한 경험에 관한 것입니다. 그리고 분명 저희와 다른 사용 사례에서 좋고 나쁜 점들이 더 있을 것입니다.

좋은 점: 레이아웃

저희는 앱을 개발하는 과정에서 오른쪽 사이드 패널 UI와 같이 탐색을 위한 중첩 레이아웃이 필요했습니다. /environment/[envId]는 환경 세부 정보를 보여주고, /environment/[envId]/deployment/[deployId]는 환경 세부 정보 옆에 사이드 패널을 열어주는 스펙이었습니다.

대시보드 UI

이는 페이지 라우터로는 구축할 수 없었지만 앱 라우터에서는 가능했습니다. 각 레이아웃이 유지되므로 형제 페이지 간 탐색 시 부모 레이아웃을 마운트 해제했다가 다시 마운트 하지 않습니다.

그러나 페이지를 중첩할 수 없기 때문에 이 UI를 구축하는 것이 어색하기도 했습니다. 환경 UI는 환경 layout.tsx 안에 있어야 하며, 환경 page.tsx에는 return null만 포함되어야 합니다.

좋은 점: 로딩 상태의 유연성

새 페이지로 이동할 때 리액트 서스펜스를 사용하면, 원하는 사용자 경험에 따라 이전 UI 또는 새 UI에 로딩 스피너를 표시할 수 있습니다. 이 기능은 리액트 기능이며 앱 라우터에서 지원하므로 Next.js에서 사용할 수 있습니다.

새로운 경로로 이동하는 경우의 기존 로딩 스피너는 <Suspense> 경계를 설정하면 쉽게 구현할 수 있습니다.

탐색 후 스피너가 있는 대시보드

새로운 가능성은 링크에 React.useTransition()을 사용하여 기존 UI에 스피너를 표시하는 것입니다. 새 UI가 로드되면 UI가 즉시 전환됩니다. 새 페이지가 백그라운드에서 로드되는 동안 사용자가 유용한 정보를 계속 볼 수 있다는 이점이 있습니다.

탐색 전 스피너가 있는 대시보드

결과적으로 UX는 좋지만, 개발자 경험은 다소 불편합니다.

tsx
import {useTransition} from "react"
+import Link from "next/link"
+import {useRouter} from "next/navigation"
+
+function NavLink() {
+  const [isPending, startTransition] = useTransition()
+  const router = useRouter()
+
+  return <Link 
+            href="/about" 
+            onClick={() => startTransition(() => router.push("/about"))} 
+          >
+            About
+            {isPending && <Spinner />}
+          </Link>
+}

사용자가 브라우저 북마크 등을 통해 해당 페이지로 직접 이동하는 경우 해당 페이지에 스피너를 표시하려면 페이지 주위에 <Suspense>가 필요하다는 점에 유의하세요.

좋은 점: 서버에서 초기 데이터 로딩의 개발자 경험(DX)

리액트 서버 컴포넌트는 주로 초기 데이터 로딩의 DX에 유용하다는 것이 입증되었습니다. 저희는 기본적으로 모든 페이지가 데이터를 로드하고 이를 클라이언트 컴포넌트로 전달하는 서버 컴포넌트로 구성된 패턴을 사용하고 있습니다.

tsx
// page.tsx
+import {ProjectPage} from './ProjectPage'
+import {getProjectData} from '@/domain/project'
+
+export default async function Page() {
+  const projectData = await getProjectData(/*args*/)
+  return <ProjectPage initialData={projectData} />
+}

그런 다음 클라이언트 컴포넌트에서 TanStack Query를 사용하여 폴링을 통한 실시간 데이터 업데이트를 수행합니다. 초기 데이터는 initialData 옵션을 통해 useQuery() 훅에 전달됩니다.

크게 강조했던 것처럼 초기 로드 성능이 더 좋을 것으로 예상했습니다. 하지만 실제로는 이것과 클라이언트 측 데이터 로딩의 차이를 구분할 수 없었습니다.

결국 이 DX는 클라이언트에서 useQuery()가 초기 데이터 가져오기를 수행하는 것보다 약간 더 나쁠 수 있습니다. 클라이언트에서 useQuery()가 초기 데이터 가져오기를 수행하면 initialData를 명시적으로 처리할 필요가 없기 때문입니다.

나쁜 점: 실시간 UI 업데이트를 위해 클라이언트 측 데이터 가져오기를 추가해야 합니다

서버 컴포넌트가 TanStack Query 및 폴링과 동일한 stale-while-revalidate 시맨틱을 지원할 수 있어야 한다고 보입니다. 하지만 Next.js에서는 그렇지 않습니다.

이를 위해 클라이언트 측 데이터 가져오기를 추가해야 합니다. 그리고 저희는 UI의 거의 모든 부분에 이 기능을 원합니다. 이에 따라 서버 측 데이터 로딩에 대한 이전 섹션에서 언급했듯이 많은 중복이 발생합니다.

나쁜 점: 서버 측 오류가 쉽게 무시되거나 숨겨집니다

서버에서 오류가 발생했는데 적절한 위치에 <ErrorBoundary />를 추가하지 않은 경우, 서버는 대신 서스펜스 폴백을 렌더링하고 클라이언트에서 해당 페이지를 다시 렌더링 하려고 시도합니다.

이로 인해 오류가 발생하고 기록되지만 UI는 정상적으로 작동하는 것처럼 보입니다. 전반적으로 매우 혼란스럽고 추적하기 어렵습니다.

나쁜 점: 경로 이동 종료 애니메이션을 구현할 수 없습니다

저희는 Framer Motion을 사용해 애니메이션을 구현하고 있습니다. 진입 애니메이션에는 잘 작동하지만, 종료 애니메이션의 경우 Next.js가 완전히 강제 종료됐습니다.

Framer Motion은 제 역할을 하고 있지만, Next.js는 이전 레이아웃 id를 유지하지 않고 자식 컴포넌트를 너무 일찍 제거합니다.

나쁜 점: 라우팅 타입 안전성 부족합니다

Next.js에는 실험적으로 타입 안전성이 내장되어 있지만 많은 제한이 있습니다.

다행히도 사용자 환경에서 이를 구현하는 것은 그리 어렵지 않습니다. 다른 게시물을 통해 전체 라우팅 유형 안전을 위한 전체 복사 붙여 넣기가 가능한 구현을 공유합니다.

최악인 점: 개발 서버 성능이 형편없습니다

9개월 전보다는 훨씬 나아졌지만, 여전히 용납할 수 없을 정도로 느립니다.

한 엔지니어는 "개발 서버 성능이 너무 나빠서, 좋은 기능을 모두 포기하고 싶은 정도입니다. Next.js 개발 서버를 피하고자 다른 프레임워크로 전환할 수도 있습니다. 심지어 다른 언어로 전환할 수도 있습니다. 그만큼 Next.js의 앱 라우터 사용이 싫습니다."

최악인 점: 개발 서버 메모리 누수

20분마다 개발 서버가 강제 종료되어 다시 시작해야 합니다. 그리고 강제 종료되기 전에도 변경 사항을 만들면 점점 느려집니다.

최악인 점: 오류를 추적하기 어렵습니다

오류가 발생하는 경우 대부분 매우 모호하고 추적할 수 있는 호출 스택이 없습니다. 한 번에 앱의 절반을 삭제하는 바이너리 검색과 같은 식으로 시도해 봐야 합니다.

next.js 하이드레이션 오류

next.js 동적 서버 사용 오류

최악인 점: 프로덕션 마케팅의 시기상조

실제로 운영 환경에서 사용할 수 있게 되기 위해서 운영 준비가 완료된 후 거의 1년이 지나야 했습니다. 초기에는 버그와 문제가 너무 많았어요. 정말 비참한 상황이었죠. 다행히 지금은 많은 부분이 수정되었지만 아직 씁쓸함이 남아있습니다.

최악인 점: 지나치게 복잡하고 불투명함

위의 모든 것을 종합해 보면 Next.js는 지나치게 복잡하고 불투명하다는 결론에 도달하게 됩니다. 문제가 발생하면 그 이유나 해결 방법을 파악할 방법이 없습니다.

저희는 이 문제를 해결하느라 많은 회사 비용을 낭비한 것이 분명합니다.

주의: 저희는 아직 Next.js 13.5.4를 사용 중입니다

Next.js 14를 사용해 보았지만, 문제가 발생하여 아직 이 업그레이드의 우선순위를 정하지 못했습니다. 14 버전에서 번들링이 크게 변경되어 많은 분이 업그레이드에 어려움을 겪고 있는 것 같습니다.

과거에는 주요 버전 업그레이드가 원활하게 진행되었지만, 이번 버전은 그렇지 않았습니다.

다시 돌아갈 수 있다면 Remix를 선택하겠습니다

훨씬 더 나은 개발 성능 외에도 Remix의 아키텍처와 추상화가 더 뛰어나다고 생각합니다. 예를 들어, Remix에서는 사용자가 클라이언트와 서버 진입점을 소유합니다. 하지만 Next.js는 모든 것을 소유하며, 명시적으로 허용하지 않는 작업은 npm 패치를 사용하지 않는 한 할 수 없었고, 저희는 지속해서 그렇게 해야 했습니다.

물론 Remix에도 나름의 단점이 있긴 하지만, 저희 Next.js 사용자가 처리해야 하는 문제를 보며 Remix 사용자가 믿을 수 없어 하는 모습을 계속 보았습니다. 바라건대 Next.js가 개선 되기를 바랍니다.

리액트 만세!

+ + + + \ No newline at end of file diff --git a/log/patterns-for-reactivity-with-modern-vanilla-javascript.html b/log/patterns-for-reactivity-with-modern-vanilla-javascript.html index efb96dd3..0c5ef520 100644 --- a/log/patterns-for-reactivity-with-modern-vanilla-javascript.html +++ b/log/patterns-for-reactivity-with-modern-vanilla-javascript.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

모던 바닐라 자바스크립트로 본 반응성을 구현하는 패턴

Chemical reaction rendering meant to convey the concept of reactivity

원문: https://frontendmasters.com/blog/vanilla-javascript-reactivity/

"반응성(Reactivity)"은 시스템이 데이터의 변화에 반응하는 방식입니다. 반응성에는 여러 가지 유형이 있지만, 이 글에서 말하는 반응성은 데이터가 변하면 어떤 일을 하는 것입니다.

웹 개발의 핵심인 반응형 패턴

브라우저는 완전히 비동기적인 환경이기 때문에 웹사이트와 웹 앱에서는 자바스크립트로 많은 것을 처리합니다. 사용자 입력에 응답하고, 서버와 통신하고, 로깅하고, 실행하는 등의 작업을 수행해야 합니다. 이러한 모든 작업에는 UI 업데이트, Ajax 요청, 브라우저 URL 및 네비게이션 변경이 포함되므로 연쇄적인 데이터 변경은 웹 개발의 핵심 요소입니다.

이 분야에서는 반응성을 프레임워크와 연관시키지만 순수한 자바스크립트로 반응성을 구현해보면 많은 것을 배울 수 있습니다. 아래에서 소개할 패턴들을 조합하여 데이터 변화에 따라 동작을 연결할 수 있습니다.

🔥 순수 자바스크립트로 핵심 패턴을 학습하면 어떤 도구나 프레임워크를 사용하든 웹 앱에서 사용되는 코드가 줄어들고 성능이 향상될 것 입니다.

패턴은 모든 언어와 시스템에 적용할 수 있기 때문에 저는 패턴을 배우는 것을 좋아합니다. 패턴을 결합하여 앱의 정확한 요구 사항을 해결할 수 있으며, 종종 더 성능이 좋고 유지 관리가 쉬운 코드로 이어질 수 있습니다.

어떤 프레임워크와 라이브러리를 사용하든 새로운 패턴을 배워 활용할 수 있기를 바랍니다!

PubSub 패턴

PubSub은 가장 기초적인 반응형 패턴 중 하나입니다. publish()로 이벤트를 발행하면 누구나 해당 이벤트를 subscribe()해 이벤트를 발행한 것과 분리된 상태에서 원하는 모든 작업을 수행할 수 있습니다.

js
const pubSub = {
+    
Skip to content
On this page

모던 바닐라 자바스크립트로 본 반응성을 구현하는 패턴

Chemical reaction rendering meant to convey the concept of reactivity

원문: https://frontendmasters.com/blog/vanilla-javascript-reactivity/

"반응성(Reactivity)"은 시스템이 데이터의 변화에 반응하는 방식입니다. 반응성에는 여러 가지 유형이 있지만, 이 글에서 말하는 반응성은 데이터가 변하면 어떤 일을 하는 것입니다.

웹 개발의 핵심인 반응형 패턴

브라우저는 완전히 비동기적인 환경이기 때문에 웹사이트와 웹 앱에서는 자바스크립트로 많은 것을 처리합니다. 사용자 입력에 응답하고, 서버와 통신하고, 로깅하고, 실행하는 등의 작업을 수행해야 합니다. 이러한 모든 작업에는 UI 업데이트, Ajax 요청, 브라우저 URL 및 네비게이션 변경이 포함되므로 연쇄적인 데이터 변경은 웹 개발의 핵심 요소입니다.

이 분야에서는 반응성을 프레임워크와 연관시키지만 순수한 자바스크립트로 반응성을 구현해보면 많은 것을 배울 수 있습니다. 아래에서 소개할 패턴들을 조합하여 데이터 변화에 따라 동작을 연결할 수 있습니다.

🔥 순수 자바스크립트로 핵심 패턴을 학습하면 어떤 도구나 프레임워크를 사용하든 웹 앱에서 사용되는 코드가 줄어들고 성능이 향상될 것 입니다.

패턴은 모든 언어와 시스템에 적용할 수 있기 때문에 저는 패턴을 배우는 것을 좋아합니다. 패턴을 결합하여 앱의 정확한 요구 사항을 해결할 수 있으며, 종종 더 성능이 좋고 유지 관리가 쉬운 코드로 이어질 수 있습니다.

어떤 프레임워크와 라이브러리를 사용하든 새로운 패턴을 배워 활용할 수 있기를 바랍니다!

PubSub 패턴

PubSub은 가장 기초적인 반응형 패턴 중 하나입니다. publish()로 이벤트를 발행하면 누구나 해당 이벤트를 subscribe()해 이벤트를 발행한 것과 분리된 상태에서 원하는 모든 작업을 수행할 수 있습니다.

js
const pubSub = {
   events: {},
   subscribe(event, callback) {
     if (!this.events[event]) this.events[event] = [];
@@ -417,8 +417,8 @@
   margin-right: 10px;
   position: relative;
 }

이제 CSS에서 해당 백분율을 기반으로 계산을 수행할 수 있습니다. 렌더링 로직을 모두 자바스크립트에 보관할 필요 없이 CSS에 바로 계산을 추가하고 CSS가 스타일링 작업을 수행하도록 할 수 있다는 것은 매우 멋진 일입니다.

참고: 현재 값을 기준으로 변경 사항을 생성하려는 경우 프로퍼티를 아래와 같이 받아올 수도 있습니다.

js
getComputedStyle(barElement).getPropertyValue('--percentage');

다양한 방법으로 반응성을 달성하는 법

현재의 바닐라 자바스크립트에는 굉장히 적은 코드만으로 반응성을 달성할 수 있는 방법이 굉장히 많습니다. 앱에서 반응형 렌더링, 로깅, 애니메이션, 사용자 이벤트 처리 등 브라우저에서 일어날 수 있는 모든 일을 처리하는 데, 적합한 방식으로 이러한 패턴을 조합할 수 있습니다.

- + \ No newline at end of file diff --git a/log/short/four-eras-of-javascript-frameworks.html b/log/short/four-eras-of-javascript-frameworks.html index b0d7036b..d751c4d1 100644 --- a/log/short/four-eras-of-javascript-frameworks.html +++ b/log/short/four-eras-of-javascript-frameworks.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

요약: 네 시대의 자바스크립트 프레임워크

원문: Four Eras of JavaScript Frameworks

자바스크립트 생태계는 올바르게 나아가고 있다.

이전 2개의 시대를 지나면서 여러 교훈을 얻고 발전해나가고 있음

3세대 프레임워크(Next.js, Nuxt.js, SveltKit, Remix 등)들은 1세대가 목표했던 올인원 솔루션을 다시 목표로 하고 있음.

2세대 프레임워크(React.js, Vue.js, Svelte) 겪었던 문제들을 해결해면서 장점들도 가져가고 있다.

  • 문제들 : 라우팅, SSR, API 통신, 상태관리 등은 여전히 개발자들에게 맡겼음. 선택지가 지나치게 많아 제한된 자원을 가진 개발자들이 개발하면서 문제를 만들어내게 되는 경우가 생김

3세대 프레임워크의 주요 초점들

  • 우리는 컴포넌트가 기반이 되는 핵심 요소라는데 동의했으므로, 라우터, 빌드 시스템, 폴더 구조 등 앱의 다른 부분을 표준화하는 것이 합리적이었음
  • 특정 요청에 대한 API secret 숨기기, 페이지 반환 시 헤더 수정, API 요청 프록시와 같은 작업을 수행할 수 있도록 백엔드와 프런트엔드를 함께 사용하는 것이 매우 유용하다는 것을 알았다.
  • 최신 프레임워크는 그 잠재력을 최대한 활용하여 클라이언트와 서버의 통합을 원활하게 하고 있다. => 마침내 우리는 네이티브 앱용 SDK와 동일한 환경에서 경쟁하기 시작

기타 키워드들

  • 웹 컴포넌트

    • 웹 컴포넌트는 조용히 발전하며 SSR과 같은 문제에 대한 솔루션을 작업하고 전역 등록을 제거해 3세대 프레임워크와 호환이 더 잘되도록 하고 있음
  • 웹어셈블리

    • Rust, 파이썬, 스위프트, 자바 등은 더 나은 UX와 함께 마침내 프런트엔드와 백엔드 사이의 장벽을 거의 0으로 줄일 수 있음
- +
Skip to content
On this page

요약: 네 시대의 자바스크립트 프레임워크

원문: Four Eras of JavaScript Frameworks

자바스크립트 생태계는 올바르게 나아가고 있다.

이전 2개의 시대를 지나면서 여러 교훈을 얻고 발전해나가고 있음

3세대 프레임워크(Next.js, Nuxt.js, SveltKit, Remix 등)들은 1세대가 목표했던 올인원 솔루션을 다시 목표로 하고 있음.

2세대 프레임워크(React.js, Vue.js, Svelte) 겪었던 문제들을 해결해면서 장점들도 가져가고 있다.

  • 문제들 : 라우팅, SSR, API 통신, 상태관리 등은 여전히 개발자들에게 맡겼음. 선택지가 지나치게 많아 제한된 자원을 가진 개발자들이 개발하면서 문제를 만들어내게 되는 경우가 생김

3세대 프레임워크의 주요 초점들

  • 우리는 컴포넌트가 기반이 되는 핵심 요소라는데 동의했으므로, 라우터, 빌드 시스템, 폴더 구조 등 앱의 다른 부분을 표준화하는 것이 합리적이었음
  • 특정 요청에 대한 API secret 숨기기, 페이지 반환 시 헤더 수정, API 요청 프록시와 같은 작업을 수행할 수 있도록 백엔드와 프런트엔드를 함께 사용하는 것이 매우 유용하다는 것을 알았다.
  • 최신 프레임워크는 그 잠재력을 최대한 활용하여 클라이언트와 서버의 통합을 원활하게 하고 있다. => 마침내 우리는 네이티브 앱용 SDK와 동일한 환경에서 경쟁하기 시작

기타 키워드들

  • 웹 컴포넌트

    • 웹 컴포넌트는 조용히 발전하며 SSR과 같은 문제에 대한 솔루션을 작업하고 전역 등록을 제거해 3세대 프레임워크와 호환이 더 잘되도록 하고 있음
  • 웹어셈블리

    • Rust, 파이썬, 스위프트, 자바 등은 더 나은 UX와 함께 마침내 프런트엔드와 백엔드 사이의 장벽을 거의 0으로 줄일 수 있음
+ \ No newline at end of file diff --git a/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality.html b/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality.html index d84f5ece..86fff513 100644 --- a/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality.html +++ b/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

요약: NDC [키노트] 블록체인과 가상세계의 진화

  • 코인, P2E보다는 블록체인 자체에 포커스
  • 닫힌 생태계를 열린 생태계로 확장하는 수단
  • 가상 세계를 진화
  • 가상 세계의 물리적 한계를 넘어 다른 가상 세계와 융합하는 통합 플랫폼, 통합 가상 세계
  • 블록체인이 어떤 역할을 하길래? - 한마디로 융합하고 나눠주기 좋은 투명한 인프라 기술 - 투명성 | 열린 생태계 | 가치의 저장
    • 투명성 : 온체인 기록, 거버넌스
    • 열린 생태계 : 누구나 기여 가능, 기여에 따라 보상을 획득
    • 가치의 저장 : NFT, 토큰
  • 기존 게임들이 서버라는 폐쇄된 환경을 넘어서지는 못했다 - 아이템, 캐릭터, 게임 머니 등은 한 게임 안에서만 통용됐다. - 블록체인 생태계에서는 모든 재화들이 자유롭게 연결 + 대체 불가능한 존재를 유지 - 전통적인 스토어형태 게임은 점점 쇠퇴될 것 - 유용한 인프라 세트, IP, 세계관, 인정받는 커뮤니티, 의미를 가지는 것이 중요해진다 - 플랫폼을 표방한 적도 없고, 주인도 없는 이 거대한 블록체인 생태계가 현존하고 가장 크고 유용한 게임 플랫폼일 수 있다 - 폐쇄된 플랫폼으로 유저, 재화, 트래픽을 독점하지 않고 융합, 통합하여 이 블록체인 생태계에 중요한 일원이 되는 것이 의미가 있을 것
  • 블록체인에 맞는 게임 설계가 필요하다 - 투명성
    • 현재 게임에서는 개발사의 의도에 따라 밸런스와 경제 상황이 바뀔 수 있다
    • 유저들이 회사를 바라보면서 게임을 하게 된다.
    • 가상 세계의 완성도와 몰입에 방해를 한다.
    • 개발사조차 바꾸기 어려운 합의된 규칙이 해법이 될 수 있다.
    • 결국 가상 세계에 몰입하도록 투명성이 도움을 줄 수 있을 것
  • 열린 생태계와 기여에 따른 보상 - 게임의 성장에 따른 과실이 모든 기여자에게 돌아갈 수 있게 한다면 더 좋을 것 같았다. - 개발사도 일원이 되는 것이다
  • 가치의 저장과 이동 - NFT가 있어도 쓸데가 없으면 무의미하지 않는지에 대한 해결이 있어야 한다고 생각했다 - 이건 넥슨이 잘할 수 있는 부분 - 게임 NFT는 게임이 없어지면 쓸모가 없어질 확률이 높다. - 나중에 활용하리라는 기대가 있지만 실제로 활용될 확률은 얼마나 될지 모른다. - 실질적인 그림이 필요
    • 메이플 스토리 IP를 이용한 블록체인 게임
    • 열린 생태계, 가치의 저장과 신뢰가 중요
    • 메이플 스토리라는 넥슨의 훼손하면 안되는 IP를 통해 안되면 말지식이 아닌 진정성을 획득
    • 여러 서비스들을 묶어서 공유할 수 있는 NFT, 토큰을 만드는 것이 중요하겠다는 결론
    • 메이플스토리 유니버스 - NFT들이 주인공. 그 밑에 각 게임들이 존재한다
    • 유니버스는 Maplestory N, N Mobile, MOD N(샌드박스 제작 플랫폼), N SDK(NFT 기반으로 여러 게임을 만들 수 있는 툴)
    • N은 기존 메이플 + NFT
    • 아이템 NFT로 존재, 토큰도 게임중 획득 가능
    • 캐시샵 없음
    • NFT 프리세일도 진행 X
    • MOD N
      • 메이플 스토리 NFT + 외부 NFT로 게임 제작 가능
      • 제작한 게임은 모두 제작자 소유
    • N SDK
      • 메이플 유니버스에서 얻은 NFT로 다양한 앱을 만들 수 있는 SDK
      • 예를들어 NFT 홀더들을 위한 굿즈 제작 펀딩 앱
- +
Skip to content
On this page

요약: NDC [키노트] 블록체인과 가상세계의 진화

  • 코인, P2E보다는 블록체인 자체에 포커스
  • 닫힌 생태계를 열린 생태계로 확장하는 수단
  • 가상 세계를 진화
  • 가상 세계의 물리적 한계를 넘어 다른 가상 세계와 융합하는 통합 플랫폼, 통합 가상 세계
  • 블록체인이 어떤 역할을 하길래? - 한마디로 융합하고 나눠주기 좋은 투명한 인프라 기술 - 투명성 | 열린 생태계 | 가치의 저장
    • 투명성 : 온체인 기록, 거버넌스
    • 열린 생태계 : 누구나 기여 가능, 기여에 따라 보상을 획득
    • 가치의 저장 : NFT, 토큰
  • 기존 게임들이 서버라는 폐쇄된 환경을 넘어서지는 못했다 - 아이템, 캐릭터, 게임 머니 등은 한 게임 안에서만 통용됐다. - 블록체인 생태계에서는 모든 재화들이 자유롭게 연결 + 대체 불가능한 존재를 유지 - 전통적인 스토어형태 게임은 점점 쇠퇴될 것 - 유용한 인프라 세트, IP, 세계관, 인정받는 커뮤니티, 의미를 가지는 것이 중요해진다 - 플랫폼을 표방한 적도 없고, 주인도 없는 이 거대한 블록체인 생태계가 현존하고 가장 크고 유용한 게임 플랫폼일 수 있다 - 폐쇄된 플랫폼으로 유저, 재화, 트래픽을 독점하지 않고 융합, 통합하여 이 블록체인 생태계에 중요한 일원이 되는 것이 의미가 있을 것
  • 블록체인에 맞는 게임 설계가 필요하다 - 투명성
    • 현재 게임에서는 개발사의 의도에 따라 밸런스와 경제 상황이 바뀔 수 있다
    • 유저들이 회사를 바라보면서 게임을 하게 된다.
    • 가상 세계의 완성도와 몰입에 방해를 한다.
    • 개발사조차 바꾸기 어려운 합의된 규칙이 해법이 될 수 있다.
    • 결국 가상 세계에 몰입하도록 투명성이 도움을 줄 수 있을 것
  • 열린 생태계와 기여에 따른 보상 - 게임의 성장에 따른 과실이 모든 기여자에게 돌아갈 수 있게 한다면 더 좋을 것 같았다. - 개발사도 일원이 되는 것이다
  • 가치의 저장과 이동 - NFT가 있어도 쓸데가 없으면 무의미하지 않는지에 대한 해결이 있어야 한다고 생각했다 - 이건 넥슨이 잘할 수 있는 부분 - 게임 NFT는 게임이 없어지면 쓸모가 없어질 확률이 높다. - 나중에 활용하리라는 기대가 있지만 실제로 활용될 확률은 얼마나 될지 모른다. - 실질적인 그림이 필요
    • 메이플 스토리 IP를 이용한 블록체인 게임
    • 열린 생태계, 가치의 저장과 신뢰가 중요
    • 메이플 스토리라는 넥슨의 훼손하면 안되는 IP를 통해 안되면 말지식이 아닌 진정성을 획득
    • 여러 서비스들을 묶어서 공유할 수 있는 NFT, 토큰을 만드는 것이 중요하겠다는 결론
    • 메이플스토리 유니버스 - NFT들이 주인공. 그 밑에 각 게임들이 존재한다
    • 유니버스는 Maplestory N, N Mobile, MOD N(샌드박스 제작 플랫폼), N SDK(NFT 기반으로 여러 게임을 만들 수 있는 툴)
    • N은 기존 메이플 + NFT
    • 아이템 NFT로 존재, 토큰도 게임중 획득 가능
    • 캐시샵 없음
    • NFT 프리세일도 진행 X
    • MOD N
      • 메이플 스토리 NFT + 외부 NFT로 게임 제작 가능
      • 제작한 게임은 모두 제작자 소유
    • N SDK
      • 메이플 유니버스에서 얻은 NFT로 다양한 앱을 만들 수 있는 SDK
      • 예를들어 NFT 홀더들을 위한 굿즈 제작 펀딩 앱
+ \ No newline at end of file diff --git a/log/short/og-image-generation.html b/log/short/og-image-generation.html index 5d82e349..b2c61c0c 100644 --- a/log/short/og-image-generation.html +++ b/log/short/og-image-generation.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

OG 이미지 생성

원문: https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation

Open Graph Protocol을 통한 소셜 미디어 이미지 생성 최적화

동적 Open Graph 이미지 생성을 지원하기 위해, Vercel의 @vercel/og 라이브러리를 사용할 수 있습니다. Vercel 엣지 함수를 사용해 소셜 미디어 카드 이미지를 생성합니다.

혜택

  • 성능: 적은 양의 코드로 이미지를 만들어낼 수 있고, Edge Function은 거의 즉각적으로 실행됩니다. 따라서 이미지가 빠르게 생성되고, Open Graph Debugger 과 같은 도구도 이용할 수 있습니다.
  • 사용 용이성: html, css를 이용해 이미지를 생성할 수 있고 마크업으로부터 동적으로 이미지를 생성합니다.
  • 비용 효율성: @vercel/og 는 엣지에서 자동적으로 알맞은 헤더를 추가해서 생성된 이미지를 캐싱할 수 있게합니다. 이는 재생성이나 비용을 절감하는데 도움을 줍니다.

지원되는 기능

  • flexbox, absolute position 등을 포함한 기본적인 css 레이아웃을 지원합니다.
  • 커스텀폰트, 텍스트 줄바꿈(text wrapping), 중앙 정렬, 중첩 이미지를 지원합니다.
  • 구글 폰트로부터 폰트 서브셋을 다운받을 수 있습니다.
  • Vercel에 배포된 어떤 프레임워크나 애플리케이션과도 호환됩니다.

사용방법

요구 사항

  • Node.js 16버전 이상이나 그 이상 버전이 필요합니다.
  • @vercel/og를 설치합니다.
bash
npm i @vercel/og
  • Next.js를 사용하려면 Next.js v12.2.3이나 그 이상 버전이 필요합니다.
  • 이미지를 생성하기 위해 프런트엔드에서 요청하는 API endpoint를 만듭니다. 이미지를 생성하는 HTML 코드가 ImageResponse 함수의 파라미터 중 하나로 포함돼있으므로, 이런 종류의 구문을 처리하도록 설계된 .jsx.tsx 파일을 사용하는 것이 좋습니다.
  • 기본 Node.js 런타임이 지원되지 않으므로 Edge Runtime 을 사용하기 위해서 runtime: edge 플래그를 활성화합니다.

시작하기

Next.js를 이용해 정적인 텍스트로부터 이미지를 만드는 예제부터 시작해보세요. 아래 명령을 통해 새 앱을 준비합니다.

shell
npm i create-next-app@latest

/pages/apiog.tsx 파일을 추가해 API 엔드포인트를 추가합니다.

그리고 아래 코드를 붙여넣으세요.

tsx
import { ImageResponse } from '@vercel/og';
+    
Skip to content
On this page

OG 이미지 생성

원문: https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation

Open Graph Protocol을 통한 소셜 미디어 이미지 생성 최적화

동적 Open Graph 이미지 생성을 지원하기 위해, Vercel의 @vercel/og 라이브러리를 사용할 수 있습니다. Vercel 엣지 함수를 사용해 소셜 미디어 카드 이미지를 생성합니다.

혜택

  • 성능: 적은 양의 코드로 이미지를 만들어낼 수 있고, Edge Function은 거의 즉각적으로 실행됩니다. 따라서 이미지가 빠르게 생성되고, Open Graph Debugger 과 같은 도구도 이용할 수 있습니다.
  • 사용 용이성: html, css를 이용해 이미지를 생성할 수 있고 마크업으로부터 동적으로 이미지를 생성합니다.
  • 비용 효율성: @vercel/og 는 엣지에서 자동적으로 알맞은 헤더를 추가해서 생성된 이미지를 캐싱할 수 있게합니다. 이는 재생성이나 비용을 절감하는데 도움을 줍니다.

지원되는 기능

  • flexbox, absolute position 등을 포함한 기본적인 css 레이아웃을 지원합니다.
  • 커스텀폰트, 텍스트 줄바꿈(text wrapping), 중앙 정렬, 중첩 이미지를 지원합니다.
  • 구글 폰트로부터 폰트 서브셋을 다운받을 수 있습니다.
  • Vercel에 배포된 어떤 프레임워크나 애플리케이션과도 호환됩니다.

사용방법

요구 사항

  • Node.js 16버전 이상이나 그 이상 버전이 필요합니다.
  • @vercel/og를 설치합니다.
bash
npm i @vercel/og
  • Next.js를 사용하려면 Next.js v12.2.3이나 그 이상 버전이 필요합니다.
  • 이미지를 생성하기 위해 프런트엔드에서 요청하는 API endpoint를 만듭니다. 이미지를 생성하는 HTML 코드가 ImageResponse 함수의 파라미터 중 하나로 포함돼있으므로, 이런 종류의 구문을 처리하도록 설계된 .jsx.tsx 파일을 사용하는 것이 좋습니다.
  • 기본 Node.js 런타임이 지원되지 않으므로 Edge Runtime 을 사용하기 위해서 runtime: edge 플래그를 활성화합니다.

시작하기

Next.js를 이용해 정적인 텍스트로부터 이미지를 만드는 예제부터 시작해보세요. 아래 명령을 통해 새 앱을 준비합니다.

shell
npm i create-next-app@latest

/pages/apiog.tsx 파일을 추가해 API 엔드포인트를 추가합니다.

그리고 아래 코드를 붙여넣으세요.

tsx
import { ImageResponse } from '@vercel/og';
 
 export const config = {
   runtime: 'edge',
@@ -56,8 +56,8 @@
     content="https://og-examples.vercel.sh/api/static"
   />
 </head>

새 소셜 미디어 게시물을 만들때마다, API 엔드포인트를 업데이트 해야합니다. 그러나 각 게시물마다 ImageResponse의 변경될 부분을 식별한다면, 각 값들을 엔드포인트의 매개변수 값으로 전달해 모든 게시물에 같은 엔드포인트를 사용할 수 있습니다.

아래 예제들에서 ImageResponse 매개변수를 사용해 다른 컨텐츠를 포함하는 방법을 살펴봅니다.

예제

이미지 생성에 사용할 컨텐츠를 URL 매개변수로 전달

이미지 생성을 위해 텍스트나 이미지 외 다른 유형 컨텐츠를 사용

이미지 생성을 위해 사용자 지정 CSS 스타일 사용

국제화 및 보안

기술적 세부사항

  • 권장 OG 이미지 크기는 1200x630 픽셀입니다.
  • @vercel/og Satori 와 Resvg를 사용해 HTML 및 CSS를 PNG로 변환합니다.
  • @vercel/og API 참조

한계

  • Edge 런타임 만 지원됩니다. 기본 Node.js 런타임은 작동하지 않습니다. 혹은 Node.js 외 다른 런타임을 사용하기 위해서는 Satori 를 직접 사용할 수 있습니다. 그러나 @vercel/og 와 Edge Runtime을 같이 사용하면 더 나은 성능을 얻을 수 있습니다.
  • ttfotf 및 woff 글꼴 형식만 지원됩니다. 글꼴 파싱 속도를 최대화하려면 woff 대신 ttf나 otf를 사용하세요.
  • CSS 속성 중 flexbox(display: flex) 및 하위 집합만 지원됩니다. 고급 레이아웃( display: grid)은 작동하지 않습니다. 지원되는 CSS 속성에 대한 자세한 내용은 Satori의 문서를 참조 하세요.
  • 최대 번들 크기는 500KB입니다. 번들 크기에는 JSX, CSS, 글꼴, 이미지 및 기타 에셋이 포함됩니다. 한도를 초과하면 자산의 크기를 줄이거나 런타임에 가져오는 것을 고려하십시오.
- + \ No newline at end of file diff --git a/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.html b/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.html index ca187cfc..d9c73b5a 100644 --- a/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.html +++ b/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

OAuth 2.0 상태 매개변수로 공격 방지 및 사용자 리디렉션하기

원문: https://auth0.com/docs/secure/attack-protection/state-parameters

인증(Authorization) 프로토콜은 애플리케이션의 이전 상태를 복원할 수 있는 state(상태) 매개변수를 제공합니다. state 매개변수는 인증 요청에서 클라이언트가 설정한 상태 객체를 보존하고, 응답에서 사용할 수 있도록 합니다.

CSRF 공격

state 매개변수를 사용하는 주된 이유는 각 인증 요청과 관련된, 고유하고 추측할 수 없는 값을 사용하여 CSRF 공격을 완화하기 위한 것입니다. 응답에서 오는 값이 보낸 값과 일치하는지 확인하여 공격을 방지할 수 있습니다.

state 매개변수는 문자열이므로 다른 정보를 인코딩할 수 있습니다. 인증 요청을 시작할 때 임의의 값을 보내고 응답을 처리할 때 받은 값의 유효성을 검사합니다. 유효성 검사를 수행할 수 있도록 클라이언트 애플리케이션 측(쿠키, 세션 또는 로컬스토리지)에 무언가를 저장합니다. 일치하지 않는 state 응답을 수신한 경우 요청하지 않은 요청에 대한 응답이거나 응답을 위조하려는 누군가이기 때문에 공격의 대상임을 유추할 수 있습니다.

CSRF 공격은 공격자가 위조된 요청에 대한 응답을 볼 방법이 없기 때문에, 사용자 데이터를 가져오는 대신 작업을 시작하기 위해 상태가 변경되는 요청을 대상을 목표로 합니다. 가장 기본적인 경우 state 매개변수는 인증에서 수신한 응답과 요청을 연관시키는 데 사용되는 nonce(number used once, 임의로 생성되는 암호화 토큰)여야 합니다.

단일 페이지 애플리케이션의 Auth0.js를 포함하여 대부분의 최신 OIDC 및 OAuth SDK는 state 생성 및 유효성 검사를 자동으로 처리합니다.

상태 매개변수 값 설정 및 비교

  1. IdP(Identity Provider)로 요청을 리디렉션하기 전에 앱에서 임의의 문자열을 생성하도록 합니다. 예를 들어:
txt
xyzABC123

state에 허용되는 길이는 무제한이 아닙니다. 414 Request-URI Too Large 오류가 표시되면 더 작은 값을 사용해 보세요.

  1. 문자열을 로컬에 저장합니다. 예를 들어:
txt
storeStateLocally(xyzABC123)
  1. 요청에 state 매개변수를 추가합니다(필요한 경우 URL 인코딩). 예를 들어:
txt
// 문자열을 인코딩
+    
Skip to content
On this page

OAuth 2.0 상태 매개변수로 공격 방지 및 사용자 리디렉션하기

원문: https://auth0.com/docs/secure/attack-protection/state-parameters

인증(Authorization) 프로토콜은 애플리케이션의 이전 상태를 복원할 수 있는 state(상태) 매개변수를 제공합니다. state 매개변수는 인증 요청에서 클라이언트가 설정한 상태 객체를 보존하고, 응답에서 사용할 수 있도록 합니다.

CSRF 공격

state 매개변수를 사용하는 주된 이유는 각 인증 요청과 관련된, 고유하고 추측할 수 없는 값을 사용하여 CSRF 공격을 완화하기 위한 것입니다. 응답에서 오는 값이 보낸 값과 일치하는지 확인하여 공격을 방지할 수 있습니다.

state 매개변수는 문자열이므로 다른 정보를 인코딩할 수 있습니다. 인증 요청을 시작할 때 임의의 값을 보내고 응답을 처리할 때 받은 값의 유효성을 검사합니다. 유효성 검사를 수행할 수 있도록 클라이언트 애플리케이션 측(쿠키, 세션 또는 로컬스토리지)에 무언가를 저장합니다. 일치하지 않는 state 응답을 수신한 경우 요청하지 않은 요청에 대한 응답이거나 응답을 위조하려는 누군가이기 때문에 공격의 대상임을 유추할 수 있습니다.

CSRF 공격은 공격자가 위조된 요청에 대한 응답을 볼 방법이 없기 때문에, 사용자 데이터를 가져오는 대신 작업을 시작하기 위해 상태가 변경되는 요청을 대상을 목표로 합니다. 가장 기본적인 경우 state 매개변수는 인증에서 수신한 응답과 요청을 연관시키는 데 사용되는 nonce(number used once, 임의로 생성되는 암호화 토큰)여야 합니다.

단일 페이지 애플리케이션의 Auth0.js를 포함하여 대부분의 최신 OIDC 및 OAuth SDK는 state 생성 및 유효성 검사를 자동으로 처리합니다.

상태 매개변수 값 설정 및 비교

  1. IdP(Identity Provider)로 요청을 리디렉션하기 전에 앱에서 임의의 문자열을 생성하도록 합니다. 예를 들어:
txt
xyzABC123

state에 허용되는 길이는 무제한이 아닙니다. 414 Request-URI Too Large 오류가 표시되면 더 작은 값을 사용해 보세요.

  1. 문자열을 로컬에 저장합니다. 예를 들어:
txt
storeStateLocally(xyzABC123)
  1. 요청에 state 매개변수를 추가합니다(필요한 경우 URL 인코딩). 예를 들어:
txt
// 문자열을 인코딩
 tenant.auth0.com/authorize?...&state=xyzABC123

요청이 전송된 후 사용자는 Auth0에 의해 애플리케이션으로 다시 리디렉션됩니다. state 값이 이 리디렉션에 포함됩니다. 사용된 연결 유형에 따라 이 값은 요청 본문 또는 쿼리 문자열에 있을 수 있습니다.

txt
/callback?...&state=xyzABC123
  1. 반환된 state 값을 이전에 저장한 값과 비교합니다. 값이 일치하면 인증 응답을 승인하고 그렇지 않으면 거부합니다.
javascript
// 문자열을 디코딩
 var decodedString = Base64.decode(encodedString);
 if(receivedState === retrieveStateStoredLocally()) {
@@ -34,8 +34,8 @@
 	expiresOn: [...]
   }
 }
  1. 사용자를 인증합니다. 생성된 nonce를 상태로 전송합니다.

  2. 콜백 처리 및 응답 유효성 검사의 일부로, 반환된 상태가 로컬에 저장된 nonce와 일치하는지 확인합니다. 일치한다면 애플리케이션 상태의 나머지 부분(예: redirectUrl)을 가져옵니다.

  3. 콜백 처리가 완료되면 이전에 저장한 URL로 사용자를 리디렉션합니다.

대체 리디렉션 방법

  1. nonce 값을 로컬로 생성하고 저장합니다.

  2. 원하는 상태(예: 리디렉션 URL)를 nonce와 함께 보호된 메시지(변조 방지를 위해 암호화/서명해야 함)로 인코딩합니다.

  3. 응답 처리에서 메시지 보호를 해제하고 저장된 nonce 및 기타 속성을 얻습니다.

  4. 포함된 nonce가 로컬에 저장된 것과 일치하는지 확인하고 그렇다면 OAuth2 메시지를 수락합니다.

제한 사항 및 고려 사항

  • 애플리케이션 유형에 따라 저장 방법을 선택합니다.
앱 유형스토리지 권장 사항
일반 웹 앱쿠키 또는 세션
SPA(Single Page Application)로컬 브라우저
네이티브 앱메모리 또는 로컬
  • 보안 관점에서 요청과 응답 모두 무결성이 보호되지 않아 사용자가 조작할 수 있습니다. redirect_uri에 매개변수를 추가하는 경우에도 마찬가지입니다.

  • 상태 매개변수 값에 허용되는 길이는 무제한이 아닙니다. 414 Request-URI Too Large 오류가 표시되면 더 작은 값을 사용해 보세요.

  • 일반 텍스트 또는 예측 가능한 방식으로 URL을 전달하는 것은 안전하지 않습니다. 상태 매개변수 값이 다음과 같은 형식을 지키고 있는지 확인하십시오.

    • CSRF 및 피싱 공격에 대한 방어에 사용할 수 있도록 고유하고 불투명합니다.
    • 쿠키에 저장되는 경우 서명을 해서 위변조를 방지해야 합니다.

더 알아보기

- + \ No newline at end of file diff --git a/log/short/state-of-vue-2022-amsterdam-recap.html b/log/short/state-of-vue-2022-amsterdam-recap.html index bc02a446..02ecc8e5 100644 --- a/log/short/state-of-vue-2022-amsterdam-recap.html +++ b/log/short/state-of-vue-2022-amsterdam-recap.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

요약: State of Vue 2022 암스테르담

원문: State of Vue 2022 Amsterdam Recap

  • Vue 2.x
    • Vue 2.7에서는 Vue 3의 Composition API, script setup을 백포팅하는데 집중중
    • Vue 2.7이 마지막 minor version 업그레이드가 될 것
  • Vue 3.x
    • Vue 3.3에서 Suspense 안정화될 것
      • Nuxt 3에서 문제없도록 테스트 중
    • reactivity transform API도 안정화
    • SSR 강화
  • Vite
    • Vite 3 메이저 버전 업데이트 예정
      • 대부분의 사람들은 변화를 못느낄 것
      • 직접 Vite를 사용하는 라이브러리(Nuxt, Vitest)는 업데이트가 필요
      • 가장 큰 변화는 내부적으로 완전 ESM으로 전환 -> node.js 12 지원 중단
  • ⚠Experimental
    • 새로운 compliation 전략을 실험중
      • 실제 적용될지는 미지수
      • SolidJS에 영감을 받았고, no-virtual DOM로 옮겨가는 아이디어
      • 적용된다면 메모리 사용에 큰 이득이 예상됨

  • Nuxt 3
    • 안정화에 가까워짐. 마이그레이션을 시작해도 무방할듯. 이번 여름에 릴리즈 예정
  • Vuetify 3
    • 아직 베타. 2주 후 다음 릴리즈 예정
  • Vitepress 1
    • 1 버전 릴리즈를 위해 노력중
    • Vue3 기반 Static Site Generation 도구로 권장하고 있음
- +
Skip to content
On this page

요약: State of Vue 2022 암스테르담

원문: State of Vue 2022 Amsterdam Recap

  • Vue 2.x
    • Vue 2.7에서는 Vue 3의 Composition API, script setup을 백포팅하는데 집중중
    • Vue 2.7이 마지막 minor version 업그레이드가 될 것
  • Vue 3.x
    • Vue 3.3에서 Suspense 안정화될 것
      • Nuxt 3에서 문제없도록 테스트 중
    • reactivity transform API도 안정화
    • SSR 강화
  • Vite
    • Vite 3 메이저 버전 업데이트 예정
      • 대부분의 사람들은 변화를 못느낄 것
      • 직접 Vite를 사용하는 라이브러리(Nuxt, Vitest)는 업데이트가 필요
      • 가장 큰 변화는 내부적으로 완전 ESM으로 전환 -> node.js 12 지원 중단
  • ⚠Experimental
    • 새로운 compliation 전략을 실험중
      • 실제 적용될지는 미지수
      • SolidJS에 영감을 받았고, no-virtual DOM로 옮겨가는 아이디어
      • 적용된다면 메모리 사용에 큰 이득이 예상됨

  • Nuxt 3
    • 안정화에 가까워짐. 마이그레이션을 시작해도 무방할듯. 이번 여름에 릴리즈 예정
  • Vuetify 3
    • 아직 베타. 2주 후 다음 릴리즈 예정
  • Vitepress 1
    • 1 버전 릴리즈를 위해 노력중
    • Vue3 기반 Static Site Generation 도구로 권장하고 있음
+ \ No newline at end of file diff --git a/log/short/toss-slash22-react-native-for-super-high-productivity.html b/log/short/toss-slash22-react-native-for-super-high-productivity.html index 34540331..4cf25a31 100644 --- a/log/short/toss-slash22-react-native-for-super-high-productivity.html +++ b/log/short/toss-slash22-react-native-for-super-high-productivity.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

요약: 토스 | Slash 22 - 미친 생산성을 위한 React Native

기존 앱의 문제점

  • 느린 배포 속도, 적은 개발 리소스
  • iOS 빌드 속도 - 하루 1/3 침대, 1/3 지하철, 1/3 빌드
  • 배포 심사 - 느리고 불규칙적, 1일 ~ 4주
  • 앱 업데이트 - 동남아의 느린 네트워크, 자동 업데이트를 꺼둔 유저들도 많다.

Flutter vs React Native

장점단점
Flutter훌륭한 공식 라이브러리 생태계 React Native보다 더 많이 사용됨높은 학습 비용
React NativeCodepush 기능 사용 가능 채용에 용이한 풍부한 개발자 풀빈약한 공식 라이브러리 생태계
  • Code Push (React Native) - 앱 내에 JavaScript 번들을 포함할 수 있고, 해당 번들을 업데이트해서 앱 업데이트 없이 최신 기능을 전달 가능

결론

  • 앱을 완전히 다시 만들기로 하고, 병렬적으로 기존앱은 부분적으로 React Native를 적용
  • Native API가 필요한 기존 앱 기능을 구현해보면서 테스트
  • 비싼 그래픽 연산과 같은 높은 성능이 필요한 작업은 부분적으로 Native View를 띄워 해결

과정

  • Native 코드를 건드려야 하는 작업과 JavaScript로만 완료할 수 있는 태스크 2가지로 분류
  • 기존 앱 사용자의 경험을 해치지 않기 위해 꼼꼼하고 많은 테스트를 수행
  • 메인 로직이 아닌 숨어있는 로직을 코드레벨에서 발견하며 옮김. 광고 마케팅 툴, 푸시, 로그 등
  • 3개월간 200번에 달하는 Code Push를 통한 업데이트가 가능했음

React Native 사용 후기 - iOS 개발자

  • 개발 속도 - 핫 리로딩. Swift로 개발시 3달, 미숙한 TypeScript로도 2주
  • 커리어적인 고민 - 전문성 포기하는건 아닐지? 기술은 이미 6 ~ 7년 지났고 Object C에서 Swift로 넘어갈 때 느꼈던 기분. 역량 확장이라고 생각하고 고민을 하지 않기로 결정

React Native 사용 후기 - 프론트엔드 개발자

  • 저렴한 학습 비용
  • 역할 확장 - 앱의 모든 flow에 관여

팀 관점에서

  • 빠르게 실패, 개선 반복 가능
  • 채용이 어려운 초기 스타트업에 유용할 것
- +
Skip to content
On this page

요약: 토스 | Slash 22 - 미친 생산성을 위한 React Native

기존 앱의 문제점

  • 느린 배포 속도, 적은 개발 리소스
  • iOS 빌드 속도 - 하루 1/3 침대, 1/3 지하철, 1/3 빌드
  • 배포 심사 - 느리고 불규칙적, 1일 ~ 4주
  • 앱 업데이트 - 동남아의 느린 네트워크, 자동 업데이트를 꺼둔 유저들도 많다.

Flutter vs React Native

장점단점
Flutter훌륭한 공식 라이브러리 생태계 React Native보다 더 많이 사용됨높은 학습 비용
React NativeCodepush 기능 사용 가능 채용에 용이한 풍부한 개발자 풀빈약한 공식 라이브러리 생태계
  • Code Push (React Native) - 앱 내에 JavaScript 번들을 포함할 수 있고, 해당 번들을 업데이트해서 앱 업데이트 없이 최신 기능을 전달 가능

결론

  • 앱을 완전히 다시 만들기로 하고, 병렬적으로 기존앱은 부분적으로 React Native를 적용
  • Native API가 필요한 기존 앱 기능을 구현해보면서 테스트
  • 비싼 그래픽 연산과 같은 높은 성능이 필요한 작업은 부분적으로 Native View를 띄워 해결

과정

  • Native 코드를 건드려야 하는 작업과 JavaScript로만 완료할 수 있는 태스크 2가지로 분류
  • 기존 앱 사용자의 경험을 해치지 않기 위해 꼼꼼하고 많은 테스트를 수행
  • 메인 로직이 아닌 숨어있는 로직을 코드레벨에서 발견하며 옮김. 광고 마케팅 툴, 푸시, 로그 등
  • 3개월간 200번에 달하는 Code Push를 통한 업데이트가 가능했음

React Native 사용 후기 - iOS 개발자

  • 개발 속도 - 핫 리로딩. Swift로 개발시 3달, 미숙한 TypeScript로도 2주
  • 커리어적인 고민 - 전문성 포기하는건 아닐지? 기술은 이미 6 ~ 7년 지났고 Object C에서 Swift로 넘어갈 때 느꼈던 기분. 역량 확장이라고 생각하고 고민을 하지 않기로 결정

React Native 사용 후기 - 프론트엔드 개발자

  • 저렴한 학습 비용
  • 역할 확장 - 앱의 모든 flow에 관여

팀 관점에서

  • 빠르게 실패, 개선 반복 가능
  • 채용이 어려운 초기 스타트업에 유용할 것
+ \ No newline at end of file diff --git a/log/the-saga-of-the-closure-compiler-and-why-typescript-won.html b/log/the-saga-of-the-closure-compiler-and-why-typescript-won.html index a94970e8..9fe4e691 100644 --- a/log/the-saga-of-the-closure-compiler-and-why-typescript-won.html +++ b/log/the-saga-of-the-closure-compiler-and-why-typescript-won.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

클로저 컴파일러의 역사, 그리고 타입스크립트가 승리한 이유

원문: https://effectivetypescript.com/2023/09/27/closure-compiler/

Closure Tools Logo 이제 6개월만 지나면 지메일이 창립 20주년을 맞이하게 된다는 사실이 나이가 들었음을 느끼게 합니다. 그 당시에 웹사이트를 활발하게 개발하지 않았다면 이 서비스가 얼마나 혁신적이었는지 가늠하기 어려울 것입니다. 이 시기 자바스크립트는 전 세계적으로 저평가를 받았던 시기였습니다. 자바스크립트를 사용하여 정교한 웹 앱을 구축할 수 있다는 생각 자체가 놀라웠습니다. 하지만 자바스크립트는 분명히 효과가 있었고, 단일 페이지 웹 앱(SPA)의 시대를 열었습니다.

이 애플리케이션 뒤에는 구글이 대규모 자바스크립트 애플리케이션을 만들기 위해 개발한 새로운 도구, 즉 클로저(Closure) 도구가 있었습니다(클로저는 'j'가 붙은 클로저가 아니라 's'가 붙은 클로저입니다). 여기에는 타입 검사를 수행하는 자바스크립트 소스-투-소스 컴파일러인 클로저 컴파일러(CC)가 포함되었습니다. 익숙한 이름인가요?

지난 20년 동안 구글에서 프런트엔드 관련 일을 해보지 않았다면 클로저 컴파일러를 접해보지 못했을 가능성이 높습니다. 클로저 컴파일러는 타입스크립트와 비슷한 틈새 시장을 점유하고 있었지만, 타입스크립트가 절대적으로 확실하게 승리했습니다.

그럼에도 불구하고, 몇 가지 이유로 클로저 컴파일러를 다시 살펴보는 것은 흥미롭습니다.

  1. 타입스크립트와 다른 높은 수준의 설계 결정을 내린 시스템을 살펴봄으로써 타입스크립트의 설계에 대해 더 깊이 이해할 수 있습니다.
  2. 우리가 원한다고 생각하지도 못했던 타입스크립트의 누락된 기능을 보여줍니다.
  3. 자바스크립트 역사에서 흥미로운 사례 연구입니다.

다시 말해, 클로저 컴파일러의 이야기는 우리에게 몇 가지 관점을 제공합니다. 타입스크립트가 너무 보편화되어 자바스크립트에 타입 검사기를 추가하는 다른 방법을 상상하기 어려울 때가 있습니다. 돌이켜보면 클로저 컴파일러는 설계 영역이 생각보다 넓었다는 것을 보여줍니다.

저는 2012년부터 2014년까지 구글에서 클로저 스타일 자바스크립트를 가장 많이 썼습니다. 이 글은 당시 존재했던 클로저를 기준으로 작성했습니다. 그 이후로 어떻게 발전했는지는 잘 모르겠습니다.

클로저 컴파일러란 무엇인가요?

타입스크립트의 모토는 "타입스크립트는 자바스크립트의 상위 집합(superset)이다"입니다. 반면에 클로저 코드는 자바스크립트입니다. 언어에 새로운 구문을 추가하지 않습니다.

타입스크립트를 --checkJs 옵션과 함께 사용해 본 적이 있다면 비슷한 개념입니다. 새로운 구문을 통해 자바스크립트에 타입을 추가하는 대신 JSDoc 스타일의 주석을 통해 타입을 추가합니다.

이 타입스크립트를 비교해 보세요.

ts
function max(a: number, b: number): number {
+    
Skip to content
On this page

클로저 컴파일러의 역사, 그리고 타입스크립트가 승리한 이유

원문: https://effectivetypescript.com/2023/09/27/closure-compiler/

Closure Tools Logo 이제 6개월만 지나면 지메일이 창립 20주년을 맞이하게 된다는 사실이 나이가 들었음을 느끼게 합니다. 그 당시에 웹사이트를 활발하게 개발하지 않았다면 이 서비스가 얼마나 혁신적이었는지 가늠하기 어려울 것입니다. 이 시기 자바스크립트는 전 세계적으로 저평가를 받았던 시기였습니다. 자바스크립트를 사용하여 정교한 웹 앱을 구축할 수 있다는 생각 자체가 놀라웠습니다. 하지만 자바스크립트는 분명히 효과가 있었고, 단일 페이지 웹 앱(SPA)의 시대를 열었습니다.

이 애플리케이션 뒤에는 구글이 대규모 자바스크립트 애플리케이션을 만들기 위해 개발한 새로운 도구, 즉 클로저(Closure) 도구가 있었습니다(클로저는 'j'가 붙은 클로저가 아니라 's'가 붙은 클로저입니다). 여기에는 타입 검사를 수행하는 자바스크립트 소스-투-소스 컴파일러인 클로저 컴파일러(CC)가 포함되었습니다. 익숙한 이름인가요?

지난 20년 동안 구글에서 프런트엔드 관련 일을 해보지 않았다면 클로저 컴파일러를 접해보지 못했을 가능성이 높습니다. 클로저 컴파일러는 타입스크립트와 비슷한 틈새 시장을 점유하고 있었지만, 타입스크립트가 절대적으로 확실하게 승리했습니다.

그럼에도 불구하고, 몇 가지 이유로 클로저 컴파일러를 다시 살펴보는 것은 흥미롭습니다.

  1. 타입스크립트와 다른 높은 수준의 설계 결정을 내린 시스템을 살펴봄으로써 타입스크립트의 설계에 대해 더 깊이 이해할 수 있습니다.
  2. 우리가 원한다고 생각하지도 못했던 타입스크립트의 누락된 기능을 보여줍니다.
  3. 자바스크립트 역사에서 흥미로운 사례 연구입니다.

다시 말해, 클로저 컴파일러의 이야기는 우리에게 몇 가지 관점을 제공합니다. 타입스크립트가 너무 보편화되어 자바스크립트에 타입 검사기를 추가하는 다른 방법을 상상하기 어려울 때가 있습니다. 돌이켜보면 클로저 컴파일러는 설계 영역이 생각보다 넓었다는 것을 보여줍니다.

저는 2012년부터 2014년까지 구글에서 클로저 스타일 자바스크립트를 가장 많이 썼습니다. 이 글은 당시 존재했던 클로저를 기준으로 작성했습니다. 그 이후로 어떻게 발전했는지는 잘 모르겠습니다.

클로저 컴파일러란 무엇인가요?

타입스크립트의 모토는 "타입스크립트는 자바스크립트의 상위 집합(superset)이다"입니다. 반면에 클로저 코드는 자바스크립트입니다. 언어에 새로운 구문을 추가하지 않습니다.

타입스크립트를 --checkJs 옵션과 함께 사용해 본 적이 있다면 비슷한 개념입니다. 새로운 구문을 통해 자바스크립트에 타입을 추가하는 대신 JSDoc 스타일의 주석을 통해 타입을 추가합니다.

이 타입스크립트를 비교해 보세요.

ts
function max(a: number, b: number): number {
   return a > b ? a : b;
 }

이에 상응하는 클로저화된 자바스크립트 코드입니다.

js
/**
  * @param {number} a
@@ -106,8 +106,8 @@
   .toSorted((a, b) => a.localeCompare(b))  
   .join('\n')
 );

하지만 이것이 어떻게 가능한지 생각해 보세요.

  • 전체 파일이 메모리에 들어맞는다고 가정하고 있는데, 1972년에는 거의 틀림없이 그렇지 않았을 것입니다.
  • 가비지 컬렉션 언어를 사용하고 있는데, 당시에는 드물었을 것입니다.
  • 노드 빌트인 및 npm을 통해 방대한 라이브러리를 손쉽게 이용할 수 있습니다.
  • 훌륭한 텍스트 편집기와 운영 체제가 있습니다.
  • 웹과 스택오버플로우가 있으니 참조 매뉴얼을 참고할 필요가 없습니다!

이 모든 것이 하드웨어의 발전 덕분입니다. 하드웨어 개발자들은 우리에게 여분의 트랜지스터를 제공하고 소프트웨어 개발자들은 더 나은 개발 프로세스를 위해 대부분의 트랜지스터를 직접 가져갑니다. 더 빨라진 네트워크 속도와 클로저 컴파일러도 마찬가지입니다. 우리는 더 유연한 개발 프로세스와 에코시스템의 대가로 대역폭의 일부를 확보했습니다.

결론

초창기에는 타입스크립트에 경량화 기능 추가에 대한 논의가 있었지만, 이제 최적화된 출력은 해당 언어에 대한 명시적인 비목표입니다. 타입 기반 경량화가 멋질 거라고 생각해 본 적이 있다면, 클로저 컴파일러는 매우 흥미로운 예시입니다. 매우 효과적일 수 있지만 생태계에 막대한 비용을 초래하기도 합니다.

독립형 외부 도구로서의 클로저 컴파일러는 거의 죽은 것처럼 보입니다(클로저 플레이그라운드는 상당히 고장 나 있고 "Copyright 2009"라고 적혀 있습니다!). 하지만 구글에서는 여전히 살아 있습니다. 타입스크립트를 채택했기 때문에 클로저 컴파일러가 가장 잘하는 일, 즉 경량화를 사용할 수 있습니다. 이를 위해 구글은 타입스크립트가 클로저화된 자바스크립트를 생성할 수 있는 도구인 tsickle을 만들었습니다. 사실 이 도구는 오픈 소스이지만 외부인이 이해하기는 어렵습니다. 앵귤러에서 사용하는 것 같지만 제가 알 수는 없습니다.

자바스크립트 역사에서 흥미로운 교훈을 얻으셨길 바랍니다! 클로저 컴파일러는 자바스크립트 생태계가 다른 원칙과 다른 장단점을 가지고 선택할 수 있었던 대안적인 경로를 보여줍니다.

이 글에 대한 활발한 토론이 해커 뉴스에 있습니다. 특히 Paul Buchheit(지메일의 창시자!)는 런타임 성능이 클로저 컴파일러의 목표였으며 인라이닝/데드 코드 제거가 이를 달성하기 위한 방법이었다고 지적합니다. 모든 게터에 비용이 수반되는, JIT 이전의 IE6 사고방식으로 돌아가기는 어렵습니다! 그렇다고 해서 이 글의 결론이 바뀌는 것은 아닙니다. 또한 클로저 컴파일러는 구글 웹 툴킷(GWT)이 아닙니다.

- + \ No newline at end of file diff --git a/log/things-you-forgot-or-never-knew-because-of-react.html b/log/things-you-forgot-or-never-knew-because-of-react.html index e0ce3109..b6bc47f9 100644 --- a/log/things-you-forgot-or-never-knew-because-of-react.html +++ b/log/things-you-forgot-or-never-knew-because-of-react.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

리액트로 인해 잊었거나 전혀 몰랐던 것들

원문: Things you forgot (or never knew) because of React

목차

1부: 음악, 기본값, 그리고 버블에 대한 서론

많은 사람들처럼, 저 역시 현지 라디오 방송국에서 흘러나오는 음악만 듣던 시절이 있었습니다. (30세 이상의 많은 사람들이 그랬을 거예요. 이게 아직 공감되지 않는다면, 잠시만 기다려 보세요.) 당시에는, 그것만으로 충분히 행복했습니다. 제게 필요한 모든 것을 갖춘 것 같았으니까요.

돌이켜보면 저는 어리석게도 좋은 것은 결국 인기를 얻게 되고, 알아야 할 가치가 있는 것이라면 저에게 스스로 다가올 것이라고 믿고 있었다는 것을 깨달았습니다.

그러나 결국 다른 음악이 제 인생에 자리 잡기 시작했습니다. 새로운 친구들과 인터넷을 통해 이전에 좋아했던 것들과는 다른 새로운 아티스트들을 알게 되었죠. 제가 이전에는 좋아했던, 아니 적어도 좋아한다고 생각했던 음악에서 점점 멀어지게 되었습니다.

음악은 달랐습니다. 한 주 동안 사랑에 빠졌다가 다음 주에 질리는 일은 없었습니다. 음악을 듣는 것이 끝없는 순환의 일부가 아니었습니다.

오히려 그 반대였어요. 들으면 들을수록 더 좋아하고 감사하게 되는 음악이었죠. 깊이가 있었죠. 물론 그때까지 제가 좋아했던 시끄럽고 왜곡된 기타, 펀치라인 가사, 그럴듯하게 꾸며진 멜로디는 없었지만요. 놀랍게도 그 점이 오히려 노래를 더 좋게 만들었습니다.

그때 저는 제가 생각했던 것만큼 만족스럽지 않았을 수도 있다는 사실을 깨닫기 시작했습니다.

어쩌면 제 행복은 무지를 전제로 한 것일지도 모른다는 생각이 들었습니다.

기본값을 뛰어넘는 풍요로움 찾기

아마도 음악에 한정되지 않더라도 이 이야기에 공감하실 수 있을 것 같습니다.

아마도 한때 좋아하지 않았던 음식이나 음료가 이제는 좋아하는 것 중 하나가 되었을지도 모릅니다. 아니면 예상치 못한 영화, 책, 게임, 팟캐스트, 인플루언서, 취미 등이 자신과 잘 맞는다고 느끼게 된 적이 있을지도 모릅니다.

세부 사항은 중요하지 않습니다. 제가 말하고자 하는 것은

아마도 인기 있는 기본값 주변을 넘어서 뭔가 멋진 것을 발견한 경험이 있으리라는 것입니다.

잘난 척하는 힙스터의 프런트엔드 버전처럼 들리지는 않길 바랍니다. 그런 의도는 아니거든요. 올리브 가든에서 버드 라이트를 마시는 것이 좋은 시간이라고 생각하신다면, 좋아요, 대신 스틱빵은 좀 내놓으세요. (역자 주: 올리브 가든은 미국의 편안하고 저렴한 이탈리안 레스토랑 체인점이고 버드 라이트 역시 가볍게 마시기 좋은 미국의 맥주 브랜드. 스틱빵은 올리브 가든에서 제공하는 빵으로 맛있다고 알려져 있음. 익숙한 것 너머에 더 좋은 것이 있을 수 있다는 것을 말하기 위해 예시로 든 것.)

가 하고자 하는 말은, 여러분이 자신도 모르게 더 좋은 것을 놓치고 있을지도 모른다는 생각을 부드럽게 공유하려는 것입니다.

익숙한 경계를 넘어 더 나은 것을 찾는다는 이 개념은 어쩌면 다른 삶의 영역과 마찬가지로 도구와 워크플로우에도 적용될 수 있습니다.

그리고 아마도, 그저 아마도 당신의 현재 만족감은, 최소한 어느 정도는 단순히 무엇을 놓치고 있는지 모르기 때문에 비롯되는 것일지도 모릅니다.

비유를 완성하고, 그 한계를 인정하기

저는 이전에 '리액트는 프런트엔드 프레임워크의 새로운 기본이다' 라는 글을 쓴 적이 있는데, 리액트를 기본적으로 사용하는 대부분 사람은 이 프레임워크가 얼마나 낙후되어 있는지 잘 인식하지 못한다고 생각합니다.

그리고 여기서부터 우리의 비유에서 미흡한 부분이 보이기 시작합니다.

개인적인 취향에 국한해서 이야기해보면, 당신이 좋아하는 것에 대해 논쟁하거나 당신의 마음을 바꾸려고 블로그 포스트를 쓰지 않을 것입니다. (적어도 지금 이 나이에는) 누가 신경 쓸까요? 재밌게 즐기면 됩니다.

하지만 음악이나 다른 주관적인 즐거움을 위한 것들과 달리, 프런트엔드 도구 선택은 다른 사람들에게 경험적이고 측정할 수 있는 영향을 미칩니다.

이러한 결정에는 진정한 책임이 수반됩니다. 단순히 우리가 좋아하는 것에 대한 것만은 아닙니다. 순전히 우리 자신을 위해 무언가를 만드는 것이 아니라면 개발에서 즐거움은 부차적인 요소이며, 가장 중요한 것은 사용자의 경험입니다.

여러분이 사용하고 있는 도구를 좋아한다면 정말 멋진 일입니다. 저는 그렇기를 바랍니다. 하지만 그것은 기껏해야 부수적인 임무일 뿐이며, 최악의 경우 잠재적으로 해로운 방해 요소가 될 수 있습니다. 개발자 경험(DX)이 사용자 경험(UX)을 대체해서는 안 됩니다.

그러니 어설픈 비유를 선택한 것을 용서해 주세요. 원한다면 평생 같은 음악을 계속 들을 수도 있습니다. 저도 그렇게 생각합니다. 하지만 우리가 사용하는 도구에 있어서는 기존의 편안함을 뛰어넘어야 할 매우 타당하고 중요한 이유가 있습니다.

리액트 거품

리액트가 경쟁자들보다 뒤떨어진다는 생각은 생소할 수 있습니다. 많은 분처럼 여러분도 여전히 리액트가 프런트엔드에서 최신 표준이라고 생각할 수 있습니다. 따라서 본격적으로 목록으로 들어가기 전에 그 거품을 빠르게 파헤쳐 보겠습니다.

이 글을 쓰게 된 계기는 Alex Russell이 Mastodon에 쓴 글 때문입니다.

누군가 오늘 저에게 IE를 지원하지 않아도 되는 새로운 앱에서 리액트를 사용하는 이유가 있는지 물어왔습니다.

저는 단 하나의 이유도 생각해 낼 수 없었습니다...

리액트가 얼마나 구식이 되었는지 아주 놀라웠습니다.

Alex는 해당 스레드에서 웹 컴포넌트에 대한 리액트의 지원 부족을 언급했습니다. 이 기능은 수년 동안 리액트에서 눈에 띄게 누락되어 왔습니다. 그리고 네, "로드맵에 추가될 예정"이라고 합니다. 하지만 이 글을 쓰는 현재로서는 구현이나 예상 출시일에 대한 확고한 약속은 없습니다.

한편, 리액트 대신 선택할 수 있는 거의 모든 프레임워크나 기술에는 이미 해당 지원이 출시되어 프로덕션에 사용되고 있습니다.

웹 컴포넌트는 그중 하나일 뿐입니다. 하지만 웹 컴포넌트는 "다른 모든 것이 이미 하고 있거나 더 잘하는 것"의 목록에 있는 유일한 항목은 아닙니다. (아래에서 몇 가지를 더 다룰 것입니다.)

리액트는 프레임워크 게임 초창기부터 표준을 정립한 덕분에 큰 혜택을 누렸습니다. 하지만 유연성과 적응성에서 심각한 단점을 수반했습니다. 2013년경에 시작된 이래로 리액트가 내린 모든 결정은 또 다른 기술 부채를 안고 있으며, 이는 동시대 동종 업계에서는 찾아볼 수 없는 문제입니다.

Alex의 말을 다시 한번 인용하자면

리액트는 2008년 제약 조건에 맞춰 설계된 13년 기술입니다. 2023년에는 혁신적인 것은 아무것도 없습니다. 사실, 현대에 기능적인 반응형 프런트엔드 프로그래밍을 하는 데 가장 느린 방법입니다...

리액트는 노후화되었고, 대부분 사람이 얼마나 많이 또는 얼마나 열악한지 깨닫지 못하는 것 같습니다. 위의 인용문을 다른 방식으로 표현하자면 (그리고 음악에 대한 서문과 다시 연결해 보겠습니다.)

리액트는 존 메이어와 제니퍼 애니스톤이 아직 사귀고 있을 때, 테일러 스위프트의 일곱 장의 앨범이 나온 시절에 설계되었습니다.

(테일러 스위프트의 새 일곱 번째 앨범 출시 전이죠. Taylor's Version 발매를 포함하지 않습니다.)

따라서 당신이 지난 몇 년 동안 리액트를 사용해 온 많은 개발자 중 한 명이라면, 오랫동안 리액트를 사용해 왔기 때문에 잊어 버렸거나 전혀 몰랐던 것들이 있을 수 있습니다.

최신 프런트엔드가 빠르게 발전하는 만큼, 리액트를 왕좌에 올려놓았던 세상이 여러 면에서 더 이상 존재하지 않는다는 사실을 깨닫는 데는 매우 느린 것 같습니다. (그랬던 적이 있다면, 애초에 페이스북의 특정 문제와 유사한 문제를 가진 조직은 많지 않았습니다).

지난 10년 동안, 웹 브라우저는 자바스크립트와 CSS에서 놀라운 성장을 보여주며 새로운 기능들을 채택해 왔습니다. 기술과 사용자의 기대도 발전했고, 현재의 도구 생태계는 예상보다 훨씬 더 많이 반복하고 적응하며 리액트를 넘어선 발전을 이루었습니다. 그러한 발전은 기존의 소프트웨어로는 따라갈 수 없는 방식으로 이루어졌습니다.

참고 사항

리액트를 "레거시 소프트웨어"라고 부르는 것이 논란의 여지가 있다는 것을 알고 있지만, 이는 공정하다고 생각합니다. 비교적 복잡하고, 비교적 오래되었으며, 많은 규칙과 문제점을 포함하고 있고, 초보자는 종종 두려워하며, 리액트가 기반으로 하는 아키텍처 결정은 반복 능력에 방해가 되는 요소가 된 지 오래되었습니다.

이 시점에서 제가 아직 여러분을 완전히 소외시키지 않았다면(일종의 엘리트주의, 장황한 서론, 괄호 내용의 과도한 사용의 조합으로 인해), 여러분이 완전히 리액트 세계에만 집중하느라 놓쳤을지도 모르는 몇 가지를 공유하고 싶습니다. 여러분의 현재 재생 목록에 있는 것보다 더 좋다고 느낄 수 있는 곡들을 발견하게 될지도 모른다는 희망으로요.

2부: 리액트 때문에 잊고 있었던(혹은 전혀 몰랐던) 것들

더 이상 생태계가 거대할 필요가 없습니다(이제 공유할 수 있기 때문입니다)

다른 글에서도 언급했지만, "검증되지 않은" 프레임워크의 이름이 개발 프로젝트의 잠재적 도구로 떠오를 때마다 사람들이 가장 먼저 궁금해하는 것은 다음과 같은 질문입니다. 생태계가 얼마나 큰가?

이 글의 전제를 읽자마자 그런 생각을 하셨을 수도 있습니다. 리액트에서 다른 프레임워크로 옮길까? 아직 충분히 큰 프레임워크가 있을까?

왜 우리는 생태계 규모에 집착하는 걸까요?

물론 우리는 이 프레임워크가 몇 년 안에 사라지거나 유지보수가 중단되지 않을 것이라는 확신을 두고 싶습니다. 충분히 그럴 만합니다. 그리고 네, 저희는 너무 새롭거나 검증되지 않은 것에 모든 것을 걸진 않을 것입니다. 하지만 , 스벨트, 프리액트, 솔리드, 아스트로 등은 모두 그 시점을 훌쩍 지났으며 잘 지원되고 유지되고 있습니다. 따라서 단순히 그것 때문만은 아닙니다.

그렇다면 진짜 문제는 무엇일까요? 제 생각에는

패키지가 우리의 프레임워크를 위해 구축되어야 한다고 훈련받았기 때문입니다.

이러한 사고방식은 제이쿼리에서 시작되었다고 볼 수 있지만, 리액트가 이를 가속했다고 생각합니다.

리액트를 사용하면 캐러셀, 지도, 아코디언 등 특정 작업을 수행하기 위해 모듈이나 위젯, 라이브러리가 필요할 때마다 반드시 리액트로 만들어야 했고, 일반 웹이나 자바스크립트는 사용할 수 없었습니다. 리액트의 모든 규칙과 상태 처리, 컴포넌트 라이프사이클의 특이점 때문에 리액트용으로 명시적으로 작성되지 않은 패키지나 라이브러리는 작동하지 않을 가능성이 높았습니다.

리액트는 특정 프레임워크에 맞춰 빌드해야 한다고 가르쳐주었습니다. 그러나 그것은 더 이상 사실이 아니며, 틀림없이 그렇게 되어서는 안 됩니다.

특히 "자바스크립트일 뿐"이라고 자주 주장하는 프레임워크의 경우, 그렇게 할 필요가 없습니다. 단지 자바스크립트라면 실제로 자바스크립트인 모든 것에서 그냥 작동해야 합니다.

물론 다른 프런트엔드 프레임워크에도 상태와 아키텍처에 대한 자체 규칙과 관습이 있습니다. 비유적으로, 그들의 마당에 있는 갈퀴를 밟을 수도 있습니다.(역자주: 다른 프레임워크에서도 비슷한 문제가 발생할 수 있다는 뜻) 그리고 스벨트나 뷰 또는 그 밖의 다른 프레임워크와 함께 작동하도록 특별히 구축된 것들은 항상 존재할 것이고, 또 그래야만 합니다.

하지만 결정적으로, 그리고 가능한 한 강력하게 강조하고 싶습니다.

리액트만큼 플랫폼과 고집스럽게 호환되지 않는 최신 프런트엔드 프레임워크는 없습니다.

다른 현대적인 도구와 프레임워크를 사용하여 빌드하는 경우, 바닐라 자바스크립트 패키지가 잘 작동할 가능성이 훨씬 더 높으며, 그 패키지는 수천 개가 넘습니다. 렌더링 주기나 기타 프레임워크 관련 문제를 일으킬 가능성도 훨씬 적습니다. 말할 것도 없이, 이들 모두 웹 컴포넌트를 사용할 수 있는 옵션도 있습니다.

특별히 제작된 패키지나 라이브러리가 필요하지 않은 경우가 많습니다. 왜냐하면 당신의 것은 이미 플랫폼과 호환이 되기 때문이며, 따라서 이미 존재하는 모든 것과 호환됩니다.

프리액트 시그널은 프리액트와 함께 사용하도록 만들어졌지만, 어떤 프레임워크나 심지어 바닐라 자바스크립트에서도 가져와서 사용할 수 있는 놀라운 예입니다. 웹 컴포넌트 역시 리액트가 아닌 거의 모든 최신 프레임워크와 호환됩니다.

프레임워크에 부족한 부분이 있다면 플랫폼에 이미 필요한 기능이 있을 가능성이 높습니다. (예를 들어, 폼 제출의 경우, 리액트에서 항상 골칫거리였지만 이제 양방향 데이터 바인딩과 브라우저에서 제공하는 규칙을 사용하면 무한히 쉬워졌습니다.)

그리고 최악의 경우, 필요한 것을 만드는 것이 리액트에서보다 훨씬 더 쉬워질 수도 있습니다. (useState를 다른 프레임워크의 버전과 비교해 보면 알 수 있습니다.)

새로운 프레임워크는 매우 보수적인 개발자들에게 단점으로 여겨지곤 하는데, 그들은 모든 면에서 철저하게 검증되지 않은 것을 시도해 보기를 경계하기 때문입니다. 하지만 기술 부채와 오래된 브라우저 지원에 대해 걱정할 필요가 적고, 기존의 좋은 아이디어와 최신 브라우저 기능을 더 자유롭게 반복할 수 있다는 점에서, 새롭다는 것은 오히려 '장점'이라는 것을 기억해야 합니다.

리액트 훅은 사실 구식입니다

훅은 리액트의 최신 진화 단계로, 클래스 컴포넌트를 대체했습니다.

정당하게 칭찬할 부분에는 칭찬을 하겠습니다. 훅은 프런트엔드 영역에서 엄청난 전환점이었습니다. 이것은 우리 애플리케이션에서 로직과 상태를 구성하는 방법을 혁명적으로 바꿨습니다. 훅은 부인할 수 없을 만큼 훌륭하며, 거의 모든 프레임워크가 상태 관리를 위한 훅과 유사한 모델을 고수하게 되었습니다.

하지만 리액트 훅은 더 이상 새로운 것이 아닙니다. (사실, 훅을 사용하는 안정적인 리액트는 제 아이와 거의 같은 나이이고 몇 주 후에 유치원에 입학합니다.)

훅은 더 이상 경쟁 우위나 주목할 만한 기능이 아니라 기본입니다. 그저 우리가 일을 하는 방식일 뿐입니다.

다른 모든 프레임워크는 자체적으로 훅을 구현할 뿐만 아니라, 주목할 만한 점은 모든 프레임워크가 더 빠르고, 더 똑똑하고, 더 쓰기 쉬우며, 또는 이 세 가지가 모두 결합되어 있다는 것입니다.

프리액트의 시그널은 여기서 언급할 가치가 있으며, 스벨트의 매우 단순한 스토어도 마찬가지입니다. 솔리드에도 시그널이 있습니다. 심지어 훅에서 직접적으로 영감을 받은 뷰 3의 컴포지션 API도 리액트 구현에 비해 몇 가지 주요 이점이 있습니다.

훅은 훌륭한 패턴이며, 리액트는 이를 대중화시킨 공로를 인정받아 마땅합니다. 하지만 거의 모든 다른 프레임워크가 더 적은 규칙과 보일러 플레이트 없이 훅을 더 잘 수행합니다.

참고 사항

시그널의 개념이 익숙하지 않으시다면, 지나치게 단순화시킨 표현이지만, 반응형 상태의 한 단계 더 나은 진화, 즉 전체 컴포넌트가 아니라 다시 렌더링할 필요가 있는 노드만 다시 렌더링하도록 기본값을 개선한 업데이트된 훅이라고 생각하시면 됩니다.

더 이상 렌더링을 세부적으로 관리할 필요가 없습니다

고백할 게 있습니다. 저는 useMemouseCallback의 차이점이 무엇인지, 언제 사용해야 하고 사용하지 말아야 하는지 아직 정확히 알지 못합니다. 말 그대로 오늘 오전에 바로 이 주제에 대한 글을 여러 개 읽었음에도 불구하고요. (농담이 아닙니다.)

두 번째 고백하자면, useEffect 의존성 배열에 들어가야 하는 것과 들어가서는 안 되는 것, 또는 그 이유가 여전히 직관적이지 않다는 것입니다. 저는 useEffect 호출을 작성할 때마다 린터가 좋아하는 모양으로 코드를 리팩터링하는 데 15분 정도를 소비하는 것 같은 느낌이 드는데, 실제로는 괜찮고 앱을 무한한 심연으로 빨아들이지 않을 것이라고 99% 확신하는 경우에도 마찬가지입니다.

리액트를 사용하신다면 아마 이런 고백에 공감하실 수 있을 겁니다. 어쩌면 이런 혼란과 모호함을 당연한 것으로 받아들였을지도 모릅니다. 하지만 그렇다면 한 가지 알아두세요.

다른 프레임워크에서는 이런 종류의 렌더링 사이클 미세 관리를 수년 동안 하지 않아도 되었습니다.

요즘 프레임워크는 사용자가 직접 손을 잡고 설명하지 않아도 이런 종류의 작업을 처리할 수 있을 만큼 똑똑합니다.

프레임워크는 실제로 필요하지 않은 리렌더링에 귀중한 자원을 낭비하지 않도록 이미 상황을 알고 있습니다. 그들은 필요하지 않은 것을 지속해 재평가하지 않고 값만 업데이트할 수 있을 만큼 똑똑합니다.

...대부분의 경우에 그렇습니다. 그들도 완벽하지는 않습니다. 하지만 무엇을 해야 하는지 알고, 기본적으로 성능 좋은 방식으로 수행하는 데는 리액트보다 훨씬 낫습니다.

다른 프레임워크에서도 몇 가지를 최적화해야 할 수도 있습니다. 완벽하지는 않습니다. 하지만 그렇게 할 때쯤이면 리액트에서 해야 했던 지점을 훨씬, 훨씬 지나고 있을 것입니다.

프레임워크의 useEffect 버전을 두려워하는 사람은 아무도 없습니다

컴포넌트가 DOM에 들어갈 때 무언가를 수행하게 하고 싶거나, 다른 데이터나 변수를 기반으로 동적으로 무언가를 다시 계산하기를 원할 때 거의 모든 다른 프레임워크는 useEffect보다 더 나은 방법을 가지고 있습니다.

여기서 너무 길게 설명할 필요는 없을 것 같습니다. React 커뮤니티 내에서도 useEffect는 악명 높은 위험한 것으로 간주하며 심지어는 아예 피하는 경우도 많기 때문입니다. 하지만 저를 믿으세요. React 기반이 아닌 다른 어떤 프런트엔드 프레임워크도 이렇게 정상적이고 유용한 기능을 사용하는 것을 두려워하지 않으며, 그 어느 곳에도 이와 같은 모호한 규칙은 없습니다.

컴포넌트가 마운트될 때 무언가를 하기 위해 서드파티 패키지를 살펴보는 사람은 아무도 없습니다.

확장성은 더 이상 프런트엔드의 문제가 아닙니다

이것은 사람들이 새로운 (리액트가 아닌) 프레임워크가 등장할 때 즉시 묻는 또 다른 질문입니다. 확장성이 있을까요? 하지만 저는 이 질문이 약간 시대에 뒤떨어진 질문이라고 생각합니다.

기억할 가치가 있는 것은 리액트를 탄생시킨 세계에는 다른 문제들이 있었다는 것입니다.

당시에는 대부분의 프런트엔드 UI가 바닐라 자바스크립트나 제이쿼리(또는 이와 유사한 대안)로 빌드되었습니다. 그리고 지금 우리가 알고 있듯이 이러한 앱 구축 방식은 특정 한계를 넘어서는 확장이 불가능했습니다.

그 이유는 상호작용하고자 하는 모든 요소와 DOM 노드에 대해 직접 선택자를 작성해야 했고, 상태를 추적하고 동기화하는 방법을 직접 수동으로 만들어야 했기 때문입니다. 이 작업에는 보통 DOM을 읽고 쓰는 작업이 포함되는데, 이 작업은 지저분하고 오류가 발생하기 쉬우며 무엇보다도 속도가 느렸습니다. (그래서 가상 DOM이 등장했지만, 그것조차도 몇 년 동안 완전히 구식이 되었습니다.)

당시에는 모듈식 코드를 작성하는 것이 불가능에 가까울 정도로 어려웠고, JS 파일은 수천 줄은 아니더라도 수백 줄로 늘어나는 경우가 많았습니다. 여러 작성자가 같은 프로젝트에서 작업하는 경우 서로의 코드를 재창조하거나 반복하거나 심지어 재정의하는 경우가 많았습니다(코드가 공유 글로벌 네임스페이스에 들어가는 경우가 많았기 때문에 충돌 가능성이 훨씬 더 높았습니다). 그리고 앱의 규모가 크거나 복잡할수록(Facebook) 문제는 더욱 심각해졌습니다.

기억해야 할 것은 다음과 같습니다. 앱이 기하급수적으로 성장하더라도 합리적으로 유지 관리가 가능한가? 이것이 프런트엔드와 관련하여 "확장성이 있는가?" 를 기준이라는 점입니다.

프런트엔드 프레임워크가 확장되지 않을 수 있다는 우려는 제이쿼리만큼이나 오래되었으며, 최신 웹 개발과 관련해서는 구시대적인 것으로 간주하여야 합니다.

리액트는 이러한 문제 중 많은 부분을 해결했습니다. 하지만 현대 공학의 기적이라기보다는 단순히 상태를 관리 및 공유하고, 데이터를 반응형으로 만들고, 복잡성을 추상화하며, 충돌, 네임스페이스 충돌, 재정의 없이 개발자가 동일한 프로그래밍 패턴을 공유할 수 있는 좋은 방법을 고안해 해냈습니다.

리액트는 프런트엔드 확장성을 위한 최고의, 유일한, 심지어 '최초의' 솔루션이 아니라 동일한 패러다임의 여러 버전 중 하나일 뿐입니다.

(또한 가장 오래된 버전 중 하나이기도 합니다.)

이를 어떻게 알 수 있을까요? 리액트의 성능을 다른 모든 프런트엔드 프레임워크와 대규모로 비교하는 수많은 벤치마크 테스트가 실행되어 그 결과가 공개되어 있습니다. (온라인에서 쉽게 구할 수 있기 때문에 여기서는 링크하지 않습니다.) 이 모든 테스트는 프런트엔드 분야의 거의 모든 다른 옵션이 리액트와 동등하거나 더 나은 성능을 발휘하며, 많은 경우 훨씬 더 나은 성능을 발휘한다는 것을 확인시켜 줍니다.

참고 사항

여기서는 앱의 크기가 커짐에 따라 복잡성이 선형적으로 증가하지 않고 최소한으로 유지되도록 하는 일반적인 의미의 확장을 언급하고 있습니다. 물론 일부 프레임워크는 마크다운 파일에서 정적 HTML을 빌드하는 것과 같은 더 전문화된 작업 측면에서 훨씬 더 나쁘거나 좋게 확장될 수 있습니다.

서버 사이드 렌더링은 더 이상 특별하지 않습니다

몇 년 전, 서버 렌더링 콘텐츠(주로 Next.js를 통해)에 관한 한 리액트가 거의 유일한 해결책이었던 시절이 있었습니다. 사람들은 리액트를 클라이언트가 아닌 서버에서 단일 페이지 앱(SPA)으로 HTML로 렌더링할 수 있다는 사실에 당연히 흥분했습니다. 속도와 SEO 개선 효과는 무시할 수 없었고, 처음에는 다른 프레임워크가 따라잡는 데 다소 시간이 걸렸습니다.

하지만 일반적으로, 특히 이 글의 주제와 마찬가지로 가장 먼저 개선을 시작하는 것이 최고인 경우는 거의 없습니다.

스벨트키트는 사용자가 아무것도 할 필요 없이 기본적으로 서버 렌더링되며, 렌더링 패턴을 세밀하게 제어할 수 있습니다. 뷰의 메타 프레임워크인 Nuxt는 게임에 더 일찍 참여했습니다(Next.js에서 영감을 받은 것이 분명합니다).

프레시(Deno의 프런트엔드 프레임워크)는 "아일랜드"(클라이언트 렌더링)로 지정한 것을 제외하고는 전적으로 서버 렌더링이며, 그 외에는 정적 HTML로만 제공됩니다. 프레시는 또한 프리액트를 사용합니다(이 역시 리액트보다 훨씬 빠르며, 훨씬 더 성능이 좋고 인체공학적인 버전의 useState와 반응성 모델인 시그널를 가지고 있습니다.).

아스트로는 서버 렌더링 기능을 가지고 있으며, 원하는 컴포넌트를 서버 렌더링할 수 있습니다. 다른 프레임워크의 컴포넌트도 잘 렌더링할 수 있으며, 경우에 따라서는 Next.js의 주요 성능 업그레이드로 주목받기도 했습니다.

솔리드스타트(솔리드의 메타 프레임워크)에는 서버 렌더링이 있습니다. 퀵은 전적으로 이 프레임워크를 중심으로 구축되었습니다. EmberAngular와 같은 오래된 프레임워크도 스토리가 있으며, 다른 프레임워크들도 있을 것이라 확신합니다.

요점은 과거에 리액트는 클라이언트 뷰 프레임워크 컴포넌트를 서버에서 렌더링하는 개념을 가진 몇 안 되는 프레임워크 중 하나였다는 것입니다. 하지만 지금은 서버 렌더링이 필수입니다. 많은 최신 프레임워크는 서버에서 렌더링할 수 있는 옵션을 제공할 뿐 아니라 기본값으로 렌더링합니다.

PHP가 돌아왔습니다.

양방향 데이터 바인딩은 어렵지 않고 나쁜 생각도 아닙니다

리액트는 페이스북이 페이스북 고유의 문제를 해결하기 위해 만들었다는 점을 기억하는 것이 중요하다고 생각합니다.

데이터는 한 방향(하향식)으로만 흘러야 한다는 리액트의 강력한 의견 중 하나는 2010년대 초에 Facebook이 직면했던 엔지니어링 도전이 어떻게 리액트의 아키텍처를 형성했는지를 보여주는 좋은 예입니다.

한동안은 단방향 데이터 흐름이 모범 사례로 간주하는 것처럼 보였습니다. 하지만 요즘에는 양방향 데이터 바인딩의 함정에 대한 해결책을 대부분 찾아냈고, 많은 경우 이것이 실제로 훨씬 더 편리하다는 것을 알게 되었습니다.

리액트에서 폼을 작업하는 것은 악명이 높습니다. 이는 사용자의 모든 키 입력이 두 단계 과정을 거치기 때문입니다. 입력에서 값을 얻어온 다음, 그 값을 상태에 설정해야 합니다(이에 따라 입력이 불필요하게 다시 렌더링되며 이미 있던 정확한 값을 포함하게 되지만 리액트 상태와 동기화됩니다.). 물론 보통은 너무 빨라서 눈치채지 못하지만, 추가 작업이 많이 필요합니다.

스벨트, 뷰 등 다른 많은 자바스크립트에서는 이 문제가 없습니다. 상태를 양방향으로 자동 업데이트되도록 바인딩할 수 있습니다. 상태가 변경되면 DOM이 업데이트되고, DOM이 변경되면 상태가 업데이트됩니다.

이렇게 하면 여러 단계를 거칠 필요가 없습니다. 예를 들어 텍스트 상자의 값만 캡처하려는 경우 양방향 데이터 바인딩을 수행하면 됩니다. 그러면 사용자가 필드에 입력하면 데이터가 자동으로 업데이트되므로 추가 단계 없이 적절한 시점에 데이터를 가져올 수 있습니다. 그 사이에 값을 설정하거나 필드를 지우는 등의 작업을 수행해야 하는 경우에도 한 줄로 간단하게 처리할 수 있습니다.

양방향 데이터 바인딩을 사용하면 한쪽이 다른 쪽을 따라잡고 있는지 계속 확인할 필요 없이 데이터와 DOM을 동기화 상태로 유지할 수 있습니다.

이 기능을 사용하면 문제가 발생할 수 있나요? 물론 그럴 수 있습니다. 하지만 모범 사례에 대한 독단적인 이상은 도움이 되기보다는 오히려 방해가 될 수 있습니다. 단방향 데이터 흐름이 대표적인 예입니다.

스타일링은 사실 쉽습니다

리액트로 주로 작업한다면 프런트엔드 컴포넌트에서 스타일을 처리하는 과정을 두 번, 세 번, 혹은 그 이상 반복했을 가능성이 높습니다.

.css 파일을 JSX 컴포넌트로 바로 가져왔을 수도 있고, CSS 모듈, 스타일 컴포넌트 및/또는 테일윈드를 사용했을 수도 있습니다(아마도 classnames 또는 tailwind-merge 패키지와 함께, 또는 둘 다와 추가 테일윈드 애드온을 함께 사용했을 수도 있습니다). 그리고 이것들은 가장 인기 있는 옵션일 뿐입니다.

테일윈드는 그 자체로 토끼굴입니다(그리고 그 자체로 프런트엔드 프레임워크로 제가 특별히 좋아하지 않습니다. 저는 플랫폼의 결에 반하는 것은 단기적인 이득을 얻는 대신 결국 장기적인 손실로 이어진다고 생각합니다.) 하지만 어쨌든 이러한 스타일링 솔루션이 존재하고 상당수 채택된 것은 적어도 부분적으로는 리액트가 처음 출시될 때부터 공식 스타일링 옵션이 없는 공백이 있었기 때문입니다.

스타일링이 다른 여러 프레임워크에서 해결된 문제라는 사실을 모를 수도 있습니다.

특히 뷰와 스벨트는 모두 자체적인 컴포넌트 스타일링 스토리를 가지고 있습니다. 둘 다 컴포넌트 수준 스코핑을 지원합니다(뷰는 참여 동의(opt-in) 방식이고, 스벨트에서는 참여 철회(opt-out) 방식입니다.). 둘 다 바닐라 CSS와 훌륭하게 작동합니다(원하는 방식이라면). 하지만 다른 모든 프런트엔드 프레임워크와 마찬가지로 이 두 프레임워크는 CSS 모듈, 테일윈드, Sass 또는 기타 사용하고자 하는 다른 프레임워크와도 호환됩니다.

하지만 가장 중요한 점은 CSS의 모든 문제(실제로 문제라고 생각하든 그렇지 않든)가 내장된 스타일 처리 기능으로 완벽하게 해결된다는 점입니다. 범위 지정 CSS는 상상할 수 있는 거의 모든 문제를 해결하기 때문에 다른 곳에서처럼 복잡한 패키지와 설정이 필요하지 않습니다.

CSS가 나쁘다는 이유 목록을 읽어보세요(실제로는 그렇지 않지만, CSS를 잘 모르는 사람들은 그렇게 말하길 좋아합니다). CSS에 대한 거의 모든 비판은 범위 지정 스타일링으로 해결되며, 여러 비(非)반응형 프레임워크에 이미 이 기능이 내장되어 있습니다.

프레임워크는 더 이상 배우기 어렵지 않습니다

저는 리액트를 주로 교육받은 개발자들이 배우기가 얼마나 어려웠는지 되돌아보고 다른 프레임워크의 학습 곡선도 비슷하게 평가할 것으로 생각합니다. 아마 그것이 우리가 새로운 시도를 하지 못하게 하는 이유 중 하나일 것입니다. 왜냐하면 처음이었기 때문에 정말 어려웠기 때문입니다.

상태 관리, 프로퍼티, 중첩, 컴포넌트 수명 주기, 훅, 그리고 물론 JSX를 작성하는 방법까지... 정말 많은 것들이 있습니다. 아무리 열렬한 리액트 팬이라도 초보자가 빠르게 익히기가 쉽지 않다는 것을 인정할 것입니다. (그렇지 않다고 말하는 사람은 아마 초보자였을 때를 잊어버린 사람일 것입니다.)

공감하실 수 있다면 좋은 소식이 있습니다.

리액트만큼 배우기 어려운 도구는 없습니다. 하지만 일단 하나의 프레임워크를 알게 되면 다른 모든 프레임워크에서 큰 도움이 됩니다.

저는 이것을 두 번째 악기를 배우는 것에 비유합니다 (음악에 다시 연결하기 위해서가 아니라). 처음 연주를 배울 때는 특정 악기를 배우는 것 외에도 음악에 대한 모든 것을 배우고, 악기로 원하는 소리를 내는 방법을 배우게 됩니다. 하지만 두 번째 악기를 배울 때는 많은 부분을 건너뛸 수 있습니다. 모든 개념이 익숙해집니다. 음악을 이해하니까요. 여러분이 해야 할 일은 기존의 지식과 근육 기억을 약간 다른 형태로 옮기는 것뿐입니다.

프런트엔드도 비슷합니다. 모든 프런트엔드 프레임워크에는 컴포넌트가 있고, 모두 타입스크립트와 호환되며, 모두 프로퍼티, 자식, 반응 상태라는 개념이 있습니다. 이러한 것들은 우리가 일반적으로 좋아하고 좋다고 동의한 것들입니다. 다만 구현 방식이 다를 뿐입니다.

말하자면, 리액트는 의심할 여지 없이 이러한 아이디어를 확산하는 데 도움이 되었지만, 리액트가 이러한 아이디어를 이상적으로 구현하는 것으로 생각하는 것은 어리석은 일입니다.

훌륭한 것은 반복을 통해 만들어지며, 대부분의 경우 나중에 나온 프런트엔드 영역의 다른 선택은 리액트의 핵심 아이디어를 기반으로 발전한다는 뚜렷한 이점을 가지고 있습니다.

즉, 리액트는 main보다 한참 뒤처진 git 브랜치와 비슷합니다. 리액트가 당신 은하계를 공전하는 별이라면 깨닫지 못할 수도 있지만... 프런트엔드는 이미 발전했습니다. 생태계는 이러한 아이디어를 받아들여 더 나은 것을 만들기 위해 달려왔습니다.

이제 더 성능이 뛰어나고 덜 복잡하며 배우기 어려운 옵션이 넘쳐납니다. 그리고 이미 리액트를 알고 있다면 그 어떤 것도 배우기 어렵지 않을 것입니다.

참고

다음 두 섹션은 게시물의 초안에는 포함되어 있지 않았으며, 2023년 8월 15일에 원본 버전에 대한 피드백을 해결하기 위해 추가되었습니다.

"새롭고 빛나는 것"만이 전부가 아닙니다 (그리고 아무도 그것에 대해 신경 쓰지 않습니다)

이러한 주제를 논할 때 자주 듣는 말은 대략 다음과 같습니다.

항상 새롭고 빛나는 것만 쫓는 멍청한 자바스크립트 개발자들! 그들은 프로젝트를 장기적으로 유지하는 데는 관심이 없어. 새롭고 멋진 프레임워크는 내일이면 잊히고 코드가 실행되지도 않을 거라고!

여기에 조금의 진실이 있습니다. 사실, 자바스크립트 개발자들(감히 말하자면 보통의 프런트엔드 개발자들)은 다른 프로그래밍 전문가들이 경계하는 것에 비해 조금 더 새로운 것에 끌리는 경향이 있는 것 같습니다.

...그런데 실제로는 얼마나 사실일까요? 전 세계 모든 자바스크립트 개발자가 새로운 것이 나타나는 순간 그들의 기술 스택 전체를 다시 작성하러 나설 것이라 확신하나요? 아니면 끊임없는 온라인 유행 흐름에 의해 양산되어 그렇게 느껴지는 것일까요?

저는 이 현상이 실제보다 더 과장돼 보이는 것이라고 생각합니다. 왜냐하면 얼리 어답터들은 모든 주목을 받는 경향이 있기 때문입니다. 그들은 많은 블로그 게시물을 작성하고 동영상을 제작합니다. 이것들이 공유되고 회자되면서 실제보다 훨씬 더 많은 종류의 행동이 일어나고 있는 것처럼 보이는 경향이 있기 때문에 실제보다 훨씬 더 과장되어 보이는 것 같습니다. (이 말이 절반만이라도 사실이라면 리액트의 시장 점유율은 지금보다 훨씬 낮아졌을 것입니다.)

제가 만난 대부분의 프런트엔드 개발자들은 다른 종류의 개발자들과 마찬가지로 자신이 알고 있는 것을 고수합니다. 단지 새로운 것을 시도하는 데 비용이 상대적으로 덜 들기 때문에 그렇게 한다고 생각합니다.

하지만 이러한 관점은 현장에서 사용할 수 있는 다른 선택지의 성숙도를 과소평가하는 것입니다.

뷰는 리액트만큼이나 오래 사용되어 왔으며 현재 버전(v3)은 거의 3년 전에 출시되었습니다. 최신 버전의 스벨트는 리액트 훅이 출시된 지 2개월 후에 출시되었으며(2개월 전에 리액트 훅이 새롭고 반짝이는 것이라고 생각하셨나요?), 스벨트키트는 거의 1년 전에 1.0을 출시했습니다. 프리액트는 버전 10에 있습니다. 솔리드는 2년이 넘도록 1.0+ 버전입니다. 아스트로는 1년 전에 1.0을 출시했습니다. 여기서 언급할 퀵과 프레시는 가장 최근에 출시되었지만 올해 초 기준으로 모두 1.0 버전입니다.

따라서 이러한 항목 중 일부가 아직 너무 새롭더라도 괜찮습니다. 이해합니다. 하지만 리액트 대안에 대한 고려를 짧은 기간 때문에 축소시키는 것은 이 분야의 성숙도와 깊이를 간과하는 잘못된 판단입니다.

리액트는 성능면에서 뒤처져 있습니다

이 주제에 대해서는 이미 많은 글이 있기 때문에 너무 길게 설명하지는 않겠습니다(제가 쓴 다른 글에도 있고, 온라인에서 쉽게 찾을 수 있습니다). 하지만 간단히 말하자면 리액트는 미미할 정도로만 느리게 느껴질 수 있지만(특히 매우 고급/최신 하드웨어와 매우 빠른 인터넷 연결을 사용하고 있다면 더욱 그렇습니다), 그 차이는 사소한 것이 아닙니다.

리액트는 성능(번들 크기와 실행 속도를 모두 의미합니다) 측면에서 많은 경우 2배 이상 뒤쳐집니다. (번들 자체는 10배 이상 차이가 날 수도 있습니다.) 최근 실행된 JS 웹 프레임워크 벤치마크에 따르면 리액트의 성능은 평균적으로 솔리드보다 거의 50%, 뷰보다 25%, 스벨트보다 40%, 프리액트보다 35% 느린 것으로 나타났습니다. (이 테스트에서는 다른 프레임워크가 사용되지 않았습니다.)

참고 사항

이 비교는 useTransition 훅과 리덕스와 같은 추가 라이브러리를 사용하지 않고 리액트 훅만 사용했을 때였습니다.

다른 연구도 있습니다. 연구마다 수치가 조금씩 다를 것이고, 연구 결과에는 항상 미묘한 차이가 있을 것입니다. 하지만,

어떤 결과를 참고하든 리액트는 그 이후 나온 거의 모든 결과보다 더 크고 느립니다.

실제 사례를 통해 설명하자면, 저는 안드로이드 폰에서 작성하는 폼에 리액트가 사용된다면 그걸 알 수 있습니다. 느린 속도와 상태와 일치하도록 DOM을 업데이트하는 루프가 반복되기 때문입니다. 그리고 리액트가 아니면 눈치채기가 힘듭니다.

하지만 사례는 잊어버리세요. 방금 데이터를 봤으니까요. 그리고 이 수치가 크게 느껴지지 않을 수도 있고, 기술 스택을 선택할 때 성능은 여러 고려 사항 중 하나일 뿐이라는 것을 알고 있습니다. "모든 것은 상황에 따라 다릅니다."

하지만 25 ~ 50%의 성능 개선은 성능 향상 측면에서 엄청난 수치라는 점을 기억하세요. 사용자의 프런트엔드 로딩 속도를 최대 두 배까지 향상한다는 것은 단순히 약간의 성능 향상의 수준을 훨씬 뛰어넘어 규모에 따라 엄청난 차이를 가져올 수 있는 수치입니다.

웹사이트를 로딩하거나 작업이 완료되기를 기다릴 때 매 초가 얼마나 중요한지 수많은 연구를 인용하지 않아도 알 수 있을 것입니다. 또한 대용량 자바스크립트 번들을 다운로드할 대역폭이 없거나 프레임워크가 페이지를 변경할 때마다 최대 2배 더 오래 기다릴 수 있는 컴퓨팅 성능이 떨어지는 사용자를 고려하는 것이 얼마나 중요한지 굳이 설명할 필요가 없으리라 생각합니다.

이렇게 큰 로딩 또는 처리량을 줄인 엔지니어는 이를 이력서에 눈에 띄는 위치에 기록할 것입니다. 이는 중요한 문제입니다.

리액트와 나머지 필드 사이의 성능 차이는 미미하지 않습니다. 오히려 최소화된 것입니다.

3부: 시도해 봐야 할 다른 것들

아마도 수십 단락 전부터 궁금해지기 시작했을 것입니다. 리액트가 그렇게 구식이라면 대안은 무엇일까요?

여기서는 몇 가지를 다루고 그 사용 사례에 대해서도 언급하겠습니다. 리액트의 문제 중 하나는 오랫동안 모든 사람을 위한 모든 것이 되려고 노력해 왔다는 점이며, 리액트 형태의 도구가 유용할 수는 있지만 하나의 스위스 군용 칼보다 두세 가지 다른 도구가 더 나을 수 있다고 생각합니다.

하지만 본격적으로 들어가기 전에 두 가지를 간단히 짚고 넘어가겠습니다.

  1. 위에서 언급한 다른 모든 최신 프레임워크를 다루기 위해 여기에 여러 옵션을 나열하고 있습니다. 이 모든 프레임워크에 대해 배우거나 사용할 것이라 예상하지는 않습니다. 굳이 하나를 선택해야 한다면 스벨트 또는 뷰를 선택하세요. 저는 철저함을 위해 모두 나열한 것뿐이라는 점을 알아두세요.

  2. 모든 옵션을 나열하지는 않았습니다. 언급하지 않은 다른 옵션도 있습니다.

    예를 들어 Ember와 Angular는 생략했는데, 그 이유는 둘 다 리액트보다 오래되었고 일반적으로 벤치마크 테스트에서 리액트를 크게 앞지르는 경향이 없기 때문입니다(미안해요, Mel).

    또한 AlpinePetite Vue와 같은 경량 옵션은 생략했는데, 이는 리액트보다는 제이쿼리의 대체품에 가깝고 프레임워크처럼 무거운 것이 필요하지 않은 경우에 빛을 발하기 때문입니다.

    마지막으로, 이 카테고리에서 약간 벗어난 매우 훌륭한 도구도 생략했습니다. Eleveny는 프레임워크라기보다는 순수한 정적 사이트 생성기에 가깝기 때문입니다. (하지만 개츠비를 사용 중이라면 한번 살펴볼 가치가 있습니다.)

이제 주간 추천을 소개합니다.

스벨트 (제 개인적인 선택)

2023년도 수료생 여러분, 스벨트를 사용하십시오.

미래에 대한 한 가지 팁만 드릴 수 있다면, 그것은 스벨트일 것입니다.

농담은 제쳐두고, 이 목록에서 리액트보다 추천할 만한 것을 하나만 꼽으라면 스벨트가 될 것입니다. 저는 2019년에 트위터에서 "스벨트는 헛소리를 뺀 리액트다"라고 오랫동안 주장해 왔고(RIP), 시간이 지날수록 그 주장은 더욱 진실이 되어가고 있습니다.

스벨트는 사용하기 쉽고, 비교적 배우기 쉬우며(특히 이미 리액트를 사용해 본 적이 있다면 더욱 그렇습니다. 구문도 비슷한 경우가 많습니다), 거의 모든 경우에서 훨씬 더 성능이 뛰어나고, 리액트가 할 수 있는 모든 것을 할 수 있습니다. 이 사이트와 요즘 제가 하는 모든 사이드 프로젝트는 스벨트키트으로 작성됩니다.

스벨트는 가장 빠른 옵션과 비교해도 손색이 없을 정도로 빠릅니다. 개발자 설문조사에서 가장 사랑받는 프레임워크의 최상위권 또는 그 근처에서 자주 등장할 정도로 DX가 놀랍습니다.

스벨트는 가능한 한 웹 플랫폼에 가깝게 개발되었기 때문에 매우 강력하면서도 개념은 대체로 친숙할 것입니다. 또한 스벨트에는 트랜지션, 이징, CSS 처리, 컴포넌트 범위 스타일 등 다양한 기능이 기본으로 포함되어 있습니다.

프레임워크 크기에 대해 궁금해하실 수도 있지만, 스벨트는 자바스크립트 런타임이 아니라 컴파일러라는 점에서 다른 점이 있습니다. 빌드 시 사용하지 않는 모든 것이 제거되고 코드가 작은 바닐라 자바스크립트 비트로 트랜스파일됩니다. 즉, 스벨트의 번들은 일반적으로 리액트의 몇분의 1 크기입니다.

프레임워크처럼 느껴지고 작동할지라도, 스벨트는 본질적으로 작고 우아한 HTML의 상위 집합으로, 빠르고 최소한의 번들로 컴파일되는 유쾌하고 간단한 구문을 가지고 있습니다.

스벨트의 자체 메타 프레임워크인 스벨트키트는 정적, 서버 렌더링, 엣지 배포, 라우트별 혼합까지 가능한 매우 다재다능하고 강력합니다. 2022년 말에 1.0 버전이 출시되었으며 프로덕션에 바로 사용할 수 있습니다. (Next.js를 만드는 Vercel에서도 지원합니다.)

스벨트는 다음과 같은 경우에 추천합니다.

위와 같은 이유로 최고의 만능 옵션으로 프런트엔드의 즐거움을 재발견하고 싶은 경우.

스벨트는 다음과 같은 경우를 대체 가능합니다.

리액트로 하는 모든 작업. 스벨트는 리액트 자체를 대체할 수도 있고, 스벨트키트는 Next.js, 개츠비, 리믹스를 대체할 수 있을 만큼 다재다능합니다(또는 한 번에 모두 대체할 수도 있습니다).

는 아마도 리액트와 가장 유사한 선택지일 수 있으며, 다음으로 큰 생태계를 가지고 있을 것입니다. 하지만 리액트보다 성능이 훨씬 뛰어나고 UI에 좀 더 중점을 둡니다.

어떤 면에서는 뷰가 리액트에서 가장 작은 도약이라고 할 수 있는데, 특히 뷰 3에서 유사한 훅 기반 접근 방식을 사용한다는 점에서 더욱 그렇습니다. 그러나 뷰는 JSX보다 기본 HTML에 가까운 템플릿 언어를 사용하므로 map 및 삼항식과 같은 해결 방법을 사용하지 않고도 템플릿 파일에 조건문과 루프를 훨씬 쉽게 작성할 수 있습니다.

뷰는 Nuxt의 Next.js와 유사한 메타 프레임워크를 가지고 있으며, 잘 유지 관리되고 항상 강력한 새 기능을 추가하고 있습니다. 또한 뷰는 범위 지정 CSS 처리 및 쉬운 전환/애니메이션과 같은 기능을 즉시 사용할 수 있어 리액트보다 약간 더 많은 기능과 도구를 기본적으로 제공하고 있습니다.

뷰는 다음과 같은 경우에 추천합니다.

커뮤니티 규모/전체 프레임워크의 인기가 중요한 요소인 경우, 리액트와 비슷하지만, 더 많은 기본 기능이 포함되거나 HTML과 유사한 것을 원하는 경우, 프레임워크가 대기업에 소유되지 않고 독립적인 것을 선호하는 경우.

뷰는 다음과 같은 경우를 대체 가능합니다.

리액트 자체 또는 Nuxt가 Next.js를 사용하는 모든 것을 대체할 수 있습니다.

솔리드

솔리드는 제가 더 나은 리액트라고 부르는 것입니다. 많은 경우 리액트와 거의 (완전히는 아니더라도) 동일해 보이지만 솔리드가 훨씬 더 성능이 뛰어납니다. 사실 빠른 옵션 중 하나입니다.

솔리드는 기본적으로 리액트에서 시작하여 복잡성, 성능 문제 및 많은 보일러 플레이트를 제거하도록 재구성됩니다. 솔리드에서는 시그널이 개념이 나타나며 컴포넌트 렌더링과 수명주기에 대한 혼란과 발목을 잡는 요소가 상당 부분 제거됩니다. 2013년 이후 우리가 배운 모든 교훈을 바탕으로 현대에 리액트가 만들어졌다면 솔리드는 리액트라고 해도 과언이 아닐 것입니다.

솔리드는 현재 베타 버전이긴 하지만 솔리드스타트에서 자체 메타 프레임워크도 제공합니다. 하지만 솔리드 자체는 충분히 사용하기에 충분히 성숙했으며 인상적인 후원사 갤러리를 자랑합니다.

솔리드는 다음과 같은 경우에 추천합니다.

일반적으로 리액트(및 JSX)를 좋아하지만, 더 현대적이고 빠르거나 더 쉬웠으면 하는 경우, 성능이 절대적인 최우선 순위인 경우.

솔리드는 다음과 같은 경우를 대체 가능합니다.

리액트와 리액트 DOM. 솔리드스타트는 언젠가 Next.js를 대체할 수 있을 것으로 보이지만, 이 글을 쓰는 현재로서는 아직 베타 버전입니다.

프레시(Fresh)

프레시는 서버사이드 렌더링 프런트엔드 프레임워크로, Deno에 구축된 아일랜드 아키텍처를 사용합니다. 이 목록에 있는 다른 대부분의 항목보다 조금 더 어리지만, Deno로 구동되는 엣지에서 실행할 수 있는 최소한의 JS, 아일랜드 기반 프레임워크로서 가능성이 가득합니다. 즉, 서버 코드가 더 빠르고, 더 안전하며, 기본적으로 타입스크립트를 사용하고, Deno가 기존 Node보다 제공하는 다른 모든 이점(예: 더 쉬운 퍼스트 파티 린팅, 테스트 및 코드 서식 설정)을 누릴 수 있다는 뜻입니다.

모든 프레시 컴포넌트는 정적으로 렌더링되어 응답 시 자바스크립트 없이 HTML로 제공되거나, 클라이언트에서만 렌더링되는 "아일랜드"로 제공됩니다. 필요에 따라 혼합하여 사용할 수 있습니다. Deno에서 실행되므로 전 세계 모든 기기에서 최대한 빠르게 로드되는 매우 빠르고 동적인 콘텐츠를 제공할 수 있습니다.

프레시는 프리액트를 사용하므로 속도가 빠르다는 것을 알 수 있으며, 리액트를 사용하던 사용자도 어렵지 않게 익힐 수 있습니다. 그리고 다시 한번 말씀드리지만, Deno를 기반으로 구축하면 기분이 좋습니다.

프레시는 다음과 같은 경우에 추천합니다.

클라우드에서 전 세계적으로 사용할 수 있는 서버사이드 앱, 최소한의 자바스크립트만 제공하거나 최신 기술을 기반으로 구축하는 것을 좋아합니다.

프레시는 다음과 같은 경우를 대체 가능합니다.

리믹스는 아마도 리액트 세계에서 프레시에 가장 가까운 것일 것입니다.

아스트로(Astro)

아스트로는 정적 이상의 기능을 제공하는 차세대 고성능 정적 사이트 생성기입니다. 아스트로는 이 목록에서 가장 최신 옵션 중 하나이지만 이미 매우 안정적인 1.0 릴리스에 있으며 광범위한 찬사와 채택을 받고 있습니다.

주로 차세대 SSG를 위해 개발되었지만(리액트 팬이라면 주목하세요. JSX와 MDX를 지원합니다), 이제 동적인 서버 측 기능도 제공합니다. 콘텐츠가 많거나 정적인 사이트에는 개츠비보다 더 추천하고 싶습니다.

진짜 킬러 기능은 다음과 같습니다. 아스트로는 기본적으로 자바스크립트를 전혀 제공하지 않습니다. 원하는 기능만 선택해서 사용할 수 있습니다.

또한 아스트로는 사용하려는 프런트엔드 프레임워크와 호환되므로 리액트, 뷰, 스벨트 등으로 템플릿을 제작하고 싶으시다면 가능합니다!

아스트로는 다음과 같은 경우에 추천합니다.

대부분 정적이거나 콘텐츠/마크다운 기반 사이트를 구축하는 경우(일부 서버 측 렌더링이나 로직이 필요할 수도 있음), 최소한의 자바스크립트만 제공하려는 경우, 자체 프런트엔드 프레임워크를 가져오고 싶은 경우.

아스트로는 다음과 같은 경우를 대체 가능합니다.

개츠비 또는 유사한 리액트 기반 콘텐츠 도구.

프리액트

리액트를 사용하시는 분이라면 이미 프리액트에 대해 알고 계시겠지만, 여기서는 언급할 필요가 있습니다. 프리액트는 리액트의 훨씬 더 날렵하고 빠른 버전입니다. 리액트를 대체하는 용도로 시작했지만, 리액트에는 없는 몇 가지 뛰어난 기능(이미 언급한 시그널과 같은)을 추가하기 시작했습니다.

프리액트는 다음과 같은 경우에 추천합니다.

기본적으로 리액트를 고수하고 싶지만 더 빠르기를 원하는 경우.

프리액트는 다음과 같은 경우를 대체 가능합니다.

리액트. (사실, 앞에 P가 추가될 뿐입니다. P는 성능을 의미합니다. 제가 다 지어낸 말이니 프리액트 팀을 탓하지 마세요).

퀵(Qwik)

서버는 하이드레이션과 성능에 대한 새로운 접근 방식으로 리액트와 유사한 코드(JSX)를 렌더링합니다. 실제로는 "하이드레이션"이라고 할 수 없으며, 자바스크립트를 DOM에 직렬화하여 필요할 때만 작은 부분만 로드합니다. 퀵은 이 목록에서 더 심층적으로 다루고 있지만 가능한 한 빨리 실행해야 하는 상호작용이 많은 경우 한번 살펴볼 가치가 있습니다.

퀵은 다음과 같은 경우에 추천합니다.

브라우저에 많은 자바스크립트를 전송하고 있으며, 이를 더욱 효율적으로 처리할 방법을 원합니다.

퀵은 다음과 같은 경우를 대체 가능합니다.

리액트 자체를 대체할 수 있으며, 엣지에서 매우 효율적으로 실행할 수 있습니다.

웹 컴포넌트 라이브러리

솔직히 저는 이 주제에 대해 잘 아는 사람이 아니기 때문에 깊이 들어가지는 않겠습니다. 웹 컴포넌트 자체나 웹 컴포넌트 프레임워크에 대한 경험이 부족하기 때문에 이 주제에 대해 잘 말할 수 없습니다.

그렇긴 하지만, 웹 컴포넌트 프레임워크/라이브러리의 혜택을 받을 수 있는 특정 종류의 프로젝트가 Lit, Stencil, Polymer 등과 같이 존재합니다. 이러한 라이브러리는 특정 프런트엔드 프레임워크에서 "독점적인" 컴포넌트를 생성하는 대신 실제 웹 컴포넌트를 작성하는 데 도움이 되며, 이 컴포넌트는 모든 웹 프로젝트에 이식할 수 있습니다.

제 생각에 대부분의 프로젝트는 여전히 순수 웹 컴포넌트보다 프런트엔드 프레임워크를 사용하는 것이 더 유리합니다. 아니면 최소한 두 가지를 함께 사용하는 것이 더 유리합니다. 앞으로는 상황이 달라질 수도 있겠지만, 현재로서는 대부분의 경우 여전히 순수 웹 컴포넌트 접근 방식에 유리하다고 생각합니다.

하지만 순수한 웹 컴포넌트 기반 접근 방식을 고려해야 하는 사용 사례도 분명히 있습니다. 그리고 그런 프로젝트의 경우 리액트는 확실히 과잉입니다. 위에서 언급한 웹 컴포넌트 라이브러리가 훨씬 더 적합할 것입니다.

웹 컴포넌트 라이브러리는 다음과 같은 경우에 추천합니다.

여러 환경에서 동일한 컴포넌트를 재사용해야 하거나, 프레임워크 변경에 대비해 미래에 대비하고 싶거나, 플랫폼 사용을 선호하고 웹 컴포넌트 작성의 단점을 감당할 준비가 되어 있는 경우.

웹 컴포넌트는 다음과 같은 경우를 대체 가능합니다.

사용 사례에 따라 부분적으로만 리액트를 대체할 수 있습니다.

마치며

이 글은 작년에 제가 쓴 리액트의 자기충족적 예언과 매우 유사합니다. 동일한 영역을 다루고 있으며, (새로운 방식이나 새로운 관점에서 바라보긴 하지만) 동일한 주장을 하고 있습니다.

같은 내용을 반복할 생각은 없었지만, 우연찮게도 이 글이 게시될 무렵에 제가 리액트를 풀타임으로 사용하게 되면서 이 부분에 대해 많이 생각하게 된 것은 분명합니다.

저는 리액트의 인기는 상당 부분 사람들이 그 너머를 보지 않기 때문이라고 믿게 되었습니다. 최고는 아니지만 대부분 사람은 최고를 찾는 것이 아니라 그저 충분히 좋은 것을 찾고 있습니다. (우리는 인간입니다. 우리 모두의 결정에는 개인적이고 감정적이며 비합리적인 이유가 많이 있으며, 그것은 괜찮습니다. 우리는 바쁘니까요.)

적어도 프런트엔드 세계에서는 기술을 선형적으로 도입하기보다는 비약적으로 도입하는 것 같습니다. 모두가 리액트에 뛰어들게 된 이유 중 하나는 당시 모든 사람이 구식 기술에 갇혀 더 나은 것을 찾고 있었기 때문입니다. 우리는 점진적으로 새로운 것을 향해 조금씩 나아가는 것이 아니라(어쩌면 처음부터 그렇게 할 수 없었기 때문일 수도 있습니다), 현재 위치에서 다음 단계로 도약하는 거대한 도약을 했습니다.

선형 선상에, '진보'라고 표시되어 있습니다. 선 위에는 '채택'이라고 표시된 왼쪽에서 오른쪽으로 점프하는 몇 개의 아치형 도약이 있습니다. 그러나 마지막 도약은 직선 '진보'라는 선의 가장 먼 가장자리에 훨씬 못 미칩니다.

하지만 중요한 것은 우리가 몇 년 전 그 도약을 한 이후로 거의 같은 자리에 앉아 있었다는 것입니다.

제 생각에 우리는 또 다른 도약에 가까워지고 있습니다.

그것이 무엇일지, 왜 그럴지는 모르겠습니다. 하지만 그 당시 제이쿼리에서 느꼈던 것처럼 리액트가 실제로 해결하지 못하는 문제들을 느끼기 시작한 것 같습니다. 그리고 결국에는 발전할 때가 되었다는 것이 분명해질 것으로 생각합니다.

그 새로운 것은 무엇일까요? 저도 모르겠어요. 그냥 웹 플랫폼이 될 수도 있습니다. 프레임워크가 필요 없을지도 모르죠. 위의 프레임워크가 될 수도 있고, 우리가 아직 보지 못한 무언가가 될 수도 있습니다. 어쩌면 어떤 것도 없을 수도 있고, 다양한 도구가 등장하고 하나의 표준으로 통합되지 않을 수도 있습니다(위의 모든 옵션 중에서 가능성이 가장 낮은 것으로 보이는 이유는 다시 말하지만, 인간이기 때문입니다. 인간은 바쁜 작은 원숭이이기 때문에 기본값을 좋아합니다.)

하지만 그 새로운 것이 무엇이든, 리액트와 그것의 차이는 시간이 지남에 따라 점점 더 커질 것으로 생각합니다.

그러니 하루하루가 이전보다 더 나은 날이 되어 여러분이 놓치고 있던 것을 탐구할 수 있기를 바랍니다.

들어주셔서 감사합니다.

- +
Skip to content
On this page

리액트로 인해 잊었거나 전혀 몰랐던 것들

원문: Things you forgot (or never knew) because of React

목차

1부: 음악, 기본값, 그리고 버블에 대한 서론

많은 사람들처럼, 저 역시 현지 라디오 방송국에서 흘러나오는 음악만 듣던 시절이 있었습니다. (30세 이상의 많은 사람들이 그랬을 거예요. 이게 아직 공감되지 않는다면, 잠시만 기다려 보세요.) 당시에는, 그것만으로 충분히 행복했습니다. 제게 필요한 모든 것을 갖춘 것 같았으니까요.

돌이켜보면 저는 어리석게도 좋은 것은 결국 인기를 얻게 되고, 알아야 할 가치가 있는 것이라면 저에게 스스로 다가올 것이라고 믿고 있었다는 것을 깨달았습니다.

그러나 결국 다른 음악이 제 인생에 자리 잡기 시작했습니다. 새로운 친구들과 인터넷을 통해 이전에 좋아했던 것들과는 다른 새로운 아티스트들을 알게 되었죠. 제가 이전에는 좋아했던, 아니 적어도 좋아한다고 생각했던 음악에서 점점 멀어지게 되었습니다.

음악은 달랐습니다. 한 주 동안 사랑에 빠졌다가 다음 주에 질리는 일은 없었습니다. 음악을 듣는 것이 끝없는 순환의 일부가 아니었습니다.

오히려 그 반대였어요. 들으면 들을수록 더 좋아하고 감사하게 되는 음악이었죠. 깊이가 있었죠. 물론 그때까지 제가 좋아했던 시끄럽고 왜곡된 기타, 펀치라인 가사, 그럴듯하게 꾸며진 멜로디는 없었지만요. 놀랍게도 그 점이 오히려 노래를 더 좋게 만들었습니다.

그때 저는 제가 생각했던 것만큼 만족스럽지 않았을 수도 있다는 사실을 깨닫기 시작했습니다.

어쩌면 제 행복은 무지를 전제로 한 것일지도 모른다는 생각이 들었습니다.

기본값을 뛰어넘는 풍요로움 찾기

아마도 음악에 한정되지 않더라도 이 이야기에 공감하실 수 있을 것 같습니다.

아마도 한때 좋아하지 않았던 음식이나 음료가 이제는 좋아하는 것 중 하나가 되었을지도 모릅니다. 아니면 예상치 못한 영화, 책, 게임, 팟캐스트, 인플루언서, 취미 등이 자신과 잘 맞는다고 느끼게 된 적이 있을지도 모릅니다.

세부 사항은 중요하지 않습니다. 제가 말하고자 하는 것은

아마도 인기 있는 기본값 주변을 넘어서 뭔가 멋진 것을 발견한 경험이 있으리라는 것입니다.

잘난 척하는 힙스터의 프런트엔드 버전처럼 들리지는 않길 바랍니다. 그런 의도는 아니거든요. 올리브 가든에서 버드 라이트를 마시는 것이 좋은 시간이라고 생각하신다면, 좋아요, 대신 스틱빵은 좀 내놓으세요. (역자 주: 올리브 가든은 미국의 편안하고 저렴한 이탈리안 레스토랑 체인점이고 버드 라이트 역시 가볍게 마시기 좋은 미국의 맥주 브랜드. 스틱빵은 올리브 가든에서 제공하는 빵으로 맛있다고 알려져 있음. 익숙한 것 너머에 더 좋은 것이 있을 수 있다는 것을 말하기 위해 예시로 든 것.)

가 하고자 하는 말은, 여러분이 자신도 모르게 더 좋은 것을 놓치고 있을지도 모른다는 생각을 부드럽게 공유하려는 것입니다.

익숙한 경계를 넘어 더 나은 것을 찾는다는 이 개념은 어쩌면 다른 삶의 영역과 마찬가지로 도구와 워크플로우에도 적용될 수 있습니다.

그리고 아마도, 그저 아마도 당신의 현재 만족감은, 최소한 어느 정도는 단순히 무엇을 놓치고 있는지 모르기 때문에 비롯되는 것일지도 모릅니다.

비유를 완성하고, 그 한계를 인정하기

저는 이전에 '리액트는 프런트엔드 프레임워크의 새로운 기본이다' 라는 글을 쓴 적이 있는데, 리액트를 기본적으로 사용하는 대부분 사람은 이 프레임워크가 얼마나 낙후되어 있는지 잘 인식하지 못한다고 생각합니다.

그리고 여기서부터 우리의 비유에서 미흡한 부분이 보이기 시작합니다.

개인적인 취향에 국한해서 이야기해보면, 당신이 좋아하는 것에 대해 논쟁하거나 당신의 마음을 바꾸려고 블로그 포스트를 쓰지 않을 것입니다. (적어도 지금 이 나이에는) 누가 신경 쓸까요? 재밌게 즐기면 됩니다.

하지만 음악이나 다른 주관적인 즐거움을 위한 것들과 달리, 프런트엔드 도구 선택은 다른 사람들에게 경험적이고 측정할 수 있는 영향을 미칩니다.

이러한 결정에는 진정한 책임이 수반됩니다. 단순히 우리가 좋아하는 것에 대한 것만은 아닙니다. 순전히 우리 자신을 위해 무언가를 만드는 것이 아니라면 개발에서 즐거움은 부차적인 요소이며, 가장 중요한 것은 사용자의 경험입니다.

여러분이 사용하고 있는 도구를 좋아한다면 정말 멋진 일입니다. 저는 그렇기를 바랍니다. 하지만 그것은 기껏해야 부수적인 임무일 뿐이며, 최악의 경우 잠재적으로 해로운 방해 요소가 될 수 있습니다. 개발자 경험(DX)이 사용자 경험(UX)을 대체해서는 안 됩니다.

그러니 어설픈 비유를 선택한 것을 용서해 주세요. 원한다면 평생 같은 음악을 계속 들을 수도 있습니다. 저도 그렇게 생각합니다. 하지만 우리가 사용하는 도구에 있어서는 기존의 편안함을 뛰어넘어야 할 매우 타당하고 중요한 이유가 있습니다.

리액트 거품

리액트가 경쟁자들보다 뒤떨어진다는 생각은 생소할 수 있습니다. 많은 분처럼 여러분도 여전히 리액트가 프런트엔드에서 최신 표준이라고 생각할 수 있습니다. 따라서 본격적으로 목록으로 들어가기 전에 그 거품을 빠르게 파헤쳐 보겠습니다.

이 글을 쓰게 된 계기는 Alex Russell이 Mastodon에 쓴 글 때문입니다.

누군가 오늘 저에게 IE를 지원하지 않아도 되는 새로운 앱에서 리액트를 사용하는 이유가 있는지 물어왔습니다.

저는 단 하나의 이유도 생각해 낼 수 없었습니다...

리액트가 얼마나 구식이 되었는지 아주 놀라웠습니다.

Alex는 해당 스레드에서 웹 컴포넌트에 대한 리액트의 지원 부족을 언급했습니다. 이 기능은 수년 동안 리액트에서 눈에 띄게 누락되어 왔습니다. 그리고 네, "로드맵에 추가될 예정"이라고 합니다. 하지만 이 글을 쓰는 현재로서는 구현이나 예상 출시일에 대한 확고한 약속은 없습니다.

한편, 리액트 대신 선택할 수 있는 거의 모든 프레임워크나 기술에는 이미 해당 지원이 출시되어 프로덕션에 사용되고 있습니다.

웹 컴포넌트는 그중 하나일 뿐입니다. 하지만 웹 컴포넌트는 "다른 모든 것이 이미 하고 있거나 더 잘하는 것"의 목록에 있는 유일한 항목은 아닙니다. (아래에서 몇 가지를 더 다룰 것입니다.)

리액트는 프레임워크 게임 초창기부터 표준을 정립한 덕분에 큰 혜택을 누렸습니다. 하지만 유연성과 적응성에서 심각한 단점을 수반했습니다. 2013년경에 시작된 이래로 리액트가 내린 모든 결정은 또 다른 기술 부채를 안고 있으며, 이는 동시대 동종 업계에서는 찾아볼 수 없는 문제입니다.

Alex의 말을 다시 한번 인용하자면

리액트는 2008년 제약 조건에 맞춰 설계된 13년 기술입니다. 2023년에는 혁신적인 것은 아무것도 없습니다. 사실, 현대에 기능적인 반응형 프런트엔드 프로그래밍을 하는 데 가장 느린 방법입니다...

리액트는 노후화되었고, 대부분 사람이 얼마나 많이 또는 얼마나 열악한지 깨닫지 못하는 것 같습니다. 위의 인용문을 다른 방식으로 표현하자면 (그리고 음악에 대한 서문과 다시 연결해 보겠습니다.)

리액트는 존 메이어와 제니퍼 애니스톤이 아직 사귀고 있을 때, 테일러 스위프트의 일곱 장의 앨범이 나온 시절에 설계되었습니다.

(테일러 스위프트의 새 일곱 번째 앨범 출시 전이죠. Taylor's Version 발매를 포함하지 않습니다.)

따라서 당신이 지난 몇 년 동안 리액트를 사용해 온 많은 개발자 중 한 명이라면, 오랫동안 리액트를 사용해 왔기 때문에 잊어 버렸거나 전혀 몰랐던 것들이 있을 수 있습니다.

최신 프런트엔드가 빠르게 발전하는 만큼, 리액트를 왕좌에 올려놓았던 세상이 여러 면에서 더 이상 존재하지 않는다는 사실을 깨닫는 데는 매우 느린 것 같습니다. (그랬던 적이 있다면, 애초에 페이스북의 특정 문제와 유사한 문제를 가진 조직은 많지 않았습니다).

지난 10년 동안, 웹 브라우저는 자바스크립트와 CSS에서 놀라운 성장을 보여주며 새로운 기능들을 채택해 왔습니다. 기술과 사용자의 기대도 발전했고, 현재의 도구 생태계는 예상보다 훨씬 더 많이 반복하고 적응하며 리액트를 넘어선 발전을 이루었습니다. 그러한 발전은 기존의 소프트웨어로는 따라갈 수 없는 방식으로 이루어졌습니다.

참고 사항

리액트를 "레거시 소프트웨어"라고 부르는 것이 논란의 여지가 있다는 것을 알고 있지만, 이는 공정하다고 생각합니다. 비교적 복잡하고, 비교적 오래되었으며, 많은 규칙과 문제점을 포함하고 있고, 초보자는 종종 두려워하며, 리액트가 기반으로 하는 아키텍처 결정은 반복 능력에 방해가 되는 요소가 된 지 오래되었습니다.

이 시점에서 제가 아직 여러분을 완전히 소외시키지 않았다면(일종의 엘리트주의, 장황한 서론, 괄호 내용의 과도한 사용의 조합으로 인해), 여러분이 완전히 리액트 세계에만 집중하느라 놓쳤을지도 모르는 몇 가지를 공유하고 싶습니다. 여러분의 현재 재생 목록에 있는 것보다 더 좋다고 느낄 수 있는 곡들을 발견하게 될지도 모른다는 희망으로요.

2부: 리액트 때문에 잊고 있었던(혹은 전혀 몰랐던) 것들

더 이상 생태계가 거대할 필요가 없습니다(이제 공유할 수 있기 때문입니다)

다른 글에서도 언급했지만, "검증되지 않은" 프레임워크의 이름이 개발 프로젝트의 잠재적 도구로 떠오를 때마다 사람들이 가장 먼저 궁금해하는 것은 다음과 같은 질문입니다. 생태계가 얼마나 큰가?

이 글의 전제를 읽자마자 그런 생각을 하셨을 수도 있습니다. 리액트에서 다른 프레임워크로 옮길까? 아직 충분히 큰 프레임워크가 있을까?

왜 우리는 생태계 규모에 집착하는 걸까요?

물론 우리는 이 프레임워크가 몇 년 안에 사라지거나 유지보수가 중단되지 않을 것이라는 확신을 두고 싶습니다. 충분히 그럴 만합니다. 그리고 네, 저희는 너무 새롭거나 검증되지 않은 것에 모든 것을 걸진 않을 것입니다. 하지만 , 스벨트, 프리액트, 솔리드, 아스트로 등은 모두 그 시점을 훌쩍 지났으며 잘 지원되고 유지되고 있습니다. 따라서 단순히 그것 때문만은 아닙니다.

그렇다면 진짜 문제는 무엇일까요? 제 생각에는

패키지가 우리의 프레임워크를 위해 구축되어야 한다고 훈련받았기 때문입니다.

이러한 사고방식은 제이쿼리에서 시작되었다고 볼 수 있지만, 리액트가 이를 가속했다고 생각합니다.

리액트를 사용하면 캐러셀, 지도, 아코디언 등 특정 작업을 수행하기 위해 모듈이나 위젯, 라이브러리가 필요할 때마다 반드시 리액트로 만들어야 했고, 일반 웹이나 자바스크립트는 사용할 수 없었습니다. 리액트의 모든 규칙과 상태 처리, 컴포넌트 라이프사이클의 특이점 때문에 리액트용으로 명시적으로 작성되지 않은 패키지나 라이브러리는 작동하지 않을 가능성이 높았습니다.

리액트는 특정 프레임워크에 맞춰 빌드해야 한다고 가르쳐주었습니다. 그러나 그것은 더 이상 사실이 아니며, 틀림없이 그렇게 되어서는 안 됩니다.

특히 "자바스크립트일 뿐"이라고 자주 주장하는 프레임워크의 경우, 그렇게 할 필요가 없습니다. 단지 자바스크립트라면 실제로 자바스크립트인 모든 것에서 그냥 작동해야 합니다.

물론 다른 프런트엔드 프레임워크에도 상태와 아키텍처에 대한 자체 규칙과 관습이 있습니다. 비유적으로, 그들의 마당에 있는 갈퀴를 밟을 수도 있습니다.(역자주: 다른 프레임워크에서도 비슷한 문제가 발생할 수 있다는 뜻) 그리고 스벨트나 뷰 또는 그 밖의 다른 프레임워크와 함께 작동하도록 특별히 구축된 것들은 항상 존재할 것이고, 또 그래야만 합니다.

하지만 결정적으로, 그리고 가능한 한 강력하게 강조하고 싶습니다.

리액트만큼 플랫폼과 고집스럽게 호환되지 않는 최신 프런트엔드 프레임워크는 없습니다.

다른 현대적인 도구와 프레임워크를 사용하여 빌드하는 경우, 바닐라 자바스크립트 패키지가 잘 작동할 가능성이 훨씬 더 높으며, 그 패키지는 수천 개가 넘습니다. 렌더링 주기나 기타 프레임워크 관련 문제를 일으킬 가능성도 훨씬 적습니다. 말할 것도 없이, 이들 모두 웹 컴포넌트를 사용할 수 있는 옵션도 있습니다.

특별히 제작된 패키지나 라이브러리가 필요하지 않은 경우가 많습니다. 왜냐하면 당신의 것은 이미 플랫폼과 호환이 되기 때문이며, 따라서 이미 존재하는 모든 것과 호환됩니다.

프리액트 시그널은 프리액트와 함께 사용하도록 만들어졌지만, 어떤 프레임워크나 심지어 바닐라 자바스크립트에서도 가져와서 사용할 수 있는 놀라운 예입니다. 웹 컴포넌트 역시 리액트가 아닌 거의 모든 최신 프레임워크와 호환됩니다.

프레임워크에 부족한 부분이 있다면 플랫폼에 이미 필요한 기능이 있을 가능성이 높습니다. (예를 들어, 폼 제출의 경우, 리액트에서 항상 골칫거리였지만 이제 양방향 데이터 바인딩과 브라우저에서 제공하는 규칙을 사용하면 무한히 쉬워졌습니다.)

그리고 최악의 경우, 필요한 것을 만드는 것이 리액트에서보다 훨씬 더 쉬워질 수도 있습니다. (useState를 다른 프레임워크의 버전과 비교해 보면 알 수 있습니다.)

새로운 프레임워크는 매우 보수적인 개발자들에게 단점으로 여겨지곤 하는데, 그들은 모든 면에서 철저하게 검증되지 않은 것을 시도해 보기를 경계하기 때문입니다. 하지만 기술 부채와 오래된 브라우저 지원에 대해 걱정할 필요가 적고, 기존의 좋은 아이디어와 최신 브라우저 기능을 더 자유롭게 반복할 수 있다는 점에서, 새롭다는 것은 오히려 '장점'이라는 것을 기억해야 합니다.

리액트 훅은 사실 구식입니다

훅은 리액트의 최신 진화 단계로, 클래스 컴포넌트를 대체했습니다.

정당하게 칭찬할 부분에는 칭찬을 하겠습니다. 훅은 프런트엔드 영역에서 엄청난 전환점이었습니다. 이것은 우리 애플리케이션에서 로직과 상태를 구성하는 방법을 혁명적으로 바꿨습니다. 훅은 부인할 수 없을 만큼 훌륭하며, 거의 모든 프레임워크가 상태 관리를 위한 훅과 유사한 모델을 고수하게 되었습니다.

하지만 리액트 훅은 더 이상 새로운 것이 아닙니다. (사실, 훅을 사용하는 안정적인 리액트는 제 아이와 거의 같은 나이이고 몇 주 후에 유치원에 입학합니다.)

훅은 더 이상 경쟁 우위나 주목할 만한 기능이 아니라 기본입니다. 그저 우리가 일을 하는 방식일 뿐입니다.

다른 모든 프레임워크는 자체적으로 훅을 구현할 뿐만 아니라, 주목할 만한 점은 모든 프레임워크가 더 빠르고, 더 똑똑하고, 더 쓰기 쉬우며, 또는 이 세 가지가 모두 결합되어 있다는 것입니다.

프리액트의 시그널은 여기서 언급할 가치가 있으며, 스벨트의 매우 단순한 스토어도 마찬가지입니다. 솔리드에도 시그널이 있습니다. 심지어 훅에서 직접적으로 영감을 받은 뷰 3의 컴포지션 API도 리액트 구현에 비해 몇 가지 주요 이점이 있습니다.

훅은 훌륭한 패턴이며, 리액트는 이를 대중화시킨 공로를 인정받아 마땅합니다. 하지만 거의 모든 다른 프레임워크가 더 적은 규칙과 보일러 플레이트 없이 훅을 더 잘 수행합니다.

참고 사항

시그널의 개념이 익숙하지 않으시다면, 지나치게 단순화시킨 표현이지만, 반응형 상태의 한 단계 더 나은 진화, 즉 전체 컴포넌트가 아니라 다시 렌더링할 필요가 있는 노드만 다시 렌더링하도록 기본값을 개선한 업데이트된 훅이라고 생각하시면 됩니다.

더 이상 렌더링을 세부적으로 관리할 필요가 없습니다

고백할 게 있습니다. 저는 useMemouseCallback의 차이점이 무엇인지, 언제 사용해야 하고 사용하지 말아야 하는지 아직 정확히 알지 못합니다. 말 그대로 오늘 오전에 바로 이 주제에 대한 글을 여러 개 읽었음에도 불구하고요. (농담이 아닙니다.)

두 번째 고백하자면, useEffect 의존성 배열에 들어가야 하는 것과 들어가서는 안 되는 것, 또는 그 이유가 여전히 직관적이지 않다는 것입니다. 저는 useEffect 호출을 작성할 때마다 린터가 좋아하는 모양으로 코드를 리팩터링하는 데 15분 정도를 소비하는 것 같은 느낌이 드는데, 실제로는 괜찮고 앱을 무한한 심연으로 빨아들이지 않을 것이라고 99% 확신하는 경우에도 마찬가지입니다.

리액트를 사용하신다면 아마 이런 고백에 공감하실 수 있을 겁니다. 어쩌면 이런 혼란과 모호함을 당연한 것으로 받아들였을지도 모릅니다. 하지만 그렇다면 한 가지 알아두세요.

다른 프레임워크에서는 이런 종류의 렌더링 사이클 미세 관리를 수년 동안 하지 않아도 되었습니다.

요즘 프레임워크는 사용자가 직접 손을 잡고 설명하지 않아도 이런 종류의 작업을 처리할 수 있을 만큼 똑똑합니다.

프레임워크는 실제로 필요하지 않은 리렌더링에 귀중한 자원을 낭비하지 않도록 이미 상황을 알고 있습니다. 그들은 필요하지 않은 것을 지속해 재평가하지 않고 값만 업데이트할 수 있을 만큼 똑똑합니다.

...대부분의 경우에 그렇습니다. 그들도 완벽하지는 않습니다. 하지만 무엇을 해야 하는지 알고, 기본적으로 성능 좋은 방식으로 수행하는 데는 리액트보다 훨씬 낫습니다.

다른 프레임워크에서도 몇 가지를 최적화해야 할 수도 있습니다. 완벽하지는 않습니다. 하지만 그렇게 할 때쯤이면 리액트에서 해야 했던 지점을 훨씬, 훨씬 지나고 있을 것입니다.

프레임워크의 useEffect 버전을 두려워하는 사람은 아무도 없습니다

컴포넌트가 DOM에 들어갈 때 무언가를 수행하게 하고 싶거나, 다른 데이터나 변수를 기반으로 동적으로 무언가를 다시 계산하기를 원할 때 거의 모든 다른 프레임워크는 useEffect보다 더 나은 방법을 가지고 있습니다.

여기서 너무 길게 설명할 필요는 없을 것 같습니다. React 커뮤니티 내에서도 useEffect는 악명 높은 위험한 것으로 간주하며 심지어는 아예 피하는 경우도 많기 때문입니다. 하지만 저를 믿으세요. React 기반이 아닌 다른 어떤 프런트엔드 프레임워크도 이렇게 정상적이고 유용한 기능을 사용하는 것을 두려워하지 않으며, 그 어느 곳에도 이와 같은 모호한 규칙은 없습니다.

컴포넌트가 마운트될 때 무언가를 하기 위해 서드파티 패키지를 살펴보는 사람은 아무도 없습니다.

확장성은 더 이상 프런트엔드의 문제가 아닙니다

이것은 사람들이 새로운 (리액트가 아닌) 프레임워크가 등장할 때 즉시 묻는 또 다른 질문입니다. 확장성이 있을까요? 하지만 저는 이 질문이 약간 시대에 뒤떨어진 질문이라고 생각합니다.

기억할 가치가 있는 것은 리액트를 탄생시킨 세계에는 다른 문제들이 있었다는 것입니다.

당시에는 대부분의 프런트엔드 UI가 바닐라 자바스크립트나 제이쿼리(또는 이와 유사한 대안)로 빌드되었습니다. 그리고 지금 우리가 알고 있듯이 이러한 앱 구축 방식은 특정 한계를 넘어서는 확장이 불가능했습니다.

그 이유는 상호작용하고자 하는 모든 요소와 DOM 노드에 대해 직접 선택자를 작성해야 했고, 상태를 추적하고 동기화하는 방법을 직접 수동으로 만들어야 했기 때문입니다. 이 작업에는 보통 DOM을 읽고 쓰는 작업이 포함되는데, 이 작업은 지저분하고 오류가 발생하기 쉬우며 무엇보다도 속도가 느렸습니다. (그래서 가상 DOM이 등장했지만, 그것조차도 몇 년 동안 완전히 구식이 되었습니다.)

당시에는 모듈식 코드를 작성하는 것이 불가능에 가까울 정도로 어려웠고, JS 파일은 수천 줄은 아니더라도 수백 줄로 늘어나는 경우가 많았습니다. 여러 작성자가 같은 프로젝트에서 작업하는 경우 서로의 코드를 재창조하거나 반복하거나 심지어 재정의하는 경우가 많았습니다(코드가 공유 글로벌 네임스페이스에 들어가는 경우가 많았기 때문에 충돌 가능성이 훨씬 더 높았습니다). 그리고 앱의 규모가 크거나 복잡할수록(Facebook) 문제는 더욱 심각해졌습니다.

기억해야 할 것은 다음과 같습니다. 앱이 기하급수적으로 성장하더라도 합리적으로 유지 관리가 가능한가? 이것이 프런트엔드와 관련하여 "확장성이 있는가?" 를 기준이라는 점입니다.

프런트엔드 프레임워크가 확장되지 않을 수 있다는 우려는 제이쿼리만큼이나 오래되었으며, 최신 웹 개발과 관련해서는 구시대적인 것으로 간주하여야 합니다.

리액트는 이러한 문제 중 많은 부분을 해결했습니다. 하지만 현대 공학의 기적이라기보다는 단순히 상태를 관리 및 공유하고, 데이터를 반응형으로 만들고, 복잡성을 추상화하며, 충돌, 네임스페이스 충돌, 재정의 없이 개발자가 동일한 프로그래밍 패턴을 공유할 수 있는 좋은 방법을 고안해 해냈습니다.

리액트는 프런트엔드 확장성을 위한 최고의, 유일한, 심지어 '최초의' 솔루션이 아니라 동일한 패러다임의 여러 버전 중 하나일 뿐입니다.

(또한 가장 오래된 버전 중 하나이기도 합니다.)

이를 어떻게 알 수 있을까요? 리액트의 성능을 다른 모든 프런트엔드 프레임워크와 대규모로 비교하는 수많은 벤치마크 테스트가 실행되어 그 결과가 공개되어 있습니다. (온라인에서 쉽게 구할 수 있기 때문에 여기서는 링크하지 않습니다.) 이 모든 테스트는 프런트엔드 분야의 거의 모든 다른 옵션이 리액트와 동등하거나 더 나은 성능을 발휘하며, 많은 경우 훨씬 더 나은 성능을 발휘한다는 것을 확인시켜 줍니다.

참고 사항

여기서는 앱의 크기가 커짐에 따라 복잡성이 선형적으로 증가하지 않고 최소한으로 유지되도록 하는 일반적인 의미의 확장을 언급하고 있습니다. 물론 일부 프레임워크는 마크다운 파일에서 정적 HTML을 빌드하는 것과 같은 더 전문화된 작업 측면에서 훨씬 더 나쁘거나 좋게 확장될 수 있습니다.

서버 사이드 렌더링은 더 이상 특별하지 않습니다

몇 년 전, 서버 렌더링 콘텐츠(주로 Next.js를 통해)에 관한 한 리액트가 거의 유일한 해결책이었던 시절이 있었습니다. 사람들은 리액트를 클라이언트가 아닌 서버에서 단일 페이지 앱(SPA)으로 HTML로 렌더링할 수 있다는 사실에 당연히 흥분했습니다. 속도와 SEO 개선 효과는 무시할 수 없었고, 처음에는 다른 프레임워크가 따라잡는 데 다소 시간이 걸렸습니다.

하지만 일반적으로, 특히 이 글의 주제와 마찬가지로 가장 먼저 개선을 시작하는 것이 최고인 경우는 거의 없습니다.

스벨트키트는 사용자가 아무것도 할 필요 없이 기본적으로 서버 렌더링되며, 렌더링 패턴을 세밀하게 제어할 수 있습니다. 뷰의 메타 프레임워크인 Nuxt는 게임에 더 일찍 참여했습니다(Next.js에서 영감을 받은 것이 분명합니다).

프레시(Deno의 프런트엔드 프레임워크)는 "아일랜드"(클라이언트 렌더링)로 지정한 것을 제외하고는 전적으로 서버 렌더링이며, 그 외에는 정적 HTML로만 제공됩니다. 프레시는 또한 프리액트를 사용합니다(이 역시 리액트보다 훨씬 빠르며, 훨씬 더 성능이 좋고 인체공학적인 버전의 useState와 반응성 모델인 시그널를 가지고 있습니다.).

아스트로는 서버 렌더링 기능을 가지고 있으며, 원하는 컴포넌트를 서버 렌더링할 수 있습니다. 다른 프레임워크의 컴포넌트도 잘 렌더링할 수 있으며, 경우에 따라서는 Next.js의 주요 성능 업그레이드로 주목받기도 했습니다.

솔리드스타트(솔리드의 메타 프레임워크)에는 서버 렌더링이 있습니다. 퀵은 전적으로 이 프레임워크를 중심으로 구축되었습니다. EmberAngular와 같은 오래된 프레임워크도 스토리가 있으며, 다른 프레임워크들도 있을 것이라 확신합니다.

요점은 과거에 리액트는 클라이언트 뷰 프레임워크 컴포넌트를 서버에서 렌더링하는 개념을 가진 몇 안 되는 프레임워크 중 하나였다는 것입니다. 하지만 지금은 서버 렌더링이 필수입니다. 많은 최신 프레임워크는 서버에서 렌더링할 수 있는 옵션을 제공할 뿐 아니라 기본값으로 렌더링합니다.

PHP가 돌아왔습니다.

양방향 데이터 바인딩은 어렵지 않고 나쁜 생각도 아닙니다

리액트는 페이스북이 페이스북 고유의 문제를 해결하기 위해 만들었다는 점을 기억하는 것이 중요하다고 생각합니다.

데이터는 한 방향(하향식)으로만 흘러야 한다는 리액트의 강력한 의견 중 하나는 2010년대 초에 Facebook이 직면했던 엔지니어링 도전이 어떻게 리액트의 아키텍처를 형성했는지를 보여주는 좋은 예입니다.

한동안은 단방향 데이터 흐름이 모범 사례로 간주하는 것처럼 보였습니다. 하지만 요즘에는 양방향 데이터 바인딩의 함정에 대한 해결책을 대부분 찾아냈고, 많은 경우 이것이 실제로 훨씬 더 편리하다는 것을 알게 되었습니다.

리액트에서 폼을 작업하는 것은 악명이 높습니다. 이는 사용자의 모든 키 입력이 두 단계 과정을 거치기 때문입니다. 입력에서 값을 얻어온 다음, 그 값을 상태에 설정해야 합니다(이에 따라 입력이 불필요하게 다시 렌더링되며 이미 있던 정확한 값을 포함하게 되지만 리액트 상태와 동기화됩니다.). 물론 보통은 너무 빨라서 눈치채지 못하지만, 추가 작업이 많이 필요합니다.

스벨트, 뷰 등 다른 많은 자바스크립트에서는 이 문제가 없습니다. 상태를 양방향으로 자동 업데이트되도록 바인딩할 수 있습니다. 상태가 변경되면 DOM이 업데이트되고, DOM이 변경되면 상태가 업데이트됩니다.

이렇게 하면 여러 단계를 거칠 필요가 없습니다. 예를 들어 텍스트 상자의 값만 캡처하려는 경우 양방향 데이터 바인딩을 수행하면 됩니다. 그러면 사용자가 필드에 입력하면 데이터가 자동으로 업데이트되므로 추가 단계 없이 적절한 시점에 데이터를 가져올 수 있습니다. 그 사이에 값을 설정하거나 필드를 지우는 등의 작업을 수행해야 하는 경우에도 한 줄로 간단하게 처리할 수 있습니다.

양방향 데이터 바인딩을 사용하면 한쪽이 다른 쪽을 따라잡고 있는지 계속 확인할 필요 없이 데이터와 DOM을 동기화 상태로 유지할 수 있습니다.

이 기능을 사용하면 문제가 발생할 수 있나요? 물론 그럴 수 있습니다. 하지만 모범 사례에 대한 독단적인 이상은 도움이 되기보다는 오히려 방해가 될 수 있습니다. 단방향 데이터 흐름이 대표적인 예입니다.

스타일링은 사실 쉽습니다

리액트로 주로 작업한다면 프런트엔드 컴포넌트에서 스타일을 처리하는 과정을 두 번, 세 번, 혹은 그 이상 반복했을 가능성이 높습니다.

.css 파일을 JSX 컴포넌트로 바로 가져왔을 수도 있고, CSS 모듈, 스타일 컴포넌트 및/또는 테일윈드를 사용했을 수도 있습니다(아마도 classnames 또는 tailwind-merge 패키지와 함께, 또는 둘 다와 추가 테일윈드 애드온을 함께 사용했을 수도 있습니다). 그리고 이것들은 가장 인기 있는 옵션일 뿐입니다.

테일윈드는 그 자체로 토끼굴입니다(그리고 그 자체로 프런트엔드 프레임워크로 제가 특별히 좋아하지 않습니다. 저는 플랫폼의 결에 반하는 것은 단기적인 이득을 얻는 대신 결국 장기적인 손실로 이어진다고 생각합니다.) 하지만 어쨌든 이러한 스타일링 솔루션이 존재하고 상당수 채택된 것은 적어도 부분적으로는 리액트가 처음 출시될 때부터 공식 스타일링 옵션이 없는 공백이 있었기 때문입니다.

스타일링이 다른 여러 프레임워크에서 해결된 문제라는 사실을 모를 수도 있습니다.

특히 뷰와 스벨트는 모두 자체적인 컴포넌트 스타일링 스토리를 가지고 있습니다. 둘 다 컴포넌트 수준 스코핑을 지원합니다(뷰는 참여 동의(opt-in) 방식이고, 스벨트에서는 참여 철회(opt-out) 방식입니다.). 둘 다 바닐라 CSS와 훌륭하게 작동합니다(원하는 방식이라면). 하지만 다른 모든 프런트엔드 프레임워크와 마찬가지로 이 두 프레임워크는 CSS 모듈, 테일윈드, Sass 또는 기타 사용하고자 하는 다른 프레임워크와도 호환됩니다.

하지만 가장 중요한 점은 CSS의 모든 문제(실제로 문제라고 생각하든 그렇지 않든)가 내장된 스타일 처리 기능으로 완벽하게 해결된다는 점입니다. 범위 지정 CSS는 상상할 수 있는 거의 모든 문제를 해결하기 때문에 다른 곳에서처럼 복잡한 패키지와 설정이 필요하지 않습니다.

CSS가 나쁘다는 이유 목록을 읽어보세요(실제로는 그렇지 않지만, CSS를 잘 모르는 사람들은 그렇게 말하길 좋아합니다). CSS에 대한 거의 모든 비판은 범위 지정 스타일링으로 해결되며, 여러 비(非)반응형 프레임워크에 이미 이 기능이 내장되어 있습니다.

프레임워크는 더 이상 배우기 어렵지 않습니다

저는 리액트를 주로 교육받은 개발자들이 배우기가 얼마나 어려웠는지 되돌아보고 다른 프레임워크의 학습 곡선도 비슷하게 평가할 것으로 생각합니다. 아마 그것이 우리가 새로운 시도를 하지 못하게 하는 이유 중 하나일 것입니다. 왜냐하면 처음이었기 때문에 정말 어려웠기 때문입니다.

상태 관리, 프로퍼티, 중첩, 컴포넌트 수명 주기, 훅, 그리고 물론 JSX를 작성하는 방법까지... 정말 많은 것들이 있습니다. 아무리 열렬한 리액트 팬이라도 초보자가 빠르게 익히기가 쉽지 않다는 것을 인정할 것입니다. (그렇지 않다고 말하는 사람은 아마 초보자였을 때를 잊어버린 사람일 것입니다.)

공감하실 수 있다면 좋은 소식이 있습니다.

리액트만큼 배우기 어려운 도구는 없습니다. 하지만 일단 하나의 프레임워크를 알게 되면 다른 모든 프레임워크에서 큰 도움이 됩니다.

저는 이것을 두 번째 악기를 배우는 것에 비유합니다 (음악에 다시 연결하기 위해서가 아니라). 처음 연주를 배울 때는 특정 악기를 배우는 것 외에도 음악에 대한 모든 것을 배우고, 악기로 원하는 소리를 내는 방법을 배우게 됩니다. 하지만 두 번째 악기를 배울 때는 많은 부분을 건너뛸 수 있습니다. 모든 개념이 익숙해집니다. 음악을 이해하니까요. 여러분이 해야 할 일은 기존의 지식과 근육 기억을 약간 다른 형태로 옮기는 것뿐입니다.

프런트엔드도 비슷합니다. 모든 프런트엔드 프레임워크에는 컴포넌트가 있고, 모두 타입스크립트와 호환되며, 모두 프로퍼티, 자식, 반응 상태라는 개념이 있습니다. 이러한 것들은 우리가 일반적으로 좋아하고 좋다고 동의한 것들입니다. 다만 구현 방식이 다를 뿐입니다.

말하자면, 리액트는 의심할 여지 없이 이러한 아이디어를 확산하는 데 도움이 되었지만, 리액트가 이러한 아이디어를 이상적으로 구현하는 것으로 생각하는 것은 어리석은 일입니다.

훌륭한 것은 반복을 통해 만들어지며, 대부분의 경우 나중에 나온 프런트엔드 영역의 다른 선택은 리액트의 핵심 아이디어를 기반으로 발전한다는 뚜렷한 이점을 가지고 있습니다.

즉, 리액트는 main보다 한참 뒤처진 git 브랜치와 비슷합니다. 리액트가 당신 은하계를 공전하는 별이라면 깨닫지 못할 수도 있지만... 프런트엔드는 이미 발전했습니다. 생태계는 이러한 아이디어를 받아들여 더 나은 것을 만들기 위해 달려왔습니다.

이제 더 성능이 뛰어나고 덜 복잡하며 배우기 어려운 옵션이 넘쳐납니다. 그리고 이미 리액트를 알고 있다면 그 어떤 것도 배우기 어렵지 않을 것입니다.

참고

다음 두 섹션은 게시물의 초안에는 포함되어 있지 않았으며, 2023년 8월 15일에 원본 버전에 대한 피드백을 해결하기 위해 추가되었습니다.

"새롭고 빛나는 것"만이 전부가 아닙니다 (그리고 아무도 그것에 대해 신경 쓰지 않습니다)

이러한 주제를 논할 때 자주 듣는 말은 대략 다음과 같습니다.

항상 새롭고 빛나는 것만 쫓는 멍청한 자바스크립트 개발자들! 그들은 프로젝트를 장기적으로 유지하는 데는 관심이 없어. 새롭고 멋진 프레임워크는 내일이면 잊히고 코드가 실행되지도 않을 거라고!

여기에 조금의 진실이 있습니다. 사실, 자바스크립트 개발자들(감히 말하자면 보통의 프런트엔드 개발자들)은 다른 프로그래밍 전문가들이 경계하는 것에 비해 조금 더 새로운 것에 끌리는 경향이 있는 것 같습니다.

...그런데 실제로는 얼마나 사실일까요? 전 세계 모든 자바스크립트 개발자가 새로운 것이 나타나는 순간 그들의 기술 스택 전체를 다시 작성하러 나설 것이라 확신하나요? 아니면 끊임없는 온라인 유행 흐름에 의해 양산되어 그렇게 느껴지는 것일까요?

저는 이 현상이 실제보다 더 과장돼 보이는 것이라고 생각합니다. 왜냐하면 얼리 어답터들은 모든 주목을 받는 경향이 있기 때문입니다. 그들은 많은 블로그 게시물을 작성하고 동영상을 제작합니다. 이것들이 공유되고 회자되면서 실제보다 훨씬 더 많은 종류의 행동이 일어나고 있는 것처럼 보이는 경향이 있기 때문에 실제보다 훨씬 더 과장되어 보이는 것 같습니다. (이 말이 절반만이라도 사실이라면 리액트의 시장 점유율은 지금보다 훨씬 낮아졌을 것입니다.)

제가 만난 대부분의 프런트엔드 개발자들은 다른 종류의 개발자들과 마찬가지로 자신이 알고 있는 것을 고수합니다. 단지 새로운 것을 시도하는 데 비용이 상대적으로 덜 들기 때문에 그렇게 한다고 생각합니다.

하지만 이러한 관점은 현장에서 사용할 수 있는 다른 선택지의 성숙도를 과소평가하는 것입니다.

뷰는 리액트만큼이나 오래 사용되어 왔으며 현재 버전(v3)은 거의 3년 전에 출시되었습니다. 최신 버전의 스벨트는 리액트 훅이 출시된 지 2개월 후에 출시되었으며(2개월 전에 리액트 훅이 새롭고 반짝이는 것이라고 생각하셨나요?), 스벨트키트는 거의 1년 전에 1.0을 출시했습니다. 프리액트는 버전 10에 있습니다. 솔리드는 2년이 넘도록 1.0+ 버전입니다. 아스트로는 1년 전에 1.0을 출시했습니다. 여기서 언급할 퀵과 프레시는 가장 최근에 출시되었지만 올해 초 기준으로 모두 1.0 버전입니다.

따라서 이러한 항목 중 일부가 아직 너무 새롭더라도 괜찮습니다. 이해합니다. 하지만 리액트 대안에 대한 고려를 짧은 기간 때문에 축소시키는 것은 이 분야의 성숙도와 깊이를 간과하는 잘못된 판단입니다.

리액트는 성능면에서 뒤처져 있습니다

이 주제에 대해서는 이미 많은 글이 있기 때문에 너무 길게 설명하지는 않겠습니다(제가 쓴 다른 글에도 있고, 온라인에서 쉽게 찾을 수 있습니다). 하지만 간단히 말하자면 리액트는 미미할 정도로만 느리게 느껴질 수 있지만(특히 매우 고급/최신 하드웨어와 매우 빠른 인터넷 연결을 사용하고 있다면 더욱 그렇습니다), 그 차이는 사소한 것이 아닙니다.

리액트는 성능(번들 크기와 실행 속도를 모두 의미합니다) 측면에서 많은 경우 2배 이상 뒤쳐집니다. (번들 자체는 10배 이상 차이가 날 수도 있습니다.) 최근 실행된 JS 웹 프레임워크 벤치마크에 따르면 리액트의 성능은 평균적으로 솔리드보다 거의 50%, 뷰보다 25%, 스벨트보다 40%, 프리액트보다 35% 느린 것으로 나타났습니다. (이 테스트에서는 다른 프레임워크가 사용되지 않았습니다.)

참고 사항

이 비교는 useTransition 훅과 리덕스와 같은 추가 라이브러리를 사용하지 않고 리액트 훅만 사용했을 때였습니다.

다른 연구도 있습니다. 연구마다 수치가 조금씩 다를 것이고, 연구 결과에는 항상 미묘한 차이가 있을 것입니다. 하지만,

어떤 결과를 참고하든 리액트는 그 이후 나온 거의 모든 결과보다 더 크고 느립니다.

실제 사례를 통해 설명하자면, 저는 안드로이드 폰에서 작성하는 폼에 리액트가 사용된다면 그걸 알 수 있습니다. 느린 속도와 상태와 일치하도록 DOM을 업데이트하는 루프가 반복되기 때문입니다. 그리고 리액트가 아니면 눈치채기가 힘듭니다.

하지만 사례는 잊어버리세요. 방금 데이터를 봤으니까요. 그리고 이 수치가 크게 느껴지지 않을 수도 있고, 기술 스택을 선택할 때 성능은 여러 고려 사항 중 하나일 뿐이라는 것을 알고 있습니다. "모든 것은 상황에 따라 다릅니다."

하지만 25 ~ 50%의 성능 개선은 성능 향상 측면에서 엄청난 수치라는 점을 기억하세요. 사용자의 프런트엔드 로딩 속도를 최대 두 배까지 향상한다는 것은 단순히 약간의 성능 향상의 수준을 훨씬 뛰어넘어 규모에 따라 엄청난 차이를 가져올 수 있는 수치입니다.

웹사이트를 로딩하거나 작업이 완료되기를 기다릴 때 매 초가 얼마나 중요한지 수많은 연구를 인용하지 않아도 알 수 있을 것입니다. 또한 대용량 자바스크립트 번들을 다운로드할 대역폭이 없거나 프레임워크가 페이지를 변경할 때마다 최대 2배 더 오래 기다릴 수 있는 컴퓨팅 성능이 떨어지는 사용자를 고려하는 것이 얼마나 중요한지 굳이 설명할 필요가 없으리라 생각합니다.

이렇게 큰 로딩 또는 처리량을 줄인 엔지니어는 이를 이력서에 눈에 띄는 위치에 기록할 것입니다. 이는 중요한 문제입니다.

리액트와 나머지 필드 사이의 성능 차이는 미미하지 않습니다. 오히려 최소화된 것입니다.

3부: 시도해 봐야 할 다른 것들

아마도 수십 단락 전부터 궁금해지기 시작했을 것입니다. 리액트가 그렇게 구식이라면 대안은 무엇일까요?

여기서는 몇 가지를 다루고 그 사용 사례에 대해서도 언급하겠습니다. 리액트의 문제 중 하나는 오랫동안 모든 사람을 위한 모든 것이 되려고 노력해 왔다는 점이며, 리액트 형태의 도구가 유용할 수는 있지만 하나의 스위스 군용 칼보다 두세 가지 다른 도구가 더 나을 수 있다고 생각합니다.

하지만 본격적으로 들어가기 전에 두 가지를 간단히 짚고 넘어가겠습니다.

  1. 위에서 언급한 다른 모든 최신 프레임워크를 다루기 위해 여기에 여러 옵션을 나열하고 있습니다. 이 모든 프레임워크에 대해 배우거나 사용할 것이라 예상하지는 않습니다. 굳이 하나를 선택해야 한다면 스벨트 또는 뷰를 선택하세요. 저는 철저함을 위해 모두 나열한 것뿐이라는 점을 알아두세요.

  2. 모든 옵션을 나열하지는 않았습니다. 언급하지 않은 다른 옵션도 있습니다.

    예를 들어 Ember와 Angular는 생략했는데, 그 이유는 둘 다 리액트보다 오래되었고 일반적으로 벤치마크 테스트에서 리액트를 크게 앞지르는 경향이 없기 때문입니다(미안해요, Mel).

    또한 AlpinePetite Vue와 같은 경량 옵션은 생략했는데, 이는 리액트보다는 제이쿼리의 대체품에 가깝고 프레임워크처럼 무거운 것이 필요하지 않은 경우에 빛을 발하기 때문입니다.

    마지막으로, 이 카테고리에서 약간 벗어난 매우 훌륭한 도구도 생략했습니다. Eleveny는 프레임워크라기보다는 순수한 정적 사이트 생성기에 가깝기 때문입니다. (하지만 개츠비를 사용 중이라면 한번 살펴볼 가치가 있습니다.)

이제 주간 추천을 소개합니다.

스벨트 (제 개인적인 선택)

2023년도 수료생 여러분, 스벨트를 사용하십시오.

미래에 대한 한 가지 팁만 드릴 수 있다면, 그것은 스벨트일 것입니다.

농담은 제쳐두고, 이 목록에서 리액트보다 추천할 만한 것을 하나만 꼽으라면 스벨트가 될 것입니다. 저는 2019년에 트위터에서 "스벨트는 헛소리를 뺀 리액트다"라고 오랫동안 주장해 왔고(RIP), 시간이 지날수록 그 주장은 더욱 진실이 되어가고 있습니다.

스벨트는 사용하기 쉽고, 비교적 배우기 쉬우며(특히 이미 리액트를 사용해 본 적이 있다면 더욱 그렇습니다. 구문도 비슷한 경우가 많습니다), 거의 모든 경우에서 훨씬 더 성능이 뛰어나고, 리액트가 할 수 있는 모든 것을 할 수 있습니다. 이 사이트와 요즘 제가 하는 모든 사이드 프로젝트는 스벨트키트으로 작성됩니다.

스벨트는 가장 빠른 옵션과 비교해도 손색이 없을 정도로 빠릅니다. 개발자 설문조사에서 가장 사랑받는 프레임워크의 최상위권 또는 그 근처에서 자주 등장할 정도로 DX가 놀랍습니다.

스벨트는 가능한 한 웹 플랫폼에 가깝게 개발되었기 때문에 매우 강력하면서도 개념은 대체로 친숙할 것입니다. 또한 스벨트에는 트랜지션, 이징, CSS 처리, 컴포넌트 범위 스타일 등 다양한 기능이 기본으로 포함되어 있습니다.

프레임워크 크기에 대해 궁금해하실 수도 있지만, 스벨트는 자바스크립트 런타임이 아니라 컴파일러라는 점에서 다른 점이 있습니다. 빌드 시 사용하지 않는 모든 것이 제거되고 코드가 작은 바닐라 자바스크립트 비트로 트랜스파일됩니다. 즉, 스벨트의 번들은 일반적으로 리액트의 몇분의 1 크기입니다.

프레임워크처럼 느껴지고 작동할지라도, 스벨트는 본질적으로 작고 우아한 HTML의 상위 집합으로, 빠르고 최소한의 번들로 컴파일되는 유쾌하고 간단한 구문을 가지고 있습니다.

스벨트의 자체 메타 프레임워크인 스벨트키트는 정적, 서버 렌더링, 엣지 배포, 라우트별 혼합까지 가능한 매우 다재다능하고 강력합니다. 2022년 말에 1.0 버전이 출시되었으며 프로덕션에 바로 사용할 수 있습니다. (Next.js를 만드는 Vercel에서도 지원합니다.)

스벨트는 다음과 같은 경우에 추천합니다.

위와 같은 이유로 최고의 만능 옵션으로 프런트엔드의 즐거움을 재발견하고 싶은 경우.

스벨트는 다음과 같은 경우를 대체 가능합니다.

리액트로 하는 모든 작업. 스벨트는 리액트 자체를 대체할 수도 있고, 스벨트키트는 Next.js, 개츠비, 리믹스를 대체할 수 있을 만큼 다재다능합니다(또는 한 번에 모두 대체할 수도 있습니다).

는 아마도 리액트와 가장 유사한 선택지일 수 있으며, 다음으로 큰 생태계를 가지고 있을 것입니다. 하지만 리액트보다 성능이 훨씬 뛰어나고 UI에 좀 더 중점을 둡니다.

어떤 면에서는 뷰가 리액트에서 가장 작은 도약이라고 할 수 있는데, 특히 뷰 3에서 유사한 훅 기반 접근 방식을 사용한다는 점에서 더욱 그렇습니다. 그러나 뷰는 JSX보다 기본 HTML에 가까운 템플릿 언어를 사용하므로 map 및 삼항식과 같은 해결 방법을 사용하지 않고도 템플릿 파일에 조건문과 루프를 훨씬 쉽게 작성할 수 있습니다.

뷰는 Nuxt의 Next.js와 유사한 메타 프레임워크를 가지고 있으며, 잘 유지 관리되고 항상 강력한 새 기능을 추가하고 있습니다. 또한 뷰는 범위 지정 CSS 처리 및 쉬운 전환/애니메이션과 같은 기능을 즉시 사용할 수 있어 리액트보다 약간 더 많은 기능과 도구를 기본적으로 제공하고 있습니다.

뷰는 다음과 같은 경우에 추천합니다.

커뮤니티 규모/전체 프레임워크의 인기가 중요한 요소인 경우, 리액트와 비슷하지만, 더 많은 기본 기능이 포함되거나 HTML과 유사한 것을 원하는 경우, 프레임워크가 대기업에 소유되지 않고 독립적인 것을 선호하는 경우.

뷰는 다음과 같은 경우를 대체 가능합니다.

리액트 자체 또는 Nuxt가 Next.js를 사용하는 모든 것을 대체할 수 있습니다.

솔리드

솔리드는 제가 더 나은 리액트라고 부르는 것입니다. 많은 경우 리액트와 거의 (완전히는 아니더라도) 동일해 보이지만 솔리드가 훨씬 더 성능이 뛰어납니다. 사실 빠른 옵션 중 하나입니다.

솔리드는 기본적으로 리액트에서 시작하여 복잡성, 성능 문제 및 많은 보일러 플레이트를 제거하도록 재구성됩니다. 솔리드에서는 시그널이 개념이 나타나며 컴포넌트 렌더링과 수명주기에 대한 혼란과 발목을 잡는 요소가 상당 부분 제거됩니다. 2013년 이후 우리가 배운 모든 교훈을 바탕으로 현대에 리액트가 만들어졌다면 솔리드는 리액트라고 해도 과언이 아닐 것입니다.

솔리드는 현재 베타 버전이긴 하지만 솔리드스타트에서 자체 메타 프레임워크도 제공합니다. 하지만 솔리드 자체는 충분히 사용하기에 충분히 성숙했으며 인상적인 후원사 갤러리를 자랑합니다.

솔리드는 다음과 같은 경우에 추천합니다.

일반적으로 리액트(및 JSX)를 좋아하지만, 더 현대적이고 빠르거나 더 쉬웠으면 하는 경우, 성능이 절대적인 최우선 순위인 경우.

솔리드는 다음과 같은 경우를 대체 가능합니다.

리액트와 리액트 DOM. 솔리드스타트는 언젠가 Next.js를 대체할 수 있을 것으로 보이지만, 이 글을 쓰는 현재로서는 아직 베타 버전입니다.

프레시(Fresh)

프레시는 서버사이드 렌더링 프런트엔드 프레임워크로, Deno에 구축된 아일랜드 아키텍처를 사용합니다. 이 목록에 있는 다른 대부분의 항목보다 조금 더 어리지만, Deno로 구동되는 엣지에서 실행할 수 있는 최소한의 JS, 아일랜드 기반 프레임워크로서 가능성이 가득합니다. 즉, 서버 코드가 더 빠르고, 더 안전하며, 기본적으로 타입스크립트를 사용하고, Deno가 기존 Node보다 제공하는 다른 모든 이점(예: 더 쉬운 퍼스트 파티 린팅, 테스트 및 코드 서식 설정)을 누릴 수 있다는 뜻입니다.

모든 프레시 컴포넌트는 정적으로 렌더링되어 응답 시 자바스크립트 없이 HTML로 제공되거나, 클라이언트에서만 렌더링되는 "아일랜드"로 제공됩니다. 필요에 따라 혼합하여 사용할 수 있습니다. Deno에서 실행되므로 전 세계 모든 기기에서 최대한 빠르게 로드되는 매우 빠르고 동적인 콘텐츠를 제공할 수 있습니다.

프레시는 프리액트를 사용하므로 속도가 빠르다는 것을 알 수 있으며, 리액트를 사용하던 사용자도 어렵지 않게 익힐 수 있습니다. 그리고 다시 한번 말씀드리지만, Deno를 기반으로 구축하면 기분이 좋습니다.

프레시는 다음과 같은 경우에 추천합니다.

클라우드에서 전 세계적으로 사용할 수 있는 서버사이드 앱, 최소한의 자바스크립트만 제공하거나 최신 기술을 기반으로 구축하는 것을 좋아합니다.

프레시는 다음과 같은 경우를 대체 가능합니다.

리믹스는 아마도 리액트 세계에서 프레시에 가장 가까운 것일 것입니다.

아스트로(Astro)

아스트로는 정적 이상의 기능을 제공하는 차세대 고성능 정적 사이트 생성기입니다. 아스트로는 이 목록에서 가장 최신 옵션 중 하나이지만 이미 매우 안정적인 1.0 릴리스에 있으며 광범위한 찬사와 채택을 받고 있습니다.

주로 차세대 SSG를 위해 개발되었지만(리액트 팬이라면 주목하세요. JSX와 MDX를 지원합니다), 이제 동적인 서버 측 기능도 제공합니다. 콘텐츠가 많거나 정적인 사이트에는 개츠비보다 더 추천하고 싶습니다.

진짜 킬러 기능은 다음과 같습니다. 아스트로는 기본적으로 자바스크립트를 전혀 제공하지 않습니다. 원하는 기능만 선택해서 사용할 수 있습니다.

또한 아스트로는 사용하려는 프런트엔드 프레임워크와 호환되므로 리액트, 뷰, 스벨트 등으로 템플릿을 제작하고 싶으시다면 가능합니다!

아스트로는 다음과 같은 경우에 추천합니다.

대부분 정적이거나 콘텐츠/마크다운 기반 사이트를 구축하는 경우(일부 서버 측 렌더링이나 로직이 필요할 수도 있음), 최소한의 자바스크립트만 제공하려는 경우, 자체 프런트엔드 프레임워크를 가져오고 싶은 경우.

아스트로는 다음과 같은 경우를 대체 가능합니다.

개츠비 또는 유사한 리액트 기반 콘텐츠 도구.

프리액트

리액트를 사용하시는 분이라면 이미 프리액트에 대해 알고 계시겠지만, 여기서는 언급할 필요가 있습니다. 프리액트는 리액트의 훨씬 더 날렵하고 빠른 버전입니다. 리액트를 대체하는 용도로 시작했지만, 리액트에는 없는 몇 가지 뛰어난 기능(이미 언급한 시그널과 같은)을 추가하기 시작했습니다.

프리액트는 다음과 같은 경우에 추천합니다.

기본적으로 리액트를 고수하고 싶지만 더 빠르기를 원하는 경우.

프리액트는 다음과 같은 경우를 대체 가능합니다.

리액트. (사실, 앞에 P가 추가될 뿐입니다. P는 성능을 의미합니다. 제가 다 지어낸 말이니 프리액트 팀을 탓하지 마세요).

퀵(Qwik)

서버는 하이드레이션과 성능에 대한 새로운 접근 방식으로 리액트와 유사한 코드(JSX)를 렌더링합니다. 실제로는 "하이드레이션"이라고 할 수 없으며, 자바스크립트를 DOM에 직렬화하여 필요할 때만 작은 부분만 로드합니다. 퀵은 이 목록에서 더 심층적으로 다루고 있지만 가능한 한 빨리 실행해야 하는 상호작용이 많은 경우 한번 살펴볼 가치가 있습니다.

퀵은 다음과 같은 경우에 추천합니다.

브라우저에 많은 자바스크립트를 전송하고 있으며, 이를 더욱 효율적으로 처리할 방법을 원합니다.

퀵은 다음과 같은 경우를 대체 가능합니다.

리액트 자체를 대체할 수 있으며, 엣지에서 매우 효율적으로 실행할 수 있습니다.

웹 컴포넌트 라이브러리

솔직히 저는 이 주제에 대해 잘 아는 사람이 아니기 때문에 깊이 들어가지는 않겠습니다. 웹 컴포넌트 자체나 웹 컴포넌트 프레임워크에 대한 경험이 부족하기 때문에 이 주제에 대해 잘 말할 수 없습니다.

그렇긴 하지만, 웹 컴포넌트 프레임워크/라이브러리의 혜택을 받을 수 있는 특정 종류의 프로젝트가 Lit, Stencil, Polymer 등과 같이 존재합니다. 이러한 라이브러리는 특정 프런트엔드 프레임워크에서 "독점적인" 컴포넌트를 생성하는 대신 실제 웹 컴포넌트를 작성하는 데 도움이 되며, 이 컴포넌트는 모든 웹 프로젝트에 이식할 수 있습니다.

제 생각에 대부분의 프로젝트는 여전히 순수 웹 컴포넌트보다 프런트엔드 프레임워크를 사용하는 것이 더 유리합니다. 아니면 최소한 두 가지를 함께 사용하는 것이 더 유리합니다. 앞으로는 상황이 달라질 수도 있겠지만, 현재로서는 대부분의 경우 여전히 순수 웹 컴포넌트 접근 방식에 유리하다고 생각합니다.

하지만 순수한 웹 컴포넌트 기반 접근 방식을 고려해야 하는 사용 사례도 분명히 있습니다. 그리고 그런 프로젝트의 경우 리액트는 확실히 과잉입니다. 위에서 언급한 웹 컴포넌트 라이브러리가 훨씬 더 적합할 것입니다.

웹 컴포넌트 라이브러리는 다음과 같은 경우에 추천합니다.

여러 환경에서 동일한 컴포넌트를 재사용해야 하거나, 프레임워크 변경에 대비해 미래에 대비하고 싶거나, 플랫폼 사용을 선호하고 웹 컴포넌트 작성의 단점을 감당할 준비가 되어 있는 경우.

웹 컴포넌트는 다음과 같은 경우를 대체 가능합니다.

사용 사례에 따라 부분적으로만 리액트를 대체할 수 있습니다.

마치며

이 글은 작년에 제가 쓴 리액트의 자기충족적 예언과 매우 유사합니다. 동일한 영역을 다루고 있으며, (새로운 방식이나 새로운 관점에서 바라보긴 하지만) 동일한 주장을 하고 있습니다.

같은 내용을 반복할 생각은 없었지만, 우연찮게도 이 글이 게시될 무렵에 제가 리액트를 풀타임으로 사용하게 되면서 이 부분에 대해 많이 생각하게 된 것은 분명합니다.

저는 리액트의 인기는 상당 부분 사람들이 그 너머를 보지 않기 때문이라고 믿게 되었습니다. 최고는 아니지만 대부분 사람은 최고를 찾는 것이 아니라 그저 충분히 좋은 것을 찾고 있습니다. (우리는 인간입니다. 우리 모두의 결정에는 개인적이고 감정적이며 비합리적인 이유가 많이 있으며, 그것은 괜찮습니다. 우리는 바쁘니까요.)

적어도 프런트엔드 세계에서는 기술을 선형적으로 도입하기보다는 비약적으로 도입하는 것 같습니다. 모두가 리액트에 뛰어들게 된 이유 중 하나는 당시 모든 사람이 구식 기술에 갇혀 더 나은 것을 찾고 있었기 때문입니다. 우리는 점진적으로 새로운 것을 향해 조금씩 나아가는 것이 아니라(어쩌면 처음부터 그렇게 할 수 없었기 때문일 수도 있습니다), 현재 위치에서 다음 단계로 도약하는 거대한 도약을 했습니다.

선형 선상에, '진보'라고 표시되어 있습니다. 선 위에는 '채택'이라고 표시된 왼쪽에서 오른쪽으로 점프하는 몇 개의 아치형 도약이 있습니다. 그러나 마지막 도약은 직선 '진보'라는 선의 가장 먼 가장자리에 훨씬 못 미칩니다.

하지만 중요한 것은 우리가 몇 년 전 그 도약을 한 이후로 거의 같은 자리에 앉아 있었다는 것입니다.

제 생각에 우리는 또 다른 도약에 가까워지고 있습니다.

그것이 무엇일지, 왜 그럴지는 모르겠습니다. 하지만 그 당시 제이쿼리에서 느꼈던 것처럼 리액트가 실제로 해결하지 못하는 문제들을 느끼기 시작한 것 같습니다. 그리고 결국에는 발전할 때가 되었다는 것이 분명해질 것으로 생각합니다.

그 새로운 것은 무엇일까요? 저도 모르겠어요. 그냥 웹 플랫폼이 될 수도 있습니다. 프레임워크가 필요 없을지도 모르죠. 위의 프레임워크가 될 수도 있고, 우리가 아직 보지 못한 무언가가 될 수도 있습니다. 어쩌면 어떤 것도 없을 수도 있고, 다양한 도구가 등장하고 하나의 표준으로 통합되지 않을 수도 있습니다(위의 모든 옵션 중에서 가능성이 가장 낮은 것으로 보이는 이유는 다시 말하지만, 인간이기 때문입니다. 인간은 바쁜 작은 원숭이이기 때문에 기본값을 좋아합니다.)

하지만 그 새로운 것이 무엇이든, 리액트와 그것의 차이는 시간이 지남에 따라 점점 더 커질 것으로 생각합니다.

그러니 하루하루가 이전보다 더 나은 날이 되어 여러분이 놓치고 있던 것을 탐구할 수 있기를 바랍니다.

들어주셔서 감사합니다.

+ \ No newline at end of file diff --git a/log/virtual-dom-back-in-block.html b/log/virtual-dom-back-in-block.html index ae034374..a15ecf12 100644 --- a/log/virtual-dom-back-in-block.html +++ b/log/virtual-dom-back-in-block.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

가상 DOM: 블록으로 돌아가기

원문: https://million.dev/blog/virtual-dom


이 글은 심층적인 분석글입니다 — 초보자를 위한 글이 아닙니다. Million.js를 배우고 싶으시다면 빠른 시작을 참조하세요.

이 포스팅은 React와 Million.js 내부를 자세히 살펴보고자 하는 숙련된 프로그래머를 대상으로 합니다.

약 4년 전, 리치 해리스(Rich Harris)는 기존 가상 DOM 조작의 성능을 분석한 가상 DOM은 순수한 오버헤드입니다라는 글을 발표했습니다. [0]

[0] "'가상 DOM은 빠르다'는 문구를 들어 보셨을 겁니다. 이는 보통 가상 DOM이 실제 DOM보다 빠르다는 뜻으로 사용됩니다. 그리고 놀랍도록 지속적으로 언급되는 밈(meme)입니다" - 해리스, 2018

리치 해리스는 "가상 DOM은 순수한 오버헤드입니다"라는 글에서 리액트와 같은 프레임워크에서 널리 알려진 기능인 가상 DOM이 많은 개발자가 생각하는 것만큼 효율적이지 않다고 주장합니다. 이어서 그는 이 기능의 작동 방식을 비판하며 대안적인 접근 방식을 제시합니다.

그리고 몇 년 후 가상 DOM은 순수한 오버헤드라는 새로운 밈이 등장했습니다. 이 밈 또한 크게 유행했고 "가상 DOM이 없는" 프레임워크 운동을 이데올로기적 소수 집단에서 전면에 드러나는 다수 진영이 되었습니다.

따라서 가상 DOM은 "아무도 좋아하지 않지만, 가족 모임에 초대해야 하는 성가신 사촌"의 지위로 강등되었습니다. 선언적 UI의 편의성을 위해 지불해야 하는 성능에 대한 세금, 즉 필요악이 된 것입니다.

지금까지는요.

탄생 이야기

가상 DOM은 실제 DOM의 잦은 조작으로 인한 성능 문제를 해결하기 위해 만들어졌습니다. 실제 DOM의 경량화된 인메모리 표현이었습니다. 나중에 실제 웹 페이지를 업데이트할 때 참조로 사용할 수 있습니다.

컴포넌트가 렌더링 되면 가상 DOM은 새 상태와 이전 상태의 차이를 계산하고("비교(diffing)"이라고 하는 프로세스) 업데이트된 가상 DOM과 동기화하기 위해 실제 DOM에 최소한의 변경을 수행합니다("재조정(reconciliation)"이라고 하는 프로세스).

시각적 예시

리액트 컴포넌트 <Numbers />가 있다고 가정해 봅시다.

jsx
function Numbers() {
+    
Skip to content
On this page

가상 DOM: 블록으로 돌아가기

원문: https://million.dev/blog/virtual-dom


이 글은 심층적인 분석글입니다 — 초보자를 위한 글이 아닙니다. Million.js를 배우고 싶으시다면 빠른 시작을 참조하세요.

이 포스팅은 React와 Million.js 내부를 자세히 살펴보고자 하는 숙련된 프로그래머를 대상으로 합니다.

약 4년 전, 리치 해리스(Rich Harris)는 기존 가상 DOM 조작의 성능을 분석한 가상 DOM은 순수한 오버헤드입니다라는 글을 발표했습니다. [0]

[0] "'가상 DOM은 빠르다'는 문구를 들어 보셨을 겁니다. 이는 보통 가상 DOM이 실제 DOM보다 빠르다는 뜻으로 사용됩니다. 그리고 놀랍도록 지속적으로 언급되는 밈(meme)입니다" - 해리스, 2018

리치 해리스는 "가상 DOM은 순수한 오버헤드입니다"라는 글에서 리액트와 같은 프레임워크에서 널리 알려진 기능인 가상 DOM이 많은 개발자가 생각하는 것만큼 효율적이지 않다고 주장합니다. 이어서 그는 이 기능의 작동 방식을 비판하며 대안적인 접근 방식을 제시합니다.

그리고 몇 년 후 가상 DOM은 순수한 오버헤드라는 새로운 밈이 등장했습니다. 이 밈 또한 크게 유행했고 "가상 DOM이 없는" 프레임워크 운동을 이데올로기적 소수 집단에서 전면에 드러나는 다수 진영이 되었습니다.

따라서 가상 DOM은 "아무도 좋아하지 않지만, 가족 모임에 초대해야 하는 성가신 사촌"의 지위로 강등되었습니다. 선언적 UI의 편의성을 위해 지불해야 하는 성능에 대한 세금, 즉 필요악이 된 것입니다.

지금까지는요.

탄생 이야기

가상 DOM은 실제 DOM의 잦은 조작으로 인한 성능 문제를 해결하기 위해 만들어졌습니다. 실제 DOM의 경량화된 인메모리 표현이었습니다. 나중에 실제 웹 페이지를 업데이트할 때 참조로 사용할 수 있습니다.

컴포넌트가 렌더링 되면 가상 DOM은 새 상태와 이전 상태의 차이를 계산하고("비교(diffing)"이라고 하는 프로세스) 업데이트된 가상 DOM과 동기화하기 위해 실제 DOM에 최소한의 변경을 수행합니다("재조정(reconciliation)"이라고 하는 프로세스).

시각적 예시

리액트 컴포넌트 <Numbers />가 있다고 가정해 봅시다.

jsx
function Numbers() {
   return (
     <foo>
       <bar>
@@ -78,8 +78,8 @@
 }

"목록과 같은" 형태를 따르는 비결정적/불안정적인 반환을 사용해야 하는 경우, <For /> 컴포넌트를 사용하면 도움이 될 수 있습니다.

jsx
function Component() {
   return <For each={items}>{(item) => <div>{item}</div>}</For>;
 }

애플리케이션 UI를 구조화할 방법에 제한이 있다는 점에 유의하세요. "안정적" 반환은 목록과 같은 동적 모양이 아닌 컴포넌트(예: 동일한 컴포넌트 내의 조건부 반환)는 허용되지 않음을 의미합니다.

세밀하게 사용하기

초보자가 저지르는 큰 실수 중 하나는 블록 가상 DOM을 모든 곳에 사용하는 것입니다. 블록 가상 DOM은 만병통치약이 아니며 일반 가상 DOM보다 항상 빠른 것은 아니기 때문에 이는 좋지 않은 생각입니다.

대신 블록 가상 DOM이 더 빠른 특정 패턴을 인식해야 하고, 해당 경우에만 사용해야 합니다. 예를 들어 큰 테이블에는 블록 가상 DOM을 사용하지만, 정적 콘텐츠가 적은 작은 폼에는 일반 가상 DOM을 사용할 수 있습니다.

마무리 생각

블록 가상 DOM은 업데이트를 관리하고 오버헤드를 최소화하는 대안적인 접근 방식을 제공함으로써 가상 DOM 개념에 대한 새로운 관점을 제시합니다. 하지만 이런 잠재력에도 불구하고 이 접근 방식은 만능 솔루션이 아닙니다. 개발자는 먼저 애플리케이션의 특정 요구 사항과 성능 요구 사항을 평가한 후 이 접근 방식을 도입할지 결정해야 합니다.

많은 애플리케이션의 경우 기존 가상 DOM으로 충분할 수 있으며 블록 가상 DOM이나 기타 성능 중심 프레임워크로 전환할 필요가 없을 수도 있습니다. 애플리케이션이 대부분의 기기에서 성능 문제없이 원활하게 실행된다면 다른 프레임워크로 전환하는 데 시간과 노력을 들일 필요가 없을 수도 있습니다. 기술 스택을 크게 변경하기 전에 장단점을 면밀히 검토하고 애플리케이션의 고유한 요구 사항을 평가하는 것이 중요합니다.

그렇지만 저는 앞으로의 미래가 기대됩니다. 여러분도 기대되시나요? (직접 구축해 보세요!)

트위터에서 토론하기 | 깃허브에서 수정하기

감사

- + \ No newline at end of file diff --git a/log/web-push-for-web-apps-on-ios-and-ipados.html b/log/web-push-for-web-apps-on-ios-and-ipados.html index 033b24b6..7cde3bd7 100644 --- a/log/web-push-for-web-apps-on-ios-and-ipados.html +++ b/log/web-push-for-web-apps-on-ios-and-ipados.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

iOS 및 iPadOS의 웹 앱용 웹 푸시

원문: https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/

오늘 iOS 및 iPadOS 16.4 베타 1이 출시되었으며, 홈 화면 웹 앱에 대한 웹 푸시 및 기타 기능이 지원됩니다.

https://webkit.org/wp-content/uploads/Web_Push_on_iOS-1024x576.png

오늘 사파리 16.4의 첫 번째 베타 버전도 출시됩니다. 이번 버전은 정규표현식 후방탐색, Import Maps, 오프스크린 캔버스, 미디어 쿼리 범위 지정, @property, font-size-adjust, 선언적 쉐도우 DOM 등 135개 이상의 기능이 포함된 대규모 릴리즈입니다. 이러한 새로운 WebKit 기능에 대한 자세한 내용은 사파리 16.4가 공개될 때 작성하겠습니다. 한편, 새로운 기능 및 수정 사항의 종합적인 목록은 사파리 16.4 베타 1 릴리즈 노트에서 확인할 수 있습니다.

사파리는 잠시 제쳐두고 iOS 및 iPadOS의 홈 화면 웹 앱에 관해 이야기해 보겠습니다.

최초의 아이폰부터, 사용자는 브로슈어 사이트, 블로그, 신문, 온라인 상점, 소셜 미디어 플랫폼, 스트리밍 비디오 사이트, 생산성 소프트웨어, 아트워크 제작용 앱 등 모든 웹 사이트를 홈 화면에 추가할 수 있었습니다. 지난 10년 동안 iOS 및 iPadOS의 사파리 사용자는 공유 버튼을 탭 하여 공유 메뉴를 연 다음 '홈 화면에 추가'를 탭 하면 이 작업을 수행할 수 있었습니다. 그럼, 해당 웹사이트의 아이콘이 홈 화면에 나타나게 되고, 이 아이콘을 빠르게 탭해서 해당 사이트로 돌아갈 수 있습니다.

웹 개발자는 매니페스트 파일(display 멤버를 standalone 또는 fullscreen으로 설정해야 합니다.)을 생성하여 웹사이트와 함께 제공할 수 있습니다. 그렇게 하면 해당 사이트는 홈 화면 웹 앱이 됩니다. 그런 다음 해당 아이콘을 탭 하면 웹 앱이 브라우저에서 열리지 않고 iOS 또는 iPadOS의 다른 앱처럼 열립니다. 사파리나 다른 브라우저와는 별도로 앱 스위처에서 앱 미리보기를 볼 수 있습니다.

홈 화면 웹 앱용 웹 푸시 추가

iOS 및 iPadOS 16.4 베타 1에서 홈 화면 웹 앱에 웹 푸시 기능이 추가되었습니다. 웹 푸시는 웹 개발자가 푸시 API, 알림 API, 서비스 워커를 모두 연동하여 사용자에게 푸시 알림을 보낼 수 있도록 해줍니다.

홈 화면에 추가된 웹 앱은 웹 앱에서 제공하는 '구독' 버튼을 탭 하는 등 사용자의 직접적인 상호 작용에 대한 응답으로 푸시 알림 수신 권한을 요청할 수 있습니다. 그러면 iOS 또는 iPadOS는 사용자에게 웹 앱에 알림 전송 권한을 부여할지 묻는 메시지를 표시합니다. 허용되면 사용자는 iPhone 및 iPad의 다른 앱과 마찬가지로 알림 설정에서 웹 앱별로 해당 권한을 관리할 수 있습니다.

웹 앱의 알림은 다른 앱의 알림과 똑같이 작동합니다. 알림은 잠금 화면, 알림 센터 및 페어링 된 애플 워치에 표시됩니다.

이는 작년 가을 macOS Ventura용 Safari 16.1에 추가된 것과 동일한 W3C 표준 기반 웹 푸시입니다. 브라우저 감지 대신 기능 감지를 사용하는 등 모범 사례에 따라 웹 앱에 표준 기반 웹 푸시를 구현한 경우 iPhone 및 iPad에서 자동으로 작동합니다.

iOS 및 iPadOS의 웹 푸시는 모든 애플 디바이스에서 네이티브 푸시를 지원하는 동일한 애플 푸시 알림 서비스를 사용합니다. 애플 개발자 프로그램의 회원이 아니어도 사용할 수 있습니다. 서버 푸시 엔드포인트를 제어하고 있는 경우 *.push.apple.com의 URL을 허용하기만 하면 됩니다.

웹 푸시 설정 방법에 대해 자세히 알아보려면 webkit.org에서 웹 푸시 만나기 문서를 참조하거나 WWDC22 세션 비디오 웹 푸시 만나기를 시청하세요.

집중 모드 지원

알림은 강력한 도구이지만, 너무 많은 알림에 압도당하는 상황에 빠지기 쉽습니다. iPhone 및 iPad의 홈 화면 웹 앱에 대한 알림은 집중 모드와 통합되어 사용자가 언제 어디서 알림을 받을지 정확하게 설정할 수 있도록 합니다. 두 대 이상의 iOS 또는 iPadOS 장치에서 동일한 웹 앱을 홈 화면에 추가한 사용자의 경우 집중 모드가 모든 장치에 자동으로 적용됩니다.

배지 API

iOS 및 iPadOS 16.4 베타 1의 홈 화면 웹 앱은 이제 배지 API를 지원합니다. iOS 및 iPadOS의 다른 앱과 마찬가지로 이제 웹 앱에서도 배지 수를 설정할 수 있습니다. setAppBadgeclearAppBadge는 사용자가 웹 앱을 포어그라운드에서 열어두거나 웹 앱이 백그라운드에서 푸시 이벤트를 처리하는 동안, 즉 배지 수를 표시할 수 있는 권한이 부여되기 전에도 배지 수를 변경할 수 있습니다.

앱 아이콘에 배지를 표시할 수 있는 권한은 iOS 및 iPadOS의 다른 앱과 똑같은 방식으로 부여됩니다. 사용자가 알림을 허용하는 권한을 부여하면 홈 화면의 아이콘에 현재 배지 수가 즉시 표시됩니다. 그런 다음 사용자는 iOS 또는 iPadOS의 다른 앱과 마찬가지로 알림 설정에서 배지에 대한 권한을 구성할 수 있습니다.

매니페스트 ID

iOS 및 iPadOS용 WebKit 16.4 베타 1은 웹 애플리케이션 매니페스트 표준의 ID 멤버에 대한 지원을 추가합니다. 이는 웹 애플리케이션의 고유 식별자 역할을 하는 문자열(URL 형태)로, OS에서 원하는 방식으로 사용하기 위한 것입니다. iOS 및 iPadOS는 여러 기기에서 집중 모드 설정을 동기화할 목적으로 매니페스트 ID를 사용합니다.

iOS는 처음부터 동일한 웹 앱의 다중 설치를 지원해 왔습니다. 하나의 웹 앱을 기기에 두 번 이상 설치할 수 있는 기능은 여러 계정을 지원하고 업무용과 개인용을 구분하는 등의 추가적인 유연성을 제공하는 등 유용할 수 있다고 생각합니다.

홈 화면에 웹 앱을 추가할 때 사용자에게 앱 이름을 변경할 기회가 주어집니다. iOS 및 iPadOS 16.4 베타 1에서는 이 이름을 매니페스트 ID와 결합하여 웹 앱을 고유하게 식별할 수 있습니다. 이렇게 하면 사용자가 하나의 디바이스에 여러 개의 웹 앱 사본을 설치하고 각 사본에 서로 다른 ID를 부여할 수 있습니다. 예를 들어, 'Shiny(개인용)'의 알림은 집중 모드에서 무음으로 설정하고 'Shiny(업무용)'의 알림은 허용할 수 있습니다. 사용자가 여러 장치에서 즐겨 찾는 웹사이트에 동일한 이름을 지정하면 한 장치의 집중 모드 설정이 동기화되어 다른 장치에도 적용됩니다.

홈 화면 추가를 위한 타사 브라우저 지원

iOS 및 iPadOS 16.4 베타 1에서는 이제 타사 브라우저에서도 공유 메뉴에서 웹사이트 및 웹 앱을 홈 화면에 추가할 수 있는 기능을 사용자에게 제공할 수 있습니다.

iOS 및 iPadOS의 애플리케이션은 activityItems 배열이 있는 UIActivityViewController를 생성하여 공유 메뉴를 표시합니다. 공유 메뉴에 '홈 화면에 추가'가 포함되려면 다음 조건을 만족해야 합니다.

  1. 응용 프로그램에는 com.apple.developer.web-browser 관리 권한이 있어야 합니다.
  2. activityItems 배열에 WKWebView가 포함되어 있어야 합니다.
  3. WKWebView가 HTTP 또는 HTTPS URL이 있는 문서를 표시하고 있어야 합니다.
  4. 장치가 iPad인 경우 공유 iPad로 구성되지 않아야 합니다.

위에서 설명한 대로 사용자가 홈 화면에 추가한 후 display 멤버를 standalone 또는 fullscreen으로 설정하는 매니페스트 파일이 있는 모든 웹사이트는 사용자가 해당 아이콘을 탭 하면 웹 앱으로 열립니다. 이는 웹사이트를 홈 화면에 추가한 브라우저와 관계없이 마찬가지입니다.

웹 앱 동작을 요청하도록 구성된 매니페스트 파일이 없는 경우(그리고 사이트를 웹 앱 가능으로 표시하는 meta 태그가 없는 경우) 해당 웹사이트는 홈 화면 북마크로 저장됩니다. iOS 및 iPadOS 16.4 베타 1부터 홈 화면 북마크는 사용자의 현재 기본 브라우저에서 열립니다.

새로운 대체 아이콘

웹 개발자는 일반적으로 브라우저의 인터페이스 전체에 웹사이트를 나타내는 아이콘을 제공합니다. 홈 화면의 아이콘이 제공되지 않는 경우 이전에는 iOS 및 iPadOS에서 사이트의 스크린샷으로 아이콘을 만들었습니다. 이제 iOS 및 iPadOS 16.4 베타 1에서는 사이트 이름의 첫 글자와 사이트의 색상을 사용하여 모노그램 아이콘을 생성하고 표시합니다.

웹사이트 또는 웹 앱에 사용할 아이콘을 제공하려면 매니페스트 파일에 아이콘을 나열하면 되는데, 이는 iOS 및 iPadOS 15.4부터 지원된 기능입니다. 또는 오랫동안 지원되어 온 기법인 HTML 문서 headapple-touch-icons을 나열하는 방법을 사용할 수 있습니다. (두 가지 방법을 모두 사용하는 경우 apple-touch-icon이 매니페스트에 선언된 아이콘보다 우선합니다.)

웹 앱을 위한 새로운 웹 API

웹 푸시, 배지 API, 매니페스트 ID 외에도 iOS 및 iPadOS 16.4 베타 1용 Webkit의 다른 많은 새로운 기능은 홈 화면 웹 앱에 중점을 둔 웹 앱 개발자에게 특히 흥미로울 것입니다. 여기에는 다음 사항들이 포함됩니다.

전체 기능 목록은 사파리 16.4 베타 1의 릴리즈 정보를 참조하세요.

- +
Skip to content
On this page

iOS 및 iPadOS의 웹 앱용 웹 푸시

원문: https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/

오늘 iOS 및 iPadOS 16.4 베타 1이 출시되었으며, 홈 화면 웹 앱에 대한 웹 푸시 및 기타 기능이 지원됩니다.

https://webkit.org/wp-content/uploads/Web_Push_on_iOS-1024x576.png

오늘 사파리 16.4의 첫 번째 베타 버전도 출시됩니다. 이번 버전은 정규표현식 후방탐색, Import Maps, 오프스크린 캔버스, 미디어 쿼리 범위 지정, @property, font-size-adjust, 선언적 쉐도우 DOM 등 135개 이상의 기능이 포함된 대규모 릴리즈입니다. 이러한 새로운 WebKit 기능에 대한 자세한 내용은 사파리 16.4가 공개될 때 작성하겠습니다. 한편, 새로운 기능 및 수정 사항의 종합적인 목록은 사파리 16.4 베타 1 릴리즈 노트에서 확인할 수 있습니다.

사파리는 잠시 제쳐두고 iOS 및 iPadOS의 홈 화면 웹 앱에 관해 이야기해 보겠습니다.

최초의 아이폰부터, 사용자는 브로슈어 사이트, 블로그, 신문, 온라인 상점, 소셜 미디어 플랫폼, 스트리밍 비디오 사이트, 생산성 소프트웨어, 아트워크 제작용 앱 등 모든 웹 사이트를 홈 화면에 추가할 수 있었습니다. 지난 10년 동안 iOS 및 iPadOS의 사파리 사용자는 공유 버튼을 탭 하여 공유 메뉴를 연 다음 '홈 화면에 추가'를 탭 하면 이 작업을 수행할 수 있었습니다. 그럼, 해당 웹사이트의 아이콘이 홈 화면에 나타나게 되고, 이 아이콘을 빠르게 탭해서 해당 사이트로 돌아갈 수 있습니다.

웹 개발자는 매니페스트 파일(display 멤버를 standalone 또는 fullscreen으로 설정해야 합니다.)을 생성하여 웹사이트와 함께 제공할 수 있습니다. 그렇게 하면 해당 사이트는 홈 화면 웹 앱이 됩니다. 그런 다음 해당 아이콘을 탭 하면 웹 앱이 브라우저에서 열리지 않고 iOS 또는 iPadOS의 다른 앱처럼 열립니다. 사파리나 다른 브라우저와는 별도로 앱 스위처에서 앱 미리보기를 볼 수 있습니다.

홈 화면 웹 앱용 웹 푸시 추가

iOS 및 iPadOS 16.4 베타 1에서 홈 화면 웹 앱에 웹 푸시 기능이 추가되었습니다. 웹 푸시는 웹 개발자가 푸시 API, 알림 API, 서비스 워커를 모두 연동하여 사용자에게 푸시 알림을 보낼 수 있도록 해줍니다.

홈 화면에 추가된 웹 앱은 웹 앱에서 제공하는 '구독' 버튼을 탭 하는 등 사용자의 직접적인 상호 작용에 대한 응답으로 푸시 알림 수신 권한을 요청할 수 있습니다. 그러면 iOS 또는 iPadOS는 사용자에게 웹 앱에 알림 전송 권한을 부여할지 묻는 메시지를 표시합니다. 허용되면 사용자는 iPhone 및 iPad의 다른 앱과 마찬가지로 알림 설정에서 웹 앱별로 해당 권한을 관리할 수 있습니다.

웹 앱의 알림은 다른 앱의 알림과 똑같이 작동합니다. 알림은 잠금 화면, 알림 센터 및 페어링 된 애플 워치에 표시됩니다.

이는 작년 가을 macOS Ventura용 Safari 16.1에 추가된 것과 동일한 W3C 표준 기반 웹 푸시입니다. 브라우저 감지 대신 기능 감지를 사용하는 등 모범 사례에 따라 웹 앱에 표준 기반 웹 푸시를 구현한 경우 iPhone 및 iPad에서 자동으로 작동합니다.

iOS 및 iPadOS의 웹 푸시는 모든 애플 디바이스에서 네이티브 푸시를 지원하는 동일한 애플 푸시 알림 서비스를 사용합니다. 애플 개발자 프로그램의 회원이 아니어도 사용할 수 있습니다. 서버 푸시 엔드포인트를 제어하고 있는 경우 *.push.apple.com의 URL을 허용하기만 하면 됩니다.

웹 푸시 설정 방법에 대해 자세히 알아보려면 webkit.org에서 웹 푸시 만나기 문서를 참조하거나 WWDC22 세션 비디오 웹 푸시 만나기를 시청하세요.

집중 모드 지원

알림은 강력한 도구이지만, 너무 많은 알림에 압도당하는 상황에 빠지기 쉽습니다. iPhone 및 iPad의 홈 화면 웹 앱에 대한 알림은 집중 모드와 통합되어 사용자가 언제 어디서 알림을 받을지 정확하게 설정할 수 있도록 합니다. 두 대 이상의 iOS 또는 iPadOS 장치에서 동일한 웹 앱을 홈 화면에 추가한 사용자의 경우 집중 모드가 모든 장치에 자동으로 적용됩니다.

배지 API

iOS 및 iPadOS 16.4 베타 1의 홈 화면 웹 앱은 이제 배지 API를 지원합니다. iOS 및 iPadOS의 다른 앱과 마찬가지로 이제 웹 앱에서도 배지 수를 설정할 수 있습니다. setAppBadgeclearAppBadge는 사용자가 웹 앱을 포어그라운드에서 열어두거나 웹 앱이 백그라운드에서 푸시 이벤트를 처리하는 동안, 즉 배지 수를 표시할 수 있는 권한이 부여되기 전에도 배지 수를 변경할 수 있습니다.

앱 아이콘에 배지를 표시할 수 있는 권한은 iOS 및 iPadOS의 다른 앱과 똑같은 방식으로 부여됩니다. 사용자가 알림을 허용하는 권한을 부여하면 홈 화면의 아이콘에 현재 배지 수가 즉시 표시됩니다. 그런 다음 사용자는 iOS 또는 iPadOS의 다른 앱과 마찬가지로 알림 설정에서 배지에 대한 권한을 구성할 수 있습니다.

매니페스트 ID

iOS 및 iPadOS용 WebKit 16.4 베타 1은 웹 애플리케이션 매니페스트 표준의 ID 멤버에 대한 지원을 추가합니다. 이는 웹 애플리케이션의 고유 식별자 역할을 하는 문자열(URL 형태)로, OS에서 원하는 방식으로 사용하기 위한 것입니다. iOS 및 iPadOS는 여러 기기에서 집중 모드 설정을 동기화할 목적으로 매니페스트 ID를 사용합니다.

iOS는 처음부터 동일한 웹 앱의 다중 설치를 지원해 왔습니다. 하나의 웹 앱을 기기에 두 번 이상 설치할 수 있는 기능은 여러 계정을 지원하고 업무용과 개인용을 구분하는 등의 추가적인 유연성을 제공하는 등 유용할 수 있다고 생각합니다.

홈 화면에 웹 앱을 추가할 때 사용자에게 앱 이름을 변경할 기회가 주어집니다. iOS 및 iPadOS 16.4 베타 1에서는 이 이름을 매니페스트 ID와 결합하여 웹 앱을 고유하게 식별할 수 있습니다. 이렇게 하면 사용자가 하나의 디바이스에 여러 개의 웹 앱 사본을 설치하고 각 사본에 서로 다른 ID를 부여할 수 있습니다. 예를 들어, 'Shiny(개인용)'의 알림은 집중 모드에서 무음으로 설정하고 'Shiny(업무용)'의 알림은 허용할 수 있습니다. 사용자가 여러 장치에서 즐겨 찾는 웹사이트에 동일한 이름을 지정하면 한 장치의 집중 모드 설정이 동기화되어 다른 장치에도 적용됩니다.

홈 화면 추가를 위한 타사 브라우저 지원

iOS 및 iPadOS 16.4 베타 1에서는 이제 타사 브라우저에서도 공유 메뉴에서 웹사이트 및 웹 앱을 홈 화면에 추가할 수 있는 기능을 사용자에게 제공할 수 있습니다.

iOS 및 iPadOS의 애플리케이션은 activityItems 배열이 있는 UIActivityViewController를 생성하여 공유 메뉴를 표시합니다. 공유 메뉴에 '홈 화면에 추가'가 포함되려면 다음 조건을 만족해야 합니다.

  1. 응용 프로그램에는 com.apple.developer.web-browser 관리 권한이 있어야 합니다.
  2. activityItems 배열에 WKWebView가 포함되어 있어야 합니다.
  3. WKWebView가 HTTP 또는 HTTPS URL이 있는 문서를 표시하고 있어야 합니다.
  4. 장치가 iPad인 경우 공유 iPad로 구성되지 않아야 합니다.

위에서 설명한 대로 사용자가 홈 화면에 추가한 후 display 멤버를 standalone 또는 fullscreen으로 설정하는 매니페스트 파일이 있는 모든 웹사이트는 사용자가 해당 아이콘을 탭 하면 웹 앱으로 열립니다. 이는 웹사이트를 홈 화면에 추가한 브라우저와 관계없이 마찬가지입니다.

웹 앱 동작을 요청하도록 구성된 매니페스트 파일이 없는 경우(그리고 사이트를 웹 앱 가능으로 표시하는 meta 태그가 없는 경우) 해당 웹사이트는 홈 화면 북마크로 저장됩니다. iOS 및 iPadOS 16.4 베타 1부터 홈 화면 북마크는 사용자의 현재 기본 브라우저에서 열립니다.

새로운 대체 아이콘

웹 개발자는 일반적으로 브라우저의 인터페이스 전체에 웹사이트를 나타내는 아이콘을 제공합니다. 홈 화면의 아이콘이 제공되지 않는 경우 이전에는 iOS 및 iPadOS에서 사이트의 스크린샷으로 아이콘을 만들었습니다. 이제 iOS 및 iPadOS 16.4 베타 1에서는 사이트 이름의 첫 글자와 사이트의 색상을 사용하여 모노그램 아이콘을 생성하고 표시합니다.

웹사이트 또는 웹 앱에 사용할 아이콘을 제공하려면 매니페스트 파일에 아이콘을 나열하면 되는데, 이는 iOS 및 iPadOS 15.4부터 지원된 기능입니다. 또는 오랫동안 지원되어 온 기법인 HTML 문서 headapple-touch-icons을 나열하는 방법을 사용할 수 있습니다. (두 가지 방법을 모두 사용하는 경우 apple-touch-icon이 매니페스트에 선언된 아이콘보다 우선합니다.)

웹 앱을 위한 새로운 웹 API

웹 푸시, 배지 API, 매니페스트 ID 외에도 iOS 및 iPadOS 16.4 베타 1용 Webkit의 다른 많은 새로운 기능은 홈 화면 웹 앱에 중점을 둔 웹 앱 개발자에게 특히 흥미로울 것입니다. 여기에는 다음 사항들이 포함됩니다.

전체 기능 목록은 사파리 16.4 베타 1의 릴리즈 정보를 참조하세요.

+ \ No newline at end of file diff --git a/log/what-if-we-had-local-first-software.html b/log/what-if-we-had-local-first-software.html index a76b96e6..2ed79522 100644 --- a/log/what-if-we-had-local-first-software.html +++ b/log/what-if-we-had-local-first-software.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

로컬 우선 소프트웨어가 있다면 어떨까요?

원문: https://adlrocha.substack.com/p/adlrocha-what-if-we-had-local-first

gray crt tv turned on in a dark room

목요일에 진행되는 첫 번째 게시글에서는 여러분과 함께 "만약에" 연습을 해보고자 합니다. 이 "만약에"라는 기법은 Spotify("음악 라이브러리를 소유할 필요가 없다면?")나 Uber("모든 자동차가 잠재적으로 택시가 될 수 있다면?") 같은 회사들이 현재 사업 모델에 도달하기 위해 사용했던 기법이라고 합니다.

저희도 한 번 스스로에게 비슷한 질문을 해보죠. "만약 인터넷이 오프라인 우선이라면? 그리고 로컬 우선 소프트웨어가 오프라인 SaaS 모델로 가는 길을 열어준다면 어떨까요?" 실제로 이 논문("로컬 우선 소프트웨어: 클라우드임에도 불구하고 데이터를 소유하는 방법")의 저자들은 이 논문에서 이와 똑같은 질문을 제기했으며, 오늘 우리가 다루고자 하는 질문도 같습니다. 오프라인 우선 인터넷은 어떤 모습일까요?

비전 뒤에 숨은 원칙

"요즘 온라인에서 얼마나 쉽게 협업하는지를 보면 놀랍습니다. 구글 문서 도구를 사용해 문서, 스프레드시트, 프레젠테이션을 공동 작업하고, 피그마에서 사용자 인터페이스 디자인을 함께 작업합니다. 또한 슬랙을 사용하여 동료와 소통하고, 트렐로에서 작업을 추적하는 등 다양한 서비스를 이용합니다. 메모를 작성하고, 프로젝트나 이벤트를 계획하고, 연락처를 기억하는 등 다양한 업무 용도로 이러한 서비스와 기타 여러 온라인 서비스에 의존하고 있습니다."

클라우드 앱이 우리의 삶을 훨씬 더 편리하게 만들었다는 데 모두 동의합니다. 오늘날 우리가 사용하는 이러한 실시간 협업 클라우드 앱이 없었다면 효율적인 원격 근무는 불가능했을 것입니다. 그럼에도 불구하고 이러한 모든 애플리케이션은 여전히 몇 가지 불편함과 위협을 안고 있습니다. 몇 가지 예를 들면, 이러한 서비스에서 생성한 데이터의 소유자는 사용자가 아닙니다. 이러한 서비스를 제공하는 회사가 파산해 서버를 중단하면 어떻게 될까요? 게다가 이러한 서비스들은 모두 중앙 집중식 인프라에 의존하기 때문에 공격, 보안 침해, 서비스 중단에 취약합니다.

창의력을 발휘해 "오페라 프리마(역자 주: 문학, 영화 등 예술 분야에서 작가의 첫 작품을 의미)"를 거의 완성한 상태에서 서버에 장애가 발생해 모든 작업이 사라진다고 상상해 보세요. 또는 더 나쁜 경우(더 가능성이 높은 시나리오)로, 집에서 연결이 끊겨서 클라우드 서비스를 탓할 수도 없는 상황이라면 어떻게 될까요? 비행기나 인터넷 연결이 안정적이지 않은 곳에서 이러한 도구로 작업하는 사용자 경험은 말할 것도 없습니다. 실시간 협업은 우리의 삶을 크게 개선해 주었지만, 아마 이보다 더 나아질 수 있을 것입니다.

"요약하자면, 클라우드는 협업을 제공하지만, 구식 앱은 소유권을 제공합니다. 두 가지 장점을 모두 누릴 수는 없을까요? 클라우드 앱이 제공하는 편리한 기기 간 접근 및 실시간 협업, 그리고 '구식' 소프트웨어가 가지는 데이터에 대한 개인 소유권을 모두를요."

이것이 바로 원격 데이터 센터의 서버보다 로컬 스토리지(디바이스 내부)와 로컬 네트워크(가정용 Wi-Fi 등)를 우선적으로 사용하는 "로컬 우선 소프트웨어"의 근거입니다. 이러한 비전을 구축하는 것은 쉽지 않으며, 서버(또는 분산 스토리지와 릴레이. 무슨 말인지 아시겠죠? 😉)는 백업 및 상호 연결 목적으로 여전히 필요할 것입니다.

따라서 "로컬 우선 소프트웨어"의 의미를 평가하기 위해 이 논문에서 저자들은 다음과 같은 7가지 이상을 추구해야 한다고 정의합니다.

  • 로딩 스피너 없이, 바로 작업 가능합니다: 몇 년 전보다 더 강력한 디바이스를 사용하지만 소프트웨어는 점점 더 느려지고 오류가 발생하기 쉽다는 것을 모두 동의할 것입니다. "로컬 우선 소프트웨어"는 인터넷 의존도를 낮추고 로컬 스토리지를 사용하여 현재 소프트웨어보다 더 빨라져야 합니다.

  • 작업이 하나의 기기에 갇히지 않아야 합니다: 이건 어려운 문제입니다. 현재의 클라우드 앱이 모든 기기에서 원활하게 작업할 수 있게 해주는 것과 마찬가지로 "로컬 우선 소프트웨어"도 이를 가능하게 해야 합니다. 더 나아가 다른 사람(및 다른 사람의 기기)과 협업할 수 있어야 하므로 데이터가 내 기기에만 머물러서는 안 됩니다. 이를 실현하기 위해서는 장치 간의 안정적인 동기화 시스템이 필요합니다.

  • 물론 네트워크는 선택 사항입니다: 로컬 우선 애플리케이션은 데이터의 기본 복사본을 각 장치의 로컬 파일 시스템에 저장하기 때문에 사용자는 오프라인 상태에서도 언제든지 이 데이터를 읽고 쓸 수 있습니다. 나중에 네트워크 연결이 가능할 때 다른 장치와 동기화됩니다. 데이터 동기화가 반드시 인터넷을 통해 이루어질 필요는 없습니다: 로컬 우선 앱은 블루투스 또는 로컬 WiFi를 사용하여 주변 장치와 데이터를 동기화할 수도 있습니다. 또한, 원활한 오프라인 지원을 위해서는 소프트웨어가 웹 브라우저의 탭이 아닌 장치에 로컬로 설치된 실행 파일로 실행되는 것이 바람직합니다. 웹 앱이 오프라인에서 작동하도록 설정하는 것은 가능하지만, 사용자가 애플리케이션에 필요한 모든 코드와 데이터가 다운로드되었는지 여부를 알기는 어려울 수 있습니다. 모바일 앱의 경우 앱을 사용하기 전에 전체 앱을 다운로드하여 설치하는 것이 이미 표준입니다.

  • 원활한 협업이 가능해야 합니다: 이 원칙을 논문에 있는 몇 가지 매력적인 이미지로 설명해 보겠습니다. 간단히 말하면, 충돌, 충돌, 그리고 더 많은 충돌입니다. 이런 경험을 해보지 않은 사람이 있을까요?

개인적으로 가장 마음에 드는(그리고 "로컬 우선 애플리케이션"에 포함할 수 있다고 생각하는) 협업 방식은 git 방식입니다. 로컬 버전의 코드에서 작업하고 주기적으로 변경 사항을 저장소에 푸시하여 모든 사람이 사용할 수 있도록 합니다. 현재 이 작업은 개발자가 수동으로 수행하지만 애플리케이션 기본 코드에서 자동화하여 네트워크에 연결할 수 있을 때마다 디바이스가 새로운 변경 사항을 푸시하도록 할 수 있습니다. 물론 이렇게 한다고 해서 충돌이 발생하지 않는 것은 아니지만, 해결할 수 있는 방법을 우리는 이미 알고 있습니다.

  • 데이터를 장기 보관할 수 있어야 합니다: 데이터는 오래 보관되어야 합니다. 로컬 디바이스에 저장되고 다른 디바이스에도 동기화될 수 있으니 로컬 우선 앱이 완벽하다고 할 수 있습니다.

  • 기본적으로 보안 및 개인정보가 보호되어야 합니다: 즉, 내 기기(및 내가 상호작용하는 기기)의 데이터와 채널이 암호화됩니다.

  • 사용자가 최종 소유권 및 통제권을 보유해야 합니다: 많은 경우 사용자가 원하지 않는 책임입니다. 그렇기 때문에 중앙집중식 백업 서버, 분산형 스토리지 등과 같은 폴백 시스템이 존재해야 하며, 디지털 생활에 대한 책임이 부담스러운 사용자는 자신의 소유권을 다른 사람에게 위임할 수 있습니다.

그렇다면 현재 클라우드 애플리케이션들은 이러한 원칙을 얼마나 충족하고 있을까요?

좋지는 않습니다..

이를 가능하게 하는 기술

"웹 브라우저를 오프라인 친화적으로 만들기 위한 많은 노력(매니페스트, 로컬 스토리지, 서비스 워커, 프로그레시브 웹 앱 등)에도 불구하고 웹 앱의 아키텍처는 여전히 근본적으로 서버 중심적입니다. 대부분의 웹 앱에서 오프라인 지원은 나중에 고려해야 할 사항이며, 따라서 그 결과도 취약합니다. 많은 웹 브라우저에서 사용자가 쿠키를 지우면 로컬 저장소의 모든 데이터도 삭제되는데, 이는 캐시에는 문제가 되지 않지만 브라우저의 로컬 스토리지는 장기적으로 중요한 데이터를 저장하는 데 적합하지 않습니다."

저의 글 "웹 앱을 오프라인에서 작동하게 만드는 방법"을 기억하시나요? 안타깝게도 제가 이 글에서 공유한 "오프라인" 설계는 로컬 우선 애플리케이션을 구축하기에는 여전히 너무 "서버 중심적"입니다. 상황을 어느정도 개선할 수는 있지만, 우리의 목표를 달성하고 7가지 원칙을 모두 충족하기에는 충분하지 않습니다.

그런 의미에서 CouchDB/PouchDB와 같이 서로 다른 장치 간에 오프라인 동기화 스토리지를 구현하는 데 철학적으로 이미 도움이 되는 기술이 있습니다.

"CouchDB는 다중 마스터 복제 방식을 개척한 것으로 유명한 데이터베이스입니다. 여러 대의 컴퓨터가 각각 데이터베이스의 완전한 복사본을 가지고 있고, 각 복제본이 독립적으로 데이터를 변경할 수 있으며, 모든 복제본 쌍이 서로 동기화하여 최신 변경 사항을 교환할 수 있습니다. CouchDB는 서버에서 사용하도록 설계되었으며, Cloudant는 호스팅 버전을 제공하고, PouchDB와 Hoodie는 동일한 동기화 프로토콜을 사용하지만 최종 사용자 장치에서 실행되도록 설계된 형제 프로젝트입니다."

하지만, 이것만으로 우리의 모든 원칙을 충족시키기에 충분하지 않습니다. CouchDB에서는 애플리케이션 코드를 통해 충돌을 명시적으로 해결해야 합니다.(특정 시나리오에서는 쉬운 일이 아닙니다.)

그렇다면 현재 우리 고민 지점에 필요한 협업 및 충돌 해결을 제공할 수 있는 기술이 있을까요? 다행히도 있습니다. 충돌 없는 복제 데이터 유형(일명 CRDT) 을 소개해 드리겠습니다.

CRDT는 해시 맵이나 리스트 같은 범용 데이터 구조이지만, 처음부터 다중 사용자를 가정했다는 특별한 특징이 있습니다.

위의 이미지로 CRDT를 설명해 보겠습니다. 데이터 저장소가 동일한 초기 상태인 두 개의 디바이스가 있습니다. 각각의 디바이스는 데이터에 대해 독립적인 업데이트를 수행합니다. CRDT 구조는 이러한 변경 사항을 업데이트 작업으로 등록하여 두 장치 간에 네트워크 통신이 가능하면 해당 업데이트를 교환하고 병합하여 데이터 구조의 공통 상태에 도달할 수 있도록 합니다. CRDT가 자동으로 해결할 수 없는 유일한 변경 유형은 여러 사용자가 동시에 동일한 객체의 동일한 속성을 업데이트하는 경우이며, 이 경우 CRDT는 충돌하는 값을 추적하고 애플리케이션이나 사용자가 해결하도록 남겨 둡니다. 따라서 결국 충돌을 피하는 방법은 이러한 다중 사용자 수정을 최대한 방지하도록 CRDT 데이터 구조를 현명하게 설계하는 것입니다.

"CRDT는 텍스트 파일보다 더 다양한 데이터 유형에서 작동한다는 점을 제외하면 Git과 같은 버전 관리 시스템과 어느 정도 유사합니다. CRDT는 모든 통신 채널 (예: 서버, P2P 연결, 로컬 장치 간 블루투스, USB 스틱 등)을 통해 상태를 동기화할 수 있습니다. CRDT가 추적하는 변경 사항은 한 번의 키 입력만큼 작을 수 있으므로 구글 문서 도구 스타일의 실시간 협업이 가능합니다. 하지만 더 큰 변경 집합을 수집하여 Git의 풀 리퀘스트처럼 공동 작업자에게 일괄적으로 보낼 수도 있습니다. 데이터 구조가 범용이기 때문에 CRDT의 저장, 통신 및 관리를 위한 범용 도구를 개발할 수 있어 모든 앱에서 이러한 기능을 다시 구현할 필요가 없습니다."

CRDT는 제가 열광하는 분야이며, 이미 Atom 에디터의 Teletype(P2P 코드 협업용)과 같이 그 활용을 탐구하는 애플리케이션이 있습니다. 논문 저자 중 한 명이 만든 이 동영상을 통해 CRDT에 대해 알아보는 것을 적극 추천합니다. 조만간 CRDT에 대한 뉴스레터 발행을 기대해 주세요.

몇 가지 개념 증명

이 논문에서는 협업 칸반 보드 또는 협업 드로잉 앱과 같은 "로컬 우선 애플리케이션" 구현에 대한 몇 가지 PoC를 공유합니다.

이러한 앱의 구현과 사용을 통해 다음과 같은 결론을 도출했습니다.

  • CRDT 기술은 작동합니다.
  • 오프라인 작업에 대한 사용자 경험은 훌륭합니다.
  • 함수형 반응형 프로그래밍과 결합하면 개발자 경험을 향상할 수 있습니다.
  • 충돌은 우려했던 것만큼 큰 문제가 되지 않습니다.
  • 문서 히스토리를 시각화하는 것이 중요합니다.
  • URL은 공유를 위한 좋은 메커니즘입니다.
  • P2P 시스템은 완전한 "온라인"이나 "오프라인"이 아니며, 그 안에서 데이터가 어떻게 이동하는지 추론하기 어려울 수 있습니다.
  • CRDT는 대량의 변경 이력을 축적하여 성능 문제를 일으킵니다.
  • 클라우드 서버는 여전히 검색, 백업, 버스트 컴퓨팅을 위한 최적의 장소입니다.
  • 네트워크 통신은 여전히 해결되지 않은 문제로 남아 있습니다.

CRDT에는 P2P 네트워킹 계층이 필요하지 않으며, 통신을 위해 서버를 사용하는 것도 괜찮습니다. 하지만 로컬 우선 소프트웨어의 장기 목표를 완전히 실현하려면 애플리케이션이 공급업체가 관리하는 모든 백엔드 서비스보다 오래 지속되기를 원하므로 분산형 솔루션이 논리적 최종 목표입니다.

프로토타입에 P2P 기술을 사용한 것은 엇갈린 결과를 얻었습니다. 한편으로는 이러한 기술들이 아직 프로덕션에 적용할 수 있는 단계에 이르지 못했습니다. 특히 또 다른 흥미로운 연구 및 탐색 분야인 NAT 통과는 사용자가 현재 연결되어 있는 특정 라우터나 네트워크 토폴로지에 따라 불안정할 수 있습니다. 하지만 P2P 프로토콜과 분산형 웹 커뮤니티가 제시하는 약속은 상당합니다. 인터넷에 접속할 수 없는 컴퓨터 간의 실시간 협업은 중앙화된 API에 의존하게 된 세상에서 마법처럼 느껴집니다.

미래를 내다보며

이제 몇 주 전에 제가 발행한 글 새로운 인터넷에 대한 저의 비전을 바탕으로 "만약에"라는 상상을 극단적으로 확장해 보겠습니다. "로컬 우선 애플리케이션"은 UX, 보안 및 개인 정보 보호 측면에서 우리가 마땅히 누려야 할 인터넷으로의 도약처럼 보입니다. 논문 저자에 따르면 네트워크 통신은 여전히 해결되지 않은 문제로 남아있습니다. 하지만.. 해결이 될 수도 있지 않을까요? web3 분야에서는 "로컬 우선 애플리케이션"이 제기하는 문제에 대한 많은 해결책을 모색하고 있습니다(그리고 그중 상당수는 이미 해결되었을 수도 있습니다).

  • 데이터 저장에 대한 책임을 지고 싶지 않다면 어떻게 해야 하나요? 분산형 스토리지(Filecoin)를 이용하면 됩니다.
  • 내 기기에 특정 작업을 실행하기에 충분한 연산 능력이 없다면 어떻게 하나요? 탈중앙화 컴퓨팅 서비스(Golem)으로 시작하세요.
  • NAT 뒤에 있는 장치와 통신하려면 어떻게 해야 하나요? libp2p, NAT 통과, 인센티브 릴레이 등을 사용합니다. 이것은 제가 아는 한 가장 활발하지 않은 "진행 중인 작업" 중 하나 일 수 있습니다.
  • 홈 연결을 통해 인터넷 연결 없이 어떻게 통신할 수 있을까요? 와이파이 오프로딩, 메시 네트워크 등..이 있습니다.

최근에 본 트윗을 인용하며 마치겠습니다. "탈중앙화된 웹의 대부분은 '전혀' 말이 되지 않으며, 말이 되는 극히 일부분은 매우 소중하고 훌륭합니다." 우리가 만들고 있는 이 소중하고 멋진 소프트웨어로 새로운 인터넷으로 가는 길을 닦아봅시다.

- +
Skip to content
On this page

로컬 우선 소프트웨어가 있다면 어떨까요?

원문: https://adlrocha.substack.com/p/adlrocha-what-if-we-had-local-first

gray crt tv turned on in a dark room

목요일에 진행되는 첫 번째 게시글에서는 여러분과 함께 "만약에" 연습을 해보고자 합니다. 이 "만약에"라는 기법은 Spotify("음악 라이브러리를 소유할 필요가 없다면?")나 Uber("모든 자동차가 잠재적으로 택시가 될 수 있다면?") 같은 회사들이 현재 사업 모델에 도달하기 위해 사용했던 기법이라고 합니다.

저희도 한 번 스스로에게 비슷한 질문을 해보죠. "만약 인터넷이 오프라인 우선이라면? 그리고 로컬 우선 소프트웨어가 오프라인 SaaS 모델로 가는 길을 열어준다면 어떨까요?" 실제로 이 논문("로컬 우선 소프트웨어: 클라우드임에도 불구하고 데이터를 소유하는 방법")의 저자들은 이 논문에서 이와 똑같은 질문을 제기했으며, 오늘 우리가 다루고자 하는 질문도 같습니다. 오프라인 우선 인터넷은 어떤 모습일까요?

비전 뒤에 숨은 원칙

"요즘 온라인에서 얼마나 쉽게 협업하는지를 보면 놀랍습니다. 구글 문서 도구를 사용해 문서, 스프레드시트, 프레젠테이션을 공동 작업하고, 피그마에서 사용자 인터페이스 디자인을 함께 작업합니다. 또한 슬랙을 사용하여 동료와 소통하고, 트렐로에서 작업을 추적하는 등 다양한 서비스를 이용합니다. 메모를 작성하고, 프로젝트나 이벤트를 계획하고, 연락처를 기억하는 등 다양한 업무 용도로 이러한 서비스와 기타 여러 온라인 서비스에 의존하고 있습니다."

클라우드 앱이 우리의 삶을 훨씬 더 편리하게 만들었다는 데 모두 동의합니다. 오늘날 우리가 사용하는 이러한 실시간 협업 클라우드 앱이 없었다면 효율적인 원격 근무는 불가능했을 것입니다. 그럼에도 불구하고 이러한 모든 애플리케이션은 여전히 몇 가지 불편함과 위협을 안고 있습니다. 몇 가지 예를 들면, 이러한 서비스에서 생성한 데이터의 소유자는 사용자가 아닙니다. 이러한 서비스를 제공하는 회사가 파산해 서버를 중단하면 어떻게 될까요? 게다가 이러한 서비스들은 모두 중앙 집중식 인프라에 의존하기 때문에 공격, 보안 침해, 서비스 중단에 취약합니다.

창의력을 발휘해 "오페라 프리마(역자 주: 문학, 영화 등 예술 분야에서 작가의 첫 작품을 의미)"를 거의 완성한 상태에서 서버에 장애가 발생해 모든 작업이 사라진다고 상상해 보세요. 또는 더 나쁜 경우(더 가능성이 높은 시나리오)로, 집에서 연결이 끊겨서 클라우드 서비스를 탓할 수도 없는 상황이라면 어떻게 될까요? 비행기나 인터넷 연결이 안정적이지 않은 곳에서 이러한 도구로 작업하는 사용자 경험은 말할 것도 없습니다. 실시간 협업은 우리의 삶을 크게 개선해 주었지만, 아마 이보다 더 나아질 수 있을 것입니다.

"요약하자면, 클라우드는 협업을 제공하지만, 구식 앱은 소유권을 제공합니다. 두 가지 장점을 모두 누릴 수는 없을까요? 클라우드 앱이 제공하는 편리한 기기 간 접근 및 실시간 협업, 그리고 '구식' 소프트웨어가 가지는 데이터에 대한 개인 소유권을 모두를요."

이것이 바로 원격 데이터 센터의 서버보다 로컬 스토리지(디바이스 내부)와 로컬 네트워크(가정용 Wi-Fi 등)를 우선적으로 사용하는 "로컬 우선 소프트웨어"의 근거입니다. 이러한 비전을 구축하는 것은 쉽지 않으며, 서버(또는 분산 스토리지와 릴레이. 무슨 말인지 아시겠죠? 😉)는 백업 및 상호 연결 목적으로 여전히 필요할 것입니다.

따라서 "로컬 우선 소프트웨어"의 의미를 평가하기 위해 이 논문에서 저자들은 다음과 같은 7가지 이상을 추구해야 한다고 정의합니다.

  • 로딩 스피너 없이, 바로 작업 가능합니다: 몇 년 전보다 더 강력한 디바이스를 사용하지만 소프트웨어는 점점 더 느려지고 오류가 발생하기 쉽다는 것을 모두 동의할 것입니다. "로컬 우선 소프트웨어"는 인터넷 의존도를 낮추고 로컬 스토리지를 사용하여 현재 소프트웨어보다 더 빨라져야 합니다.

  • 작업이 하나의 기기에 갇히지 않아야 합니다: 이건 어려운 문제입니다. 현재의 클라우드 앱이 모든 기기에서 원활하게 작업할 수 있게 해주는 것과 마찬가지로 "로컬 우선 소프트웨어"도 이를 가능하게 해야 합니다. 더 나아가 다른 사람(및 다른 사람의 기기)과 협업할 수 있어야 하므로 데이터가 내 기기에만 머물러서는 안 됩니다. 이를 실현하기 위해서는 장치 간의 안정적인 동기화 시스템이 필요합니다.

  • 물론 네트워크는 선택 사항입니다: 로컬 우선 애플리케이션은 데이터의 기본 복사본을 각 장치의 로컬 파일 시스템에 저장하기 때문에 사용자는 오프라인 상태에서도 언제든지 이 데이터를 읽고 쓸 수 있습니다. 나중에 네트워크 연결이 가능할 때 다른 장치와 동기화됩니다. 데이터 동기화가 반드시 인터넷을 통해 이루어질 필요는 없습니다: 로컬 우선 앱은 블루투스 또는 로컬 WiFi를 사용하여 주변 장치와 데이터를 동기화할 수도 있습니다. 또한, 원활한 오프라인 지원을 위해서는 소프트웨어가 웹 브라우저의 탭이 아닌 장치에 로컬로 설치된 실행 파일로 실행되는 것이 바람직합니다. 웹 앱이 오프라인에서 작동하도록 설정하는 것은 가능하지만, 사용자가 애플리케이션에 필요한 모든 코드와 데이터가 다운로드되었는지 여부를 알기는 어려울 수 있습니다. 모바일 앱의 경우 앱을 사용하기 전에 전체 앱을 다운로드하여 설치하는 것이 이미 표준입니다.

  • 원활한 협업이 가능해야 합니다: 이 원칙을 논문에 있는 몇 가지 매력적인 이미지로 설명해 보겠습니다. 간단히 말하면, 충돌, 충돌, 그리고 더 많은 충돌입니다. 이런 경험을 해보지 않은 사람이 있을까요?

개인적으로 가장 마음에 드는(그리고 "로컬 우선 애플리케이션"에 포함할 수 있다고 생각하는) 협업 방식은 git 방식입니다. 로컬 버전의 코드에서 작업하고 주기적으로 변경 사항을 저장소에 푸시하여 모든 사람이 사용할 수 있도록 합니다. 현재 이 작업은 개발자가 수동으로 수행하지만 애플리케이션 기본 코드에서 자동화하여 네트워크에 연결할 수 있을 때마다 디바이스가 새로운 변경 사항을 푸시하도록 할 수 있습니다. 물론 이렇게 한다고 해서 충돌이 발생하지 않는 것은 아니지만, 해결할 수 있는 방법을 우리는 이미 알고 있습니다.

  • 데이터를 장기 보관할 수 있어야 합니다: 데이터는 오래 보관되어야 합니다. 로컬 디바이스에 저장되고 다른 디바이스에도 동기화될 수 있으니 로컬 우선 앱이 완벽하다고 할 수 있습니다.

  • 기본적으로 보안 및 개인정보가 보호되어야 합니다: 즉, 내 기기(및 내가 상호작용하는 기기)의 데이터와 채널이 암호화됩니다.

  • 사용자가 최종 소유권 및 통제권을 보유해야 합니다: 많은 경우 사용자가 원하지 않는 책임입니다. 그렇기 때문에 중앙집중식 백업 서버, 분산형 스토리지 등과 같은 폴백 시스템이 존재해야 하며, 디지털 생활에 대한 책임이 부담스러운 사용자는 자신의 소유권을 다른 사람에게 위임할 수 있습니다.

그렇다면 현재 클라우드 애플리케이션들은 이러한 원칙을 얼마나 충족하고 있을까요?

좋지는 않습니다..

이를 가능하게 하는 기술

"웹 브라우저를 오프라인 친화적으로 만들기 위한 많은 노력(매니페스트, 로컬 스토리지, 서비스 워커, 프로그레시브 웹 앱 등)에도 불구하고 웹 앱의 아키텍처는 여전히 근본적으로 서버 중심적입니다. 대부분의 웹 앱에서 오프라인 지원은 나중에 고려해야 할 사항이며, 따라서 그 결과도 취약합니다. 많은 웹 브라우저에서 사용자가 쿠키를 지우면 로컬 저장소의 모든 데이터도 삭제되는데, 이는 캐시에는 문제가 되지 않지만 브라우저의 로컬 스토리지는 장기적으로 중요한 데이터를 저장하는 데 적합하지 않습니다."

저의 글 "웹 앱을 오프라인에서 작동하게 만드는 방법"을 기억하시나요? 안타깝게도 제가 이 글에서 공유한 "오프라인" 설계는 로컬 우선 애플리케이션을 구축하기에는 여전히 너무 "서버 중심적"입니다. 상황을 어느정도 개선할 수는 있지만, 우리의 목표를 달성하고 7가지 원칙을 모두 충족하기에는 충분하지 않습니다.

그런 의미에서 CouchDB/PouchDB와 같이 서로 다른 장치 간에 오프라인 동기화 스토리지를 구현하는 데 철학적으로 이미 도움이 되는 기술이 있습니다.

"CouchDB는 다중 마스터 복제 방식을 개척한 것으로 유명한 데이터베이스입니다. 여러 대의 컴퓨터가 각각 데이터베이스의 완전한 복사본을 가지고 있고, 각 복제본이 독립적으로 데이터를 변경할 수 있으며, 모든 복제본 쌍이 서로 동기화하여 최신 변경 사항을 교환할 수 있습니다. CouchDB는 서버에서 사용하도록 설계되었으며, Cloudant는 호스팅 버전을 제공하고, PouchDB와 Hoodie는 동일한 동기화 프로토콜을 사용하지만 최종 사용자 장치에서 실행되도록 설계된 형제 프로젝트입니다."

하지만, 이것만으로 우리의 모든 원칙을 충족시키기에 충분하지 않습니다. CouchDB에서는 애플리케이션 코드를 통해 충돌을 명시적으로 해결해야 합니다.(특정 시나리오에서는 쉬운 일이 아닙니다.)

그렇다면 현재 우리 고민 지점에 필요한 협업 및 충돌 해결을 제공할 수 있는 기술이 있을까요? 다행히도 있습니다. 충돌 없는 복제 데이터 유형(일명 CRDT) 을 소개해 드리겠습니다.

CRDT는 해시 맵이나 리스트 같은 범용 데이터 구조이지만, 처음부터 다중 사용자를 가정했다는 특별한 특징이 있습니다.

위의 이미지로 CRDT를 설명해 보겠습니다. 데이터 저장소가 동일한 초기 상태인 두 개의 디바이스가 있습니다. 각각의 디바이스는 데이터에 대해 독립적인 업데이트를 수행합니다. CRDT 구조는 이러한 변경 사항을 업데이트 작업으로 등록하여 두 장치 간에 네트워크 통신이 가능하면 해당 업데이트를 교환하고 병합하여 데이터 구조의 공통 상태에 도달할 수 있도록 합니다. CRDT가 자동으로 해결할 수 없는 유일한 변경 유형은 여러 사용자가 동시에 동일한 객체의 동일한 속성을 업데이트하는 경우이며, 이 경우 CRDT는 충돌하는 값을 추적하고 애플리케이션이나 사용자가 해결하도록 남겨 둡니다. 따라서 결국 충돌을 피하는 방법은 이러한 다중 사용자 수정을 최대한 방지하도록 CRDT 데이터 구조를 현명하게 설계하는 것입니다.

"CRDT는 텍스트 파일보다 더 다양한 데이터 유형에서 작동한다는 점을 제외하면 Git과 같은 버전 관리 시스템과 어느 정도 유사합니다. CRDT는 모든 통신 채널 (예: 서버, P2P 연결, 로컬 장치 간 블루투스, USB 스틱 등)을 통해 상태를 동기화할 수 있습니다. CRDT가 추적하는 변경 사항은 한 번의 키 입력만큼 작을 수 있으므로 구글 문서 도구 스타일의 실시간 협업이 가능합니다. 하지만 더 큰 변경 집합을 수집하여 Git의 풀 리퀘스트처럼 공동 작업자에게 일괄적으로 보낼 수도 있습니다. 데이터 구조가 범용이기 때문에 CRDT의 저장, 통신 및 관리를 위한 범용 도구를 개발할 수 있어 모든 앱에서 이러한 기능을 다시 구현할 필요가 없습니다."

CRDT는 제가 열광하는 분야이며, 이미 Atom 에디터의 Teletype(P2P 코드 협업용)과 같이 그 활용을 탐구하는 애플리케이션이 있습니다. 논문 저자 중 한 명이 만든 이 동영상을 통해 CRDT에 대해 알아보는 것을 적극 추천합니다. 조만간 CRDT에 대한 뉴스레터 발행을 기대해 주세요.

몇 가지 개념 증명

이 논문에서는 협업 칸반 보드 또는 협업 드로잉 앱과 같은 "로컬 우선 애플리케이션" 구현에 대한 몇 가지 PoC를 공유합니다.

이러한 앱의 구현과 사용을 통해 다음과 같은 결론을 도출했습니다.

  • CRDT 기술은 작동합니다.
  • 오프라인 작업에 대한 사용자 경험은 훌륭합니다.
  • 함수형 반응형 프로그래밍과 결합하면 개발자 경험을 향상할 수 있습니다.
  • 충돌은 우려했던 것만큼 큰 문제가 되지 않습니다.
  • 문서 히스토리를 시각화하는 것이 중요합니다.
  • URL은 공유를 위한 좋은 메커니즘입니다.
  • P2P 시스템은 완전한 "온라인"이나 "오프라인"이 아니며, 그 안에서 데이터가 어떻게 이동하는지 추론하기 어려울 수 있습니다.
  • CRDT는 대량의 변경 이력을 축적하여 성능 문제를 일으킵니다.
  • 클라우드 서버는 여전히 검색, 백업, 버스트 컴퓨팅을 위한 최적의 장소입니다.
  • 네트워크 통신은 여전히 해결되지 않은 문제로 남아 있습니다.

CRDT에는 P2P 네트워킹 계층이 필요하지 않으며, 통신을 위해 서버를 사용하는 것도 괜찮습니다. 하지만 로컬 우선 소프트웨어의 장기 목표를 완전히 실현하려면 애플리케이션이 공급업체가 관리하는 모든 백엔드 서비스보다 오래 지속되기를 원하므로 분산형 솔루션이 논리적 최종 목표입니다.

프로토타입에 P2P 기술을 사용한 것은 엇갈린 결과를 얻었습니다. 한편으로는 이러한 기술들이 아직 프로덕션에 적용할 수 있는 단계에 이르지 못했습니다. 특히 또 다른 흥미로운 연구 및 탐색 분야인 NAT 통과는 사용자가 현재 연결되어 있는 특정 라우터나 네트워크 토폴로지에 따라 불안정할 수 있습니다. 하지만 P2P 프로토콜과 분산형 웹 커뮤니티가 제시하는 약속은 상당합니다. 인터넷에 접속할 수 없는 컴퓨터 간의 실시간 협업은 중앙화된 API에 의존하게 된 세상에서 마법처럼 느껴집니다.

미래를 내다보며

이제 몇 주 전에 제가 발행한 글 새로운 인터넷에 대한 저의 비전을 바탕으로 "만약에"라는 상상을 극단적으로 확장해 보겠습니다. "로컬 우선 애플리케이션"은 UX, 보안 및 개인 정보 보호 측면에서 우리가 마땅히 누려야 할 인터넷으로의 도약처럼 보입니다. 논문 저자에 따르면 네트워크 통신은 여전히 해결되지 않은 문제로 남아있습니다. 하지만.. 해결이 될 수도 있지 않을까요? web3 분야에서는 "로컬 우선 애플리케이션"이 제기하는 문제에 대한 많은 해결책을 모색하고 있습니다(그리고 그중 상당수는 이미 해결되었을 수도 있습니다).

  • 데이터 저장에 대한 책임을 지고 싶지 않다면 어떻게 해야 하나요? 분산형 스토리지(Filecoin)를 이용하면 됩니다.
  • 내 기기에 특정 작업을 실행하기에 충분한 연산 능력이 없다면 어떻게 하나요? 탈중앙화 컴퓨팅 서비스(Golem)으로 시작하세요.
  • NAT 뒤에 있는 장치와 통신하려면 어떻게 해야 하나요? libp2p, NAT 통과, 인센티브 릴레이 등을 사용합니다. 이것은 제가 아는 한 가장 활발하지 않은 "진행 중인 작업" 중 하나 일 수 있습니다.
  • 홈 연결을 통해 인터넷 연결 없이 어떻게 통신할 수 있을까요? 와이파이 오프로딩, 메시 네트워크 등..이 있습니다.

최근에 본 트윗을 인용하며 마치겠습니다. "탈중앙화된 웹의 대부분은 '전혀' 말이 되지 않으며, 말이 되는 극히 일부분은 매우 소중하고 훌륭합니다." 우리가 만들고 있는 이 소중하고 멋진 소프트웨어로 새로운 인터넷으로 가는 길을 닦아봅시다.

+ \ No newline at end of file diff --git a/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.html b/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.html index da2c2337..3ab2eeec 100644 --- a/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.html +++ b/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

2023년 Vue에게 기대할 수 있는 점과 React와의 차이점

원문: https://thenewstack.io/vue-2023/

Vue.js 제작자 Evan You가 Vue 3가 Vue 2와 무엇이 다른지, 특히 가상 DOM의 사용이 어떻게 발전했는지 설명합니다.

Featued image for: What to Expect from Vue in 2023 and How it Differs from React

2년 전 자바스크립트 프레임워크인 Vue.js에 관한 다큐멘터리에서 이 프레임워크는 자바스크립트 생태계 주요 프레임워크인 페이스북의 React와 구글의 Angular에 비해 일종의 인디 대안으로 묘사되었습니다. "덜 기업적이고 [...] 더 서민적인 느낌입니다."라고 한 강연자가 설명했습니다.

가장 트렌디한 자바스크립트 프레임워크인 React와 비교했을 때 가장 눈에 띄는 차이점은 웹 표준 옹호자들이 Vue를 지지한다는 점입니다. 그 이유에 대한 단서는 Vue의 공식 문서에서 찾을 수 있는데, 문서에서는 "React에서는 모든 것이 자바스크립트일 뿐입니다. HTML 구조는 JSX를 통해 표현될 뿐만 아니라 최근에는 CSS 관리도 자바스크립트 안에 넣는 추세입니다."라고 설명합니다. 반면에 Vue는 "고전적인 웹 기술을 수용하고 그 위에 구축한다"고 말합니다. (참고: 해당 인용문은 Vue 2 문서에서 발췌한 것으로, 최신 Vue 3 문서에서는 이 비교를 찾을 수 없었습니다.)

최근 몇 년 동안 React의 자바스크립트 중심 접근 방식과 이를 사용하는 프레임워크(예: Next.js)에 대한 반발이 많았고, Vue, Svelte, Lit와 같은 프레임워크가 제공하는 "고전적인 웹 기술" 위에 구축하려는 움직임이 있었습니다.

Evan You의 State of the Vuenion

이러한 맥락에서 이번 달(2023년 2월 16일 기준) 암스테르담에서 열린 JSworld 컨퍼런스에서 오프라인 및 온라인으로 진행된 연례 "State of the Vuenion"(역자 주: Evan You가 매년 Vue 생태계에 대한 개요 및 새로운 업데이트, 개발 현황을 발표하는 컨퍼런스) 발표에서 Vue 제작자 Evan You가 어떤 말을 했는지 궁금했습니다.

Evan You는 팬데믹으로 인해 3년 전을 마지막으로 JSworld에 직접 참석하지 못했다는 점을 언급하며 기조연설을 시작했습니다. 그래서 그는 3년 전에는 Vue 생태계에 존재하지 않았거나 아직 안정적이지 않았던 것들을 나열했습니다: Vue 3는 "안정적이지 않았고", Vite(빌드 도구), Volar("임베디드 프로그래밍 언어 도구 구축을 위한 프레임워크"), Pinia("Vue 생태계를 위한 상태 관리 라이브러리")가 존재하지 않았습니다.

그는 "우리는 본질적으로 Vite를 중심으로 완전히 새로운 생태계를 만들었습니다."라고 말하며, "이와 함께 Vue 생태계 내에서뿐만 아니라 다른 모든 프레임워크와도 연결되는 새롭고 흥미로운 모든 것들을 그 위에 구축하였습니다."라고 덧붙였습니다.

https://cdn.thenewstack.io/media/2023/02/76621bfd-vue3_ecosystem.jpgVue 생태계

Evan You는 Vue 애플리케이션을 구축하기 위한 기본 프레임워크인 Nuxt를 필두로 현재 Vue 도구 생태계에 찬사를 보냈습니다. 그러나 계속해서 Vue 3를 안정적으로 만드는 것이 2023년의 주된 관심사라고 말했습니다. 1년 전인 지난 2월에 Vue 3가 새로운 기본 버전이 되었지만, "레거시 프로젝트"라고 불리는 프로젝트에서는 여전히 Vue 2를 사용하고 있습니다. 그는 Vue 3 채택의 대부분이 "신규 프로젝트"에서 이루어졌다고 언급했습니다.

Evan You는 "우리는 아직 Vue 2에서 Vue 3로 전환하는 단계에 있습니다."라고 말하며 많은 대형 프로젝트가 여전히 Vue 2를 사용 중이거나 Vue 3로 전환할 계획을 세우고 있다고 지적했습니다.

Vue 3와 가상 DOM에 대한 새로운 접근 방식

올해 Vue 3에서 계획된 다양한 관리상의 변경에 대해 논의한 후, Evan You는 Vue 2와 비교하여 Vue 3가 "렌더링"하는 방식의 차이점에 대해 설명하는 시간을 가졌습니다. "렌더링 전략은 시간이 지남에 따라 변화하고 있습니다."라고 말하며 특히 가상 DOM(VDOM)을 처리하는 방식에 대해 언급했습니다.

그 얘기를 하기 전에 Vue 3를 이해하는 데 도움이 될 만한 VDOM에 대한 간략한 소개를 하겠습니다. 이 날 JSworld의 다른 세션에서 Marc Backes가 "가상 DOM을 만들어 봅시다."라는 제목의 세션을 진행했습니다. 다음 세 개의 슬라이드는 VDOM이 무엇이며 Vue와 같은 프레임워크 내에서 그 목적이 무엇인지 잘 요약해 줍니다. (VDOM은 React에 의해 대중화되었지만, Vue를 포함한 다른 많은 프레임워크에서도 이 개념을 채택하고 있습니다).

https://cdn.thenewstack.io/media/2023/02/3eb464b9-vdom1.jpg가상 DOM이란 무엇인가

https://cdn.thenewstack.io/media/2023/02/8b42c599-vdom2.jpg왜 가상 DOM을 사용하는가

https://cdn.thenewstack.io/media/2023/02/29695806-vdom4.jpg가상 DOM을 만들어 보기

Backes는 또한 Vue에서 사용하는 렌더링 파이프라인을 다음과 같이 시각적으로 표현했습니다(Vue 문서에 있는 동일한 다이어그램을 다양한 색깔로 표현한 버전입니다).

https://cdn.thenewstack.io/media/2023/02/8e1beaff-vdom3.jpgVue 렌더링 파이프라인

다시 Evan You의 발표 내용으로 돌아가보겠습니다. 그는 "Vue 2에서는 순수 가상 DOM을 사용했는데, 이는 [...] React가 사용하는 것과 유사하며 컴파일 타임 최적화를 수행하지 않는다는 것을 의미합니다. 전혀 최적화하지 않는 건 아니지만 거의 하지 않습니다."라고 말했습니다.

https://cdn.thenewstack.io/media/2023/02/b58f5f5f-vue2_diagram.jpgVue 2 렌더링

"따라서 컴포넌트 트리 또는 앱 수준에서는 각 컴포넌트가 자체 종속성을 추적하도록 하여 세분화된 업데이트를 수행할 수 있습니다."라고 그는 Vue 2에 관해 설명합니다.

단점은 가상 DOM 오버헤드인데, 그는 이를 "가상 DOM 노드를 다시 생성한 다음 해당 트리를 통해 차이를 확인하는 데 드는 비용"이라고 설명했습니다. 그는 "Vue 2는 이 오버헤드를 지속적으로 지불하고 있습니다."라고 덧붙였습니다.

이 문제를 해결하기 위해 Vue 3에서는 다른 접근 방식을 취했습니다. 그는 "컴파일러 정보에 기반한 가상 DOM"이라고 설명했는데, 이는 "컴파일 타임에 훨씬 더 많은 최적화를 수행"한다는 의미입니다.

https://cdn.thenewstack.io/media/2023/02/ca2632f4-vue3_diagram.jpgVue 3 렌더링

단일 파일 컴포넌트

VDOM의 복잡성은 차치하고서라도, Vue의 인기 상승에는 "단일 파일 컴포넌트(SFC)" 접근 방식이 큰 부분을 차지합니다. Vue는 SFC를 "Vue 컴포넌트의 템플릿, 로직, 스타일링을 단일 파일에 캡슐화할 수 있는 특수 파일 형식"으로 정의합니다. 다른 곳에서 Vue는 SFC를 "HTML과 유사한 파일 형식"이라고 부릅니다.

Vue 핵심 팀원인 Damian Dulisz와의 2017년 인터뷰에서 그는 SFC 형식을 통해 "코드를 이해하고 추론하기가 훨씬 더 쉬워졌다"라고 말했습니다.

The New Stack의 엔지니어링 디렉터인 Aaron Ban은 SFC 접근 방식으로 인해 Vue의 팬이 되었습니다. 그는 SFC 접근 방식이 제공하는 "깔끔한 조직"을 좋아하며, 또한 SFC 접근 방식이 모듈화의 훌륭한 예라고 생각합니다. "사실 SFC를 올바르게 수행하는 데 필요한 엄격한 커트라인을 스스로에게 강요하기는 어려운 훈련입니다."라고 그는 말했습니다. 하지만 그는 이것이 지난 10여 년 동안 많은 개발자가 배워온 '빨리빨리'라는 사고방식에 대한 해독제라고 생각합니다. 그는 이러한 사고방식은 개발자들이 "적절한 경계선을 그리는 데 신경 쓰지 않고 '나중에 고치면 된다'는 생각으로 '일단 작동만 시키면 된다'는 식의 나쁜 습관을 조장해 왔다"라고 말합니다.

Ban은 단일 파일 컴포넌트를 제공하는 다른 두 가지 프레임워크인 Svelte와 Lit의 디자인도 마음에 들어 합니다.

SFC가 개발자들에게 보편적으로 사랑받는 것은 아닙니다. Vue 문서에서도 이를 인정하고 있습니다. "전통적인 웹 개발 배경을 가진 일부 사용자는 SFC가 HTML/CSS/JS가 분리해야 할 서로 다른 관심사를 한 곳에 섞어 놓았다는 우려를 할 수 있습니다!"

이러한 반대 의견에 대해 Vue는 SFC 접근 방식이 "실제로 컴포넌트를 더 응집력 있고 유지 관리하기 쉽게 만든다"라고 주장합니다.

결론

Evan You의 JSworld 기조연설에 따르면 2023년에 Vue 개발자에게 큰 변화가 예상되지는 않을 것입니다. Vue 2에서 Vue 3로 업그레이드하도록 개발자를 계속 유도하는 것과 함께, 계속해서 확장되는 생태계에 대한 추가적인 개선이 이어질 것입니다.

Vue는 저희와 같은 기술 전문 매체에서는 그다지 주목 받지 못할 수도 있지만, 매년 이렇게 웹 표준을 준수하는 자바스크립트 프레임워크는 살펴 볼 가치가 있습니다. 우리는 확실히 Vue의 계속적인 발전을 즐기고 있습니다.

- +
Skip to content
On this page

2023년 Vue에게 기대할 수 있는 점과 React와의 차이점

원문: https://thenewstack.io/vue-2023/

Vue.js 제작자 Evan You가 Vue 3가 Vue 2와 무엇이 다른지, 특히 가상 DOM의 사용이 어떻게 발전했는지 설명합니다.

Featued image for: What to Expect from Vue in 2023 and How it Differs from React

2년 전 자바스크립트 프레임워크인 Vue.js에 관한 다큐멘터리에서 이 프레임워크는 자바스크립트 생태계 주요 프레임워크인 페이스북의 React와 구글의 Angular에 비해 일종의 인디 대안으로 묘사되었습니다. "덜 기업적이고 [...] 더 서민적인 느낌입니다."라고 한 강연자가 설명했습니다.

가장 트렌디한 자바스크립트 프레임워크인 React와 비교했을 때 가장 눈에 띄는 차이점은 웹 표준 옹호자들이 Vue를 지지한다는 점입니다. 그 이유에 대한 단서는 Vue의 공식 문서에서 찾을 수 있는데, 문서에서는 "React에서는 모든 것이 자바스크립트일 뿐입니다. HTML 구조는 JSX를 통해 표현될 뿐만 아니라 최근에는 CSS 관리도 자바스크립트 안에 넣는 추세입니다."라고 설명합니다. 반면에 Vue는 "고전적인 웹 기술을 수용하고 그 위에 구축한다"고 말합니다. (참고: 해당 인용문은 Vue 2 문서에서 발췌한 것으로, 최신 Vue 3 문서에서는 이 비교를 찾을 수 없었습니다.)

최근 몇 년 동안 React의 자바스크립트 중심 접근 방식과 이를 사용하는 프레임워크(예: Next.js)에 대한 반발이 많았고, Vue, Svelte, Lit와 같은 프레임워크가 제공하는 "고전적인 웹 기술" 위에 구축하려는 움직임이 있었습니다.

Evan You의 State of the Vuenion

이러한 맥락에서 이번 달(2023년 2월 16일 기준) 암스테르담에서 열린 JSworld 컨퍼런스에서 오프라인 및 온라인으로 진행된 연례 "State of the Vuenion"(역자 주: Evan You가 매년 Vue 생태계에 대한 개요 및 새로운 업데이트, 개발 현황을 발표하는 컨퍼런스) 발표에서 Vue 제작자 Evan You가 어떤 말을 했는지 궁금했습니다.

Evan You는 팬데믹으로 인해 3년 전을 마지막으로 JSworld에 직접 참석하지 못했다는 점을 언급하며 기조연설을 시작했습니다. 그래서 그는 3년 전에는 Vue 생태계에 존재하지 않았거나 아직 안정적이지 않았던 것들을 나열했습니다: Vue 3는 "안정적이지 않았고", Vite(빌드 도구), Volar("임베디드 프로그래밍 언어 도구 구축을 위한 프레임워크"), Pinia("Vue 생태계를 위한 상태 관리 라이브러리")가 존재하지 않았습니다.

그는 "우리는 본질적으로 Vite를 중심으로 완전히 새로운 생태계를 만들었습니다."라고 말하며, "이와 함께 Vue 생태계 내에서뿐만 아니라 다른 모든 프레임워크와도 연결되는 새롭고 흥미로운 모든 것들을 그 위에 구축하였습니다."라고 덧붙였습니다.

https://cdn.thenewstack.io/media/2023/02/76621bfd-vue3_ecosystem.jpgVue 생태계

Evan You는 Vue 애플리케이션을 구축하기 위한 기본 프레임워크인 Nuxt를 필두로 현재 Vue 도구 생태계에 찬사를 보냈습니다. 그러나 계속해서 Vue 3를 안정적으로 만드는 것이 2023년의 주된 관심사라고 말했습니다. 1년 전인 지난 2월에 Vue 3가 새로운 기본 버전이 되었지만, "레거시 프로젝트"라고 불리는 프로젝트에서는 여전히 Vue 2를 사용하고 있습니다. 그는 Vue 3 채택의 대부분이 "신규 프로젝트"에서 이루어졌다고 언급했습니다.

Evan You는 "우리는 아직 Vue 2에서 Vue 3로 전환하는 단계에 있습니다."라고 말하며 많은 대형 프로젝트가 여전히 Vue 2를 사용 중이거나 Vue 3로 전환할 계획을 세우고 있다고 지적했습니다.

Vue 3와 가상 DOM에 대한 새로운 접근 방식

올해 Vue 3에서 계획된 다양한 관리상의 변경에 대해 논의한 후, Evan You는 Vue 2와 비교하여 Vue 3가 "렌더링"하는 방식의 차이점에 대해 설명하는 시간을 가졌습니다. "렌더링 전략은 시간이 지남에 따라 변화하고 있습니다."라고 말하며 특히 가상 DOM(VDOM)을 처리하는 방식에 대해 언급했습니다.

그 얘기를 하기 전에 Vue 3를 이해하는 데 도움이 될 만한 VDOM에 대한 간략한 소개를 하겠습니다. 이 날 JSworld의 다른 세션에서 Marc Backes가 "가상 DOM을 만들어 봅시다."라는 제목의 세션을 진행했습니다. 다음 세 개의 슬라이드는 VDOM이 무엇이며 Vue와 같은 프레임워크 내에서 그 목적이 무엇인지 잘 요약해 줍니다. (VDOM은 React에 의해 대중화되었지만, Vue를 포함한 다른 많은 프레임워크에서도 이 개념을 채택하고 있습니다).

https://cdn.thenewstack.io/media/2023/02/3eb464b9-vdom1.jpg가상 DOM이란 무엇인가

https://cdn.thenewstack.io/media/2023/02/8b42c599-vdom2.jpg왜 가상 DOM을 사용하는가

https://cdn.thenewstack.io/media/2023/02/29695806-vdom4.jpg가상 DOM을 만들어 보기

Backes는 또한 Vue에서 사용하는 렌더링 파이프라인을 다음과 같이 시각적으로 표현했습니다(Vue 문서에 있는 동일한 다이어그램을 다양한 색깔로 표현한 버전입니다).

https://cdn.thenewstack.io/media/2023/02/8e1beaff-vdom3.jpgVue 렌더링 파이프라인

다시 Evan You의 발표 내용으로 돌아가보겠습니다. 그는 "Vue 2에서는 순수 가상 DOM을 사용했는데, 이는 [...] React가 사용하는 것과 유사하며 컴파일 타임 최적화를 수행하지 않는다는 것을 의미합니다. 전혀 최적화하지 않는 건 아니지만 거의 하지 않습니다."라고 말했습니다.

https://cdn.thenewstack.io/media/2023/02/b58f5f5f-vue2_diagram.jpgVue 2 렌더링

"따라서 컴포넌트 트리 또는 앱 수준에서는 각 컴포넌트가 자체 종속성을 추적하도록 하여 세분화된 업데이트를 수행할 수 있습니다."라고 그는 Vue 2에 관해 설명합니다.

단점은 가상 DOM 오버헤드인데, 그는 이를 "가상 DOM 노드를 다시 생성한 다음 해당 트리를 통해 차이를 확인하는 데 드는 비용"이라고 설명했습니다. 그는 "Vue 2는 이 오버헤드를 지속적으로 지불하고 있습니다."라고 덧붙였습니다.

이 문제를 해결하기 위해 Vue 3에서는 다른 접근 방식을 취했습니다. 그는 "컴파일러 정보에 기반한 가상 DOM"이라고 설명했는데, 이는 "컴파일 타임에 훨씬 더 많은 최적화를 수행"한다는 의미입니다.

https://cdn.thenewstack.io/media/2023/02/ca2632f4-vue3_diagram.jpgVue 3 렌더링

단일 파일 컴포넌트

VDOM의 복잡성은 차치하고서라도, Vue의 인기 상승에는 "단일 파일 컴포넌트(SFC)" 접근 방식이 큰 부분을 차지합니다. Vue는 SFC를 "Vue 컴포넌트의 템플릿, 로직, 스타일링을 단일 파일에 캡슐화할 수 있는 특수 파일 형식"으로 정의합니다. 다른 곳에서 Vue는 SFC를 "HTML과 유사한 파일 형식"이라고 부릅니다.

Vue 핵심 팀원인 Damian Dulisz와의 2017년 인터뷰에서 그는 SFC 형식을 통해 "코드를 이해하고 추론하기가 훨씬 더 쉬워졌다"라고 말했습니다.

The New Stack의 엔지니어링 디렉터인 Aaron Ban은 SFC 접근 방식으로 인해 Vue의 팬이 되었습니다. 그는 SFC 접근 방식이 제공하는 "깔끔한 조직"을 좋아하며, 또한 SFC 접근 방식이 모듈화의 훌륭한 예라고 생각합니다. "사실 SFC를 올바르게 수행하는 데 필요한 엄격한 커트라인을 스스로에게 강요하기는 어려운 훈련입니다."라고 그는 말했습니다. 하지만 그는 이것이 지난 10여 년 동안 많은 개발자가 배워온 '빨리빨리'라는 사고방식에 대한 해독제라고 생각합니다. 그는 이러한 사고방식은 개발자들이 "적절한 경계선을 그리는 데 신경 쓰지 않고 '나중에 고치면 된다'는 생각으로 '일단 작동만 시키면 된다'는 식의 나쁜 습관을 조장해 왔다"라고 말합니다.

Ban은 단일 파일 컴포넌트를 제공하는 다른 두 가지 프레임워크인 Svelte와 Lit의 디자인도 마음에 들어 합니다.

SFC가 개발자들에게 보편적으로 사랑받는 것은 아닙니다. Vue 문서에서도 이를 인정하고 있습니다. "전통적인 웹 개발 배경을 가진 일부 사용자는 SFC가 HTML/CSS/JS가 분리해야 할 서로 다른 관심사를 한 곳에 섞어 놓았다는 우려를 할 수 있습니다!"

이러한 반대 의견에 대해 Vue는 SFC 접근 방식이 "실제로 컴포넌트를 더 응집력 있고 유지 관리하기 쉽게 만든다"라고 주장합니다.

결론

Evan You의 JSworld 기조연설에 따르면 2023년에 Vue 개발자에게 큰 변화가 예상되지는 않을 것입니다. Vue 2에서 Vue 3로 업그레이드하도록 개발자를 계속 유도하는 것과 함께, 계속해서 확장되는 생태계에 대한 추가적인 개선이 이어질 것입니다.

Vue는 저희와 같은 기술 전문 매체에서는 그다지 주목 받지 못할 수도 있지만, 매년 이렇게 웹 표준을 준수하는 자바스크립트 프레임워크는 살펴 볼 가치가 있습니다. 우리는 확실히 Vue의 계속적인 발전을 즐기고 있습니다.

+ \ No newline at end of file diff --git a/log/why-we-create-the-composition-api.html b/log/why-we-create-the-composition-api.html index 4d8bc1f2..f0895a39 100644 --- a/log/why-we-create-the-composition-api.html +++ b/log/why-we-create-the-composition-api.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

컴포지션 API를 만든 이유

원문: Function-based component API (extended discussion)

Composition API 제안에 반대하는 유저의 글에 대한 Evan You의 답변 번역


저는 당신의 의견을 존중하므로 다음 내용을 어느 것도 개인적인 것으로 받아들이지 마세요.

결국 정말 중요한 문제들은 전혀 해결되지 않기때문에 이 급진적인 변화는 정당화할 수 없습니다. 본질적으로 이 제안은 그저 겉만 번지르르한 새로운 것을 쫓는 것과 같습니다.

저는 이 말에 동의할 수 없습니다. Logic Composition은 아마도 프로젝트 확장 측면에서 가장 중요한 문제 중 하나일 것입니다. 다른 스레드에서 제가 썼던 말을 다시 인용합니다:

  • 이 RFC 스레드(Composition API 제안. 이하 RFC)에서는 많은 유저들이 정확히 본인들이 현재 직면한 문제를 해결해줄 수 있다고 말하고 있습니다. 그리고 그들은 또한 현재의 object-based syntax(Options API)가 프로젝트의 확장성을 방해하는 병목 현상이라고 언급했습니다. 나는 여러분 중 많은 사람들이 이것을 개인적으로 경험한 적이 없다는 것을 인정합니다(완전히 맞는 말이고, 심지어 훌륭합니다!). 그러나 ‘미학적인’ 선택이 실제 유지 관리 부담이 된다면(물론 특정 유형의 프로젝트에서만), 더 이상 단순한 문제가 아닙니다. 더 나은 추상화로 문제를 해결할 수 있는 기회를 일부 사용자의 ‘미적’ 선호로 인해 거부하는 것은 잘못된 절충안처럼 보입니다.

Vue는 작게 시작했지만 오늘날에는 다양한 수준의 복잡성과 비즈니스 영역을 포함하는 매우 광범위한 프로젝트에서 사용되고 있습니다. 다양한 유형의 프로젝트를 처리하는 개발자는 다양한 요구 사항에 직면하게 되며, 일부는 object-based syntax API를 사용하여 쉽게 처리할 수 있지만 일부는 그렇지 않습니다. 주요 예시들로

  1. 수백 줄 길이의, 다양한 로직을 포함하고 있는 대형 컴포넌트
  2. 여러 컴포넌트 간에 공통 로직을 공유할 필요성

(1) 에 해당하는 상황에서는 로직들이 강제로 각 옵션 유형들에 나눠져 할당됩니다. 예를 들어, 하나의 data fetching 작업이 prop, data, computed property, mounted hook 그리고 watcher까지 필요할 수도 있습니다. 즉, 컴포넌트에서 하나의 data fetching 과정을 이해하려고 할 때 옵션 목록에서 계속 위아래로 점프하게 됩니다. 동시에 속성을 훑어볼 때 속성이 어떤 유형 인지 알고 있지만 처리해야하는 로직 을 말하기는 상당히 어렵습니다. 컴포넌트에 더 많은 로직들이 추가되면 상황이 악화됩니다. 이에 비해 Composition API를 사용하면 한 data fetching을 위한 모든 관련 로직을 그룹화할 수 있으며 더 중요한 것은 별도의 함수 또는 별도의 파일로 깔끔하게 추출할 수 있다는 점입니다.

이 문제는 프로젝트의 파일 구성으로 비유할 수 있습니다. 우리 중 많은 사람들이 파일 유형별로 파일을 구성하는 것(예: 모든 것을 htmljs및 css 폴더로 분할)이 확장성이 없다는 데 동의합니다. 한가지 기능과 관련된 코드들이 잘못 이해한 "관심사 분리(seperation of concerns)"를 위해 세 개의 폴더로 강제로 분할됩니다. 여기서 핵심은 "관심사"가 파일 형식으로 정의되지 않는다는 것입니다. 대신 우리 대부분은 기능이나 책임(responsibility)별로 파일을 구성합니다. 이것이 바로 사람들이 Vue 단일 파일 구성 요소(SFC)를 좋아하는 이유입니다. SFC는 기능별로 코드를 구성하는 방법입니다. 아이러니하게도 SFC가 처음 도입되었을 때 많은 사람들이 SFC가 관심사 분리에 위배된다고 생각하여 반대했지만 나중에 SFC가 실제로 관심사를 분리하는 더 합리적인 방법이라는 것을 인정했습니다.

(2)는 RFC의 ‘동기 (Motivation)’ 섹션에서 중요하게 설명했는데, mixins/HOCs/scoped slots이 할 수 있는 것들을 단점없이 똑같이 해낼 수 있다는 것을 보여줍니다.

React Hook을 통해 우리는 Hook의 특성 중 일부가 위에서 언급한 문제들을 해결하는 데 도움이 될 수 있음을 발견했습니다. 이것이 우리가 이 제안(Composition API)을 하게 된 근본적인 이유입니다. 그야말로 "새로운 것"이지만, 우리는 그것이 "새롭다"는 이유가 아니라 객관적으로 존재하는 문제에 대한 해결책을 제시하기 때문에 새로운 것을 채택하고 있습니다. 장기적으로 이 새로운 API의 가능성이 위에서 언급한 문제들을 다루는 개발자들의 시간을 절약해 막대한 이익을 가져다 줄 것입니다.

Type Safety도 중요한 고려 사항입니다. 다시 말하지만, 이 사항 또한 많은 사용자들이 간절히 원했지만 TypeScript를 사용하지 않는 사람들에게는 가치가 없어 보일 수 있습니다. 이해할 수 있습니다. 그러나 해결되는 문제가 당신에게 영향을 미치지 않기 때문에 어떤 문제도 해결되지 않는다고 주장하는 것은 약간 이기적인 것이라고 생각합니다.

모든 종류의 프로젝트에 급진적인 API 변경 사항을 도입하는 것은 급격한 변화(Breaking Changes)이며, 이전 API와의 역호환성을 관대하게 제공해도 이 문제가 해결되지 않습니다.

"Breaking"은 ‘사용자가 강제로 코드를 변경해야함’으로 정의됩니다. 사용자는 기존 코드를 변경할 필요가 없으므로 Breaking이 아닙니다. 이 부분에 대해서는 더 이상 반박할 여지가 없다고 생각합니다.

이전 버전과의 호환성으로도 충분하지 않다면, 본질적으로 프로젝트가 급진적인 새로운 아이디어를 도입해서는 안 된다고 말하는 것입니다. 저는 이것이 프로젝트 정책 수준의 논쟁이라고 생각합니다. 만약 제가 투표를 한다면, 저는 단호하게 반대할 것입니다. 우리는 사용자의 최선의 이익을 염두에 두고 최선을 다할 것이지만 프로젝트는 발전해야하고 발전할 것입니다.

이런 식으로 일을 하는 것은 불가사의하고 비잔틴이나 미로 같은 "스파게티 코드"로 이어질 가능성이 더 큽니다. Vue의 가장 큰 장점 중 하나는 단순함과 접근성입니다. Vue 주요 [변덕스럽고 종잡을 수 없는 API 변경과 아키텍처 문제로 인해 다른 많은 JavaScript 관련 약속이 그러하듯이 Vue에 대한 주요 조직의 약속은 손에서 증발하기보다는 유통 기한과 내구성을 가질 만큼 충분히 정적입니다.]

반대로, 이 제안의 동기는 장기적으로 Vue 프로젝트의 유지보수성을 향상시키는 것이었습니다.

JavaScript 프로젝트를 살펴보면 모든 코드는 한 시작지점 파일에서 시작하며, 본질적으로 암시적으로 "main" 함수가 호출되면서 시작합니다. 단일 함수 시작점이 스파게티 코드로 이어지는 것이라면 모든 JavaScript 프로젝트는 스파게티 코드여야 합니다. 이는 분명히 사실이 아닙니다. 왜냐구요? 개발자로서 우리는 코드를 모듈 또는 더 작은 기능으로 분할하여 구성하는 방법을 배웠기 때문입니다.

함수 기반 API 디자인의 핵심 특징은 setup() 내 코드를 이해한다는 것이 관용적인 JavaScript 코드를 이해하는 것과 다르지 않으며, 일반 JavaScript 코드를 구성하는 데 사용할 수 있는 모든 기술을 사용해 setup() 함수를 구성할 수 있다는 것입니다. 팀에서 일반적인 JavaScript 코드에 사용하는 모든 지식/스타일 가이드/코드 검토 프로세스를 Vue setup() 함수의 코드에 적용할 수 있습니다.

저는 새로운 API가 이론적으로 코드 품질에 대한 임계값이 더 낮을 수 있음에 동의합니다. 그러나 언급한 바와 같이 Vue가 아닌 코드베이스에서 스파게티 코드를 방지하기 위해 이미 수행하고 있는 모든 작업들을 적용할 수 있으므로 완화될 수 있습니다. 반면에 새로운 API로 작성된 코드는 코드 품질의 상한선도 상당히 높습니다. 새로운 API로 작성된 모든 코드는 옵션 기반 API보다 훨씬 더 높은 품질의 코드로 리팩토링될 수 있지만 옵션 기반 API를 사용하면 믹스인에 의존해야하고 그 단점들도 처리해야 합니다.

저는 또한 이 RFC가 유지 보수성을 위해 단순성을 거래하는 것에 관한 것이 아니라는 점을 지적하고 싶습니다. 알아야할 것은 지금 몇 년 동안 사용했을 수도 있는 API와 처음 본 API간의 느낌을 비교하고 있다는 사실입니다. 기본적으로 아래가 컴포넌트에 관한 관점의 전환입니다.

  • 옵션 기반 API는 컴포넌트를 컴포넌트가 포함한 속성/메서드/옵션이 정의된 유형에 기반해 이해합니다.
  • 함수 기반 API는 컴포넌트를 캡슐화하는 논리적 주제에 기반해 이해합니다.

많은 사용자가 "단순함을 잃는다"고 말할 때 한탄하는 것은 사실 옵션 유형별로 컴포넌트를 살필 수 있는 능력을 잃는 것에 대해 말하는 것입니다. 그러나 새 API를 사용하면 컴포넌트를 옵션 유형별로 살필 수 있는 능력을 제공하는 분석기를 구현하는 것이 매우 간단합니다. 즉, 새 API에서는 두 가지 관점 모두에서 컴포넌트를 살필 수 있지만 옵션 기반 API를 사용하면 하나로 제한됩니다 (옵션 간에 분할할 때 논리적 주제에 대한 의도가 손실되기 때문에).

Vue를 좋게 만드는 것들을 버릴 가치가 없습니다.

"아무것도 버리지 않는다"는 말을 되풀이하는 것도 지겹습니다. 그러나 "Vue를 좋게 만드는 것"이 실제로 무엇인지 정의하려고 합니다. 이 RFC에 반대하는 많은 사용자는 그것을 object-based syntax로 정의하고 object-base syntax를 제거하면 Vue를 Vue스럽게 만드는 모든 것을 제거하는 것처럼 보인다고 말합니다. 그러나 그대로 남아 있는 것을 살펴보겠습니다.

  • 템플릿 구문은 변경되지 않습니다 (심지어 성능이 향상되고 있습니다!)
  • 반응성 시스템이 작동하는 방식은 변경되지 않습니다.
  • computed 속성, watcher 및 컴포넌트 life cycle의 개념은 변경되지 않습니다.
  • SFC 형식은 변경되지 않습니다.
  • CLI가 변경되지 않습니다.
  • 프레임워크의 진보적 성격은 변하지 않습니다.
  • 더 나은 개발 도구를 제공하겠다는 팀의 약속은 변하지 않습니다.
  • 사실 기술적으로, object format도 변경되지 않습니다. 작동하던 모든 것들은 계속 작동합니다.

Vue의 object-based syntax는 처음부터 존재해왔습니다. 위의 많은 것들은 나중에 추가되었으며 각각 Vue의 성장에 기여했습니다. object-based syntax이 당신에게 중요한 전부라고 생각하신다면 한 걸음 물러서서 Vue를 실제로 만드는 것이 무엇인지 다시 생각해 보시기 바랍니다. 결국 이 RFC는 보이는 것처럼 급진적인 변화가 아닙니다.

참고할만한 링크

- +
Skip to content
On this page

컴포지션 API를 만든 이유

원문: Function-based component API (extended discussion)

Composition API 제안에 반대하는 유저의 글에 대한 Evan You의 답변 번역


저는 당신의 의견을 존중하므로 다음 내용을 어느 것도 개인적인 것으로 받아들이지 마세요.

결국 정말 중요한 문제들은 전혀 해결되지 않기때문에 이 급진적인 변화는 정당화할 수 없습니다. 본질적으로 이 제안은 그저 겉만 번지르르한 새로운 것을 쫓는 것과 같습니다.

저는 이 말에 동의할 수 없습니다. Logic Composition은 아마도 프로젝트 확장 측면에서 가장 중요한 문제 중 하나일 것입니다. 다른 스레드에서 제가 썼던 말을 다시 인용합니다:

  • 이 RFC 스레드(Composition API 제안. 이하 RFC)에서는 많은 유저들이 정확히 본인들이 현재 직면한 문제를 해결해줄 수 있다고 말하고 있습니다. 그리고 그들은 또한 현재의 object-based syntax(Options API)가 프로젝트의 확장성을 방해하는 병목 현상이라고 언급했습니다. 나는 여러분 중 많은 사람들이 이것을 개인적으로 경험한 적이 없다는 것을 인정합니다(완전히 맞는 말이고, 심지어 훌륭합니다!). 그러나 ‘미학적인’ 선택이 실제 유지 관리 부담이 된다면(물론 특정 유형의 프로젝트에서만), 더 이상 단순한 문제가 아닙니다. 더 나은 추상화로 문제를 해결할 수 있는 기회를 일부 사용자의 ‘미적’ 선호로 인해 거부하는 것은 잘못된 절충안처럼 보입니다.

Vue는 작게 시작했지만 오늘날에는 다양한 수준의 복잡성과 비즈니스 영역을 포함하는 매우 광범위한 프로젝트에서 사용되고 있습니다. 다양한 유형의 프로젝트를 처리하는 개발자는 다양한 요구 사항에 직면하게 되며, 일부는 object-based syntax API를 사용하여 쉽게 처리할 수 있지만 일부는 그렇지 않습니다. 주요 예시들로

  1. 수백 줄 길이의, 다양한 로직을 포함하고 있는 대형 컴포넌트
  2. 여러 컴포넌트 간에 공통 로직을 공유할 필요성

(1) 에 해당하는 상황에서는 로직들이 강제로 각 옵션 유형들에 나눠져 할당됩니다. 예를 들어, 하나의 data fetching 작업이 prop, data, computed property, mounted hook 그리고 watcher까지 필요할 수도 있습니다. 즉, 컴포넌트에서 하나의 data fetching 과정을 이해하려고 할 때 옵션 목록에서 계속 위아래로 점프하게 됩니다. 동시에 속성을 훑어볼 때 속성이 어떤 유형 인지 알고 있지만 처리해야하는 로직 을 말하기는 상당히 어렵습니다. 컴포넌트에 더 많은 로직들이 추가되면 상황이 악화됩니다. 이에 비해 Composition API를 사용하면 한 data fetching을 위한 모든 관련 로직을 그룹화할 수 있으며 더 중요한 것은 별도의 함수 또는 별도의 파일로 깔끔하게 추출할 수 있다는 점입니다.

이 문제는 프로젝트의 파일 구성으로 비유할 수 있습니다. 우리 중 많은 사람들이 파일 유형별로 파일을 구성하는 것(예: 모든 것을 htmljs및 css 폴더로 분할)이 확장성이 없다는 데 동의합니다. 한가지 기능과 관련된 코드들이 잘못 이해한 "관심사 분리(seperation of concerns)"를 위해 세 개의 폴더로 강제로 분할됩니다. 여기서 핵심은 "관심사"가 파일 형식으로 정의되지 않는다는 것입니다. 대신 우리 대부분은 기능이나 책임(responsibility)별로 파일을 구성합니다. 이것이 바로 사람들이 Vue 단일 파일 구성 요소(SFC)를 좋아하는 이유입니다. SFC는 기능별로 코드를 구성하는 방법입니다. 아이러니하게도 SFC가 처음 도입되었을 때 많은 사람들이 SFC가 관심사 분리에 위배된다고 생각하여 반대했지만 나중에 SFC가 실제로 관심사를 분리하는 더 합리적인 방법이라는 것을 인정했습니다.

(2)는 RFC의 ‘동기 (Motivation)’ 섹션에서 중요하게 설명했는데, mixins/HOCs/scoped slots이 할 수 있는 것들을 단점없이 똑같이 해낼 수 있다는 것을 보여줍니다.

React Hook을 통해 우리는 Hook의 특성 중 일부가 위에서 언급한 문제들을 해결하는 데 도움이 될 수 있음을 발견했습니다. 이것이 우리가 이 제안(Composition API)을 하게 된 근본적인 이유입니다. 그야말로 "새로운 것"이지만, 우리는 그것이 "새롭다"는 이유가 아니라 객관적으로 존재하는 문제에 대한 해결책을 제시하기 때문에 새로운 것을 채택하고 있습니다. 장기적으로 이 새로운 API의 가능성이 위에서 언급한 문제들을 다루는 개발자들의 시간을 절약해 막대한 이익을 가져다 줄 것입니다.

Type Safety도 중요한 고려 사항입니다. 다시 말하지만, 이 사항 또한 많은 사용자들이 간절히 원했지만 TypeScript를 사용하지 않는 사람들에게는 가치가 없어 보일 수 있습니다. 이해할 수 있습니다. 그러나 해결되는 문제가 당신에게 영향을 미치지 않기 때문에 어떤 문제도 해결되지 않는다고 주장하는 것은 약간 이기적인 것이라고 생각합니다.

모든 종류의 프로젝트에 급진적인 API 변경 사항을 도입하는 것은 급격한 변화(Breaking Changes)이며, 이전 API와의 역호환성을 관대하게 제공해도 이 문제가 해결되지 않습니다.

"Breaking"은 ‘사용자가 강제로 코드를 변경해야함’으로 정의됩니다. 사용자는 기존 코드를 변경할 필요가 없으므로 Breaking이 아닙니다. 이 부분에 대해서는 더 이상 반박할 여지가 없다고 생각합니다.

이전 버전과의 호환성으로도 충분하지 않다면, 본질적으로 프로젝트가 급진적인 새로운 아이디어를 도입해서는 안 된다고 말하는 것입니다. 저는 이것이 프로젝트 정책 수준의 논쟁이라고 생각합니다. 만약 제가 투표를 한다면, 저는 단호하게 반대할 것입니다. 우리는 사용자의 최선의 이익을 염두에 두고 최선을 다할 것이지만 프로젝트는 발전해야하고 발전할 것입니다.

이런 식으로 일을 하는 것은 불가사의하고 비잔틴이나 미로 같은 "스파게티 코드"로 이어질 가능성이 더 큽니다. Vue의 가장 큰 장점 중 하나는 단순함과 접근성입니다. Vue 주요 [변덕스럽고 종잡을 수 없는 API 변경과 아키텍처 문제로 인해 다른 많은 JavaScript 관련 약속이 그러하듯이 Vue에 대한 주요 조직의 약속은 손에서 증발하기보다는 유통 기한과 내구성을 가질 만큼 충분히 정적입니다.]

반대로, 이 제안의 동기는 장기적으로 Vue 프로젝트의 유지보수성을 향상시키는 것이었습니다.

JavaScript 프로젝트를 살펴보면 모든 코드는 한 시작지점 파일에서 시작하며, 본질적으로 암시적으로 "main" 함수가 호출되면서 시작합니다. 단일 함수 시작점이 스파게티 코드로 이어지는 것이라면 모든 JavaScript 프로젝트는 스파게티 코드여야 합니다. 이는 분명히 사실이 아닙니다. 왜냐구요? 개발자로서 우리는 코드를 모듈 또는 더 작은 기능으로 분할하여 구성하는 방법을 배웠기 때문입니다.

함수 기반 API 디자인의 핵심 특징은 setup() 내 코드를 이해한다는 것이 관용적인 JavaScript 코드를 이해하는 것과 다르지 않으며, 일반 JavaScript 코드를 구성하는 데 사용할 수 있는 모든 기술을 사용해 setup() 함수를 구성할 수 있다는 것입니다. 팀에서 일반적인 JavaScript 코드에 사용하는 모든 지식/스타일 가이드/코드 검토 프로세스를 Vue setup() 함수의 코드에 적용할 수 있습니다.

저는 새로운 API가 이론적으로 코드 품질에 대한 임계값이 더 낮을 수 있음에 동의합니다. 그러나 언급한 바와 같이 Vue가 아닌 코드베이스에서 스파게티 코드를 방지하기 위해 이미 수행하고 있는 모든 작업들을 적용할 수 있으므로 완화될 수 있습니다. 반면에 새로운 API로 작성된 코드는 코드 품질의 상한선도 상당히 높습니다. 새로운 API로 작성된 모든 코드는 옵션 기반 API보다 훨씬 더 높은 품질의 코드로 리팩토링될 수 있지만 옵션 기반 API를 사용하면 믹스인에 의존해야하고 그 단점들도 처리해야 합니다.

저는 또한 이 RFC가 유지 보수성을 위해 단순성을 거래하는 것에 관한 것이 아니라는 점을 지적하고 싶습니다. 알아야할 것은 지금 몇 년 동안 사용했을 수도 있는 API와 처음 본 API간의 느낌을 비교하고 있다는 사실입니다. 기본적으로 아래가 컴포넌트에 관한 관점의 전환입니다.

  • 옵션 기반 API는 컴포넌트를 컴포넌트가 포함한 속성/메서드/옵션이 정의된 유형에 기반해 이해합니다.
  • 함수 기반 API는 컴포넌트를 캡슐화하는 논리적 주제에 기반해 이해합니다.

많은 사용자가 "단순함을 잃는다"고 말할 때 한탄하는 것은 사실 옵션 유형별로 컴포넌트를 살필 수 있는 능력을 잃는 것에 대해 말하는 것입니다. 그러나 새 API를 사용하면 컴포넌트를 옵션 유형별로 살필 수 있는 능력을 제공하는 분석기를 구현하는 것이 매우 간단합니다. 즉, 새 API에서는 두 가지 관점 모두에서 컴포넌트를 살필 수 있지만 옵션 기반 API를 사용하면 하나로 제한됩니다 (옵션 간에 분할할 때 논리적 주제에 대한 의도가 손실되기 때문에).

Vue를 좋게 만드는 것들을 버릴 가치가 없습니다.

"아무것도 버리지 않는다"는 말을 되풀이하는 것도 지겹습니다. 그러나 "Vue를 좋게 만드는 것"이 실제로 무엇인지 정의하려고 합니다. 이 RFC에 반대하는 많은 사용자는 그것을 object-based syntax로 정의하고 object-base syntax를 제거하면 Vue를 Vue스럽게 만드는 모든 것을 제거하는 것처럼 보인다고 말합니다. 그러나 그대로 남아 있는 것을 살펴보겠습니다.

  • 템플릿 구문은 변경되지 않습니다 (심지어 성능이 향상되고 있습니다!)
  • 반응성 시스템이 작동하는 방식은 변경되지 않습니다.
  • computed 속성, watcher 및 컴포넌트 life cycle의 개념은 변경되지 않습니다.
  • SFC 형식은 변경되지 않습니다.
  • CLI가 변경되지 않습니다.
  • 프레임워크의 진보적 성격은 변하지 않습니다.
  • 더 나은 개발 도구를 제공하겠다는 팀의 약속은 변하지 않습니다.
  • 사실 기술적으로, object format도 변경되지 않습니다. 작동하던 모든 것들은 계속 작동합니다.

Vue의 object-based syntax는 처음부터 존재해왔습니다. 위의 많은 것들은 나중에 추가되었으며 각각 Vue의 성장에 기여했습니다. object-based syntax이 당신에게 중요한 전부라고 생각하신다면 한 걸음 물러서서 Vue를 실제로 만드는 것이 무엇인지 다시 생각해 보시기 바랍니다. 결국 이 RFC는 보이는 것처럼 급진적인 변화가 아닙니다.

참고할만한 링크

+ \ No newline at end of file diff --git a/log/why-you-should-be-using-vue-new-composition-api.html b/log/why-you-should-be-using-vue-new-composition-api.html index d01c1a60..cc520d90 100644 --- a/log/why-you-should-be-using-vue-new-composition-api.html +++ b/log/why-you-should-be-using-vue-new-composition-api.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

뷰의 새로운 컴포지션 API를 사용해야 하는 이유

원문: https://aschmelyun.com/blog/why-you-should-be-using-vue-new-composition-api/

아마 뷰의 새로운 컴포지션 API에 대한 소식이 계속해서 들려오고 있을 것입니다. 하지만, 이 새로운 API가 약간 무섭고 위협적이게 느껴질것이며 어느 부분에서 훨씬 더 나은지 명확하게 다가오지 않을 것입니다.

이 글에서는 이전 방식과 새로운 방식을 비교하며 컴포지션 API를 배워야 하는 이유를 명확하게 설명합니다. 예제는 간단하게 시작하여 점점 더 복잡해지기 때문에 이를 통해 컴포지션 API가 이전 방식과 크게 다르지 않다는 것도 알 수 있을 것 입니다.

컴포지션 API는 뷰 2의 옵션 API를 대체하지만 뷰 3 애플리케이션에서 필수 가 아니라는 장점이 있습니다. 이전에 뷰 2에서 했던 것처럼 여전히 검증된 옵션 API를 사용하고 컴포넌트를 작성할 수 있습니다. 이제 바로 이 새로운 방법을 채택하고 싶거나 업데이트에 익숙해지기를 원하는 사람들을 위해 몇 가지 예를 살펴보겠습니다. 아래 예시는 뷰 3의 컴포지션 API를 사용하여 재작성된 몇 가지 일반적이고 간단한 컴포넌트입니다.

간단한 카운터

아래 예시는 프런트엔드 프레임워크를 배울때 "Hello world"격인 카운터 컴포넌트 예제입니다. 뷰 2에서는 어떻게 작성하는지 살펴보죠.

vue
<template>
+    
Skip to content
On this page

뷰의 새로운 컴포지션 API를 사용해야 하는 이유

원문: https://aschmelyun.com/blog/why-you-should-be-using-vue-new-composition-api/

아마 뷰의 새로운 컴포지션 API에 대한 소식이 계속해서 들려오고 있을 것입니다. 하지만, 이 새로운 API가 약간 무섭고 위협적이게 느껴질것이며 어느 부분에서 훨씬 더 나은지 명확하게 다가오지 않을 것입니다.

이 글에서는 이전 방식과 새로운 방식을 비교하며 컴포지션 API를 배워야 하는 이유를 명확하게 설명합니다. 예제는 간단하게 시작하여 점점 더 복잡해지기 때문에 이를 통해 컴포지션 API가 이전 방식과 크게 다르지 않다는 것도 알 수 있을 것 입니다.

컴포지션 API는 뷰 2의 옵션 API를 대체하지만 뷰 3 애플리케이션에서 필수 가 아니라는 장점이 있습니다. 이전에 뷰 2에서 했던 것처럼 여전히 검증된 옵션 API를 사용하고 컴포넌트를 작성할 수 있습니다. 이제 바로 이 새로운 방법을 채택하고 싶거나 업데이트에 익숙해지기를 원하는 사람들을 위해 몇 가지 예를 살펴보겠습니다. 아래 예시는 뷰 3의 컴포지션 API를 사용하여 재작성된 몇 가지 일반적이고 간단한 컴포넌트입니다.

간단한 카운터

아래 예시는 프런트엔드 프레임워크를 배울때 "Hello world"격인 카운터 컴포넌트 예제입니다. 뷰 2에서는 어떻게 작성하는지 살펴보죠.

vue
<template>
   <div class="counter">
     <span>{{ counter }}</span>
     <button @click="counter += 1">+1</button>
@@ -304,8 +304,8 @@
   }
 }
 </script>

먼저 import 문을 사용하여 useLikes 기능을 가져온 다음 각각 likes ref 객체 및 likesAmount 메서드로 구성된 객체를 해체해 사용합니다. 동일한 useLikes 함수를 통해 기본 컴포넌트로 가져옵니다.

남은 작업은 하드 코딩된 값으로 1로 설정한 postId 속성을 전달하는 것뿐이었습니다.

마무리

여기까지입니다! 뷰 2로 작성된 3개의 다른 컴포넌트와 뷰 3로 복제된 컴포넌트를 보았습니다.

프레임워크 경험이 있는 개발자든 아직 요령을 배우고 있는 개발자든 이 최신 버전의 뷰를 사용하는 데 도움이 되었기를 바랍니다. 다양하고 때로는 위협적인 모양에도 불구하고 컴포지션 API는 프런트엔드 코드를 보다 안정적이고 유지 관리하기 쉬운 방식으로 구성하고 리팩터링 하는 데 도움이 될 수 있습니다.

질문이나 의견이 있거나 일반적인 웹 개발에 대해 더 많은 대화를 나누고 싶다면 주저하지 말고 Twitter로 문의하세요!

- + \ No newline at end of file diff --git a/posts/how-to-apply-utterances-on-vitepress.html b/posts/how-to-apply-utterances-on-vitepress.html index 78d29355..bd976a19 100644 --- a/posts/how-to-apply-utterances-on-vitepress.html +++ b/posts/how-to-apply-utterances-on-vitepress.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

How to apply utterances in VitePress (VitePress 블로그에 utternaces 적용하기)

1. https://utteranc.es/ 에 접속해 지시를 따라 repo를 지정합니다.

2. Comment용 컴포넌트를 만듭니다.

vue
<script setup>
+    
Skip to content
On this page

How to apply utterances in VitePress (VitePress 블로그에 utternaces 적용하기)

1. https://utteranc.es/ 에 접속해 지시를 따라 repo를 지정합니다.

2. Comment용 컴포넌트를 만듭니다.

vue
<script setup>
 import { onMounted } from 'vue';
 
 onMounted(() => {
@@ -82,9 +82,9 @@
 disableComment: true
 ---
 
-## Hello World
- +## Hello World
+ \ No newline at end of file diff --git a/posts/how-to-generate-sitemap-xml-for-vitepress.html b/posts/how-to-generate-sitemap-xml-for-vitepress.html index 9af63e5e..3912ca4f 100644 --- a/posts/how-to-generate-sitemap-xml-for-vitepress.html +++ b/posts/how-to-generate-sitemap-xml-for-vitepress.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

How to generate sitemap.xml for Vitepress (Vitepress 블로그에 sitemap.xml 생성하는 방법)

참고: https://github.com/vuejs/vitepress/issues/520

bash
# install sitemap
+    
Skip to content
On this page

How to generate sitemap.xml for Vitepress (Vitepress 블로그에 sitemap.xml 생성하는 방법)

참고: https://github.com/vuejs/vitepress/issues/520

bash
# install sitemap
 npm i -D sitemap
javascript
// .vitepress/config.js
 import { SitemapStream } from 'sitemap';
 import { createWriteStream } from 'fs'
@@ -46,8 +46,8 @@
   }
   // ...
 }
- + \ No newline at end of file diff --git a/reading.html b/reading.html index a3fd3d3d..822731b5 100644 --- a/reading.html +++ b/reading.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

📚 책

2024년

잘 그리기 금지

잘 그리기 금지

사이토 나오키
100100 %
개발자 원칙

개발자 원칙

박성철, 강대명, 공용준, 김정, 박미정, 박종천
100100 %
소프트 스킬

소프트 스킬

존 손메즈
1515 %

2023년

모순

모순

양귀자
~
100100 %
0원으로 사는 삶
6060 %
소크라테스 익스프레스
6060 %
리팩터링

리팩터링

마틴 파울러
~
100100 %
무의미의 축제

무의미의 축제

밀란 쿤데라
~
100100 %
아무튼, 계속
~
100100 %
스토너

스토너

존 윌리엄스
~
100100 %
너무나 많은 여름이
~
100100 %
가난의 문법
5353 %
호밀밭의 파수꾼

호밀밭의 파수꾼

제롬 데이비드 샐린저
100100 %
이토록 평범한 미래
100100 %

2022년

당신 인생의 이야기
100100 %
재수사1

재수사1

장강명
~
100100 %
재수사2

재수사2

장강명
~
100100 %
가벼운 마음

가벼운 마음

크리스티앙 보뱅
~
100100 %
나의 아름다운 할머니
39.0909090909090939 %
시선으로부터
3.8805970149253734 %
가벼운 책임
76.7676767676767677 %
누구나 자료구조와 알고리즘
6666 %
시드 마이어

시드 마이어

시드 마이어, 제니퍼 리 누넌
1313 %
H마트에서 울다

H마트에서 울다

미셸 자우너
100100 %
오직 두사람
100100 %
읽지 않은 책에 대해 말하는 법
82.7004219409282783 %
깨끗한 존경
62.9629629629629663 %
작별인사

작별인사

김영하
100100 %
게으름에 대한 찬양

게으름에 대한 찬양

버트런드 러셀
1212 %
쓰고 싶다 쓰고 싶지 않다

쓰고 싶다 쓰고 싶지 않다

전고운, 이석원, 이다혜, 이랑, 박정민, 김종관
100100 %
멀고도 가까운

멀고도 가까운

리베카 솔닛
~
34.8648648648648635 %
거의 모든 것의 역사
10.80074487895716811 %
책 읽는 삶

책 읽는 삶

C. S. 루이스
7878 %
세상을 바꾸는 행동경제학

세상을 바꾸는 행동경제학

마이클 샌더스, 수잔나 흄
1111 %
쥐

아트 슈피겔만
100100 %
아무튼, 메모
100100 %
신호와 소음

신호와 소음

네이트 실버
24.62380300957592325 %
실격당한 자들을 위한 변론
100100 %
산책과 연애
100100 %

2021년

리얼리티 버블
88 %
자기 앞의 생

자기 앞의 생

로맹 가리(에밀 아자르)
100100 %
눈물을 마시는 새
~
9797 %

2020년

모래알만 한 진실이라도
~
100100 %
쌤 코끼리 그려주세요
100100 %
편집자는 편집을 하지 않는다 7
100100 %
불안의 책

불안의 책

페르난두 페소아
1313 %
한 권으로 읽는 컴퓨터 구조와 프로그래밍
1818 %
일 잘하는 사람은 단순하게 합니다
2929 %
함께자라기
100100 %
- +
Skip to content
On this page

📚 책

2024년

잘 그리기 금지

잘 그리기 금지

사이토 나오키
100100 %
개발자 원칙

개발자 원칙

박성철, 강대명, 공용준, 김정, 박미정, 박종천
100100 %
소프트 스킬

소프트 스킬

존 손메즈
1515 %

2023년

모순

모순

양귀자
~
100100 %
0원으로 사는 삶
6060 %
소크라테스 익스프레스
6060 %
리팩터링

리팩터링

마틴 파울러
~
100100 %
무의미의 축제

무의미의 축제

밀란 쿤데라
~
100100 %
아무튼, 계속
~
100100 %
스토너

스토너

존 윌리엄스
~
100100 %
너무나 많은 여름이
~
100100 %
가난의 문법
5353 %
호밀밭의 파수꾼

호밀밭의 파수꾼

제롬 데이비드 샐린저
100100 %
이토록 평범한 미래
100100 %

2022년

당신 인생의 이야기
100100 %
재수사1

재수사1

장강명
~
100100 %
재수사2

재수사2

장강명
~
100100 %
가벼운 마음

가벼운 마음

크리스티앙 보뱅
~
100100 %
나의 아름다운 할머니
39.0909090909090939 %
시선으로부터
3.8805970149253734 %
가벼운 책임
76.7676767676767677 %
누구나 자료구조와 알고리즘
6666 %
시드 마이어

시드 마이어

시드 마이어, 제니퍼 리 누넌
1313 %
H마트에서 울다

H마트에서 울다

미셸 자우너
100100 %
오직 두사람
100100 %
읽지 않은 책에 대해 말하는 법
82.7004219409282783 %
깨끗한 존경
62.9629629629629663 %
작별인사

작별인사

김영하
100100 %
게으름에 대한 찬양

게으름에 대한 찬양

버트런드 러셀
1212 %
쓰고 싶다 쓰고 싶지 않다

쓰고 싶다 쓰고 싶지 않다

전고운, 이석원, 이다혜, 이랑, 박정민, 김종관
100100 %
멀고도 가까운

멀고도 가까운

리베카 솔닛
~
34.8648648648648635 %
거의 모든 것의 역사
10.80074487895716811 %
책 읽는 삶

책 읽는 삶

C. S. 루이스
7878 %
세상을 바꾸는 행동경제학

세상을 바꾸는 행동경제학

마이클 샌더스, 수잔나 흄
1111 %
쥐

아트 슈피겔만
100100 %
아무튼, 메모
100100 %
신호와 소음

신호와 소음

네이트 실버
24.62380300957592325 %
실격당한 자들을 위한 변론
100100 %
산책과 연애
100100 %

2021년

리얼리티 버블
88 %
자기 앞의 생

자기 앞의 생

로맹 가리(에밀 아자르)
100100 %
눈물을 마시는 새
~
9797 %

2020년

모래알만 한 진실이라도
~
100100 %
쌤 코끼리 그려주세요
100100 %
편집자는 편집을 하지 않는다 7
100100 %
불안의 책

불안의 책

페르난두 페소아
1313 %
한 권으로 읽는 컴퓨터 구조와 프로그래밍
1818 %
일 잘하는 사람은 단순하게 합니다
2929 %
함께자라기
100100 %
+ \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index cb207291..5e68e1dd 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://ktseo41.github.io/blog/log/announcing-vue-3-42024-02-01T15:59:20.000Zhttps://ktseo41.github.io/blog/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/posts/how-to-apply-utterances-on-vitepress2023-05-13T14:06:36.000Zhttps://ktseo41.github.io/blog/study/Brilliant2022-10-12T14:48:57.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter12023-08-16T14:32:01.000Zhttps://ktseo41.github.io/blog/archive2023-02-04T06:38:46.000Zhttps://ktseo41.github.io/blog/debt2023-05-06T06:41:24.000Zhttps://ktseo41.github.io/blog/2024-02-09T11:25:15.000Zhttps://ktseo41.github.io/blog/log/experimenting-with-measuring-soft-navigations2023-11-26T13:23:40.000Zhttps://ktseo41.github.io/blog/log/avoid-these-common-pitfalls-of-react-usestate2023-01-05T13:30:24.000Zhttps://ktseo41.github.io/blog/log/fully-typed-web-apps2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/how-core-web-vital-affect-seo2024-02-01T15:51:12.000Zhttps://ktseo41.github.io/blog/log/making-cloudflare-for-web2023-06-09T04:15:11.000Zhttps://ktseo41.github.io/blog/log/making-javascript-run-fast-on-webassembly2023-01-05T13:24:04.000Zhttps://ktseo41.github.io/blog/log/patterns-for-reactivity-with-modern-vanilla-javascript2023-09-10T02:40:53.000Zhttps://ktseo41.github.io/blog/log/short/og-image-generation2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/log/short/four-eras-of-javascript-frameworks2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters2023-08-15T10:51:19.000Zhttps://ktseo41.github.io/blog/log/short/state-of-vue-2022-amsterdam-recap2023-05-13T14:07:26.000Zhttps://ktseo41.github.io/blog/log/short/toss-slash22-react-native-for-super-high-productivity2023-05-06T06:16:33.000Zhttps://ktseo41.github.io/blog/log/the-saga-of-the-closure-compiler-and-why-typescript-won2023-11-01T02:16:18.000Zhttps://ktseo41.github.io/blog/log/virtual-dom-back-in-block2023-06-26T13:59:15.000Zhttps://ktseo41.github.io/blog/log/what-if-we-had-local-first-software2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/things-you-forgot-or-never-knew-because-of-react2023-08-22T04:01:53.000Zhttps://ktseo41.github.io/blog/log/web-push-for-web-apps-on-ios-and-ipados2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react2023-05-13T16:19:31.000Zhttps://ktseo41.github.io/blog/log/why-we-create-the-composition-api2023-05-13T14:07:26.000Zhttps://ktseo41.github.io/blog/log/why-you-should-be-using-vue-new-composition-api2023-01-29T09:11:30.000Zhttps://ktseo41.github.io/blog/posts/how-to-generate-sitemap-xml-for-vitepress2023-05-06T06:41:24.000Zhttps://ktseo41.github.io/blog/study/LeetCode2022-11-15T02:35:57.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter102023-10-03T12:10:03.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter112023-10-03T12:50:06.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter32023-08-30T16:10:36.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter122023-09-26T16:02:08.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter22023-08-30T16:04:21.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter42023-09-26T16:02:08.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter62023-08-30T16:04:21.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter82023-09-06T15:45:09.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter72023-08-30T16:10:36.000Zhttps://ktseo41.github.io/blog/study/refactoring/intro2023-06-29T14:35:44.000Zhttps://ktseo41.github.io/blog/study/%EB%88%84%EA%B5%AC%EB%82%98%20%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%982022-10-13T11:06:09.000Zhttps://ktseo41.github.io/blog/study/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B42022-10-12T14:46:08.000Zhttps://ktseo41.github.io/blog/study/%ED%95%A8%EA%BB%98%EC%9E%90%EB%9D%BC%EA%B8%B02022-07-24T12:08:41.000Zhttps://ktseo41.github.io/blog/AoC/2022/day12022-12-13T15:08:34.000Zhttps://ktseo41.github.io/blog/vim2023-12-18T03:07:39.000Zhttps://ktseo41.github.io/blog/AoC/2022/day32022-12-13T15:06:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day22022-12-13T15:06:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day42022-12-07T10:46:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day52022-12-14T09:27:00.000Zhttps://ktseo41.github.io/blog/AoC/2022/day62022-12-14T10:21:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/2022-12-14T10:21:13.000Zhttps://ktseo41.github.io/blog/study/%ED%81%B4%EB%A6%B0%20%EC%BD%94%EB%93%9C2023-02-03T01:04:54.000Zhttps://ktseo41.github.io/blog/reading2024-02-26T15:38:01.000Z \ No newline at end of file +https://ktseo41.github.io/blog/log/announcing-vue-3-42024-02-01T15:59:20.000Zhttps://ktseo41.github.io/blog/log/short/four-eras-of-javascript-frameworks2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/posts/how-to-apply-utterances-on-vitepress2023-05-13T14:06:36.000Zhttps://ktseo41.github.io/blog/study/Brilliant2022-10-12T14:48:57.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter12023-08-16T14:32:01.000Zhttps://ktseo41.github.io/blog/archive2023-02-04T06:38:46.000Zhttps://ktseo41.github.io/blog/debt2023-05-06T06:41:24.000Zhttps://ktseo41.github.io/blog/2024-02-09T11:25:15.000Zhttps://ktseo41.github.io/blog/log/experimenting-with-measuring-soft-navigations2023-11-26T13:23:40.000Zhttps://ktseo41.github.io/blog/log/avoid-these-common-pitfalls-of-react-usestate2023-01-05T13:30:24.000Zhttps://ktseo41.github.io/blog/log/how-core-web-vital-affect-seo2024-02-01T15:51:12.000Zhttps://ktseo41.github.io/blog/log/making-cloudflare-for-web2023-06-09T04:15:11.000Zhttps://ktseo41.github.io/blog/log/fully-typed-web-apps2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/making-javascript-run-fast-on-webassembly2023-01-05T13:24:04.000Zhttps://ktseo41.github.io/blog/log/nextjs-app-router-migration-the-good-bad-and-ugly2024-02-28T16:17:26.000Zhttps://ktseo41.github.io/blog/log/patterns-for-reactivity-with-modern-vanilla-javascript2023-09-10T02:40:53.000Zhttps://ktseo41.github.io/blog/log/short/ndc-keynotes-evolution-of-blockchain-and-virtual-reality2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/log/short/og-image-generation2022-12-18T12:19:40.000Zhttps://ktseo41.github.io/blog/log/short/prevent-attacks-and-redirect-users-with-oauth-2_0-state-parameters2023-08-15T10:51:19.000Zhttps://ktseo41.github.io/blog/log/short/state-of-vue-2022-amsterdam-recap2023-05-13T14:07:26.000Zhttps://ktseo41.github.io/blog/log/short/toss-slash22-react-native-for-super-high-productivity2023-05-06T06:16:33.000Zhttps://ktseo41.github.io/blog/log/the-saga-of-the-closure-compiler-and-why-typescript-won2023-11-01T02:16:18.000Zhttps://ktseo41.github.io/blog/log/things-you-forgot-or-never-knew-because-of-react2023-08-22T04:01:53.000Zhttps://ktseo41.github.io/blog/log/virtual-dom-back-in-block2023-06-26T13:59:15.000Zhttps://ktseo41.github.io/blog/log/web-push-for-web-apps-on-ios-and-ipados2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/what-if-we-had-local-first-software2023-05-04T11:38:19.000Zhttps://ktseo41.github.io/blog/log/what-to-expect-from-vue-in-2023-and-how-it-differs-from-react2023-05-13T16:19:31.000Zhttps://ktseo41.github.io/blog/log/why-we-create-the-composition-api2023-05-13T14:07:26.000Zhttps://ktseo41.github.io/blog/log/why-you-should-be-using-vue-new-composition-api2023-01-29T09:11:30.000Zhttps://ktseo41.github.io/blog/posts/how-to-generate-sitemap-xml-for-vitepress2023-05-06T06:41:24.000Zhttps://ktseo41.github.io/blog/study/LeetCode2022-11-15T02:35:57.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter102023-10-03T12:10:03.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter112023-10-03T12:50:06.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter122023-09-26T16:02:08.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter22023-08-30T16:04:21.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter32023-08-30T16:10:36.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter42023-09-26T16:02:08.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter62023-08-30T16:04:21.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter82023-09-06T15:45:09.000Zhttps://ktseo41.github.io/blog/study/refactoring/intro2023-06-29T14:35:44.000Zhttps://ktseo41.github.io/blog/study/refactoring/chapter72023-08-30T16:10:36.000Zhttps://ktseo41.github.io/blog/study/%EB%88%84%EA%B5%AC%EB%82%98%20%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%982022-10-13T11:06:09.000Zhttps://ktseo41.github.io/blog/study/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B42022-10-12T14:46:08.000Zhttps://ktseo41.github.io/blog/AoC/2022/day12022-12-13T15:08:34.000Zhttps://ktseo41.github.io/blog/study/%ED%95%A8%EA%BB%98%EC%9E%90%EB%9D%BC%EA%B8%B02022-07-24T12:08:41.000Zhttps://ktseo41.github.io/blog/vim2023-12-18T03:07:39.000Zhttps://ktseo41.github.io/blog/AoC/2022/day22022-12-13T15:06:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day32022-12-13T15:06:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day42022-12-07T10:46:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/day52022-12-14T09:27:00.000Zhttps://ktseo41.github.io/blog/AoC/2022/day62022-12-14T10:21:13.000Zhttps://ktseo41.github.io/blog/AoC/2022/2022-12-14T10:21:13.000Zhttps://ktseo41.github.io/blog/reading2024-02-26T15:38:01.000Zhttps://ktseo41.github.io/blog/study/%ED%81%B4%EB%A6%B0%20%EC%BD%94%EB%93%9C2023-02-03T01:04:54.000Z \ No newline at end of file diff --git a/study/Brilliant.html b/study/Brilliant.html index aeefd695..c6879e9c 100644 --- a/study/Brilliant.html +++ b/study/Brilliant.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Brilliant (✘)

중단


0 zap
0일 연속 진행중
총 42개 강의 완료

Computer Science Foundations

컴퓨터 과학의 핵심 아이디어에서 시작하여 알고리즘과 신경망으로 진행합니다.

Computer Science Fundamentals

15100 %
Ancient Search Technology

사서는 책을 저자, 제목, 주제별로 찾을 수 있는 방법이 필요했습니다. 하지만 책장에서 책은 한 가지 방법으로만 정렬할 수 있습니다. 사서들은 이 문제를 해결하기 위해 수세기 전에 한 방법을 만들어 냈습니다. 바로 카드 카탈로그를 이용하는 것입니다.

alt
출처 : Brilliant

카드 카탈로그의 색인 카드는 해당 책을 빠르게 찾을 수 있는 번호를 포함해 책에 대한 모든 주요 정보를 포함하고 있습니다. 만약 카드를 저자별로 묶어놓는다면 우리가 톨스토이의 책을 찾으려고 할 때 빠르게 찾을 수 있습니다. 저자에 따른 정렬만이 아니라 제목, 출판일 등등 도서관을 이용객에게 중요한 정보별로 어떤 것이든 이용할 수 있습니다.

일반적으로 컴퓨터를 이용해 아주 많은 양의 데이터를 검색해야할 때, 아래 두 가지 방법 중 하나를 수행하게 됩니다.

  • 모든 데이터를 하나씩 탐색하는 것. 컴퓨터는 이 작업을 아주 빠르게 수행할 수 있습니다. 특히, 병렬로 작업을 수행할 때요.
  • 별도의 목록을 탐색하는 것 - 즉, Index - 유용한 순서로 정렬돼있습니다. 마치 카드 카탈로그처럼요.
Where Should We Put Books?

또 다른 문제

만약 책장에 책이 꽉 차있는데, 중간에 다른 책을 추가해야한다면? 많은 책을 움직여야 합니다.

이 문제를 해결하기 위해 사서들은 책장에 추가적인 공간을 남겨두는 방식을 사용합니다.

하지면 여전히 문제는 존재합니다. 남겨둔 공간이 낭비되는 것이죠.

Who Cares Where We put the Books?

공간을 절약할 수 있는 또 다른 현대적인 방법이 있습니다.

책을 아무곳에나 두는 겁니다. 컴퓨터 시스템만이 책의 장소를 기억하는 거죠.

Naming

이 것이 우리 시스템의 주요 문제점입니다. 이름을 알기 위해서는 이름을 알아야합니다.

Beemesh 시스템은 모든 디바이스가 생산될 때부터 central authority의 주소를 알도록 했습니다. 컴퓨터가 제일 처음 Beemesh에 연결될 때 이미 TOWN-HALL의 주소를 알고 있게 되는 것이죠.

사실, 이건 인터넷이 작동하는 방식과 매우 흡사합니다. 우리의 컴퓨터는 인터넷에 연결되기 전부터 central naming authority의 주소를 알고 있습니다.

Abstraction

시청의 컴퓨터를 작동시키는 비용은 1시간에 2센트입니다. 이 계산에 따르면 Sophia의 느린 Python 프로그램을 900번 돌리는 비용은 35센트입니다.

Sophia의 시급은 50달러입니다. 그리고 Sophia가 더 빠른 알고리즘으로 프로그램을 개선하는데는 2시간이 걸립니다.

프로그램 개선이 더 저렴한 방법이 되기 위해서는 프로그램을 몇번이나 돌려야할까요?

Interfaces

Jing 시장의 요청을 수행하기 위한 3가지 다른 방법을 알아봤습니다. 하지만 Jing 시장의 입장에서는 이 셋이 모두 같은 Interface를 가지고 있었습니다. 그녀는 항상 Records Office를 통해 Fire Department 메모들을 요청했을 뿐이었습니다.

Jing 시장에게서 감춰진 영역이 있어서 신경쓰이게 하지 않고 다른 방법을 사용하도록 바꿀 수 있었습니다. 인터페이스에서 중요한 부분 중 하나입니다.

Algorithm Fundamentals

1774 %

Building Blocks

Pseudocode
Conditional Algorithms
Manipulating Numbers
Repetition
Arrays

Array Algorithms

Searching an Array
Sorting an Array
Insertion Sort

Selection Sort는 정렬되지 않은 영역을 반복적으로 스캔해 swap을 최소화 합니다.

Insertion Sort는 필요하지 않은 스캔을 줄이고 대신 swap 횟수를 늘립니다

The Speed of Algorithms

Timing Programs with a Stopwatch
Counting Operations
Best, Worst and Average Case
Comparing Algorithms
Understanding Big O
The Mathmatcis of Big O

Stable Matching

The Stable Matching Problem
Using Greediness

Deferred Acceptance Algorithm

Correctness

Termination

Running Time

Variants

  • Gale-Shapley 알고리즘을 현실적인 문제에 맞춰 수정
    • 자리가 2개 이상인 병원
    • 자리와 후보의 수가 불일치
  • 이상적인 조건에서 우선적으로 알고리즘을 만들고 현실에 맞춰 수정하는 과정

Who Benefits?

Data Structures

00 %

Introduction to Neural Networks

00 %
- +
Skip to content
On this page

Brilliant (✘)

중단


0 zap
0일 연속 진행중
총 42개 강의 완료

Computer Science Foundations

컴퓨터 과학의 핵심 아이디어에서 시작하여 알고리즘과 신경망으로 진행합니다.

Computer Science Fundamentals

15100 %
Ancient Search Technology

사서는 책을 저자, 제목, 주제별로 찾을 수 있는 방법이 필요했습니다. 하지만 책장에서 책은 한 가지 방법으로만 정렬할 수 있습니다. 사서들은 이 문제를 해결하기 위해 수세기 전에 한 방법을 만들어 냈습니다. 바로 카드 카탈로그를 이용하는 것입니다.

alt
출처 : Brilliant

카드 카탈로그의 색인 카드는 해당 책을 빠르게 찾을 수 있는 번호를 포함해 책에 대한 모든 주요 정보를 포함하고 있습니다. 만약 카드를 저자별로 묶어놓는다면 우리가 톨스토이의 책을 찾으려고 할 때 빠르게 찾을 수 있습니다. 저자에 따른 정렬만이 아니라 제목, 출판일 등등 도서관을 이용객에게 중요한 정보별로 어떤 것이든 이용할 수 있습니다.

일반적으로 컴퓨터를 이용해 아주 많은 양의 데이터를 검색해야할 때, 아래 두 가지 방법 중 하나를 수행하게 됩니다.

  • 모든 데이터를 하나씩 탐색하는 것. 컴퓨터는 이 작업을 아주 빠르게 수행할 수 있습니다. 특히, 병렬로 작업을 수행할 때요.
  • 별도의 목록을 탐색하는 것 - 즉, Index - 유용한 순서로 정렬돼있습니다. 마치 카드 카탈로그처럼요.
Where Should We Put Books?

또 다른 문제

만약 책장에 책이 꽉 차있는데, 중간에 다른 책을 추가해야한다면? 많은 책을 움직여야 합니다.

이 문제를 해결하기 위해 사서들은 책장에 추가적인 공간을 남겨두는 방식을 사용합니다.

하지면 여전히 문제는 존재합니다. 남겨둔 공간이 낭비되는 것이죠.

Who Cares Where We put the Books?

공간을 절약할 수 있는 또 다른 현대적인 방법이 있습니다.

책을 아무곳에나 두는 겁니다. 컴퓨터 시스템만이 책의 장소를 기억하는 거죠.

Naming

이 것이 우리 시스템의 주요 문제점입니다. 이름을 알기 위해서는 이름을 알아야합니다.

Beemesh 시스템은 모든 디바이스가 생산될 때부터 central authority의 주소를 알도록 했습니다. 컴퓨터가 제일 처음 Beemesh에 연결될 때 이미 TOWN-HALL의 주소를 알고 있게 되는 것이죠.

사실, 이건 인터넷이 작동하는 방식과 매우 흡사합니다. 우리의 컴퓨터는 인터넷에 연결되기 전부터 central naming authority의 주소를 알고 있습니다.

Abstraction

시청의 컴퓨터를 작동시키는 비용은 1시간에 2센트입니다. 이 계산에 따르면 Sophia의 느린 Python 프로그램을 900번 돌리는 비용은 35센트입니다.

Sophia의 시급은 50달러입니다. 그리고 Sophia가 더 빠른 알고리즘으로 프로그램을 개선하는데는 2시간이 걸립니다.

프로그램 개선이 더 저렴한 방법이 되기 위해서는 프로그램을 몇번이나 돌려야할까요?

Interfaces

Jing 시장의 요청을 수행하기 위한 3가지 다른 방법을 알아봤습니다. 하지만 Jing 시장의 입장에서는 이 셋이 모두 같은 Interface를 가지고 있었습니다. 그녀는 항상 Records Office를 통해 Fire Department 메모들을 요청했을 뿐이었습니다.

Jing 시장에게서 감춰진 영역이 있어서 신경쓰이게 하지 않고 다른 방법을 사용하도록 바꿀 수 있었습니다. 인터페이스에서 중요한 부분 중 하나입니다.

Algorithm Fundamentals

1774 %

Building Blocks

Pseudocode
Conditional Algorithms
Manipulating Numbers
Repetition
Arrays

Array Algorithms

Searching an Array
Sorting an Array
Insertion Sort

Selection Sort는 정렬되지 않은 영역을 반복적으로 스캔해 swap을 최소화 합니다.

Insertion Sort는 필요하지 않은 스캔을 줄이고 대신 swap 횟수를 늘립니다

The Speed of Algorithms

Timing Programs with a Stopwatch
Counting Operations
Best, Worst and Average Case
Comparing Algorithms
Understanding Big O
The Mathmatcis of Big O

Stable Matching

The Stable Matching Problem
Using Greediness

Deferred Acceptance Algorithm

Correctness

Termination

Running Time

Variants

  • Gale-Shapley 알고리즘을 현실적인 문제에 맞춰 수정
    • 자리가 2개 이상인 병원
    • 자리와 후보의 수가 불일치
  • 이상적인 조건에서 우선적으로 알고리즘을 만들고 현실에 맞춰 수정하는 과정

Who Benefits?

Data Structures

00 %

Introduction to Neural Networks

00 %
+ \ No newline at end of file diff --git a/study/LeetCode.html b/study/LeetCode.html index cb77f044..d95682d2 100644 --- a/study/LeetCode.html +++ b/study/LeetCode.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

LeetCode

첫번쨰 풀이

javascript
/**
+    
Skip to content
On this page

LeetCode

첫번쨰 풀이

javascript
/**
  * @param {number[]} nums
  * @param {number} target
  * @return {number}
@@ -288,8 +288,8 @@
 
   return result;
 };
  • Runtime 하위 78.34%, 메모리 39.78% 로 그나마 만족스러운 결과. 다른 사람 풀이를 참고해야할 것 같다.
  • const result = new Array(nums.length)로 변경하니 Runtime 97.16%, 메모리 89.43%로 대폭 증가했다. 길이가 특정되지 않은 배열인 경우 메모리 공간 및 후연산 같은 것들이 더 있는 것 같다.
- + \ No newline at end of file diff --git a/study/refactoring/chapter1.html b/study/refactoring/chapter1.html index def1d08f..c28a9e84 100644 --- a/study/refactoring/chapter1.html +++ b/study/refactoring/chapter1.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

Chapter 01 - 리팩터링: 첫 번째 예시

인상깊은 문장, 코드들

1.2 예시 프로그램을 본 소감

  • 프로그램이 잘 작동하는 상황에서 그저 코드가 '지저분하다'는 이유로 불평하는 것은 프로그램의 구조를 너무 미적인 기준으로만 판단하는 건 아닐까? 컴파일러는 코드가 깔끔하든 지저분하든 개의치 않으니 말이다. 하지만 그 코드를 수정하려면 사람이 개입되고, 사람은 코드의 미적 상태에 민감하다. 설계가 나쁜 시스템은 수정하기 어렵다. 원하는 동작을 수행하도록 하기위해 수정해야 할 부분을 찾고, 기존 코드와 잘 맞물려 작동하게 할 방법을 강구하기가 어렵기 떄문이다. 무엇을 수정할지 찾기 어렵다면 실수를 저질러서 버그가 생길 가능성도 높아진다.

  • 그래서 나는 수백 줄짜리 코드를 수정할 때면 먼저 프로그램의 작동 방식을 더 쉽게 파악할 수 있도록 코드를 여러 함수와 프로그램 요소로 재구성한다. 프로그램의 구조가 빈약하다면 대체로 구조부터 바로잡은 뒤에 기능을 수정하는 편이 작업하기가 훨씬 수월하다.

  • 프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가한다.

1.3 리팩터링의 첫 단계

  • 리팩터링의 첫 단계는 항상 똑같다. 리팩터링할 코드 영역을 꼼꼼하게 검사해줄 테스트 코드들부터 마련해야 한다. 리팩터링에서 테스트의 역할은 굉장히 중요하다. 리팩터링 기법들이 버그 발생 여지를 최소화하도록 구성됐다고는 하나 실제 작업은 사람이 수행하기 때문에 언제든 실수할 수 있다.

1.4 statement() 함수 쪼개기

js
export default function statement(invoice, plays) {
+    
Skip to content
On this page

Chapter 01 - 리팩터링: 첫 번째 예시

인상깊은 문장, 코드들

1.2 예시 프로그램을 본 소감

  • 프로그램이 잘 작동하는 상황에서 그저 코드가 '지저분하다'는 이유로 불평하는 것은 프로그램의 구조를 너무 미적인 기준으로만 판단하는 건 아닐까? 컴파일러는 코드가 깔끔하든 지저분하든 개의치 않으니 말이다. 하지만 그 코드를 수정하려면 사람이 개입되고, 사람은 코드의 미적 상태에 민감하다. 설계가 나쁜 시스템은 수정하기 어렵다. 원하는 동작을 수행하도록 하기위해 수정해야 할 부분을 찾고, 기존 코드와 잘 맞물려 작동하게 할 방법을 강구하기가 어렵기 떄문이다. 무엇을 수정할지 찾기 어렵다면 실수를 저질러서 버그가 생길 가능성도 높아진다.

  • 그래서 나는 수백 줄짜리 코드를 수정할 때면 먼저 프로그램의 작동 방식을 더 쉽게 파악할 수 있도록 코드를 여러 함수와 프로그램 요소로 재구성한다. 프로그램의 구조가 빈약하다면 대체로 구조부터 바로잡은 뒤에 기능을 수정하는 편이 작업하기가 훨씬 수월하다.

  • 프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가한다.

1.3 리팩터링의 첫 단계

  • 리팩터링의 첫 단계는 항상 똑같다. 리팩터링할 코드 영역을 꼼꼼하게 검사해줄 테스트 코드들부터 마련해야 한다. 리팩터링에서 테스트의 역할은 굉장히 중요하다. 리팩터링 기법들이 버그 발생 여지를 최소화하도록 구성됐다고는 하나 실제 작업은 사람이 수행하기 때문에 언제든 실수할 수 있다.

1.4 statement() 함수 쪼개기

js
export default function statement(invoice, plays) {
   let totalAmount = 0;
   let volumeCredits = 0;
   let result = `청구내역 (고객명: ${invoice.customer})\n`;
@@ -137,8 +137,8 @@
 // ...

-> 변수 선언 위치를 옮기는 것도 하나의 리팩터링 과정이라는 것이 역시 같은 이유로 인상깊다. 물론 여기서는 관심사를 한 군데에 모아서 별도로 분리하려는 목적이 눈에 보이지만, 변수 선언 위치도 신경써야할 중요한 부분이라는 것을 기억해야 할 것 같다.

  • 여기서 잠시 멈추고 방금 한 일에 대해 생각해보자. 무엇보다도 반복문을 쪼개서 성능이 느려지지 않을까 걱정할 수 있다. 하지만, 이정도 중복은 성능에 미치는 영향이 미미할 때가 많다.

  • 때로는 리팩터링이 성능에 상당한 영향을 주기도 한다. 그런 경우라도 나는 개의치 않고 리팩터링한다. 잘 다듬어진 코드라야 성능 개선 작업도 훨씬 수월하기 때문이다.

1.6 계산 단계와 포맷팅 단계 분리하기

  • 단계 쪼개기

  • 첫 단계에서는 statement()에 필요한 데이터를 처리하고, 다음 단계에서는 앞서 처리한 결과를 텍스트나 HTML로 표현하도록 하자. 다시 말해 첫 번째 단계에서는 두 번째 단계로 전달할 중간 데이터 구조를 생성하는 것이다.

js
function htmlStatement(invoice, plays) {
   return renderHtml(createStatementData(invoice, plays));
 }

-> 실제 팀 내에서 누군가가 위와같은 코드를 작성했다면 코드 리뷰에서 LGTM를 했을까? 내 판단력을 어떻게 믿고 객관성을 어떻게 지닐 수 있을까?

1.10 마치며

  • 좋은 코드를 가늠하는 확실한 방법은 '얼마나 수정하기 쉬운가'다.

  • 이번 예시를 통해 배울 수 있는 가장 중요한 것은 바로 리팩터링하는 리듬이다.

느낀 점

  • 내가 생각하던 리팩터링과 다르게 실제 리팩터링은 아주 작은 단위의 변경이었다. 2챕터에 나오지만 내가 리팩터링(refactoring)이라고 자주 말했던 행위는 재구성(restructuring)에 가까웠던 것 같다.
  • 어떤 코드를 리팩터링 대상인지 포착하는 것이 중요할 것 같은데, 경험이 필요하지 않을까?
  • 테스트 코드가 중요해보인다. 하지만 실제 우리 회사에 적용하는데 어려움이 있는 것도 사실이라 그 간극을 어떻게 메울지가 고민된다. (책에서는 레거시 코드 활용 전략이라는 책을 추천)
  • 리팩터링이 성능에 영향을 줄지라도, 개의치않고 리팩터링해야한다는 점도 기억해야할 것 같다. 프런트엔드에서 반복문 등을 최적화하는 것에 신경쓰기보다는 가독성에 신경을 쓰는 것이 더 중요할 수도 있을 것 같다.
- + \ No newline at end of file diff --git a/study/refactoring/chapter10.html b/study/refactoring/chapter10.html index 3b79556c..b239c825 100644 --- a/study/refactoring/chapter10.html +++ b/study/refactoring/chapter10.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

Chapter 10 - 조건부 로직 간소화

인상깊은 문장, 코드들

10.1 조건문 분해하기

js
if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd))
+    
Skip to content
On this page

Chapter 10 - 조건부 로직 간소화

인상깊은 문장, 코드들

10.1 조건문 분해하기

js
if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd))
     charge = quantity * plan.summerRate;
 else
     charge = quantity * plan.regularRate + plan.regularServiceCharge;

->

js
if (summer())
@@ -35,8 +35,8 @@
 if (this.discountRate) {
     base = base - (this.discountRate * base);
 }
  • 특정 조건이 참일 때만 제대로 동작하는 코드 영역이 있을 수 있다. ... 이런 가정이 코드에 항상 명시적으로 기술되어 있지는 않아서 알고리즘을 보고 연역해서 알아내야 할 때도 있다. 주석에라도 적혀 있다면 그나마 형편이 좀 낫다. 더 나은 방법은 어서션을 이용해서 코드 자체에 삽입해놓는 것이다.

느낀점

  • 10.2 조건식 통합하기에 부합하는 코드가 장바구니 담기 로직에서 존재한다. 수량이 맞는지, 함꼐 구매할 수 없는 상품이 같이 주문되고 있는지 등을 검사한다. 함께 구매할 수 없는 상품을 구분하는 로직을 이미 computed property로 분리했는데, 이럼에도 불구하고 조건식을 통합해야할까? 그리고 여러 if문을 만들어주는게 가독성과 여러 상황을 나타내기에 좋다고 생각했었는데, 이번 기회에 다시 생각해봐야겠다.
  • 10.3 중첩 조건문을 보호 구문으로 바꾸기에서 '보호 구문'이라는 표현을 알 수 있어 좋았다. 기존에는 그냥 일찍 return 하기 정도로 표현했던 것 같다.
  • 10.4 조건부 로직을 다형성으로 바꾸기
    • And 이름이 포함된 메서드를 분리해야한다는 것을 알았다. 기존에 몇개 And 구문을 포함한 메서드를 만들었었는데, 돌아보니 왜 그랬나 싶다. 한 예로 then chaining을 해야하는 경우에 And 를 넣어서 추상화 한 것이 있었다. 들여쓰기가 생기는게 싫어서 그랬던 것 같은데 async await로 대체하면서 동기화를 해주면 좋았을 것 같다.
    • 리팩터링 예제에서 china 관련된 로직에서 분기가 생겨서 이를 분리했는데, 이런 분기 지점을 포착하는 것이 좋았다.
  • 10.5 특이 케이스 추가하기
    • 예제에서처럼 또 다시 파생된 NullPaymentHistory를 생성해주는 것은 코드에 대한 커버가 완벽하게 되는 느낌이라 만족감이 들기도 하지만, 실제 이런 리팩터링을 PR로 생성한다면, 그리고 만약 비슷한 관점이 없는 개발자라면 긍정적으로 받아들이지 않을 수도 있을 것 같다. 너무 단순한 값을 위해 클래스까지 동원한 느낌 (마침 이런 설명이 다음 페이지에 바로 나왔다.)
    • 객체 리터럴이 조금 더 익숙한 느낌으로 와닿는다. 그런데 왜 클래스를 사용하는 쪽을 선호하는지 설명이 없었어서 아쉬웠다.
  • 10.6 어서션 추가하기 실제로 숫자 입력 컴포넌트에서 예외처리를 했던 것 같은데, 로직상에서 if (value < 0) return 0; 이런식으로 처리했던 것 같다. 그럼에도 불구하고 어서션을 추가하는 것이 좋은 것일까? 아니면 음수도 입력받을 수 있는 경우 + 사용자로부터 입력받은 value를 사용하는 쪽에서 양수만 가능한 경우 assert를 해줘야할까? 이미 그 전에 음수를 걸러내는 로직이 있는데 assert를 해줘야 하나? 주석으로 처리하는 것과 차이가 있나? 고민이 든다. 뒷 부분에 '프로그래머가 일으킬만한 오류에만 어서션을 사용한다'고 되어있다. 그럼 테스트코드로 잡는 것이 맞지 않나?
- + \ No newline at end of file diff --git a/study/refactoring/chapter11.html b/study/refactoring/chapter11.html index 7c06a69f..b83f6aa2 100644 --- a/study/refactoring/chapter11.html +++ b/study/refactoring/chapter11.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

Chapter 11 - API 리팩터링

인상깊은 문장, 코드들

모듈과 함수는 소프트웨어를 구성하는 빌딩 블록이며, API는 이 블록들을 끼워 맞추는 연결부다. 이런 API를 이해하기 쉽고 사용하기 쉽게 만드는 일은 중요한 동시에 어렵기도 하다.

11.1 질의 함수와 변경 함수 분리하기

  • 우리는 외부에서 관찰할 수 있는 겉보기 부수효과가 전혀 없이 값을 반환해주는 함수를 추구해야 한다. 이런 함수는 어느 때건 원하는 만큼 호출해도 아무 문제가 없다.
  • 이를 위한 한 가지 방법은 '질의 함수(읽기 함수)는 모두 부수효과가 없어야 한다'는 규칙을 따르는 것이다.

11.2 함수 매개변수화하기

js
function tenPercentRaise(aPerson) {
+    
Skip to content
On this page

Chapter 11 - API 리팩터링

인상깊은 문장, 코드들

모듈과 함수는 소프트웨어를 구성하는 빌딩 블록이며, API는 이 블록들을 끼워 맞추는 연결부다. 이런 API를 이해하기 쉽고 사용하기 쉽게 만드는 일은 중요한 동시에 어렵기도 하다.

11.1 질의 함수와 변경 함수 분리하기

  • 우리는 외부에서 관찰할 수 있는 겉보기 부수효과가 전혀 없이 값을 반환해주는 함수를 추구해야 한다. 이런 함수는 어느 때건 원하는 만큼 호출해도 아무 문제가 없다.
  • 이를 위한 한 가지 방법은 '질의 함수(읽기 함수)는 모두 부수효과가 없어야 한다'는 규칙을 따르는 것이다.

11.2 함수 매개변수화하기

js
function tenPercentRaise(aPerson) {
   aPerson.salary = aPerson.salary.multiply(1.1);
 }
 function fivePercentRaise(aPerson) {
@@ -75,8 +75,8 @@
     this._highMedicalRiskFalg = true;
   }
 }
- + \ No newline at end of file diff --git a/study/refactoring/chapter12.html b/study/refactoring/chapter12.html index 0cc2cf4d..fb68dd3b 100644 --- a/study/refactoring/chapter12.html +++ b/study/refactoring/chapter12.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

Chapter 12 - 상속 다루기

인상깊은 문장, 코드들

12.1 메서드 올리기

  • 나중에 다른 서브클래스가 더해질 수도 있으니 Party의 서브클래스가 monthlyCost()를 구현해야 한다는 사실을 알려주는 게 좋을 것이다.
js
get monthlyCost() {
+    
Skip to content
On this page

Chapter 12 - 상속 다루기

인상깊은 문장, 코드들

12.1 메서드 올리기

  • 나중에 다른 서브클래스가 더해질 수도 있으니 Party의 서브클래스가 monthlyCost()를 구현해야 한다는 사실을 알려주는 게 좋을 것이다.
js
get monthlyCost() {
   throw new SubclassResponsibilityError();
 }

12.6 타입 코드를 서브클래스로 바꾸기

js
function createEmployee(name, type) {
   return new Employee(name, type);
@@ -34,8 +34,8 @@
       return new Manager(name);
   }
 }

12.7 서브클래스 제거하기

  • 더 이상 쓰이지 않는 서브클래스와 마주하는 프로그래머는 가치 없는 것을 이해하느라 에너지를 낭비할 것이다.

12.8 슈퍼클래스 추출하기

  • 객체 지향을 설명할 때 '상속 구조는 현실 세계에서 활용하는 여러 분류 체계에 기초하여 구현에 들어가기 앞서 부모, 자식 관계를 신중하게 설계해야 한다.'라고 이야기하는 사람이 많다.
  • 하지만 내 경험에 비춰보자면 상속은 프로그램이 성장하면서 깨우쳐가게 되며, 슈퍼클래스로 끌어올리고 싶은 공통 요소를 찾았을 때 수행하는 사례가 잦았다.

12.10 서브클래스를 위임으로 바꾸기

  • 그렇다면 이런 행복한 상황에서 나는 왜 서브클래스를 위임으로 바꾸려 할까? 상속은 한 번만 사용할 수 있는 도구다. 따라서 상속을 사용해야 할 다른 이유가 생긴다면, 그리고 그 이유가 프리미엄 예약 서브클래스보다 가치가 크다고 생각된다면 프리미엄 에약을 (상속이 아닌) 다른 방식으로 표현해야 할 것이다.

12.11 슈퍼클래스를 위임으로 바꾸기

  • 상속을 잘못 적용한 예로는 자바의 스택 클래스가 유명하다.
  • 이상의 이유로 '상속은 절대 사용하지 말라'고 조언하는 사람도 있다. 나는 동의하지 않는다. ... 의미상 적합한 조건이라면 상속은 간단하고 효과적인 메커니즘이다. 이런 상황이 변하여 상속이 더는 최선의 방법이 아니게 되면 언제든 이번 리팩터링을 이용해 슈퍼클래스를 위임으로 바꿀 수 있다.

느낀 점

  • 12.6 타입 코드를 서브클래스로 바꾸기 예제는 Vue.js의 예시로 들면 template에서 분기를 해서 마크업을 나눠주다가, 자식 컴포넌트로 쪼개는 것과 비슷할까? 어떨 때 이렇게 하는게 좋을까?
    • 특정 타입에서만 의미가 있는 값을 사용하는 필드나 메서드가 있을 때?
  • 12.7 더 이상 쓰이지 않는 서브클래스와 마주하는 프로그래머는 가치 없는 것을 이해하느라 에너지를 낭비할 것이다. 컴포넌트도 같다. 리팩터링하거나 변경하려는 공통 메서드를 사용하지 않는 컴포넌트에서 사용중인 경우가 있었다.
  • 12.8 프로그램이 성장하면서 깨우쳐가게 된다는 말이 좋았다.
  • 12.10
    • '상속은 한번만 사용할 수 있는 도구다.' 이런 제약을 두는 것이 복잡도를 낮추는데 도움이 되는 것 같다.
    • 결국 분기를 어떻게 해줄 것인지가 중요해보이는 느낌인데 맞을지는 모르겠다. 언어의 도움을 받아 (상속) 분기를 해주던 것을 수동으로 (위임) 분기를 해주는 것으로 바뀐 것 같다.
    • JSX를 사용해서 클래스를 구현가능하게 했던 React와 다르게 Vue에서는 어차피 자식 컴포넌트를 생성할 수 밖에 없다. 그리고 상속이 그렇게 유효한지 또 모르겠으므로.. 딱히 프런트엔드나 Vue에서 상속을 사용할 일이 없었을 것 같긴 하다.
    • SpeiciesDelegate 슈퍼클래스를 또 생성한 것을 보고, 이렇게까지 해야한다는 데서 클래스에 대한 회의감도 잠시 들었다. 그러나, 객체 지향과 같이 널리 사용되는 개념은 분명 이점이 있을 것이다.
  • 12.11
    • 자바와 같은 언어도 잘못 설계하고 (여전히 못 고친) 사례가 있는데 너무 작은 부분을 완벽하게 하려고 하는건 아닌지 하는 반성. 일단 되게 만든 후 제대로 리팩터링 하는 습관만 들여도.. 엄청 훌륭한 개발자가 되는 것 아닐까?
    • 언제든 슈퍼클래스를 위임으로 바꿀 수 있으니 상속은 자유롭게 사용하라 (한번만)는 말도 좋다.
- + \ No newline at end of file diff --git a/study/refactoring/chapter2.html b/study/refactoring/chapter2.html index 76bd26ca..398ea1af 100644 --- a/study/refactoring/chapter2.html +++ b/study/refactoring/chapter2.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Chapter 02 - 리팩터링 원칙

인상깊은 문장, 코드들

2.1 리팩터링 정의

  • 누군가 "리팩터링하다가 코드가 깨져서 며칠이나 고생했다"라고 한다면, 십중팔구 리팩터링한 것이 아니다.
  • 나는 코드베이스를 정리하거나 구조를 바꾸는 모든 작업을 재구성(restructuring)이라는 포괄적인 용어로 표현하고, 리팩터링은 재구성 중 특수한 한 형태로 본다.
  • 한 번에 바꿀 수 있는 작업을 수많은 단계로 잘게 나눠서 작업하는 모습을 처음 접하면 리팩터링하는 것이 오히려 비효율적이라고 생각하기 쉽다. 하지만 이렇게 잘게 나눔으로써 오히려 작업을 더 빨리 처리할 수 있다. 단계들이 체계적으로 구성되어 있기도 하고, 무엇보다 디버깅하는 데 시간을 뺏기지 않기 때문이다.

2.3 리팩터링하는 이유

리팩터링하면 소프트웨어 설계가 좋아진다.

  • 리팩터링하지 않으면 소프트웨어의 내부 설계(아키텍처)가 썩기 쉽다. 아키텍처를 충분히 이해하지 못한 채 단기 목표만을 위해 코드를 수정하다 보면 기반 구조가 무너지기 쉽다.
  • 그러면 코드만 봐서는 설계를 파악하기 어려워진다.
  • 코드 구조가 무너지기 시작하면 악효과가 누적된다. 코드만으로 설계를 파악하기 어려워질수록 설계를 유지하기 어려워지고, 설계가 부패되는 속도는 더욱 빨라진다.
  • 반면 규칙적인 리팩터링은 코드의 구조를 지탱해줄 것이다.

리팩터링하면 소프트웨어를 이해하기 쉬워진다.

  • 사실 프로그래밍에서는 사람이 가장 중요하지만 소홀하기 쉽다. 코드를 컴파일하는 데 시간이 살짝 더 걸린다고 누가 뭐라 하겠는가?
  • 하지만 다른 프로그래머가 내 코드를 제대로 이해했다면 한 시간에 끝낼 수정을 일주일이나 걸린다면 사정이 달라진다.

리팩터링하면 버그를 쉽게 찾을 수 있다.

  • 리팩터링하면 코드가 하는 일을 깊이 파악하게 되면서 새로 깨달은 것을 곧바로 코드에 반영하게 된다.
  • 프로그램의 구조를 명확하게 다듬으면 그냥 '이럴 것이다'라고 가정하던 점들이 분명히 드러나는데, 버그를 지나치려야 지나칠 수 없을 정도까지 명확해진다.
  • 켄트 벡의 말을 떠올리게 해준다. "난 뛰어난 프로그래머가 나이에요. 단지 뛰어난 습관을 지닌 괜찮은 프로그래머일 뿐이에요."

리팩터링하면 프로그래밍 속도를 높일 수 있다.

  • 지금까지 제시한 장점을 한 마디로 정리하면 다음과 같다.
  • 리팩터링하면 코드 개발 속도를 높일 수 있다.
  • 하지만 리팩터링하는 데 시간이 드니 전체 개발 속도는 떨어질까봐 걱정할 수도 있다.

2.4 언제 리팩터링해야 할까?

3의 법칙

  1. 처음에는 그냥 한다.
  2. 비슷한 일을 두 번째로 하게 되면 일단 계속한다.
  3. 비슷한 일을 세 번째 하게 되면 리팩터링한다.

준비를 위한 리팩터링: 기능을 쉽게 추가하게 만들기

  • 리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전이다.

이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기

  • 나는 코드를 파악할 때마다 그 코드의 의도가 더 명확하게 드러나도록 리팩터링할 여지는 없는지 찾아본다.
  • 이쯤 되면 코드를 어느 정도 이해하게 되지만, 아쉽게도 나는 기억력이 나빠서 그런 세부사항을 오래 기억하지 못한다.
  • 내가 이해한 것을 코드에 반영해두면 더 오래 보존할 수 있을 뿐만 아니라 동료들도 알 수 있다.

쓰레기 줍기 리팩터링

  • 코드를 파악하던 중에 일을 비효율적으로 처리하는 모습을 발견할 때가 있다.
  • 이때 약간 절충을 해야 한다. 원래 하려던 작업과 관련 없는 일에 너무 많은 시간을 빼앗기긴 싫을 것이다.
  • 그렇다고 쓰레기가 나뒹굴게 방치해서 나중에 일을 방해하도록 내버려두는 것도 좋지 않다.
  • 나라면 간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음, 하던 일을 끝내고 나서 처리한다.

계획된 리팩터링과 수시로 하는 리팩터링

  • 나는 개발에 들어가기 전에 리팩터링 일정을 따로 잡아두지 않고, 기능을 추가하거나 버그를 잡는 동안 리팩터링도 함께 한다.
  • 간과하기 쉽지만 굉장히 중요한 점이다. 리팩터링은 프로그래밍과 구분되는 별개의 활동이 아니다. 마치 프로그래밍할 떄 if문 작성 시간을 따로 구문하지 않는 것과 같다.

보기 싫은 코드를 발견하면 리팩터링하자. 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야한다.

무언가 수정하려 할 때는 먼저 수정하기 쉽게 정돈하고(단, 만만치 않을 수 있다)

그런 다음 쉽게 수정하자. - 켄트 벡

  • 계획된 리팩터링이 무조건 나쁘다는 말은 아니다. 그동안 리팩터링에 소홀했다면, 따로 시간을 내서 새 기능을 추가하기 쉽도록 코드베이스를 개선할 필요가 있다. 이때 리팩터링에 투자한 일주일의 효과를 다음 몇 달 동안 누릴 수도 있다.
  • 리팩터링 작업 대부분은 드러나지 않게, 기회가 될 때마다 해야 한다.

오래 걸리는 리팩터링

  • 팀 전체가 달려들어도 몇 주는 걸리는 대규모 리팩터링도 있다.
  • 이런 상황에 처하더라도 팀 전체가 리팩터링에 매달리는 데는 회의적이다. 그보다는 주어진 문제를 몇 주에 걸쳐 조금씩 해결해나가는 편이 효과적일 때가 많다.
  • 누구든지 리팩터링해야할 코드와 관련한 작업을 하게 될 때마다 원하는 방향으로 조금씩 개선하는 식이다.
  • 예컨대 라이브러리를 교체할 때는 기존 것과 새 것 모두를 포용하는 추상 인터페이스부터 마련한다. 기존 코드가 이 추상 인터페이스를 호출하도록 만들고 나면 라이브러리를 훨씬 쉽게 교체할 수 있다.

코드 리뷰에 리팩터링 활용하기

  • 리팩터링은 다른 이의 코드를 리뷰하는 데도 도움된다.
  • 지금은 새로운 아이디어가 떠오르면 리팩터링하여 쉽게 구현해넣을 수 있는지부터 살펴본다. 쉽다면 실제로 리팩터링한다.
  • 흔히 쓰는 풀 리퀘스트 모델에서는 그리 효과적이지 않다. 이왕이면 참석자가 참석하는 방식이 좋다. 내가 경험한 가장 좋은 방법은 작성자와 나란히 앉아서 코드를 훑어가면서 리팩터링하는 것이다. (짝 프로그래밍)

관리자에게는 뭐라고 말해야 할까?

  • 기술을 모르는 상당수의 관리자와 고객은 코드베이스의 건강 상태가 생산성에 미치는 영향을 모른다. 이런 상황에 있는 이들에게는 "리팩터링한다고 말하지 말라"고 조언하겠다.
  • 하극상일까? 그렇진 않다. 소프트웨어 개발자는 프로다. 프로 개발자의 역할은 효과적인 소프트웨어를 최대한 빠르게 만드는 것이다. 내 경험상 리팩터링하면 소프트웨어를 빠르게 만드는 데 아주 효과적이다.

리팩터링하지 말아야 할 때

  • 지저분한 코드를 발견해도 굳이 수정할 피룡가 없다면 리팩터링하지 않는다.
  • 외부 API 다루듯 호출해서 쓰는 코드라면 지저분해도 그냥 둔다.
  • 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.
  • 리팩터링하는 것보다 처음부터 새로 작성하는 게 쉬울 때도 리팩터링하지 않는다.
  • 사실 이런 결정을 내리기는 쉽지 않다. 직접 리팩터링해보기 전에는 어느 쪽이 쉬운지 확실히 알 수 없을때도 많기 때문이다.
  • 뛰어난 판단력과 경험이 뒷받침돼야 한다. 그래서 이 판단에 대해서는 한 마디 조언으로 표현하기는 어렵다.

2.9 리팩터링의 유래

  • 리팩터링이 중요함을 깨달은 선구자들인 워드 커닝햄과 켄트 벡은 1980년대부터 스몰토크를 활용해 개발해왔다. 스몰토크는 기능이 풍부한 소프트웨어를 빠르게 작성할 수 있는 굉장히 역동적인 환경인데, 당시 개발 환경 중에서 리팩터링을 활용해보기에 특히 좋았다. 스몰토크는 컴파일 - 링크 - 실행 주기가 상당히 짧아서 마지막으로 컴파일한 시점을 안다면 수정 작업을 빠르게 진행할 수 있었다.
  • 워드와 켄트는 이런 환경에 특화된 소프트웨어 개발 방법을 고민했고, 그 결과로 XP가 탄생한 것이다. 워드와 켄트는 생산성을 높이는 데 리팩터링의 역할이 크다는 사실을 깨닫고, 그 후로 리팩터링을 실전 프로젝트에 활용하면서 개선해나갔다.
  • 두 사람의 아이디어가 스몰토크 커뮤니티에 큰 반향을 일으키면서 리팩터링이란 개념이 스몰토크 개발 문화에 중요한 요소로 자리 잡았다.
  • 랄프의 박사 과정 학생인 빌 옵다이크는 특히 프레임워크에 관심이 많았다. 그는 리팩터링의 잠재 가치를 간파하고 스몰토크를 넘어 다른 언어들에도 적용할 수 있으리라 생각했다. 빌은 박사 연구 주제로 리팩터링을 개발 도구에서 지원하는 방안을 파고들었고, 그중에서도 C++ 프레임워크 개발에 유용한 리팩터링에 관심이 많았다.
  • 다행히 리팩터링이란 개념을 업계에서 잘 받아들였다. ... 이처럼 대중화되면서 코드를 재구성하는 모든 작업을 가리키는 느슨한 의미로 사용하는 사람이 많아졌다. 어쨌든 리팩터링은 주류 개발 기법으로 자리 잡았다.

2.10 리팩터링 자동화

  • 리팩터링과 관련하여 지난 수십 년 사이에 가장 큰 변화는 자동 리팩터링을 지원하는 도구가 등장한 것이다. 예를 들어 <인텔리제이 IDEA>나 <이클립스>에서 자바로 프로그래밍할 때는 메서드 이름을 바꾸는 작업을 메뉴에서 원하는 항목을 클릭하는 것만으로 처리할 수 있다.
  • 현재는 에디터나 독립 도구에서도 리팩터링 기능을 제공할 정도로 자동 리팩터링이 흔해졌다. 물론 완성도는 저마다 제법 차이가 난다.
  • 자동 리팩터링을 제대로 구현하려면 코드를 텍스트 상태가 아닌, 구문 트리로 해석해서 다뤄야 한다.
  • 정적 타입 언어라면 훨씬 안전하게 구현할 수 있는 리팩터링 수가 늘어난다.
  • 대부분의 리팩터링이 믿을만하더라도 중간에 꼬인 부분이 없는지 이따금 테스트로 확인하는 것이 바람직하다. 나는 주로 자동 리팩터링과 수동 리팩터링을 함께 사용한다. 그래서 테스트도 충분히 거친다.
  • 최근에는 언어 서버라는 기술이 뜨고 있다. 언어 서버란 구문 트리를 구성해서 텍스트 에디터에 API 형태로 제공하는 소프트웨어다. 언어 서버는 다양한 텍스트 에디터를 지원할 수 있고, 정교한 코드 분석과 리팩터링 기능을 제공할 수 있다.

2.11 더 알고싶다면

  • 이 책은 그동안 많은 독자에게 리팩터링을 소개했지만, 독자가 리팩터링을 체화하게끔 이끌기보다는 특정 리팩터링 기법이 궁금할 때 찾아볼 수 있는 레퍼런스를 제공하는 데 주력했다. 리팩터링 연습에 주력한 책을 원한다면 윌리엄 웨이크가 쓴 "리팩터링 워크북"을 추천한다.
  • 책 제목에는 리팩터링이란 단어가 없지만 참고할 만한 책으로 마이클 페더스의 "레거시 코드 활용 전략"이 있다. 이 책은 주로 테스트 커버리지가 낮은 오래된 코드베이스를 리팩터링하는 방법을 다루고 있다.

느낀 점

  • 리팩터링이라는 용어에 대해 정확히 이해하지 못하고 있었던 것 같다.

    누군가 "리팩터링하다가 코드가 깨져서 며칠이나 고생했다"라고 한다면, 십중팔구 리팩터링한 것이 아니다. 나는 코드베이스를 정리하거나 구조를 바꾸는 모든 작업을 재구성(restructuring)이라는 포괄적인 용어로 표현하고, 리팩터링은 재구성 중 특수한 한 형태로 본다.

    • 내가 리팩터링이라고 인식했던 행위는 거의 재구성이라는 행위였던 것 같다.
  • 실제 리팩터링을 활용해볼 수 있지 않을까?

    • 회사에서 더 이상 관리되지 않는 서드파티 패키지를 업데이트하려고 하는데, 이 패키지를 사용하고 있는 곳이 많고 업데이트를 하게되면 이전과 사용방식이 달라져 고민을 하고 있던 중이었다.
    • 2.4 오래 걸리는 리팩터링의 범주 안에서 기존 것과 새 것을 모두 포용하는 추상 컴포넌트를 만들어서 기존 코드를 수정하고, 새로운 코드를 작성하면서 리팩터링을 진행해보면 어떨까 싶다.
  • 리팩터링한다고 말하지 말았어야 했던 것 같다.

    • 최근 레거시 코드와 빌드 환경을 업그레이드하기 위해서 리팩터링 기간을 관리자에게 요청한 적이 있는데, 책을 읽고 나니 별도의 기간을 요청하지 않고 개발을 하며 자연스럽게 진행했어야 했던 것 같다.
  • 언제 리팩터링 해야할까 소챕터의 내용은 여러번 더 읽어봐야겠다.

  • 지속적인 통합에 대한 다른 사람들의 의견이 궁금하다

    • 혼자서 작업하는 코드베이스라면 가능할 것 같다. 그러나 여러 사람이 함께 작업하는 코드베이스라면 이론적으로만 가능한 방법이지 않을까? 기존 기능이 호환되는지에 대한 테스트코드가 철저하게 동작하고 있어야할 것 같다. 그리고 새로 추가되는 기능이 릴리즈 전에는 작동하지 않는지를 테스트해야하는걸까? 이런 테스트 코드가 유의미한가?
  • 레거시 코드를 부분적으로 리팩터링한다면?

    • 어느 회사나 어느정도 그렇겠지만 현재 회사의 프런트엔드 코드에도 레거시가 많고, 중구난방으로 짜여있는 스파게티 코드들도 많다. 그 때문에 기능 추가나 수정에 항상 스트레스와 부담을 느끼는데, 책에서 언급한 '레거시 코드 활용 전략'의 내용도 궁금하고, 레거시 코드를 부분적으로 공략해서 조금이라도 개선해나간다면 지금보다 더 기능 추가와 수정이 쉽게 될까?
    • 진행되다만 흔적들만 남을까봐 걱정도 된다.
  • 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하는 것은 아키텍처가 아니라 코드레벨에서도 좋은 것 같다.

    • 코드레벨에서도 추측으로 미래를 대비해 코드를 작성하지말고 현재 파악한 요구사항만을 해결하는 코드를 작성하자.
    • 그리고 추가 요구사항이 들어오면 그때 리팩터링을 통해 코드를 수정하자.
  • 성능에 대한 신비로운 사실. 전체 코드 중 극히 일부에서 대부분의 시간을 소비한다.

  • IDE에서 지원하는 리팩터링을 활용해보고 싶다.

    • JavaScript에서도 가능할까? Vue나 React처럼 프런트엔드 프레임워크에서도 가능할까?
- +
Skip to content
On this page

Chapter 02 - 리팩터링 원칙

인상깊은 문장, 코드들

2.1 리팩터링 정의

  • 누군가 "리팩터링하다가 코드가 깨져서 며칠이나 고생했다"라고 한다면, 십중팔구 리팩터링한 것이 아니다.
  • 나는 코드베이스를 정리하거나 구조를 바꾸는 모든 작업을 재구성(restructuring)이라는 포괄적인 용어로 표현하고, 리팩터링은 재구성 중 특수한 한 형태로 본다.
  • 한 번에 바꿀 수 있는 작업을 수많은 단계로 잘게 나눠서 작업하는 모습을 처음 접하면 리팩터링하는 것이 오히려 비효율적이라고 생각하기 쉽다. 하지만 이렇게 잘게 나눔으로써 오히려 작업을 더 빨리 처리할 수 있다. 단계들이 체계적으로 구성되어 있기도 하고, 무엇보다 디버깅하는 데 시간을 뺏기지 않기 때문이다.

2.3 리팩터링하는 이유

리팩터링하면 소프트웨어 설계가 좋아진다.

  • 리팩터링하지 않으면 소프트웨어의 내부 설계(아키텍처)가 썩기 쉽다. 아키텍처를 충분히 이해하지 못한 채 단기 목표만을 위해 코드를 수정하다 보면 기반 구조가 무너지기 쉽다.
  • 그러면 코드만 봐서는 설계를 파악하기 어려워진다.
  • 코드 구조가 무너지기 시작하면 악효과가 누적된다. 코드만으로 설계를 파악하기 어려워질수록 설계를 유지하기 어려워지고, 설계가 부패되는 속도는 더욱 빨라진다.
  • 반면 규칙적인 리팩터링은 코드의 구조를 지탱해줄 것이다.

리팩터링하면 소프트웨어를 이해하기 쉬워진다.

  • 사실 프로그래밍에서는 사람이 가장 중요하지만 소홀하기 쉽다. 코드를 컴파일하는 데 시간이 살짝 더 걸린다고 누가 뭐라 하겠는가?
  • 하지만 다른 프로그래머가 내 코드를 제대로 이해했다면 한 시간에 끝낼 수정을 일주일이나 걸린다면 사정이 달라진다.

리팩터링하면 버그를 쉽게 찾을 수 있다.

  • 리팩터링하면 코드가 하는 일을 깊이 파악하게 되면서 새로 깨달은 것을 곧바로 코드에 반영하게 된다.
  • 프로그램의 구조를 명확하게 다듬으면 그냥 '이럴 것이다'라고 가정하던 점들이 분명히 드러나는데, 버그를 지나치려야 지나칠 수 없을 정도까지 명확해진다.
  • 켄트 벡의 말을 떠올리게 해준다. "난 뛰어난 프로그래머가 나이에요. 단지 뛰어난 습관을 지닌 괜찮은 프로그래머일 뿐이에요."

리팩터링하면 프로그래밍 속도를 높일 수 있다.

  • 지금까지 제시한 장점을 한 마디로 정리하면 다음과 같다.
  • 리팩터링하면 코드 개발 속도를 높일 수 있다.
  • 하지만 리팩터링하는 데 시간이 드니 전체 개발 속도는 떨어질까봐 걱정할 수도 있다.

2.4 언제 리팩터링해야 할까?

3의 법칙

  1. 처음에는 그냥 한다.
  2. 비슷한 일을 두 번째로 하게 되면 일단 계속한다.
  3. 비슷한 일을 세 번째 하게 되면 리팩터링한다.

준비를 위한 리팩터링: 기능을 쉽게 추가하게 만들기

  • 리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전이다.

이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기

  • 나는 코드를 파악할 때마다 그 코드의 의도가 더 명확하게 드러나도록 리팩터링할 여지는 없는지 찾아본다.
  • 이쯤 되면 코드를 어느 정도 이해하게 되지만, 아쉽게도 나는 기억력이 나빠서 그런 세부사항을 오래 기억하지 못한다.
  • 내가 이해한 것을 코드에 반영해두면 더 오래 보존할 수 있을 뿐만 아니라 동료들도 알 수 있다.

쓰레기 줍기 리팩터링

  • 코드를 파악하던 중에 일을 비효율적으로 처리하는 모습을 발견할 때가 있다.
  • 이때 약간 절충을 해야 한다. 원래 하려던 작업과 관련 없는 일에 너무 많은 시간을 빼앗기긴 싫을 것이다.
  • 그렇다고 쓰레기가 나뒹굴게 방치해서 나중에 일을 방해하도록 내버려두는 것도 좋지 않다.
  • 나라면 간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음, 하던 일을 끝내고 나서 처리한다.

계획된 리팩터링과 수시로 하는 리팩터링

  • 나는 개발에 들어가기 전에 리팩터링 일정을 따로 잡아두지 않고, 기능을 추가하거나 버그를 잡는 동안 리팩터링도 함께 한다.
  • 간과하기 쉽지만 굉장히 중요한 점이다. 리팩터링은 프로그래밍과 구분되는 별개의 활동이 아니다. 마치 프로그래밍할 떄 if문 작성 시간을 따로 구문하지 않는 것과 같다.

보기 싫은 코드를 발견하면 리팩터링하자. 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야한다.

무언가 수정하려 할 때는 먼저 수정하기 쉽게 정돈하고(단, 만만치 않을 수 있다)

그런 다음 쉽게 수정하자. - 켄트 벡

  • 계획된 리팩터링이 무조건 나쁘다는 말은 아니다. 그동안 리팩터링에 소홀했다면, 따로 시간을 내서 새 기능을 추가하기 쉽도록 코드베이스를 개선할 필요가 있다. 이때 리팩터링에 투자한 일주일의 효과를 다음 몇 달 동안 누릴 수도 있다.
  • 리팩터링 작업 대부분은 드러나지 않게, 기회가 될 때마다 해야 한다.

오래 걸리는 리팩터링

  • 팀 전체가 달려들어도 몇 주는 걸리는 대규모 리팩터링도 있다.
  • 이런 상황에 처하더라도 팀 전체가 리팩터링에 매달리는 데는 회의적이다. 그보다는 주어진 문제를 몇 주에 걸쳐 조금씩 해결해나가는 편이 효과적일 때가 많다.
  • 누구든지 리팩터링해야할 코드와 관련한 작업을 하게 될 때마다 원하는 방향으로 조금씩 개선하는 식이다.
  • 예컨대 라이브러리를 교체할 때는 기존 것과 새 것 모두를 포용하는 추상 인터페이스부터 마련한다. 기존 코드가 이 추상 인터페이스를 호출하도록 만들고 나면 라이브러리를 훨씬 쉽게 교체할 수 있다.

코드 리뷰에 리팩터링 활용하기

  • 리팩터링은 다른 이의 코드를 리뷰하는 데도 도움된다.
  • 지금은 새로운 아이디어가 떠오르면 리팩터링하여 쉽게 구현해넣을 수 있는지부터 살펴본다. 쉽다면 실제로 리팩터링한다.
  • 흔히 쓰는 풀 리퀘스트 모델에서는 그리 효과적이지 않다. 이왕이면 참석자가 참석하는 방식이 좋다. 내가 경험한 가장 좋은 방법은 작성자와 나란히 앉아서 코드를 훑어가면서 리팩터링하는 것이다. (짝 프로그래밍)

관리자에게는 뭐라고 말해야 할까?

  • 기술을 모르는 상당수의 관리자와 고객은 코드베이스의 건강 상태가 생산성에 미치는 영향을 모른다. 이런 상황에 있는 이들에게는 "리팩터링한다고 말하지 말라"고 조언하겠다.
  • 하극상일까? 그렇진 않다. 소프트웨어 개발자는 프로다. 프로 개발자의 역할은 효과적인 소프트웨어를 최대한 빠르게 만드는 것이다. 내 경험상 리팩터링하면 소프트웨어를 빠르게 만드는 데 아주 효과적이다.

리팩터링하지 말아야 할 때

  • 지저분한 코드를 발견해도 굳이 수정할 피룡가 없다면 리팩터링하지 않는다.
  • 외부 API 다루듯 호출해서 쓰는 코드라면 지저분해도 그냥 둔다.
  • 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.
  • 리팩터링하는 것보다 처음부터 새로 작성하는 게 쉬울 때도 리팩터링하지 않는다.
  • 사실 이런 결정을 내리기는 쉽지 않다. 직접 리팩터링해보기 전에는 어느 쪽이 쉬운지 확실히 알 수 없을때도 많기 때문이다.
  • 뛰어난 판단력과 경험이 뒷받침돼야 한다. 그래서 이 판단에 대해서는 한 마디 조언으로 표현하기는 어렵다.

2.9 리팩터링의 유래

  • 리팩터링이 중요함을 깨달은 선구자들인 워드 커닝햄과 켄트 벡은 1980년대부터 스몰토크를 활용해 개발해왔다. 스몰토크는 기능이 풍부한 소프트웨어를 빠르게 작성할 수 있는 굉장히 역동적인 환경인데, 당시 개발 환경 중에서 리팩터링을 활용해보기에 특히 좋았다. 스몰토크는 컴파일 - 링크 - 실행 주기가 상당히 짧아서 마지막으로 컴파일한 시점을 안다면 수정 작업을 빠르게 진행할 수 있었다.
  • 워드와 켄트는 이런 환경에 특화된 소프트웨어 개발 방법을 고민했고, 그 결과로 XP가 탄생한 것이다. 워드와 켄트는 생산성을 높이는 데 리팩터링의 역할이 크다는 사실을 깨닫고, 그 후로 리팩터링을 실전 프로젝트에 활용하면서 개선해나갔다.
  • 두 사람의 아이디어가 스몰토크 커뮤니티에 큰 반향을 일으키면서 리팩터링이란 개념이 스몰토크 개발 문화에 중요한 요소로 자리 잡았다.
  • 랄프의 박사 과정 학생인 빌 옵다이크는 특히 프레임워크에 관심이 많았다. 그는 리팩터링의 잠재 가치를 간파하고 스몰토크를 넘어 다른 언어들에도 적용할 수 있으리라 생각했다. 빌은 박사 연구 주제로 리팩터링을 개발 도구에서 지원하는 방안을 파고들었고, 그중에서도 C++ 프레임워크 개발에 유용한 리팩터링에 관심이 많았다.
  • 다행히 리팩터링이란 개념을 업계에서 잘 받아들였다. ... 이처럼 대중화되면서 코드를 재구성하는 모든 작업을 가리키는 느슨한 의미로 사용하는 사람이 많아졌다. 어쨌든 리팩터링은 주류 개발 기법으로 자리 잡았다.

2.10 리팩터링 자동화

  • 리팩터링과 관련하여 지난 수십 년 사이에 가장 큰 변화는 자동 리팩터링을 지원하는 도구가 등장한 것이다. 예를 들어 <인텔리제이 IDEA>나 <이클립스>에서 자바로 프로그래밍할 때는 메서드 이름을 바꾸는 작업을 메뉴에서 원하는 항목을 클릭하는 것만으로 처리할 수 있다.
  • 현재는 에디터나 독립 도구에서도 리팩터링 기능을 제공할 정도로 자동 리팩터링이 흔해졌다. 물론 완성도는 저마다 제법 차이가 난다.
  • 자동 리팩터링을 제대로 구현하려면 코드를 텍스트 상태가 아닌, 구문 트리로 해석해서 다뤄야 한다.
  • 정적 타입 언어라면 훨씬 안전하게 구현할 수 있는 리팩터링 수가 늘어난다.
  • 대부분의 리팩터링이 믿을만하더라도 중간에 꼬인 부분이 없는지 이따금 테스트로 확인하는 것이 바람직하다. 나는 주로 자동 리팩터링과 수동 리팩터링을 함께 사용한다. 그래서 테스트도 충분히 거친다.
  • 최근에는 언어 서버라는 기술이 뜨고 있다. 언어 서버란 구문 트리를 구성해서 텍스트 에디터에 API 형태로 제공하는 소프트웨어다. 언어 서버는 다양한 텍스트 에디터를 지원할 수 있고, 정교한 코드 분석과 리팩터링 기능을 제공할 수 있다.

2.11 더 알고싶다면

  • 이 책은 그동안 많은 독자에게 리팩터링을 소개했지만, 독자가 리팩터링을 체화하게끔 이끌기보다는 특정 리팩터링 기법이 궁금할 때 찾아볼 수 있는 레퍼런스를 제공하는 데 주력했다. 리팩터링 연습에 주력한 책을 원한다면 윌리엄 웨이크가 쓴 "리팩터링 워크북"을 추천한다.
  • 책 제목에는 리팩터링이란 단어가 없지만 참고할 만한 책으로 마이클 페더스의 "레거시 코드 활용 전략"이 있다. 이 책은 주로 테스트 커버리지가 낮은 오래된 코드베이스를 리팩터링하는 방법을 다루고 있다.

느낀 점

  • 리팩터링이라는 용어에 대해 정확히 이해하지 못하고 있었던 것 같다.

    누군가 "리팩터링하다가 코드가 깨져서 며칠이나 고생했다"라고 한다면, 십중팔구 리팩터링한 것이 아니다. 나는 코드베이스를 정리하거나 구조를 바꾸는 모든 작업을 재구성(restructuring)이라는 포괄적인 용어로 표현하고, 리팩터링은 재구성 중 특수한 한 형태로 본다.

    • 내가 리팩터링이라고 인식했던 행위는 거의 재구성이라는 행위였던 것 같다.
  • 실제 리팩터링을 활용해볼 수 있지 않을까?

    • 회사에서 더 이상 관리되지 않는 서드파티 패키지를 업데이트하려고 하는데, 이 패키지를 사용하고 있는 곳이 많고 업데이트를 하게되면 이전과 사용방식이 달라져 고민을 하고 있던 중이었다.
    • 2.4 오래 걸리는 리팩터링의 범주 안에서 기존 것과 새 것을 모두 포용하는 추상 컴포넌트를 만들어서 기존 코드를 수정하고, 새로운 코드를 작성하면서 리팩터링을 진행해보면 어떨까 싶다.
  • 리팩터링한다고 말하지 말았어야 했던 것 같다.

    • 최근 레거시 코드와 빌드 환경을 업그레이드하기 위해서 리팩터링 기간을 관리자에게 요청한 적이 있는데, 책을 읽고 나니 별도의 기간을 요청하지 않고 개발을 하며 자연스럽게 진행했어야 했던 것 같다.
  • 언제 리팩터링 해야할까 소챕터의 내용은 여러번 더 읽어봐야겠다.

  • 지속적인 통합에 대한 다른 사람들의 의견이 궁금하다

    • 혼자서 작업하는 코드베이스라면 가능할 것 같다. 그러나 여러 사람이 함께 작업하는 코드베이스라면 이론적으로만 가능한 방법이지 않을까? 기존 기능이 호환되는지에 대한 테스트코드가 철저하게 동작하고 있어야할 것 같다. 그리고 새로 추가되는 기능이 릴리즈 전에는 작동하지 않는지를 테스트해야하는걸까? 이런 테스트 코드가 유의미한가?
  • 레거시 코드를 부분적으로 리팩터링한다면?

    • 어느 회사나 어느정도 그렇겠지만 현재 회사의 프런트엔드 코드에도 레거시가 많고, 중구난방으로 짜여있는 스파게티 코드들도 많다. 그 때문에 기능 추가나 수정에 항상 스트레스와 부담을 느끼는데, 책에서 언급한 '레거시 코드 활용 전략'의 내용도 궁금하고, 레거시 코드를 부분적으로 공략해서 조금이라도 개선해나간다면 지금보다 더 기능 추가와 수정이 쉽게 될까?
    • 진행되다만 흔적들만 남을까봐 걱정도 된다.
  • 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하는 것은 아키텍처가 아니라 코드레벨에서도 좋은 것 같다.

    • 코드레벨에서도 추측으로 미래를 대비해 코드를 작성하지말고 현재 파악한 요구사항만을 해결하는 코드를 작성하자.
    • 그리고 추가 요구사항이 들어오면 그때 리팩터링을 통해 코드를 수정하자.
  • 성능에 대한 신비로운 사실. 전체 코드 중 극히 일부에서 대부분의 시간을 소비한다.

  • IDE에서 지원하는 리팩터링을 활용해보고 싶다.

    • JavaScript에서도 가능할까? Vue나 React처럼 프런트엔드 프레임워크에서도 가능할까?
+ \ No newline at end of file diff --git a/study/refactoring/chapter3.html b/study/refactoring/chapter3.html index a8bae6ac..3c584c9c 100644 --- a/study/refactoring/chapter3.html +++ b/study/refactoring/chapter3.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Chapter 03 - 코드에서 나는 악취

인상깊은 문장, 코드들

리팩터링을 언제 시작하고 언제 그만할지를 판단하는 일은 리팩터링의 작동 원리를 아는 것 못지않게 중요하다.

인스턴스 변수를 삭제하거나 상속 계층을 만드는 방법을 설명하기는 쉽다. 이런 일들은 간단한 문제에 속한다. 하지만 이런 일들을 '언제' 해야 하는지에 대해서는 명확하게 정립된 규칙이 없다.

리팩터링을 언제 멈춰야 하는지를 판단하는 정확한 기준을 제시하지는 않을 것이다. 경험에 따르면 숙련된 사람의 직관만큼 정확한 기준은 없다. 종료 기준보다는 리팩터링하면 해결할 수 있는 문제의 징후를 제시하겠다.

3.1 기이한 이름

  • 추리 소설이라면 무슨 일이 전개되는지 궁금증을 자아낼수록 좋지만, 코드는 아니다. 세계적인 기인이라는 느낌을 풍기고 싶더라도 꾹 참고 코드는 단순하고 명료하게 작성해야 한다.
  • 코드를 명료하게 표현하는 데 가장 중요한 요소 하나는 바로 '이름'이다. 그래서 함수, 모듈, 변수, 클래스 등은 그 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록 엄청나게 신경 써서 이름을 지어야 한다.
  • 하지만 아쉽게도 이름 짓기는 프로그래밍에서 가장 어렵기로 손꼽히는 두 가지중 하나다. (다른 하나는 캐시 무효화다.)
  • 이름 바꾸기는 단순히 이름을 다르게 표현하는 연습이 아니다. 마땅한 이름이 떠오르지 않는다면 설계에 더 근본적인 문제가 숨어 있을 가능성이 높다. 그래서 혼란스러운 이름을 잘 정리하다 보면 코드가 훨씬 간결해질 때가 많다.

3.2 중복 코드

  • 똑같은 코드 구조가 여러 곳에서 반복된다면 하나로 통합하여 더 나은 프로그램을 만들 수 있다. 코드가 중복되면 각각을 볼 때마다 서로 차이점은 없는지 주의 깊에 살펴봐야 하는 부담이 생긴다. 그중 하나를 변경할 때는 다른 비슷한 코드들도 모두 살펴보고 적절히 수정해야 한다.

3.3 긴 함수

  • 짧은 함수들로 구성된 코드베이스를 얼핏 훑으면 연산하는 부분이 하나도 없어 보인다. 코드가 끝없이 위임하는 방식으로 작성되어 있기 때문이다. 하지만 이런 프로그램을 수년 동안 다루다보면 이 짧은 함수들이 얼마나 중요한지 깨닫게 된다. 간접 호출의 효과, 즉 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 떄 나오는 것이다.
  • 예전 언어는 서브루틴을 호출하는 비용이 컸기 때문에 짧은 함수를 꺼렸다. 하지만 요즘 언어는 프로세스 안에서의 함수 호출 비용을 거의 없애버렸다. 물론 코드를 읽는 사람 입장에서는 함수가 하는 일을 파악하기 위해 왔다 갔다 해야 하므로 여전히 부담이 된다. 다행히 함수 호출부와 선언부 사이를 빠르게 이동하거나 호출과 선언을 동시에 보여주는 개발 환경을 활용하면 이 부담이 줄어들지만, 짧은 함수로 구성된 코드를 이해하기 쉽게 만드는 가장 확실한 방법은 좋은 이름이다.
  • 주석을 달아야 할 만한 부분은 무조건 함수로 만든다. 본문에는 원래 주석으로 설명하려던 코드가 담기고, 함수 이름은 동작 방식이 아닌 '의도'가 드러나게 짓는다.
  • 함수를 짧게 만드는 작업의 99%는 함수 추출하기가 차지한다.
  • 조건문이나 반복문도 추출 대상의 실마리를 제공한다.
  • 반복문도 그 안의 코드와 함께 추출해서 독립된 함수로 만든다. 추출한 반복문 코드에 적합한 이름이 떠오르지 않는다면 성격이 다른 두 가지 작업이 섞여 있기 때문일 수 있다. 이럴 때는 과감히 반복문 쪼개기를 적용해서 작업을 분리한다.

3.4 긴 매개변수 목록

  • 종종 다른 매개변수에서 값을 얻어올 수 있는 매개변수가 있을 수 있는데, 이런 매개변수는 매개변수를 질의 함수로 바꾸기로 제거할 수 있다.
  • 사용 중인 데이터 구조에서 값들을 뽑아 각각을 별개의 매개변수로 전달하는 코드라면 객체 통째로 넘기기를 적용해서 원본 데이터 구조를 그대로 전달한다.
  • 함수의 동작 방식을 정하는 플래그 역할의 매개변수는 플래그 인수 제거하기로 없애준다.

3.5 전역 데이터

  • 전역 데이터를 주의해야 한다는 말은 우리가 소프트웨어 개발을 시작한 초창기부터 귀가 따갑게 들었다. 심지어 전역 데이터는 이를 함부로 사용한 프로그래머들에게 벌을 주는 지옥 4층에 사는 악마들이 만들었다는 말이 돌 정도였다.
  • 이를 방지하기 위해 우리가 사용하는 대표적인 리팩터링은 변수 캡슐화하기다. 다른 코드에서 오염시킬 가능성이 있는 데이터를 발견할 때마다 이 기법을 가장 먼저 적용한다. 이런 데이터를 함수로 감싸는 것만으로도 데이터를 수정하는 부분을 쉽게 찾을 수 있고 접근을 통제할 수 있게 된다.

3.6 가변 데이터

  • 무분별한 데이터 수정에 따른 위험을 줄이는 방법은 얼마든지 있다. (변수 캡슐화하기)
  • 값을 다른 곳에서 설정할 수 있는 가변 데이터가 풍기는 악취는 특히 고약하다. 혼동과 버그와 야근을 부를 뿐만 아니라, 쓸데없는 코드이기도 하다. 이럴 때는 파생 변수를 질의 함수로 바꾸기에 식초 농축액을 섞어서 코드 전체에 골고루 뿌려준다.

3.7 뒤엉킨 변경

  • 코드를 수정할 때는 시스템에서 고쳐야 할 딱 한 군데를 찾아서 그 부분만 수정할 수 있기를 바란다. 이렇게 할 수 없다면 (서로 밀접한 악취인) 뒤엉킨 변경과 산탄총 수술 중 하나가 풍긴다.
  • 뒤엉킨 변경은 단일 책임 원칙(SRP)이 제대로 지켜지지 않을 때 나타난다. 예컨대 지원해야 할 데이터베이스가 추가될 때마다 함수 세 개를 바꿔야 하고, 금융 상품이 추가될 때마다 또 다른 함수 네 개를 바꿔야 하는 모듈이 있다면 뒤엉킨 변경이 발생했다는 뜻이다.
  • 물론 데이터베이스와 금융 상품 여러 개를 추가하고 나서야 이 악취가 느껴지는 경우도 많다. 개발 초기에는 맥락 사이의 경계를 명확히 나누기가 어렵고 소프트웨어 시스템의 기능이 변경되면서 이 경계도 끊임없이 움직이기 때문이다.

3.8 산탄총 수술

  • 산탄총 수술은 뒤엉킨 변경과 비슷하면서도 정반대다.
뒤엉킨 변경산탄총 수술
원인맥락을 잘 구분하지 못함
해법(원리)맥락을 명확히 구분
발생 과정(현상)한 코드에 섞여 들어감여러 코드에 흩뿌려짐
해법(실제 행동)맥락별로 분리맥락별로 모음
  • 이 냄새는 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때 풍긴다. 변경할 부분이 코드 전반에 퍼져 있다면 찾기도 어렵고 꼭 수정해야 할 곳을 지나치기 쉽다.
  • 이럴 때는 함께 변경되는 대상들을 함수 옮기기와 필드 옮기기로 모두 한 모듈에 묶어두면 좋다.

3.9 기능 편애

  • 기능 편애는 흔히 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용할 일이 더 많을 때 풍기는 냄새다.
  • 실행 과정에서 외부 객체의 게터 메서드 대여섯 개를 호출하도록 작성된 함수를 수없이 봤다. 다행히 해결하기는 쉽다. 이 함수가 데이터와 가까이 있고 싶어 한다는 의중이 뚜렷이 드러나므로 소원대로 데이터 근처로 옮겨주면 된다.

3.11 기본형 집착

  • 자신에게 주어진 문제에 딱 맞는 기초 타입(화폐, 좌표, 구간 등)을 직접 정의하기를 몹시 꺼리는 사람이 많다. 그래서 금액을 그냥 숫자형으로 계산하거나, 물리량을 계산할 때도 밀리미터나 인치 같은 단위를 무시하고, 범위도 if (a < upper && a > lower)처럼 처리하는 코드를 수없이 봤다.
  • 기본형을 객체로 바꾸기를 적용하면 기본형만이 거주하는 구석기 동굴을 의미 있는 자료형들이 사는 최신 온돌식 코드로 탈바꿈시킬 수 있다.

느낀 점

  • 앞선 리팩토링 방법 내용을 읽으면서 궁금했던 '언제 리팩토링을 해야할까'의 상세한 지점들이 있어 이번 장을 읽으면서 그 부분들을 해소할 수 있었다. '언제'와 '어떻게'가 모두 중요할 것이기 때문에 이번 장 내용을 잘 기억해두어야겠다.
- +
Skip to content
On this page

Chapter 03 - 코드에서 나는 악취

인상깊은 문장, 코드들

리팩터링을 언제 시작하고 언제 그만할지를 판단하는 일은 리팩터링의 작동 원리를 아는 것 못지않게 중요하다.

인스턴스 변수를 삭제하거나 상속 계층을 만드는 방법을 설명하기는 쉽다. 이런 일들은 간단한 문제에 속한다. 하지만 이런 일들을 '언제' 해야 하는지에 대해서는 명확하게 정립된 규칙이 없다.

리팩터링을 언제 멈춰야 하는지를 판단하는 정확한 기준을 제시하지는 않을 것이다. 경험에 따르면 숙련된 사람의 직관만큼 정확한 기준은 없다. 종료 기준보다는 리팩터링하면 해결할 수 있는 문제의 징후를 제시하겠다.

3.1 기이한 이름

  • 추리 소설이라면 무슨 일이 전개되는지 궁금증을 자아낼수록 좋지만, 코드는 아니다. 세계적인 기인이라는 느낌을 풍기고 싶더라도 꾹 참고 코드는 단순하고 명료하게 작성해야 한다.
  • 코드를 명료하게 표현하는 데 가장 중요한 요소 하나는 바로 '이름'이다. 그래서 함수, 모듈, 변수, 클래스 등은 그 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록 엄청나게 신경 써서 이름을 지어야 한다.
  • 하지만 아쉽게도 이름 짓기는 프로그래밍에서 가장 어렵기로 손꼽히는 두 가지중 하나다. (다른 하나는 캐시 무효화다.)
  • 이름 바꾸기는 단순히 이름을 다르게 표현하는 연습이 아니다. 마땅한 이름이 떠오르지 않는다면 설계에 더 근본적인 문제가 숨어 있을 가능성이 높다. 그래서 혼란스러운 이름을 잘 정리하다 보면 코드가 훨씬 간결해질 때가 많다.

3.2 중복 코드

  • 똑같은 코드 구조가 여러 곳에서 반복된다면 하나로 통합하여 더 나은 프로그램을 만들 수 있다. 코드가 중복되면 각각을 볼 때마다 서로 차이점은 없는지 주의 깊에 살펴봐야 하는 부담이 생긴다. 그중 하나를 변경할 때는 다른 비슷한 코드들도 모두 살펴보고 적절히 수정해야 한다.

3.3 긴 함수

  • 짧은 함수들로 구성된 코드베이스를 얼핏 훑으면 연산하는 부분이 하나도 없어 보인다. 코드가 끝없이 위임하는 방식으로 작성되어 있기 때문이다. 하지만 이런 프로그램을 수년 동안 다루다보면 이 짧은 함수들이 얼마나 중요한지 깨닫게 된다. 간접 호출의 효과, 즉 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 떄 나오는 것이다.
  • 예전 언어는 서브루틴을 호출하는 비용이 컸기 때문에 짧은 함수를 꺼렸다. 하지만 요즘 언어는 프로세스 안에서의 함수 호출 비용을 거의 없애버렸다. 물론 코드를 읽는 사람 입장에서는 함수가 하는 일을 파악하기 위해 왔다 갔다 해야 하므로 여전히 부담이 된다. 다행히 함수 호출부와 선언부 사이를 빠르게 이동하거나 호출과 선언을 동시에 보여주는 개발 환경을 활용하면 이 부담이 줄어들지만, 짧은 함수로 구성된 코드를 이해하기 쉽게 만드는 가장 확실한 방법은 좋은 이름이다.
  • 주석을 달아야 할 만한 부분은 무조건 함수로 만든다. 본문에는 원래 주석으로 설명하려던 코드가 담기고, 함수 이름은 동작 방식이 아닌 '의도'가 드러나게 짓는다.
  • 함수를 짧게 만드는 작업의 99%는 함수 추출하기가 차지한다.
  • 조건문이나 반복문도 추출 대상의 실마리를 제공한다.
  • 반복문도 그 안의 코드와 함께 추출해서 독립된 함수로 만든다. 추출한 반복문 코드에 적합한 이름이 떠오르지 않는다면 성격이 다른 두 가지 작업이 섞여 있기 때문일 수 있다. 이럴 때는 과감히 반복문 쪼개기를 적용해서 작업을 분리한다.

3.4 긴 매개변수 목록

  • 종종 다른 매개변수에서 값을 얻어올 수 있는 매개변수가 있을 수 있는데, 이런 매개변수는 매개변수를 질의 함수로 바꾸기로 제거할 수 있다.
  • 사용 중인 데이터 구조에서 값들을 뽑아 각각을 별개의 매개변수로 전달하는 코드라면 객체 통째로 넘기기를 적용해서 원본 데이터 구조를 그대로 전달한다.
  • 함수의 동작 방식을 정하는 플래그 역할의 매개변수는 플래그 인수 제거하기로 없애준다.

3.5 전역 데이터

  • 전역 데이터를 주의해야 한다는 말은 우리가 소프트웨어 개발을 시작한 초창기부터 귀가 따갑게 들었다. 심지어 전역 데이터는 이를 함부로 사용한 프로그래머들에게 벌을 주는 지옥 4층에 사는 악마들이 만들었다는 말이 돌 정도였다.
  • 이를 방지하기 위해 우리가 사용하는 대표적인 리팩터링은 변수 캡슐화하기다. 다른 코드에서 오염시킬 가능성이 있는 데이터를 발견할 때마다 이 기법을 가장 먼저 적용한다. 이런 데이터를 함수로 감싸는 것만으로도 데이터를 수정하는 부분을 쉽게 찾을 수 있고 접근을 통제할 수 있게 된다.

3.6 가변 데이터

  • 무분별한 데이터 수정에 따른 위험을 줄이는 방법은 얼마든지 있다. (변수 캡슐화하기)
  • 값을 다른 곳에서 설정할 수 있는 가변 데이터가 풍기는 악취는 특히 고약하다. 혼동과 버그와 야근을 부를 뿐만 아니라, 쓸데없는 코드이기도 하다. 이럴 때는 파생 변수를 질의 함수로 바꾸기에 식초 농축액을 섞어서 코드 전체에 골고루 뿌려준다.

3.7 뒤엉킨 변경

  • 코드를 수정할 때는 시스템에서 고쳐야 할 딱 한 군데를 찾아서 그 부분만 수정할 수 있기를 바란다. 이렇게 할 수 없다면 (서로 밀접한 악취인) 뒤엉킨 변경과 산탄총 수술 중 하나가 풍긴다.
  • 뒤엉킨 변경은 단일 책임 원칙(SRP)이 제대로 지켜지지 않을 때 나타난다. 예컨대 지원해야 할 데이터베이스가 추가될 때마다 함수 세 개를 바꿔야 하고, 금융 상품이 추가될 때마다 또 다른 함수 네 개를 바꿔야 하는 모듈이 있다면 뒤엉킨 변경이 발생했다는 뜻이다.
  • 물론 데이터베이스와 금융 상품 여러 개를 추가하고 나서야 이 악취가 느껴지는 경우도 많다. 개발 초기에는 맥락 사이의 경계를 명확히 나누기가 어렵고 소프트웨어 시스템의 기능이 변경되면서 이 경계도 끊임없이 움직이기 때문이다.

3.8 산탄총 수술

  • 산탄총 수술은 뒤엉킨 변경과 비슷하면서도 정반대다.
뒤엉킨 변경산탄총 수술
원인맥락을 잘 구분하지 못함
해법(원리)맥락을 명확히 구분
발생 과정(현상)한 코드에 섞여 들어감여러 코드에 흩뿌려짐
해법(실제 행동)맥락별로 분리맥락별로 모음
  • 이 냄새는 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때 풍긴다. 변경할 부분이 코드 전반에 퍼져 있다면 찾기도 어렵고 꼭 수정해야 할 곳을 지나치기 쉽다.
  • 이럴 때는 함께 변경되는 대상들을 함수 옮기기와 필드 옮기기로 모두 한 모듈에 묶어두면 좋다.

3.9 기능 편애

  • 기능 편애는 흔히 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용할 일이 더 많을 때 풍기는 냄새다.
  • 실행 과정에서 외부 객체의 게터 메서드 대여섯 개를 호출하도록 작성된 함수를 수없이 봤다. 다행히 해결하기는 쉽다. 이 함수가 데이터와 가까이 있고 싶어 한다는 의중이 뚜렷이 드러나므로 소원대로 데이터 근처로 옮겨주면 된다.

3.11 기본형 집착

  • 자신에게 주어진 문제에 딱 맞는 기초 타입(화폐, 좌표, 구간 등)을 직접 정의하기를 몹시 꺼리는 사람이 많다. 그래서 금액을 그냥 숫자형으로 계산하거나, 물리량을 계산할 때도 밀리미터나 인치 같은 단위를 무시하고, 범위도 if (a < upper && a > lower)처럼 처리하는 코드를 수없이 봤다.
  • 기본형을 객체로 바꾸기를 적용하면 기본형만이 거주하는 구석기 동굴을 의미 있는 자료형들이 사는 최신 온돌식 코드로 탈바꿈시킬 수 있다.

느낀 점

  • 앞선 리팩토링 방법 내용을 읽으면서 궁금했던 '언제 리팩토링을 해야할까'의 상세한 지점들이 있어 이번 장을 읽으면서 그 부분들을 해소할 수 있었다. '언제'와 '어떻게'가 모두 중요할 것이기 때문에 이번 장 내용을 잘 기억해두어야겠다.
+ \ No newline at end of file diff --git a/study/refactoring/chapter4.html b/study/refactoring/chapter4.html index 878f70d5..bd8c62ec 100644 --- a/study/refactoring/chapter4.html +++ b/study/refactoring/chapter4.html @@ -20,9 +20,9 @@ -
Skip to content
On this page

Chapter 04 - 테스트 구축하기

인상깊은 문장, 코드들

4.1 자가 테스트 코드의 가치

  • 프로그래머들이 어떻게 일하는지 가만히 살펴보면 실제로 코드를 작성하는 시간의 비중은 그리 크지 않음을 발견할 수 있다.
  • 프로그래머라면 누구나 꼬박 하루를 (혹은 그 이상을) 잡아먹은 디버깅 무용담을 하나씩은 간직하고 있을 것이다. 버그 수정 자체는 대체로 금방 끝난다. 진짜 끔찍한 건 버그를 찾는 여정이다. 또한 버그를 잡는 과정에서 다른 버그를 심기도 하는데, 그 사실을 한참이 지나서야 알아채기도 한다. 그래서 또다시 그 버그를 찾느라 수많은 시간을 날린다.

4.4 테스트 추가하기

  • 일부 프로그래머들이 선호하는 public 메서드를 빠짐없이 테스트하는 방식과는 다르다. 명심하자! 테스트는 위험 요인을 중심으로 작성해야 한다! 테스트의 목적은 어디까지나 현재 혹은 향후에 발생하는 버그를 찾는 데 있다. 따라서 단순히 필드를 읽고 쓰기만 하는 접근자는 테스트할 필요가 없다. 이런 코드는 너무 단순해서 버그가 숨어들 가능성도 별로 없다.
  • 나는 적은 수의 테스트만으로 큰 효과를 얻고 있다. 잘못될까봐 가장 걱정되는 영역을 집중적으로 테스트하는데, 이렇게 해서 테스트에 쏟는 노력의 효과를 극대화하는 것이다.
  • 완벽하게 만드느라 테스트를 수행하지 못하느니, 불완전한 테스트라도 작성해서라도 테스트를 수행하는 게 낫다.

4.7 끝나지 않은 여정

  • 테스트 용이성을 아키텍처 평가 기준으로 활용하는 사례도 많다.

느낀 점

  • TDD나 테스트 코드에 대한 기대와 선망은 높지만 프런트엔드에서 실제로 적용하는 것이 어떤지에 대해서는 잘 모르겠다. 컴포넌트를 테스트 한다면.? 책에 따르면 중요한 곳만 테스트하면 된다고 했으니 수량 변경 (최저 수량, 최대 수량, 구매 제한 정책 등) 컴포넌트, form validation 컴포넌트 등에 적용해볼만 할까? 수량의 경우는 그나마 테스트하기가 쉬울 것 같다. 그럼 다크모드, 모바일, 중간 사이즈 태블릿, PC 등은 테스트 코드로 어떻게 잡을 수 있을까? 로지컬하게 input output만 잡을 수 있는 테스트에 비해서는 확실히 어렵고 낯설다. PlayWright 등에서는 visible 등의 속성을 활용할 수는 있겠지만 버튼 위치, border 여부 등까지 고려한다면 테스트 자체가 일단 일이다.
  • 1 pass 0 failing 표시해주는 자가 테스트 자체가 이 당시에는 혁신이었나보다.
  • 테스트는 위험 요인을 중심으로 작성!
  • Vue vs React 테스트 용이성? 결론적으로, React와 Vue는 모두 테스트하기 용이하며 강력한 테스팅 도구와 유틸리티를 제공합니다. 선택하는 것은 주로 개인의 선호나 프로젝트의 요구 사항에 따라 달라질 수 있습니다. by GPT
- +
Skip to content
On this page

Chapter 04 - 테스트 구축하기

인상깊은 문장, 코드들

4.1 자가 테스트 코드의 가치

  • 프로그래머들이 어떻게 일하는지 가만히 살펴보면 실제로 코드를 작성하는 시간의 비중은 그리 크지 않음을 발견할 수 있다.
  • 프로그래머라면 누구나 꼬박 하루를 (혹은 그 이상을) 잡아먹은 디버깅 무용담을 하나씩은 간직하고 있을 것이다. 버그 수정 자체는 대체로 금방 끝난다. 진짜 끔찍한 건 버그를 찾는 여정이다. 또한 버그를 잡는 과정에서 다른 버그를 심기도 하는데, 그 사실을 한참이 지나서야 알아채기도 한다. 그래서 또다시 그 버그를 찾느라 수많은 시간을 날린다.

4.4 테스트 추가하기

  • 일부 프로그래머들이 선호하는 public 메서드를 빠짐없이 테스트하는 방식과는 다르다. 명심하자! 테스트는 위험 요인을 중심으로 작성해야 한다! 테스트의 목적은 어디까지나 현재 혹은 향후에 발생하는 버그를 찾는 데 있다. 따라서 단순히 필드를 읽고 쓰기만 하는 접근자는 테스트할 필요가 없다. 이런 코드는 너무 단순해서 버그가 숨어들 가능성도 별로 없다.
  • 나는 적은 수의 테스트만으로 큰 효과를 얻고 있다. 잘못될까봐 가장 걱정되는 영역을 집중적으로 테스트하는데, 이렇게 해서 테스트에 쏟는 노력의 효과를 극대화하는 것이다.
  • 완벽하게 만드느라 테스트를 수행하지 못하느니, 불완전한 테스트라도 작성해서라도 테스트를 수행하는 게 낫다.

4.7 끝나지 않은 여정

  • 테스트 용이성을 아키텍처 평가 기준으로 활용하는 사례도 많다.

느낀 점

  • TDD나 테스트 코드에 대한 기대와 선망은 높지만 프런트엔드에서 실제로 적용하는 것이 어떤지에 대해서는 잘 모르겠다. 컴포넌트를 테스트 한다면.? 책에 따르면 중요한 곳만 테스트하면 된다고 했으니 수량 변경 (최저 수량, 최대 수량, 구매 제한 정책 등) 컴포넌트, form validation 컴포넌트 등에 적용해볼만 할까? 수량의 경우는 그나마 테스트하기가 쉬울 것 같다. 그럼 다크모드, 모바일, 중간 사이즈 태블릿, PC 등은 테스트 코드로 어떻게 잡을 수 있을까? 로지컬하게 input output만 잡을 수 있는 테스트에 비해서는 확실히 어렵고 낯설다. PlayWright 등에서는 visible 등의 속성을 활용할 수는 있겠지만 버튼 위치, border 여부 등까지 고려한다면 테스트 자체가 일단 일이다.
  • 1 pass 0 failing 표시해주는 자가 테스트 자체가 이 당시에는 혁신이었나보다.
  • 테스트는 위험 요인을 중심으로 작성!
  • Vue vs React 테스트 용이성? 결론적으로, React와 Vue는 모두 테스트하기 용이하며 강력한 테스팅 도구와 유틸리티를 제공합니다. 선택하는 것은 주로 개인의 선호나 프로젝트의 요구 사항에 따라 달라질 수 있습니다. by GPT
+ \ No newline at end of file diff --git a/study/refactoring/chapter6.html b/study/refactoring/chapter6.html index 1e36186b..b8d1a45b 100644 --- a/study/refactoring/chapter6.html +++ b/study/refactoring/chapter6.html @@ -20,7 +20,7 @@ -
Skip to content
On this page

Chapter 06 - 기본적인 리팩터링

인상깊은 문장, 코드들

6.1 함수 추출하기

배경

  • 언제 독립된 함수로 묶어야 할지에 관한 의견은 수없이 많다.
  • 내 눈에는 '목적과 구현을 분리'하는 방식이 가장 합리적인 기준으로 보인다.
  • 코드를 보고 무슨 일을 하는지 파악하는 데 한참이 걸린다면 그 부분을 함수로 추출한 뒤 '무슨 일'에 걸맞는 이름을 짓는다.
  • 이렇게 해두면 나중에 코드를 다시 읽을 때 함수의 목적이 눈에 확 들어오고, 본문 코드에 대해서는 더 이상 신경 쓸 일이 거의 없다.
  • 단 한줄짜리 함수를 만드는 일도 적지 않았다.
    • 스몰토크의 그래픽스 클래스에는 텍스트나 그래픽을 강조하려고 색상을 반전시키는 목적으로 쓰이는 highlight()라는 메서드가 있었는데, 구현 코드를 보니 단순히 reverse()라는 메서드만 호출하고 있었다.
    • 메서드 이름이 구현 코드보다 길었지만, 그건 문제가 되지 않았다. 코드의 목적(강조)과 구현(반전) 사이의 차이가 그만큼 컸기 때문이다.

값을 반환할 변수가 여러 개라면?

  • 나는 주로 추출할 코드를 다르게 재구성하는 방향으로 처리한다. 개인적으로 함수가 값 하나만 반환하는 방식을 선호하기 때문이다.

6.2 함수 인라인하기

배경

  • 때로는 함수 본문이 이름만큼 명확한 경우도 있다.
  • 잘못 추출된 함수들도 다시 인라인한다. 잘못 추출된 함수들을 원래 함수로 합친 다음, 필요하면 원하는 형태로 다시 추출하는 것이다.

예시

js
function rating(aDriver) {
+    
Skip to content
On this page

Chapter 06 - 기본적인 리팩터링

인상깊은 문장, 코드들

6.1 함수 추출하기

배경

  • 언제 독립된 함수로 묶어야 할지에 관한 의견은 수없이 많다.
  • 내 눈에는 '목적과 구현을 분리'하는 방식이 가장 합리적인 기준으로 보인다.
  • 코드를 보고 무슨 일을 하는지 파악하는 데 한참이 걸린다면 그 부분을 함수로 추출한 뒤 '무슨 일'에 걸맞는 이름을 짓는다.
  • 이렇게 해두면 나중에 코드를 다시 읽을 때 함수의 목적이 눈에 확 들어오고, 본문 코드에 대해서는 더 이상 신경 쓸 일이 거의 없다.
  • 단 한줄짜리 함수를 만드는 일도 적지 않았다.
    • 스몰토크의 그래픽스 클래스에는 텍스트나 그래픽을 강조하려고 색상을 반전시키는 목적으로 쓰이는 highlight()라는 메서드가 있었는데, 구현 코드를 보니 단순히 reverse()라는 메서드만 호출하고 있었다.
    • 메서드 이름이 구현 코드보다 길었지만, 그건 문제가 되지 않았다. 코드의 목적(강조)과 구현(반전) 사이의 차이가 그만큼 컸기 때문이다.

값을 반환할 변수가 여러 개라면?

  • 나는 주로 추출할 코드를 다르게 재구성하는 방향으로 처리한다. 개인적으로 함수가 값 하나만 반환하는 방식을 선호하기 때문이다.

6.2 함수 인라인하기

배경

  • 때로는 함수 본문이 이름만큼 명확한 경우도 있다.
  • 잘못 추출된 함수들도 다시 인라인한다. 잘못 추출된 함수들을 원래 함수로 합친 다음, 필요하면 원하는 형태로 다시 추출하는 것이다.

예시

js
function rating(aDriver) {
     return moreThanFiveLateDeliveries(aDriver) ? 2 : 1;
 }
 
@@ -92,8 +92,8 @@
     get lastName() { return this._lastName; }
     get firstName() { return this._firstName; }
 }
  • 첫번째 방법으로도 충분히 공유 데이터를 변경할 수 있을 것 같은데, 두번째 방법은 무엇이 다른 것일까?
  • 메디 프론트 내의 기간 범위 참고를 하나의 객체나 클래스로 묶어보면 어떨까?

    • 범위 개념은 객체 하나로 묶어서 표현하는게 더 나은 대표적인 예이다. 그리고 우리 코드에도 이런 개념이 많이 있다. 이런 코드들에 적용해보면 어떨까?
    • 그리고 범위를 더 넓히면 회사 코드에서는 대부분 날짜 관련 비교나 포매팅시 moment를 직접 이용하고 있었어서 date-fns 등 더 나은 방안으로 마이그레이션하는데 어려움이 있는 상태이다. 날짜를 다루는 대표적인 객체를 만들어 사용하도록 한다면 이런 부분도 해결할 수 있을 것 같다.
  • 여러 함수를 클래스로 묶기나, 변환 함수로 묶는 방식은 결제나 가격 정보 쪽에서 활용하기에 좋아보인다.

    • 데이터로부터 여러 정보를 도출하는 작업이 반복될 때, 클래스를 지원하지 않는 언어에서는 변환 함수로 묶는 것을 제안하고 있다. 그래서 이 둘은 같은 목적을 가지고 있는 것이라는 생각이 든다.
    • 그리고 현재 회사 코드는 가격 정보를 받아와서 사용 가능한 포인트나 캐시 같은 값을 계산을 해주는 부분들도 많은데 이런 부분이 적용해보기 좋은 것 같다.
  • 단계 쪼개기는 단계를 쪼개기 위해 코드를 살피고 목적이 되는 대상을 찾는 과정 자체가 중요해보인다.

    • 자바 코드 예시에서는 명령줄 인수를 읽어 동작을 결정하는 과정과, 추출된 정보를 바탕으로 동작을 수행하는 부분이 있다. 이 차이와 대상을 포착하게 되면 오히려 이후 분리는 쉬워보인다.
  • - + \ No newline at end of file diff --git a/study/refactoring/chapter7.html b/study/refactoring/chapter7.html index 1bcf5c36..c7a626b3 100644 --- a/study/refactoring/chapter7.html +++ b/study/refactoring/chapter7.html @@ -20,7 +20,7 @@ -
    Skip to content
    On this page

    Chapter 07 - 캡슐화

    인상깊은 문장, 코드들

    7.1 레코드 캡슐화하기

    • 대부분의 프로그래밍 언어는 데이터 레코드를 표현하는 구조를 제공한다. ... 하지만 단순한 레코드에는 단점이 있다. 특히, 계산해서 얻을 수 있는 값과 그렇지 않을 값을 명확히 구분해 저장해야 하는 점이 번거롭다.
    • 가령 값의 범위를 표현하려면 {start: 1, end: 5}{start: 1, length: 5} (또는 내 스타일을 고집한다면 {end: 5, length: 5}) 등의 방식으로 저장할 수 있다. 어떤 식으로 저장하든 '시작'과 '끝'과 '길이'를 알 수 있어야 한다.
    • 바로 이 때문에 나는 가변 데이터를 저장하는 용도로는 레코드보다 객체를 선호하는 편이다. 객체를 사용하면 어떻게 저장했는지를 숨긴 채 세 가지 값을 각각의 메서드로 제공할 수 있다.
    • 필드 이름을 바꿔도 기존 이름과 새 이름 모두를 각각의 메서드로 제공할 수 있어서 사용자 모두가 새로운 메서드로 옮겨갈 때까지 점진적으로 수정할 수 있다.

    예시: 간단한 레코드 캡슐화하기

    • 레코드를 캡슐화하는 목적은 변수 자체는 물론 그 내용을 조작하는 방식도 통제하기 위해서다.
    js
    const organization = { name: "애크미 구스베리", country: "GB" };

    ->

    js
    class Organization {
    +    
    Skip to content
    On this page

    Chapter 07 - 캡슐화

    인상깊은 문장, 코드들

    7.1 레코드 캡슐화하기

    • 대부분의 프로그래밍 언어는 데이터 레코드를 표현하는 구조를 제공한다. ... 하지만 단순한 레코드에는 단점이 있다. 특히, 계산해서 얻을 수 있는 값과 그렇지 않을 값을 명확히 구분해 저장해야 하는 점이 번거롭다.
    • 가령 값의 범위를 표현하려면 {start: 1, end: 5}{start: 1, length: 5} (또는 내 스타일을 고집한다면 {end: 5, length: 5}) 등의 방식으로 저장할 수 있다. 어떤 식으로 저장하든 '시작'과 '끝'과 '길이'를 알 수 있어야 한다.
    • 바로 이 때문에 나는 가변 데이터를 저장하는 용도로는 레코드보다 객체를 선호하는 편이다. 객체를 사용하면 어떻게 저장했는지를 숨긴 채 세 가지 값을 각각의 메서드로 제공할 수 있다.
    • 필드 이름을 바꿔도 기존 이름과 새 이름 모두를 각각의 메서드로 제공할 수 있어서 사용자 모두가 새로운 메서드로 옮겨갈 때까지 점진적으로 수정할 수 있다.

    예시: 간단한 레코드 캡슐화하기

    • 레코드를 캡슐화하는 목적은 변수 자체는 물론 그 내용을 조작하는 방식도 통제하기 위해서다.
    js
    const organization = { name: "애크미 구스베리", country: "GB" };

    ->

    js
    class Organization {
       constructor(data) {
         this._name = data.name;
         this._country = data.country;
    @@ -274,8 +274,8 @@
             return this._cashA + this._cashB
         }
     }
  • 중첩된 레코드를 다루는 일은 아주 많다. 처음부터 캡슐화를 잘했다면, 클래스나 객체 지향이 낯설었어도 더 깔끔한 코드를 만들 수 있었을까?

  • 원본 데이터를 제공할 필요는 어떤 것때문에 있을까?

    • 우리 서비스에서 이용 중인 오픈소스 마켓 서비스는 서버와 클라이언트 패키지를 모두 제공한다. 서버를 커스터마이징할 일이 생겼는데 클라이언트 커스터마이징하기 어려운 상황이라 변경을 하지 않았다. 그래서 대신 직접 API를 호출해서 사용해야 했다. 비슷한 경우일까?
  • 컬렉션 캡슐화하기는 프런트엔드에서 어떤 경우에 주로 발생할까?

    • 한 배열이 있고, 그 배열 데이터를 prop으로 자식, 손자, 그 아래까지 drilling해서 사용한다고 가정해보자. 그리고 시간에 쫓기는 개발자 혹은 스파게티 코드에서 해당 배열을 다른 개발자가 사용한다면? 원본 배열을 변경하려는 시도를 할 확률이 높아진다. 다만 Vue에서는 다행히 prop을 직접 변경한다면 warning을 띄워준다.
  • 클래스 추출하기는 컴포넌트 분리하기에서도 적용할 개념이 느껴진다

    • 메서드와 데이터가 너무 많은 클래스는 이해하기가 쉽지 않으니 잘 살펴보고 적절히 분리하는 것이 좋다.
    • methods, computed, lifeCycle 메서드 등등이 총 10개가 넘어가면 분리한다면?
  • 위임 숨기기는 가독성이 떨어지지 않을까? 지나친 추상화가 되어 코드 수정도 어렵게 되지는 않을까? -> 너무 당연한 말이지만 적절한 곳에 적절한 방법을 쓰는게 중요할 것 같다.

  • - + \ No newline at end of file diff --git a/study/refactoring/chapter8.html b/study/refactoring/chapter8.html index 2cf7bf1e..b67227da 100644 --- a/study/refactoring/chapter8.html +++ b/study/refactoring/chapter8.html @@ -20,9 +20,9 @@ -
    Skip to content
    On this page

    Chapter 08 - 기능 이동

    인상깊은 문장, 코드들

    8.2 필드 옮기기

    배경

    • 데이터 구조가 중요하다. 하지만 훌륭한 프로그램이 갖춰야 할 다른 요인들과 마찬가지로, 제대로 하기가 어렵다. 가장 적합한 데이터 구조를 알아내고자 프로젝트 초기에 분석을 해본 결과, 경험과 도메인 주도 설계 같은 기술이 내 능력을 개선해줌을 알아냈다.
    • 하지만, 나의 모든 기술과 경험에도 불구하고 초기 설계에서는 실수가 빈번했다. 프로젝트를 진행할수록 우리는 문제 도메인과 데이터 구조에 대해 더 많은 것을 배우게 된다. 그래서 오늘까지는 합리적이고 올바랐던 설계가 다음 주가 되면 잘못된 것으로 판명나곤 한다.

    느낀점

    • 8.2 필드 옮기기가 중요한 내용처럼 느껴졌다. 프런트엔드 개발이라서 데이터 구조를 설계할 일은 적다. 하지만 어떤 개발이든 결국 다루는 데이터 구조에 대해 인식하고 있어야 한다고 생각하고, 그런 면에서 백과 프런트의 구분은 그런면에서 아쉬운 부분이 있지 않나한다.
    • 8.2 어서션을 추가하거나 로깅을 해서 확신을 갖는 방법도 좋은 것 같다.
    • 8.6 문장 슬라이드하기 라는 리팩터링 방법을 명명함으로서 관련된 코드를 모으는 작업을 강조하고, 세분화된 리팩터링 과정을 거칠 수 있게돼서 좋은 것 같다.
    • 8.6 문장 슬라이드하기 내용 중 '나는 2번 줄이 부수효과가 없다는 걸 어떻게 알았을까? ... 나는 거의 명령-질의 분리(Command-Query Seperation) 원칙을 지켜가며 코딩하므로, 내가 직접 작성한 코드라면 값을 반환하는 함수는 모두 부수효과가 없음을 알고 있던 것이다'라는 내용이 인상 깊었다. 최근 장바구니 리팩터링을 하면서 비슷한 상황이 있었는데 명령-질의가 모두 담긴 함수를 만든 것 같다. 이 부분을 분리해서 리팩터링을 해봐야겠다.
      • 만약 updateOrder 함수가 update된 order를 반환한다면, 명령-질의 분리를 위반한 것일까?
    • 8.7 반복문 쪼개기가 리팩터링 공부에서 얻은 큰 수확중 하나다. 이전까지는 오히려 하나의 반복문으로 해결할 수 있지 않을까를 고민했을 것 같다. 어떤 코드가 좋은 코드인지에 대한 기준이 모호해서 어떤 곳에서는 순회를 줄이려고 하고, 어떤 곳에서는 가독성을 향상시키려고 했던 것 같다. 반복문 쪼개기를 통해서 이전에 작성한 코드의 반복문을 마주치게 되면 쪼갤 수 없을까를 고민하게 된다.
      • 리팩터링 절차 1번 복제하기!! 너무 좋아서 느낌표 2개
    • 개인적으로 8.8 반복문을 파이프라인으로 바꾸기를 선호하는데, 이름을 알게돼서 좋았다. 보통은 '자바스크립트 내장 메서드 활용하기'정도로 사용하고 있었다.
    • 8.9 죽은 코드 제거하기에서도 말했듯이 제거할 코드를 주석처리하기보다는 지우고 commit message를 잘 남기는 것이 좋다고 생각한다. 다른 사람들의 의견도 궁금하다.
    - +
    Skip to content
    On this page

    Chapter 08 - 기능 이동

    인상깊은 문장, 코드들

    8.2 필드 옮기기

    배경

    • 데이터 구조가 중요하다. 하지만 훌륭한 프로그램이 갖춰야 할 다른 요인들과 마찬가지로, 제대로 하기가 어렵다. 가장 적합한 데이터 구조를 알아내고자 프로젝트 초기에 분석을 해본 결과, 경험과 도메인 주도 설계 같은 기술이 내 능력을 개선해줌을 알아냈다.
    • 하지만, 나의 모든 기술과 경험에도 불구하고 초기 설계에서는 실수가 빈번했다. 프로젝트를 진행할수록 우리는 문제 도메인과 데이터 구조에 대해 더 많은 것을 배우게 된다. 그래서 오늘까지는 합리적이고 올바랐던 설계가 다음 주가 되면 잘못된 것으로 판명나곤 한다.

    느낀점

    • 8.2 필드 옮기기가 중요한 내용처럼 느껴졌다. 프런트엔드 개발이라서 데이터 구조를 설계할 일은 적다. 하지만 어떤 개발이든 결국 다루는 데이터 구조에 대해 인식하고 있어야 한다고 생각하고, 그런 면에서 백과 프런트의 구분은 그런면에서 아쉬운 부분이 있지 않나한다.
    • 8.2 어서션을 추가하거나 로깅을 해서 확신을 갖는 방법도 좋은 것 같다.
    • 8.6 문장 슬라이드하기 라는 리팩터링 방법을 명명함으로서 관련된 코드를 모으는 작업을 강조하고, 세분화된 리팩터링 과정을 거칠 수 있게돼서 좋은 것 같다.
    • 8.6 문장 슬라이드하기 내용 중 '나는 2번 줄이 부수효과가 없다는 걸 어떻게 알았을까? ... 나는 거의 명령-질의 분리(Command-Query Seperation) 원칙을 지켜가며 코딩하므로, 내가 직접 작성한 코드라면 값을 반환하는 함수는 모두 부수효과가 없음을 알고 있던 것이다'라는 내용이 인상 깊었다. 최근 장바구니 리팩터링을 하면서 비슷한 상황이 있었는데 명령-질의가 모두 담긴 함수를 만든 것 같다. 이 부분을 분리해서 리팩터링을 해봐야겠다.
      • 만약 updateOrder 함수가 update된 order를 반환한다면, 명령-질의 분리를 위반한 것일까?
    • 8.7 반복문 쪼개기가 리팩터링 공부에서 얻은 큰 수확중 하나다. 이전까지는 오히려 하나의 반복문으로 해결할 수 있지 않을까를 고민했을 것 같다. 어떤 코드가 좋은 코드인지에 대한 기준이 모호해서 어떤 곳에서는 순회를 줄이려고 하고, 어떤 곳에서는 가독성을 향상시키려고 했던 것 같다. 반복문 쪼개기를 통해서 이전에 작성한 코드의 반복문을 마주치게 되면 쪼갤 수 없을까를 고민하게 된다.
      • 리팩터링 절차 1번 복제하기!! 너무 좋아서 느낌표 2개
    • 개인적으로 8.8 반복문을 파이프라인으로 바꾸기를 선호하는데, 이름을 알게돼서 좋았다. 보통은 '자바스크립트 내장 메서드 활용하기'정도로 사용하고 있었다.
    • 8.9 죽은 코드 제거하기에서도 말했듯이 제거할 코드를 주석처리하기보다는 지우고 commit message를 잘 남기는 것이 좋다고 생각한다. 다른 사람들의 의견도 궁금하다.
    + \ No newline at end of file diff --git a/study/refactoring/intro.html b/study/refactoring/intro.html index 29f5ce7d..4ba2208f 100644 --- a/study/refactoring/intro.html +++ b/study/refactoring/intro.html @@ -20,9 +20,9 @@ -
    Skip to content
    On this page

    들어가며

    옛날 옛적에 한 컨설턴트가 개발 프로젝트를 점검하러 파견을 나갔다. 작성된 코드를 보니 클래스 상속 구조가 시스템의 주축을 이루고 있었고, 전반적으로 아주 엉망이었다.

    컨설턴트는 프로젝트 팀장에게 코드를 살펴보면서 정리하라고 권했지만 팀장은 콧방귀를 뀌는 듯한 태도였다. 어쨌든 그 코드는 문제없이 돌아가는 데다 중요한 일정들이 코앞이었으니 그럴 만도 했다. 팀장은 나중에 여유가 생기면 하겠다고 했다.

    6개월 후 그 프로젝트는 완전히 망했다. 코드가 너무 복잡해서 디버깅도 할 수 없었고 최소한의 성능 요건을 맞추는 것도 불가능했다.

    켄트 벡이 그 프로젝트를 새로 시작하기 위한 컨설팅을 맡았다. 시스템의 거의 모든 부분을 처음부터 새로 작성해야 했다. 켄트는 일하는 방식에 여러모로 변화를 줬는데, 그중 가장 핵심은 리팩터링을 활용해 코드를 꾸준히 정리하게 했다는 점이다. 결국 두 번쨰 시도는 성공했고, 전적으로 리팩터링 덕이었다.

    리팩터링이란

    리팩터링은 겉으로 드러나는 코드의 기능(겉보기 동작)은 바꾸지 않으면서 내부 구조를 개선하는 방식으로 소프트웨어 시스템을 수정하는 과정이다. 버그가 생길 가능성을 최소로 줄이면서 코드를 정리하는 정제된 방법이다. 요컨대, 리팩터링한다는 것은 코드를 작성하고 난 뒤에 설계를 개선하는 일이다.

    리팩터링의 각 단계는 간단하다 못해 지나칠 정도로 단순하다. 한 클래스의 필드를 다른 클래스로 옮기고, 일부 코드를 메서드 밖으로 빼서 별도의 메서드로 만들고, 코드 일부를 상속 구조의 위/아래로 올리거나 내리는 등의 작업이다. 이런 사소한 수정도 누적되면 설계가 놀랍도록 개선된다. 소프트웨어가 부식된다는 개념의 정반대가 바로 리팩터링이다.

    리팩터링을 하면 일의 균형이 바뀐다. 처음부터 완벽한 설계를 갖추기보다는 개발을 진행하면서 지속적으로 설계한다. 시스템을 구축하는 과정에서 더 나은 설계가 무엇인지 배우게 된다. 그 결과, 개발의 시작부터 끝날 때까지 프로그램은 줄곧 우수한 설계를 유지한다.

    누가 읽어야 하나

    이 책은 소프트웨어 개발을 직업으로 하는 전문 프로그래머를 위해 쓰였다.

    리팩터링은 코드에 집중하지만, 사실 시스템 설계에 미치는 영향이 상당히 크다. 그래서 선임 개발자나 아키텍트라면 반드시 리팩터링의 원리를 이해하고 프로젝트에 활용해야 한다.

    책 전부를 읽지 않고도 내용 대부분을 습득하려면 다음과 같이 하자.

    • 리팩터링이 뭔지 모른다면 1장을 읽자. 1장의 예시를 보면 리팩터링 진행 절차를 명확하게 알 수 있다.
    • 리팩터링해야 하는 이유를 모르겠다면 1장과 2장을 읽자. 리팩터링이 무엇이고 왜 필요한지 설명해준다.
    • 리팩터링해야 할 곳을 찾고 싶을 때는 3장을 읽자. 리팩터링이 필요할 만한 곳에서 보내는 신호(악취)를 잡아내는 요령을 설명해준다.
    • 리팩터링을 실습하고 싶다면 1장부터 4장까지는 꼼꼼히 읽고, 나머지를 빠르게 훑어보자. 카탈로그 부분은 어떤 기법들이 있는지 정도만 대략 보면 되지, 세세한 부분까지 전부 이해할 필요는 없다. 리팩터링을 당장 실시해야 할 때 해당 기법 부분을 펼쳐 자세히 읽고 따르면 된다. 카탈로그는 그때그때 찾아보는 부분이므로 한 번에 이어서 읽는 것은 불필요하고 비효율적이다.
    - +
    Skip to content
    On this page

    들어가며

    옛날 옛적에 한 컨설턴트가 개발 프로젝트를 점검하러 파견을 나갔다. 작성된 코드를 보니 클래스 상속 구조가 시스템의 주축을 이루고 있었고, 전반적으로 아주 엉망이었다.

    컨설턴트는 프로젝트 팀장에게 코드를 살펴보면서 정리하라고 권했지만 팀장은 콧방귀를 뀌는 듯한 태도였다. 어쨌든 그 코드는 문제없이 돌아가는 데다 중요한 일정들이 코앞이었으니 그럴 만도 했다. 팀장은 나중에 여유가 생기면 하겠다고 했다.

    6개월 후 그 프로젝트는 완전히 망했다. 코드가 너무 복잡해서 디버깅도 할 수 없었고 최소한의 성능 요건을 맞추는 것도 불가능했다.

    켄트 벡이 그 프로젝트를 새로 시작하기 위한 컨설팅을 맡았다. 시스템의 거의 모든 부분을 처음부터 새로 작성해야 했다. 켄트는 일하는 방식에 여러모로 변화를 줬는데, 그중 가장 핵심은 리팩터링을 활용해 코드를 꾸준히 정리하게 했다는 점이다. 결국 두 번쨰 시도는 성공했고, 전적으로 리팩터링 덕이었다.

    리팩터링이란

    리팩터링은 겉으로 드러나는 코드의 기능(겉보기 동작)은 바꾸지 않으면서 내부 구조를 개선하는 방식으로 소프트웨어 시스템을 수정하는 과정이다. 버그가 생길 가능성을 최소로 줄이면서 코드를 정리하는 정제된 방법이다. 요컨대, 리팩터링한다는 것은 코드를 작성하고 난 뒤에 설계를 개선하는 일이다.

    리팩터링의 각 단계는 간단하다 못해 지나칠 정도로 단순하다. 한 클래스의 필드를 다른 클래스로 옮기고, 일부 코드를 메서드 밖으로 빼서 별도의 메서드로 만들고, 코드 일부를 상속 구조의 위/아래로 올리거나 내리는 등의 작업이다. 이런 사소한 수정도 누적되면 설계가 놀랍도록 개선된다. 소프트웨어가 부식된다는 개념의 정반대가 바로 리팩터링이다.

    리팩터링을 하면 일의 균형이 바뀐다. 처음부터 완벽한 설계를 갖추기보다는 개발을 진행하면서 지속적으로 설계한다. 시스템을 구축하는 과정에서 더 나은 설계가 무엇인지 배우게 된다. 그 결과, 개발의 시작부터 끝날 때까지 프로그램은 줄곧 우수한 설계를 유지한다.

    누가 읽어야 하나

    이 책은 소프트웨어 개발을 직업으로 하는 전문 프로그래머를 위해 쓰였다.

    리팩터링은 코드에 집중하지만, 사실 시스템 설계에 미치는 영향이 상당히 크다. 그래서 선임 개발자나 아키텍트라면 반드시 리팩터링의 원리를 이해하고 프로젝트에 활용해야 한다.

    책 전부를 읽지 않고도 내용 대부분을 습득하려면 다음과 같이 하자.

    • 리팩터링이 뭔지 모른다면 1장을 읽자. 1장의 예시를 보면 리팩터링 진행 절차를 명확하게 알 수 있다.
    • 리팩터링해야 하는 이유를 모르겠다면 1장과 2장을 읽자. 리팩터링이 무엇이고 왜 필요한지 설명해준다.
    • 리팩터링해야 할 곳을 찾고 싶을 때는 3장을 읽자. 리팩터링이 필요할 만한 곳에서 보내는 신호(악취)를 잡아내는 요령을 설명해준다.
    • 리팩터링을 실습하고 싶다면 1장부터 4장까지는 꼼꼼히 읽고, 나머지를 빠르게 훑어보자. 카탈로그 부분은 어떤 기법들이 있는지 정도만 대략 보면 되지, 세세한 부분까지 전부 이해할 필요는 없다. 리팩터링을 당장 실시해야 할 때 해당 기법 부분을 펼쳐 자세히 읽고 따르면 된다. 카탈로그는 그때그때 찾아보는 부분이므로 한 번에 이어서 읽는 것은 불필요하고 비효율적이다.
    + \ No newline at end of file diff --git "a/study/\353\210\204\352\265\254\353\202\230 \354\236\220\353\243\214\352\265\254\354\241\260\354\231\200 \354\225\214\352\263\240\353\246\254\354\246\230.html" "b/study/\353\210\204\352\265\254\353\202\230 \354\236\220\353\243\214\352\265\254\354\241\260\354\231\200 \354\225\214\352\263\240\353\246\254\354\246\230.html" index a3286171..d3e335a2 100644 --- "a/study/\353\210\204\352\265\254\353\202\230 \354\236\220\353\243\214\352\265\254\354\241\260\354\231\200 \354\225\214\352\263\240\353\246\254\354\246\230.html" +++ "b/study/\353\210\204\352\265\254\353\202\230 \354\236\220\353\243\214\352\265\254\354\241\260\354\231\200 \354\225\214\352\263\240\353\246\254\354\246\230.html" @@ -20,7 +20,7 @@ -
    Skip to content
    On this page

    누구나 자료구조와 알고리즘

    버블 정렬

    javascript
    function bubbleSort(arr) {
    +    
    Skip to content
    On this page

    누구나 자료구조와 알고리즘

    버블 정렬

    javascript
    function bubbleSort(arr) {
       let sortedLength = 0;
     
       while (sortedLength !== arr.length) {
    @@ -39,8 +39,8 @@
     
       return arr;
     }
    - + \ No newline at end of file diff --git "a/study/\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270 \354\225\214\352\263\240\353\246\254\354\246\230 \353\254\270\354\240\234\355\222\200\354\235\264.html" "b/study/\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270 \354\225\214\352\263\240\353\246\254\354\246\230 \353\254\270\354\240\234\355\222\200\354\235\264.html" index eefb587e..ef9d2117 100644 --- "a/study/\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270 \354\225\214\352\263\240\353\246\254\354\246\230 \353\254\270\354\240\234\355\222\200\354\235\264.html" +++ "b/study/\354\236\220\353\260\224\354\212\244\355\201\254\353\246\275\355\212\270 \354\225\214\352\263\240\353\246\254\354\246\230 \353\254\270\354\240\234\355\222\200\354\235\264.html" @@ -20,7 +20,7 @@ -
    Skip to content
    On this page

    자바스크립트 알고리즘 문제풀이

    3537 %

    코딩 문제를 풀기 위해 배우는 것이 아니라, 총알을 쌓아두듯이 문제 해결 방법 지식을 쌓아두기 위해서 공부하는 것이다.

    한 알고리즘 카테고리가 나오면, 유튜브에서 다른 접근 방식도 찾아보자

    정해진 해결법이 있는 것이 아니다.

    기본문제 풀이

    1. 세 수 중 최솟값

    내 문제 풀이

    javascript
    function solution(a, b, c){
    +    
    Skip to content
    On this page

    자바스크립트 알고리즘 문제풀이

    3537 %

    코딩 문제를 풀기 위해 배우는 것이 아니라, 총알을 쌓아두듯이 문제 해결 방법 지식을 쌓아두기 위해서 공부하는 것이다.

    한 알고리즘 카테고리가 나오면, 유튜브에서 다른 접근 방식도 찾아보자

    정해진 해결법이 있는 것이 아니다.

    기본문제 풀이

    1. 세 수 중 최솟값

    내 문제 풀이

    javascript
    function solution(a, b, c){
       if(a <= b && a <= c) return a
       if(b <= a && b <= c) return b
       if(c <= a && c <= b) return c
    @@ -286,8 +286,8 @@
     
       return result;
     }
    • String => reverse => join이 아닌 숫자 계산으로만 숫자를 뒤집어 보라는 말씀을 듣고 다시 풀어봄

    --

    - + \ No newline at end of file diff --git "a/study/\355\201\264\353\246\260 \354\275\224\353\223\234.html" "b/study/\355\201\264\353\246\260 \354\275\224\353\223\234.html" index b1bc9d37..f96131d7 100644 --- "a/study/\355\201\264\353\246\260 \354\275\224\353\223\234.html" +++ "b/study/\355\201\264\353\246\260 \354\275\224\353\223\234.html" @@ -20,7 +20,7 @@ -
    Skip to content
    On this page

    클린 코드

    클린 코드

    클린 코드

    로버트 C. 마틴
    28.5714285714285729 %

    4 주석

    나쁜 코드에 주석을 달지 마라. 새로 짜라.
    - 브라이언 W. 커니핸, P.J. 플라우거

    • 우리는 코드로 의도를 표현하지 못해, 그러니까 실패를 만회하기 위해 주석을 사용한다. ... 진심이다. 주석은 언제나 실패를 의미한다.

    • 내가 이렇듯 주석을 무시하는 이유가 무엇이냐고? 거짓말을 하니까. 항상도 아니고 고의도 아니지만 너무 자주 거짓말을 하니까.

    • 주석을 엄격하게 관리 ... 하지만 나라면 코드를 깔끔하게 정리하고 표현력을 강화하는 방향으로, 그래서 애초에 주석이 필요 없는 방향으로 에너지를 쏟겠다.

    • 진실은 한곳에만 존재한다. 바로 코드다.

    주석은 나쁜 코드를 보완하지 못한다

    • 코드에 주석을 추가하는 일반적인 이유는 코드 품질이 나쁘기 때문이다.

    코드로 의도를 표현하라!

    • 확실히 코드만으로 의도를 설명하기 어려운 경우가 존재한다.
    java
    // 직원에게 복지 혜택을 받을 자격이 있는지 검사한다.
    +    
    Skip to content
    On this page

    클린 코드

    클린 코드

    클린 코드

    로버트 C. 마틴
    28.5714285714285729 %

    4 주석

    나쁜 코드에 주석을 달지 마라. 새로 짜라.
    - 브라이언 W. 커니핸, P.J. 플라우거

    • 우리는 코드로 의도를 표현하지 못해, 그러니까 실패를 만회하기 위해 주석을 사용한다. ... 진심이다. 주석은 언제나 실패를 의미한다.

    • 내가 이렇듯 주석을 무시하는 이유가 무엇이냐고? 거짓말을 하니까. 항상도 아니고 고의도 아니지만 너무 자주 거짓말을 하니까.

    • 주석을 엄격하게 관리 ... 하지만 나라면 코드를 깔끔하게 정리하고 표현력을 강화하는 방향으로, 그래서 애초에 주석이 필요 없는 방향으로 에너지를 쏟겠다.

    • 진실은 한곳에만 존재한다. 바로 코드다.

    주석은 나쁜 코드를 보완하지 못한다

    • 코드에 주석을 추가하는 일반적인 이유는 코드 품질이 나쁘기 때문이다.

    코드로 의도를 표현하라!

    • 확실히 코드만으로 의도를 설명하기 어려운 경우가 존재한다.
    java
    // 직원에게 복지 혜택을 받을 자격이 있는지 검사한다.
     if ((employee.flags & HOURLY_FLAG) && employee.age > 65)

    다음 코드는 어떤가?

    java
    if (employee.isEligibleForFullBenefits())

    5 형식 맞추기

    • 프로그래머라면 형식을 깔끔하게 맞춰 코드를 짜야 한다. 코드 형싱글 맞추기 위한 간단한 규칙을 정하고 그 규칙을 착실히 따라야 한다. 팀으로 일한다면 팀이 합의해 규칙을 정하고 모두가 그 규칙을 따라야 한다. 필요하다면 규칙을 자동으로 적용하는 도구를 활용한다.

    형식을 맞추는 목적

    • 코드 형식은 의사소통의 일환이다. 의사소통은 전문 개발자의 일차적인 의무다.
    • 어쩌면 '돌아가는 코드'가 전문 개발자의 일차적인 의무라 여길지도 모르겠다. 하지만 이 책을 읽으면서 생각이 바뀌었기 바란다.
    • 원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다.

    적절한 행 길이를 유지하라

    • JUnit, FitNesse, Time and Money는 상대적으로 파일 크기가 작다. 500줄을 넘어가는 파일이 없으며 대다수가 200줄 미만이다.
    • 500줄을 넘지 않고 대부분 200줄 정도인 파일로도 커다란 시스템을 구축할 수 있다는 사실이다.

    신문 기사처럼 작성하라

    • 최상단에 기사를 몇 마디로 요약하는 표제가 나온다. 독자는 표제를 보고서 기사를 읽을지 말지 결정한다.
    • 첫 문단은 전체 기사 내용을 요약한다. 쭉 읽으며 내려가면 세세한 사실이 조금씩 드러난다.
    • 코드도 마찬가지다. 이름만 보고도 올바른 모듈을 살펴보고 있는지 아닌지를 판단할 정도로 신경 써서 짓는다. 그리고 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명한다. 아래로 내려갈수록 의도를 세세하게 묘사한다.

    개념은 빈 행으로 분리하라

    • 일련의 행 묶음은 완결된 생각 하나를 표현한다.

    세로 밀집도

    • 줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀접한 코드 행은 세로로 가까이 놓여야 한다는 뜻이다.
    목록 5-3
    typescript
    class ReporterConfig {
         /**
          * 리포터 리스너의 클래스 이름
    @@ -129,8 +129,8 @@
     ctxt.getScratchDirectoryOption().getAbsolutePath();
    • 어느 방법도 썩 내키지 않는다.
    • ctxt가 객체라면 뭔가를 하라고 말해야지 속을 드러내라고 말하면 안 된다.
    typescript
    const outFile: string = outDir + "/" + className.replace(/\./g, "/") + ".class";
     const fout: FileOutputStream = new FileOutputStream(outFile);
     const bos: BufferedOutputStream = new BufferedOutputStream(fout);
    • 위 코드는 같은 모듈에서 (한참 아래로 내려가서) 가져온 코드다.
    • 어찌 됐거나, 임시 디렉터리의 절대 경로를 얻으려는 이유가 임시 파일을 생성하기 위한 목적이라는 사실이 드러난다.
    • 그렇다면 ctxt 객체에 임시 파일을 생성하라고 시키면 어떨까?
    typescript
    const bos: BufferedOutputStream = ctxt.createScratchFileStream(classFileName);
    • 객체에게 맡기기에 적당한 임무로 보인다! ctxt는 내부 구조를 드러내지 않으며, 자신이 몰라야 하는 여러 객체를 탐색할 필요가 없다. 따라서 디미터 법칙을 위반하지 않는다.

    자료 전달 객체

    • 자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스다. 이런 자료 구조체를 때로는 자료 전달 객체(data transfer object, DTO)라고 부른다.
    • DTO는 굉장히 유용한 구조체다. 특히 데이터베이스와 통신하거나 소켓에서 받은 메시지의 구문을 분석할 때 유용하다.

    결론

    • 객체는 동작을 공개하고 자료를 숨긴다. 그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다.
    • 자료 구조는 별다른 동작 없이 자료를 노출한다. 그래서 기존 자료 구조에 새 동작을 추가하기는 쉬운 반면, 기존 함수에 새 자료 구조를 추가하기는 어렵다.
    • (어떤) 시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다. 다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.
    • 우수한 소프트웨어 개발자는 편견없이 이 사실을 이해해 직면한 문제에 최적인 해결책을 선택한다.
    - + \ No newline at end of file diff --git "a/study/\355\225\250\352\273\230\354\236\220\353\235\274\352\270\260.html" "b/study/\355\225\250\352\273\230\354\236\220\353\235\274\352\270\260.html" index d5b898f6..8ed3564c 100644 --- "a/study/\355\225\250\352\273\230\354\236\220\353\235\274\352\270\260.html" +++ "b/study/\355\225\250\352\273\230\354\236\220\353\235\274\352\270\260.html" @@ -20,9 +20,9 @@ -
    Skip to content
    On this page

    함께 자라기

    220100 %

    머리말

    내가 정말 잘할 수 있을까? 아니, 우리가 정말 자랄 수 있을까?"

    • 무엇이건 실제 바깥세상(야생)에 임팩트를 남기려면 혼자 힘으로만 되는 게 없는 것 같습니다. 함께 해야 합니다.
    • 세상은 함께 해야 뭔가 이룰 수 있는데 왜 우리는 혼자 하는 것만 배울까요.
    • 세가지 질문
      • 내가 정말 자랄 수 있을까?
      • 우리가 정말 함께 자랄 수 있을까?
      • 우리가 정말 매일매일 함께 자랄 수 있을까?
    • 저는 학습의 본의는 야생 학습에 더 가깝다고 생각을 하고, 현실 세계에서는 야생 학습이 더 많이 필요하다고 봅니다. 그래서 이 책에서 학습을 이야기할 때에는 대부분의 경우 야생 학습을 언급하는 것이라고 보면 되겠습니다.
    • 수파리 이야기로 마무리하면 좋겠습니다. ... 수파리는 특히 제 1단계(일단 규칙을 무조건적으로 받아들이고 따르는 단계)를 강조하기 위해 쓰이는데, 그 미명하에서 얼마나 많은 교육적 폭력이 자행되어 왔나 하는 생각이 듭니다.

    자라기

    당신은 몇년차?

    경력, 그 견딜 수 없는 무거움

    그런데 소프트웨어 기술자의 등급이라는 것이, 겉으로는 기술자격이나 학력에 경험을 함께 고려해 결정되는 것 같아 보이지만 사실상 '경험'이라는 요소가 가장 결정적 역할을 합니다. ... 이런 제도 때문에 사람들은 더더욱 경력의 틀(심리학적 프레임) 안에서 생각하게 됩니다. ... 저는 이 글을 통해,

    1. 경력 연차라는 것으로부터 이 사람이 초급인지 아닌지 정도의 정보만 기대할 수 있으며
    2. 초급이 아닌 사람들에 대해서는 경력 연차가 오히려 혼동을 불러일으키는 잘못된 정보로 작용할 수 있고
    3. 고로 경력 연차로 채용 여부나 임금 수준을 결정하는 것은 판단 편의적이고 관료주의적이며 결과적으로 조직에 손해를 줄 수 있는 방식

    이라고 이야기하려고 합니다.

    직원을 뽑을 때 무엇이 그 사람의 실력을 가장 잘 예측할까?

    ...는 채용 시 가장 효과적인 예측변수가 무엇이냐에 대해 연구했습니다. 0에 가까우면 상관성이 없다고 말하고, 1이나 -1에 가까우면 상관성이 높다고 합니다. 통상 0.5를 넘으면 강한 효과가 있다고 하고 0.2에서 0.5 사이는 중간정도라고 하며, 0.2 이하는 약한 효과라고 합니다.

    경력 연차의 상관성은 0.18, 학력의 상관성은 0.10입니다. 관심사조차도 직무 성과와 상관성이 0.10이 되는 수준입니다.

    그렇다면 어떤 것들이 상관성이 높았을까요? 작업 샘플 테스트(실제로 채용 후 해야 할 작업의 일부를 해보는 테스트)가 0.54, 아이큐가 0.51이었습니다. 성실성이나 꼼꼼한 같은 성격 테스트도 0.41이나 0.31 정도의 상관성이 있었습니다. 레퍼런스 체크도 0.26으로 연차들의 상관성보다 높았습니다.

    그렇다고 연차가 완전히 의미가 없는 것은 아니었습니다. 경력이 얼마 되지 않았을 떄 몇 년간은 연차의 상관성이 꽤 높은 편입니다.

    중요하다고 생각하는 것이 중요하지 않다

    예를 들면 경력을 지나치게 중요하게 여기는 회사가 많습니다. 동시에 협력 능력을 지나치게 등한시하는 회사가 많았습니다.

    최소한도의 경력 수준만 넘겼으면 오히려 몇 년 일했는지는 모르는 것이 더 낫다고 생각하고요. 실제 작업을 해보도록 하는 작업 샘플 테스트, 실제 업무를 주고 시험적으로 짧은 기간 동안 일을 해보게 하는 것 등을 권합니다.

    잘 뽑는 것 이상으로 중요한 것 🚧

    개발자들이 할 수 있는 것 🚧

    자기계발은 복리로 돌아온다 🚧

    복리의 비밀

    "조직에는 세 가지 차원의 작업이 있다"고 컴퓨터 선구자이자 마우스 발명가인 더글라스 엥겔바트가 말했다.

    A 작업은 겉으로 가장 잘 드러나는 수준으로, 한 회사의 사람과 자원의 대부분은 이 수준에 초점이 맞춰져 있다. 그 회사의 사람고 자원의 대부분은 이 수준에 초점이 맞춰져 있다.

    하지만 다음 수준인 B 작업 없이는 효과적인 A 작업은 불가능할 것이다. B 작업은 회사가 자신의 제품과 서비스를 개발, 생산, 판매하는 걸 가능케 해주는 시스템과 프로세스를 설계하는 것과 관련이 있다.

    하지만 가장 미묘하고 또 잠재적으로 가장 영향력이 큰 것은 C 작업으로, 이는 우리의 사고방식과 상호 작용 방식을 개선한다. 궁극적으로는 C 작업의 품질이 우리가 설계하는 시스템과 프로세스의 품질을 결정짓고, 나아가 우리가 제공하는 제품과 서비스의 품질을 결정짓는다.

    보통 경영학에서는 더하는 조직을 작업 그룹이라고 하고 곱하는 조직을 팀이라고 구분합니다. 작업 그룹은 주어진 일을 사람 숫자에 맞게 나눠주고 각자 정해진 일을 하는 형태를 말합니다. 서로 교류할 필요가 없습니다. 반면에 팀은 일을 상호 협력적으로 진행합니다.

    • 그리고 조직의 효과성을 가장 잘 예측하는 변수는 동료 코칭이라고 합니다. 서로 업무적으로 도움을 주고받는 걸 말하죠. 이 동료 코칭과 퍼포먼스 간의 상관계수는 0.82입니다.

    잠자는 시간을 줄이는 것이 더하기적 사고라면, 집단의 지능을 높이는 것은 곱하기적 사고입니다.

    그냥 일하는 시간을 늘리는 것은 작업량을 늘리는 것에 지나지 않습니다.

    A 작업을 개선하려면 두 가지 질문을 해 봐야 합니다. 첫 번째는 어떻게 하면 더하기보다 곱하기를 할 수 있을 것인가입니다. 두 번째는 어떻게 해야 곱하는 비율(이자율)을 높일 수 있는가 혹은 이자 적용 주기(1년에 한 번 대신에 1달에 한번)를 짧게 할 수 있는가입니다.

    • 자신이 이미 갖고 있는 것들을 잘 활용하라
    • 외부 물질을 체화하라
    • 자신을 개선하는 프로세스에 대해 생각해 보라
      • 예컨대 나의 A 작업을 되돌아보는 회고/반성 활동을 주기적으로 하는 프로세스를 만들어라(C 작업).
      • 나를 개선하는 과정(B 작업)을 어떻게 하면 개선할 수 있을지 고민하라.
    • 피드백을 자주 받아라
      • 일찍, 그리고 자주 실패하라. 실패에서 학습하라.
    • 자신의 능력을 높여주는 도구와 환경을 점진적으로 만들어라

    학습 프레임과 실행 프레임

    한 그룹의 아이들에게는 실행 프레임을 갖게 합니다. "여러분이 얼마나 그림을 잘 그리는지 보고자 하는 겁니다. 여러분의 창의성을 측정해 보려고 합니다. 점수를 매길 거에요. ..." 다른 그룹 아이들에게는 학습 프레임을 갖게 합니다. "내가 안 그려 보았던 방식들을 실험해 보는 시간이에요. 여러 가지 방식으로 실험해 보세요." ... 실행 프레임에서는 '잘하기'에 초점을 맞추게 하고, 학습 프레임에서는 '자라기'에 초점을 맞추게 합니다.

    여기에서 말하는 실행 프레임은 사람들이 현재 주어진 과업이 뭔가 좋은 성과를 내는 걸로 생각하는 틀을 말합니다. 학습 프레임은 현재 주어진 과업이 내가 얼마나 배우느냐로 여기게 되는 틀을 말합니다.

    현재 상황 자체가 어렵지 않냐. 업무하면서 학습이 중요하다는 생각을 갖기가 어렵지 않냐.

    지금 자신의 상황 '때문에' 학습 프레임을 갖는 것이 힘들다는 생각이 든다면, 이 우주 어딘가의 누구는 비슷한 상황 '덕분에' 학습 프레임을 가질 수 있었다고 생각하고 있다고 상상해 보면 어떨까요?

    가장 학습하기 힘든 직업이 살아남는다

    학습에 유리한 조건, 불리한 조건

    컴퓨터로 대체되기 힘든 일

    무엇에 집중할 것인가

    달인이 되는 비결

    동기가 부족하다

    피드백을 제때 받지 못한다

    수십 년 동안 전문가가 안 되는 비결

    전문성 형성에서 타당성과 피드백의 중요성

    타당성과 피드백을 높이기

    당신이 제자리걸음인 이유

    의도적 수련의 필수조건, 적절한 난이도

    실력이 늘지 않는 이유

    제자리걸음에서 벗어나기

    지루함을 느끼는 경우: a1 실력 낮추기

    지루함을 느끼는 경우: a2 난이도 높이기

    불안함을 느끼는 경우: b2 실력 높이기

    불안함을 느끼는 경우: b1 난이도 낮추기

    테트리스의 핵심은 살아있으면서도 간단한, 아기 버전의 테트리스를 만드는 것입니다.

    동적인 균형

    팀장이 할 수 있는 일

    이소룡의 자기 혁신

    의도적 수련의 일상적 예시

    실력 조정하기(a1, b2)

    난이도 조절하기(a2, b1)

    일반적으로 제가 새로운 기술을 코칭에 적용할 경우 이 난이도 조절을 적극적으로, 점진적으로 하는 것 같습니다.

    처음에는 현재 제 자신에게 적용해 홉니다. ... 그 다음에는 과거의 힘들거나 어려웠던 상황을 떠올려서 그 때의 자신을 코칭해 봅니다. ... 이게 되면 실제로 그 사람과 코칭을 해봅니다. 이 때에는 미리 언급을 합니다.

    프로그래밍 언어 배우기의 달인

    '인간' 역엔지니어링 방법을 사용하고, 또 가르치고 있습니다.

    S 님의 어떤 전문성을 끌어낼까 하다가 '프로그래밍 언어를 배우는 전문성'을 하기로 했습니다.

    튜토리얼을 읽을 때 뭘 만들지 생각하고 읽는다

    적극적 읽기

    첫 번째 목표로 주로 삼는 프로그램은 단어 개수 세기 프로그램이라고 합니다.

    공부할 때 표준 라이브러리 소스코드를 읽는다

    자연 언어 교육과는 다르게 프로그래밍 언어 교육에서는 읽기보다 쓰기를 더 강조하는 경향이 있습니다. 프로그래밍 언어를 가르칠 때 읽기를 교육하는 경우는 극히 드물죠. 하지만 프로그래머가 실제로 업무를 할 때에는 코드를 읽는 시간이 쓰는 시간을 압도합니다. 좋은 코드를 읽어봐야 좋은 코드를 쓸 수 있기도 하고요.

    S 님은 튜토리얼을 읽어 나가면서 틈틈이 해당 언어의 표준 라이브러리를 찾아 읽었습니다.

    Java로 작성된 프로그램이냐 C로 작성된 프로그램이냐를 가르는 진짜 기준은 어떤 언어의 키워드를 썼느냐가 아니라 어떤 스타일을 따르고 어떤 숙어를 사용했는가입니다.

    공부 중 다른 사람의 코드에 내가 필요한 기능을 추가한다

    전문성을 효과적으로 뽑아내는 전문가가 되기

    한 가지 비결은 전문가가 구체적인 사건에 대해 말하도록 유도하는 겁니다.

    S 님의 경우에는, 가장 최근에 익힌 언어가 Go라고 하더군요. 그 언어를 익힌 과정을 시간대별로 짚어가며 어떤 행동을 했는지, 그리고 암묵적인 의사결정과 상황판단이 무엇이었는지를 추출했습니다.

    실수는 예방하는 것이 아니라 관리하는 것이다

    미연에 실수를 막아야 한다?

    미국 산림청의 산불 정책이 수십년 전에 바뀐 것을 아십니까? 예전에는 산불 예방을 강조했습니다.

    이제는 불 예방에서 불 관리 쪽으로 초점이 바뀌었습니다.

    흥미로운 부분은 가장 사망률이 높은 병원과 가장 낮은 병원 집단 사이에 수술 후 합병증 발생 확률이 통계적으로 차이가 있었다는 점입니다. 그럼 무엇이 사망률의 차이를 만들었을까요? 합병증을 발견하고 적절한 조치를 취하는 부분에서 차이가 났습니다. ... 사망률이 낮은 병원은 심각한 합병증이 벌어지는 것을 잘 알아챘고, 또 합병증이 생긴 후 적절한 조치를 했던 것이죠.

    두 가지의 실수 문화

    실수 예방 문화에서는 실수를 한 사람을 비난하고, 처벌하고, 따라서 실수를 감추고 그에 대해 논의하기 꺼리며 문제가 생겼을 때 협력도 덜 하게 됩니다. 반대로 실수 관리 문화에서는 실수가 나쁜 결과를 내기 전에 빨리 회복하도록 돕고, 실수를 공개하고, 실수에 대해 서로 이야기하고 거기에서 배우는 분위기가 생깁니다.

    실수 연구의 역사를 보면, 초기에는 기술적인 부분만 보다가 그 다음에는 인간적인 부분을 보다가, 이제는 문화적인 부분을 이야기합니다.

    실수가 없으면 학습하지 못합니다. 이는 학습이론의 기본입니다.

    다양한 실수를 경험하는 걸 격려하고, 실수 사례를 배우고, 실수 시에 어떻게 대처하는가를 가르치는 교육이 더 효과적이라는 연구 결과가 많습니다.

    뛰어난 선생에 대한 미신

    흥미롭게도 많은 조직에서 교육은 투입으로 성과를 측정하는 대표적 분야입니다.

    기업에서의 교육, 훈련 효과에 대한 메타분석 연구에 따르면 대부분의 훈련은 6개월 정도만 지나도 효과가 거의 사라집니다.

    존 해티의 연구에 따르면 교사가 가진 주제에 대한 지식수준은 효과 크기가 0.09에 지나지 않으며 ... 교사가 지식이 얼마나 많은지는 큰 영향을 미치는 요소가 아니라는 말이지요.

    왜 그럴까요? ... 여기에서는 특히 '아는 것을 온전히 가르칠 수 있는가'하는 면에 초접을 맞춰보죠.

    전문가가 가르쳐주는 것은 전부가 아니다

    의료계의 연구를 보면, 전문가가 특정 수술법을 학생에게 가르칠 때, ... 70%는 가르치지 않는다는 분석이 거듭해 나왔습니다. 가르치는 능력을 인정받고 한 번 이상의 '탁월한 교사상'을 받은 사람임에도 그랬고, .. 그 기술을 성공적으로 해내기 위해 필요한 것의 30%만 가르쳐 놓고 자신은 다 가르쳤다고 생각하는 겁니다.

    이런 현상이 벌어지는 이유에는 ... 대표적인 것이 자동화입니다. 전문가가 되면 자신이 하는 일이 반복적으로 몸에 익고 자동화가 되어서 결국 암묵적이 되어 버립니다.

    인지적 작업 분석으로 극복하기

    이걸 극복하는 방법이 있을까요? 네. 있습니다. ... 한 가지 힌트를 드리자면, 앞에서 <프로그래밍 언어 배우기의 달인>의 인지적 작업 분석 같은 방법을 선생과 학생이 쓰는 겁니다. ... 메타분석에 따르면 선생이 인지적 작업 분석에 능숙한가 하는 것이 학생들의 학업성취도에 미치는 여향의 효과 크기가 자그만치 1.29나 됩니다. 이런 분석 능력이 뛰어난 선생이 잘 가르치는 사람이라는 이야기입니다.

    또 선생의 메타인지를 돕기 위해 자기가 어떻게 생각하면서 이 문제를 풀었는지 그 인지적 과정을 선생에게 알려주는 것도 매우 효과적입니다.

    나홀로 전문가에 대한 미신

    보통은 어떤 사람이 전문가라고 하면 그 사람의 뇌 안에서 무슨 일이 벌어질까에만 주목하는 면이 있습니다. '고독한 천재'같은 ... 이미지로 떠올리기도 하죠. 그런데 과연 현실에서의 전문가가 정말 그런 사람일까요?

    뭘 하든지 나 혼자가 아니라 항상 누군가가 등장하고, 일의 성패에 다른 사람이 관련되어 있기 때문입니다. 정리하면 다음과 같습니다.

    1) 아무리 기술적인 실천법이라고 해도 2) 그 기술은 사회적 맥락 속에서 실천되어야 하며 3) 그 기술의 성공을 위해서는 사회적 자본과 사회적 기술이 함께 필요하다.

    사회적 자본과 기술

    신뢰가 깨어져 있는 상태에서는 어떤 행동을 해도 악의적으로 보인다는 것입니다.

    이 신뢰를 사회적 자본의 일종이라고 합니다.

    고독한 전문가라는 미신

    전문가가 해당 도메인 지식만 뛰어난 사람이라는 것은 대표적인 미신입니다. 전문가는 사회적 자본과 사회적 기술 또한 뛰어납니다.

    이제는 프로그래밍을 잘한다는 정의 안에 의사소통 능력을 그 일부로 보게 된 겁니다.

    희망적인 소식은 이런 사회적 기술을 훈련으로 개선할 수 있다는 겁니다.

    간단한 방법은 주변 사람들과 주고받는 마이크로 인터랙션에 신경을 쓰는 겁니다. 그걸 기록하고, 복기하고, 다르게 인터랙션한다고 하면 어떻게 했으면 좋았을까를 생각해보는 것만으로도 훈련이 될 수 있습니다.

    저는 ... TDD를 사람들에게 교육하고 컨설팅해주었습니다. 제 경험에 한해서는 TDD 도입에 실패하는 경우, ... 필요한 사회적 자본과 사회적 기술이 없어서가 훨씬 더 많았습니다.

    어떤 기술적 지식을 전달한다고 해도 그것을 사회적 맥락 속에서 가르치고 경험하게 하려고 노력하고 있습니다.

    제가 중요하게 다루는 사회적 기술은 도움받기, 피드백 주고받기, 영향력 미치기, 가르치고 배우기, 위임하기 등이 있습니다.

    함께

    사람들은 협력이 중요하다고 합니다. 그래서 프로젝트를 할 때 협력적으로 하자고 합니다. 그러나 실제 모습을 들여다보면 초반에 일을 세밀하게 나누고 선을 긋습니다. 그리고 안녕이죠.

    우리는 협력을 제대로 배워본 적이 거의 업시 때문입니다.

    그래서 지금부터라도 협력 방법을 배우고 수련해야 합니다.

    소프트웨어 관리자의 개선 우선순위

    조엘 테스트라는 것이 있습니다.

    그러나 여기에 가장 큰 위험이 존재합니다. 선의의 관리자나 경영진이 각 질문의 맥락을 이해하지 못한 채 단순히 12가지 질문에 예라고 답하는 것을 목표로 노력하는 경우를 말하는 겁니다.

    모든 항목에 "예"라고 답하는 것이 무조건 더 낫다고 동의하기 어렵다

    제가 아는 뛰어난 팀들은 툴을 고를 때 단순히 비싼 게 뭐냐를 기준으로 고르지 않습니다. 이 항목을 보고 '비싼 툴을 쓰면 잘하겠지'하고 생각하는 건 기술을 이해하지 못하는 경영자 마인드에 가깝습니다.

    12가지 질문이 개발팀 평가에서 정말 중요한 요소인가?

    품질 전문가 제럴드 와인버그가 한 말을 살펴봅시다. 이분은 소프트웨어 개발을 잘 관리하려면 세 가지 근본적 능력이 필요하다고 했습니다.

    1. 복잡한 상황을 이해하는 능력으로, 프로젝트를 계획한 다음 관찰하고 행동하여 계획에 맞게 프로젝트가 진행되게 하거나 계획을 바꿀 수 있어야 한다.
    2. 관찰하는 능력으로, 무엇이 벌어지고 있는지를 관찰하고, 효과적인 적응 행동을 하기 위해 자신이 관찰한 것이 어떤 의미인지 이해할 수 있어야 한다.
    3. 행동하는 능력으로, 어려운 대인 상황에서 우리가 심지어 혼란스럽거나 화가 나 거나 아니면 무서워서 도망쳐 숨어버리고 싶을 때에도 적절하게 행동할 수 있어야 한다.

    이 세 가지 능력을 활용해 실제 조직과 개인(관리자 자신을 포함-와인버그는 자신을 바꾸지 못하는 사람은 다른 사람을 바꾸는 일도 할 수 없다고 합니다)

    QSM 4권에 소프트웨어 개발 비용에 대한 내용이 있습니다. 다음 네 가지 요소의 분류에서 가장 중요한 것부터 나열해 보세요.

    • 도구 : 소프트웨어 개발에 사용하는 모든 종류의 도구. 컴퓨터, 모니터, 디버거, IDE
    • 사람 : 사람들의 능력과 경험
    • 시스템 : 제품 자체의 복잡도, 요구되는 신뢰성, DB 크기, 타깃(VM 등)의 변화 가능성, 스케줄 제약 등
    • 관리 : 사람을 배정하고 작업 분배를 조정하고 위임하는 것, 작업 모니터링, 동기를 고취하는 것, 작업 조건/환경을 개선하는 것, 자원의 준비, 리스크를 일찍 확인하고 적절한 조치를 취하는 것, 요구사항과 설계 스펙이 비준(validate)되게 돕는 것 등

    비슷한 크기의 소프트웨어를 개발한다고 할 때, 각 분류별로 비용 면에서 가장 적게 드는 회사부터 그렇지 않은 회사까지 100등까지 순위를 매깁니다. 85등이던 회사가 10등하는 회사로 '개선'을 했다면 개발 비용이 얼마나 줄어들까요? 개선효과가 높은 것은 무엇일까요?

    ...

    관리, 시스템, 사람, 도구 순서였습니다. ... 하지만 각 분류별로 실제로 개선 시도가 얼마나 있었는지 확인해 보니 가장 많은 개선 노력이 있었던 분류를 바로 '도구'였습니다

    다시 조엘 테스트로 돌아갑시다. 조엘 테스트는 가장 만만하고 쉬운 것부터 시작하는 관리자의 성향과 충돌하지 않습니다.

    저는 관리자가 눈에 잘 보이고 갈아치우기 쉬운 '도구'들에 신경을 쓰는 것이 위험하다고 생각합니다.

    협력을 통한 추상화

    커뮤니케이션과 협력

    일반적으로, 실력이 뛰어난 프로그래머는 보통 정도의 실력을 가진 프로그래머에 비해 커뮤니케이션, 협력 능력이 더 뛰어납니다.

    백지장도 맞들면 찢어진다?

    톱니바퀴 실험

    둘이서 함께 작업한 경우 58%나 추상화 규칙을 찾아냈습니다. 4배가 넘습니다. 만약 두 사람이 한 팀으로 작업하되 서로 이너랙션하지 않았고, 그들의 결과물 중 더 나은 것을 택하는 방식(명목 집단(nominal group)이라고 함)이라면? 이 경우는 확률적으로 계산할 수 있는데, 26%가 됩니다.

    그러면서 맞은편의 사람과 이야기를 하는데, ... 이런 혼동을 해결하기 위해 추상적 개념을 도입합니다. 예컨대 바퀴에 식별 번호를 붙인다든지 하는 것이지요.

    둘이서 협력하면서 작업하면 서로 시각이 다르기 때문에 두 사람의 다른 시각을 연결해 줄 다리가 필요하고, 그 다리에는 필연적으로 추상화의 요소가 있게 됩니다. 서로 다른 것들을 하나로 묶어야 하기 때문입니다.

    추상화의 중요성

    만약 코드가 비지니스 로직이 들어가고 그 로직이 domain-rich 하다면 되도록 가독성을 추구하겠지만, 저는 때로 가독성을 손해보면서까지 중복을 줄이기도 합니다. ... 흥미로운 객체들을 발견합니다. ... 내가 전에 모르던 것을 배우게 됩니다.

    '흥미로운 무엇'이 바로 추상화입니다.

    인용문 대로 소프트웨어 공학의 역사는 정말 추상화를 높이기 위한 여정이었습니다. ... 그런데 우리는 조금 전 추상화를 높일 수 있는 방법을 하나 찾아냈습니다.

    대화하는 프로그래밍

    익스트림 프로그래머는 작업하면서 프로그래밍 각 단계에 대해 함께 이야기한다.

    자신이 작성하는 코드의 추상성을 높이고 싶다면 혼자서 고민하지 말고 다른 사람들과 협동하고, 대화하세요. 같이 그림도 그려보고 함께 소스코드를 편집하세요. 인간에게는 다른 인간과 소통하고 협력할 수 있는 놀라운 능력이 있습니다. 대화는 기적입니다.

    신뢰를 깎는 공유인가 신뢰를 쌓는 공유인가

    공유 조건별 신뢰도 변화 실험

    조금 충격적인 이야기를 해드리겠습니다. 두 경우 모두 공유 후에 신뢰감이 더 떨어졌습니다. 특히 첫 번째, 즉 디자인 하나만 작업하고 그걸 공유한 경우가 더 많이 떨어졌습니다만, 두 조건 모두 신뢰감이 통계적으로 유의미하게 떨어졌습니다. 공유를 해서 신뢰가 더 떨어지는 상황이 벌어진 것이죠.

    각자 여러 개의 디자인을 만들고 그걸 모두 공유한 경우였습니다. 이때는 신뢰가 유의미하게 증가했습니다.

    하나 공유나 최고 공유의 경우 우리는 공유 자리에 기대감보다 불안감을 갖고 갈 겁니다.

    복수 공유의 장점

    복수 공유는 그런 불안감이 상대적으로 덜합니다. 여러 개를 준비했으니 그중 하나를 두고 뭐라고 해도 나에 대한 공격은 아닌 겁니다.

    마지막으로 가장 놀라운 부분 ... 클릭률이 더 높았습니다. 복수 공유는 (같은 시간을 투자했을 때) 신뢰도 높아지고 성과도 더 좋았다는 말입니다.

    여러분의 공유는 어떻습니까? 신뢰를 깎아먹는 공유를 하고 계신가요, 신뢰를 쌓아가는 공유를 하고 계신가요?

    객관성의 주관성

    새로운 개념을 주변에 설득하기 위해 노력하는 분들을 많이 봅니다.

    그런 분들을 만나면 저는 다음과 같은 질문을 던집니다. "상대방에 대해 얼마나 이해를 하고 계신가요? 얼마나 대화를 해보셨나요?"

    강사는 자신이 좋은 예를 들었다고 생각합니다. 하지만 질문자는 그렇게 생각하지 않습니다. '예'의 정이가 주관적이라 벌어진 일이죠.

    품질은 상대적이다

    품질 전문가 제럴드 와인버그는 품질을 다음과 같이 정의합니다.

    품질이란 누군가에게 가치가 되는 것이다.

    우리가 일반적으로 듣는 품질의 정이와 다르죠? ... 그런 정의들은 매우 플라톤적입니다. 뭔가 고상하고 완벽한 품질이라는 것이 하늘 어딘가에 있는 것처럼 들립니다. 하지만 와인버그의 정의는 상대주의적이며 동시에 무척 실용적입니다.

    우리가 품질을 이야기할 때에는 '누구'를 놓고 하는 말이냐는 걸 생각해 봐야 한다 이겁니다.

    결국 결정하는 것은 사람입니다.

    감정을 배제할 수 없다

    그리고 논리랑 감정적 판단을 분리할 수가 없습니다.

    의사결정을 하는 과정에 감정적이고 직관적인 부분이 큰 역할을 하고 있으며, 그런 감정적 부분이 배제된다면 의사결정을 제대로 할 수 없다는 것을 알 수 있습니다.

    남을 설득하려면 논리성과 객관성에 대한 환상을 버려야 합니다. 그래야 현실적으로 설득이 가능합니다. 내가 설득하고 싶은 상대를 자주 만나서 신뢰를 쌓고, 그 사람이 무엇을 중요하게 여기는지, 어떤 설명 방식을 선호하는지 이해해야 합니다.

    성향과 기질에 따른 애자일 설명법

    결론은, 객관성이라고 하는 것은 상대적이며, 내가 생각하는 객관이 상대의 객관이 아닐 수 있고, 그렇기 때문에 설득에 성공하려면 우선 그 사람을 이해하는 것에서 출발해야 한다는 말입니다.

    이것도 모르세요?

    공감하고 이해하려는 대화

    이런 과정을 거치면 홍춘이의 머릿속에는 어떤 그림이 떠오를까요? ... 술퍼맨의 머릿속 지도와 사고 흐름을 엿보게 되는 것이죠.

    그 사람이 이 상황에서 왜 이런 접근을 할 수밖에 없었는지 알기 때문에 좀 더 정확하고 효과적인 제안을 해줄 수 있습니다. ... 또, 소위 암묵지라고 부르는 것들을 전달해줄 수도 있습니다.

    행동을 유도하는 대화

    술퍼맨 : 네, 그러고 싶어요. 그런데 언젠가 한번 마음먹고 제대로 공부해야지, 해야지 하고 생각하면서 몇 달째 미루고 있는 것 같아요.

    홍춘이 : 정규식을 배워서 해보고 싶은 것들이 있나봐요. ...

    참고로 코칭의 흥미로운 점은 코치 자신(홍춘이)이 해당 영역(정규식)에 대한 전문지식이 없어도 코칭을 할 수 있다는 점입니다.

    하향식 접근의 함정

    대부분의 기업에서 직원 숫자가 늘어나기 시작하면 추상 층위에 따라 팀을 나눕니다. 각 층위의 전문가 팀이 존재합니다. 기획팀, 구현팀, QA팀 등, 그리고 일이 진행됨에 따라 팀 간의 바통 터치가 이루어집니다. 위에서 아래 방향으로요.

    그럼 모든 문제를 탑다운 식으로 푸는 것이 우리의 지향점일까요? 인공지능 연구에선 이 세상의 문제를 두 종류로 나눕니다. 잘 정의된 문제와 잘 정의되지 않은 문제 ... 오목이나 체스 ... 여기에 속합니다.

    하지만 우리가 실생활에서 만나는 대다순의 문제는 잘 정의되지 않은 문제입니다.

    앞서의 전문가들은 ... 잘 정의되지 않은 문제를 접하면 접근법을 바꿉니다. 탑다운과 바텀업을 섞어 씁니다. 뛰어난 전문가일수록 더욱 그러합니다.

    특히 탑다운과 바텀업의 방향이 전환되는 시점들에서 '아하 순간'이 찾아왔습니다.

    "이번 일은 복잡하고 불확실하니까 철저하게 계획하고 단계적으로 접근하자!" 이 말은 곧, 이번 일은 불확실하니까 초보처럼 일하자는 말과 똑같습니다.

    오히려 전문가일수록 자신의 계획을 수정한 횟수가 많았습니다.

    연구에 따르면, 프로그램을 이해할 때 고수는 상호 참조 전략을 쓰는 반면 하수는 그렇지 않았습니다.

    고수는 ... 프로그램에서 이해한 것을 도메인 어휘로 번역합니다. 그러고는 도메인 어휘를 프로그램상의 어휘로 다시 바꿔서 검증합니다. 이를 상호 참조 전략이라고 합니다.

    빠르고 빈번한 바통 터치가 가능한 전문가 조직

    삼투압적 의사소통

    사람들이 물리적으로 가까운 거리에 있어야 유리하겠죠.

    그리고 한번에 처리되는 일의 양(batch size)을 줄여야 합니다. 배치 사이즈를 줄여서 지속적 흐름을 만들고 짧은 시간 내에 탑, 바텀을 오가게 합니다. 예를 들어 전에는 디자이너가 100개의 일자리를 다 처리한 후에 한꺼번에 모아 결과를 전달했다면 점차 50개로, 10개로, 1개로 낮추어야 합니다.

    어느 한 단계를 한번에 완료하는 것은 더 낮은 품질로 가는 지름길입니다.

    흔히들 말하는 개발의 5단계도 비슷합니다. ... 어떻게 해야 첫 달부터, 아니 첫 주부터 분석, 설계, 구현, 테스트, 전개를 모두 왔다갔다할 수 있을까를 고민해야 할 것입니다.

    전문가 팀이 실패하는 이유

    회사에서의 올스타는 어떨까요? ... 스타들이 한 명씩 팀에 추가될 떄마다 팀의 추가적 성과 향상은 한계효용을 보이며 어느 수준을 지나면 음의 방향으로 작용한다고 합니다.

    전문가가 추가되는게 도움이 안 되거나 오히려 성과를 깎아먹는 경향은 특히나 전문가들의 전문성이 서로 유사할 떄 도드라졌습니다.

    자기들이 알아서 하게 놔둔 전문가팀은 비전문가로만 구성된 팀보다도 훨씬 못한 결과가 나왔습니다.

    팀 내에 개인 내 다양성이 높은 멤버가 없다면 전문가로 구성된 팀은 정보 공유가 잘 안 되어서 성과가 떨어질 수 있다는 분석을 했습니다.

    구글이 밝힌 탁월한 팀의 비밀

    제가 봤을 떄 중요한 부분은 세 군데입니다.

    1. 팀에 누가 있는지(전문가, 내향/외향, 지능 등)보다 팀원들이 서로 어떻게 상호작용하고 자신의 일을 어떻게 바라보는지가 훨씬 중요했다.

    2. 5가지 성공적 팀의 특징을 찾았는데, 그중 압도적으로 높은 예측력을 보인 변수는 팀의 심리적 안전감이었다.

    3. 팀 토론 등 특별히 고안된 활동을 통해 심리적 안전감을 개선할 수 있었다.

    여기에서 말하는 심리적 안전감이란, 내 생각이나 의견, 질문, 걱정, 혹은 실수가 드러났을 때 처벌받거나 놀림받지 않을 거라는 믿음을 말합니다.

    에드몬드슨은 이런 도구를 사용해 병원의 중환자실의 심리적 안전감을 측정해 보았습니다. ... 예상과 비슷하게, 직위에 따라 느끼는 심리적 안전감에 통계적으로 유의미한 차이가 있었습니다.

    심리적 안전감이 높은 병실에서는 ... 18%나 낮은 사망률을 보였습니다.

    팀원이 불편한 문제를 제기하거나, 어리석어 보이는 질문을 하거나, 부족한 의견을 얘기하거나, 어처구니없는 실수를 저지를 때 여러분은 어떤 마이크로 인터랙션을 보여주고 계신가요?

    쾌속 학습팀

    최소 침습 심장 수술

    논문 제목은 <팀 학습의 속도 높이기>입니다. 최소 침습 심장 수술법을 어떤 팀이 빨리 익히는가 하는 것이 주제입니다.

    하지만 놀라운 점은 수술 시간 감소율이 팀마다 천차만별이었다는 겁입니다.

    학습 속도와 상관없는 것

    리더가 팀 학습 속도에 미치는 영향

    단순히 기술적 탁월함만을 갖춘 사람보다는 학습 환경을 만들 수 있는 리더가 필요하다는 것입니다.

    학습 환경의 차이

    선발 자체가 매우 협동적

    속도가 빠른 팀은 새로운 수술 도입을 기술적 도전이라기보다 조직적 도전으로 받아들였습니다. 개개인이 새로운 기술을 획득해야 한다고 보지 않고, 함께 일하는 새로운 방법을 만들어야 한다고 생각했습니다.

    마지막으로, 속도가 빠른 팀은 심리적으로 보호가 되고 있었습니다.

    기술 전환에 성공한 개발팀

    속도가 빠른 팀은 도전 자체를 팀의 학습 능력에 대한 도전으로 받아들였고, 같이 학습해야 한다고 생각했습니다.

    속도가 느리거나 낙오된 팀은 학습을 개인의 과제로 치부했습니다. 학습보다는 단기 퍼포먼스를 중요시했습니다.

    현실에서 실천하기

    다시 현실에서 돌아와서, 나는 팀장도 아니고, 정치적인 힘도 없습니다. 그렇다면 이 상황에서 내가 무엇을 할 수 있을까요? 팀원과 팀장에게 이 책을 권할 수 있는 분위기도 아니라면?

    우선 자신의 학습 환경을 만드세요. 거기서부터가 출발입니다. 개별 기술 이상으로 일하는 방식에 대해 실험을 해 보세요.

    프로젝트 확률론

    이번 프로젝트는 제떄에 끝낼 수 있을 것 같았는데

    소프트웨어 공학 쪽의 연구에 따르면 사람들이 통상적으로 추정하는 소요시간에 적어도 2~3배를 해야 80% 정도의 확률로 마칠 수 있는 시간이 나온다고 합니다.

    게다가 일반적으로 일의 소요 시간을 추정할 때 사람들이 낙관적으로 추정한다는 편향에 대한 연구 결과가 많다는 점까지 고려하면 상황은 더 심각해집니다.

    또 다른 연구에 따르면, 사람들에게 가장 그럴싸한 추정(best guess)을 부탁했을 때와 자신이 기대하는 최선의 상황(best case scenario)을 상상해서 추정해보라고 부탁했을 때 그 추정치는 큰 차이가 없었습니다.

    애자일 확률론

    제가 선호하는 접근법은 관리자가 12명 모두에게 단지 3가지 일만 주고 서로 협동해서 그 일을 하도록 요청하는 것입니다.

    이 방식이 잘 돌아가는 이유는 사람들이 '관심사의 섞임'을 통해 서로에 대해 엄청나게 많은 것을 매우 빨리 배울 수 있기 때문입니다.

    애자일은 앞서의 고전적 방법과 달리 일을 공유합니다. 각자 일을 얼마나 진행했는지 매일 공유할 뿐 아니라 내 일, 네 일의 구분선이 뚜렷하지 않습니다. 애자일에서는 되도록 사람들이 섞이도록 합니다.

    애자일은 마치 프랙털 구조처럼 부분 속에 전체가 들어가게 합니다. 그렇게 하면 과거에서 미래를 접쳐 보기가 훨씬 쉽습니다. 일이 진행될수록 점점 추정 정확도가 높아집니다.

    한 사람만이라도 중요한 통찰이 있었다면 이걸 공유해서 '또는' 확률로 만들고, 버그 같이 나쁜 일에 대해서는 여러 사람이 중복 검토를 해서 모두가 실수해야지만 구멍이 나게 '그리고' 확률로 바꾸는 것입니다.

    애자일

    당시 주도적인 소프트웨어 개발 방식은 계획주도의 방식이었습니다. 계획주도 방식에서는 초반에 계획을 정교하고 꼼꼼하게 만들려고 엄청난 노력을 합니다. 그러면 실행단계는 간단해지고 예측 가능해진다고 생각하기 때문입니다. 하지만 애자일은, 불확실성이 높은 일에 대해서는 애초에 이것이 불가능하다고 봅니다. 불확실성 크기 때문에 미리 분석하고 설계하는 데 한계가 있다는 것이지요.

    이번에는 과의의 애자일을 얘기해 보겠습니다. 애자일을 단순히 소프트웨어 개발 방법론이라는 울타리에 가두어 보지 않고, 일하는 한 가지 스타일, 혹은 더 넘어서서 삶을 사는 방식으로까지 확장해 보는 것이지요.

    학습과 협력은 불확실성이 큰 상황에서 좋은 대응전략이 됩니다. 우리의 삶도 불확실하기 때문에 학습과 협력은 현명한 전략이 될 것이고요.

    애자일의 씨앗

    씨앗이 될만한 것을 줘야합니다.

    고객에게 매일 가치를 전하라.

    애자일 도입 성공 요인 분석

    두려워도 중요하다면 시도해봐야 하지 않겠는가

    당신의 조직에 새 방법론이 먹히지 않는 이유

    결과들을 보면 상담에서 어떤 기법을 쓰느냐보다 치료자가 누구인가가 상담 효과에 더 큰 영향을 준다는 게 거듭 밝혀졌습니다.

    매뉴얼이 말하고 있는 것보다 훨씬 더 많은 것을 상담사들이 할 수 있다는 말이 될 것입니다.

    사실 더 나아가서 모든 지식이 근본적으로는 암묵지라고 역설했습니다.

    맥락을 가로지르는 보편적 규칙들이 별로 없다고 생각이 든다면, 결과를 에측하기 어렵고 불확실성이 높다면, 해당 분야는 '복잡한 도메인'이 됩니다. 상담이 그렇죠. 이런 복잡한 분야일수록 어떤 특정 기법의 효과보다도 치료자 효과가 더 큰 영향을 미칠 것입니다.

    내가 어떤 팀장인지가 전혀 바뀌지 않으면서 새 방법론만 도입한다고 무슨 효과가 있을까요.

    애자일을 애자일스럽게 도입하기

    칸반 같은 개별 실천법은 상시 변화하고 발전하는 도요타의 특정 시점의 스냅샷 같은 것이 아닐까 생각합니다. 우리가 배워야 할 것은 칸반 이면의, 칸반이 나올 수 있었던 구조의 문화입니다.

    "... 애자일을 도입할 때 확실성 위에서 진행하려고 한다면 문제가 된다"

    이것은 거의 모든 종류의 방법론 도입에 적용됩니다. 왜냐하면 방법론 도입은 태생적으로 불확실성이 높기 때문입니다. ... 수순을 따르는 것이 아니라 곁에 있는 사람들과 함께 주변을 탐색하고 조금 나아가고 확인하고를 반복하면서 우리의 현 맥락에 맞는 좋은 전략들을 스스로 만들어 나가는 것이 아닐까 합니다

    - +
    Skip to content
    On this page

    함께 자라기

    220100 %

    머리말

    내가 정말 잘할 수 있을까? 아니, 우리가 정말 자랄 수 있을까?"

    • 무엇이건 실제 바깥세상(야생)에 임팩트를 남기려면 혼자 힘으로만 되는 게 없는 것 같습니다. 함께 해야 합니다.
    • 세상은 함께 해야 뭔가 이룰 수 있는데 왜 우리는 혼자 하는 것만 배울까요.
    • 세가지 질문
      • 내가 정말 자랄 수 있을까?
      • 우리가 정말 함께 자랄 수 있을까?
      • 우리가 정말 매일매일 함께 자랄 수 있을까?
    • 저는 학습의 본의는 야생 학습에 더 가깝다고 생각을 하고, 현실 세계에서는 야생 학습이 더 많이 필요하다고 봅니다. 그래서 이 책에서 학습을 이야기할 때에는 대부분의 경우 야생 학습을 언급하는 것이라고 보면 되겠습니다.
    • 수파리 이야기로 마무리하면 좋겠습니다. ... 수파리는 특히 제 1단계(일단 규칙을 무조건적으로 받아들이고 따르는 단계)를 강조하기 위해 쓰이는데, 그 미명하에서 얼마나 많은 교육적 폭력이 자행되어 왔나 하는 생각이 듭니다.

    자라기

    당신은 몇년차?

    경력, 그 견딜 수 없는 무거움

    그런데 소프트웨어 기술자의 등급이라는 것이, 겉으로는 기술자격이나 학력에 경험을 함께 고려해 결정되는 것 같아 보이지만 사실상 '경험'이라는 요소가 가장 결정적 역할을 합니다. ... 이런 제도 때문에 사람들은 더더욱 경력의 틀(심리학적 프레임) 안에서 생각하게 됩니다. ... 저는 이 글을 통해,

    1. 경력 연차라는 것으로부터 이 사람이 초급인지 아닌지 정도의 정보만 기대할 수 있으며
    2. 초급이 아닌 사람들에 대해서는 경력 연차가 오히려 혼동을 불러일으키는 잘못된 정보로 작용할 수 있고
    3. 고로 경력 연차로 채용 여부나 임금 수준을 결정하는 것은 판단 편의적이고 관료주의적이며 결과적으로 조직에 손해를 줄 수 있는 방식

    이라고 이야기하려고 합니다.

    직원을 뽑을 때 무엇이 그 사람의 실력을 가장 잘 예측할까?

    ...는 채용 시 가장 효과적인 예측변수가 무엇이냐에 대해 연구했습니다. 0에 가까우면 상관성이 없다고 말하고, 1이나 -1에 가까우면 상관성이 높다고 합니다. 통상 0.5를 넘으면 강한 효과가 있다고 하고 0.2에서 0.5 사이는 중간정도라고 하며, 0.2 이하는 약한 효과라고 합니다.

    경력 연차의 상관성은 0.18, 학력의 상관성은 0.10입니다. 관심사조차도 직무 성과와 상관성이 0.10이 되는 수준입니다.

    그렇다면 어떤 것들이 상관성이 높았을까요? 작업 샘플 테스트(실제로 채용 후 해야 할 작업의 일부를 해보는 테스트)가 0.54, 아이큐가 0.51이었습니다. 성실성이나 꼼꼼한 같은 성격 테스트도 0.41이나 0.31 정도의 상관성이 있었습니다. 레퍼런스 체크도 0.26으로 연차들의 상관성보다 높았습니다.

    그렇다고 연차가 완전히 의미가 없는 것은 아니었습니다. 경력이 얼마 되지 않았을 떄 몇 년간은 연차의 상관성이 꽤 높은 편입니다.

    중요하다고 생각하는 것이 중요하지 않다

    예를 들면 경력을 지나치게 중요하게 여기는 회사가 많습니다. 동시에 협력 능력을 지나치게 등한시하는 회사가 많았습니다.

    최소한도의 경력 수준만 넘겼으면 오히려 몇 년 일했는지는 모르는 것이 더 낫다고 생각하고요. 실제 작업을 해보도록 하는 작업 샘플 테스트, 실제 업무를 주고 시험적으로 짧은 기간 동안 일을 해보게 하는 것 등을 권합니다.

    잘 뽑는 것 이상으로 중요한 것 🚧

    개발자들이 할 수 있는 것 🚧

    자기계발은 복리로 돌아온다 🚧

    복리의 비밀

    "조직에는 세 가지 차원의 작업이 있다"고 컴퓨터 선구자이자 마우스 발명가인 더글라스 엥겔바트가 말했다.

    A 작업은 겉으로 가장 잘 드러나는 수준으로, 한 회사의 사람과 자원의 대부분은 이 수준에 초점이 맞춰져 있다. 그 회사의 사람고 자원의 대부분은 이 수준에 초점이 맞춰져 있다.

    하지만 다음 수준인 B 작업 없이는 효과적인 A 작업은 불가능할 것이다. B 작업은 회사가 자신의 제품과 서비스를 개발, 생산, 판매하는 걸 가능케 해주는 시스템과 프로세스를 설계하는 것과 관련이 있다.

    하지만 가장 미묘하고 또 잠재적으로 가장 영향력이 큰 것은 C 작업으로, 이는 우리의 사고방식과 상호 작용 방식을 개선한다. 궁극적으로는 C 작업의 품질이 우리가 설계하는 시스템과 프로세스의 품질을 결정짓고, 나아가 우리가 제공하는 제품과 서비스의 품질을 결정짓는다.

    보통 경영학에서는 더하는 조직을 작업 그룹이라고 하고 곱하는 조직을 팀이라고 구분합니다. 작업 그룹은 주어진 일을 사람 숫자에 맞게 나눠주고 각자 정해진 일을 하는 형태를 말합니다. 서로 교류할 필요가 없습니다. 반면에 팀은 일을 상호 협력적으로 진행합니다.

    • 그리고 조직의 효과성을 가장 잘 예측하는 변수는 동료 코칭이라고 합니다. 서로 업무적으로 도움을 주고받는 걸 말하죠. 이 동료 코칭과 퍼포먼스 간의 상관계수는 0.82입니다.

    잠자는 시간을 줄이는 것이 더하기적 사고라면, 집단의 지능을 높이는 것은 곱하기적 사고입니다.

    그냥 일하는 시간을 늘리는 것은 작업량을 늘리는 것에 지나지 않습니다.

    A 작업을 개선하려면 두 가지 질문을 해 봐야 합니다. 첫 번째는 어떻게 하면 더하기보다 곱하기를 할 수 있을 것인가입니다. 두 번째는 어떻게 해야 곱하는 비율(이자율)을 높일 수 있는가 혹은 이자 적용 주기(1년에 한 번 대신에 1달에 한번)를 짧게 할 수 있는가입니다.

    • 자신이 이미 갖고 있는 것들을 잘 활용하라
    • 외부 물질을 체화하라
    • 자신을 개선하는 프로세스에 대해 생각해 보라
      • 예컨대 나의 A 작업을 되돌아보는 회고/반성 활동을 주기적으로 하는 프로세스를 만들어라(C 작업).
      • 나를 개선하는 과정(B 작업)을 어떻게 하면 개선할 수 있을지 고민하라.
    • 피드백을 자주 받아라
      • 일찍, 그리고 자주 실패하라. 실패에서 학습하라.
    • 자신의 능력을 높여주는 도구와 환경을 점진적으로 만들어라

    학습 프레임과 실행 프레임

    한 그룹의 아이들에게는 실행 프레임을 갖게 합니다. "여러분이 얼마나 그림을 잘 그리는지 보고자 하는 겁니다. 여러분의 창의성을 측정해 보려고 합니다. 점수를 매길 거에요. ..." 다른 그룹 아이들에게는 학습 프레임을 갖게 합니다. "내가 안 그려 보았던 방식들을 실험해 보는 시간이에요. 여러 가지 방식으로 실험해 보세요." ... 실행 프레임에서는 '잘하기'에 초점을 맞추게 하고, 학습 프레임에서는 '자라기'에 초점을 맞추게 합니다.

    여기에서 말하는 실행 프레임은 사람들이 현재 주어진 과업이 뭔가 좋은 성과를 내는 걸로 생각하는 틀을 말합니다. 학습 프레임은 현재 주어진 과업이 내가 얼마나 배우느냐로 여기게 되는 틀을 말합니다.

    현재 상황 자체가 어렵지 않냐. 업무하면서 학습이 중요하다는 생각을 갖기가 어렵지 않냐.

    지금 자신의 상황 '때문에' 학습 프레임을 갖는 것이 힘들다는 생각이 든다면, 이 우주 어딘가의 누구는 비슷한 상황 '덕분에' 학습 프레임을 가질 수 있었다고 생각하고 있다고 상상해 보면 어떨까요?

    가장 학습하기 힘든 직업이 살아남는다

    학습에 유리한 조건, 불리한 조건

    컴퓨터로 대체되기 힘든 일

    무엇에 집중할 것인가

    달인이 되는 비결

    동기가 부족하다

    피드백을 제때 받지 못한다

    수십 년 동안 전문가가 안 되는 비결

    전문성 형성에서 타당성과 피드백의 중요성

    타당성과 피드백을 높이기

    당신이 제자리걸음인 이유

    의도적 수련의 필수조건, 적절한 난이도

    실력이 늘지 않는 이유

    제자리걸음에서 벗어나기

    지루함을 느끼는 경우: a1 실력 낮추기

    지루함을 느끼는 경우: a2 난이도 높이기

    불안함을 느끼는 경우: b2 실력 높이기

    불안함을 느끼는 경우: b1 난이도 낮추기

    테트리스의 핵심은 살아있으면서도 간단한, 아기 버전의 테트리스를 만드는 것입니다.

    동적인 균형

    팀장이 할 수 있는 일

    이소룡의 자기 혁신

    의도적 수련의 일상적 예시

    실력 조정하기(a1, b2)

    난이도 조절하기(a2, b1)

    일반적으로 제가 새로운 기술을 코칭에 적용할 경우 이 난이도 조절을 적극적으로, 점진적으로 하는 것 같습니다.

    처음에는 현재 제 자신에게 적용해 홉니다. ... 그 다음에는 과거의 힘들거나 어려웠던 상황을 떠올려서 그 때의 자신을 코칭해 봅니다. ... 이게 되면 실제로 그 사람과 코칭을 해봅니다. 이 때에는 미리 언급을 합니다.

    프로그래밍 언어 배우기의 달인

    '인간' 역엔지니어링 방법을 사용하고, 또 가르치고 있습니다.

    S 님의 어떤 전문성을 끌어낼까 하다가 '프로그래밍 언어를 배우는 전문성'을 하기로 했습니다.

    튜토리얼을 읽을 때 뭘 만들지 생각하고 읽는다

    적극적 읽기

    첫 번째 목표로 주로 삼는 프로그램은 단어 개수 세기 프로그램이라고 합니다.

    공부할 때 표준 라이브러리 소스코드를 읽는다

    자연 언어 교육과는 다르게 프로그래밍 언어 교육에서는 읽기보다 쓰기를 더 강조하는 경향이 있습니다. 프로그래밍 언어를 가르칠 때 읽기를 교육하는 경우는 극히 드물죠. 하지만 프로그래머가 실제로 업무를 할 때에는 코드를 읽는 시간이 쓰는 시간을 압도합니다. 좋은 코드를 읽어봐야 좋은 코드를 쓸 수 있기도 하고요.

    S 님은 튜토리얼을 읽어 나가면서 틈틈이 해당 언어의 표준 라이브러리를 찾아 읽었습니다.

    Java로 작성된 프로그램이냐 C로 작성된 프로그램이냐를 가르는 진짜 기준은 어떤 언어의 키워드를 썼느냐가 아니라 어떤 스타일을 따르고 어떤 숙어를 사용했는가입니다.

    공부 중 다른 사람의 코드에 내가 필요한 기능을 추가한다

    전문성을 효과적으로 뽑아내는 전문가가 되기

    한 가지 비결은 전문가가 구체적인 사건에 대해 말하도록 유도하는 겁니다.

    S 님의 경우에는, 가장 최근에 익힌 언어가 Go라고 하더군요. 그 언어를 익힌 과정을 시간대별로 짚어가며 어떤 행동을 했는지, 그리고 암묵적인 의사결정과 상황판단이 무엇이었는지를 추출했습니다.

    실수는 예방하는 것이 아니라 관리하는 것이다

    미연에 실수를 막아야 한다?

    미국 산림청의 산불 정책이 수십년 전에 바뀐 것을 아십니까? 예전에는 산불 예방을 강조했습니다.

    이제는 불 예방에서 불 관리 쪽으로 초점이 바뀌었습니다.

    흥미로운 부분은 가장 사망률이 높은 병원과 가장 낮은 병원 집단 사이에 수술 후 합병증 발생 확률이 통계적으로 차이가 있었다는 점입니다. 그럼 무엇이 사망률의 차이를 만들었을까요? 합병증을 발견하고 적절한 조치를 취하는 부분에서 차이가 났습니다. ... 사망률이 낮은 병원은 심각한 합병증이 벌어지는 것을 잘 알아챘고, 또 합병증이 생긴 후 적절한 조치를 했던 것이죠.

    두 가지의 실수 문화

    실수 예방 문화에서는 실수를 한 사람을 비난하고, 처벌하고, 따라서 실수를 감추고 그에 대해 논의하기 꺼리며 문제가 생겼을 때 협력도 덜 하게 됩니다. 반대로 실수 관리 문화에서는 실수가 나쁜 결과를 내기 전에 빨리 회복하도록 돕고, 실수를 공개하고, 실수에 대해 서로 이야기하고 거기에서 배우는 분위기가 생깁니다.

    실수 연구의 역사를 보면, 초기에는 기술적인 부분만 보다가 그 다음에는 인간적인 부분을 보다가, 이제는 문화적인 부분을 이야기합니다.

    실수가 없으면 학습하지 못합니다. 이는 학습이론의 기본입니다.

    다양한 실수를 경험하는 걸 격려하고, 실수 사례를 배우고, 실수 시에 어떻게 대처하는가를 가르치는 교육이 더 효과적이라는 연구 결과가 많습니다.

    뛰어난 선생에 대한 미신

    흥미롭게도 많은 조직에서 교육은 투입으로 성과를 측정하는 대표적 분야입니다.

    기업에서의 교육, 훈련 효과에 대한 메타분석 연구에 따르면 대부분의 훈련은 6개월 정도만 지나도 효과가 거의 사라집니다.

    존 해티의 연구에 따르면 교사가 가진 주제에 대한 지식수준은 효과 크기가 0.09에 지나지 않으며 ... 교사가 지식이 얼마나 많은지는 큰 영향을 미치는 요소가 아니라는 말이지요.

    왜 그럴까요? ... 여기에서는 특히 '아는 것을 온전히 가르칠 수 있는가'하는 면에 초접을 맞춰보죠.

    전문가가 가르쳐주는 것은 전부가 아니다

    의료계의 연구를 보면, 전문가가 특정 수술법을 학생에게 가르칠 때, ... 70%는 가르치지 않는다는 분석이 거듭해 나왔습니다. 가르치는 능력을 인정받고 한 번 이상의 '탁월한 교사상'을 받은 사람임에도 그랬고, .. 그 기술을 성공적으로 해내기 위해 필요한 것의 30%만 가르쳐 놓고 자신은 다 가르쳤다고 생각하는 겁니다.

    이런 현상이 벌어지는 이유에는 ... 대표적인 것이 자동화입니다. 전문가가 되면 자신이 하는 일이 반복적으로 몸에 익고 자동화가 되어서 결국 암묵적이 되어 버립니다.

    인지적 작업 분석으로 극복하기

    이걸 극복하는 방법이 있을까요? 네. 있습니다. ... 한 가지 힌트를 드리자면, 앞에서 <프로그래밍 언어 배우기의 달인>의 인지적 작업 분석 같은 방법을 선생과 학생이 쓰는 겁니다. ... 메타분석에 따르면 선생이 인지적 작업 분석에 능숙한가 하는 것이 학생들의 학업성취도에 미치는 여향의 효과 크기가 자그만치 1.29나 됩니다. 이런 분석 능력이 뛰어난 선생이 잘 가르치는 사람이라는 이야기입니다.

    또 선생의 메타인지를 돕기 위해 자기가 어떻게 생각하면서 이 문제를 풀었는지 그 인지적 과정을 선생에게 알려주는 것도 매우 효과적입니다.

    나홀로 전문가에 대한 미신

    보통은 어떤 사람이 전문가라고 하면 그 사람의 뇌 안에서 무슨 일이 벌어질까에만 주목하는 면이 있습니다. '고독한 천재'같은 ... 이미지로 떠올리기도 하죠. 그런데 과연 현실에서의 전문가가 정말 그런 사람일까요?

    뭘 하든지 나 혼자가 아니라 항상 누군가가 등장하고, 일의 성패에 다른 사람이 관련되어 있기 때문입니다. 정리하면 다음과 같습니다.

    1) 아무리 기술적인 실천법이라고 해도 2) 그 기술은 사회적 맥락 속에서 실천되어야 하며 3) 그 기술의 성공을 위해서는 사회적 자본과 사회적 기술이 함께 필요하다.

    사회적 자본과 기술

    신뢰가 깨어져 있는 상태에서는 어떤 행동을 해도 악의적으로 보인다는 것입니다.

    이 신뢰를 사회적 자본의 일종이라고 합니다.

    고독한 전문가라는 미신

    전문가가 해당 도메인 지식만 뛰어난 사람이라는 것은 대표적인 미신입니다. 전문가는 사회적 자본과 사회적 기술 또한 뛰어납니다.

    이제는 프로그래밍을 잘한다는 정의 안에 의사소통 능력을 그 일부로 보게 된 겁니다.

    희망적인 소식은 이런 사회적 기술을 훈련으로 개선할 수 있다는 겁니다.

    간단한 방법은 주변 사람들과 주고받는 마이크로 인터랙션에 신경을 쓰는 겁니다. 그걸 기록하고, 복기하고, 다르게 인터랙션한다고 하면 어떻게 했으면 좋았을까를 생각해보는 것만으로도 훈련이 될 수 있습니다.

    저는 ... TDD를 사람들에게 교육하고 컨설팅해주었습니다. 제 경험에 한해서는 TDD 도입에 실패하는 경우, ... 필요한 사회적 자본과 사회적 기술이 없어서가 훨씬 더 많았습니다.

    어떤 기술적 지식을 전달한다고 해도 그것을 사회적 맥락 속에서 가르치고 경험하게 하려고 노력하고 있습니다.

    제가 중요하게 다루는 사회적 기술은 도움받기, 피드백 주고받기, 영향력 미치기, 가르치고 배우기, 위임하기 등이 있습니다.

    함께

    사람들은 협력이 중요하다고 합니다. 그래서 프로젝트를 할 때 협력적으로 하자고 합니다. 그러나 실제 모습을 들여다보면 초반에 일을 세밀하게 나누고 선을 긋습니다. 그리고 안녕이죠.

    우리는 협력을 제대로 배워본 적이 거의 업시 때문입니다.

    그래서 지금부터라도 협력 방법을 배우고 수련해야 합니다.

    소프트웨어 관리자의 개선 우선순위

    조엘 테스트라는 것이 있습니다.

    그러나 여기에 가장 큰 위험이 존재합니다. 선의의 관리자나 경영진이 각 질문의 맥락을 이해하지 못한 채 단순히 12가지 질문에 예라고 답하는 것을 목표로 노력하는 경우를 말하는 겁니다.

    모든 항목에 "예"라고 답하는 것이 무조건 더 낫다고 동의하기 어렵다

    제가 아는 뛰어난 팀들은 툴을 고를 때 단순히 비싼 게 뭐냐를 기준으로 고르지 않습니다. 이 항목을 보고 '비싼 툴을 쓰면 잘하겠지'하고 생각하는 건 기술을 이해하지 못하는 경영자 마인드에 가깝습니다.

    12가지 질문이 개발팀 평가에서 정말 중요한 요소인가?

    품질 전문가 제럴드 와인버그가 한 말을 살펴봅시다. 이분은 소프트웨어 개발을 잘 관리하려면 세 가지 근본적 능력이 필요하다고 했습니다.

    1. 복잡한 상황을 이해하는 능력으로, 프로젝트를 계획한 다음 관찰하고 행동하여 계획에 맞게 프로젝트가 진행되게 하거나 계획을 바꿀 수 있어야 한다.
    2. 관찰하는 능력으로, 무엇이 벌어지고 있는지를 관찰하고, 효과적인 적응 행동을 하기 위해 자신이 관찰한 것이 어떤 의미인지 이해할 수 있어야 한다.
    3. 행동하는 능력으로, 어려운 대인 상황에서 우리가 심지어 혼란스럽거나 화가 나 거나 아니면 무서워서 도망쳐 숨어버리고 싶을 때에도 적절하게 행동할 수 있어야 한다.

    이 세 가지 능력을 활용해 실제 조직과 개인(관리자 자신을 포함-와인버그는 자신을 바꾸지 못하는 사람은 다른 사람을 바꾸는 일도 할 수 없다고 합니다)

    QSM 4권에 소프트웨어 개발 비용에 대한 내용이 있습니다. 다음 네 가지 요소의 분류에서 가장 중요한 것부터 나열해 보세요.

    • 도구 : 소프트웨어 개발에 사용하는 모든 종류의 도구. 컴퓨터, 모니터, 디버거, IDE
    • 사람 : 사람들의 능력과 경험
    • 시스템 : 제품 자체의 복잡도, 요구되는 신뢰성, DB 크기, 타깃(VM 등)의 변화 가능성, 스케줄 제약 등
    • 관리 : 사람을 배정하고 작업 분배를 조정하고 위임하는 것, 작업 모니터링, 동기를 고취하는 것, 작업 조건/환경을 개선하는 것, 자원의 준비, 리스크를 일찍 확인하고 적절한 조치를 취하는 것, 요구사항과 설계 스펙이 비준(validate)되게 돕는 것 등

    비슷한 크기의 소프트웨어를 개발한다고 할 때, 각 분류별로 비용 면에서 가장 적게 드는 회사부터 그렇지 않은 회사까지 100등까지 순위를 매깁니다. 85등이던 회사가 10등하는 회사로 '개선'을 했다면 개발 비용이 얼마나 줄어들까요? 개선효과가 높은 것은 무엇일까요?

    ...

    관리, 시스템, 사람, 도구 순서였습니다. ... 하지만 각 분류별로 실제로 개선 시도가 얼마나 있었는지 확인해 보니 가장 많은 개선 노력이 있었던 분류를 바로 '도구'였습니다

    다시 조엘 테스트로 돌아갑시다. 조엘 테스트는 가장 만만하고 쉬운 것부터 시작하는 관리자의 성향과 충돌하지 않습니다.

    저는 관리자가 눈에 잘 보이고 갈아치우기 쉬운 '도구'들에 신경을 쓰는 것이 위험하다고 생각합니다.

    협력을 통한 추상화

    커뮤니케이션과 협력

    일반적으로, 실력이 뛰어난 프로그래머는 보통 정도의 실력을 가진 프로그래머에 비해 커뮤니케이션, 협력 능력이 더 뛰어납니다.

    백지장도 맞들면 찢어진다?

    톱니바퀴 실험

    둘이서 함께 작업한 경우 58%나 추상화 규칙을 찾아냈습니다. 4배가 넘습니다. 만약 두 사람이 한 팀으로 작업하되 서로 이너랙션하지 않았고, 그들의 결과물 중 더 나은 것을 택하는 방식(명목 집단(nominal group)이라고 함)이라면? 이 경우는 확률적으로 계산할 수 있는데, 26%가 됩니다.

    그러면서 맞은편의 사람과 이야기를 하는데, ... 이런 혼동을 해결하기 위해 추상적 개념을 도입합니다. 예컨대 바퀴에 식별 번호를 붙인다든지 하는 것이지요.

    둘이서 협력하면서 작업하면 서로 시각이 다르기 때문에 두 사람의 다른 시각을 연결해 줄 다리가 필요하고, 그 다리에는 필연적으로 추상화의 요소가 있게 됩니다. 서로 다른 것들을 하나로 묶어야 하기 때문입니다.

    추상화의 중요성

    만약 코드가 비지니스 로직이 들어가고 그 로직이 domain-rich 하다면 되도록 가독성을 추구하겠지만, 저는 때로 가독성을 손해보면서까지 중복을 줄이기도 합니다. ... 흥미로운 객체들을 발견합니다. ... 내가 전에 모르던 것을 배우게 됩니다.

    '흥미로운 무엇'이 바로 추상화입니다.

    인용문 대로 소프트웨어 공학의 역사는 정말 추상화를 높이기 위한 여정이었습니다. ... 그런데 우리는 조금 전 추상화를 높일 수 있는 방법을 하나 찾아냈습니다.

    대화하는 프로그래밍

    익스트림 프로그래머는 작업하면서 프로그래밍 각 단계에 대해 함께 이야기한다.

    자신이 작성하는 코드의 추상성을 높이고 싶다면 혼자서 고민하지 말고 다른 사람들과 협동하고, 대화하세요. 같이 그림도 그려보고 함께 소스코드를 편집하세요. 인간에게는 다른 인간과 소통하고 협력할 수 있는 놀라운 능력이 있습니다. 대화는 기적입니다.

    신뢰를 깎는 공유인가 신뢰를 쌓는 공유인가

    공유 조건별 신뢰도 변화 실험

    조금 충격적인 이야기를 해드리겠습니다. 두 경우 모두 공유 후에 신뢰감이 더 떨어졌습니다. 특히 첫 번째, 즉 디자인 하나만 작업하고 그걸 공유한 경우가 더 많이 떨어졌습니다만, 두 조건 모두 신뢰감이 통계적으로 유의미하게 떨어졌습니다. 공유를 해서 신뢰가 더 떨어지는 상황이 벌어진 것이죠.

    각자 여러 개의 디자인을 만들고 그걸 모두 공유한 경우였습니다. 이때는 신뢰가 유의미하게 증가했습니다.

    하나 공유나 최고 공유의 경우 우리는 공유 자리에 기대감보다 불안감을 갖고 갈 겁니다.

    복수 공유의 장점

    복수 공유는 그런 불안감이 상대적으로 덜합니다. 여러 개를 준비했으니 그중 하나를 두고 뭐라고 해도 나에 대한 공격은 아닌 겁니다.

    마지막으로 가장 놀라운 부분 ... 클릭률이 더 높았습니다. 복수 공유는 (같은 시간을 투자했을 때) 신뢰도 높아지고 성과도 더 좋았다는 말입니다.

    여러분의 공유는 어떻습니까? 신뢰를 깎아먹는 공유를 하고 계신가요, 신뢰를 쌓아가는 공유를 하고 계신가요?

    객관성의 주관성

    새로운 개념을 주변에 설득하기 위해 노력하는 분들을 많이 봅니다.

    그런 분들을 만나면 저는 다음과 같은 질문을 던집니다. "상대방에 대해 얼마나 이해를 하고 계신가요? 얼마나 대화를 해보셨나요?"

    강사는 자신이 좋은 예를 들었다고 생각합니다. 하지만 질문자는 그렇게 생각하지 않습니다. '예'의 정이가 주관적이라 벌어진 일이죠.

    품질은 상대적이다

    품질 전문가 제럴드 와인버그는 품질을 다음과 같이 정의합니다.

    품질이란 누군가에게 가치가 되는 것이다.

    우리가 일반적으로 듣는 품질의 정이와 다르죠? ... 그런 정의들은 매우 플라톤적입니다. 뭔가 고상하고 완벽한 품질이라는 것이 하늘 어딘가에 있는 것처럼 들립니다. 하지만 와인버그의 정의는 상대주의적이며 동시에 무척 실용적입니다.

    우리가 품질을 이야기할 때에는 '누구'를 놓고 하는 말이냐는 걸 생각해 봐야 한다 이겁니다.

    결국 결정하는 것은 사람입니다.

    감정을 배제할 수 없다

    그리고 논리랑 감정적 판단을 분리할 수가 없습니다.

    의사결정을 하는 과정에 감정적이고 직관적인 부분이 큰 역할을 하고 있으며, 그런 감정적 부분이 배제된다면 의사결정을 제대로 할 수 없다는 것을 알 수 있습니다.

    남을 설득하려면 논리성과 객관성에 대한 환상을 버려야 합니다. 그래야 현실적으로 설득이 가능합니다. 내가 설득하고 싶은 상대를 자주 만나서 신뢰를 쌓고, 그 사람이 무엇을 중요하게 여기는지, 어떤 설명 방식을 선호하는지 이해해야 합니다.

    성향과 기질에 따른 애자일 설명법

    결론은, 객관성이라고 하는 것은 상대적이며, 내가 생각하는 객관이 상대의 객관이 아닐 수 있고, 그렇기 때문에 설득에 성공하려면 우선 그 사람을 이해하는 것에서 출발해야 한다는 말입니다.

    이것도 모르세요?

    공감하고 이해하려는 대화

    이런 과정을 거치면 홍춘이의 머릿속에는 어떤 그림이 떠오를까요? ... 술퍼맨의 머릿속 지도와 사고 흐름을 엿보게 되는 것이죠.

    그 사람이 이 상황에서 왜 이런 접근을 할 수밖에 없었는지 알기 때문에 좀 더 정확하고 효과적인 제안을 해줄 수 있습니다. ... 또, 소위 암묵지라고 부르는 것들을 전달해줄 수도 있습니다.

    행동을 유도하는 대화

    술퍼맨 : 네, 그러고 싶어요. 그런데 언젠가 한번 마음먹고 제대로 공부해야지, 해야지 하고 생각하면서 몇 달째 미루고 있는 것 같아요.

    홍춘이 : 정규식을 배워서 해보고 싶은 것들이 있나봐요. ...

    참고로 코칭의 흥미로운 점은 코치 자신(홍춘이)이 해당 영역(정규식)에 대한 전문지식이 없어도 코칭을 할 수 있다는 점입니다.

    하향식 접근의 함정

    대부분의 기업에서 직원 숫자가 늘어나기 시작하면 추상 층위에 따라 팀을 나눕니다. 각 층위의 전문가 팀이 존재합니다. 기획팀, 구현팀, QA팀 등, 그리고 일이 진행됨에 따라 팀 간의 바통 터치가 이루어집니다. 위에서 아래 방향으로요.

    그럼 모든 문제를 탑다운 식으로 푸는 것이 우리의 지향점일까요? 인공지능 연구에선 이 세상의 문제를 두 종류로 나눕니다. 잘 정의된 문제와 잘 정의되지 않은 문제 ... 오목이나 체스 ... 여기에 속합니다.

    하지만 우리가 실생활에서 만나는 대다순의 문제는 잘 정의되지 않은 문제입니다.

    앞서의 전문가들은 ... 잘 정의되지 않은 문제를 접하면 접근법을 바꿉니다. 탑다운과 바텀업을 섞어 씁니다. 뛰어난 전문가일수록 더욱 그러합니다.

    특히 탑다운과 바텀업의 방향이 전환되는 시점들에서 '아하 순간'이 찾아왔습니다.

    "이번 일은 복잡하고 불확실하니까 철저하게 계획하고 단계적으로 접근하자!" 이 말은 곧, 이번 일은 불확실하니까 초보처럼 일하자는 말과 똑같습니다.

    오히려 전문가일수록 자신의 계획을 수정한 횟수가 많았습니다.

    연구에 따르면, 프로그램을 이해할 때 고수는 상호 참조 전략을 쓰는 반면 하수는 그렇지 않았습니다.

    고수는 ... 프로그램에서 이해한 것을 도메인 어휘로 번역합니다. 그러고는 도메인 어휘를 프로그램상의 어휘로 다시 바꿔서 검증합니다. 이를 상호 참조 전략이라고 합니다.

    빠르고 빈번한 바통 터치가 가능한 전문가 조직

    삼투압적 의사소통

    사람들이 물리적으로 가까운 거리에 있어야 유리하겠죠.

    그리고 한번에 처리되는 일의 양(batch size)을 줄여야 합니다. 배치 사이즈를 줄여서 지속적 흐름을 만들고 짧은 시간 내에 탑, 바텀을 오가게 합니다. 예를 들어 전에는 디자이너가 100개의 일자리를 다 처리한 후에 한꺼번에 모아 결과를 전달했다면 점차 50개로, 10개로, 1개로 낮추어야 합니다.

    어느 한 단계를 한번에 완료하는 것은 더 낮은 품질로 가는 지름길입니다.

    흔히들 말하는 개발의 5단계도 비슷합니다. ... 어떻게 해야 첫 달부터, 아니 첫 주부터 분석, 설계, 구현, 테스트, 전개를 모두 왔다갔다할 수 있을까를 고민해야 할 것입니다.

    전문가 팀이 실패하는 이유

    회사에서의 올스타는 어떨까요? ... 스타들이 한 명씩 팀에 추가될 떄마다 팀의 추가적 성과 향상은 한계효용을 보이며 어느 수준을 지나면 음의 방향으로 작용한다고 합니다.

    전문가가 추가되는게 도움이 안 되거나 오히려 성과를 깎아먹는 경향은 특히나 전문가들의 전문성이 서로 유사할 떄 도드라졌습니다.

    자기들이 알아서 하게 놔둔 전문가팀은 비전문가로만 구성된 팀보다도 훨씬 못한 결과가 나왔습니다.

    팀 내에 개인 내 다양성이 높은 멤버가 없다면 전문가로 구성된 팀은 정보 공유가 잘 안 되어서 성과가 떨어질 수 있다는 분석을 했습니다.

    구글이 밝힌 탁월한 팀의 비밀

    제가 봤을 떄 중요한 부분은 세 군데입니다.

    1. 팀에 누가 있는지(전문가, 내향/외향, 지능 등)보다 팀원들이 서로 어떻게 상호작용하고 자신의 일을 어떻게 바라보는지가 훨씬 중요했다.

    2. 5가지 성공적 팀의 특징을 찾았는데, 그중 압도적으로 높은 예측력을 보인 변수는 팀의 심리적 안전감이었다.

    3. 팀 토론 등 특별히 고안된 활동을 통해 심리적 안전감을 개선할 수 있었다.

    여기에서 말하는 심리적 안전감이란, 내 생각이나 의견, 질문, 걱정, 혹은 실수가 드러났을 때 처벌받거나 놀림받지 않을 거라는 믿음을 말합니다.

    에드몬드슨은 이런 도구를 사용해 병원의 중환자실의 심리적 안전감을 측정해 보았습니다. ... 예상과 비슷하게, 직위에 따라 느끼는 심리적 안전감에 통계적으로 유의미한 차이가 있었습니다.

    심리적 안전감이 높은 병실에서는 ... 18%나 낮은 사망률을 보였습니다.

    팀원이 불편한 문제를 제기하거나, 어리석어 보이는 질문을 하거나, 부족한 의견을 얘기하거나, 어처구니없는 실수를 저지를 때 여러분은 어떤 마이크로 인터랙션을 보여주고 계신가요?

    쾌속 학습팀

    최소 침습 심장 수술

    논문 제목은 <팀 학습의 속도 높이기>입니다. 최소 침습 심장 수술법을 어떤 팀이 빨리 익히는가 하는 것이 주제입니다.

    하지만 놀라운 점은 수술 시간 감소율이 팀마다 천차만별이었다는 겁입니다.

    학습 속도와 상관없는 것

    리더가 팀 학습 속도에 미치는 영향

    단순히 기술적 탁월함만을 갖춘 사람보다는 학습 환경을 만들 수 있는 리더가 필요하다는 것입니다.

    학습 환경의 차이

    선발 자체가 매우 협동적

    속도가 빠른 팀은 새로운 수술 도입을 기술적 도전이라기보다 조직적 도전으로 받아들였습니다. 개개인이 새로운 기술을 획득해야 한다고 보지 않고, 함께 일하는 새로운 방법을 만들어야 한다고 생각했습니다.

    마지막으로, 속도가 빠른 팀은 심리적으로 보호가 되고 있었습니다.

    기술 전환에 성공한 개발팀

    속도가 빠른 팀은 도전 자체를 팀의 학습 능력에 대한 도전으로 받아들였고, 같이 학습해야 한다고 생각했습니다.

    속도가 느리거나 낙오된 팀은 학습을 개인의 과제로 치부했습니다. 학습보다는 단기 퍼포먼스를 중요시했습니다.

    현실에서 실천하기

    다시 현실에서 돌아와서, 나는 팀장도 아니고, 정치적인 힘도 없습니다. 그렇다면 이 상황에서 내가 무엇을 할 수 있을까요? 팀원과 팀장에게 이 책을 권할 수 있는 분위기도 아니라면?

    우선 자신의 학습 환경을 만드세요. 거기서부터가 출발입니다. 개별 기술 이상으로 일하는 방식에 대해 실험을 해 보세요.

    프로젝트 확률론

    이번 프로젝트는 제떄에 끝낼 수 있을 것 같았는데

    소프트웨어 공학 쪽의 연구에 따르면 사람들이 통상적으로 추정하는 소요시간에 적어도 2~3배를 해야 80% 정도의 확률로 마칠 수 있는 시간이 나온다고 합니다.

    게다가 일반적으로 일의 소요 시간을 추정할 때 사람들이 낙관적으로 추정한다는 편향에 대한 연구 결과가 많다는 점까지 고려하면 상황은 더 심각해집니다.

    또 다른 연구에 따르면, 사람들에게 가장 그럴싸한 추정(best guess)을 부탁했을 때와 자신이 기대하는 최선의 상황(best case scenario)을 상상해서 추정해보라고 부탁했을 때 그 추정치는 큰 차이가 없었습니다.

    애자일 확률론

    제가 선호하는 접근법은 관리자가 12명 모두에게 단지 3가지 일만 주고 서로 협동해서 그 일을 하도록 요청하는 것입니다.

    이 방식이 잘 돌아가는 이유는 사람들이 '관심사의 섞임'을 통해 서로에 대해 엄청나게 많은 것을 매우 빨리 배울 수 있기 때문입니다.

    애자일은 앞서의 고전적 방법과 달리 일을 공유합니다. 각자 일을 얼마나 진행했는지 매일 공유할 뿐 아니라 내 일, 네 일의 구분선이 뚜렷하지 않습니다. 애자일에서는 되도록 사람들이 섞이도록 합니다.

    애자일은 마치 프랙털 구조처럼 부분 속에 전체가 들어가게 합니다. 그렇게 하면 과거에서 미래를 접쳐 보기가 훨씬 쉽습니다. 일이 진행될수록 점점 추정 정확도가 높아집니다.

    한 사람만이라도 중요한 통찰이 있었다면 이걸 공유해서 '또는' 확률로 만들고, 버그 같이 나쁜 일에 대해서는 여러 사람이 중복 검토를 해서 모두가 실수해야지만 구멍이 나게 '그리고' 확률로 바꾸는 것입니다.

    애자일

    당시 주도적인 소프트웨어 개발 방식은 계획주도의 방식이었습니다. 계획주도 방식에서는 초반에 계획을 정교하고 꼼꼼하게 만들려고 엄청난 노력을 합니다. 그러면 실행단계는 간단해지고 예측 가능해진다고 생각하기 때문입니다. 하지만 애자일은, 불확실성이 높은 일에 대해서는 애초에 이것이 불가능하다고 봅니다. 불확실성 크기 때문에 미리 분석하고 설계하는 데 한계가 있다는 것이지요.

    이번에는 과의의 애자일을 얘기해 보겠습니다. 애자일을 단순히 소프트웨어 개발 방법론이라는 울타리에 가두어 보지 않고, 일하는 한 가지 스타일, 혹은 더 넘어서서 삶을 사는 방식으로까지 확장해 보는 것이지요.

    학습과 협력은 불확실성이 큰 상황에서 좋은 대응전략이 됩니다. 우리의 삶도 불확실하기 때문에 학습과 협력은 현명한 전략이 될 것이고요.

    애자일의 씨앗

    씨앗이 될만한 것을 줘야합니다.

    고객에게 매일 가치를 전하라.

    애자일 도입 성공 요인 분석

    두려워도 중요하다면 시도해봐야 하지 않겠는가

    당신의 조직에 새 방법론이 먹히지 않는 이유

    결과들을 보면 상담에서 어떤 기법을 쓰느냐보다 치료자가 누구인가가 상담 효과에 더 큰 영향을 준다는 게 거듭 밝혀졌습니다.

    매뉴얼이 말하고 있는 것보다 훨씬 더 많은 것을 상담사들이 할 수 있다는 말이 될 것입니다.

    사실 더 나아가서 모든 지식이 근본적으로는 암묵지라고 역설했습니다.

    맥락을 가로지르는 보편적 규칙들이 별로 없다고 생각이 든다면, 결과를 에측하기 어렵고 불확실성이 높다면, 해당 분야는 '복잡한 도메인'이 됩니다. 상담이 그렇죠. 이런 복잡한 분야일수록 어떤 특정 기법의 효과보다도 치료자 효과가 더 큰 영향을 미칠 것입니다.

    내가 어떤 팀장인지가 전혀 바뀌지 않으면서 새 방법론만 도입한다고 무슨 효과가 있을까요.

    애자일을 애자일스럽게 도입하기

    칸반 같은 개별 실천법은 상시 변화하고 발전하는 도요타의 특정 시점의 스냅샷 같은 것이 아닐까 생각합니다. 우리가 배워야 할 것은 칸반 이면의, 칸반이 나올 수 있었던 구조의 문화입니다.

    "... 애자일을 도입할 때 확실성 위에서 진행하려고 한다면 문제가 된다"

    이것은 거의 모든 종류의 방법론 도입에 적용됩니다. 왜냐하면 방법론 도입은 태생적으로 불확실성이 높기 때문입니다. ... 수순을 따르는 것이 아니라 곁에 있는 사람들과 함께 주변을 탐색하고 조금 나아가고 확인하고를 반복하면서 우리의 현 맥락에 맞는 좋은 전략들을 스스로 만들어 나가는 것이 아닐까 합니다

    + \ No newline at end of file diff --git a/vim.html b/vim.html index fc23e83b..beb75422 100644 --- a/vim.html +++ b/vim.html @@ -20,12 +20,12 @@ -
    Skip to content
    On this page

    📟 Vim

    alt
    출처 : VIM! No EXIT !! :D :D

    링크

    Use Cases

    Changing case

    • ~ : case 변경 후 오른쪽으로 커서 이동
    • {Visual}~: highlighted text case 변경
    • {Visual}U : highlighted text uppercase로 변경
    • {Visual}u : highlighted text lowercase로 변경

    참고

    Indentation

    • {Visual}[count]> : 현재 line count 수 만큼 오른쪽으로 indent (shiftwidth)
    • >% : curly-braces block 오른쪽으로 indent
    • >iB : block을 오른쪽으로 indent

    참고

    Substitution

    :[range]substitution/from/to/[flags]

    • :%s/from/to/[flags] : 전체 파일을 탐색하면서 substitution을 수행. %는 전체 문자열을 의미, s`는 substitution을 의미
    • :.s/from/to/[flags] : 현재라인에서 substitution을 수행
    • :.,$s/from/to/[flags] : 현재라인부터 파일의 끝까지 탐색하면서 substitution을 수행

    참고

    Writing and Quiting

    :x : Like ":wq", but write only when changes have been made.

    ZZ : Write current file, if modified, and close the current window (same as ":x").

    참고

    simple-change

    v_g_CTRL-X({Visual}g CTRL-X) : Subtract [count] from the number or alphabetic character in the highlighted text. If several lines are highlighted, each value will be decremented by an additional [count] (so effectively creating a [count] decrementing sequence).

    참고

    원하는 열로 이동

    N|: N번째 열로 이동

    • 80A=<ESC>d80|: =를 80번 반복 입력한 후 80번째 열까지 삭제

    참고

    Open command in editor in zsh (Ctrl + x + e 대체)

    bash
    # .zshrc 마지막에 추가
    +    
    Skip to content
    On this page

    📟 Vim

    alt
    출처 : VIM! No EXIT !! :D :D

    링크

    Use Cases

    Changing case

    • ~ : case 변경 후 오른쪽으로 커서 이동
    • {Visual}~: highlighted text case 변경
    • {Visual}U : highlighted text uppercase로 변경
    • {Visual}u : highlighted text lowercase로 변경

    참고

    Indentation

    • {Visual}[count]> : 현재 line count 수 만큼 오른쪽으로 indent (shiftwidth)
    • >% : curly-braces block 오른쪽으로 indent
    • >iB : block을 오른쪽으로 indent

    참고

    Substitution

    :[range]substitution/from/to/[flags]

    • :%s/from/to/[flags] : 전체 파일을 탐색하면서 substitution을 수행. %는 전체 문자열을 의미, s`는 substitution을 의미
    • :.s/from/to/[flags] : 현재라인에서 substitution을 수행
    • :.,$s/from/to/[flags] : 현재라인부터 파일의 끝까지 탐색하면서 substitution을 수행

    참고

    Writing and Quiting

    :x : Like ":wq", but write only when changes have been made.

    ZZ : Write current file, if modified, and close the current window (same as ":x").

    참고

    simple-change

    v_g_CTRL-X({Visual}g CTRL-X) : Subtract [count] from the number or alphabetic character in the highlighted text. If several lines are highlighted, each value will be decremented by an additional [count] (so effectively creating a [count] decrementing sequence).

    참고

    원하는 열로 이동

    N|: N번째 열로 이동

    • 80A=<ESC>d80|: =를 80번 반복 입력한 후 80번째 열까지 삭제

    참고

    Open command in editor in zsh (Ctrl + x + e 대체)

    bash
    # .zshrc 마지막에 추가
     autoload edit-command-line
     zle -N edit-command-line
     bindkey -M vicmd v edit-command-line

    v

    • bash vi mode에서는 v를 입력하면 editor에서 command를 입력할 수 있도록 창이 열린다. 같은 keybind를 해주는 듯

    참고

    debt

    - + \ No newline at end of file