洪 民憙 (Hong Minhee) :nonbinary:'s avatar

洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · 977 following · 1332 followers

An intersectionalist, feminist, and socialist living in Seoul (UTC+09:00). @tokolovesme's spouse. Who's behind @fedify, @hollo, and @botkit. Write some free software in , , , & . They/them.

서울에 사는 交叉女性主義者이자 社會主義者. 金剛兔(@tokolovesme)의 配偶者. @fedify, @hollo, @botkit 메인테이너. , , , 等으로 自由 소프트웨어 만듦.

()

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

Hello, I'm an open source software engineer in my late 30s living in , , and an avid advocate of and the .

I'm the creator of @fedify, an server framework in , @hollo, an ActivityPub-enabled microblogging software for single users, and @botkit, a simple ActivityPub bot framework.

I'm also very interested in East Asian languages (so-called ) and . Feel free to talk to me in , (), or (), or even in Literary Chinese (, )!

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post

安寧(안녕)하세요, 저는 서울에 살고 있는 30() 後半(후반) 오픈 소스 소프트웨어 엔지니어이며, 自由(자유)·오픈 소스 소프트웨어와 聯合宇宙(연합우주)(fediverse)의 熱烈(열렬)支持者(지지자)입니다.

저는 TypeScript() ActivityPub 서버 프레임워크인 @fedify 프로젝트와 싱글 유저() ActivityPub 마이크로블로그인 @hollo 프로젝트와 ActivityPub 봇 프레임워크인 @botkit 프로젝트의 製作者(제작자)이기도 합니다.

저는 ()아시아 言語(언어)(이른바 )와 유니코드에도 關心(관심)이 많습니다. 聯合宇宙(연합우주)에서는 國漢文混用體(국한문 혼용체)를 쓰고 있어요! 제게 韓國語(한국어)英語(영어), 日本語(일본어)로 말을 걸어주세요. (아니면, 漢文(한문)으로도!)

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post

こんにちは、私はソウルに住んでいる30代後半のオープンソースソフトウェアエンジニアで、自由・オープンソースソフトウェアとフェディバースの熱烈な支持者です。名前は洪 民憙ホン・ミンヒです。

私はTypeScript用のActivityPubサーバーフレームワークである「@fedify」と、ActivityPubをサポートする1人用マイクロブログである 「@hollo」と、ActivityPubのボットを作成する為のシンプルなフレームワークである「@botkit」の作者でもあります。

私は東アジア言語(いわゆるCJK)とUnicodeにも興味が多いです。日本語、英語、韓国語で話しかけてください。(または、漢文でも!)

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


LLM 기반의 게시글 번역 기능이 추가되었습니다. 우선, 자신이 쓴 게시글이 LLM을 이용해 번역되는 것을 허용하려면, 게시글 공개 설정에서 “LLM 기반 자동 번역 허용” 옵션을 켜 주셔야 합니다. 기존 게시글은 모두 이 옵션이 꺼져 있습니다만, 새로 쓰는 게시글의 경우 기본적으로 켜져 있습니다.

한국어판 게시글 공개 설정 페이지에 추가된 “LLM 기반 자동 번역 허용” 옵션
한국어판 게시글 공개 설정 페이지에 추가된 “LLM 기반 자동 번역 허용” 옵션
영어판 게시물 공개 설정 페이지에 추가된 “Allow LLM-powered automatic translation” 옵션
영어판 게시물 공개 설정 페이지에 추가된 “Allow LLM-powered automatic translation” 옵션

위와 같이 옵션을 켜 준 게시글은 위쪽에 다음과 같이 “다른 언어로 읽기” 메뉴가 표시되게 됩니다. 이 메뉴에 나오는 언어 목록은 언어 설정에서 정할 수 있습니다.

게시글 첫 부분에 표시되는 “다른 언어로 읽기” 메뉴 (한국어판)
게시글 첫 부분에 표시되는 “다른 언어로 읽기” 메뉴 (한국어판)
게시글 첫 부분에 표시되는 “Read in other languages” 메뉴 (영어판)
게시글 첫 부분에 표시되는 “Read in other languages” 메뉴 (영어판)

이 중에서 이미 번역이 완료된 언어는 바로 표시되지만, 아직 번역이 완료되지 않은 언어의 경우, 아래와 같이 기다리라는 메시지가 뜨게 됩니다. 게시글의 분량에 따라 번역 시간은 차이가 나지만, 짧으면 30초에서 길면 5분 정도 걸립니다.

