What is Hackers' Pub?

Hackers' Pub is a place for software engineers to share their knowledge and experience with each other. It's also an ActivityPub-enabled social network, so you can follow your favorite hackers in the fediverse and get their latest posts in your feed.

0
0

"We're talking about codifying into law a definition of antisemitism which would restrict and punish accurate and necessary criticisms of Israel."

"It's an attack on the ability to say things that are objectively true."
———————————————
Author: Marianne Dhenin
Subscribe to Their Newsletter & Become a Member: newsletter.mariannedhenin.com
———————————————

newsletter.mariannedhenin.com/

0
0
0
0
0
0

The Hidden Persuaders by Vance Packard & Mark Crispin Miller, 2007

"One of the best books around for demystifying the deliberately mysterious arts of ."-- Salon
"Fascinating, entertaining and thought-stimulating."-- The New York Times Book Review
"A brisk, authoritative and frightening report on how manufacturers, fundraisers and politicians are attempting to turn the American mind into a kind of catatonic dough that will buy, give or vote at their command-- The New Yorker

Originally published in 1957 and now back in print to celebrate its fiftieth anniversary, The Hidden Persuaders is Vance Packard’s pioneering and prescient work revealing how advertisers use psychological methods to tap into our unconscious desires in order to "persuade" us to buy the products they are selling.
A classic examination of how our thoughts and feelings are manipulated by business, media and politicians, The Hidden Persuaders was the first book to expose the hidden world of “motivation research,” the psychological technique that advertisers use to probe our minds in order to control our actions as consumers. Through analysis of products, political campaigns and television programs of the 1950s, Packard shows how the insidious manipulation practices that have come to dominate today’s corporate-driven world began. Featuring an introduction by Mark Crispin Miller, The Hidden Persuaders has sold over one million copies, and forever changed the way we look at the world of advertising.
0
0
0
0
0
0
0
0

An Nyeong (安寧) shared the below article:

왜 gaji인가? - TS로 안전하게 GitHub Actions 작성하기

개발곰 @gaebalgom@hackers.pub

최근에 저는 TS로 GitHub Actions를 작성하기 위한 툴을 만들었습니다. 그 이름하여 GitHub Actions Justified Improvements, gaji 라는 툴입니다. 저는 왜 TS로 GitHub Actions를 작성하게 되었으며, 기존 툴들과 어떤 점이 다를까요? 같이 알아보시죠.

가지 공식 문서

Toss Client DevOps Team에서의 인턴 근무

올해 1월부터, 저는 Toss Client DevOps Team 에서 인턴 근무를 시작했습니다. Client DevOps Team을 가장 단순하게 표현하자면, 클라이언트 개발자가 빠르고 안전하게 배포할 수 있는 인프라 환경을 구축하는 팀입니다. 제가 주로 진행한 작업은 기존 워크플로우를 GitHub Actions로 전환하고, 새로운 검사를 위한 커스텀 액션을 만드는 일이었습니다. 수십 개의 워크플로우를 다루면서, 빠르고 안전한 배포 인프라를 만들어야 하는 팀에서 정작 그 인프라를 만드는 과정 자체는 느리고 불안전하다는 걸 체감했습니다. 오타 하나를 확인하려면 커밋 → 푸시 → CI 실행 → 실패 확인이라는 사이클을 반복해야 했고, 로컬에서 재현할 방법이 없으니 git 실력만 늘었습니다.

인턴을 하며 자리잡은 생각들

이런 인턴 근무를 하면서, 몇가지 생각이 자리잡았습니다. 철학까지는 아니고, 단순한 생각 정도입니다.

  1. 입출력이 명확해야 좋은 소프트웨어입니다.

  2. YAML은 동작을 표현할 언어가 아닙니다. Actions는 입출력과 사이드이펙트가 있는 동작입니다. 이걸 데이터를 표현하기 위한 언어인 YAML로 표현하는 것 자체가 언어의 사용처가 잘못된 것이 아닐까요? 선언적이지 않은 걸 선언적으로 표현하려다 보니, YAML 안에 셸 스크립트를 넣는 기형적인 구조가 되어버렸습니다.

  3. 어느 환경에서든 재현 가능해야 좋은 도구입니다.

gaji는 이 중 1, 2번에서 출발했고, 3번은 act 같은 도구의 영역입니다.

GitHub Actions의 3가지 구조적 문제

