2026년 7월 13일 월요일

[기술조사] Device Fingerprinting (디바이스 핑거프린팅)

Device Fingerprinting (or Browser Fingerprinting)

웹앱(Web Application)을 제작구상을 하다보니, 스마트폰을 식별하는 기술이 있을까 고민하게 되었습니다. LTE 또는 5G망에서 공인IP, Javascript에서 스마트폰 고유식별번호 확인, 동일한 스마트폰, 등등...
검색과 LLM(Gemini)를 통해서 알아보니, 생각한 방안들이 제한되어 있거나, 불가능한 것이 많았습니다.

웹브라우저 / JavaScript 환경에서 스마트폰를 식별하는 기술을 기기 핑거프린팅 또는 브라우저 핑거프린팅이라고 합니다. 해당 기술에 대해서 결론부터 말하면, 동일한 시점에 출고된 100% 같은 기종을 완벽하게 식별하는 것은 이론상 매우 어려운 것으로 판단하였습니다. 

실제, 동일 모델 간에 미세하게 달리지는 소프트웨어 설정, 사용환경, 하드웨어 미세 오차를 조합해서 높은 확률로 식별할 수 있을 것 같습니다. 스마트폰의 식별하기 위해서 몇 가지 스마트폰 정보를 모아서, 나만의 고유한 조합(해시값)을 만드는 방식입니다


스마트폰 정보 (Web Browser / JavaScript 환경에서 수집할 수 있는 정보)

 1. 운영체제(OS)정보, 웹브라우저(Web Browser) 정보
 2. 디스플레이의 가로/세로 픽셀 크기, DPR(Device Pixel Ratio)
 3. 설치된 폰트 리스트(기본적으로 탑재된 폰트 + 사용자가 추가로 설치한 서체 목록)
 4. 오디오 연산
 5. 그래픽카드 WebGL 또는 Canvas
 6. 사용자의 다크모드 설정
 7. 터치 스크린 최대 동시 터치 가능 수
 8. CPU 논리 코어 수
 9. 기타 등등...


현실에서 스마트폰은 겉보기엔 같아도 내부 상태가 다를 것입니다. 
위의 요소를 선별적으로 조합하고 추가 로직이 들어간다면 고유식별율이 높아질 것이라 예상됩니다. 그리고 아이폰/안드로이드 폰에 따라서 수집한 정보가 의미가 없을 수도 있습니다. 특히, 아이폰은 하드웨어 정보를 숨기기 때문에, GPU, 모델명, 메모리 정보를 얻을 수 없거나, 상세한 정보를 제공 안합니다. 

스마트폰의 모든 요소가 같다면, 식별할 방법이 없습니다. 



서버측에서도 수신 IP는 단순 참고할 수 있는 정보입니다. 스마트폰을 고유식별성에는 문제가 있습니다. 
같은 공간에서 통신사가 동일한 스마트폰 2개를 사용되는 경우, 똑같은 공인 IP가 될 수 있습니다. 


곧, 직접 코드로 확인해볼려고합니다. 

[기타] 구글 애드센스 승인 - 재신청

구글 애드센스 승인 거절 

https://www.microlabs.info/2026/07/blog-post_04.html

동일한 사유로 거절되었습니다. "주의필요", "가치가 별로 없는 콘텐츠" 

확인해보니, 몇 가지 설정이 안되어 있어 승인이 거절된 것으로 보입니다. 구글 검색 사이트에서 저의 글이 검색이 안되고, Google Search Console에서도 글이 색인이 안되어 있습니다. 

블로그 포스팅 20여개 이상 있는데, 구글에서 검색이 안되는 것입니다. LLM를 이용해서 "애드센스 승인과 구글 서치 콘솔(Google Search Console)"과 연관이 있는지 문의했습니다. 관련이 있다고 합니다. 구글에서 검색을 할 수 있어야, 애드센스 심사를 할 수 있나 봅니다. (추측)

- Google Search Console : Sitemap 추가 유무 확인
- Google Blog(Blogger.com) : 설정 - 맞춤 로봇 헤더 태그 사용설정 활성화