게시글이 번역중이라는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역중입니다. 번역이 완료될 때까지 기다려 주세요.”
게시글이 번역중이라는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역중입니다. 번역이 완료될 때까지 기다려 주세요.”
게시글이 번역중이라는 메시지 (영어판): “This article is being translated from Korean to English. Please wait until the translation is complete.”
게시글이 번역중이라는 메시지 (영어판): “This article is being translated from Korean to English. Please wait until the translation is complete.”

번역이 완료되면, 아래와 같이 메시지가 바뀝니다.

게시글의 번역본 상단에 뜨는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역되었습니다.”
게시글의 번역본 상단에 뜨는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역되었습니다.”
게시글의 번역본 상단에 뜨는 메시지 (영어판): “This article has been translated from Korean to English.”
게시글의 번역본 상단에 뜨는 메시지 (영어판): “This article has been translated from Korean to English.”

번역 기능은 제가 Hackers' Pub을 맨 처음 구상할 때부터 핵심 기능으로 고려하고 있던 것이었습니다. 소프트웨어 프로그래머로서 일정 수준 이상 성장하기 위해서는 반드시 영어를 배워야만 하는 불합리함이나 그리고 일본어나 중국어 등 영어가 아닌 언어로 쓰인 다양한 자료에 대부분의 외국인은 접근하지 못한다는 아쉬움을 오래 전부터 느꼈기 때문입니다. 다행히 얼마 전부터 LLM의 번역 품질이 아주 좋아졌고, 이를 활용하여 꽤 괜찮은 품질의 번역 기능을 Hackers' Pub 같은 작은 웹사이트에서도 구현할 수 있게 되었네요.

참고로 현재 번역에 쓰이는 모델은 Claude Sonnet 3.7입니다. 저렴하다고는 할 수 없는 모델인데요. 시범적으로 운영해 보고, 비용이 너무 부담된다고 여겨지면 Gemini 2.5 Flash 같은 다른 모델로 전환하는 것도 고려하고 있습니다.

아무튼, 모처럼 추가한 번역 기능이니 많은 분들이 유용함을 누리셨으면 좋겠습니다.

아래는 제가 샘플로 미리 만들어 둔 번역본들입니다:

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to ここあにゃん :surprised_karin_chibi:'s post

@AmaseCocoa 有りますよ。例:https://hackers.pub/.well-known/webfinger?resource=https://hackers.pub/ap/actors/019382d3-63d7-7cf7-86e8-91e2551c306c

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

アプリケーション開発の観点から見たDrizzle ORMとKyselyの比較」(日本語)

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


TypeScript로 백엔드 서버를 개발하면서 적절한 ORM 선택은 항상 중요한 결정 중 하나입니다. 최근 제 프로젝트에서 Drizzle ORM과 Kysely를 모두 사용해 볼 기회가 있었는데, 개인적으로는 Drizzle ORM이 더 편리하고 생산성이 높았던 경험을 공유하고자 합니다.

두 ORM에 대한 간략한 소개

Drizzle ORM은 TypeScript용 ORM으로, 타입 안전성과 직관적인 API를 강점으로 내세우고 있습니다. 스키마 정의부터 마이그레이션, 쿼리 빌더까지 풀스택 개발 경험을 제공합니다.

Kysely는 “타입 안전한 SQL 쿼리 빌더”로 자신을 소개하며, 타입스크립트의 타입 시스템을 활용해 쿼리 작성 시 타입 안전성을 보장합니다.

두 도구 모두 훌륭하지만, 제 개발 경험에 비추어 볼 때 Drizzle ORM이 몇 가지 측면에서 더 편리했습니다.

Drizzle ORM을 선호하게 된 이유

스키마 정의의 직관성

Drizzle ORM의 스키마 정의 방식은 매우 직관적이고 선언적입니다:

import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').unique().notNull(),
  age: integer('age')
});

Drizzle ORM은 이 스키마 정의로부터 자동으로 CREATE TABLE SQL을 생성할 수 있어, 스키마와 코드가 항상 동기화되어 있습니다.

반면 Kysely는 타입 정의에 더 중점을 두고 있어 스키마와 타입 정의가 분리되는 경향이 있습니다:

interface Database {
  users: {
    id: Generated<number>;
    name: string;
    email: string;
    age: number | null;
  };
}

이 타입 정의는 TypeScript 코드에서 타입 안전성을 제공하지만, 이 타입 정의만으로는 CREATE TABLE SQL을 생성할 수 없다는 것이 결정적인 단점입니다. 실제로 테이블을 생성하려면 별도의 SQL 스크립트나 마이그레이션 코드를 작성해야 합니다. 이는 타입과 실제 데이터베이스 스키마 간의 불일치 가능성을 높입니다.

Drizzle의 접근 방식이 데이터베이스 스키마와 TypeScript 타입을 더 긴밀하게 연결해주어 개발 과정에서 혼란을 줄여주었습니다.