위 생각을 가지고 GitHub Actions를 보면, 다음과 같은 문제점이 있습니다.

  1. YAML은 데이터 표현 언어지, 동작을 표현하기에 적합하지 않습니다.
  2. 타입 검사가 없습니다. 외부 저장소에 의존할 일이 많은데(actions/checkout@v5조차 외부 저장소입니다), 이들이 요구하는 입력에 대한 검증이 전혀 없습니다. 사용자가 직접 문서를 보고 일일이 형식에 맞게 입력해야 합니다.
  3. 로컬에서 재현하기가 힘듭니다.

이 세 가지가 결합해 GitHub Actions는 실행하기 전까지 간단한 오타 하나도 못 찾는 플랫폼이 되었습니다.

name: CI
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v4
        with:
          node-versoin: '20'  # 키 이름 오타! 런타임까지 오류 없음 ❌
          cache: 'npm'

      - run: npm ci
      - run: npm test

gaji는 첫 번째와 두 번째 문제를 해결하는 데 집중합니다.

기존 도구들과의 비교

actionlint

솔직히 말하면, gaji를 만들 당시에는 actionlint의 존재를 몰랐습니다. 이후에 알게 되었는데, 훌륭한 도구입니다. ${{ }} 표현식의 타입 체크, 액션 입력 검증, shellcheck 통합 등 YAML 워크플로우의 오류를 상당히 잘 잡아줍니다.

다만 근본적인 접근 방식이 다릅니다. actionlint는 YAML을 유지하면서 사후에 오류를 잡는 린터이고, gaji는 YAML 자체를 벗어나서 작성 시점에 오류를 불가능하게 만드는 접근입니다. 린터는 "실수를 알려주고", 타입 시스템은 "실수를 하기 어렵게 만듭니다." 개발 경험 측면에서도, actionlint는 별도 CLI를 실행하거나 에디터 플러그인을 설치해야 하지만, gaji는 TypeScript 네이티브 자동완성과 인라인 타입 힌트가 에디터에서 즉시 동작합니다.

이 둘을 같이 쓰면 더욱 좋습니다. gaji가 생성한 YAML을 actionlint로 검증하면 가장 이상적인 조합이 됩니다. gaji가 TypeScript 단에서 액션 입력의 타입을 잡고, actionlint가 ${{ }} 표현식 검증 같은 YAML 단의 검사를 보완합니다.

emmanuelnk/github-actions-workflow-ts

github-actions-workflow-ts는 TS로 GitHub Actions를 표기한다는 아이디어의 출발점이 된 프로젝트입니다. action.yml에서 타입을 자동 생성한다는 아이디어 자체는 gaji와 동일합니다. 다만 코드젠의 주체가 다릅니다. github-actions-workflow-ts는 메인테이너가 trackedActions 목록을 관리하여 npm 패키지로 배포하는 방식이고, gaji는 사용자가 참조하는 모든 액션에 대해 즉시 로컬에서 타입을 생성합니다.

github-actions-workflow-ts의 장점은 명확합니다. npm 패키지를 설치하면 바로 사용 가능하고, 사용자가 별도의 코드젠을 실행할 필요가 없습니다. step outputs에 대한 타입 안전성도 지원합니다.

반면 단점도 있습니다. 메인테이너가 관리하는 목록에 있는 액션만 타입이 지원되므로, 커스텀 액션이나 GHE 내부 액션은 사용할 수 없습니다. 새 액션이나 버전 추가도 메인테이너에 의존하고, 외부 JS 런타임이 필요합니다.

gaji의 장점은 사용자가 참조하는 어떤 액션이든 즉시 타입을 생성한다는 점입니다. 커스텀 액션이든 GHE 내부 액션이든 상관없습니다. Rust 바이너리로 동작하므로 JS 런타임도 불필요합니다. 반면 단점으로는 사용자가 gaji dev를 실행해야 타입이 생성되고, 타입이 로컬에서 생성되므로 프로젝트마다 세팅이 필요하다는 점이 있습니다.

저는 GHE 환경에서 수많은 커스텀 액션을 다뤘던 경험 때문에, gaji 쪽의 접근이 필요하다고 판단했습니다.

gaji의 접근법

왜 이렇게 만들었는가

