ElleMeDit

@ellemedit@hackers.pub · 11 following · 15 followers

초기 스타트업에는 별도의 플랫폼 엔지니어링 팀이 필요하지 않을 수 있다. 작은 규모의 조직에서는 애플리케이션 엔지니어들이 플랫폼 엔지니어링 업무를 겸하곤 한다. 공유 코드의 문제점이 증가해 자발적인 기여로 감당하기 어려울 정도가 되면 플랫폼 엔지니어링 팀을 구성할 때다. 최초의 플랫폼 엔지니어링 팀은 다른 엔지니어링 조직과 강한 연결을 유지해야 하며, 과도한 수준의 플랫폼을 구축하지 않도록 주의해야 한다.

이 문제 자체보다 '지나친 시스템 중심 접근', '과도한 개발 중심 접근' 같은 문제가 팀에 해를 입힌다는 것을 모두가 동일한 수준으로 이해하는게 더 어려운 문제처럼 느껴진다. 원글에 "리더십은 권위에 호소하며 표준을 규정해버리곤 한다." 라는 서술이 있는데, 리더십은 실무와 멀어지면서 정말로 팀에 필요한 관심사와 전혀 다른 문제를 고민하는걸 보아왔다.

개인으로서는 리더를 조금씩 해킹하는 것 이외엔 수단이 안보이는데, 이런 짓을 하다보면 현타가 온다. 성실히 임하면 문제를 해결하기 위한 자원을 기대하지 않는 곳에 사용하거나, 같이 일한 동료들을 인정하는 대신 본인의 노고와 보상을 높게 치면서 다른 동료들이 힘들어하고, 코드베이스와 협업문화에 관찰하기 힘든 레버리지들이 쌓이는게 눈에 보이기 때문이다.

보통은 이런 인식자체를 못할 뿐더러, 이런 주장을 인정하려고도 하지 않는다. 단기적으로 본인에게 득이 되는 것 보다 잃는게 많고 현재에 너무 만족스럽거나 고된 스트레스에 시달리기 때문이다. 이런걸 무시할 수 있는 사람은 싸이코패스 내지는 책임 선긋기의 달인 정도이기 때문에, 나한테 신뢰할 수 있는 리더라는 존재는 유니콘에 좀 더 가깝다.

문제를 해결하는 리더란 존재를 만나보고 싶다.

5
1

여성향 커미션 중개 플랫폼 크레페를 운영하는 쿠키플레이스에서 시니어 백엔드 엔지니어 채용을 진행중입니다. 채용공고에 해당 직무 소개, 복지, 연봉, 회사문화의 내용이 포함돼 있습니다. 많은 관심 부탁드립니다. Node.js, TypeScript, GraphQL에 대한 높은 숙련도 및 지식으로 팀에 기여해주실 분을 쿠키플레이스에서 극진히 기대하고 있습니다.

크레페에서는 이런 기술스택을 사용합니다

  • Node.js, TypeScript, Vitest, Fastify
  • GraphQL  - Yoga, Relay, Pothos, Prisma
  • ElasticSearch, MongoDB, FCM
  • Docker, Github Actions
  • AWS  - ElasticBeanstalk, CloudWatch, Aurora PostgreSQL, Lambda, SES, S3, ElastiCache (Redis)
  • Grafana, Sentry

구성원의 성장과 덕질을 지원해요

  • 희망 도서 구매 (만화책 및 TRPG 룰북 포함)
  • 워크샵 및 교육 프로그램 지원
  • 전시, 공연 및 각종 행사 티켓 지원
  • 월 5만 크레페 포인트
  • 전동작탁 AMOS JP-EX COLOR
  • 6인용 TRPG/보드게임 테이블

지원자님이 예상하실 수 있는 처우는 이래요

  • 연봉: 최소 8000만원 ~ 최대 2억원 (주 40시간)
  • 스톡옵션 부여에 열려있는 포지션
크레페, 나만의 레시피, 나만의 창작물
10
1
0
3

js 커뮤니티는 환경변수 주입 정도는 컴파일타임 의존성 주입처럼 생각하긴 하는듯. 과거에 subpath import, export 없을 때 많이 쓰이던 방식이 고착화된게 아닌가 하는 뇌피셜이 있음..

4

Node.js 개발자라면 꼭 읽어봤으면 하는 아티클 2선

일반적인 Node.js 애플리케이션을 개발할 때 프레임워크와 무관하게 함께 일하는 동료들에게 필수적으로 추천하고 싶은 아티클이 있다.

빠르고 유지보수 가능한 데이터베이스 패턴들

https://sophiebits.com/2020/01/01/fast-maintainable-db-patterns

특정 프레임워크나 ORM에 의존하지 않고도 N+1 Query, 캐싱 같은 일반적인 문제를 해결하며 유지보수 가능한 형태로 코딩하는 방법을 제시한다. DataLoader로 모든 문제가 해결된다고 생각할 수도 있지만, 근본적인 문제 해결 과정을 직접 고민해보는 것만으로도 엔지니어링 역량 향상에 큰 도움이 된다.

Next.js에서 보안을 고려하는 방법

https://nextjs.org/blog/security-nextjs-server-components-actions

React 관련 내용이 포함되어 있지만, 그 부분을 제외하고 읽어도 충분히 가치가 있다. 데이터를 클라이언트에 전달할 때 마스킹하거나 접근 권한을 검사하는 방법을 구체적으로 알려준다. 핵심은 별도의 플러그인이나 외부 시스템 없이도 간단하면서 효과적인 권한 검사 시스템을 구축할 수 있다는 점이다.

마무리