마이그레이션 경험

Drizzle ORM의 마이그레이션 도구(drizzle-kit)는 정말 인상적이었습니다. 스키마 변경사항을 자동으로 감지하고 SQL 마이그레이션 파일을 생성해주는 기능이 개발 워크플로우를 크게 개선했습니다:

npx drizzle-kit generate:pg

이 명령어 하나로 스키마 변경사항에 대한 마이그레이션 파일이 생성되며, 이를 검토하고 적용하는 과정이 매우 간단했습니다.

반면 Kysely의 마이그레이션은 본질적으로 수동적입니다. 개발자가 직접 마이그레이션 파일을 작성해야 하며, 스키마 변경사항을 자동으로 감지하거나 SQL을 생성해주는 기능이 없습니다:

// Kysely의 마이그레이션 예시
async function up(db: Kysely<any>): Promise<void> {
  await db.schema
    .createTable('users')
    .addColumn('id', 'serial', (col) => col.primaryKey())
    .addColumn('name', 'text', (col) => col.notNull())
    .addColumn('email', 'text', (col) => col.unique().notNull())
    .addColumn('age', 'integer')
    .execute();
}

async function down(db: Kysely<any>): Promise<void> {
  await db.schema.dropTable('users').execute();
}

이러한 수동 방식은 복잡한 스키마 변경에서 실수할 가능성이 높아지고, 특히 큰 프로젝트에서는 작업량이 상당히 증가할 수 있었습니다.

하지만 Kysely의 마이그레이션에도 두 가지 중요한 장점이 있습니다:

  1. TypeScript 기반 마이그레이션: Kysely의 마이그레이션 스크립트는 TypeScript로 작성되기 때문에, 마이그레이션 로직에 애플리케이션 로직을 통합할 수 있습니다. 예를 들어, S3와 같은 오브젝트 스토리지의 데이터도 함께 마이그레이트하는 복잡한 시나리오를 구현할 수 있습니다. 반면 Drizzle ORM은 SQL 기반 마이그레이션이므로 이러한 통합이 불가능합니다.

  2. 양방향 마이그레이션: Kysely는 updown 함수를 모두 정의하여 업그레이드와 다운그레이드를 모두 지원합니다. 이는 특히 팀 협업 환경에서 중요한데, 다른 개발자의 변경사항과 충돌이 발생할 경우 롤백이 필요할 수 있기 때문입니다. Drizzle ORM은 현재 업그레이드만 지원하며, 다운그레이드 기능이 없어 협업 시 불편할 수 있습니다.

참고로, Python 생태계의 SQLAlchemy 마이그레이션 도구인 Alembic은 훨씬 더 발전된 형태의 마이그레이션을 제공합니다. Alembic은 비선형적인 마이그레이션 경로(브랜치포인트 생성 가능)를 지원하여 복잡한 팀 개발 환경에서도 유연하게 대응할 수 있습니다. 이상적으로는 JavaScript/TypeScript 생태계의 ORM도 이러한 수준의 마이그레이션 도구를 제공하는 것이 바람직합니다.

관계 설정의 용이성

Drizzle ORM에서 테이블 간 관계 설정이 매우 직관적이었습니다:

import { relations } from 'drizzle-orm';

export const usersRelations = relations(users, ({ one, many }) => ({
  profile: one(profiles, {
    fields: [users.id],
    references: [profiles.userId],
  }),
  posts: many(posts)
}));

이 방식은 데이터베이스 설계의 본질적인, 관계적인 측면을 명확하게 표현해주었습니다.

쿼리 작성의 편의성과 동일 이름 칼럼 문제 처리

두 ORM 모두 쿼리 작성을 위한 API를 제공하지만, Drizzle의 접근 방식이 더 직관적이고 관계형 모델을 활용하기 쉬웠습니다:

// Drizzle ORM - db.query 방식으로 관계 활용
const result = await db.query.posts.findMany({
  where: eq(posts.published, true),
  with: {
    user: true  // 게시물 작성자 정보를 함께 조회
  }
});

// 결과 접근이 직관적이고 타입 안전함
console.log(result[0].title);       // 게시물 제목
console.log(result[0].user.name);   // 작성자 이름 - 객체 구조로 명확하게 구분됨
console.log(result[0].user.id);     // 작성자 ID - 게시물 ID와 이름이 같아도 문제 없음

// Kysely
const result = await db
  .selectFrom('posts')
  .where('posts.published', '=', true)
  .leftJoin('users', 'posts.userId', 'users.id')
  .selectAll();