왜 Rust인가? 빠르기 때문입니다. 단순히 빌드된 바이너리의 속도를 이야기하는 것이 아닙니다. clippy, rustfmt 등 여러 검사 도구가 내장되어 있어서 LLM을 이용한 개발 속도를 크게 줄여주었습니다. 덕분에 인턴을 하면서도 빠르게 만들 수 있었습니다. 또한 oxc 등 Rust로 작성된 TypeScript 지원 도구들이 이미 성숙해 있어서, Rust에서 TypeScript를 다루는 것 또한 편했습니다.

왜 TypeScript인가? 우선 제가 JS/TS 개발자입니다. TypeScript의 타입 시스템은 강력하면서도 보편적이라 많은 개발자가 이미 익숙합니다. 그리고 GitHub Actions의 YAML 구조가 본질적으로 JSON과 유사하므로, TS/JS에서 JSON-like 객체로 표현하기가 매우 자연스럽습니다. 이를 단적으로 보여주는 것은 모든 gaji 워크플로우 파일이 그 자체로 유효한 TS 파일이라는 점입니다. Deno처럼 TS를 바로 실행할 수 있는 환경에서 gaji로 작성된 워크플로우를 실행하면, 해당 워크플로우를 JSON으로 표현한 결과를 출력합니다.

왜 action.yml 자동 코드젠인가? Client DevOps Team에서 커스텀 액션을 작성하는 일을 했고, 이미 상당히 많은 커스텀 액션이 존재했습니다. 이들의 문서를 일일이 보며 작성하는 것이 매우 힘들었던 경험이 직접적인 동기였습니다. Hackers.pub에 기여하면서 GraphQL 자동 코드젠의 개념을 접했고, 같은 접근을 GitHub Actions에 적용할 수 있겠다고 판단했습니다.

핵심 구조

gaji 워크플로우는 getAction()JobWorkflow.build()의 흐름으로 구성됩니다. gaji dev --watch를 실행하면 새 액션 참조를 감지하여 자동으로 타입을 생성합니다.

import { getAction, Job, Workflow } from "../generated/index.js";

const checkout = getAction("actions/checkout@v5");
const setupNode = getAction("actions/setup-node@v4");

const build = new Job("ubuntu-latest")
  .addStep(checkout({}))
  .addStep(setupNode({
    with: {
      "node-version": "20",
      cache: "npm",
    },
  }))
  .addStep({ run: "npm ci" })
  .addStep({ run: "npm test" });

const workflow = new Workflow({
  name: "CI",
  on: { push: { branches: ["main"] } },
}).addJob("build", build);

workflow.build("ci");

이렇게 작성하면 모든 액션 입력에 대한 자동완성, 컴파일 시점 타입 체크, action.yml 문서의 IDE 힌트 표시, 기본값 표시가 모두 동작합니다. CompositeJob으로 공통 로직을 클래스로 추출하거나, CallJob으로 재사용 가능한 워크플로우를 호출하는 것도 TS 코드상에선 자연스럽습니다.

실제 사례: gaji 자체의 릴리즈 CD

gaji는 모든 ci/cd를 gaji로 작성하고 있습니다. 그중에서 제일 복잡한 release.ts는 4개의 Job으로 구성되어 있습니다.

  • build: 5개 플랫폼(linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64) 크로스 빌드
  • upload-release-assets: GitHub Release에 바이너리와 체크섬 업로드
  • publish-npm: npm에 플랫폼별 패키지 퍼블리시
  • publish-crates: crates.io에 OIDC 기반 퍼블리시

이 워크플로우가 YAML로 컴파일되면 약 180줄의 평탄한 구조가 됩니다. 주석 없이는 Job 간 경계나 의존관계를 파악하기 어렵습니다. TypeScript 버전에서는 build, uploadReleaseAssets, publishNpm, publishCrates라는 변수명만으로 구조가 즉시 파악됩니다. 6개의 외부 액션을 타입 안전하게 사용하고, 복잡한 매트릭스 빌드와 OS별 분기가 코드 구조 안에서 가독성 있게 표현됩니다.

gaji의 한계

gaji에는 여전히 한계가 존재합니다.

근본적으로, 최종 산출물이 여전히 YAML입니다. GitHub Actions 플랫폼의 입력 형식이 YAML인 이상, gaji도 그 제약 안에 갇힙니다. gaji는 이 플랫폼 위에서의 최선이지, 이상적인 해답은 아닙니다. 원본 action.yml의 inputs가 문자열이나 숫자 정도로만 표현되기 때문에, "npm" | "yarn" | "pnpm" 같은 세밀한 값 수준의 타입까지는 제공할 수 없습니다. ${{ matrix.target.rust_target }} 같은 GitHub Actions 표현식도 여전히 순수 문자열이라 타입 검증이 불가능합니다.

