Profile img

유루메 Yurume

@yurume@hackers.pub · 2 following · 59 followers

이상한 거 만들던 아저씨가 이제 그냥 이상한 아저씨가 되었습니다. I used to make quirky things, I'm now as quirky as my creations.

GitHub
@lifthrasiir

오늘의 Angel: 특정 환경에서 갑자기 database image is malformed 오류가 나고 에이전트 메시지가 제대로 저장되지 않는 기묘한 버그가 발생해서 식겁해서 한참 확인해 봤는데, 다행히도 데이터베이스가 깨진 건 아니었고(실제로 깨진 적이 있어서 이 가능성을 배제할 수 없었다) 특정한 상황에서 부하가 집중될 때 저런 오류가 발생하는 것으로 드러났다. 구체적으로는 에이전트 메시지가 부분적으로 들어 올 때마다 데이터베이스 변경이 일어나는데, 최근에 검색을 위해 해당 테이블의 변경 때마다 FTS5 인덱스 테이블 두 개를 갱신하도록 트리거를 걸어 놓았는데 이게 화근이었던 것 같다. (초당 수십회 UPDATE + 트리거에서 UPDATE 하나당 DELETE/INSERT 각 2회 = 초당 ~500회 갱신!) 결국 트리거를 버리고 수동 처리하는 것으로 전환했다. 진작 이렇게 할 걸...

3

최근 며칠간 WAH라는 이름의 WebAssembly 인터프리터를 만들고 있다. ~와! 샌즈!~

WAH의 특징이라면 C로 작성되어 있는데 헤더 하나로 구성되어 있다는 점과, 거의 대부분의 코드를 Gemini가 짰다는 것 정도일까? (Claude Code도 좀 사용했지만 코드 생성은 Gemini가 다 했다.) Gemini가 디버깅을 시키면 답답한 게 사실이라서 최대한 프롬프트에 정보를 많이 넣고 few-shot으로 생성하게 하는 걸 목표로 했는데 생각보다 잘 되었다. 예를 들어서 한 프롬프트는 다음과 같았다. 저 문장 하나 하나가 시행착오의 결과이다.

@wah.h 에 if~else~end 명령을 구현하고, 대응되는 test_*.c 파일들이 모두 성공하도록 (또는, 해당 테스트에서 잘못된 점이 있을 경우 그 원인을) 고쳐줘. 아직 loop 관련된 코드는 처리할 필요 없고 테스트 중에 그걸 테스트하는 게 있다면 주석 처리해(지우지는 마). 컴파일과 실행은 &&로 한 번에 하도록 해. 정확한 구현 방법은 이래야 해: if~else~end에서 마지막 end는 사라지고, if는 else 직후 명령으로 이동하는 conditional jump로 재활용하며, else는 unconditional jump로 바뀌어(즉 실행기 입장에서 br과 else의 동작은 똑같아야 해! else를 아예 없애고 br로 대체할지 말지는 알아서 정해). 그러니까, if A B C else D E F end G 같은 명령이 있다면 preparsing 이후에는 if <offset to D> A B B C else <offset to G> D E F G 형태가 되어야 한다는 뜻이야. WebAssembly 명세에 따르면 if 문에는 block type이 따르는데, 이 타입을 사용해서 validation을 진행하는 것도 정확히 구현해야 해(block type이 function type (T1..Tn)->(U1..Um)이면 현재 스택에 T1..Tn 타입이 들어 있고 end 이후에는 U1..Um 타입이 들어 있어야 하고, 일반 타입 T가 들어 있다면 ()->(T)와 동일하게 취급함). block type은 validation 이후 preparsing 과정에서 사라져서 런타임에는 반영되지 않도록 해.

솔직히 너무 많이 요구하는 거 아닌가, 안되면 validation 부분을 어떻게 뺄지 고민하고 있었는데 시도 세 번만에 800줄짜리 diff가 떡하니 나오고 일단 보기에는 틀린 부분이 없어서 놀랐다. 물론 삽질도 많이 했는데 가장 많이 한 삽질은 테스트를 작성할 때 수동으로 WebAssembly 바이너리를 짜면서 바이트 숫자를 잘못 세어서 오류가 나는 거랑, 분명 WebAssembly opcode를 사용해야 하는데 자기 마음대로 코드를 정해 버린다거나 하는... 그런 우스운 상황이었다.