// 결과 접근 시 칼럼 이름 충돌 문제
console.log(result[0].id) // 오류: posts.id와 users.id 중 어떤 것인지 모호함
console.log(result[0].name) // 오류: 둘 다 name 칼럼이 있다면 모호함

Drizzle의 접근 방식이 테이블과 컬럼을 참조할 때 타입 안전성을 더 강력하게 보장하고, 관계를 활용한 쿼리 작성이 더 직관적이었습니다.

특히 여러 테이블 조인 시 동일한 이름의 칼럼 처리 부분에서 Drizzle ORM이 훨씬 더 편리했습니다. 이는 제 개발 경험에서 가장 중요한 차이점 중 하나였습니다.

// Drizzle ORM - 동일 이름 칼럼 처리
const result = await db.query.posts.findMany({
  with: {
    user: true  // posts.id와 users.id가 모두 있지만 자동으로 구분됨
  }
});

// 결과에 자연스럽게 접근 가능
console.log(result[0].id);        // 게시물 ID
console.log(result[0].user.id);   // 사용자 ID - 명확하게 구분됨
console.log(result[0].user.name); // 사용자 이름

// Kysely - 동일 이름 칼럼 처리를 위해 별칭 필요
const result = await db
  .selectFrom('posts')
  .leftJoin('users', 'posts.userId', 'users.id')
  .select([
    'posts.id as postId',       // 별칭 필수
    'posts.title',
    'posts.content',
    'users.id as userId',       // 별칭 필수
    'users.name as userName',   // 칼럼 이름이 같을 수 있으므로 별칭 필수
    'users.email as userEmail'  // 일관성을 위해 모든 사용자 관련 칼럼에 접두어 필요
  ]);

// 별칭을 통한 접근
console.log(result[0].postId);    // 게시물 ID
console.log(result[0].userId);    // 사용자 ID
console.log(result[0].userName);  // 사용자 이름

Drizzle ORM은 테이블과 칼럼을 객체로 참조하기 때문에, 동일한 이름의 칼럼이 있어도 자연스럽게 계층 구조로 처리되며 타입 추론도 정확하게 작동합니다. 반면 Kysely에서는 문자열 기반 접근 방식 때문에 별칭을 수동으로 지정해야 하는 경우가 많았고, 복잡한 조인에서 이런 작업이 번거로워졌습니다. 특히 여러 테이블에 같은 이름의 칼럼이 많을수록 모든 칼럼에 명시적인 별칭을 지정해야 하는 불편함이 있었습니다.

또한 Drizzle ORM은 결과 타입을 자동으로 정확하게 추론해주어 별도의 타입 지정 없이도 안전하게 결과를 사용할 수 있었습니다.

Kysely의 장점

물론 Kysely도 여러 강점이 있습니다:

  1. 더 가벼운 구조: 필요한 기능만 포함할 수 있는 모듈화된 구조
  2. SQL에 더 가까운 접근: SQL 구문에 매우 충실한 API 설계
  3. 유연성: 복잡한 쿼리에서 때로 더 유연한 작성이 가능

또한 앞서 언급했듯이, Kysely의 TypeScript 기반 마이그레이션과 양방향(up/down) 마이그레이션 지원은 특정 상황에서 Drizzle ORM보다 우위에 있는 기능입니다.

SQLAlchemy와의 비교 및 앞으로의 기대

JavaScript/TypeScript 생태계의 ORM을 이야기하기 전에, 여러 언어 중에서도 Python의 SQLAlchemy는 특별한 위치를 차지합니다. 개인적으로 여태 사용해본 다양한 언어의 ORM 중에서 SQLAlchemy가 가장 기능이 풍부하고 강력하다고 느꼈습니다. 복잡한 쿼리 구성, 고급 관계 매핑, 트랜잭션 관리, 이벤트 시스템 등 SQLAlchemy의 기능은 정말 방대합니다.

Drizzle ORM은 JavaScript 생태계에서 매우 인상적인 발전을 이루었지만, 아직 SQLAlchemy의 경지에는 이르지 못했다고 생각합니다. 특히 다음과 같은 부분에서 SQLAlchemy의 성숙도와 기능 풍부함이 돋보입니다:

  • 복잡한 서브쿼리와 윈도우 함수 지원
  • 다양한 이벤트 리스너와 훅
  • 다양한 상속 전략
  • 복잡한 트랜잭션 관리와 세션 관리
  • 대규모 프로젝트에서 검증된 안정성
  • Alembic을 통한 비선형적 마이그레이션 지원
  • 놀라울 정도로 방대하고 상세한 문서화

결론

두 ORM 모두 훌륭한 도구이지만, 제 개발 스타일과 프로젝트 요구사항에는 Drizzle ORM이 더 잘 맞았습니다. 특히 스키마 정의의 직관성, 강력한 마이그레이션 도구, 그리고 전반적인 개발자 경험 측면에서 Drizzle ORM이 더 생산적인 개발을 가능하게 해주었습니다.