기술적인 제한도 있습니다. gaji devgetAction()을 정적 분석해서 실행되기 때문에 문자열 리터럴만 지원하고, 변수나 템플릿 리터럴은 사용할 수 없습니다. 문자열 값 자체의 오타(cache: "npn" vs cache: "npm")도 잡을 수 없고요.

앞으로의 방향

gaji의 현재 아키텍처는 TypeScript → Parse (oxc) → Execute (QuickJS) → YAML입니다. 코드젠을 만들면서 한 가지 아이디어를 얻었는데, 프론트엔드(사용자가 작성하는 언어)와 백엔드(YAML 생성)를 잘 분리하고, 중간 언어를 잘 정의하면 TypeScript 외의 다른 언어로도 워크플로우를 작성할 수 있겠다는 것입니다.

1.0에서는 플러그인 시스템을 도입해 다른 언어 지원을 확장할 수 있는 구조를 만들 계획입니다. gaji의 핵심 가치인 action.yml 자동 타입 생성을 TypeScript에 국한하지 않고 확장하고 싶습니다.

Special Thanks

gaji 브랜드

이름 제안을 해 주신 kiwiyou 님, RanolP 님, 로고 제작을 해 주신 sij411 님께 감사드립니다. Client DevOps Team에게도 감사합니다. 이 팀에서 겪은 경험이 아니었으면 YAML과 GitHub Actions에 대해 생각해 보지 않았을 겁니다. emmanuelnk/github-actions-workflow-ts에게도 감사를 표합니다. TS로 GitHub Actions를 표기한다는 아이디어와 기본적인 TS API 설계는 여기서 가져왔습니다.

Read more →
4
0
0
0

Joy is different from fun or entertainment. It's not a celebration of suffering. It's like finding fresh air when sadness surrounds us from all sides. Joy is balm, mental medicine. It offers company in loneliness, nourishment for a weary mind. It provides solace when vulnerability overwhelms us, reassurance that we are still loved and worthy when things go wrong.
youtu.be/ICh0NKHGRrM

0
0
0
0
1

