기본 콘텐츠로 건너뛰기

AI와 함께 춤을.. 아니, 코딩을.. (4) - 모노레포로 개발 환경 통합하기

바이브 코딩을 하는 가장 큰 이유는 아마도 개발 생산성 향상 일 것이다. 그래서인지 바이브 코딩을 하면서 자연스럽게 "어떻게 하면 효율을 더 높일 수 있을까?"를 고민하게 된다. 직접 코드를 작성하지 않으니, 그만큼 남는 시간을 프로세스 개선에 투자하게 되는 셈이다. 지난 포스팅에서 앱과 서버를 함께 개발할 때 명세 문서를 작성하고, 이를 기반으로 AI 에이전트에게 개발을 지시하는 방식을 소개했었다. 오늘은 이 방식을 실제로 사용하면서 겪었던 불편함과, 그것을 어떻게 개선했는지 이야기해보려 한다. 기존 개발 환경 앱에 기능을 추가하다 보니 서비스가 하나가 아니라 여러 개가 되었다. 당시 내 개발 환경을 간단히 그려보면 이런 구조였다. 개발 Macbook └─ 앱 프로젝트/ ├─ docs/ └─ src/ Ubuntu 서버 ├─ server1 프로젝트/ │ ├─ docs/ │ └─ src/ └─ server2 프로젝트/ ├─ docs/ └─ src/ iOS 앱 개발은 어쩔 수 없이 Mac에서 해야 했다. 서버는 DB도 돌려야 하고, 실제 운영 환경과 동일한 조건에서 개발하는 게 나을 것 같아 Ubuntu에서 진행했다. Macbook 용량도 부족한데 DB 서버를 계속 띄워놓기도 부담스러웠고, 초기에 API 서버가 PHP + Apache 조합이었던 것도 분리한 이유 중 하나였다. 기존 개발 프로세스 새로운 기능을 추가하거나 수정할 때는 이런 순서로 작업했다. VS Code에서 앱 프로젝트를 열고, Claude를 이용해 명세를 작성 한다. 작성된 명세를 구현이 필요한 각 프로젝트의 docs 폴더에 복사 한다. VS Code에서 각 프로젝트를 연다. 서버의 경우 VS Code의 원격 연결을 이용한다. 각 프로젝트에서 Claude를 실행하고, docs 폴더의 명세를 기반으로 개발을 지시 한다. 문제점 문제...

AI와 함께 춤을.. 아니, 코딩을.. (4) - 모노레포로 개발 환경 통합하기

바이브 코딩을 하는 가장 큰 이유는 아마도 개발 생산성 향상 일 것이다. 그래서인지 바이브 코딩을 하면서 자연스럽게 "어떻게 하면 효율을 더 높일 수 있을까?"를 고민하게 된다. 직접 코드를 작성하지 않으니, 그만큼 남는 시간을 프로세스 개선에 투자하게 되는 셈이다. 지난 포스팅에서 앱과 서버를 함께 개발할 때 명세 문서를 작성하고, 이를 기반으로 AI 에이전트에게 개발을 지시하는 방식을 소개했었다. 오늘은 이 방식을 실제로 사용하면서 겪었던 불편함과, 그것을 어떻게 개선했는지 이야기해보려 한다. 기존 개발 환경 앱에 기능을 추가하다 보니 서비스가 하나가 아니라 여러 개가 되었다. 당시 내 개발 환경을 간단히 그려보면 이런 구조였다. 개발 Macbook └─ 앱 프로젝트/ ├─ docs/ └─ src/ Ubuntu 서버 ├─ server1 프로젝트/ │ ├─ docs/ │ └─ src/ └─ server2 프로젝트/ ├─ docs/ └─ src/ iOS 앱 개발은 어쩔 수 없이 Mac에서 해야 했다. 서버는 DB도 돌려야 하고, 실제 운영 환경과 동일한 조건에서 개발하는 게 나을 것 같아 Ubuntu에서 진행했다. Macbook 용량도 부족한데 DB 서버를 계속 띄워놓기도 부담스러웠고, 초기에 API 서버가 PHP + Apache 조합이었던 것도 분리한 이유 중 하나였다. 기존 개발 프로세스 새로운 기능을 추가하거나 수정할 때는 이런 순서로 작업했다. VS Code에서 앱 프로젝트를 열고, Claude를 이용해 명세를 작성 한다. 작성된 명세를 구현이 필요한 각 프로젝트의 docs 폴더에 복사 한다. VS Code에서 각 프로젝트를 연다. 서버의 경우 VS Code의 원격 연결을 이용한다. 각 프로젝트에서 Claude를 실행하고, docs 폴더의 명세를 기반으로 개발을 지시 한다. 문제점 문제...

AI와 함께 춤을... (1) - OpenClaw 체험기, 결국 돌아온 Claude