위 아티클들을 추천하는 이유는 간단하다. 특정 프레임워크에 결속되지 않으면서도 독립적이고 지역적으로 백엔드 애플리케이션에서 볼 수 있는 일반적인 문제를 해결할 수 있는 방법들을 제시하기 때문이다. 이런 접근법은 전체 코드베이스의 안전성과 성능을 크게 향상시키며, 결국 더 많은 개발자들이 행복하게 일할 수 있는 환경을 만들어준다고 생각한다.

대부분 프레임워크에 의존적이거나 플러그인에 의존해 전체 코드베이스를 올바르게 수정하기 어려워지는 모습을 여러번 보았다. 개인적으로 엔지니어링 문화에서 크게 해결하고 싶은 부분이다. JavaScript 뿐만 아니라 가능하면 언어나 런타임에 있는 근원적 요소만을 통해 문제를 해결하는게 건강하게 문제를 해결할 수 있는 방법이라고 본다.

6

"AI가 아이디어를 너무나 쉽게 구체화할 수 있기 때문에, 아무리 발전된 아이디어라도 내 생각을 공유하고 싶은 마음이 덜 든다." 이거 나만 못하는 건가? 암만해도 원하는 수준대로 만들기가 너무 어려운데 확실히 연습해야 되나 싶다.

1

Next.js 서버 액션은 서버 데이터를 가져오는 용도로 사용하기에 적합하지 않다. React 공식문서에서는 다음과 같이 말하고 있다.

Server Functions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Functions typically process one action at a time and do not have a way to cache the return value.

서버 액션이 여러 호출되면 바로 실행되는 대신 큐에 쌓이고 순차적으로 처리된다. 이미 실행된 서버 액션은 이후 취소할 수 없다.

이에 서버 액션을 데이터 가져오기로 활용하면 끔찍해지는 UX가 생길 수 있는데, 예를 들어 페이지의 목록 검색 화면에서 검색 후 데이터를 가져오는 상황에 않았다고 다른 화면으로 네비게이션이 불가능한 것은 일반적인 경험이 아니다.

이러면 RSC를 통해 무한 스크롤을 구현하지 못하는가? 에 대해서 의문이 생길 수 있는데 여기에 대해서 대안을 발견했다.

function ServerComponent({ searchParams }) {
  const page = parseInt((await searchParams).page ?? "1", 10)
  const items = await getItems(page)
  return (
    <Collection id={page}>
      {items.map(item => <InfiniteListItem key={item.id} {...items} />)}
    </Collection>
  )
}
"use client"

function Collection({ id, children }) {
  const [collection, setCollection] = useState(new Map([[id, children]]))
  const [lastId, setLastId] = useState(id)
  if (id !== lastId) {
    setCollection(oldCollection => {
      const newCollection = new Map(oldCollection)
      newCollection.set(id, children)
      return newCollection
    })
    setLastId(id)
  }
  return Array
    .from(collection.entries())
    .map(
      ([id, children]) => <Fragment key={id}>{children}</Fragment>
    )
}

대충 이런 꼴이다. 이러고 page를 증가시키거나 감소시키는건 intesection observer나 특정 엘리먼트의 onClick 이벤트 따위를 의존하면 된다. 이러면 데이터 가져오기 패턴을 RSC 형태로 의존할 수 있다. InfiniteListItem는 서버컴포넌트, 클라이언트컴포넌트 무엇으로 구현하더라도 상관없다. 가령 아래와 같은 식:

function ServerComponent({ searchParams }) {
  const page = parseInt((await searchParams).page ?? "1", 10)
  const { items, hasNext } = await getItems(page)
  return (
    <div>
      <Collection id={page}>
        {items.map(item => <InfiniteListItem key={item.id} {...items} />)}
      </Collection>
      {hasNext && (
        <IntersectionObserver nextUrl={`/?page=${page + 1}`} />
      )}
    </div>
  )
}

검색 조건이나 검색어에 따라 상태를 초기화시키려면 다음과 같이 표현하면 된다.

function ServerComponent({ searchParams }) {
  const page = parseInt((await searchParams).page ?? "1", 10)
  const query = parseInt((await searchParams).query ?? "")
  const { items, hasNext } = await getItems(page, query)
  return (
    <div>
      <Form action="/">
        <input name="query" />
        <button />
      </Form>
      <Collection id={page} key={query}>
        {items.map(item => <InfiniteListItem key={item.id} {...items} />)}
      </Collection>
      {hasNext && (
        <IntersectionObserver nextUrl={`/?page=${page + 1}&query=${query}`} />
      )}
    </div>
  )
}

매우 PHP스럽고, 암묵적이기도 하다. 다만 RSC의 데이터 가져오기 패턴을 활용하면서 기존 컴포넌트를 최대한 재사용할 수 있게 된다는 점이 좋다.

2

@ellemedit 음, “front-end”는 두 단어의 합성어라고 생각해서 그렇게 썼는데, 요즘에는 그냥 붙여서 쓰는 경우가 더 많으니 하이픈을 빼도 되겠네요. BASIC은 언어 이름(“Beginners' All-purpose Symbolic Instruction Code”)이라고 생각해서 대문자로 표기했습니다.

0

ElleMeDit replied to the below article:

한국 소프트웨어 개발자들이 자주 틀리는 외래어 표기법

洪 民憙 (Hong Minhee) @hongminhee@hackers.pub

전에 단문으로 올렸던 글을 지속적으로 갱신해볼까 싶어 게시글로 만들어 봅니다.

영어 틀린 표기 올바른 표기
algorithm 알고리 알고리
app 어플
application 플리케이션 플리케이션
BASIC 베이 베이
directory 디렉 디렉
front-end 트엔드 트엔드
launch
license 라이 라이
message
method
parallel 페러 패럴
proxy
release 릴리 릴리
repository 레포 리파
shader 이더 이더
shell
Read more →
2
0
1
0