Google Search Console의 Sitemap 추가는 Atom, RSS 모두 등록했습니다. 검색이나 LLM(Gemini)에서는 sitemap.xml 등록하라고 하는데, sitemap.xml 추가가 안됩니다. "https://주소/sitemap.xml" 입력은 되지만, 블로그 정보를 가지고 올 수 없는 것으로 보입니다. 그리고 RSS피드 하나만 성공적으로 등록되어 있다면, 그것만으로도 충분하다고 합니다. 

Google Blog(Blogger) 설정에서 맞춤 로봇 헤더 태그 사용설정을 했습니다. 하부 세부 설정을 해야하는데, Gemini가 제시해준대로 하부설정을 하였습니다. 

Google Search Console, URL 검사를 통해서 '수동 색인 요청'을 해보려고 합니다. 
포스팅 주소를 입력 후, [색인 생성 요청] 클릭하면 됩니다. 3개 정도 신청하려고 합니다. 


Adsense 검토요청 다시 합니다. 




참고 : 초기 작은광고(배너) 단순 노출 1000회이면 약0.5달러 내외로 조사하였습니다. 방문자의 체류시간이 길어지면, 더 비싼 광고를 매칭해주어 수익이 상승할 수 있다고 합니다. 

2026년 7월 12일 일요일

[웹앱] SyncGo (Synchronize and Go)

SyncGo (Text 복사)

https://syncgo.microlabs.info/


컴퓨터로 작업하다가 스마트폰으로 긴 텍스트나 링크를 보내야 할 때, 보통 어떻게 하시나요?
보통 생각하는 것에 메일(자신에게 보내기), 카톡 등을 사용할 것입니다. 메일 로그인 하는 것, 카톡 사전 설치 등 좀 번거롭습니다. 

컴퓨터를 2~3대로 작업하는 경우, 간단한 설정내용, 코드, 라이선스 키 등을 빨리 복사해서 사용했으면 하는 경우가 간혹 있습니다. 컴퓨터와 스마트폰 간에도 텍스트를 쉽게 복사하고 싶을 때도 가끔 있습니다. 


SyncGo는 어떤 서비스?

 - 별도의 프로그램이 앱을 설치할 필요 없이, 웹브라우저만 있으면 컴퓨터-컴퓨터, 컴퓨터-스마트폰간에 텍스트를 간편절차로 복사/붙여넣기 할 수 있는 초간단 웹앱(Web Application) 입니다. 


주요 특징

 - 회원 가입 필요 없이 바로 사용가능 : 복잡한 가입절차 없이 웹사이트에서 접속해서 바로 사용
 - OS 제약 없음 : 인터넷만 연결되어면 사용가능
 - 프로그램 설치 필요없음 : 웹브라우저로 SyncGo주소로 접속, 즐겨찾기(북마크)로 등록

 
이럴 때 사용하면 정말 편해요!

 - 컴퓨터로 찾은 맛집 주소, 링크 
 - 인증번호, 계좌번호, 지갑주소 
 - 컴퓨터에서 작성한 긴 문장
 - 컴퓨터간에 코딩할 때, 일부코드 복사
 - LLM 답변 복사, 등




텍스트를 입력하고 [저장]버튼을 누르면 
접근코드, URL, QR Code(URL)
출력됩니다. 




접근코드(5자리)를 입력하면 
작성한 텍스트 내용을 보여줍니다.

텍스트를 입력할 때 설정한 유효시간이 지나면
자료는 삭제됩니다.


텍스트는 100KB 제한이 있습니다. 또한, 유효시간은 5~720분(5분~12시간)까지 설정할 수 있습니다. 기본값은 30분으로 설정하였습니다. 접근코드(AccessCode), URL, QR Code(URL)을 통해서 저장된 텍스트를 확인할 수 있도록 하였습니다. 

사용해 보시고 아쉬운 점이나 필요한 기능이 있다면 댓글로 남겨주세요. 


개발자노트 : 개발초기에 무의식적으로 SincGo문구로 적용해서, 막판에 SyncGo로 다 변경했습니다. 참고로, 파일복사기능도 고민하고 있습니다. 


#텍스트복사 #기기간텍스트전송 #생산성앱 #유용한사이트 #싱크고 #SyncGo

2026년 7월 5일 일요일

[웹앱] 희석용량, 희석배율 계산기

희석용량 계산기, 희석배율 계산기



일상 속에서 또는 업무 중에 락스 소독액, 농약, 식물 액체비료(액비), 차량 디테일링 용품 등을 희석할 때마다 계산을 해야 했습니다. 