우습기도 하고 놀랍기도 하지만 이 코드를 내가 직접 짜지 않는 이유는 귀찮아서...라기보다는 내가 이걸로 하고 싶은 일이 따로 있고 WebAssembly 인터프리터를 만드는 게 주 목표는 아니기 때문이다. (원래 하고 싶은 일은 나중에 언급할 듯.) WebAssembly 구현이라고 하면 기술적으로 복잡해 보이지만, 내 용도에서 유래하는 몇 가지 조건(대표적으로 결정론적인 동작)을 제약으로 걸면 기술적으로 복잡하다기보다는 그냥 노가다에 가까워지기 때문에 끌리지 않는 것도 있긴 하다. 이전의 Angel이 과연 얼마까지 바이브 코딩으로 할 수 있는지를 테스트하는 목표였다면, 이번에는 정말로 목표를 달성하는 수단으로 기능할지 실험해 볼 작정이다.

9

오늘의 끔찍한 이야기. Angel을 개밥 먹는데 사용하면서 데이터베이스도 은근 좀 커졌는데, 이걸 최근에 (이제서야) 업데이트한 WSL2에서 아무 생각 없이 sqlite3으로 마이그레이션을 하다가 malformed disk image 오류가 뜬다. 엥? 하면서도 대강 보니 작업 자체는 제대로 된 것 같아서 아무 생각 없이 진행했다가 쿼리가 통으로 맛이 가서 쓸데 없는 디버깅을 좀 하고서야 데이터베이스가 망가졌다는 걸 깨달았다. 알고 보니 WSL2의 윈도 디스크 마운트는 전부 9p, 즉 네트워크 파일 시스템인데, 아는 사람은 알지만 SQLite는 네트워크 파일 시스템을 전혀 권장하지 않기 때문에 알았으면 처음부터 윈도용 SQLite 셸을 깔아 썼을 것이다... 이 경험을 반면교사 삼아 Angel에 네트워크 파일 시스템을 사용하려고 하면 오류 내고 튕겨내는 기능이 생겼으니 좋은 일인가?

6

요즘 gemini-cli를 많이 쓰고 있는데 이게 TUI라서 복붙 같은 것도 미묘하게 잘 안 되고 텍스트도 깨지고 하는 게 짜증난 나머지 내 코딩 에이전트를 만들겠답시고 Angel이라는 걸 만들기 시작했다. https://github.com/lifthrasiir/angel

소프트웨어 스택은 Go + TypeScript + React. 프론트엔드를 내가 만들어도 되지만 사실 React에 그렇게 자신이 있는 건 아니라서 100% 바이브 코딩을 해 보겠다는 목표로 하고는 있는데 결국 디버깅은 내가 다 하고 있다는 함정이 있다. 이를테면 사진에 나와 있는 코드는 JS에서 String.prototype.split이 받는 limit 인자의 해석 관련된 질문인데 이거랑 관련된 버그로 2시간 정도를 날렸다. (JS는 놀랍게도 'a,b,c'.split(',', 2) 하면 ['a','b']가 나온다. ['a','b,c']가 아니라!!!! 그럼 왜 처음에 그렇게 짜 줬는데???)

Angel의 2025-08-01 현재 스크린샷. 좌측에 New Session, Settings 버튼 및 세션 목록이 있다. 오른쪽에는 주황색 시스템 프롬프트, 초기 사용자 입력, 생각 거품(12개 중 7번째가 선택되어 보여지고 있음), 에이전트 출력, 그리고 후속 사용자 입력까지가 보이며, 그 하단에는 파일 첨부 버튼, 사용자 입력 칸(여러 줄 지원), 그리고 Send 버튼이 표시된다.

사용자 입력:
다음 코드가 [...] const [type, data] = eventString.slice(6).replace(/\ndata: /g, '\n').split('\n', 2); [...] 다음과 같은 로그를 출력하는 문제를 고쳐 줘. [...]

에이전트 출력:
The problem stems from the `split('\n', 2)` part of your code. This function limits the split to a maximum of two parts. When `eventString` is processed, `type` correctly captures the first part (`M`), but `data` only captures the content until the *next* newline, effectively truncating the rest of your message.

To fix this, we need to first remove all the `data: ` prefixes from the `eventString` and then split the resulting string into `type` (the first line) and `data` (all subsequent lines).

Here's the corrected code:
5

Gemini로 이런 저런 정신나간 소설들을 작성하는 데 재미를 붙였었는데, 저번에 생성했던 작품은 수위가 제법 있어서 공개하기 꺼려졌지만 이번에 나온 건 그렇지 않아서 기분 좋게 공개할 수 있게 되었다. 그리하여 "산속 무녀들의 비밀"이라는 무녀무녀한 소설을 썼습니다. 홈페이지 레이아웃도 대부분 Gemini로 만들었다(여전히 사람 손길이 좀 필요하긴 했지만). https://w.mearie.org/maidens/