최근 OpenClaw 라는 AI 툴이 등장해 인기를 끌고 있다. 나도 혹시 쓸모가 있을까 싶어 급히 Mac Mini를 주문하고 이 유행에 동참해 보았다. 사실 나중에 알고 보니 Mac에서만 동작한다는 건 이미 업데이트된 정보였는데, 역시 사람은 공부를 해야 한다. 😅 설치는 쉬웠지만, 설정은 만만치 않았다 OpenClaw 설치 자체는 어렵지 않았다. 문제는 설정 과정이었다. OpenClaw가 사용할 LLM 서비스 API Key 가 필요했고, 인터넷 검색을 시키려면 Brave API 도 필요했다. 처음에는 내가 이미 구독 중인 Claude MAX 요금제를 그대로 활용하려 했다. 그런데 Anthropic 측에서 이를 약관 위반으로 판단해 막아둔 상태였고, 내가 시도하던 시점에는 사용이 불가능했다. 그래서 차선책으로 Gemini 무료 티어 를 기본 LLM으로 설정했다. 그런데 작업 하나를 요청했을 뿐인데 바로 API 사용량 초과가 떴다. 내가 사용하기 얼마 전에 분당 사용량 제한 정책이 도입된 모양이었다. 어쩔 수 없이 Gemini를 유료로 전환하고, 가장 저렴한 모델을 적용했다. 원격에서 작업을 지시하기 위해 텔레그램 봇 까지 설정을 마쳤다. 잠깐씩 틈틈이 하다 보니 여기까지 오는 데만 며칠이 걸렸다. 그때 그 시절, 리눅스를 설치하던 밤 여기까지 하고 나니 문득 옛 기억이 떠올랐다. 1990년대 말에서 2000년대 초, 리눅스 배포판이 막 알려지던 시절이었다. 어렵게 배포판을 구해서 밤새 설치하고 설정을 마치면… "이제 뭘 해야 하지?" 하며 컴퓨터 전원을 끄던 그때 말이다. OpenClaw 설정을 끝낸 지금, 딱 그 느낌이었다. OpenClaw + Claude Code, 합체를 시도하다 이 녀석을 무엇에 쓸까 고민하다가, OpenClaw에서 Gemini 대신 Claude Code 에게 실제 작업을 맡기는 구조를 시도해 보기로 했다. 구상은 이랬다. 내가 "제미나이에 대해서 검색...

AI와 함께 춤을.. 아니, 코딩을.. (3) - 서버 개발, AI와 함께 넘은 벽

요즘 개발되는 앱의 상당수는 앱 단독으로 동작하지 않고, 서버와 통신하는 구조로 만들어진다. 내가 개발하는 앱도 당연히 백엔드 서버를 이용하고 있다. 서버 개발이라는 벽 지난 포스팅 에서도 언급했듯이, 나는 요즘 일반적으로 많이 쓰이는 PHP나 Node.js 같은 기술에 대한 경험이 별로 없다. 그래서 이전에는 작은 기능 하나를 서버에 추가하려 해도 오랜 시간을 소비해야 했다. 결국 가급적이면 서버에 의존하지 않는 기능만 만들곤 했다. 내가 AI를 개발에 이용하기 시작한 주요 이유 중 하나가 바로 이 서버 개발 때문이었다. 처음에는 외주를 통해 개발되어 있던 기존 서버에 Cursor를 이용해 엔드포인트를 하나씩 추가하거나 수정하는 방식으로 진행했다. 응답이 제각각인 문제 그런데 이 과정에서 문제가 생겼다. AI가 새로운 엔드포인트를 만들 때마다 서버의 응답 형태가 조금씩 달라지면서, 클라이언트와 통합하는 데 어려움이 발생한 것이다. REST API에 대한 경험 없이 단순히 AI에게 구현만 시킨 결과였다. 문서화로 인터페이스 통일하기 이러한 비효율을 극복하기 위해 선택한 방법이 바로 지난 포스팅 에서 이야기한 문서화였다. 기능 개발의 전반적인 상황을 설명하고, 클라이언트와 서버 간의 인터페이스까지 함께 문서화하도록 했다. 그리고 생성된 문서를 앱과 서버 양쪽 프로젝트에 포함시켜, 이를 기반으로 개발하도록 함으로써 각 구현 단계에서 서로 다른 방식으로 구현되는 것을 방지했다. AI는 항상 새로운 개발자다 여기서 한 가지 주의할 점이 있다. 이미 한 번 구현된 서버에 새로운 엔드포인트를 추가해야 할 때, 기존과 동일한 방식으로 인터페이스를 구성해야 한다는 것을 반드시 함께 지시해야 했다. AI는 항상 새로운 개발자라고 보면 된다. 새로운 개발자는 자기 방식으로 개발하려는 경향 이 있다. 그래서 이전에 작성한 문서를 함께 제공하고, 이를 기반으로 작성하라고 명확히 지시해야 한다. 요즘은 AI 에이전트들이 프로젝트의 기존 코...

AI와 함께 춤을.. 아니, 코딩을.. (2) - 문서화로 AI와 소통하기

나는 오랫동안 개발을 업으로 하고 있다. 주로 소규모 기업에서 거의 1인 개발을 해왔다. 다른 개발자가 있더라도 각자 자기 일을 하는 그런 회사였다. 그러다 보니 여러 명이 하나의 프로젝트를 같이 수행하는 형태의 일이 별로 익숙하지 않다. 혼자 개발하고 테스트하다 보니, 체계화된 문서화도 나에겐 익숙하지 않다. 장기간 나만의 룰로 관습적으로 개발을 해왔다. 매번 새로 입사한 개발자 AI를 통해 코딩을 시작한 초기에는 에이전트에게 내가 지금 하고자 하는 일과 현재 상황을 전달하는 방법에 집중할 수밖에 없었다. AI 에이전트와 일하는 것은 매번 새로 입사한 개발자와 일하는 상황과 같다고 느꼈다. 아무것도 모르는 개발자에게 전후 사정 설명 없이 "이걸 해줘" 하면, 원하는 대로 동작하는 것 같지만 제대로 동작하지 않는 결과물을 만들어 내곤 했다. 그리고 이걸 수정하기 위해 대화가 길어지면 에이전트가 맥락을 잃어버리는 경우가 빈번히 발생했다. 문서화라는 해답 그래서 선택한 방법이 문서화였다. 내가 개발하고자 하는 기능을 문서로 정리하고, 이 문서를 기반으로 에이전트에게 개발을 요청하는 방식이다. 비슷한 시기에 AI를 이용한 코딩 관련 콘텐츠를 보면 문서화 이야기가 많았고, 그 시기에 아마존에서 출시한 Kiro라는 IDE는 이런 부분을 아예 내장하기까지 했다. 이야기했듯이 나는 문서화에 익숙하지 않다. 그래서 개발하고자 하는 기능을 문서로 정리하는 작업도 나에게는 그렇게 만만한 작업이 아니었다. 그래서 선택한 방법은 "문서화도 에이전트에게 시키자" 였다. 에이전트와 기획 회의하기 새로운 기능 개발이 필요하면 기획 회의를 에이전트와 진행한다. 보통 대화는 이렇게 시작한다. "지금부터 이런이런 기능을 개발하기 위한 기획 문서를 작성할 예정이다. 아직 코딩을 하지는 않을 것이다." 왜 "아직 코딩을 하지는 않을 것이다"라고 붙였을까 궁금할 텐데, 개발용 에이전트들은...