"물을 1L에 500배로 희석하려면 원액을 몇 mL 필요하지?"
"원액 3mL가 물에 섞었는데 혼합비율이 어떻게 되지?"

설치할 필요없이 희석용량 & 희석배율 계산기 웹앱을 사용하세요.  

 - 물의 양과 희석배수를 입력하면 사용량이 계산됩니다.
 - 물의 양과 물질 용량을 입력하면 혼합비율(희석배수)가 계산됩니다. 


희석의 목적
- 농도조절 : 용액의 농도를 조절하고 특정 농도의 용액을 얻기 위해 희석이 사용됩니다. 특정 실험이나 분석에서는 정확한 농도의 용액이 필요할 수 있습니다.
- 반응속도조절 : 어떤 화학 반응은 고농도에서 빠르게 일어나지만, 너무 높은 농도에서는 원하는 결과를 얻기 어려울 수 있습니다. 따라서 희석을 통해 반응 속도를 적절히 조절할 수 있습니다.
- 분석의 정확성 : 어떤 분석 기술에서는 정확한 결과를 얻기 위해 희석이 필요할 수 있습니다. 특히, 농도가 너무 높으면 측정이나 분석이 어려울 수 있습니다.
- 화학반응특성 : 몇 가지 화합물은 농도가 높을수록 더 복잡한 화학 반응을 일으킬 수 있습니다. 희석은 이러한 반응의 특성을 조절하고 예측할 수 있도록 도와줍니다.


개발자 노트 : 식물을 키우신다면, 눈대중으로 또는 대충 희석하지 말고, 정확하게 희석해서 식물에 적용하세요. 식물 비료/농약, 락스 희석(청소), 세차제품 등을 사용하다 보면 희석하는 경우가 많습니다. 
디자인도 아주 간단하게 만들었고, 애플리케이션 설치 없이 바로 웹브라우저에서 해당링크로 접속하면 희석계산기를 사용할 수 있습니다. 

Tag : #희석계산기 #희석배율 #희석용량 #웹앱

2026년 7월 4일 토요일

[기술조사] 아키텍쳐 & 다수의 프로세스간에 통신 방식

분산 프로세스 아키텍처에서 가장 철학적이고 실무적인 논쟁이 바로 통신방식입니다. 통신방식은 중앙 관리형 통신방식(Orchestration & Gateway), 분사형 통신 방식(Cherography & Message Broker) 정도로 확인하였습니다. 

프로세스를 여러 개로 분리를 시작하면, 가장 먼저 마주하는 거대한 벽이 "통신 복잡성"입니다. 다수의 프로세스가 직접 통신한다면 관리해야 항목(커넥션, URL)이 늘어납니다. 그래서 프로세스간 직접 통신방식은 많이 언급하지 않을려고 합니다. 


1. 중앙 관리형 통신방식(GateWay & Orchestration)
 - 중앙집권과 명령입니다. 각 프로세스는 스스로 판단하지 안혹, 오직 중앙의 지휘자가 내리는 명령에 따라서면 움직입니다.  요청->대기->응답 과정을 거치는 것입니다. 
 - 비지니스 로직과 흐름이 한눈에 보임, 중앙 관리 프로세스가 병목이 될 수 있음 


2. 분산형 통신방식(Choreography & Message Broker)
 - 지방자치와 이벤트입니다. 중앙의 통제관이 없으며, 각 프로세스는 시스템이 발생한 "사건"을 듣고 로직을 수행합니다. 
 - 시스템 확장(프로세스 추가)이 자유로움, 흐름이 사방으로 진행되어 모니터링이 어려움 
 - RabbitMQ, Kafka, Redis Pub/Sub 


중앙 관리형 통신방식이든 분산형 통신방식이든 해당 프로세스가 문제가 발생하면, 전체 시스템이 마비되는 것은 동일합니다. 이런 것을 피하려면 프로세스간에 직접 통신방식으로 해야 해야 하는데, 프로세스가 늘어날 수록 관리가 상당히 어렵습니다. 

중앙 관리형 통신방식(GateWay & Orchestration), 분산형 통신방식(Choreography & Message Broker) 모두 해당 프로세스가 죽으면 마비되는 것은 동일합니다. 장애 발생했을 때 '데이터 유실'과 '인프라 수준에서 이 문제를 어떻게 극복(복구)' 관점에서 분류된 것으로 보입니다. 