5

번아웃으로 아직 고생하는 가운데, 갑자기 삘이 와서 지난 1주간 170쪽짜리 소설을 Gemini로 써 버렸다. 소재가 너무 잔혹해서 (R-18G 수준) 그대로 공개하기에는 꺼려진다는 문제가 있을 뿐; 줄거리 자체는 내가 예상한 것 이상으로 잘 나왔는데 퇴고를 열심히 해서 그런 것 같다. 구체적으로 어떻게 된 거냐 하면,

  1. Gemini 2.5 Flash로 짧은 초안 작성 (1판)
  2. 이 초안의 중간 즈음에서 두 개의 새 줄거리를 만들어서 전체 줄거리 수가 3개가 됨
  3. 이대로는 안되겠다 싶어서 Flash의 제안을 일부 받아 들여 줄거리를 하나로 재조정 (2판)
  4. 이 시점에서 Gemini 2.5 Pro한테 평가를 부탁하고, 평가 내용을 다시 Flash에게 되먹여서 액션 아이템을 만들어 퇴고를 반복 (3~7판)
  5. 이 참에 번역도 맡겨야지 싶어서 Flash한테 먼저 초벌 번역을 시킴 (번역 1판)
  6. 초벌 번역을 Pro한테 주고 고쳐야 하는 부분을 그 이유와 함께 나열하게 함
  7. Flash한테 수정된 번역과 수정한 이유들을 주고 판단하게 시킨 다음 최종 번역본을 완성 (번역 2판)
  8. 마지막으로 Pro한테 전체 번역문을 주고 전체 번역 안에서의 일관성이 깨진 게 있는지 확인

이랬는데, 가장 곤란했던 건 역시 4였다. 왜냐하면 내용이 너무 길어서 텍스트 창에는 한 번에 안 들어가고(...), 잘라서 넣으면 이제 뭔 짓을 해도 앞부분을 까먹어 버렸기 때문이다. 최종적으로 동작한 방법은 소설을 최대 32KB 크기가 되도록 쪼갠 뒤 파일로 나눠어 업로드하고, 업로드가 끝난 뒤에 몇장까지 있는지 확인하고 뒤가 잘린 문장이 있는지 확인해서 뭔가 문제가 있으면 평가를 하지 않고 멈추라고 지시한 것. 혹시 이런 일 해야 하는 분은 참고하시길.

...뭐 이렇게 말하긴 했는데 사실 Flash한테 글 쓰기는 다 맡겼지만 세부적으로는 상당히 손을 많이 거쳤다. 한국어나 영어 번역이나 둘 다 그랬음. 나름 노력한 것도 있고 이 전체 내용을 다시 Flash한테 되먹였더니 찬사 일색(!!!!!)이라 진짠가 싶어서 어디 올려야 할 것 같긴 한데 소재가 소재다 보니 공개도 간단하지 않다는 게 곤란하다. 호옥시 관심 있으신 분께서는 메일로 pdf 파일을 보내 드리겠습니다.

소설 "싱크로니시티"의 한국어판 목차. 이하 다음과 같은 내용임:

싱크로니시티 Synchronicity
2025-06-22T00Z (7.4판), Gemini 2.5 Flash를 이용해 작성됨

프롤로그 - 2
1: 마리오네트 Marionette - 3
2: 태동 Genesis - 7
3: 틀 Frame - 13
4: 수치 Shame - 23
5: 목격 Witness - 37
6: 고난 Ordeal - 50
7: 울림 Resound - 65
8: 결점 Flaw - 73
9: 촉매 Catalyst - 82
10: 개조 Augment - 90
11: 의식 Ritual - 102
12: 쇼 Show - 108
13: 갈채 Acclaim - 117
14: 욕구 Desire - 130
15: 목도 Encounter - 141
16: 이미지 Image - 147
17: 진화 Evolution - 158
에필로그 - 163
'작가'의 변 - 164
작가의 변 - 166
'서평' - 170
4