바이브 코딩의 마법을 깨기
------------------------------
- *AI가 생성한 복잡한 코드 대량 생산* 이 확산되며, 인간이 읽지 않는 코드를 만드는 현상이 업계 전반에 퍼지고 있음
- 경영진은 *AI로 인한 인력 감축* 을 정당화하고, 개발자들은 AI가 만든 코드 비율을 채우라는 압박을 받는 상황
- 이러한 ‘바이브 코딩’은 *도박의 중독 메커니즘과 유사한 ‘다크 플로우(…
------------------------------
https://news.hada.io/topic?id=26708&utm_source=googlechat&utm_medium=bot&utm_campaign=1834

0

I’m giving a talk titled “Designing APIs for Swift Concurrency” this Thursday at the @getsentrySentry HQ in SF! Join for food, cool people, and an exploration of writing correct, ergonomic code in a poorly understood area of Swift. Here’s the link to sign up: https://luma.com/tqb3l8w6
0
0
0

Simon Park shared the below article:

왜 gaji인가? - TS로 안전하게 GitHub Actions 작성하기

개발곰 @gaebalgom@hackers.pub

최근에 저는 TS로 GitHub Actions를 작성하기 위한 툴을 만들었습니다. 그 이름하여 GitHub Actions Justified Improvements, gaji 라는 툴입니다. 저는 왜 TS로 GitHub Actions를 작성하게 되었으며, 기존 툴들과 어떤 점이 다를까요? 같이 알아보시죠.

가지 공식 문서

Toss Client DevOps Team에서의 인턴 근무

올해 1월부터, 저는 Toss Client DevOps Team 에서 인턴 근무를 시작했습니다. Client DevOps Team을 가장 단순하게 표현하자면, 클라이언트 개발자가 빠르고 안전하게 배포할 수 있는 인프라 환경을 구축하는 팀입니다. 제가 주로 진행한 작업은 기존 워크플로우를 GitHub Actions로 전환하고, 새로운 검사를 위한 커스텀 액션을 만드는 일이었습니다. 수십 개의 워크플로우를 다루면서, 빠르고 안전한 배포 인프라를 만들어야 하는 팀에서 정작 그 인프라를 만드는 과정 자체는 느리고 불안전하다는 걸 체감했습니다. 오타 하나를 확인하려면 커밋 → 푸시 → CI 실행 → 실패 확인이라는 사이클을 반복해야 했고, 로컬에서 재현할 방법이 없으니 git 실력만 늘었습니다.

인턴을 하며 자리잡은 생각들

이런 인턴 근무를 하면서, 몇가지 생각이 자리잡았습니다. 철학까지는 아니고, 단순한 생각 정도입니다.

  1. 입출력이 명확해야 좋은 소프트웨어입니다.

  2. YAML은 동작을 표현할 언어가 아닙니다. Actions는 입출력과 사이드이펙트가 있는 동작입니다. 이걸 데이터를 표현하기 위한 언어인 YAML로 표현하는 것 자체가 언어의 사용처가 잘못된 것이 아닐까요? 선언적이지 않은 걸 선언적으로 표현하려다 보니, YAML 안에 셸 스크립트를 넣는 기형적인 구조가 되어버렸습니다.

  3. 어느 환경에서든 재현 가능해야 좋은 도구입니다.

gaji는 이 중 1, 2번에서 출발했고, 3번은 act 같은 도구의 영역입니다.

GitHub Actions의 3가지 구조적 문제

위 생각을 가지고 GitHub Actions를 보면, 다음과 같은 문제점이 있습니다.

  1. YAML은 데이터 표현 언어지, 동작을 표현하기에 적합하지 않습니다.
  2. 타입 검사가 없습니다. 외부 저장소에 의존할 일이 많은데(actions/checkout@v5조차 외부 저장소입니다), 이들이 요구하는 입력에 대한 검증이 전혀 없습니다. 사용자가 직접 문서를 보고 일일이 형식에 맞게 입력해야 합니다.
  3. 로컬에서 재현하기가 힘듭니다.

이 세 가지가 결합해 GitHub Actions는 실행하기 전까지 간단한 오타 하나도 못 찾는 플랫폼이 되었습니다.

name: CI
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v4
        with:
          node-versoin: '20'  # 키 이름 오타! 런타임까지 오류 없음 ❌
          cache: 'npm'

      - run: npm ci
      - run: npm test

gaji는 첫 번째와 두 번째 문제를 해결하는 데 집중합니다.

기존 도구들과의 비교

actionlint

솔직히 말하면, gaji를 만들 당시에는 actionlint의 존재를 몰랐습니다. 이후에 알게 되었는데, 훌륭한 도구입니다. ${{ }} 표현식의 타입 체크, 액션 입력 검증, shellcheck 통합 등 YAML 워크플로우의 오류를 상당히 잘 잡아줍니다.

다만 근본적인 접근 방식이 다릅니다. actionlint는 YAML을 유지하면서 사후에 오류를 잡는 린터이고, gaji는 YAML 자체를 벗어나서 작성 시점에 오류를 불가능하게 만드는 접근입니다. 린터는 "실수를 알려주고", 타입 시스템은 "실수를 하기 어렵게 만듭니다." 개발 경험 측면에서도, actionlint는 별도 CLI를 실행하거나 에디터 플러그인을 설치해야 하지만, gaji는 TypeScript 네이티브 자동완성과 인라인 타입 힌트가 에디터에서 즉시 동작합니다.

이 둘을 같이 쓰면 더욱 좋습니다. gaji가 생성한 YAML을 actionlint로 검증하면 가장 이상적인 조합이 됩니다. gaji가 TypeScript 단에서 액션 입력의 타입을 잡고, actionlint가 ${{ }} 표현식 검증 같은 YAML 단의 검사를 보완합니다.

emmanuelnk/github-actions-workflow-ts

github-actions-workflow-ts는 TS로 GitHub Actions를 표기한다는 아이디어의 출발점이 된 프로젝트입니다. action.yml에서 타입을 자동 생성한다는 아이디어 자체는 gaji와 동일합니다. 다만 코드젠의 주체가 다릅니다. github-actions-workflow-ts는 메인테이너가 trackedActions 목록을 관리하여 npm 패키지로 배포하는 방식이고, gaji는 사용자가 참조하는 모든 액션에 대해 즉시 로컬에서 타입을 생성합니다.

github-actions-workflow-ts의 장점은 명확합니다. npm 패키지를 설치하면 바로 사용 가능하고, 사용자가 별도의 코드젠을 실행할 필요가 없습니다. step outputs에 대한 타입 안전성도 지원합니다.

반면 단점도 있습니다. 메인테이너가 관리하는 목록에 있는 액션만 타입이 지원되므로, 커스텀 액션이나 GHE 내부 액션은 사용할 수 없습니다. 새 액션이나 버전 추가도 메인테이너에 의존하고, 외부 JS 런타임이 필요합니다.

gaji의 장점은 사용자가 참조하는 어떤 액션이든 즉시 타입을 생성한다는 점입니다. 커스텀 액션이든 GHE 내부 액션이든 상관없습니다. Rust 바이너리로 동작하므로 JS 런타임도 불필요합니다. 반면 단점으로는 사용자가 gaji dev를 실행해야 타입이 생성되고, 타입이 로컬에서 생성되므로 프로젝트마다 세팅이 필요하다는 점이 있습니다.

저는 GHE 환경에서 수많은 커스텀 액션을 다뤘던 경험 때문에, gaji 쪽의 접근이 필요하다고 판단했습니다.

gaji의 접근법

왜 이렇게 만들었는가

왜 Rust인가? 빠르기 때문입니다. 단순히 빌드된 바이너리의 속도를 이야기하는 것이 아닙니다. clippy, rustfmt 등 여러 검사 도구가 내장되어 있어서 LLM을 이용한 개발 속도를 크게 줄여주었습니다. 덕분에 인턴을 하면서도 빠르게 만들 수 있었습니다. 또한 oxc 등 Rust로 작성된 TypeScript 지원 도구들이 이미 성숙해 있어서, Rust에서 TypeScript를 다루는 것 또한 편했습니다.

왜 TypeScript인가? 우선 제가 JS/TS 개발자입니다. TypeScript의 타입 시스템은 강력하면서도 보편적이라 많은 개발자가 이미 익숙합니다. 그리고 GitHub Actions의 YAML 구조가 본질적으로 JSON과 유사하므로, TS/JS에서 JSON-like 객체로 표현하기가 매우 자연스럽습니다. 이를 단적으로 보여주는 것은 모든 gaji 워크플로우 파일이 그 자체로 유효한 TS 파일이라는 점입니다. Deno처럼 TS를 바로 실행할 수 있는 환경에서 gaji로 작성된 워크플로우를 실행하면, 해당 워크플로우를 JSON으로 표현한 결과를 출력합니다.

왜 action.yml 자동 코드젠인가? Client DevOps Team에서 커스텀 액션을 작성하는 일을 했고, 이미 상당히 많은 커스텀 액션이 존재했습니다. 이들의 문서를 일일이 보며 작성하는 것이 매우 힘들었던 경험이 직접적인 동기였습니다. Hackers.pub에 기여하면서 GraphQL 자동 코드젠의 개념을 접했고, 같은 접근을 GitHub Actions에 적용할 수 있겠다고 판단했습니다.

핵심 구조

gaji 워크플로우는 getAction()JobWorkflow.build()의 흐름으로 구성됩니다. gaji dev --watch를 실행하면 새 액션 참조를 감지하여 자동으로 타입을 생성합니다.

import { getAction, Job, Workflow } from "../generated/index.js";

const checkout = getAction("actions/checkout@v5");
const setupNode = getAction("actions/setup-node@v4");

const build = new Job("ubuntu-latest")
  .addStep(checkout({}))
  .addStep(setupNode({
    with: {
      "node-version": "20",
      cache: "npm",
    },
  }))
  .addStep({ run: "npm ci" })
  .addStep({ run: "npm test" });

const workflow = new Workflow({
  name: "CI",
  on: { push: { branches: ["main"] } },
}).addJob("build", build);

workflow.build("ci");

이렇게 작성하면 모든 액션 입력에 대한 자동완성, 컴파일 시점 타입 체크, action.yml 문서의 IDE 힌트 표시, 기본값 표시가 모두 동작합니다. CompositeJob으로 공통 로직을 클래스로 추출하거나, CallJob으로 재사용 가능한 워크플로우를 호출하는 것도 TS 코드상에선 자연스럽습니다.

실제 사례: gaji 자체의 릴리즈 CD

gaji는 모든 ci/cd를 gaji로 작성하고 있습니다. 그중에서 제일 복잡한 release.ts는 4개의 Job으로 구성되어 있습니다.

  • build: 5개 플랫폼(linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64) 크로스 빌드
  • upload-release-assets: GitHub Release에 바이너리와 체크섬 업로드
  • publish-npm: npm에 플랫폼별 패키지 퍼블리시
  • publish-crates: crates.io에 OIDC 기반 퍼블리시

이 워크플로우가 YAML로 컴파일되면 약 180줄의 평탄한 구조가 됩니다. 주석 없이는 Job 간 경계나 의존관계를 파악하기 어렵습니다. TypeScript 버전에서는 build, uploadReleaseAssets, publishNpm, publishCrates라는 변수명만으로 구조가 즉시 파악됩니다. 6개의 외부 액션을 타입 안전하게 사용하고, 복잡한 매트릭스 빌드와 OS별 분기가 코드 구조 안에서 가독성 있게 표현됩니다.

gaji의 한계

gaji에는 여전히 한계가 존재합니다.

근본적으로, 최종 산출물이 여전히 YAML입니다. GitHub Actions 플랫폼의 입력 형식이 YAML인 이상, gaji도 그 제약 안에 갇힙니다. gaji는 이 플랫폼 위에서의 최선이지, 이상적인 해답은 아닙니다. 원본 action.yml의 inputs가 문자열이나 숫자 정도로만 표현되기 때문에, "npm" | "yarn" | "pnpm" 같은 세밀한 값 수준의 타입까지는 제공할 수 없습니다. ${{ matrix.target.rust_target }} 같은 GitHub Actions 표현식도 여전히 순수 문자열이라 타입 검증이 불가능합니다.

기술적인 제한도 있습니다. gaji devgetAction()을 정적 분석해서 실행되기 때문에 문자열 리터럴만 지원하고, 변수나 템플릿 리터럴은 사용할 수 없습니다. 문자열 값 자체의 오타(cache: "npn" vs cache: "npm")도 잡을 수 없고요.

앞으로의 방향

gaji의 현재 아키텍처는 TypeScript → Parse (oxc) → Execute (QuickJS) → YAML입니다. 코드젠을 만들면서 한 가지 아이디어를 얻었는데, 프론트엔드(사용자가 작성하는 언어)와 백엔드(YAML 생성)를 잘 분리하고, 중간 언어를 잘 정의하면 TypeScript 외의 다른 언어로도 워크플로우를 작성할 수 있겠다는 것입니다.

1.0에서는 플러그인 시스템을 도입해 다른 언어 지원을 확장할 수 있는 구조를 만들 계획입니다. gaji의 핵심 가치인 action.yml 자동 타입 생성을 TypeScript에 국한하지 않고 확장하고 싶습니다.

Special Thanks

gaji 브랜드

이름 제안을 해 주신 kiwiyou 님, RanolP 님, 로고 제작을 해 주신 sij411 님께 감사드립니다. Client DevOps Team에게도 감사합니다. 이 팀에서 겪은 경험이 아니었으면 YAML과 GitHub Actions에 대해 생각해 보지 않았을 겁니다. emmanuelnk/github-actions-workflow-ts에게도 감사를 표합니다. TS로 GitHub Actions를 표기한다는 아이디어와 기본적인 TS API 설계는 여기서 가져왔습니다.

Read more →
4

으으음... nix 쓰는 거 점점 부담스러워져서 좀 타개책이 필요하다.

  • nix는 패키지 단위가 아니라 nixpkgs 단위로 버전을 관리하다보니 특정 패키지만 마이너 버전 업하는게 불편하다
    • 나는 A 패키지만 버전업 하고 싶은데용? → 불편하고 힘들게 해야함
  • 각 레포마다 다른 버전의 nixpkgs를 쓰고 있을 수도 있음
    • 이게 의존성 관리에는 문제가 없는데, 내 맥뿍 용량 관리(...)랑 빌드 시간 관리(...)에 영향을 크게 줌
    • 예를 들어 시스템에 이미 A 패키지가 깔려있는데, 어떤 레포에 진입하니 자동으로 A 패키지를 다시 빌드하네? 왜??? 하고 보면 시스템의 nixpkgs와 레포의 nixpkgs 버전이 달라서 그렇다거나
  • darwin-rebuild, nixos-rebuild로만 리빌드하다보니 작은 수정에도 시간이 오래 걸린다
  • home-manager가 돌아가다가 중간에 스크립트가 삐끗하면 그대로 조용히 실패함. 실패라고 알려주는 것도 아니고, 롤백도 아니고, 경고도 아니고, 그거 빼고 실행해주는 것도 아니고, 멈췄다고 알려주는 것도 아니고 그냥 쓱 조용히 멈추고 뒷부분 실행을 안 한다...
    • 가끔 Emcas 설정 로드 안 되어있길래 열심히 뒤적거려보면 이런 문제가 많음
  • 언어가 strict하지 않고 lazy typing이라 그런가 LLM이 종종 해멜 때가 많음
nix-darwin으로 설치한 WezTerm.app이 권한을 요구하는 모습home-manager에서 script가 실패하자 "조용히 실패"한 모습
3
0
0
0
0
0

Imagine how quickly Fortinet and Ivanti and the other usual suspects would unfuck their shit if they were held responsible for the losses of their customers the same way car manufacturers are ( sometimes ) held liable for their negligence.

0
0
0

260216의 주제는
1.까치
2.독점욕
3.커튼 사이로 햇살이 비치면
원하는 주제를 고르시거나, 모든 주제를 엮어 창작하셔도 좋습니다.

편하신 시간대에 1시간 동안 전력을 다해주세요.
글/그림/수공예/그외 모든 창작물 가능.

툿을 올리실 때 @daily_1hour매일_전력_1시간 계정을 태그해주시면 그날 밤~다음 전력 주제 발표 전까지 리노트합니다.
(툿이 리노트할 수 없는 상태라면 마음/북마크만 찍습니다.)

NSFW 컨텐츠의 경우 반드시 CW를 걸어주세요.

0
0
0
0
0
0
0
0
0

drafted snac.css

  • few colors
  • default fonts and everything
  • large high contrast font for content
  • small fonts for controls
  • dark and light color schemes
  • big and small screens
  • works with styles from my site
please note, it's just a draft.

updated /var/snac/data/server.json
  "cssurls": [ "/style.css", "/snac.css" ],
while keeping /var/snac/data/styles.css empty, otherwise snac re-creates it with default styles... :)


