얼굴인식 사진공유 카메라앱 슈티를 함께 만들 분을 찾습니다. 앱은 출시되어 있어 써보실수 있습니다. 이번달 내로 페디버스 연동을 끝내면 제가 생각한 MVP는 완성입니다. 앞으로도 개발해야할 부분들이 많고, 개중에 기술적으로 흥미로운 문제들도 다수 있습니다.
지금 2025년 상반기 투자유치를 목표로 팀 빌딩을 하고 있습니다. 관심 있으신 분, 또는 잘 모르겠지만 이야기를 나눠보고 싶은 분도 bgl@gwyng.com으로 편하게 연락주세요.
@arkjun@hackers.pub · 62 following · 68 followers
中年의 中小企業 開發者, 90年代 Console Gamer. 좋은 하루를 繼續해 나아간다. 좋은 하루가 모이면 좋은 人生이 된다.
韓国人のプログラマー、40代、小学生の息子とゲームするのが幸せ😃💕龍が如く 、ゼルダの伝説、マリオ、ピクミン好き
「いい1日を続ける」
いい1日を続けていけば、いい人生になる!
얼굴인식 사진공유 카메라앱 슈티를 함께 만들 분을 찾습니다. 앱은 출시되어 있어 써보실수 있습니다. 이번달 내로 페디버스 연동을 끝내면 제가 생각한 MVP는 완성입니다. 앞으로도 개발해야할 부분들이 많고, 개중에 기술적으로 흥미로운 문제들도 다수 있습니다.
지금 2025년 상반기 투자유치를 목표로 팀 빌딩을 하고 있습니다. 관심 있으신 분, 또는 잘 모르겠지만 이야기를 나눠보고 싶은 분도 bgl@gwyng.com으로 편하게 연락주세요.
며칠 전 Fedify에 팬아웃을 두 단계로 나누는 변경을 통해 Hackers' Pub에서 단문 작성시 오래 걸리는 문제를 해결했었는데 (그래봤자 팔로워가 100명이 넘는 나한테나 느낄 수 있는 문제였을 것 같지만), 이렇게 하니까 큐에서 팬아웃 태스크 자체가 오랫동안 안 빠지는 체증이 존재해서 큐에 여러 메시지를 넣는 연산 자체를 새로 추가하고 있다. 정확히는 PostgreSQL을 큐로 사용하고 있는데, 메시지 하나 넣고 NOTIFY
하고, 다음 메시지 넣고 또 NOTIFY
하고… 하는 게 비효율적이라 메시지를 일단 다 넣은 다음 NOTIFY
를 한 번만 하도록 고치고 있다.
Fedify 쪽의 MessageQueue
인터페이스에 선택적인 enqueueMany()
연산을 추가했고, @fedify/postgres 패키지에서도 해당 연산을 구현했다. Hackers' Pub에 적용했고, 이제 효과가 있는지 두고 보면 된다…
지금 해커스펍은 Fresh를 활용한 MPA 앱으로 구현되어 있는데, 개인적으로 이것 때문에 이런저런 사용성 아쉬움을 느끼고 있었다. 그래서 해커스펍에 GraphQL API를 붙여서 SPA 프론트엔드를 새로 구현하겠다는 음모계획을 가지고, 이를 위한 기반 작업의 일환으로 Drizzle의 새로운 Relational Query Builder API(RQBv2)를 적용하는 PR을 만들어 보았다 😋
Juntai Park shared the below article:
GIGAZINE(ギガジン) @gigazine.net@web.brid.gy
2025年1月19日に事実上のTikTok禁止法とも呼べる「外国の敵が管理するアプリケーションからアメリカ国民を守るための法案」が施行され、その影響でTikTokはサービスの継続が不透明な状況が続いています。そんなTikTokに対し、AIチャットボットなどを開発するPerplexityがTikTokの買収に関心を示しました。
続きを読む...
해커스펍 모바일 최적화 되면 조켓당 앱도 있으면 조켓당 그러면 트위터맹키로 잡고 살텐데🌸
@dogpoop2dev박소예 기여각이네요...?
해커스펍 모바일 최적화 되면 조켓당 앱도 있으면 조켓당 그러면 트위터맹키로 잡고 살텐데🌸
해커스펍 모바일 최적화 되면 조켓당 앱도 있으면 조켓당 그러면 트위터맹키로 잡고 살텐데🌸
@dogpoop2dev박소예 얼리스테이지에다가 오픈소스라 우리 모두가 앱을 만드는 주체가 될 수 있어요
Hackers' Pub에 행동 강령이 있다는 사실, 아셨나요?
우리 커뮤니티는 단순한 기술 토론을 넘어 모든 구성원이 진정으로 환영받는 포용적인 공간을 만들기 위해 상세한 행동 강령을 마련했습니다.
특히 주목할 만한 점은:
구조적 차별에 대한 명확한 입장: “모든 사람을 동등하게 대우한다”는 명목 하에 현실의 구조적 불평등을 무시하지 않으며, 이를 극복하기 위한 적극적인 노력을 중요시합니다.
기술적 엘리트주의 지양: “이것도 모르세요?”와 같은 조롱, 특정 기술 스택이나 도구에 대한 비하, 초보자의 질문을 무시하는 행위를 명확히 금지합니다.
모든 언어의 동등한 존중: 전 세계의 모든 언어를 동등하게 존중하며, 어떤 언어로도 자유롭게 소통할 수 있습니다.
자세한 내용은 행동 강령 페이지에서 확인하실 수 있습니다.
Hackers' Pub에 드디어 인용 기능이 구현되었습니다. 인용할 글의 링크를 복사한 뒤 단문 작성창에 붙여넣으시면 해당 글을 인용할지 묻는 창이 뜹니다. 확인을 선택하시면 해당 글이 인용되게 됩니다.
참고로 인용할 글은 꼭 Hackers' Pub의 글이 아니어도 ActivityPub을 지원하는 사이트의 아무 글이나 다 가능합니다. 예를 들어 Mastodon 인스턴스에서 글 링크를 복사해서 붙여도 동작합니다.
내가 쓴 글에 누가 어떻게 인용을 했나 궁금하실 경우, 글 아래에 있는 공유 아이콘 오른쪽에 위치한 반응 아이콘을 누르시면 확인할 수 있습니다. (원래는 공유한 사람 탭만 있었는데 인용 탭이 새로 생겼습니다.)
기술적으로는 FEP-e232 오브젝트 링크 스펙과 Misskey의 인용 확장 스펙, Pleroma의 인용 확장 스펙, 그리고 Fedibird의 인용 확장 스펙을 모두 구현하기 때문에, 인용 기능을 지원하는 현존하는 모든 ActivityPub 서비스와 호환됩니다.
RE: https://hackers.pub/@hongminhee/0195c73c-24f5-74c0-883d-1a0a0db14b6d
해커스 펍 이후로 한국 페디버스 개발자 생태계에 특이점이 왔다 (라고 주장하는중)
해커스 펍에 남기는 첫 글로 진.짜. 술을 파는 해커스 펍을 소개하겠습니다… 도쿄 히가시나카노에 위치한ハッカーズバー(hackers bar)에 가시면 바텐더 분의 라이브코딩을 구경하며 블루스크린, 커널 패닉 등의 이름이 붙여진 칵테일을 마실 수 있어요… 모두가 각자의 랩탑을 들고 와서 자유롭게 코딩하고 이야기 나누는 분위기! 도쿄에서 손에 꼽게 인상적이었던 바였습니다. 도쿄에서 술도 마시고 코딩도 하고 싶으신 분들은 한 번 들러보심이~~!
@hongminhee洪 民憙 (Hong Minhee)
@gaeulbyul가을별
@arkjunJuntai Park 복잡도가 어찌되는지 모르겠는데, 장문의 글을 렌더링할때도 버벅임이 좀 있었어요! (Draft를 좀 오래 묵혀놓긴 했었음)
@kodingwarriorJaeyeol Lee
@gaeulbyul가을별
@arkjunJuntai Park 원인 찾아서 고쳤습니다. 조금 복잡한 버그였는데요…
social.
을 뗀 silicon.moe
를 쓰도록 설정해두고 있기 때문에 두 핸들은 사실 같은 것입니다.@kodingwarrior@social.silicon.moe
로 저장되어 있어서 @kodingwarrior@silicon.moe
로 검색하면 캐시 히트가 안 되는 것입니다. 그래서 캐시가 영원히 안 되는 효과가 있던 거죠.일단 수정은 Markdown 렌더링 결과를 캐시하도록 맨 바깥에서 처리했고요. 다만, 핸들에 쓰이는 호스트명이 웹에 쓰이는 호스트명과 다른 케이스에 캐시가 안 되는 문제는 근본적으로 고쳐두긴 하려고 합니다.
Juntai Park shared the below article:
가을별 @gaeulbyul@hackers.pub
파이어폭스에 숨겨진 유용한 기능들을 소개합니다. `about:config`를 통해 주소창에서 계산기 및 단위 변환 기능을 활성화하는 방법부터, 페이지 내의 모든 미디어를 한눈에 보고 다운로드할 수 있는 페이지 정보 활용법을 알아봅니다. 또한, 파이어폭스에 숨겨진 이스터에그 게임을 찾는 방법과 개발자 도구의 UI 크기를 사용자에 맞게 조절하는 팁도 제공합니다. 이 글을 통해 파이어폭스의 숨겨진 잠재력을 발견하고, 브라우징 경험을 더욱 풍부하게 만들어 보세요.
Read more →Juntai Park shared the below article:
Jaeyeol Lee @kodingwarrior@hackers.pub
작년 10월 쯤부터 강남에 파견근무를 가게 되었다. 간만에 돈벌이가 나쁘지 않은 생활, 요즘 받는거에 비하면 월급 두배 이벤트를 하고 있는데, 그만큼 너무 바빠졌다. 주말도 쉬지 않고 일했고, 설연휴도 삼일절 연휴도 쉬지도 못하고 일했다. 그러다 보니, 책을 읽을 시간도 없을 뿐더러, 사람을 만나러 다닐 여유도 거의 없다시피 했다. 일정을 잡는 것도 눈치봐야 하는 수준으로 바빠졌고, 이 일정이 언제 끝날지도 모르겟다.
그래서 블로그에 근황을 남기자니, "네.. 그냥 뺑이치고 있습니다..." 라고 밖에 요약이 되지 않는다.
블로그에 쓸만한 근황은 잘 없는 것 같지만, 그래도 몇가지 변경사항은 있는것 같아서 기록이라도 남겨야겠다. 대외활동을 하게 될 일은 당연히 없었어서 타임라인을 나열하기도 어렵고, "그냥 요즘 이런 변화가 생겼고, 이런 생각을 하고 있습니다" 정도로 남겨두겠다.
삶에 변화를 좀 줘볼까하는 마음가짐에 프랭클린 플래너랑 속지를 구매했다. (사실 이런짓은 2016년/2020년 시도해본 적도 있었다) CEO 사이즈가 간편하기도 하고, 펜을 꽂을 수 있는 공간도 있어서 들고 다니면서 뭔가를 끄적이기에도 좋다.
<script data-allowed-prefixes="https://social.silicon.moe/" async src="https://social.silicon.moe/embed.js"></script>Post by @kodingwarrior@silicon.moeView on Mastodon
요즘은 일할때 아에 A4 용지 하나 꺼내서 거기다가 해야할 일들 나열하고, 어떤 Sub task를 해야하는지 시각적으로 쪼개기도 하는데, 키보드로 타이핑해서 할 일을 관리하는 것보다 역설적으로 더 관리가 잘 된다. 하나하나 남김없이 기록으로 남겨야겠다는 강박을 가지면 그것도 그것대로 집중이 안되었던 것 같다. 필요하면 그때그때 하나의 축약된 스냅샷을 남긴다면 모를까.
Getting Things Done 에 따르면, 할 일 관리 내지는 생산성의 끝판왕은 펜과 종이로 충분하다고도 설명하곤 했었는데, 왜 그런지는 요즘 들어서 실감하고 있다. 그렇다고, Vim을 사용하는 워크플로우가 별로이냐면 그것도 아니다. 각자, 담당할 수 있는 영역이 다를 뿐이고, 시각화가 필요하거나 시각적인 정보의 자유로운 배치를 원한다면 마우스로 어거지로 배치하느니 차라리 펜과 종이만한게 없다.
지하철 타고 다닐때나 버스를 타고 다닐때, 종이책을 들고 다니면서 읽거나 아이패드로 책을 읽곤 하지만, 책 자체가 내용이 많은건지 내 처리속도(1분당 1-2페이지)가 느린건지 유의미하게 읽는 양이 그렇게 많지는 않다. 꾸준히 읽는다는 것 자체에 의미를 둘 수는 있긴 하겠지만, '찔끔찔끔 읽으면서 내가 가져갈 수 있는게 무엇인가?'라는 실용적인 관점에서 접근해보니, 책 읽는데 시간을 들이기보다는 조금이라도 생각나는 것들을 다이어리에다가 기록이라도 남겨두면 이것들을 조합해서 밀린 계획들을 조금이라도 정리도 할 수 있고, 블로그에 글도 올리고, 블로그에 글을 올리겠다고 밀린 것들도 청산할 수 있고 일석이조 아닌가?
물론 책을 읽을 시간이 많으면 베스트겠다.
지금 진행중인 3년이 넘는 계약도 슬슬 끝나간다. 취업 시장에 나올 수 있을때까지 한 6개월~1년 정도 남았다고 볼 수 있는데, 밥벌이를 하면서 취업 준비를 하기도 적당한 시기다. 사실은, "취업 준비"라는걸 제대로 해본 적도 없었다. 지금까지 해온 밥벌이도 그냥 코딩테스트는 그냥저냥 통과해서 그 운빨로 인턴을 시작하기도 했고, 그 다음부터는 지인(혹은 2차 지인)이 다니는 회사에 공식적인 전형이 없이 일을 해오긴 했었다. 그래서, 취업 준비를 하는 것도 이번이 처음이다.
여기에서도 간단하게 언급하긴 했었는데, 취준을 하게 된다면 프론트엔드 직군을 알아보거나 혹은 풀스택 직군을 알아보게 될 것 같다. 프론트엔드 직군을 생각하게 된 이유는 아래와 같다.
아무리 기능이 많더라도 사용성이 구리거나 이쁘지도 않다면, 그걸 쓰려고 하는 고객도 잘 없다. 그것은 즉슨 돈벌이가 되지도 않는다. 기능을 특정 고객에게 맞춤형으로 개발한다고 한들, 사용성이 구리거나 이쁘지도 않으면 다른 경쟁업체에게 빼앗기기 일쑤다. 돈이 되는 일을 하고 가치를 창출하려면 프론트엔드를 하는게 불가피하다는 결론에 도달했다.
본업은 분명히 백엔드로 시작하긴 했었지만, 실무에서 주로 하게 되었던 일들은 프론트엔드 할 사람이 없거나 혹은 일손이 모자라서 짬처리를 하는 일이었다. 거쳐갔던 회사 중에는 신중하게 기획하고 제품을 잘 만드는 것에 집중하고 기술스택을 가리지 않는 좋은 회사도 있었지만 이 경우는 짬처리와는 거리가 멀었다. 짬처리를 당하든, 내가 자발적으로 하게 되든, 결국에는 프론트엔드는 피할 수 없는 일이 되어왔다.
피할 수 없으면, 이걸로 계속 밥벌이를 하고 있으면, 그냥 이걸 내 커리어로 들고 가는게 맞지 않을까? 라는 생각이 들었다. 어차피, 백엔드도 그렇게 깊게 하지도 않았으니 프론트엔드가 손에 맞아가는 이 시점에 프론트엔드로 방향 트는 것도 방법이겠다 싶다.
프론트엔드 쪽으로 취업을 하려고 생각은 하고 있지만, 이래저래 걱정은 많다. 가장 먼저 드는 생각은, 내가 프론트엔드 개발을 할 때는 손이 그렇게 빠르지가 않다. Figma를 보면서 작업하면 금방이라고 느끼는 사람도 있겠지만, 하루에 10페이지-20페이지를 금방 찍어내는 사람이랑은 속도 차이가 좀 있는 것 같다.
거기다 처음부터 다시 배워야 하는 수준이다. 백엔드도 그렇게 깊게 하지는 않았지만, 프론트엔드는 더더욱 구조를 생각하면서 짜왔던 편도 아니거니와, 돌아만 가면 되는 수준으로 야매로 짜오긴 했다. 컴포넌트 나눠서 개발하는건 당연히 기본이긴 하지만, 잘 나누는지는 모르겠다. 그나마, "CSS는 과학이다"라는 마음가짐이었어서 CSS는 어느 정도 익숙하지만 딱 거기까지만인 것 같다.
지금까지 커리어를 이어오면서, 가장 취약했던 것도 사실은 프론트엔드이기도 하다. 퍼블리싱을 입히는 작업이 가장 괴롭게 느껴지기도 했었고, 다른 작업보다 심리적인 저항감이 있었어서 상대적으로 시간이 오래 걸리기도 했었다. (ADHD의 영향이 있어서일지도 모른다) 오히려 약점인 분야로 취업을 생각하고 있는 것도 어떻게 보면 이상하기도 하지만, "나는 프론트엔드 개발자다" 라는 마음가짐으로 임하게 된다면 그나마 저항감이 덜어질 것 같다.
프론트엔드 개발자로서 어필하려면, 당장은 프론트엔드 개발자로서 포트폴리오가 될만한 것들을 만들어야 한다. 그러면서, 더더욱 의욕을 잃지 않을만한 것을 찾아서 만들어야 한다. 그래서 요즘은 나도 쓰고 남한테도 쓰라고 권장할 수 있는 앱을 만들려고 시도하는 중이다. 이 글을 쓰고 있는 Hackers Pub에 기여할 방법을 찾아보기도 하고, 직접 Mastodon 클라이언트를 만들고 있기도 하다. 다음 분기에는 꼭 출시하는게 목표다. 면접이나 과제 전형 준비는.... 일단 맞으면서 배워야겠지..
그래도 Full-stack 엔지니어(요즘 용어로는 Product 엔지니어) 라는 선택지도 완전히 버리지는 못해서 백엔드를 해야한다면 그때그때 습득하면 될 것 같다.
위에서 언급했다시피, 책 읽을 시간도 거의 확보하지 못했다. 집 - 사무실 - 집 - 사무실 루틴을 반복하는 것도 모자라서 최소 일주일에 한번 이상은 사무실에서 밤새기까지 해서 책을 읽을 정신적인 여력 조차도 없었다.
그나마 읽은 것들을 나열하자면....
이젠 좀 바쁜 것도 끝이 보이고, 이젠 진짜 하고 싶은거 많이 하면서 다음 분기를 보내고 싶다.
Juntai Park shared the below article:
洪 民憙 (Hong Minhee) @hongminhee@hackers.pub
최근 X(구 Twitter)를 떠나는 사용자들이 늘면서 Bluesky에 대한 관심이 높아지고 있습니다. Bluesky는 깔끔한 인터페이스와 과거 Twitter와 유사한 사용자 경험을 제공하며, '신뢰할 수 있는 이탈'이라는 매력적인 개념을 내세워 X의 유력한 대안으로 떠오르고 있습니다. 하지만 이 글에서는 Bluesky와 그 기반 프로토콜인 AT Protocol이 연합우주(fediverse)의 대안이 될 수 없는 이유를 설명합니다. Bluesky는 메시지 전달 방식 대신 공유 힙 방식을 사용하며, 이는 중앙 릴레이에 의존하게 만들어 탈중앙화의 이상과는 거리가 멀어집니다. 또한, 전역 뷰에 대한 집착은 차단 목록의 전체 공개와 같은 개인 정보 보호 문제를 야기하며, AT Protocol은 아직 특정 사기업에 의해 주도되고 있어 개방형 표준으로서의 한계를 가지고 있습니다. Bluesky는 이동 가능한 아이덴티티를 제공하지만, 여전히 중앙화된 요소에 의존하고 있으며, DM은 완전히 중앙화되어 있습니다. 결론적으로, Bluesky는 X의 훌륭한 대안이 될 수 있지만, 연합우주가 제공하는 탈중앙화된 가치와 경험을 대체하기는 어려울 것입니다. 이 글을 통해 Bluesky와 연합우주의 차이점을 명확히 이해하고, 자신에게 맞는 플랫폼을 선택하는 데 도움이 될 것입니다.
Read more →https://www.frontend.moe/posts/naver-2025-coding-test/ 팀네이버 코딩 테스트 후기를 개인 블로그에 올려두었습니다. 꾸준히 일할 수 있는 지속 가능한 소프트웨어 엔지니어로서의 삶을 지켜내고자 반성글을 쓰게 되었습니다(...)
@hongminhee洪 民憙 (Hong Minhee) 안그래도 설정하다가 그냥 vsc 쓰고 있어요 :( 말리시는 이유가 있을까요?
높은 목표를 가진 개발자라도 결국엔 아주 사소한 동기로 움직이는거 같다.
나같은 경우엔, 완벽한 프로그래밍 언어를 만드는 것이 목표인데(가능한지는 차치하고), 완벽하다는건 나말고 다른 누군가가 같은 문제 의식을 가진다면 똑같이 그곳에 다다를 거란걸 의미한다. 그 프로그래밍 언어의 설계에서 내 마음대로 결정할수 있는 부분은 없을 것이다. 설계에서 최적의 선택지만을 택해야 완벽할테니까 말이다. 그때가선 그 선택들이 너무 자명해서, 내겐 처음부터 선택의 여지가 없었다고 느낄것이다.
그럼에도 내가 결정할 수 있을 부분이 있기는한데, 그 언어의 이름에 뜬금없이 우리집 강아지 이름을 붙인다던가 하는 것이다. 이게 그 사소한 동기다.
@bglbgl gwyng 사이먼 페이튼 존스의 고양이 이름이 하스켈인데 고양이 이름이 먼저였을까요, 프로그래밍 언어 이름이 먼저였을까요?
높은 목표를 가진 개발자라도 결국엔 아주 사소한 동기로 움직이는거 같다.
나같은 경우엔, 완벽한 프로그래밍 언어를 만드는 것이 목표인데(가능한지는 차치하고), 완벽하다는건 나말고 다른 누군가가 같은 문제 의식을 가진다면 똑같이 그곳에 다다를 거란걸 의미한다. 그 프로그래밍 언어의 설계에서 내 마음대로 결정할수 있는 부분은 없을 것이다. 설계에서 최적의 선택지만을 택해야 완벽할테니까 말이다. 그때가선 그 선택들이 너무 자명해서, 내겐 처음부터 선택의 여지가 없었다고 느낄것이다.
그럼에도 내가 결정할 수 있을 부분이 있기는한데, 그 언어의 이름에 뜬금없이 우리집 강아지 이름을 붙인다던가 하는 것이다. 이게 그 사소한 동기다.
安寧하세요, 저는 서울에 살고 있는 30代 後半 오픈 소스 소프트웨어 엔지니어이며, 自由·오픈 소스 소프트웨어와 聯合宇宙(fediverse)의 熱烈한 支持者입니다.
저는 TypeScript用 ActivityPub 서버 프레임워크인 @fedifyFedify: an ActivityPub server framework 프로젝트와 싱글 유저用 ActivityPub 마이크로블로그인
@holloHollo
프로젝트와 ActivityPub 봇 프레임워크인
@botkitBotKit by Fedify
프로젝트의 製作者이기도 합니다.
저는 東아시아 言語(이른바 #CJK)와 유니코드에도 關心이 많습니다. 聯合宇宙에서는 國漢文混用體를 쓰고 있어요! 제게 韓國語나 英語, 日本語로 말을 걸어주세요. (아니면, 漢文으로도!)
こんにちは、私はソウルに住んでいる30代後半のオープンソースソフトウェアエンジニアで、自由・オープンソースソフトウェアとフェディバースの熱烈な支持者です。名前は洪 民憙です。
私はTypeScript用のActivityPubサーバーフレームワークである「@fedifyFedify: an ActivityPub server framework」と、ActivityPubをサポートする1人用マイクロブログである 「
@holloHollo
」と、ActivityPubのボットを作成する為のシンプルなフレームワークである「
@botkitBotKit by Fedify
」の作者でもあります。
私は東アジア言語(いわゆるCJK)とUnicodeにも興味が多いです。日本語、英語、韓国語で話しかけてください。(または、漢文でも!)
Hello, I'm an open source software engineer in my late 30s living in #Seoul, #Korea, and an avid advocate of #FLOSS and the #fediverse.
I'm the creator of @fedifyFedify: an ActivityPub server framework, an #ActivityPub server framework in #TypeScript,
@holloHollo
, an ActivityPub-enabled microblogging software for single users, and
@botkitBotKit by Fedify
, a simple ActivityPub bot framework.
I'm also very interested in East Asian languages (so-called #CJK) and #Unicode. Feel free to talk to me in #English, #Korean (#한국어), or #Japanese (#日本語), or even in Literary Chinese (#文言文, #漢文)!
安寧하세요, 저는 서울에 살고 있는 30代 後半 오픈 소스 소프트웨어 엔지니어이며, 自由·오픈 소스 소프트웨어와 聯合宇宙(fediverse)의 熱烈한 支持者입니다.
저는 TypeScript用 ActivityPub 서버 프레임워크인 @fedifyFedify: an ActivityPub server framework 프로젝트와 싱글 유저用 ActivityPub 마이크로블로그인
@holloHollo
프로젝트와 ActivityPub 봇 프레임워크인
@botkitBotKit by Fedify
프로젝트의 製作者이기도 합니다.
저는 東아시아 言語(이른바 #CJK)와 유니코드에도 關心이 많습니다. 聯合宇宙에서는 國漢文混用體를 쓰고 있어요! 제게 韓國語나 英語, 日本語로 말을 걸어주세요. (아니면, 漢文으로도!)
Hello, I'm an open source software engineer in my late 30s living in #Seoul, #Korea, and an avid advocate of #FLOSS and the #fediverse.
I'm the creator of @fedifyFedify: an ActivityPub server framework, an #ActivityPub server framework in #TypeScript,
@holloHollo
, an ActivityPub-enabled microblogging software for single users, and
@botkitBotKit by Fedify
, a simple ActivityPub bot framework.
I'm also very interested in East Asian languages (so-called #CJK) and #Unicode. Feel free to talk to me in #English, #Korean (#한국어), or #Japanese (#日本語), or even in Literary Chinese (#文言文, #漢文)!
ActivityPub 구현들에서 인용을 하면 content
값에 자동으로 “RE: 인용된 글 링크” 또는 “QT: 인용된 글 링크 [参照]” 같은 식으로 덧붙이는 동작들을 하는데, 다행히 Akkoma나 Fedibird 등에서는 이를 .quote-inline
이나 .reference-link-inline
같은 클래스로 묶어줘서 CSS로 그것들을 가리는 게 가능하다. 그런데, 오직 Misskey만 그런 처리를 안 해줘서 CSS만으로 가릴 방법이 없다…
나두 해커스펍
아무래도 Hackers' Pub 가입 직후에 팔로 추천 탭을 보여주는 게 나을 것 같기도… 🤔
GN⁺: 스크립트에서는 긴 옵션을 사용합시다
------------------------------
- 많은 명령줄 유틸리티는 짧은 형식 옵션(-f
)과 긴 형식 옵션(--force
)을 지원함
- 짧은 형식은 대화형 사용을 위한 것임, 스크립트에서는 긴 형식을 사용할 것을 권장함
- 예를 들어, 터미널에서는 $ git switch -c my-new-branch
라고 입력함.
- 릴리스 스크립트에서는 다음과 같이 작성함:
- `try …
------------------------------
https://news.hada.io/topic?id=19905&utm_source=googlechat&utm_medium=bot&utm_campaign=1834
백준 관련해서 보다가 이런저런 프로젝트들이 많길래 모아놓는 저장소를 하나 팠다.
디지털 가드닝에 관심이 많은 개발자입니다.
- 특히 위키 형식의 문서 관리, knowledge graph 구조의 시각화에 관심이 있어요.
- kodingwarrior.github.io/wiki
Neovim 이라는 텍스트 에디터에 굉장히 꽂혀있습니다.
- 과몰입한 나머지 플러그인까지 개발해본 경험이 있어요.
- 한국어권 개발자를 위한 Vim 디스코드를 운영중입니다 (vim.kr)
프로그래밍을 하는 행위 자체를 좋아합니다.
- 프로그래밍으로 퍼즐을 푸는 행위를 좋아했고, 비슷한 흔적을 가진 사람들에게 친밀감을 느낍니다.
해커스펍을 더 흥하게 할 수 있는 아이디어가 하나 더 생각났다,, 다음주 주말쯤에 보따리 봉인 풀어야지 캬캬캬
개발자 한 100명 정도 해커스펍에 오면 사실상 트위터 개발자 타임라인이랑 비슷한 리젠율 찍을듯
HackersPub을 통해 개발자들 위주로 연합우주 타임라인이 계속 핫해질듯...!!!
그동안(10+년;;) git이 엄청 잘만든 물건 같지는 않다고 생각하며 대충 쓰고있었는데, 요즘 branch 개념 자체가 근본적인 실수란 생각이 들기 시작했다. branch 대신에 변경의 시작과 끝, 양 끝점을 가지는 interval을 쓰는게 맞는거 같다(카테고리 이론의 작은 교훈: primitive는 양 끝점을 가지는게 좋다).
git을 쓰면 히스토리 길어진다고 squash merge 등을 하는데, (나도 하지만) 사실 기껏 만들어놓은 히스토리를 뭉개버리는 말도 안되는 동작이다. 만약 interval을 쓴다면 히스토리는 그대로 남기고 UI 단에서 fold/unfold 등을 해줄수 있을 것이다.
Darcs 등이 interval에 기초하는데, 지금은 일이 너무 바빠서 시도할 여유가 없다. 한번 숨고를 시간이 주어지면 멀쩡한 VCS를 탐색하는 시간을 가질것이다.
해커펍은 퍼머링크로 아카이빙 참조하기 최적이라 생각해서 앞으로 기술을 다루며 기록 및 참조하는 용도로 잘 사용하려고 합니다.
트위터는 나중에 다른 사람에게 보여줄 참조용으로 쓰기에는 너무 정보 대비 소음이 많은 특성 때문에 잘 맞지 않는다고 생각합니다.
📢 Hackers' Pub 초대 시스템 오픈!
Hackers' Pub에 초대 시스템이 적용되었습니다. 이제 설정 → 초대 페이지에서 지인들을 초대할 수 있습니다.
주요 내용:
Hackers' Pub의 퀄리티를 유지하고, 더욱 풍성한 기술 논의를 위해 신중한 초대를 부탁드립니다.
궁금한 점이나 건의사항은 답글로 남겨주세요.
Hackers' Pub 커뮤니티 성장에 많은 참여 부탁드립니다!
📢 Hackers' Pub 招待システムオープン!
Hackers' Pub に招待システムが適用されました。これで設定→招待ページから知人を招待できます。
主な内容:
Hackers' Pub のクオリティを維持し、より豊かな技術議論のために慎重な招待をお願いいたします。
ご不明な点やご要望は、この投稿への返信としてお寄せください。
Hackers' Pub コミュニティの成長にご協力をお願いいたします!
📢 Hackers' Pub 초대 시스템 오픈!
Hackers' Pub에 초대 시스템이 적용되었습니다. 이제 설정 → 초대 페이지에서 지인들을 초대할 수 있습니다.
주요 내용:
Hackers' Pub의 퀄리티를 유지하고, 더욱 풍성한 기술 논의를 위해 신중한 초대를 부탁드립니다.
궁금한 점이나 건의사항은 답글로 남겨주세요.
Hackers' Pub 커뮤니티 성장에 많은 참여 부탁드립니다!
@curry박준규 확장이 하도 많아서 뭐가 있는지 다 알기가 어려운 것 같아요… 😂
@hongminhee洪 民憙 (Hong Minhee) 이런 표현이 있습니다.
GHC has more flags than the UN.
https://github.com/dahlia/hackerspub/pull/12
해커스펍의 멘션 기능에 가독성 개선이 필요할 것 같아서 제안하는 느낌으로 PR은 올렸는데, 다른 분들도 어떤 의견을 가지고 계실지 모르겠다
仮名もハングルも表音文字だから日本語の文章をハングルで表記できそうと思ったらそれっぽいのがもうあった
https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AE%E3%83%8F%E3%83%B3%E3%82%B0%E3%83%AB%E8%A1%A8%E8%A8%98
Juntai Park shared the below article:
洪 民憙 (Hong Minhee) @hongminhee@hackers.pub
Despite their bad reputation in the Java community, checked exceptions provide superior type safety comparable to Rust's Result<T, E>
or Haskell's Either a b
—we've been dismissing one of Java's best features all along.
Few features in Java have been as consistently criticized as checked exceptions. Modern Java libraries and frameworks often go to great lengths to avoid them. Newer JVM languages like Kotlin have abandoned them entirely. Many experienced Java developers consider them a design mistake.
But what if this conventional wisdom is wrong? What if checked exceptions represent one of Java's most forward-thinking features?
In this post, I'll argue that Java's checked exceptions were ahead of their time, offering many of the same type safety benefits that are now celebrated in languages like Rust and Haskell. Rather than abandoning this feature, we should consider how to improve it to work better with modern Java's features.
To set the stage, let's review how Java's exception system works:
Unchecked exceptions (subclasses of RuntimeException
or Error
): These don't need to be declared or caught. They typically represent programming errors (NullPointerException
, IndexOutOfBoundsException
) or unrecoverable conditions (OutOfMemoryError
).
Checked exceptions (subclasses of Exception
but not RuntimeException
): These must either be caught with try
/catch
blocks or declared in the method signature with throws
. They represent recoverable conditions that are outside the normal flow of execution (IOException
, SQLException
).
Here's how this works in practice:
// Checked exception - compiler forces you to handle or declare it
public void readFile(String path) throws IOException {
Files.readAllLines(Path.of(path));
}
// Unchecked exception - no compiler enforcement
public void processArray(int[] array) {
int value = array[array.length + 1]; // May throw ArrayIndexOutOfBoundsException
}
At their core, checked exceptions are a way of encoding potential failure modes into the type system via method signatures. This makes certain failure cases part of the API contract, forcing client code to explicitly handle these cases.
Consider this method signature:
public byte[] readFileContents(String filePath) throws IOException
The throws IOException
clause tells us something critical: this method might fail in ways related to IO operations. The compiler ensures you can't simply ignore this fact. You must either:
This type-level representation of potential failures aligns perfectly with principles of modern type-safe programming.
One often overlooked advantage of Java's checked exceptions is their automatic propagation. Once you declare a method as throws IOException
, any exception that occurs is automatically propagated to the caller without additional syntax.
Compare this with Rust, where you must use the ?
operator every time you call a function that returns a Result
:
// Rust requires explicit propagation with ? for each call
fn read_and_process(path: &str) -> Result<(), std::io::Error> {
let content = std::fs::read_to_string(path)?;
process_content(&content)?;
Ok(())
}
// Java automatically propagates exceptions once declared
void readAndProcess(String path) throws IOException {
String content = Files.readString(Path.of(path));
processContent(content); // If this throws IOException, it's automatically propagated
}
In complex methods with many potential failure points, Java's approach leads to cleaner code by eliminating the need for repetitive error propagation markers.
The approach of encoding failure possibilities in the type system has been adopted by many modern languages, most notably Rust with its Result<T, E>
type and Haskell with its Either a b
type.
In Rust:
fn read_file_contents(file_path: &str) -> Result<Vec<u8>, std::io::Error> {
std::fs::read(file_path)
}
When calling this function, you can't just ignore the potential for errors—you need to handle both the success case and the error case, often using the ?
operator or pattern matching.
In Haskell:
readFileContents :: FilePath -> IO (Either IOException ByteString)
readFileContents path = try $ BS.readFile path
Again, the caller must explicitly deal with both possible outcomes.
This is fundamentally the same insight that motivated Java's checked exceptions: make failure handling explicit in the type system.
If checked exceptions are conceptually similar to these widely-praised error handling mechanisms, why have they fallen out of favor? There are several legitimate criticisms:
The most common complaint is the boilerplate required when propagating exceptions up the call stack:
void methodA() throws IOException {
methodB();
}
void methodB() throws IOException {
methodC();
}
void methodC() throws IOException {
// Actual code that might throw IOException
}
Every method in the chain must declare the same exception, creating repetitive code. While automatic propagation works well within a method, the explicit declaration in method signatures creates overhead.
Java 8 introduced lambdas and streams, but checked exceptions don't play well with them:
// Won't compile because map doesn't expect functions that throw checked exceptions
List<String> fileContents = filePaths.stream()
.map(path -> Files.readString(Path.of(path))) // Throws IOException
.collect(Collectors.toList());
This forces developers to use awkward workarounds:
List<String> fileContents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new UncheckedIOException(e); // Wrap in an unchecked exception
}
})
.collect(Collectors.toList());
Adding a checked exception to an existing method breaks all implementing classes and calling code. This makes evolving interfaces over time difficult, especially for widely-used libraries and frameworks.
The strictness of checked exceptions can lead to the worst possible outcome—developers simply catching and ignoring exceptions to make the compiler happy:
try {
// Code that might throw
} catch (Exception e) {
// Do nothing or just log
}
This is worse than having no exception checking at all because it provides a false sense of security.
Rather than abandoning checked exceptions entirely, Java could enhance the existing system to address these legitimate concerns. Here are some potential improvements that preserve the type safety benefits while addressing the practical problems:
One of the biggest pain points with checked exceptions today is their incompatibility with functional interfaces. Consider how much cleaner this would be:
// Current approach - forced to handle or wrap exceptions inline
List<String> contents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
// Potential future approach - lambdas can declare exceptions
List<String> contents = filePaths.stream()
.map((String path) throws IOException -> Files.readString(Path.of(path)))
.collect(Collectors.toList());
This would require updating functional interfaces to support exception declarations:
@FunctionalInterface
public interface Function<T, R, E extends Exception> {
R apply(T t) throws E;
}
Another powerful enhancement would be allowing generic type parameters in throws
clauses:
public <E extends Exception> void processWithException(Supplier<Void, E> supplier) throws E {
supplier.get();
}
This would enable much more flexible composition of methods that work with different exception types, bringing some of the flexibility of Rust's Result<T, E>
to Java's existing exception system.
Unlike Rust which requires the ?
operator for error propagation, Java already automatically propagates checked exceptions when declared in the method signature. What Java needs instead is better support for checked exceptions in functional contexts:
// Current approach for handling exceptions in streams
List<String> contents = filePaths.stream()
.map(path -> {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw new RuntimeException(e); // Lose type information
}
})
.collect(Collectors.toList());
// Hypothetical improved API
List<String> contents = filePaths.stream()
.mapThrowing(path -> Files.readString(Path.of(path))) // Preserves checked exception
.onException(IOException.class, e -> logError(e))
.collect(Collectors.toList());
Optional<T>
and Stream<T>
APIs The standard library could be enhanced to better support operations that might throw checked exceptions:
// Hypothetical API
Optional<String> content = Optional.ofThrowable(() -> Files.readString(Path.of("file.txt")));
content.ifPresentOrElse(
this::processContent,
exception -> log.error("Failed to read file", exception)
);
It's worth examining how other languages have addressed the error handling problem:
Result<T, E>
and ?
operator Rust's approach using Result<T, E>
and the ?
operator shows how propagation can be made concise while keeping the type safety benefits. The ?
operator automatically unwraps a successful result or returns the error to the caller, making propagation more elegant.
However, Rust's approach requires explicit propagation at each step, which can be more verbose than Java's automatic propagation in certain scenarios.
Kotlin made all exceptions unchecked but provides functional constructs like runCatching
that bring back some type safety in a more modern way:
val result = runCatching {
Files.readString(Path.of("file.txt"))
}
result.fold(
onSuccess = { content -> processContent(content) },
onFailure = { exception -> log.error("Failed to read file", exception) }
)
This approach works well with Kotlin's functional programming paradigm but lacks compile-time enforcement.
Try[T]
, Either[A, B]
, and Effect Systems Scala offers Try[T]
, Either[A, B]
, and various effect systems that encode errors in the type system while integrating well with functional programming:
import scala.util.Try
val fileContent: Try[String] = Try {
Source.fromFile("file.txt").mkString
}
fileContent match {
case Success(content) => processContent(content)
case Failure(exception) => log.error("Failed to read file", exception)
}
This approach preserves type safety while fitting well with Scala's functional paradigm.
Java's checked exceptions were a pioneering attempt to bring type safety to error handling. While the implementation has shortcomings, the core concept aligns with modern type-safe approaches to error handling in languages like Rust and Haskell.
Copying Rust's Result<T, E>
might seem like the obvious solution, but it would represent a radical departure from Java's established paradigms. Instead, targeted enhancements to the existing checked exceptions system—like allowing lambdas to declare exceptions and supporting generic exception types—could preserve Java's unique approach while addressing its practical limitations.
The beauty of such improvements is that they'd maintain backward compatibility while making checked exceptions work seamlessly with modern Java features like lambdas and streams. They would acknowledge that the core concept of checked exceptions was sound—the problem was in the implementation details and their interaction with newer language features.
So rather than abandoning checked exceptions entirely, perhaps we should recognize them as a forward-thinking feature that was implemented before its time. As Java continues to evolve, we have an opportunity to refine this system rather than replace it.
In the meantime, next time you're tempted to disparage checked exceptions, remember: they're not just an annoying Java quirk—they're an early attempt at the same type safety paradigm that newer languages now implement with much celebration.
What do you think? Could these improvements make checked exceptions viable for modern Java development? Or is it too late to salvage this controversial feature? I'm interested in hearing your thoughts in the comments.
자바의 체크드 예외 재고찰: 저평가된 타입 안전성 기능
------------------------------
## 주요 내용 요약
* 자바의 체크드 예외가 커뮤니티에서 널리 비판받는 기능임에도 타입 안전성 측면에서 뛰어난 장점 보유.
* Rust의 Result<T, E>
나 Haskell의 Either a b
와 개념적으로 유사한 타입 안전성 메커니즘 제공.
* 체크드 예외가 메서드 시그니처에 잠재적 실패 가능성을 명시적으로 표현하…
------------------------------
https://news.hada.io/topic?id=19877&utm_source=googlechat&utm_medium=bot&utm_campaign=1834
모든 자바스크립트 개발자들이 단 하나의 패키지 매니저와 단 하나의 빌드 시스템, 단 하나의 모듈 시스템을 사용하면 좋겠다고 진심으로 생각한다
모든 자바스크립트 개발자들이 단 하나의 패키지 매니저와 단 하나의 빌드 시스템, 단 하나의 모듈 시스템을 사용하면 좋겠다고 진심으로 생각한다
@parksbSimon Park 사견으로는 그냥 다들 Deno를 썼으면 좋겠네요…
@linear “조용한 공개”는 “공개”와 거의 모든 면에서 같지만 로그인 안 했을 때 Hackers' Pub 첫 화면에서 보이지 않는다는 점, 외부 연합우주 서버에서 “연합 타임라인”에 뜨지 않는다는 점만 달라요.
이제 단문에 포함된 대표 링크에 대해 Open Graph 메타데이터를 추출하여 표시하게 되었습니다. 또한, 링크에 fediverse:creator
메타데이터가 있을 경우, 저자의 연합우주 프로필까지 하단에 표시하게 됩니다.
참고로 Hackers' Pub은 대부분의 경우 Fedify의 bleeding edge 버전을 쓰고 있습니다.
오늘 하려던 Fedify 작업은 얼추 끝내서, 다시 Hackers' Pub 작업에 손을 댑니다.
저는 AI에게 감사 인사를 하는 데에도 돈이 든다는 걸 깨달아버려서, 이제는 감사도 표하지 않는 삭막한 인간이 되고야 말았습니다.
오늘 하루는 Fedify 작업을 해야 해서 아마도 Hackers' Pub 개발은 못 할 것 같습니다.
…라고 썼지만, Fedify의 신기능을 테스트하기 위해 Hackers' Pub에 적용해 보고 있습니다. ㅎㅎㅎ
오픈소스 프로젝트를 시작하는 비법은 특별한게 아니다.
일정 주기(일, 주, 월, 년 등) 반복되는 동일한 수기 또는 수동 작업 -> 공통범주로 최대한 묶음 -> 적정한 수준의 자동화 계획 -> 코드로 구현 -> 오픈소스 라이선스 붙여서 공개
이게 곧 프로젝트가 되는거임.
…라고 썼지만, Fedify의 신기능을 테스트하기 위해 Hackers' Pub에 적용해 보고 있습니다. ㅎㅎㅎ
참고로 Hackers' Pub은 대부분의 경우 Fedify의 bleeding edge 버전을 쓰고 있습니다.