1. 데이터 영속성 관점 (메시지 보관 창고 유무)
 - 수동 중앙 관리 프로세스 : 중앙 관리 프로세스가 장애 시, A프로세스가 B 프로세스로 요청을 보내면, 프로세스 연결자체가 실패하면서 에러 발생하고, A 프로세스가 메시지를 저장하지 않았다면 유실됩니다.

 - 메시지 브로커 : 메시지 브로커는 단순한 통로가 아니고, '디스크 보관 기능이 있는 메모리 창고' 개념입니다. 프로세스 2,3 모두 죽어있더라도 메시지 브로커만 살아있다면 메시지를 큐(Queue)에 안전하게 쌓아두고, 프로세스 2,3 실행되면 밀려있던 메시지를 순서대로 처리할 수 있습니다. 


2. 고가용성과 클러스터링의 난이도
 - (직접 구현한) 중앙 관리 프로세스 : 비즈니스 로직, 세션 상태, 흐름 제어 코드등이 포함되어 있고, 변화가 있을 때 개발자가 직접 코드로 다 구현해야 합니다. 

 - 전문 메시지 브로커(RabbitMQ, Kafka 등) : 전세계 천재 개발자들이 만든 전문 인프로 소프트웨어이고, "우리는 절대로 죽으면 안 된다" 목표로 제작된 것입니다. 


3. 시스템의 결함도와 부하 분산
 - 중앙 관리 프로세스 : 프로세스들이 중앙 관리자에 철저히 종속됩니다. 

 - 메시지 브로커 : 예를 들어서, A프로세스는 브로커에 메시지르 초당 10,000개씩 던지고 자기 할 일을 하러 갑니다. 브러커 뒤에는 B 프로세스의 성능이 부족해 초당 1000 만 처리하더라도, 시스테밍 터지지 않고 브로커 큐에 안전하게 저장됩니다.(Buffer, Load Balacing) 


처음부터 메시지 브로커를 도입하면 인프라 관리 비용이 들기 때문에, 시스템 초기에는 단순한 중앙 관리자로 시작하고, "절대 데이터 유실되면 안 된다"거나 "특정 구간에 트래픽이 몰려 서버가 버티지 못한다"는 신호가 올 때 RabbitMQ나 Kafka 같은 브로커 도입을 검토하는 것이 가장 현실적인 개발 방향입니다. 

개발 초기에는 데이터 유실까지 고려하지 않고 메시지 전달만 잘 되도록 중앙 관리자를 만들면서 전문SW(메시지 브로커) 적용을 고민해보는 것도 좋을 것 같습니다. 전문 SW가 오픈소스를 사용한다고 해도, 사용능력도 향상시키거나, 해당인력이 배정하거나 해야할 것 같네요. 





[Code] 모듈러 모놀리딕(Modular Monolithic) + 프로세스 분리 & Python 예제 #2

모듈러 모놀리딕(Modular Monolithic) + 프로세스 분리 & Python 예제 #2

모듈러 모놀리딕으로 개발하다가, 특정모듈을 분리하려고 합니다. 여기서 분리는 프로세스(실행파일)을 독립적으로 분리하려고 합니다. 분리하려는 이유는 여러가지를 가정할 수 있을 것 같습니다. 

초기 개발할 때는 모듈러 모놀리딕으로 진행하다가 MacroService 또는 Citadel 아키텍처로 변환이 되는 시작점이 되는 것으로 보입니다. 개발 초기부터 MSA로 시작할 필요가 없다고 생각하고, 또한 MSA가 최종 목표도 아닙니다. 

아키텍처 전환 시, 발생하는 변화가 있습니다. (쉽게 표현하면, 프로세스가 나누어지면)
통신방식의 변환이 필요한 것입니다. In-Memory -> IPC/Network로 변경해야 하고, 코드가 더 들어갑니다. 
다시 말해서, 노출된 함수를 직접 호출하는 방식이 아닌, IPC 또는 Network로 통신을 해야 합니다. 


main_app            # [프로세스 1]
 - main.py
 - cli.py
 - feature_a.py
 - feature_b.py   # 로직수행하지 않음. 프로세스2로 요청을 보내는 대리인 역할