AI와 함께 춤을.. 아니, 코딩을.. (1) - 오래된 개발자의 AI 코딩 여정기

ChatGPT가 본격적으로 서비스를 시작하면서 나 뿐만 아니라 우리 모두의 삶에 많은 것이 달라졌다. 🤖 ChatGPT와의 첫 만남 회사 대표의 강권에 힘입어 ChatGPT가 서비스를 시작하자마자 유료 구독을 해서 사용하기 시작했다. 그런데 나는 인터넷을 업무 외 용도로는 크게 사용하지 않는 편이다. 인터넷 쇼핑도 거의 안 하고, 배달앱은 아직도 사용하지 않고 있다. 인터넷에서 하는 거라고는 개발을 위한 검색, 게시판 읽기, 가끔 궁금한 것 찾아보기 정도다. 그러다 보니, ChatGPT가 처음 나왔을 때 나에겐 크게 쓸모가 없었다. 그때는 ChatGPT에 환각이 많았기 때문에 개발 관련해서 뭔가를 물어보면 쓸 만한 답변을 하질 못했다. 답변을 받았더라도 이를 검증하기 위해 다시 구글링을 해야 했기 때문에 크게 도움이 되진 않았다. 💡 우연히 시작된 AI 코딩 ChatGPT를 코딩에 사용한 것은 우연한 기회였다. 집사람 친구 딸이 학교에서 코딩 숙제가 나왔는데 도저히 모르겠다고 도움을 요청해 왔다. 간단한 계산기였던가 그랬던 것 같은데, 직접 코딩해서 돌아가는지 확인하는 것까지는 귀찮아서 혹시나 하는 마음에 ChatGPT에 작성을 지시했다. 어라. 대충 눈으로 컴파일했을 때 문제없이 동작할 것 같은 코드가 나와서 그걸 보내줬다. 그러면서 개발에 ChatGPT를 사용하기 시작했다. 간단한 함수 단위로 머리 쓰기 싫을 때 작성을 맡기고 복사해서 붙여넣는 방식이었다. 그럼에도 이걸 적극적으로 사용할 수 없었던 것은 코딩에도 환각이 발생했기 때문이다. 코드에서 환각이 발생할 일이 뭐가 있겠냐 싶겠지만, 정확히 기억은 안 나는데 무엇인가를 구현해야 했는데 잘 모르는 부분이라 GPT에게 요청했다. 언제나 그렇듯이 매우 그럴듯한 코드를 뽑아줬다. 다만 존재하지 않는 패키지를 사용하라는 가이드와 함께... 그래서 간단한 함수 작성 같은 경우에만 쓰다가 이것도 귀찮아서 잘 사용하지 않게 되었다. ⚡ GitHub Copilot — ID...

수경재배 상추 두 번째 도전 - 그로잉스펀지 비교와 TDS 측정기 활용 후기

두 번째 수경재배 상추 도전기 게으름으로 인하여 두 번째 상추 재배는 수확까지 끝난 다음에야 포스팅을 하게 되었습니다. 두 번째 상추 재배는 새로운 그로잉스펀지와 재배기에 심을 수 있는 12포트 중에서 4포트만 사용하여 상추를 재배했습니다. 그리고, TDS 측정기를 이용하여 양액의 농도 측정도 하면서 재배를 하였습니다. 새 그로잉스펀지 - 네모 스펀지 사용기 수경 재배기를 살 때 포함되어 왔던 그로잉스펀지는 지난번 상추 재배로 인하여 모두 소비되어서 알리에서 새로운 스펀지를 주문했습니다. 주문하면서 실수로 동그란 스펀지가 아닌 네모 스펀지를 주문하는 바람에 포트에 넣었을 때 약간의 공간이 생깁니다만 크게 문제가 되지는 않습니다. 그런데 이번에 스펀지는 번들 스펀지에 비해서 밀도가 높다라고 해야할지 스펀지에 구멍이 적은 것 같습니다. 상추 뿌리가 스펀지를 뚫고 나오는데 지난번 보다 오래 걸린것 같습니다. 다음에 주문할 때에는 이런 부분을 좀 주의해야 할 것 같습니다. TDS 측정기로 양액 농도 관리 스펀지와 함께 TDS 측정기도 함께 구매해서 양액의 농도도 측정하였습니다. 상추의 경우 560 ~ 840 정도의 TDS 범위로 양액을 맞춰주라고 하는데, 수경 재배기에 번들된 양액을 12포트 분량으로 혼합하면 이 범위를 만족합니다. 지난번 재배에서는 이 값을 몰라서 싹을 틔우는 시기와 어린 시기에 양액 농도를 낮게 했었는데 그럴 필요는 없었던 것 같습니다. 5주 후 수확 결과 약 5주 가량 길러서 수확하기 직전의 상태입니다. 12포트를 키울 때 보다 빛을 잘 받아서 그런지 웃자람도 없고, 상치 잎의 크기도 지난번보다 상대적으로 컸습니다. 보통 상추를 키울때, 잎이 커지면 일부를 따 먹으면서 계속 키우는데 4포트만 키우게 되면 잎을 따 먹기에는 양이 너무 적어서 다 키워서 한번에 수확을 해야 했습니다. 그래서 다음 재배는 포트수를 조금 더 늘려서 시도해보겠습니다.