동일 이름 칼럼 처리와 같은 실질적인 문제에서 Drizzle ORM의 객체 기반 접근 방식이 가져다주는 편리함은 실제 프로젝트에서 큰 차이를 만들었습니다.

ORM 선택은 결국 프로젝트 특성과 개인 선호도에 크게 좌우됩니다. 새로운 프로젝트를 시작한다면 두 도구 모두 간단히 테스트해보고 자신의 워크플로우에 더 적합한 것을 선택하는 것이 좋겠지만, 제 경우에는 Drizzle ORM이 명확한 승자였습니다.

앞으로 Drizzle ORM이 더욱 발전하여 SQLAlchemy 수준의 풍부한 기능과 유연성을 제공하게 되길 바랍니다. JavaScript/TypeScript 생태계에도 그런 수준의 강력한 ORM이 있으면 좋겠습니다. 다행히도 Drizzle ORM은 계속해서 발전하고 있으며, 그 발전 속도를 보면 기대가 큽니다.

여러분의 경험은 어떤가요? 다른 ORM 도구나 언어를 사용해보셨다면 의견을 공유해주세요!

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

Hackers' PubにLLMを活用した記事の自動翻訳機能が追加されました。これにより、Hackers' Pubに投稿された英語や韓国語の記事を日本語で閲覧できるだけでなく、日本語で書いた記事を海外の読者に紹介する事も可能に成りました。

なお、Hackers' Pubは招待制で運営されています。ご興味のある方は、DMでメールアドレスを教えていただければ、招待いたします。

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub


LLM 기반의 게시글 번역 기능이 추가되었습니다. 우선, 자신이 쓴 게시글이 LLM을 이용해 번역되는 것을 허용하려면, 게시글 공개 설정에서 “LLM 기반 자동 번역 허용” 옵션을 켜 주셔야 합니다. 기존 게시글은 모두 이 옵션이 꺼져 있습니다만, 새로 쓰는 게시글의 경우 기본적으로 켜져 있습니다.

한국어판 게시글 공개 설정 페이지에 추가된 “LLM 기반 자동 번역 허용” 옵션
한국어판 게시글 공개 설정 페이지에 추가된 “LLM 기반 자동 번역 허용” 옵션
영어판 게시물 공개 설정 페이지에 추가된 “Allow LLM-powered automatic translation” 옵션
영어판 게시물 공개 설정 페이지에 추가된 “Allow LLM-powered automatic translation” 옵션

위와 같이 옵션을 켜 준 게시글은 위쪽에 다음과 같이 “다른 언어로 읽기” 메뉴가 표시되게 됩니다. 이 메뉴에 나오는 언어 목록은 언어 설정에서 정할 수 있습니다.

게시글 첫 부분에 표시되는 “다른 언어로 읽기” 메뉴 (한국어판)
게시글 첫 부분에 표시되는 “다른 언어로 읽기” 메뉴 (한국어판)
게시글 첫 부분에 표시되는 “Read in other languages” 메뉴 (영어판)
게시글 첫 부분에 표시되는 “Read in other languages” 메뉴 (영어판)

이 중에서 이미 번역이 완료된 언어는 바로 표시되지만, 아직 번역이 완료되지 않은 언어의 경우, 아래와 같이 기다리라는 메시지가 뜨게 됩니다. 게시글의 분량에 따라 번역 시간은 차이가 나지만, 짧으면 30초에서 길면 5분 정도 걸립니다.

게시글이 번역중이라는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역중입니다. 번역이 완료될 때까지 기다려 주세요.”
게시글이 번역중이라는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역중입니다. 번역이 완료될 때까지 기다려 주세요.”
게시글이 번역중이라는 메시지 (영어판): “This article is being translated from Korean to English. Please wait until the translation is complete.”
게시글이 번역중이라는 메시지 (영어판): “This article is being translated from Korean to English. Please wait until the translation is complete.”

번역이 완료되면, 아래와 같이 메시지가 바뀝니다.

게시글의 번역본 상단에 뜨는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역되었습니다.”
게시글의 번역본 상단에 뜨는 메시지 (한국어판): “이 게시글은 영어에서 한국어로 번역되었습니다.”
게시글의 번역본 상단에 뜨는 메시지 (영어판): “This article has been translated from Korean to English.”
게시글의 번역본 상단에 뜨는 메시지 (영어판): “This article has been translated from Korean to English.”