service_b            # [프로세스 2]
 - service_b.py    # 자체 웹 서버를 탑재한 B 기능 실행 파일



1. [프로세스 1] main.py | cli.py | feature_a.py (변경없음)


2. [프로세스 1] feature_b.py 
기존 비즈니스 로직 코드는 삭제되고, 독립된 B 프로세스 웹 서버로  HTTP POST 요청을 보내는 코드로 대체합니다. 

# main_app/feature_b.py
import requests

# 독립 실행된 B 프로세스의 REST API 주소
B_SERVICE_URL = "http://127.0.0.1:8000/execute"

def run(input_value: str) -> str:
    print(" [네트워크] 독립된 B 프로세스로 REST API 요청 전송 중...")
    
    # REST API에 보낼 JSON 데이터 구성
    payload = {"text": input_value}
    
    try:
        # B 프로세스 서버로 POST 요청 발송 (타임아웃 3초 설정)
        response = requests.post(B_SERVICE_URL, json=payload, timeout=3)
        
        if response.status_code == 200:
            data = response.json()
            return data.get("result", "응답 데이터 누락")
        else:
            return f" B 서비스 오류 (HTTP {response.status_code})"
            
    except requests.exceptions.ConnectionError:
        # B 프로세스가 죽어있어도 메인 시스템은 크래시 나지 않고 결함이 격리됨
        return "B 서비스 프로세스에 연결할 수 없습니다. (서버가 꺼져있음)"


3. [프로세스 2] service_b.py (분리된 독립 B 서비스 코드)
프로세스1과 완전히 별개로 실행되는 가벼운 웹 서버입니다. 기존 B기능의 비지니스 로직이 이관된 것입니다. (사전에 pip install fastapi uvicorn 설치 필요) FastAPI 사용

# service_b/service_b.py
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn

app = FastAPI(title="독립된 B 기능 매크로서비스")

# 요청 데이터 구조 정의 (DTO)
class RequestData(BaseModel):
    text: str

def _pure_business_logic(data: str) -> str:
    """기존 b.py에 있던 핵심 비즈니스 로직"""
    return data[::-1]

@app.post("/execute")
def handle_b_feature(data: RequestData):
    """메인 프로세스로부터 REST API 요청을 받는 엔드포인트"""
    print(f"[B 프로세스 수신] 요청 데이터: '{data.text}'")
    
    # 비즈니스 로직 수행
    processed_text = _pure_business_logic(data.text)
    
    # JSON 형태로 응답 반환
    return {
        "status": "success",
        "result": f"[B 원격 프로세스 완료] 뒤집힌 결과 -> {processed_text}"
    }

if __name__ == "__main__":
    print("B 기능 독립 프로세스 서버를 시작합니다 (Port: 8000)...")
    # 8000번 포트에서 독립된 웹 서버 프로세스로 가동
    uvicorn.run(app, host="127.0.0.1", port=8000)



2개 실행파일을 모두 실행해야 합니다. 2개의 프로세스이므로 터미널에 두개 열어서 각각 실행합니다. 
 - python service_b.py
 - python main.py


추가 고려사항
 - 프로세스간에 통신하는 방식은 여러가지가 있지만, 여기서는 REST를 사용한 것입니다. 다른 방식으로 선정했다면, 그에 맞는 코드로 적용하면 됩니다. 

 - B기능이 자원(CPU, Memory)를 많이 소모하는 경우, B 실행파일만 별도의 고성능 서버에 실행할 수 있습니다. 코드에서 IP, Port만 변경해주면 됩니다. 

 - B기능이 자주 변경되어 배포해야하는 것은 메인 프로세스를 중단하지 않고 B 모듈/서비스만 배포하여 실행할 수 있습니다. (반대의 경우도 동일함)

 - B기능에 문제가 발생하면(메모리 누수로 인한 비정상 종료), 메인 프로세스에 영향이 거의 없습니다. 




Step #1 : 모든 코드가 하나의 큰 프로세스 내부에 있으며, In-Memory 함수 호출로 통신함
Step #2 : 메인 프로세스는 핵심기능(A)를 유지하고, 분리된 독립 B 서비스가 독립적으로 존재. 메인 프로세스 내부의 Feature_b.py는 로직수행이 아닌 REST 클라이언트가 되어 원격으로 독립 B 서비스를 REST API요청을 보냅니다. 