iOS Privacy Manifest(PrivacyInfo.xcprivacy) 설정 가이드 - Xcode 프로젝트 적용 방법

Privacy Manifest 요구사항 개요 Apple App Store는 2024년 5월 1일부터 배포되는 앱(신규, 업데이트 모두)에 대해서 Privacy Manifest 를 포함을 요구하고 있습니다. 아마 저를 포함하는 많은 개발자들이 이 사항을 가지고 머리를 싸매고 있지 않을까 생각이 됩니다. Privacy Manifest를 프로젝트에 포함시키는 것은 기술적으로 어렵지 않고 애플도 비교적 잘 설명된 문서들을 제공하고 있습니다. ( 참고1 , 참고2 ) 그리고, 이미 많은 글에서 이것에 대해서 설명하고 있습니다. 서드파티 SDK와 Privacy Manifest의 의미 저는 애플의 이러한 정책의 방향성은 훌륭하다고 생각합니다. 요즘 개인정보 관련한 정보 제공 요구가 나날이 강화되고 있는데, 앱 개발자 입장에서 내가 작성한 코드에 대해서는 그나마 알 수 있지만, 요즘과 같이 많은 서드파티 SDK 의존성을 바탕으로 앱을 개발하고 있는 상황에서 각 서드파티 SDK에서 수집되는 정보를 일일이 파악할 수도 없으며, 이들이 이 정보를 이용하는 목적은 더더욱 알기가 어렵기 때문입니다. 그리고, 단순 "수집"이냐 "추적"이냐 까지 파고 들려면, 용어도 어렵고, 정책적 부분이 판단도 애매한 상황에서 개발자가 자신이 개발한 앱에서 수집하는 개인정보에 대해서 모두 제공하는 것은 불가에 가깝습니다. 그래서 앱 스토어에서 "앱이 수집하는 개인정보" 섹션을 채우라고 했을 때는 개인정보를 수집할 것 같은 서드파티들의 기술지원 페이지를 참고해서 항목들을 정리해야하만 했습니다. 이번 애플 정책 요구에서 눈에 띄는것은 각 서드파티에서 제공하는 SDK에도 Privacy Manifest를 포함하도록 요청하고 있습니다. 이로 인해서 개발자는 내가 개발하는 코드에서 수집되는 정보에 대해서 좀 더 집중할 수 있습니다. 다만, 오래된 서드파티 SDK 버전을 사용하는 경우에는 부득이 업데이트를 하거나 대안을 찾거나 하는 피곤한 상황이 생...

수경재배 상추 47일차 - 최종 수확량과 경제성 분석

상추 추수 이후 성장 현황 지난번 상추 추수 이후 많이 자랐습니다. 상추 잎을 따내고 나면 위 사진과 같이 앙상한 상추들이 보입니다. 역시 빛이 약하다보니 수경재배기의 LED 빛을 잘 받는 가운데 부분 이외의 포트에서 자라는 상추는 웃자람이 심하여 제대로 서 있질 못하게 되어 여기에서 더 키우는 것은 한계인 것 같아서 웃자람이 덜한 가운데 3포트만 남기고 나머지는 모두 따냈습니다. 12포트 50일 수확량과 경제성 분석 50일 약간 안되는 기간동안 12포트에 씨를 심어서 따낸 상추잎은 마트에서 소분해서 파는 봉지기준으로 4~5봉지 정도 되는 것 같습니다. 수경재배기 구입비용, 전기요금 등을 감안하면 한두번 키워서는 경제성이 형편없습니다. 그리고, 향후 투입될 양액 구매비용과 그로잉스펀지(수경재배기의 각 포트에 끼워서 상추를 키워내는 배지) 구매비용등을 감안하면... 장기적으로도 경제성은 없을 듯 합니다.. 그냥 재미로... 다음 재배 계획 새로 주문해 놓은 그로잉스펀지가 도착하면 12포트 대신 4~5포트만 심어서 키워서 웃자람이 덜하게 키워볼 예정입니다. 이 글은 이번 재배에 대해서는 마지막 포스트입니다..

[iOS/Flutter] CocoaPods CDN trunk URL SSL 인증서 오류 해결 방법