번역 기능은 제가 Hackers' Pub을 맨 처음 구상할 때부터 핵심 기능으로 고려하고 있던 것이었습니다. 소프트웨어 프로그래머로서 일정 수준 이상 성장하기 위해서는 반드시 영어를 배워야만 하는 불합리함이나 그리고 일본어나 중국어 등 영어가 아닌 언어로 쓰인 다양한 자료에 대부분의 외국인은 접근하지 못한다는 아쉬움을 오래 전부터 느꼈기 때문입니다. 다행히 얼마 전부터 LLM의 번역 품질이 아주 좋아졌고, 이를 활용하여 꽤 괜찮은 품질의 번역 기능을 Hackers' Pub 같은 작은 웹사이트에서도 구현할 수 있게 되었네요.

참고로 현재 번역에 쓰이는 모델은 Claude Sonnet 3.7입니다. 저렴하다고는 할 수 없는 모델인데요. 시범적으로 운영해 보고, 비용이 너무 부담된다고 여겨지면 Gemini 2.5 Flash 같은 다른 모델로 전환하는 것도 고려하고 있습니다.

아무튼, 모처럼 추가한 번역 기능이니 많은 분들이 유용함을 누리셨으면 좋겠습니다.

아래는 제가 샘플로 미리 만들어 둔 번역본들입니다:

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

카카오톡은 Linux 버전을 내놓든가 아니면 웹 버전을 내놓아라! (아니, 그냥 사람들이 카카오톡을 이제 그만 썼으면 좋겠다…)

dansup's avatar
dansup

@dansup@mastodon.social

This new FediDB v2 webapp can be self-hosted btw!

Working on adding a few new pages/features to FediDB, including:

- translation support (i18n)
- a federated wiki (👀)
- apps + clients
- popular accounts
- viral topics
- trends
- quarterly reports
- stats overview w/ geomaps + advanced filtering

And much more ✨

> git clone github.com/fedidb/fedidb-nuxt

🔗 : new.fedidb.org/

Deno's avatar
Deno

@deno_land@fosstodon.org

Deno 2.3 is here:
🌱 deno compile with FFI & Node native add-ons
📦 Local npm packages
⭐ deno fmt CSS/HTML/SQL in tagged templates
🔭 OTel event recording & tracing in distributed services
and more —

deno.com/blog/v2.3

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hackers.pub

.github/copilot-instructions.md, .cursorrules, .windsurfrules, CLAUDE.md… 이것 말고도 많이 있을텐데, 어차피 들어가야 하는 내용은 다 거기서 거기. 지금은 한 파일에 적고 심볼릭 링크로 같은 곳을 바라보게 하고 있지만, .editorconfig처럼 그냥 어떤 식으로든 표준화가 되었으면 좋겠다.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

@hollo 따로 글이 지워지거나 옮겨지지는 않고요, 팔로워가 새 계정으로 옮겨집니다. 그리고 예전 계정은 아마 못 쓰게 될 겁니다. 로그인은 되는데 새 글을 올리거나 하는 게 막힐 거예요.

kiwiyou's avatar
kiwiyou

@kiwiyou@twt.rs

고기 먹으러 와서 이체자 찾기
焼き肉屋で異体字探し
(1) 石雲樓
(2) 睡穩葉舟輕,風徴浪不驚。仼君蘆葦㟁,終夜動秋聲。

robin's avatar
robin

@robin_maki@planet.moe

출시했다
typie.co

정진명의 굳이 써서 남기는 생각's avatar
정진명의 굳이 써서 남기는 생각

@jm@guji.jjme.me

『사회적 배제Social Exclusion』란 개인이 삶의 경제적, 사회적, 정치적, 또는 문화적 측면에서 온전히 참여할 수 없는 상태와 그런 상태를 유지하거나 그런 상태로 만드려는 과정을 가리키는 말입니다.(Report on the World Social Situation 2016, p.19)

『사회적 배제주의Social Exclusionism』라는 말은, 더 좋은 표현이 있을지도 모르겠지만, 그런 상태를 추구하는 움직임을 가리키기 위해 붙인 이름입니다. 대충 다음과 같은 사례들, 그런 사례를 옹호하고 주장하는 사례들을 보다가 이 문서를 쓰게 되었습니다.

  • 범죄자에 대한 극형, 제도적 사회 배제 요구
  • 장애인의 이동권 묵살 및 부적절한 시설 수용 행태에 대한 합리화
  • 성노동자 및 탈성노동자의 발언권 압수 시도와 탈성매매에 대한 방해
  • 미등록 상태/등록 상태의 이주노동자에 대한 차별 요구와 처우에 대한 합리화
  • 다양성에 대한 백래시