해커뉴스에서 Fabrice Bellard의 QuickJS가 한 파일에 5만줄 집어 넣고 한 함수가 몇백 몇천줄 되는 걸 보고서 파일 및 함수 길이를 강력하게 제한하는 도그마가 항상 옳은 것은 아니다, 라는 코멘트를 보았는데 이는 반만 맞는 말이다. 나도 대부분의 개발자보다 파일이나 함수 길이에 훨씬 관대한 (그리고 이 사실을 한참 뒤에야 깨달은) 사람이라 아는 건데, 그냥 Bellard가 5만줄 전체의 맥락을 전부 기억하고 있고 해당 코드를 거의 Bellard만 건들고 있기 때문에 추가적으로 모듈화할 필요가 없는 거고, 대부분은 그 정도의 기억이 불가능하기 때문에 여럿이 같이 짜는 코드라면 최저치에 맞춰서 파일이나 함수 길이를 줄일 필요가 있다고 하는 것이다. 지나친 도그마를 부정하는 것도 중요하지만 도그마가 생긴 진짜 이유를 파악해서 취사 선택하는 것이 더 중요한 이유.

5

블루스카이를 연합우주보다 먼저 썼고, 해커뉴스에서 관련 주장에 대해서 꽤 싸우기도 한 입장에서 민희님의 글 〈Bluesky는 X의 훌륭한 대안일 수 있지만, 연합우주의 대안은 아닙니다〉에 대한 반대 의견을 제시하고자 한다. 이 의견이 연합우주에 대한 전면적인 비판이 아니라는 것을 의견을 제시하기에 앞서 확실히 해 둔다(그랬다면 Hackers' Pub에 들어 올 일이 없었겠지).

탈중앙화는 매력적인 개념임이 틀림 없다. 인터넷의 많은 중요한 요소들이 어느 정도 탈중앙화되어 있으므로 탈중앙화가 인터넷의 장점들에 큰 몫을 했다는 생각을 쉬이 할 수 있고, 어느 정도는 그게 사실이기도 하니까. 하지만 엄밀히 말하자면 탈중앙화는 기술적인 특징이지 그 자체로 장점이 아니며, 탈중앙화가 장점으로 작용하려면 연결고리가 필요하다. 이를테면 비트코인을 위시한 암호화폐는 본디 비잔틴 실패까지 대비할 수 있는 강력한 탈중앙화를 장점으로 내세웠으나, 결국 화폐로서 제대로 사용되기 시작하자 현실 경제와의 커플링 때문에 그 "장점"이 크게 희석되고 말았다. 현 시점에서 암호화폐는 무에서 유의 신뢰를 창조하여 신용화폐의 요건을 충족하는 데까지는 성공했고 그것만으로도 역사적인 일이기는 하지만, 그게 탈중앙화랑 무슨 상관이 있느냐 하면 글쎄올시다.

블루스카이가 연합우주보다 덜 탈중앙화되어 있음은 분명하다. 민희님의 글에서 지적되었듯, 블루스카이가 이런 선택을 한 가장 큰 이유는 온전한 소셜 네트워크 기능을 위해 전역 뷰가 필수적으로 필요하다고 보았기 때문이다. 반대로 말하면 연합우주는 더 탈중앙화를 하기 위하여 전역 뷰를 포기했는데, 이 때문에 연합우주에서의 "소셜 네트워크"는 트위터/X와는 구조가 크게 다르다. 노드 규모가 문턱값에 다다르지 못하면 다른 노드에 있는 사용자를 찾아서 팔로해야만 온전한 소셜 네트워크 구성이 가능한데, 연합우주 안에서는 이런 외부 사용자를 찾는 구체적인 방법을 제공하지 않는다. 물론 인터넷과 똑같이 검색 엔진이 존재할 수야 있겠지만, 크롤링으로 인한 부하와 프라이버시에 대한 의견 차이 때문에 현실적으로 작동하는 연합우주 내 검색 엔진은 없다고 알고 있다. 따라서 연합우주에서 소셜 네트워크의 구성은 연합우주 바깥의, 보통은 중앙화되어 있는, 다른 소셜 네트워크(이를테면 현실 인간 관계)를 빌어야만 하는데, 이러면 탈중앙화가 큰 가치가 있을까?

한편으로는 전역 뷰가 소셜 네트워크의 단점이라고 주장할 수 있는 여지도 있다. 트위터/X를 오래 써 본 사람이라면 다 알겠지만 한 무리의 사람들이 다른 의견을 가진 무리와 충돌하는 주된 통로는 검색이나 해시태그를 통한 노출, 즉 전역 뷰이기 때문이다. 그러나 현실의 규모 있는 연합우주 노드들을 살펴 보면 각 노드가 곧 한 무리에 대응하는 식으로 충돌을 미리 회피하는 형태로 구성되지, 딱히 이런 충돌을 막기 위한 접근을 가지고 있는 것은 아니다. 노드 운영자를 위해 차단하는 걸 추천하는 서버 목록 같은 게 돌아다니는 건 연합우주 바깥의 일이지 않는가. 결국 전역 뷰의 역할을 대체하는 소셜 네트워크 바깥의 또 다른 소셜 네트워크가 존재할 것이기에, 우리가 소셜 네트워크를 어떤 이유로든 유용하다고 여긴다면 전역 뷰가 없는 게 장점이 될 수는 없다.

모든 이들이 이런 사고 과정을 가지고 블루스카이나 연합우주를 선택했다고 생각하진 않지만, 적어도 현 시점에서 사용자들은 블루스카이(이 글을 쓰는 시점에서 약 3360만명)를 연합우주(FediDBFediverse.party로부터 추정할 때 최대 1530만명)보다 선호하는 것은 틀림이 없다. 게다가 블루스카이의 규모는 최근 1년 사이에 10배 불어난 것이고, 조금 장애가 있었지만 현재는 잘 동작하는 것으로 보인다. 위의 논의와 결합해 보면, 블루스카이는 정석적인 스케일링에 성공하고 있는 반면 연합우주는 스케일링 문제를 회피하기 위해 온전한 소셜 네트워크의 구성을 포기했다고 볼 수도 있는 대목이다. 블루스카이가 못미더운 부분은 분명히 존재하지만, 연합우주가 더 좋은 소셜 네트워크 경험을 제공한다고 가정하고 블루스카이의 단점을 제시할 수는 없다. 마치 암호화폐를 논할 때 장점만 말할 수 없는 것과 마찬가지로 말이다.



RE: https://hackers.pub/@hongminhee/2025/bluesky-a-good-alternative-to-x-not-to-the-fediverse

2
0
0

C++ 표준화 위원회(WG21)에게 C++의 원 저자인 비야네 스트롭스트룹Bjarne Stroustrup이 보낸 메일이 이번 달 초에 본인에 의해 공개된 모양이다. C++가 요즘 안전하지 않은 언어라고 열심히 얻어 맞고 있는 게 싫은지 프로파일(P3081)이라고 하는 언어 부분집합을 정의하려고 했는데, 프로파일이 다루는 문제들이 아주 쉬운 것부터 연구가 필요한 것까지 한데 뒤섞여 있어 구현이 매우 까다롭기에 해당 제안이 적절하지 않음을 올해 초에 가멸차게 까는 글(P3586)이 올라 오자 거기에 대한 응답으로 작성된 것으로 보인다. 더 레지스터의 표현을 빌면 "(본지가 아는 한) 스트롭스트룹이 이 정도로 강조해서 말하는 건 2018년 이래 처음"이라나.

여론은 당연히 호의적이지 않은데, 기술적인 반론이 대부분인 P3586과는 달리 해당 메일은 원래 공개 목적이 아니었음을 감안해도 기술적인 얘기는 쏙 빼 놓고 프로파일이 "코드를 안 고치고도 안전성을 가져 갈 수 있다"는 허황된 주장에 기반해 그러니까 프로파일을 당장 집어 넣어야 한다고 주장하고 있으니 그럴 만도 하다. 스트롭스트룹이 그렇게 이름을 언급하지 않으려고 했던 러스트를 굳이 들지 않아도, 애당초 (이 또한 계속 부정하고 싶겠지만) C++의 주요 장점 중 하나였던 강력한 C 호환성이 곧 메모리 안전성의 가장 큰 적이기 때문에 프로파일이 아니라 프로파일 할아버지가 와도 안전성을 진짜로 확보하려면 코드 수정이 필수적이고, 프로파일이 그 문제를 해결한다고 주장하는 건 눈 가리고 아웅이라는 것을 이제는 충분히 많은 사람들이 깨닫지 않았는가. 스트롭스트룹이 허황된 주장을 계속 반복하는 한 C++는 안전해질 기회가 없을 듯 하다.

0

최근에 오랫동안 쓰던 키보드가 망가져서 큰 맘 먹고 프리플로우 Archon M1 PRO MAX를 질렀는데, 요즘 키보드는 다 WebHID 가지고 웹 드라이버로 설정하는 것 같다. 자바스크립트니까 뜯기 쉽겠거니 싶어서 살펴 봤는데 커스텀 HID 레포트를 보낼 수 있는 기능을 사용해서 명령들을 나열해 놓았고, 개중에는 롬을 통으로 날리는 것도 가감없이 노출되어 있길래 음 역시 WebHID 같은 건 웹에 넣을 기능이 못된다는 결론을 내렸다. 가볍게 함수 목록만 요약해서 https://gist.github.com/lifthrasiir/c79c90ecf697b1e6dc73e83f32984499에 올렸다.

0