문제 배경 - Privacy Manifest 대응 중 발생 Apple에서 Privacy manifest 파일 추가를 요구하여 이와 관련된 수정 작업을 진행하고 있습니다. 이 요구에는 내가 개발한 소스 뿐만 아니라 서드파티 SDK를 사용하는 경우에 해당 서드파티 SDK도 privacy manifest을 포함해야 한다라는 요건이 있어서, 개발중인 프로젝트에 privacy manifest를 추가해야 하고, 서드파티 SDK도 privacy manifest를 포함한 버전으로 업데이트를 해야만 하게 되었습니다. NSUserDefaults 만 사용하더라도 privacy manifest 포함해야 하기 때문에 상당히 많은 서드파티 SDK를 함께 업데이트 해야한 합니다. 그리고, 서드파티들도 최근에 이것을 지원하고 있기 때문에 거의 최신 버전을 사용해야 합니다. 그리고, 이로 인해서 부득히 빌드 체인도 함께 업데이트 해야하게 되었습니다. 더더욱 flutter로 안드로이드도 함께 개발하다보니 안드로이드 빌드 체인도 함께 업데이트해야 해서 일이 커졌습니다. 오류 내용 - CDN trunk URL SSL 인증서 오류 업데이트를 위한 작업중 pod install 과정에서 아래와 같은 오류가 발생했습니다. CDN: trunk URL couldn't be downloaded: https://cdn.jsdelivr.net/cocoa/Specs/0/3/5/Firebase/10.25.0/Firebase.podspec.json Response: SSL peer certificate or SSH remote key was not OK 오류 메시지에 포함된 URL을 웹 브라우저로 접속해보면 인증서가 만료된 상태입니다. 뭔가 저장소 관리에 문제가 있는 모양입니다. 오류 내용으로 검색해보면 주기적으로 문의가 올라오는데, 된다고 하는 방법으로도 안되는 걸로 봐선 발생하는 경우에 발생하는 원인이 여러가지 일 수도 있는 것 같습니다. 해결 방법 - Podfile에 저장소 명시적 지정...

수경재배 상추 36일차 - 첫 수확과 솎아주기 후기

36일차 상추 성장 상태 그 동안 상추가 이 만큼 자랐습니다. 광량이 부족해서인지, 양분이 부족해서인지 밭에서 키우는 상추보다 잎이 여린데, 크기는 시중에 파는 상추 정도의 잎 크기가 되었습니다. 포트의 간격이 좁아서 자기네 끼리 가려서 빛을 받지 못하는 잎도 많아지고 해서 큰 잎을 위주로 솎아야 겠습니다. 첫 수확 - 두 사람이 먹기 충분한 양 이 만큼의 잎을 따 주었습니다. 두 사람 정도가 한 번 먹기에는 충분한 분량이 나왔네요. 솎아주기 후 재배기 상태 수경 재배기에는 이렇게 볼품 없는 상추들이 남았습니다. 곧 다시 풍성해지겠지요. 자라는 걸 보고 포트간의 간격이 너무 좁아서 크는데 문제가 있다고 생각되면 중간 중간 비워 주던가 해야겠습니다.

수경재배 상추 25일차 - 잎이 상추다워지고 물갈이 완료

25일차 성장 상태 - 상추다운 잎 수경 재배기에 상추를 파종한지 25일 되었습니다. 수경 재배기에 딸려 온 수경 포트가 뚤려 있는 구멍에 씨앗을 넣어두는 형태로 되어 있어서, 뿌리와 잎의 경계(줄기??) 부분이 흙에 심었을 때 처럼 잘 잡아주지는 못하는 형태여서 줄기 부분이 아직은 많이 가늘어서 누운 애들도 있고, 빠빳하게 하늘을 향해 서려면 좀 시간이 더 지나야 할 것 같습니다. 그럼에도 불구하고 그 동안 이만큼 자라서, 이제 상추가 좀 상추다워 졌습니다. 다음에는 씨앗을 스폰지에 끼우는 방식으로 해 봐야겠습니다. 2주 전 양액을 추가할 때에는 물이 줄어든것이 거의 눈에 띄지는 않았었습니다. 이번에는 잎이 커지면서 증산 작용도 활발해져서, 수조에 넣어 놓은 물도 700ml 가량이 줄어 들었습니다. 뿌리 성장 현황 이젠 뿌리도 많이 생겼지만, 아직은 갈 길이 먼 것 같습니다. 2주차 물갈이 - 양액 A/B 각 10ml 투입 지난 번에 양액을 넣어주고 2주가 흘러서, 전체 물갈이를 해주었습니다. 양액은 지난번과 같이 4L 수조에 A/B 용액 각 10ml씩 넣었습니다. 빨리 상추 쌈을 싸 먹는 날이 왔으면 좋겠네요..

수경재배 상추 10일차 - 첫 양액 투입과 A/B 용액 배합 방법

파종 10일 후 성장 현황 상추를 파종한지 10일이 지나서 상추들이 이만큼 자랐습니다. 뿌리 성장 상태 상추의 뿌리가 포트 밖으로 빠져나올 정도로 길게 자랐습니다. 그래도 아직은 뿌리의 가닥 수도 작고, 가늘고 약합니다. 사무실에 사람이 있는 동안은 난방을 하니까 괜찮은데, 저녁에는 아직도 기온이 많이 내려가기 때문에 성장이 더딘것 같습니다. 이제 낮기온도 꽤 올라가고 꽃도 피기 시작하니까 멀지 않아서 폭풍 성장을 할 것 같습니다. 양액 A/B 용액 배합 방법 수경재배기 메뉴얼에서는 2주에 한 번 전체 물을 갈아주고, 그 외에는 보충을 해주라고 되어 있습니다. 아직 상추가 싹이 작기도 하고, 10일 밖에 지나지 않았지만, 그 동안 물로만 키우고 있었기 때문에 오늘은 양액을 넣어 주기로 했습니다. 그래서 전체 물갈이를 할 예정입니다. 우선 양액을 준비합니다. 국내에서 많이 판매되는 양액이 있기는 합니다만, 수경재배기에 포함되어 있는 양액을 먼저 사용하려고 합니다. 수경재배기에 포함되어 있는 양액은 액체 상태가 아닌 알갱이 상태로 두 개의 병에 담겨 있습니다. 각 병에 물 100ml 씩을 넣고 알갱이가 다 녹을 때까지 섞어 줍니다. 병에 100ml 눈금이 표시되어 있기 때문에 눈금까지 넣어 주면 됩니다. 메뉴얼 상에는 역삼투압 방식으로 정수된 물을 사용하라고 하는데, 전 그냥 수돗물을 사용했습니다. 순수한 물을 사용하면 아무래도 양액의 농도나 같은 것들이 좀 더 정확해 지지 않을까 싶긴 합니다만, 사무실에 정수기도 없고.... 그렇다고 약국에 증류수를 사러가기도 뭐하고.. 근처에 약국도 없고.. ^^;;;;;;; 여튼, 알갱이가 다 녹을 때까지 섞어 줍니다. A용액은 약간 노란빛이 드는 액체가 되고, B용액은 투명색을 그대로 유지합니다. 양액 희석과 수조 채우기 2L 생수병에 물 2L를 채우고, A용액을 10ml 넣어준 다음에 B용액 10ml 를 추가하였습니다. A/B용액이 직접 만나게 되면 화학 반응이 일어날 수 있는 모양입...