이런 사례의 대부분은, 사회적으로 배제하려는 대상이 사회에 어떻게 존재하는지에 대해 알려고 시도하지 않는 것과, '어쨌든 나는 보기 싫다'는 심리를 사회가 동의해야 한다고 믿는 자기중심적인 사고에서 온다고 생각합니다.

우리 사회 구조의 많은 장치들은 힘을 가진 권력자―대개는 국가겠지요―가 개인―사람을 포함하겠지만, 국가만큼이나 힘이 있는 자본가나 기업도 여기 포함되겠지요―에게 할 수 있는 폭거를 제지하기 위한 장치라고 생각합니다. 민주주의 사회라면 가져야 할 표현의 자유, 정치 참여의 자유 같은 개념들은, 사실 개인과 개인의 관계를 규정하기 위한 도구가 아니었다는 것이 제 생각입니다. 그만큼 국가가 개인에 대해서 행할 수 있는 폭거에 대해서는 우리가 여러 시행착오를 거쳐 여기까지 왔다고 생각합니다.

그렇다면 민주주의 사회에서, 그러니까 한 사람 한 사람이 주권을 가져야 하는 사회에서, 그 주권자들이 "어떠한 사람들을 사회적으로 배제해야 한다"고 주장한다면, 그것은 무엇으로 다스려야 할까요? 다스릴 수 있는 것일까요? 어떤 근거로? 누가? 저는 이 문제에 답해야 한다고 생각하지만, 어떻게 답을 내릴 수 있을지는 모르겠습니다.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

@hollo 감사합니다. Railway 설정 매뉴얼은 업데이트하도록 하겠습니다.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

@hollo 프로필 사진을 설정 안 하셔서 그 페이지에서 맨 처음으로 나오는 이미지가 걸린 것 같네요.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

@hollo 네, S3에는 이미지나 비디오 같은 미디어만 저장합니다.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

ソフトウェア開発に関する韓国語圏および英語圏の記事をLLMを活用して日本語に自動翻訳した記事が投稿されるサービスが有れば、利用する意向は有りますか?

OptionVoters
購読する6 (19%)
時々確認する18 (56%)
利用しない8 (25%)
洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

ソフトウェア開発に関する韓国語圏および英語圏の記事をLLMを活用して日本語に自動翻訳した記事が投稿されるサービスが有れば、利用する意向は有りますか?

OptionVoters
購読する6 (19%)
時々確認する18 (56%)
利用しない8 (25%)
洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to Woojin Kim's post

@me iOS 내장 한국어 키보드에 “이중 언어”라는 옵션이 생겼더라고요.

https://raycat.net/484123

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to Woojin Kim's post

@me iOS에 그런 기능이 최근 들어왔던 것 같던데요!

Hollo :hollo:'s avatar
Hollo :hollo:

@hollo@hollo.social

We're pleased to announce that has been included in the Nivenly Fediverse Security Fund program!

The @nivenly Foundation has launched a security bounty fund to support contributors who identify and help fix vulnerabilities in popular software. Both Hollo and @fedify are among the selected projects that meet their responsible security disclosure requirements.

This program will run from April–September 2025, with bounties of $250–$500 USD for high and critical security vulnerabilities.

We're honored to be recognized alongside other established fediverse projects like Mastodon, Misskey, and Lemmy. This further encourages our commitment to maintaining strong security practices.

If you're interested in contributing to Hollo's security, please follow our responsible disclosure process outlined in our SECURITY.md file.

Learn more about the program:

https://nivenly.org/blog/2025/04/01/nivenly-fediverse-security-fund/

Fedify: ActivityPub server framework's avatar
Fedify: ActivityPub server framework

@fedify@hollo.social

We're pleased to announce that has been included in the Nivenly Fediverse Security Fund program!

The @nivenly Foundation has launched a security bounty fund to support contributors who identify and help fix vulnerabilities in popular software. Both Fedify and @hollo are among the selected projects that meet their responsible security disclosure requirements.

This program will run from April–September 2025, with bounties of $250–$500 USD for high and critical security vulnerabilities.

We're honored to be recognized alongside other established fediverse projects like Mastodon, Misskey, and Lemmy. This further encourages our commitment to maintaining strong security practices.

If you're interested in contributing to Fedify's security, please follow our responsible disclosure process outlined in our SECURITY.md file.

Learn more about the program:

https://nivenly.org/blog/2025/04/01/nivenly-fediverse-security-fund/

🕊️ rins's avatar
🕊️ rins

@rns_8i8@calc.rettuce.page

おひとり様サーバーで見るHolloとMitra :: rettuce
rettuce.page/posts/fediverse-hollo-and-mitra/
3ヶ月くらいあたためていた日記を書きました

GENKI's avatar
GENKI

@nibushibu@vivaldi.net

素晴らしい :clapping:

新しい分散/連合型SNS「Pulsate」を開発している - /dev/sdR2 laminne.hatenablog.jp/entry/20

Evan Prodromou's avatar
Evan Prodromou

@evanprodromou@socialwebfoundation.org

I'm making an initial version of places.pub available today. places.pub is a collection of Place objects suitable for use in geosocial applications on the ActivityPub network. Part of my work in the Social Web Community Group at the W3C has been participation in the GeoSocial Task Force. This is a sub-group of the SocialCG that focuses on implementing user stories in ActivityPub related to the intersection of geographical systems and social networking, for example, tagging an image with […]

I’m making an initial version of places.pub available today. places.pub is a collection of Place objects suitable for use in geosocial applications on the ActivityPub network.

Part of my work in the Social Web Community Group at the W3C has been participation in the GeoSocial Task Force. This is a sub-group of the SocialCG that focuses on implementing user stories in ActivityPub related to the intersection of geographical systems and social networking, for example, tagging an image with the place it represents, or checking in to a location.

One important need for geosocial software is that all objects in ActivityPub, including Place objects, need to have a permanent URL as their id property, which shares the description of that object in Activity Streams 2.0 format. However, there isn’t a good dataset of geographical objects — countries, states or provinces or regions, cities, buildings, businesses, parks, streets — available in AS2 on the Web right now. That is slowing down experimentation in the Geosocial Task Force.

Using the service

So, I worked on making places.pub for geosocial hackers to experiment with. It’s a service that exposes places from the amazing OpenStreetMap collection of data as AS2 objects on the Web. So, given an OpenStreetMap object like the Rogers Centre Ottawa, it provides an AS2 version suitable for use in geosocial activities in ActivityPub. It also has a rudimentary search mechanism, although I think most users will want to use the Nominatim service for searching the OpenStreetMap database, and then map the IDs onto places.pub.

Once you know the places.pub ID for a place, you can use it for geotagging objects, people, activities, or using special geosocial activity types like check in, check out, and travel. There is a good list of examples on the places.pub home page, but obviously this is not an exhaustive list!

How it is built

This wasn’t my first time trying to build places.pub; I’d done two earlier versions with different architectures and the same interface. The first time out, about 7 years ago, I created a full NodeJS server that used a full mirror of the OpenStreetMap database, so I didn’t need to hit the OSM API to fetch data. It worked pretty well, but it was really expensive — hundreds of dollars per month to keep a database server of that size running and synched.

I tried a second version a few months ago, which did batch generation of AS2 Place objects from the OpenStreetMap exports, and then uploaded them to the S3 service at Amazon Web Services. This was a whole lot cheaper, but it took a long time to download, convert, and re-upload the data.

This third implementation, with source code available on GitHub, is a little bit easier than both. Instead of sloshing the huge OSM dataset back and forth, I used the version of the data stored in the Google Cloud Public Datasets system on BigQuery. This let me ignore the effort of moving data, and just focus on giving it a good ActivityPub-compatible interface using a Google Cloud Run function. It seems to work pretty nicely.

Next steps

I’d love to see some experimentation with using places.pub for geosocial activity in the social web. I’m going to work on some implementations in my own ActivityPub software. If you find problems with the software, please add an issue on GitHub or let me know on the Fediverse at @evanprodromou.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to wakest ⁂'s post

@liaizon @smallcircles @rysiek @index I guess it's because Mastodon assumes fedi handles are immutable…?

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

()】의 마지막 ()을 이렇게 쓰기도 하는구나.

Patrick Wu :neocat_flag_bi:'s avatar
Patrick Wu :neocat_flag_bi:

@patrick@o0o.social

今日偶遇舊字形

just small circles 🕊's avatar
just small circles 🕊

@smallcircles@social.coop

"The Good, the Bad and the Ugly" is a good article by @dominik

chrastecky.dev/technology/acti

The two mentioned examples in "The Bad" are long-time issues that were also discussed at . I just responded to one of them on the forum..

The Update(Note) quirk. socialhub.activitypub.rocks/t/

The other one is around Direct Messages which are a hack (a Note with special sauce). specifies ChatMessage object type here, which is the intended way to extend the protocol.

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to Sebastian Lasse's post

@sl007 Thanks for sharing this interesting approach! I'd be very interested in looking at your code once it's completed. The way you're handling ActivityPub data with Deno KV sounds promising, especially your methods for versioning and avoiding duplicates. Please let me know when it's available to check out!

洪 民憙 (Hong Minhee) :nonbinary:'s avatar
洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social · Reply to Jaeyeol Lee (a.k.a. kodingwarrior) :vim:'s post

@kodingwarrior 😥

← Newer
Older →