본문 바로가기

반응형

전체 글

(134)
3편: CustomPainter로 지도 그리기, 그리고 900배 확대 그리는 구조구조는 단순합니다.CustomPainter가 시군구 250개의 Path를 그립니다그 위에 시도 경계선을 더 굵게 덧그립니다전체를 InteractiveViewer로 감싸서 핀치 줌과 이동을 처리합니다위경도를 화면 좌표로 바꾸는 투영은 직접 만들었습니다. 우리나라 정도 범위라면 복잡한 투영이 필요 없고, 경도에 cos(기준위도)를 곱해서 가로를 보정하는 정도면 충분합니다. 기준 위도는 35.9도로 잡았습니다. lonMin 124.6 / lonMax 131.0 / latMin 33.1 / latMax 38.7 / latRef 35.9scale = min(width / rawW, height / rawH)처음에 밟은 지뢰들선 굵기가 같이 커집니다. 확대하면 경계선도 같이 두꺼워져서 금방 지저분해집니다..
2편: 시군구 250개 지도 데이터, 확대하면 틈이 벌어졌습니다 지도 SDK 대신 GeoJSON지도 SDK를 붙이면 타일 이미지가 깔립니다. 하지만 제가 원한 건 도로도 건물도 없는, 지역 모양만 있는 지도였습니다. 지역이 색으로 채워지는 게 전부인 화면이라 타일은 오히려 방해였습니다.그래서 공개 데이터를 썼습니다.출처: southkorea/southkorea-maps (통계청 2018 시군구 경계)시도 17개로 시작했다가 시군구 250개로 세분화했습니다. 시도 단위는 한 번 여행하면 금방 칠해져서 재미가 없습니다원본은 18MB라 저장소에는 넣지 않고 변환 결과만 커밋했습니다경계 데이터는 그대로 쓰기엔 너무 무겁습니다. 점 개수를 줄이는 단순화(simplify)가 필요합니다.그런데 확대하면 틈이 생겼습니다부산 중구와 부산진구 사이에 흰 선 같은 틈이 보였습니다. 처음..
1편: 여행 기록을 지도에 채우는 앱, 기획부터 법규 검토까지 시작은 대동여지도였습니다여행을 다녀와도 사진은 갤러리에 묻히고, 어디를 갔었는지는 금방 흐려집니다. 그래서 다녀온 지역이 지도에 하나씩 채워지는 앱을 만들기로 했습니다. 지도를 채워 나간다는 감각이 핵심이고, 사진은 그 지역을 설명하는 재료입니다.기술 스택은 Flutter(안드로이드 + iOS)로 정했습니다. 지도는 구글 맵 같은 지도 SDK를 쓰지 않고, GeoJSON을 직접 그리는 방식을 택했습니다. 이유는 2편에서 자세히 다루겠습니다.제품 원칙을 먼저 못 박았습니다개발하면서 계속 흔들리는 지점이 생기기 때문에, 처음에 원칙을 정해 두었습니다.여행이 중심이다. 사용자가 여행(제목 + 기간)을 먼저 만들고, 그 안에 지역과 사진을 채운다사진은 여행 안에서만 추가한다. 지도에서 지역을 눌렀을 때 뜨는 시..
[쪽지 기능 2편] 운영자, 백그라운드 탭, 관리자 화면 — 만들면서 걸린 것들 1편에서는 쪽지를 누구에게 열어줄지, 게스트가 사라지면 대화를 어떻게 할지 같은 정책을 정리했습니다. 이번 편은 그걸 실제로 만들면서 걸린 세 가지입니다.운영자는 players에 없다쪽지 테이블의 from_key/to_key는 players 테이블을 외래 키로 참조합니다. 1편에서 말한 CASCADE 정리가 이 구조 덕분에 돌아가요.그런데 운영자 쪽지를 넣으려니 구멍이 하나 보였습니다. 운영자는 players에 행이 없어요. 관리자 대시보드(썬더박스)는 별도 인증을 쓰니까요. 운영자가 보내는 쪽지에는 넣을 보낸 사람 키가 없고, 사용자가 운영자에게 답장하면 넣을 받는 사람 키가 없습니다.운영자용 가짜 players 행을 하나 만드는 방법도 있었지만, 그러면 랭킹이나 친구 조회 같은 곳에서 그 행을 매번 ..
[쪽지 기능 1편] 익명 서비스에서 쪽지를 누구에게 열어줄 것인가 PlayTalk에 쪽지 기능을 붙였습니다.그동안 PlayTalk에서 다른 사람과 이야기하는 방법은 둘뿐이었어요. 랜덤 매칭으로 만난 상대와 채팅하거나, 친구에게 대화 신청을 보내는 것. 둘 다 상대가 지금 접속해 있어야 합니다. 친구가 오프라인이면 할 수 있는 게 없고, 건의함에 의견을 남겨준 사용자에게 운영자인 제가 답할 방법도 없었어요.쪽지는 흔한 기능이라 금방 끝날 줄 알았는데, 구현 전에 검토하면서 정해야 할 게 열 개 넘게 나왔습니다. 그래서 두 편으로 나눠 정리합니다. 1편은 무엇을 허용할지 정한 이야기, 2편은 막상 만들면서 걸린 것들입니다.누구에게 보낼 수 있게 할 것인가처음 떠올린 발송 지점은 세 곳이었습니다. 친구 목록, 건의함 답변, 그리고 쪽지 화면에서의 답장이요. 여기에 신고 처리..
dev에서만 API가 index.html을 돌려줄 때 — 새 경로를 추가하면 등록해야 하는 두 곳 SPA + 자체 API 서버 조합으로 개발하다 보면 가끔 이런 걸 만납니다. SyntaxError: Unexpected token '서버 코드는 방금 짰고, 라우터에도 분명히 등록했고, 배포 서버에서는 잘 되는데 로컬 dev에서만 이럽니다. 응답을 열어보면 JSON이 아니라 index.html 통째가 와 있어요.PlayTalk에서 랭킹용 조회 엔드포인트를 하나 추가하다가 또 밟아서, 기록 겸 정리해 둡니다.원인: SPA 폴백이 API 요청을 먹는다SPA는 클라이언트 라우팅을 쓰기 때문에, 어떤 경로로 들어와도 서버가 index.html을 돌려줘야 새로고침이 동작합니다. 그래서 dev 서버와 서비스 워커 양쪽에 "모르는 경로는 전부 index.html" 이라는 규칙이 깔려 있어요.문제는 이 "모르는 경로"..
로그인 없이 쓰는 서비스의 숙제 — "게스트 기록은 언제까지 남나요"에 답하기까지 PlayTalk은 로그인 없이 바로 놀 수 있는 서비스입니다. 접속하면 쿠키에 UUID가 하나 발급되고, 그걸로 전적이 쌓이고 랭킹에도 올라갑니다. 회원가입은 선택이에요.이 설계는 진입 장벽을 확 낮춰줬지만, 대신 "그럼 그 기록은 어떻게 되는데?" 라는 질문을 계속 만들어 냈습니다. 이 질문에 제대로 답하기까지 커밋이 다섯 개쯤 걸렸는데, 문구 수정이 그중 셋이었습니다. 코드보다 말이 어려웠던 작업이라 정리해 둡니다.문제 1: 주인 없는 기록이 랭킹에 눌러앉았다게스트 신원은 쿠키에 있습니다. 쿠키를 지우거나, 브라우저를 바꾸거나, 시크릿 모드로 들어오면 새 UUID가 발급됩니다.그러면 옛 UUID의 기록은 어떻게 될까요? 아무도 찾아가지 않는 채로 랭킹에 남습니다. 플레이 기록이 있으니 랭킹에는 계속 ..
게임 탭을 인기순으로 바꾸면서 배운 것들 — 원본 배열, 안정 정렬, 그리고 일부러 넣은 캐시 PlayTalk 랭킹 화면에는 게임별 탭이 가로로 나열돼 있습니다. 게임이 늘면서 탭이 화면을 넘겼고, 정작 사람들이 제일 많이 하는 게임이 가로 스크롤 뒤쪽에 묻히는 일이 생겼습니다. 탭 순서가 그냥 코드에 적힌 배열 순서였거든요."플레이 수 많은 순으로 배치하자." 한 줄짜리 요구인데, 하다 보니 결정할 게 꽤 나왔습니다.1. 판수를 어디서 세나 — plays vs 집계 테이블먼저 게임별 총 플레이 수가 필요했습니다. 기존 랭킹 응답에는 top-10 플레이어의 개인 판수만 있어서 게임 전체 합계를 알 수 없었어요.DB에는 후보가 둘 있었습니다.plays — 판 단위 원천 테이블. SELECT game, COUNT(*) FROM plays GROUP BY game 이면 끝.player_game_stat..

반응형