0
0
0
0
0

Juntai Park shared the below article:

일주일만에 새로운 엑셀 라이브러리를 만들다

Haze @nebuleto@hackers.pub

SheetKit은 기존 Node.js 엑셀 라이브러리들의 성능 한계와 기능 제약을 해결하기 위해 Rust로 개발된 고성능 스프레드시트 라이브러리입니다. 저자는 대량의 데이터 처리와 동적 템플릿 생성을 위해 Rust 코어 기반에 napi-rs를 활용한 Node.js 바인딩 구조를 설계했으며, 코딩 에이전트와의 긴밀한 협업을 통해 단 일주일 만에 초기 배포부터 v0.5.0 릴리스까지 달성했습니다. 특히 자바스크립트 객체 생성에 따른 가비지 컬렉션(garbage collection) 압박을 줄이기 위해 이진 버퍼(binary buffer)를 통한 데이터 전송 방식을 도입하고, 지연 로딩(lazy loading)과 스트리밍 리더 기능을 통해 대용량 파일 처리 효율을 극대화했습니다. 벤치마크 결과 기존 라이브러리 대비 압도적인 메모리 절감과 속도 향상을 보여주었으며, 특정 쓰기 시나리오에서는 V8 엔진의 최적화 덕분에 Rust 네이티브보다 빠른 성능을 기록하기도 했습니다. 현재 164개의 수식 함수와 43개의 차트 타입을 지원하며 실제 업무 현장에 성공적으로 적용 중인 SheetKit은 Node.js 환경에서 대규모 엑셀 데이터를 다루는 개발자들에게 강력하고 효율적인 솔루션을 제공합니다.

Read more →
7
0
0
1
0
0
0
0
0
0
0
1

So a person set a GoPro at the entrance to a burrowing owl's burrow. There are dozens of comments about what a fantastic photo it is. Having photographed burrowing owls--from an ethical distance--near the Salton Sea ag fields, I know my friend Wendy down there would be horrified, as am I, by what the photographer did. It is wrong to disturb any bird to get-the-shot. 😡 The only reason to approach a burrow is to plant a small flag warning people--& tractors--to steer clear. flickr.com/photos/wemesq/with/

0
0
0