[Code] 모듈러 모놀리딕(Modular Monolithic) & Python 예제 #1

모듈러 모놀리딕과 파이썬 예제 #1

모률러 모놀리딕(Modular Monolithic) 아키텍처는 시스템을 하나의 단일 프로세스(Monolithic)로 배포하되, 내부 코드는 독립적인 모듈(Module)단위로 엄격하게 분리하여 결합도를 낮추는 아키텍처입니다. 각 모듈은 내부 구현을 숨기고(캡슐화), 명확한 인터페이스를 통해서만 소통해야 합니다.

기본예제 Project를 main.py | cli.py | feature_a.py | feature_b.py 로 구성하였고, 파이썬으로 언어입니다.

 - main.py 애플리케이션 진입
 - cli.py 사용자 인터페이스 입/출력 담당 모듈
 - feature_a.py 비지니스 로직 A 모듈
 - feature_b.py 비지니스 로직 B 모듈


1. 비지니스 로직 A 모듈 (feature_a.py)
 외부에는 데이터를 처리하는 핵심 인터페이스(run)만 노출하고, 내부 동작 알고리즘(_secret_process)은 숨김힙니다. 

# feature_a.py
def _secret_process(data: str) -> str:
    """모듈 내부에서만 사용하는 캡슐화된 메서드 (Private)"""
    return f"[A 모듈 가공] -> {data}"

def run(input_value: str) -> str:
    """외부에서 호출하는 명확한 Public API 인터페이스"""
    print("⚙️ A 기능 모듈 작동 중...")
    result = _secret_process(input_value)
    return f"A 기능 완료 결과: {result}"


2. 비지니스 로직 B 모듈 (feature_b.py)
 A 모듈과 완전히 독립되어 있으며, 자신만의 비즈니스 로직을 수행합니다. 

# feature_b.py
def run(input_value: str) -> str:
    """외부에서 호출하는 명확한 Public API 인터페이스"""
    print("⚙️ B 기능 모듈 작동 중...")
    # 간단한 비즈니스 로직 예시 (역순 정렬)
    reversed_data = input_value[::-1]
    return f"B 기능 완료 결과: {reversed_data}"


3. 입출력 담당 모듈 (cli.py)
 비지니스 로직(A, B)이 어떻게 돌아가는지 전혀 알 필요가 없습니다. 오직 사용자에게 입력을 받고 결과를 출력하는 UI역할에만 충실합니다. 

# cli.py
def get_user_choice() -> tuple[str, str]:
    """사용자로부터 메뉴 선택과 입력값을 받는 인터페이스"""
    print("\n==============================")
    print("1: A 기능 실행")
    print("2: B 기능 실행")
    print("q: 프로그램 종료")
    print("==============================")
    
    choice = input("원하는 기능을 선택하세요: ").strip()
    if choice == 'q':
        return choice, ""
        
    user_input = input("기능에 전달할 텍스트를 입력하세요: ")
    return choice, user_input

def display_result(result: str):
    """결과 화면을 출력하는 인터페이스"""
    print("\n📢 [CLI 출력]")
    print(f"결과: {result}")


4. 진입점 및 모듈 조립 (main.py)
 애플리케이션을 초기화하고, 각 모듈의 인터페이스를 연결하는 역할을 합니다. 중요한 점은 A모듈과 B모듈이 서로 참조하지 않고, CLI모듈도 A, B을 알지 못하며, 오직 main.py가 이들을 중재한다는 것입니다. 

# main.py
import cli
import feature_a
import feature_b

def bootstrap():
    """프로그램 초기 실행 및 준비 단계"""
    print("🚀 시스템 초기화 중... 모듈 로드 완료.")
    print("모듈러 모놀리딕 애플리케이션을 시작합니다.")

def main():
    bootstrap()
    
    while True:
        # 1. CLI 모듈을 통해 사용자 입력 수집
        choice, user_data = cli.get_user_choice()
        
        if choice == 'q':
            print("👋 프로그램을 종료합니다.")
            break
            
        # 2. 제어 흐름 분기 및 모듈 간 중재
        result = ""
        if choice == '1':
            # CLI에서 받은 데이터를 A 모듈 인터페이스로 전달
            result = feature_a.run(user_data)
        elif choice == '2':
            # CLI에서 받은 데이터를 B 모듈 인터페이스로 전달
            result = feature_b.run(user_data)
        else:
            result = "❌ 잘못된 선택입니다. 다시 시도하세요."
            
        # 3. 처리된 결과를 다시 CLI 모듈을 통해 출력
        cli.display_result(result)