[iOS] iOS App Store 유럽 연합(EU) 디지털 서비스법(DSA) 규정 준수 - 거래자 제공업체 계정?

앱에 대한 고객 리뷰를 보기 위해서 App Store Connect 에 접속을 하니, 불안감을 조성하는 붉은색 알림이 하나 표시되고 있었습니다. 디지털 서비스법에 따라 정보를 제공 하라는 메시지입니다. 일단, 무슨 법에 따라서 변경 하라는 메시지는 법을 잘모르는 입장에서는 괜히 부담이 많이 갑니다. 용어도 잘 모르겠고, 이것으로 인하여 나에게 미치는 영향도 잘 모르겠는 경우가 많아서 입니다. 그렇다고 무시하면 앱 배포가 중단될 수 있다는 협박성(?) 내용이 항상 뒤 따르기 때문에 잘 모르더라도 해야만 합니다. 그래서 규정 준수를 위하여 링크를 타고 들어가면 아래와 같은 절차를 만나게 됩니다. 디지털 서비스법은 유럽 연합(EU)에서 정한 법인 것은 알겠고, "거래자 제공업체 계정", "비거래자 제공업체 계정" 둘 중에 하나를 고르면 되는 것으로 보입니다. 심리적으로는 왠지 모르게 "거래자 제공업체 계정"에 해당할 것 같은데, 거래자가 뭔지 모르겠으니, "거래자 자격이 있는지 더 알아보기"를 클릭해서 해당 설명이 있는 페이지로 이동합니다. (불친절한) 애플 가이드 페이지가 보여지고, 거래자에 대한 설명은 아래와 같이 되어 있고, EU에서 제공하는 홈페이지 링크가 하나 걸려 있습니다. DSA에서는 거래자를 “개인 또는 공공 소유 여부와 무관하게 자신의 명의로 또는 자신을 대신하여 행동하는 사람 또는 모든 자연인,  그리고 무역, 비즈니스(Business), 기술 또는 직업과 관련된 목적을 위해 행동하는 모든 사람” 으로 정의합니다. 귀하가 거래자에 해당되는지 여부는 법률 고문과 상담하십시오.( # ) 위 문장을 제가 이해하기에는 앱스토어에 앱을 배포하는 모든 사람/회사는 거래자에 해당할 것 같습니다. 그럼 나는 "거래자 제공업체 계정"을 선택하면 될 것 같은데, 그럼 "비거래자 제공업체 계정" 선택이 필요 없지 않은가라는 의문이 들었습니다. 아니면 애플에서 ...

수경재배 상추 파종 3일차 - 싹이 돋았습니다

12포트 중 8포트 발아 성공 사무실 수경 재배기에 뿌려 놓은 상추 씨앗이 주말 동안 싹을 틔웠습니다. 오래된 씨앗이라서 싹이 날지 걱정했는데, 12 포트 중에서 8포트가 싹이 났습니다. 남은 포트와 뿌리 노출 문제 4포트가 아직 소식이 없는데, 조금 더 지켜보고 다시 파종 해야 겠습니다. 씨앗이 흙에 묻히는 구조가 아니라서 뿌리가 LED 빛에 노출되는 구조인데, 문제 없는지 모르겠네요. 뿌리에는 빛이 안가는게 좋을 것 같은데...

가정용 수경재배기 구매 후기 - 사무실에서 상추 키우기 시작

식집사가 되기로 결심한 이유 식집사라는 말이 요즘 유행하는 것 같습니다. 저는 식집사까지는 아니고, 화분에 뭔가를 키우는 걸 좋아합니다. 다만, 애써 뭔가를 사서 하거나 하지는 않고, 생기면 물주고 최대한 안죽이고 키운다 정도였습니다. 집에서 키우는 호야, 벤자민고무나무 같으면 누나가 주고.. 형이 주고.. 해서 한식구가 되었고, 죽이지 않고 10 수년째 키우고 있는 중입니다. 단지, 분갈이도 안해주고, 물만 주고, 가끔 다이소 같은데서 파는 비료 조금 넣어주는 정말 죽지 않고 버티게만 하고 있다는 표현이 맞을 것 같습니다. 그리고, 상추, 고추 같은걸 화분에 키워서 먹는걸 좋아합니다. 키우는 기간도 짧고 뭔가 결과물도 있고.. ^^; 그런데, 집이 아파트이다 보니 햇볕도 부족하고 키울 공간도 부족해서 부족함을 느끼다가, 2~3년 전에 사무실 근처에 텃밭을 조금 빌려서 상추를 기른 적이 있는데, 저랑은 좀 맞지 않더군요.. 너무 열심히 가꿔야 한다라는 제약이 있더군요. 하루 이틀만 게을리하면 잡초가 상추보다 더 많이 나고.. 땅은 정말 조금인데 수확물은 감당할 수 없고.. 해서 이후로는 상추 같은건 그냥 사먹는 걸로 하고... 농사(?)는 안하는 걸로 했습니다. 요근래 뭔가를 다시 키우고 싶다는 생각이 들었습니다. 좀 열심히.. 그래서 저도 식집사가 되어 보기로 했습니다. 돈도 좀 쓰고.. ㅡ.ㅡ;; 알리익스프레스 12포트 수경재배기 선택 그 첫번째 시도로 사무실에 농장을 만들어 보기로 했습니다. 바로 가정용 수경 재배기라는 것을 구매해 보았습니다. G마켓, 알리 같은데 보면 많은 종류의 수경재배기를 판매하고 있습니다. 작은 것 부터 큰 것 까지 종류가 참 많더군요.. 가격도 싼것 부터 비싼것 까지 다양하게 있더군요.. 전 알리에서 $43정도 하는 12포트짜리 수경 재배기를 구매하였습니다. 이걸 선택한 이유는 사무실 책상에 놓고 키우기에 크기도 적당하고, 자체 조명도 있어서 햇볕 걱정도 하지 않아도 되고, 보기도 나름 나쁘지 않고, 처음 시도부...

[flutter] deep link

 개발하고 있는 앱에서 다른 사용자를 앱으로 초대하는 기능을 추가하게 되어 앱에 deep link 기능을 앱에 구현하게 되었습니다. 구현에 필요한 자료는 이미 더 잘 정리되어 있는 많은 자료들이 있으니 그것들을 참고하면 될 것 같아서 여기에서는 특별히 설명하지 않습니다. 다만 내 앱에 해당 기능을 넣기 위해서 자료를 찾고 구현하는 과정에서 헷갈렸던 것들과 구현중 문제가 있었던 부분에 대해서 프로젝트를 정리하는 차원에서 메모를 남기기로 해서 글을 쓰고 있습니다. 참고:  - https://itnext.io/deep-linking-in-flutter-boost-user-experience-in-apps-29dd25842757  - https://docs.flutter.dev/ui/navigation/deep-linking 용어 deep link는 보통 웹에서 인덱스 페이지가 아닌 상세 페이지에 대한 다이렉트 링크를 생성하는 것을 말합니다. 예를 들어서 어떤 웹페이지를 사용하기 위해서는 홈 화면에서 로그인을 하고 몇 단계를 거쳐서 특정 페이지로 들어가야하는데, 이 기능에 대한 지름길을 만드는걸 deep link로 이해하면 되겠습니다. 그리고 deep link 구현관련하여 모바일에서는 OS에 따라서 custom scheme(url scheme), universal link, app link 등의 용어가 튀어 나오는데, 표준 URI 형식을 이용하여 앱을 실행시키기 위한 방법을 말한다고 이해하면 간단하겠다. 기술에 대한 상세로 들어가면 약간의 차이가 있으나 큰 틀에서 차이는 없기 때문에 deep link를 구현하기 위해서 app을 실행(lunch)하기 위한 기술이라고 보면 됩니다. 그리고, 검색하다가 보면 dynamic link라는 용어가 나오는데, firebase에서 제공하던 서비스인데 현재는 서비스 종료되었으니 무시하면 됩니다. Navigator / Router flutter로 deep link를 구현할 때 현재 앱이 Navigator를 이용...

[flutter] textScaleFactor

노안이 있는 사람이나 시각 장애가 있는 사람들은 모바일 환경의 기본 글자 크기에 불편함을 느끼는 사용자들을 위해서 iOS와 안드로이드에서는 접근성 설정을 통해서 글자 크기를 크게 또는 작게 설정할 수 있도록 지원하고 있습니다. 그리고, 앱 개발시에도 이를 고려하여 개발하라고 가이드하고 있습니다. 그렇지만 앱 개발 단계에서 이런 부분이 몰라서, 귀찮아서 또는 디자인과 같은 현실적 한계로 인하여 가이드를 무시하고 개발되는 경우가 종종 발생하게 됩니다. 이렇게 접근성 설정을 무시하고 앱을 개발하면 앱 접근성 설정을 이용하는 사용자 환경에서 화면이 깨지거나, 사용상의 문제를 발생시키는 경우가 발생합니다. 또는 앱 심사 과정에서 거부되기도 합니다. 그런데 이런 문제가 인식된 시점에 디자인 변경이 어렵거나, 변경해야 하는 범위가 커서 접근성 설정을 무시하고 기본 글자크기로 나오도록 하여 문제를 회피하여 해결해야하는 방법을 알아보겠습니다. 아래 방법은 flutter에서 문자의 비율을 시스템에서 설정하는 값이 아닌 개발자가 기본 비율로 강제하도록 하여 접근성 설정이 무시되도록 하는 방법입니다. Widget build(BuildContext context) { // 사용자가 OS에서 제공하는 접근성 설정을 변경할 경우, 앱의 폰트 크기가 변경되는 것을 방지한다. // 폰트 크기가 크게 변경되면 다이얼로그의 레이아웃이 깨져서 다음 단계로 진행하지 못하는 경우가 발생함. final mediaQueryData = MediaQuery.of(context); final newMediaQueryData = mediaQueryData.copyWith(textScaleFactor: 1.0); return MediaQuery( data: newMediaQueryData, child: Container() ) } 내용이 잘못되었거나, 더 좋은 방법이 있으면 댓글 남겨주시기 바랍니다.

[flutter] 모바일 앱 재시작 또는 종료

모바일 앱을 개발하다 보면 앱을 재실행 시키거나 코드에 의한 종료를 해야하는 경우가 발생합니다. 예를 들어서 앱의 전반에 걸쳐서 영향을 끼치는 설정을 초기화하고 새로 로딩해야 하는 경우가 있습니다. 이런 경우에는 해당 설정값만 다시 로딩하는 방법도 있겠지만, 이 값이 여러곳에 영향을 끼친다던가 초기화 해야하는 값들이 많다던가 하면 머리가 아파지고, 앱을 재시작 시켜서 자연스럽게 설정값을 읽어들지게 하는게 자연스러울 수 있습니다. 그런데, iOS와 안드로이드 모바일 환경에서는 코드에 의해서 앱을 재실행 시키거나, 종료 시키는 것에 대해서는 권장하지 않으며, iOS의 경우에는 이런 기능이 들어가면 앱 스토어 심사 단계에서 거부될 수 있습니다. 그래도 좋은 사용자 경험을 위해서 앱의 종료나 재시작이 꼭 필요한 경우에는 구현을 하는게 좋습니다. 앱 재시작 설정 초기화 후 앱을 재로딩이 필요한 경우라면 앱이 자동으로 재시작 되는 것이 앱이 종료되는 것 보다는 더 좋은 사용자 경험을 제공합니다. 그런데 iOS에서는 앱을 재시작 시킬 수 있는 방법을 찾지 못해서 안드로이드에서 재실행 시키는 방법만 정리하도록 하겠습니다. flutter 에서 제공하는 기능만으로 앱을 재시작 시키는 방법은 아직 찾지 못했고, 메소드 채널을 이용하여 네이티브 코드로 구현하셔야 합니다. PackageManager packageManager = getPackageManager(); Intent intent = packageManager.getLaunchIntentForPackage(getPackageName()); ComponentName componentName = intent.getComponent(); Intent mainIntent = Intent.makeRestartActivityTask(componentName); startActivity(mainIntent); System.exit(0); 참고 : https://ideaj...

Xcode 15 - ipa is not a valid bundle.

 Xcode 15.0.1(15A507) 업데이트 후 ipa 파일을 생성해서 XCode의 Device 메뉴를 통해서 ipa 설치시 아래와 같은 오류가 발생합니다. Error installing  'xxxxxx.ipa', ERROR: Error Domain=com.apple.dt.CoreDeviceError Code=3002 "Failed to install the app on the device." UserInfo={NSLocalizedDescription=Failed to install the app on the device., NSURL=file:///xxxxxx.ipa, NSUnderlyingError=0x600005c85c80 {Error Domain=com.apple.dt.CoreDeviceError Code=3000 "The item at xxxxxx.ipa is not a valid bundle." UserInfo={NSURL=file://xxxxxx.ipa, NSLocalizedDescription=The item at xxxxxx.ipa is not a valid bundle., NSLocalizedFailureReason=Failed to read the bundle.}}} Domain: com.apple.dt.DVTCoreDevice Code: -1 User Info: {     DVTErrorCreationDateKey = "2023-11-20 06:30:34 +0000"; } -- System Information macOS Version 14.1 (Build 23B74) Xcode 15.0.1 (22266) (Build 15A507) Timestamp: 2023-11-20T15:30:34+09:00 ipa 파일이 유효하지 않은 번들이라는 오류 입니다.  인증서, 프로비저닝 등은 Xcode에서 자동 생성하는 것을 사용하였고, 단말은 테스트 단말로 등록되어 있는 단말임에도 ...

Admob UMP(Google User Messaging Platform) SDK를 이용한 GDPR(General Data Protection Regulation) 대응

얼마 전 부터 운영중인 앱의 Admob 계정을 들어가면 화면 상단에 아래와 같은 눈에 거슬리는 공지가 표시되기 시작했습니다. "올해 안에 EEA 및 영국 사용자에게 광고를 게재하는 모든 게시자는 Google에서 인증한 동의 관리 플랫폼(CMP)을 사용해야 합니다. Google의 자체 동의 관리 솔루션을 포함하여 Google에서 인증한 CMP 이면 어떤 것이든 이 목적으로 사용할 수 있습니다. Google의 동의 관리 솔루션을 사용하는 데 관심이 있으면 먼저 GDPR 메시지를 설정하고 UMP SDK를 구현하세요." 유럽쪽 사용자에 대해서 GDPR(General Data Protection Regulation) 동의 를 받을 수 있도록 하라는 것이다. GDPR 동의에 대해서 처리해야할 법적인 절차를 잘 모르니 친절한(?) Google의 도움을 받을 수 있다고 하니 받는 것으로 했습니다. 메시지를 보면 구글에서 인증한 동의 관리 플랫폼(CMP)를 사용하거나, 구글에서 제공하는 UMP SDK를 이용해서 구현 하면 된다는 내용입니다. 구글에서 UMP SDK를 제공한다고 하니, 이용하기로 합니다. UMP SDK 는 별도의 SDK 형태로 배포되지 않고, Admob SDK에 포함되어 있고, UMP SDK를 이용하여 구현하는 것은 가이드 페이지에 있는 것을 따라가면 되는 수준이라 여기에서는 생략하도록 합니다. # 참고 : - https://support.google.com/admob/answer/10113207 - https://developers.google.com/admob/ios/privacy - https://developers.google.com/admob/android/privacy - https://developers.google.com/admob/flutter/eu-consent 저의 경우에는 구현은 어렵지 않게 했으나, 이 것의 동작을 이해하는데 오랜 시간이 필요했습니다. 그 이유는 사용자로부터 개인정보 이용에 대한 동의를 얻지 못했을 때 광...