if __name__ == "__main__":
    main()


모듈러 아키텍처 관점에서의 핵심 포인트
 - 낮은 결함도(Low Coupling) : feature_a.py와 feature_b.py는 서로의 존재를 모릅니다. 나중에 B기능을 삭제하거나, C기능으로 대체해도 A기능에 영향이 없습니다. 

 - 높은 응집도(High Cohesion) : cli.py는 입출력만 담당하고, feature_a는 본인의 데이터 처리에만 집중합니다. UI가 웹(Web)이나 GUI로 바뀌더라도 cli.py만 수정하거나 교체하면 됩니다. 

 - 단일 진입점(Single Entry Point) : main.py가 전체 흐름을 제어하는 컨트롤 타워 역할을 수행하여 모듈 간의 무분별한 직접 참조(Spaghetti Code)를 방지합니다. 




모듈러 모놀리딕 배포관점 및 개발/논리 관점 
 - 배포관점 : 전체 시스템이 하나의 거대한 '애플리케이션'으로 묶여 있으며, 단일 프로세스와 메모리 공간을 공유합니다. 배포관점은 모놀리딕 입니다. 

 - 개발/논리 - 아키텍처 관점 : 시스템 내부가 모듈별로 엄격하게 분리되어 있습니다. 각 모듈은 자신만의 내부 로직과 데이터 액세스 계층을 가지며, 외부에는 명확한 'Public API 인터페이스'만 노출하여 소통합니다. 

[기타] 구글 애드센스 승인 난이도 & 웹앱 수익화

웹 애플리케이션(Web Application, WebApp) 그리고 구글 애드센스 승인 난이도. 

블로그에 웹앱 관련 주제로 기술조사/앱소개로 포스팅을 15개 미만으로 포스팅을 하였습니다. 
애드센스를 신청하였으나, "주의필요 - 가치가 별로 없는 콘텐츠"로 거절이 된 상태입니다. 


생각보다 어렵습니다. 블로그를 통해서 애드센스를 승인받으려고 한 이유가 비교적 쉬울 것 같았습니다.
 
예전에 웹앱 몇개 만들어서 애드센스 신청을 했지만, 모두 거절되었습니다. 웹사이트를 구축해서 일정수준 컨텐츠를 포함하여 구성하는 것이 상당히 어렵습니다. 이러한 이유로, 블로그 개설해서 메인도메인에 애드센스 승인을 기대했는데, 거절되었네요. 

약 3~4년전에 티스토리로 통해서 애드센스 승인이 된적이 있었는데, 비교적 쉽게 승인이 되어 아주 어렵지 않구나라고 느꼈습니다. 생각보다 승인조건이 까다로운 것 같습니다. 

블로그에 포스팅을 좀 더 많이하고, 애드센스 재신청을 해볼려고 합니다. 
일단 구글 서치 콘솔에 주소 등록을 해두었습니다. 아직 포스팅한 글이 구글에 검색이 안되고 있었습니다. 


검색과 LLM 서비스를 통해서 알아본 결과, 쉽지 안다고 합니다. 
"애드센스+고시"의 합성어로 '애고시'로 표현을 합니다. 

한 포스팅 당 글자 수가 최소 1000자 이상은 되어야 구글은 이를 "가치가 있는 글"로 판단하고, 200~300자 내외로 짧은 글이 많으면 승인이 안된다고 합니다. 포스팅은 최소 15개 이상의 글이 있어야 한다고 합니다. 중구난방 주제의 포스팅이 많으면 전문성이 낮다고 판단한다고 합니다. 독창적인 컨텐츠를 우선하고, 인용이 많은 글(짜집기)이 많으면 "가치 없는 콘텐츠"라는 사유로 무조건 탈락합니다. 그리고 구글 검색창에 내 글이 등록(색인 생성)되어 있는지도 확인합니다.  

정리하면, 한 포스팅 당 최소 1000자 이상, 포스팅은 최소 15개 이상, 1~2개의 전문성의 포스팅, 독창적인 콘텐츠, 구글 서치 콘솔에 등록은 필수 입니다. 

구글 애드센스(AdSense) 승인은 시간여유를 가지면서 진행해야 합니다. 애드센스 승인과 비교해볼 때 애드몹(AdMob) 광고 승인이 상당히 쉬운 편입니다. 애드센스 승인 난이도가 있어서, 아마도 크몽 같은 플랫폼에 애드센스 승인 대행, 승인코치해주는 강의 및 서비스가 존재할 것 같습니다. 

애드센스와 애드몹 승인 난이도가 왜 이렇게 다른지 정말 궁금합니다. 왜?
진입장벽? 무문별한 광고? 애드센스는 웹에 광고를 삽입하여 수익화하는 서비스인데, 이용이 쉽고 무분별한 사용 때문에 승인 난이도를 높게 설정했는지 궁금합니다. 


웹앱/애플리케이션/SW 전문성, 포스팅 20개, 1개 포스팅당 1000자 이상, 이 기준을 달성하고 다시 승인요청을 하려고 합니다. 

[웹앱] 초간단 계수기 (Simple Counter)

초간단 계수기 (Simple Counter) 

https://lapp.microlabs.info/cnt


일상 또는 업무할 때, 무언가의 개수를 세어야 했던 경험이 있을 것입니다. 그래서 스마트폰,PC에서 웹 브라우저만 있으면 간편하게 사용할 수 있는 '초간단 계수기' 웹앱을 만들어 보았습니다. 



직관적인 4가지 핵심 구성

1. 계수 숫자 디스플레이
  - 화면 상단에 숫자가 크게 표시됩니다. 멀리서 보거나 움직이면서 스마트폰을 탭할 때도 눈에 잘 들어오도록 숫자를 크게 표시하였습니다. 

2. 가장 많이 쓰는 [+1] 증가 버튼
 - 숫자를 하나씩 올릴 때 사용합니다. 버튼 영역을 넉넉하게 배정하여, 화면을 보지 않고도 카운트할 수 있습니다. 또한 스마트폰에서 진동을 느낄 수 있습니다. 

3. 실수 바로 잡는 [1 빼기] 버튼
 - 간혹 버튼을 실수로 누르거나, 수정이 필요한 경우가 필요하여, [1 빼기] 버튼을 추가하였습니다. 

4. 새롭게 시작하는 [초기화] 버튼 
 - 측정이 끝나고, 새로운 카운트를 시작하고 싶을 때, 클릭 한 번으로 숫자를 즉시 0으로 되돌립니다. 


개발자 노트 : 최대한 간단하게 만들었습니다. 숫자를 카운트하는 본질에만 집중한 것입니다. 별도의 설치가 필요한 애플리케이션이 아닌, 웹 링크(url)만 저장해두면 웹브라우저에서 가볍게 동작합니다. 스마트폰에서 링크를 즐겨찾기 또는 홈 화면에 추가(바로가기) 할 수 있습니다. 


[웹앱] 타이어 제조연월 확인

타이어 제조연월(제조 연도/월) 확인 애플리케이션


타이어 고유의 DOT코드(주차 형식)를 입력하면, 누구나 이해하기 쉬운 "연도와 월" 정보로 즉시 변환해주는 안전 운전 도구 입니다. 최근에 생산된 타이어인지 현장에서 확인하고 싶은 때, 중고차를 구매했을 때, 유용하게 사용할 수 있습니다. 

내 타이어 제조일자(DOT코드) 확인하는 방법!!!
타이어 바깥쪽 옆면(사이드월)을 보시면 괄호로 둘러싸여 있거나 타원형 안에 적힌 4자리 숫자를 확인하시면 됩니다. 

 



[참고] 타이어 교체 주기 
타이어는 고무 재질 특성상 마모가 되지 않았더라도 생산된 지 5~6년이 지나면 고무가 경화(딱딱해짐)되어 갈라짐이나 파손의 위험이 커집니다. 본 웹앱을 통해서 타이어 나이를 확인하세요. 


개발자 노트 : 자바스크립트(JavaScript) 기반의 날짜 계산 애플리케이션입니다. 모바일과 PC에서 동일하게 이용할 수 있습니다.