Tech
-
검색엔진이 좋아하는 블로그는 따로 있다
검색엔진 최적화를 위한 SEO 대응, 그리고 효과적인 글쓰기
2025-07-20 14:26
내 글이 검색엔진 상단에 노출되게 하려면 어떻게 해야할까? 검색엔진 최적화, 즉 SEO 대응을 위한 방법은 크게 두가지로 나눌 수 있다. 시스템적으로 SEO 대응하기 글 쓸 때 “효과적으로” 작성하기 이 포스팅에서는 위 두가지 방법을 통해 검색엔진에 블로그 글을 노출시키고 유입을 늘리는 방법을 설명한다. 🛠 시스템적으로 할 수 있는 것들 Github Pages로 호스팅되는 Jekyll 기반의 페이지를 기준으로 설명한다. 1. sitemap.xml 생성 및 등록 검색엔진이 내 사이트 구조를 파악할 수 있도록 도와주는 것이 sitemap.xml이다. Jekyll에선 jekyll-sitemap 플러그인을 이용하면 자동으로 생성된다. # _config.yml url: "https://blog.cowkite.com" # 블로그 주소 plugins: - jekyll-sitemap 생성된 sitemap.xml을 Google Search Console에 등록해주면 크롤링과 인덱싱이 시작되고, 구글 검색엔진에 내 글이 노출된다. 자세한 내용은 이전 글인 👉 내 블로그 글이 구글 검색결과에 노출되도록하기 내 블로그 글이 구글 검색결과에 노출되도록하기 2. robots.txt 설정 크롤러가 어떤 페이지에 접근 가능한지 알려주는 robots.txt도 중요하다. “어디는 봐도 되고, 어디는 보지 마라”고 알려주는 ‘지침서’같은 것이다. 검색 허용 여부 제어함으로써 일부 페이지를 크롤링하지 못하게 막을 수도 있고, CSS, JS 같은 리소스나 관리용 경로 차단함으로써 불필요한 리소스를 차단할 수도 있다. 사이트맵 위치를 알려줌으로써 검색엔진이 빠르게 구조를 이해하게 도와줄 수도 있다. 블로그의 루트 경로에 직접 robots.txt 파일을 생성한다. 기본적으로는 아래 구조를 따른다. User-agent: * Allow: / Sitemap: https://{블로그주소}/sitemap.xml 만약 특정 경로를 차단하고 싶으면 Disallow를 추가해주면 된다. User-agent: * Disallow: /admin/ Allow: / Sitemap: https://{블로그주소}/sitemap.xml 3. canonical 태그 설정 설정에 따라 같은 글을 여러 URL로 접근할 수도 있을 것이다. 예를들면 아래와 같은 경우가 있다. - https://blog.cowkite.com/page1 - https://blog.cowkite.com/page1?utm_source=naver 이 경우 검색엔진은 중복 콘텐츠로 인식할 수 있기 때문에, canonical 태그로 대표 URL을 명시하는 것이 중요하다. 이렇게 설정해두면 검색 결과에 표시될 우선 URL로 인식되고, SEO 평점 분산을 방지할 수 있다. _layouts/default.html 또는 _includes/head.html 파일을 수정해서 아래 한줄을 추가하면, 사이트 전역의 <head>를 일괄 적용할 수 있다. <link rel="canonical" href="{ page.url | absolute_url }"> 4. 메타 태그 및 OG(Open Graph) 설정 OG 태그란 Open Graph Protocol이 줄임말로, Facebook, Twitter 등 SNS에서 링크 미리보기 정보를 읽어올 수 있게 제목, 설명, 이미지, URL 등을 설정할 수 있다. 나 또한 개인적으로 블로그를 만들면서 가장 신경썼던 것 중에 하난데, 다른 설정들과 달리 공유할 때 즉각적으로 보이는 영역이므로 세심하게 설정하는 것을 추천한다. 또한 Google 검색 미리보기에도 영향을 미치기도하므로, 검색결과와 SNS 공유 썸네일에서 예쁘게 보이려면 OG 태그를 활용하는 것이 좋다. canonical 태그를 추가할 때와 마찬가지로 _includes/head.html또는 _layouts/default.html에 추가해주면 된다. <meta property="og:type" content="article"> <meta property="og:title" content="{{ page.title }}"> <meta property="og:description" content="{{ page.subtitle | default: site.description }}"> <meta property="og:url" content="{{ page.url | absolute_url }}"> <meta property="og:image" content="{{ site.url }}/assets//assets/2504202307/og-default.png"> 여기서 조금 더 신경 쓰면 각 게시물마다의 썸네일을 적용할 수 있다. 또 추가로 공유 썸네일에서 description을 활용하지 않는 SNS를 대응해서, title에 description까지 노출하도록 적용할 수도 있다. 이 부분까지 다루기엔 글이 흐름이 너무 길어질 수 있으니, 추후에 별도의 글로 작성해야겠다. 5. 이미지 최적화 및 lazy-loading 이미지는 SEO에서 LCP(Largest Contentful Paint) 성능에 큰 영향을 준다. 당연한 얘기겠지만 이미지가 크면 LCP, CLS 등 Core Web Vitals 점수가 하락하므로, 용량이 과다할 경우 감점 요인이 된다. 물리적으로 과도하지 않은 이미지 사이즈 및 webp 포맷의 이미지를 사용하는 것이 것이 가장 우선시 되어야하지만, 시스템적으로도 보완할 수 있는 방법이 있다. webp 확장자의 파일이 있을 경우 우선 사용하고, 없을 땐 jpg/png 사용하도록 일관화하기 사용자가 스크롤할 때 불러오도록 lazy-loading 속성 사용 alt 속성을 적용해서 이미지 설명으로 SEO + 접근성 향상 시키기 이 때 liquid를 활용해서 커스텀 스니펫을 사용하면, 이미지를 삽입할 때마다 신경쓰지 않아도 된다. _includes/lazy_image.html를 생성하고 아래 코드를 삽입한다. <figure class="{{ include.figure_class | default: 'lazy-figure' }}"> {% if include.webp %} <picture> <source srcset="{{ include.webp }}" type="image/webp"> <img src="{{ include.src }}" alt="{{ include.alt | default: '' }}" loading="lazy" decoding="async" width="{{ include.width | default: '100%' }}" class="{{ include.class | default: 'lazy-img' }}"> </picture> {% else %} <img src="{{ include.src }}" alt="{{ include.alt | default: '' }}" loading="lazy" decoding="async" width="{{ include.width | default: '100%' }}" class="{{ include.class | default: 'lazy-img' }}"> {% endif %} {% if include.caption %} <figcaption>{{ include.caption }}</figcaption> {% endif %} </figure> 그러면 앞으로 {% include img.html src="이미지주소"...를 사용할 때마다 자동으로 이 코드 스니펫을 참조하게 된다. alt, width, height 태그를 자동 지정해주고, loading="lazy", decoding="async" 같은 속성을 주입하도록 설정했다. 이 때 .webp 파일을 사용하면 물리적인 이미지 용량 감소에도 도움이 되므로, 이미지 경로내에 .webp 확장자가 있는 경우에 그 파일을 사용할 수 있도록 적용했다. 사용하기 일반적으로 마크다운에서 이미지를 사용할때는  방법을 사용했을 것이다. 이제 커스텀 스니펫을 사용하기위해, 글을 작성할 때 아래처럼 작성하면 된다. {% include img.html src="이미지주소" text="설명" width="800" height="600" %} 6. CSS/JS 최적화 검색엔진은 페이지의 로딩 속도 역시 평가 지표로 활용한다. 특히 Core Web Vitals 중 LCP(Largest Contentful Paint), FID(First Input Delay)와 같은 성능 지표는 HTML 문서와 더불어 JS, CSS의 영향도 크게 받는다. CSS와 JS가 불필요하게 크거나, 페이지 렌더링을 블로킹하는 경우 페이지 노출 순위에 불리하게 작용할 수 있다. 이를 방지하기 위해 다음과 같은 조치를 적용할 수 있다. 비동기 로딩: <script> 태그에 defer 또는 async 속성을 사용하여 렌더링 블로킹을 최소화한다. defer: HTML 파싱이 끝난 뒤 실행되며, 순서를 보장한다. async: 다운로드가 완료되면 바로 실행되며, 순서는 보장되지 않는다. 불필요한 CSS 제거 (purge): 사용되지 않는 스타일을 빌드 시점에 제거하여 최종 번들 용량을 줄인다. Jekyll에서는 별도 빌드 스크립트를 통해 purgeCSS와 같은 도구를 연동하거나, TailwindCSS를 사용하는 경우 content 경로 설정으로 처리 가능하다. 경량 웹폰트 사용: 외부 폰트를 불러올 경우 기본 시스템 폰트 혹은 Pretendard, Inter 등 경량화된 웹폰트를 사용하는 것이 바람직하다. 또한 font-display: swap 속성을 지정하여 텍스트가 즉시 표시되도록 설정하는 것이 좋다. 성능 최적화는 단지 빠른 로딩을 넘어서 사용자 경험과 SEO 평가 모두에 영향을 주기 때문에, CSS/JS 자산의 관리 전략은 SEO의 핵심 기초라 할 수 있다. 7. HTTPS 적용 HTTPS는 검색엔진 최적화에 있어 필수 요소이다. Google은 HTTPS를 공식적으로 순위 결정 요소로 활용한다고 밝혔으며, 사용자의 브라우저에서도 보안 경고를 유발할 수 있기 때문에 반드시 적용되어야 한다. GitHub Pages는 자체적으로 HTTPS를 기본 제공하지만, 맞춤 도메인을 사용하는 경우 다음과 같은 사항들을 확인해야 한다. DNS 설정 확인: 커스텀 도메인을 사용하는 경우, GitHub Pages에 연결된 CNAME 설정 및 A 레코드가 올바르게 지정되어 있어야 한다. HTTPS 강제 리디렉션 설정: https:// 접속을 강제하도록 GitHub Pages 설정에서 “Enforce HTTPS” 옵션을 활성화한다. Search Console 등록 시 HTTP/HTTPS 구분: Google Search Console에서는 HTTP와 HTTPS를 별도의 속성으로 인식하기 때문에, HTTPS 도메인 기준으로 사이트를 등록하고 sitemap.xml도 해당 주소로 제출해야 한다. SSL 인증서는 GitHub에서 자동으로 발급되지만, 적용 지연이나 DNS 설정 누락 등으로 HTTPS가 정상 작동하지 않을 수 있으므로 최종적으로 https://{도메인} 주소로 접속 시 인증서가 문제 없이 작동하는지 확인하는 절차가 필요하다. HTTPS가 적용되지 않은 사이트는 보안뿐만 아니라 검색 신뢰도 측면에서도 불이익을 받을 수 있으므로, 사이트 초기 구축 시 반드시 우선적으로 확인해야 할 항목이다. ✍️ 콘텐츠적으로 할 수 있는 것들 1. 글 하나에 핵심 키워드 하나 검색엔진은 하나의 페이지가 어떤 주제를 다루는지를 판단할 때, 해당 콘텐츠의 중심 키워드를 기준으로 문맥을 분석한다. 따라서 하나의 글 안에 여러 키워드가 혼재되어 있다면 주제성이 약해지고, 검색 결과에서의 적합도 또한 떨어질 수 있다. 가장 이상적인 구조는 글 하나당 하나의 핵심 키워드를 중심으로 전체 내용을 구성하는 것이다. 핵심 키워드를 명확히 정의하고, 그 키워드가 설명하는 대상, 배경, 실행 방법, 예시 등으로 글의 흐름을 잡아나가야 검색엔진도 정확하게 해당 페이지를 평가할 수 있다. 특히 검색 트렌드가 짧은 문장형 또는 질문형 검색어로 이동하고 있기 때문에, 키워드는 단순 명사형보다는 “jekyll SEO 설정 방법”, “깃허브 페이지 SEO 적용하기” 와 같이 문장 형태로 구성하는 것도 효과적이다. 2. 제목과 소제목에 키워드 삽입 검색엔진은 <title>, <h1>, <h2> 태그와 같은 구조화된 제목 영역을 우선적으로 인식하여 콘텐츠의 주제를 파악한다. 이때 핵심 키워드를 제목에 포함시키는 것은 해당 키워드와의 연관성을 직접적으로 전달하는 가장 효과적인 방법이다. 예를 들어, Jekyll 블로그 SEO 설정 방법이라는 제목은 “jekyll”, “seo”, “설정”, “블로그”라는 주요 키워드를 자연스럽게 포함하고 있으며, 본문 내 소제목들도 "## sitemap.xml 생성하기", "## canonical 태그 설정"과 같이 키워드 중심의 문장으로 구성하면 검색엔진이 각 단락의 맥락을 더 쉽게 이해하게 된다. 또한, 제목이 검색결과에서 클릭률(CTR)에 직접적인 영향을 주기 때문에, 단순 키워드 나열보다는 사용자 관점에서 유익함이 드러나도록 문장을 구성하는 것이 중요하다. 3. 자연스럽게 키워드 반복 검색엔진은 본문 내 키워드의 밀도와 위치, 반복 빈도를 통해 해당 페이지의 주제와 전문성을 판단한다. 하지만 과도하거나 인위적인 키워드 반복은 오히려 패널티 요소로 작용할 수 있기 때문에, 문맥 속에 자연스럽게 녹아들도록 배치하는 것이 바람직하다. 보통 하나의 글 내에서 핵심 키워드를 3~5회 정도 자연스럽게 사용하되, 각 문단의 앞부분 또는 제목과 인접한 위치에서 강조하는 것이 효과적이다. 예를 들어, "jekyll seo"라는 키워드를 사용할 경우 "jekyll 블로그를 운영하는 입장에서 seo는 필수적인 고려사항이다"와 같이 문장 흐름에 맞게 삽입하면 SEO와 독자 경험 두 측면 모두에 긍정적인 결과를 낼 수 있다. 4. 내부/외부 링크 적극 활용 링크는 콘텐츠의 신뢰성과 구조를 높이는 데 있어 중요한 역할을 한다. 내부 링크는 동일 사이트 내의 관련 콘텐츠를 연결함으로써 사용자 체류 시간을 증가시키고, 사이트 전반의 인덱싱 효율을 개선하는 데 기여한다. 반면, 외부 링크는 Google, MDN, Wikipedia 등 신뢰도 높은 출처를 인용하여 정보의 신빙성을 높이는 데 효과적이다. Jekyll 기반 블로그에서는 다음과 같이 내부 링크를 활용할 수 있다: <a href="/blog/2504212055/">다음 글 보기</a> 이처럼 HTML 앵커 태그를 사용하여 다른 포스트로 자연스럽게 흐름을 연결하면, 사용자는 맥락 상 연관된 정보를 연속적으로 탐색할 수 있고, 검색엔진은 해당 페이지의 정보 연결성을 긍정적으로 평가한다. 5. alt 텍스트와 캡션 작성 이미지 역시 SEO 대상이다. 특히 이미지에 포함된 내용을 검색엔진이 직접 해석할 수 없기 때문에, 대체 텍스트인 alt 속성과 선택적 figcaption 태그를 활용하여 이미지의 의미를 텍스트로 보완해야 한다. 예를 들어 다음과 같이 작성하면: <img src="/assets/example.png" alt="jekyll seo 설정을 위한 sitemap 예시"> <figcaption>SEO를 위해 sitemap.xml을 설정하는 예시 화면</figcaption> 검색엔진은 alt 속성을 통해 이미지의 의미를 인식하고, 시각장애인이나 이미지 로딩이 불가한 상황에서도 접근성을 유지할 수 있다. 캡션은 콘텐츠 내 시각 자료가 단순한 장식이 아닌 정보 요소임을 강조하며, 이미지와 텍스트 간의 연결성을 높이는 역할을 한다. 6. 콘텐츠 최신 상태 유지 검색엔진은 페이지가 언제 작성되었고, 얼마나 자주 업데이트되는지를 통해 정보의 신선도(Freshness)를 평가한다. 따라서 오래된 콘텐츠라 하더라도, 주기적인 업데이트와 last_modified_at 등의 메타데이터를 활용하면 SEO 관점에서 긍정적인 신호로 작용할 수 있다. Jekyll에서는 아래와 같이 작성일과 수정일을 명시할 수 있다: # 포스트 Front Matter 예시 date: 2023-05-10 last_modified_at: 2025-04-20 수정일을 명시하면 검색엔진이 인덱싱 시 해당 글이 최근에 갱신되었음을 인식하며, 사용자에게도 정보의 최신성을 간접적으로 전달할 수 있다. 단, 날짜만 변경하는 식의 형식적 갱신은 오히려 신뢰도를 저하시킬 수 있으므로, 실제로 의미 있는 변경 사항이 동반되어야 한다는 점을 유의해야 한다. 🔖 추가 점검 사항 검색엔진 최적화는 단순히 초기 설정을 잘하는 것으로 끝나지 않는다. 사이트 운영 중 발생할 수 있는 인덱싱 오류, 구조적 문제, 콘텐츠 노출 누락 등에 대응하기 위해서는 정기적인 점검과 사후관리가 필수적이다. Search Console에서 인덱싱 상태 수시 확인 Google Search Console은 내 사이트가 검색엔진에 어떻게 인식되고 있는지 확인할 수 있는 대표적인 도구다. 페이지별 색인 여부, 오류 메시지, 모바일 사용성, 클릭 수 등의 데이터를 통해 현재 상태를 진단하고 필요한 조치를 취할 수 있다. 특히 다음과 같은 상태 메시지를 수시로 체크해야 한다: Discovered - currently not indexed: 페이지는 발견되었지만 아직 인덱싱되지 않은 상태 Crawled - currently not indexed: 크롤링은 되었으나 인덱스에서 제외된 상태 Duplicate without user-selected canonical: 중복 콘텐츠로 판단되었으나 대표 URL이 지정되지 않은 상태 각 메시지는 원인을 분석하고 해당 페이지의 내부 링크를 강화하거나 sitemap을 재등록하는 등의 대응이 필요하다. canonical 태그 명시로 중복 콘텐츠 방지 특정 글이 쿼리 파라미터에 따라 여러 URL로 접근 가능한 경우, 검색엔진은 이를 서로 다른 콘텐츠로 판단하거나 중복 콘텐츠로 인식할 수 있다. 이때 canonical 태그를 통해 대표 URL을 명시함으로써 SEO 점수의 분산을 방지하고, 검색 결과에 노출될 URL을 통제할 수 있다. 이 조치는 특히 UTM 파라미터, 공유용 링크 등 다양한 유입경로가 존재하는 블로그 환경에서 더욱 중요하다. OG 이미지 및 게시물별 썸네일 삽입 OG(Open Graph) 태그는 SNS 공유 시 콘텐츠의 미리보기 정보를 제공하며, 간접적으로 클릭률(CTR)과 검색 노출에도 영향을 미친다. 본문 내 OG 이미지 또는 대표 썸네일을 삽입하면 사용자에게 콘텐츠의 신뢰감을 주고, 다양한 플랫폼에서 일관된 콘텐츠 미리보기를 제공할 수 있다. 가능하다면 각 포스트마다 개별 OG 이미지를 설정하고, 기본 이미지가 존재하지 않는 경우에는 og-default.png 등의 기본값을 지정해두는 것이 좋다. 반응형 UI 및 모바일 퍼스트 디자인 적용 검색 트래픽의 상당 부분은 모바일에서 유입되며, Google은 모바일 페이지의 품질을 기준으로 인덱싱하는 Mobile-first Indexing을 적용하고 있다. 따라서 모든 페이지는 데스크탑뿐 아니라 다양한 해상도에서도 적절히 렌더링되어야 하며, 폰트 크기, 버튼 크기, 이미지 너비 등에서도 모바일 사용성을 충분히 고려해야 한다. Jekyll 기반 블로그의 경우, CSS media query, flex/grid 레이아웃 구조, 뷰포트 메타 태그 등 기본적인 반응형 설계를 적용하는 것이 좋다. Lighthouse로 주기적인 성능 체크 Google Chrome의 개발자 도구에서 제공하는 Lighthouse는 SEO, 퍼포먼스, 접근성, PWA 등 다양한 영역에 대한 자동 진단 리포트를 제공하는 도구다. 페이지 로딩 시간, 렌더링 차단 리소스, 이미지 최적화 여부 등을 점검할 수 있으며, 각 항목은 점수화되어 표시되므로 변경 전후를 비교하거나 병목 지점을 찾는 데 유용하다. 주요 항목으로는 다음을 점검하는 것이 좋다: Largest Contentful Paint (LCP) Total Blocking Time (TBT) Cumulative Layout Shift (CLS) SEO 항목 내 title/description 유무, 링크 상태 등 정기적인 Lighthouse 테스트를 통해 SEO 대응뿐만 아니라 전체적인 웹페이지 품질을 한층 더 안정적으로 유지할 수 있다. 📚 마치며 SEO는 한 번 설정하면 끝나는 게 아니라, 계속 손보고 점검해야 하는 일이다. 검색엔진도 계속 바뀌고, 사람들이 뭘 찾는지도 계속 달라지니까. 처음엔 메타 태그를 달고, sitemap을 만들고, 키워드를 넣는 식으로 기술적인 부분부터 시작하지만 쓰다 보면 결국 중요한 건 그 안에 담긴 내용이 사람한테 얼마나 도움이 되느냐라는 걸 느끼게 된다. 검색엔진에 잘 보이는 것도 중요하지만, 그보다 더 오래 남는 건 읽는 사람이 ‘좋은 글이었다’고 느끼는 순간일지도 모르겠다. 그래서 요즘은 예전처럼 “어떻게 하면 상위에 노출될까?”보다는 “이 내용이 필요한 사람한테 닿을 수 있을까?”를 더 자주 생각하게 된다. 이 글도 누군가에게 그런 작은 도움 하나쯤은 되었으면 좋겠다.
-
내 블로그 글이 구글 검색결과에 노출되도록하기
페이지의 사이트색인을 생성하고 Google Search Console에 등록하기
2025-04-20 22:48
📦 구글은 나를 모른다 블로그를 시작할 때 흔히 착각하는 것이 있다. 구글 검색에 내 글이 알아서 잘 노출될 것이라는 것. 혹은 Google Analytics로 유입된 것을 확인하거나, 댓글이 달리고나면 내 글이 잘 검색되고 있을거라는 기대를 한다. 실제로 글을 작성하고 며칠이 지나면 구글 검색결과에 노출이 되긴한다. (혹은 페이지 구조에 따라 아예 안 될 수도 있다.) 글을 올리고 ‘언제쯤부터 내 글이 검색될 수 있을지’ 기다리는 대신 구글 검색 결과에 더 효과적으로 노출하는 방법을 소개하려고한다. 바로 Google Search Console에 사이트를 등록하고, 색인을 제출하는 것. 🤔 Google Search Console? Google Search Console에 사이트색인을 등록하는 이유는 단순히 검색결과에 더 잘 나타나기 위해서다. 물론 굳이 콘솔에 사이트색인을 등록하지 않더라도 언젠가는 구글이 내 페이지를 크롤링해서 검색결과에 노출하긴 하지만, 구글이 수동으로 사이트를 찾는 데엔 시간이 걸리기도하고, 특히 커스텀 블로그나 GitHub Pages 기반의 블로그는 내부 링크 구조가 약하면 크롤링이 잘 되지 않는 경우도 많기 때문에 직접 등록해주는 것이 좋다. 또한 Google Search Console의 부가적인 기능으로 페이지 상태를 실시간으로 확인할 수 있고, 어떤 페이지가 검색 유입이 많은지, 어떤 쿼리로 유입되는지 분석이 가능하므로 SEO 개선 힌트도 얻을 수 있다. 🏃 적용 방법 Github Pages로 호스팅되는 Jekyll 기반의 페이지를 기준으로 설명한다. 1. 사이트맵 파일 생성 Jekyll에서는 jekyll-sitemap 플러그인을 사용하면 사이트맵 파일인 sitemap.xml이 자동 생성된다. _config.yml에 url을 명시해주고, 플러그인을 추가해주자. url: "https://blog.cowkite.com" # 블로그 주소 plugins: - jekyll-sitemap 이제 배포하고 나면 ‘{블로그주소}/sitemap.xml’에서 전체 포스트 목록을 구글봇이 볼 수 있게 된다. 내 설정 파일을 예시로 들면, ‘https://blog.cowkite.com/sitemap.xml’ 주소에 생성되는 것이다. 사이트색인은 새 글을 발행하거나 _config.yml 파일이 수정될 때마다 자동으로 크롤링된다. 2. Google Search Console 등록 Google Search Console에 접속한 뒤, 속성(Property)을 추가해준다. 그러면 구글이 자동으로 소유권을 확인하고 등록한다. 도메인 방식은 DNS 설정이 필요하므로, URL 접두어 방식으로 등록하는 것을 추천한다. 만약 소유권 확인이 안 된다면 안내에 따라 수동으로 소유권을 등록하는 방법도 있다. includes/head.html에 소유권을 확인하기 위한 코드를 삽입하면 된다. <!-- Google Search Console --> <meta name="google-site-verification" content="xxxxx" /> 3. sitemap 제출하기 직접 제출하지 않아도 시간이 지나면 수동으로 크롤링하는 듯 하지만, 좌측 메뉴에서 Sitemaps 메뉴에 진입하여 직접 제출할 수 있다. 수동으로 sitemap.xml 파일을 생성해서 지정할 것이 아니라면, 최초 1회 제출을 통해 구글봇이 주기적으로 갱신되는 것을 크롤링한다. 제출하면 색인 대기열에 들어가고 몇 시간~며칠 사이에 검색 노출이 시작된다. sitemap.xml 파일 주소를 입력 후 '제출' 버튼을 클릭한다. 4. 페이지 색인 생성 요청하기 좌측 메뉴에서 ‘URL 검사’를 클릭하여 메뉴에 진입해서, 발행된 글의 주소를 입력한다. 안내 메시지가 ‘URL이 Google에 등록되어 있지 않음‘이든, ‘URL이 Google에 등록되어 있음‘이든 ‘색인 생성 요청’ 버튼을 클릭하면 된다. 이 또한 직접 제출하지 않아도 시간이 지나면 수동으로 크롤링 되지만, 반영하는데 시간이 소요되므로 글을 발행하거나 수정할 때마다 수동으로 요청하면 좋다. '색인 생성 요청' 버튼 클릭하기 🧘 마치며 Google Search Console은 구글 검색엔진에 효과적으로 대응하는 방법이 맞다. 그러나 브라우저가 구글만 있는 것은 아니기 때문에, 궁극적으로는 SEO까지 잘 대응해야한다. 사이트 색인을 등록하는 것이 내 블로그를 ‘인지’하게 하는거라면, SEO 대응은 내 글을 ‘노출’하게 하는 것이다. 다음 편인 검색엔진 최적화 (SEO 대응) 글까지 참고해주면 좋다. 👉 검색엔진이 좋아하는 블로그는 따로 있다 검색엔진이 좋아하는 블로그는 따로 있다 보너스) 🚨 트러블 슈팅 1. 색인이 안 되는 흔한 원인들 색인 생성 및 제출, 검토 과정에서 아래 오류가 발생할 수 있다. Search Console에서 “URL 없음” 오류 블로그 주소와 다른 속성을 등록한 경우 발생한다. 나의 경우에는 https로 시작하는 주소를 입력해야하는데, http로 시작하는 속성을 생성해서 지속적으로 해당 오류가 발생했다. 뒤늦게 발견하고 https로 시작하는 속성을 새로 등록하고 해결되었다. sitemap.xml이 생성되지 않음 jekyll-sitemap 플러그인을 누락했거나, _config.yml 파일에 url 속성이 설정되어있지 않을 경우 발생한다. _config.yml 파일을 다시 확인해준다. 새 글이 sitemap에 없는 경우 일단 단순히 내 브라우저에 파일이 캐싱되어있는지 먼저 확인해봐야한다. 브라우저의 시크릿모드로 확인하거나, 터미널에 curl {블로그주소}/sitemap.xml 명령어를 통해 확인할 수 있다. % curl https://blog.cowkite.com/sitemap.xml <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://blog.cowkite.com/blog/2003062358/</loc> </url> ... 여전히 새 글이 sitemap에 노출되지 않는다면, GitHub Pages가 아직 빌드가 안 된 경우이므로 다시 빌드를 하면 된다. Action을 제어하는 경우가 아니라면, empty commit을 하거나 _config.yml 설정을 바꿔주는 것으로 충분하다. % git commit --allow-empty -m "Trigger rebuild" % git push 2. Search Console에서 페이지 색인 과정 중 발생하는 오류들 사용자가 선택한 표준이 없는 중복 페이지 같은 내용을 다른 URL로 향유할 경우에 발생한다. 예를 들면 아래 같은 경우에서 구글이 어떤 URL을 대표로 삼을지 몰라 발생하는 오류다. - https://blog.cowkite.com/page1 - https://blog.cowkite.com/page1?utm_source=naver 나의 경우에는 위 경우가 아님에도 불구하고, 각기 다른 다양한 게시물들에서 중복 페이지 오류가 발생하긴 했다. 어쨌든 해결법은 _layouts/default.html 혹은 _includes/head.html에 canonical 태그를 추가함으로써 이 URL이 진짜 주소임을 알릴 수 있다. <link rel="canonical" href="https://blog.cowkite.com/blog/2504202248/"> 리디렉션이 포함된 페이지 말 그대로 페이지가 리디렉션돼서 색인할 수 없다는 뜻인데, 나의 경우엔 내가 페이지 속성을 실수로 https가 아닌 http로 등록한데서 발생한 휴먼 에러긴하다. 이처럼 실제로 리다이렉션을 한 경우가 아니라면 보통은 http → https, www → non-www, 커스텀 도메인 변경 등이 원인이 된다. 커스텀 도메인을 사용하는 경우, 최종 주소 (리디렉션 된 주소) 를 등록해야 한다. 예를 들면 ‘https://cowkite.github.io’가 아닌 ‘https://blog.cowkite.com’로 등록이 되어야한다. 찾을 수 없음 (404) 사이트맵에는 있지만, 해당 글을 찾을 수 없는 경우에 발생한다. 대표적으로 기존에 게시했던 글을 삭제하는 경우다. 혹은 퍼머링크가 바뀌었을 가능성도 있다. Jekyll에서 퍼머링크는 기본적으로 날짜 기반이므로, YYYY/MM/DD/slug 구조를 확인해야한다. 발견됨 - 현재 색인이 생성되지 않음 콘텐츠 양이 너무 적거나, 내부/외부 링크가 거의 없거나, robots.txt가 막고 있거나, 구글이 “중복 컨텐츠일 수도”라고 생각한 경우 해당 오류를 발생시킨다. 위에서 설명한대로 글 작성 후에 Search Console에서 직접 색인 생성을 요청하면 된다. 크롤링됨 - 현재 색인이 생성되지 않음 위 오류와 거의 흡사한데, 너무 비슷한 내용만 반복된 페이지이거나, sitemap에 너무 늦게 반영된 경우 발생할 수 있다. 혹은 블로그 코드에 <meta name="robots" content="noindex">가 설정되어있을 수도 있다. 이럴 경우 _layouts 또는 _includes/head.html에서 meta robots 태그를 확인해보고, 만약 없다면 추가해준다. <meta name="robots" content="index, follow"> 그리고 sitemap.xml이 최신인지 확인하여 위에 설명한대로 empty commit을 통해 강제로 sitemap 갱신할 수 있다. 만약 모든 것이 정상인데 발생하는 오류라면, 마찬가지로 해당 글들을 수동으로 페이지 색인 생성하도록 요청한다.
-
니들은.. 수동배포 같은거 하지마라.. 😎
Android앱에 Fastlane과 Firebase App Distribution을 통한 CD 자동배포 적용하기
2021-07-17 00:06
재직중인 회사의 기술블로그에 올리브영 안드로이드 테스트앱 자동배포하기라는 제목으로 글을 기재했는데, 사족을 지우고 조금 더 깔끔하게 개인 블로그에도 남겨보고 싶어 글을 일부 수정해서 가져왔다. (회사 블로그에 글을 작성할 땐 왠지 모르게 괜한 사족을 붙여 둥글둥글한 느낌으로 작성하게 된다..) 참고로 부제는 니들은.. 수동배포 같은거 하지마라.. 😎 그럼,, Start~! 📢 테스트앱 올라갔어요! 우리 회사에서 서비스하고 있는 ‘올리브영’ 앱은 PlayStore Beta로 테스트앱 관리를 하고 있었다. feature 단위 건의 개발이 완료되면 버전별로 테스트 앱을 배포하고 QC를 진행하는 방식인데, 가장 기본적인 방법일 수도 있지만 이게 여간 짜증나고 불편한 것이 아니다. 1. 테스트앱을 제공하는데 너무 많은 시간이 걸린다. 개발이 완료되면 앱을 빌드한뒤 플레이스토어에 업로드해야한다. 우선 2차 인증을 거친 구글 로그인을 해야하고 적당한 릴리즈노트와 함께 앱을 업로드하면, 앱파일을 첨부하는데 일정 시간을 소요한뒤에 앱을 제출할 수 있다. 업로드가 완료되면 바로 제공되는 것도 아니고, 약 30분의 ‘출시준비중’ 단계를 대기한 후에 테스터들에게 앱이 제공된다. 2. 앱이 제공되고나면 QA엔지니어에게 직접 알려야한다. 앱이 제공되고나면 QA엔지니어에겐 누가 알려줄까? That’s Me..^^.. 🧚♀️ 앱 업로드 후 30분동안 ‘출시준비중’ 상태를 뺑글뺑글 도는 것을 지켜보다가, 출시가 완료되면 QA엔지니어에게 호다닥 달려가서 알려준다. (호외요 호외~) 3. 테스터가 추가될때마다 일일이 추가해야하고, 오랫동안 기다려야한다. 신규 테스터를 추가하기 위해서는, (1) 플레이스토어 계정을 전달받아야하고 (2) 전달받은 계정에 수기로 권한을 등록해야한다. (3) 권한을 획득한 테스터는 플레이스토어에서 ‘베타 참여하기’ 버튼을 누른 뒤 (4) 약 4시간을 기다려야 테스트앱을 다운받을 수 있다. 이게 진짜 별거 아닌 것 같은데, 많이 들어올 땐 하루에도 몇번씩 이 문의가 들어온다. (바빠 죽겠는데 권한 추가하고 가이드 메일까지 보내줘야함. 환장할 노릇..) 4. 이전 버전을 테스트할 수 없다. 한번에 1개의 버전만 테스트가 가능하다. 그나마 TestFlight는 ‘이전 빌드 보기’통해 과거 버전의 앱도 설치할 수 있어서, iOS는 이 방법으로 기능별 버전을 분리해서 QC를 진행하고 있는데, 플레이스토어는 가장 최신 버전의 앱만 제공할 수 있어 동시다발적으로 여러개의 QC를 태울땐 난감해진다. 또 프로덕트에 앱이 출시되고나면, 자연스레 Beta에 등록된 앱이 이전 버전이 되면서 무효화 되기 때문에 Beta앱을 또 다시 빌드해서 등록해주어야한다. 안 그래도 챙겨야할게 한두개가 아니라 바쁜 배포날.. 또 하나의 배포 태스크인셈.. 매번 할때마다 너무 비효율적이라고 생각했다. 🤷 Bitrise가 아니라 fastlane을 선택한 이유 회사 블로그엔 글을 쓸때 이 부분을 엄청 구구절절하게 썼는데, 사실 원래는 무조건 Bitrise를 쓰고싶었다.. 허락도 받고 예산확보까지 받아놨는데… 내부망에서만 접근가능하도록 구성된 Git 환경 때문에 처참하게 적용 실패했다. 😔 너무 익숙해져서 내부망에서만 접근 가능하다는걸 깜박했던 것 같다. 🧚♀️: 마젤토브 힘내봐.. 마젤토브 빌드해봐.. 🤖: (뭐래..) 근래 블로그에서 했던 드립중에 가장 맘에 드는 드립 Android도 iOS만큼 fastlane과 궁합이 괜찮을까? 굳이 이야기해보자면, 일단 다 떠나서 Firebase Distribution으로 테스트앱을 제공하자는 목표가 1차적으로 설정되어 있었고, 그 과정에서 Firebase의 공식 document에서도 fastlane 연동방법을 공식적으로 안내해주는것을 보고 괜찮겠군 싶었다. 어차피 iOS 앱에도 fastlane 적용중이었고.. 나중엔 젠킨스까지 연동해서 CI까지 쉽게 적용할 수 있을 것 같아서 마음에 들었다. 🎬 본격적인 적용기! 🏃 이제 적용해보자! 자 이제 플랫폼 검토가 끝났으니 적용을 해야한다. Firebase 공식문서인 Distribute Android apps to testers using fastlane을 참고해서 쉽게 적용할 수 있었다. 1. Google 자격증명 획득 서비스 연동을 위해 API키를 생성하고 Google PlayStore에 등록해줘야한다. 스크린샷을 첨부했으나, 회사 보안 지침상 문제가 될만한 내용들은 모두 가렸고 그나마 노출되는 정보는 스크린샷을 촬영하기위한 테스팅 정보들이다. (열심히 가리느라 힘들었다 💦) 1. Google Play Console > 설정 > API 액세스 > 새 서비스 계정 만들기 > Google Cloud Platform 링크 클릭 2. 'Google Play Android Developer' 프로젝트 선택 > 서비스 계정 만들기 클릭 3. 서비스 계정 정보 입력. 이 때 역할을 필수로 '서비스 계정 사용자'로 설정해주어야 한다. 4. 서비스 계정이 생성되었으면, '키 관리' 메뉴로 이동 5. 키 추가 > 새 키 만들기 > JSON > 만들기 클릭 후 생성된 키를 기기에 저장 6. 다시 1번의 Google Play Console로 돌아오면 신규 서비스계정이 생성된것을 확인할 수 있다. 여기서 '액세스 권한 부여' 버튼을 클릭 7. '앱 권한' 메뉴에서 타겟 앱을 설정하고, '계정 권한' 메뉴에서 '관리자 권한'을 부여한 후 '사용자 초대' 버튼을 클릭하여 완료 2. Firebase App Distribution 활성화 Firebase console에서 App Distribution 메뉴에 진입하여 기능을 활성화해준다. 3. fastlane 설치 macOS 기준으로 fastlane 설치하는 방법을 설명한다. 터미널에서 하기 명령어를 실행하여 fastlane을 설치한다. $ brew install fastlane 프로젝트 경로로 이동하여, fastlane을 초기화해준다. 해당 과정에서 패키지명과 위 사전작업 단계에서 설정한 JSON 파일 경로를 입력하게 된다. ~/workspace$ fastlane init (옵션) fastlane이 정상 설치 되었는지 확인하려면 아래 명령어를 입력해준다. ~/workspace$ bundle exec fastlane test 4. fastlane과 Firebase App Distribution 연결 fastlane을 Firebase App Distribution과 연결해준다. ~/workspace$ fastlane add_plugin firebase_app_distribution 하기 명령어를 입력하여 인증을 위한 Google Auth URL을 받아온다. ~/workspace$ bundle exec fastlane run firebase_app_distribution_login > Open the following address in your browser and sign in with your Google account: > https://accounts.google.com/o/oauth2/auth.... 터미널에서 출력된 페이지 URL을 브라우저로 실행하여 인증한 뒤, 반환되는 인증코드를 콘솔에 입력하면 Refresh Token이 발급된다. 해당 토큰을 환경변수로 설정해준다. $ export FIREBASE_TOKEN={token} 5. 배포 lane 설정 마지막으로 배포를 위한 lane 명령어를 생성한다. workspace의 ./fastlane/Fastfile 파일을 열어 하기 블록을 추가해준다. ... desc "Lane for distribution" lane :distribute do gradle( task: "assembleDevelop", build_type: "Release" ) firebase_app_distribution( app: "(Firbase App ID)", groups_file: "fastlane/testers-groups.txt", release_notes_file: "fastlane/release-notes.txt", debug: true ) end 각 설정값 별 상세 옵션은 Firebase App Distribution - 3단계: Fastfile 설정 및 앱 배포 문서에서 확인하실 수 있다. 우리 앱은 앱개발담당자/QA/기획자/협력사 정도로 구분해서 각 테스터들 그룹을 만들고, 해당 그룹의 정보가 위치한 txt 파일을 바라보도록 설정했다. 릴리즈노트도 이런식으로 작성하면 관리에 더 용이하다. 🚀 배포 시작 실행 이제 번거로운 빌드-업로드-배포-확인요청 4단계를, 단 한줄만으로 완료할 수 있다! $ fastlane distribution # 만약 gradle permission dined 오류가 발생한다면 하기 명령어로 권한 부여 후 재시도 해준다. ~/workspace$ chmod +x gradlew 👾 테스터 추가 이제 마지막으로 테스터들을 추가해야한다! 일일이 메일계정을 취합받아서 등록하는 방법과 URL을 통해 직접 참여할 수 있도록 유도하는 방법이 있는데, 당연히 후자로 ㄱㄱ Firebase console에서 초대 링크 > 새 초대 링크 > 그룹 선택 > 링크 만들기 클릭 💁 QA 엔지니어 초대 위에서 만든 링크를 이제 QA 엔지니어들에게 전달하기만하면 된다. QA 엔지니어는 링크를 통해 테스트앱을 설치할 수 있다. 이때, ‘App Tester’라는 앱을 설치하면 향후에도 계속 편하게 테스트앱을 받아볼 수 있다. 테스터들은 링크를 클릭한 후 이메일 주소를 입력하면, 메일에서 Firebase의 친절한 안내를 따라 앱을 설치할 수 있다. 마치며 회사블로그에 글 실으려고 처음으로 만들어본 주작 톡.. 거창하게 자동배포 어쩌고 하긴했는데, 사실 약 반년간 이 프로젝트하면서 비효율적인 부분이 너무 많고 날이 갈면 갈 수록 점점 바빠져서 충분히 개선 될 수 있을 부분들에 더 이상 힘 쏟고 싶지 않았다. 🤢 Firebase App Distribution 적용하는 것도 벼르고 벼르던 일 중에 하나였는데 드디어 해내서 정말 기분 좋다ㅠㅠ! 이제 하루 30분 정도 아꼈으니 일주일동안 약 2시간 정도는 개발 더 할 수 있다.. 🥳 (기뻐야하는데 왜 눈물이 나지..)
-
Github Profile 꾸미기
README.md를 활용한 나만의 깃헙 프로필 만들기
2021-02-24 15:44
작년 여름 Github 신기능으로 프로필 영역을 꾸밀 수 있는 Design Github profile using README.md 포스팅이 공개되었다. 나도 한번 해봐야지하다가 바쁘다는 핑계로 미뤄왔는데, 최근 CV 정리하면서보니 더 이상 미루면 안 될 것 같아서 이제서야 해보았다. 😉 🌈💖✨휘황찬란하고 화려해진 제 프로필 좀 보세요❣️💕💛 프로필 생성하기 GitHub에는 여러 이스터에그가 있는데, username.github.io 이름의 repository를 생성하면 이 블로그처럼 GitHub Pages를 활용한 블로그를 생성할 수 있다. 프로필 또한 이 이스터에그 중 하나로 github user name과 동일한 이름의 repository를 만들면 You found a secret!이라는 메시지와 함께 README.md 파일로 깃헙 프로필을 작성할 수 있음으로 알려준다. Github 접속 > Repository > New 클릭하여 신규 repository를 생성해준 뒤 이름을 본인의 username과 동일하게 입력한다. 생성할 때 Add a README file 항목을 활성화해주면 직접 README.md 파일을 만들지 않아도 된다. 확인 버튼을 누르면 respotiroy가 만들어지고, Add a README file 옵션을 활성화했을 경우에는 README.md 파일이 함께 생성된다. (혹은 직접 만들어도 된다.) 기본으로 'Hi there 👋' 내용이 입력되어있다. 이 때 프로필로 가보면 위의 README.md 파일과 같은 내용으로 프로필 영역이 생긴것을 확인할 수 있다. 힘차게 흔드는 손 발견! 이제 이 README.md 파일을 마음껏 수정해서 프로필 영역을 작성하고 꾸미면 된다. 프로필 꾸미기(1) - 본문 작성 Shields.io : 본문에 뱃지 넣기 나의 경우에는 연락처 정보와 스킬셋 기술을 위해 Shields.io를 사용해서 뱃지를 넣었다. https://img.shields.io/badge/<LABEL>-<MESSAGE>-<COLOR> 형태로 파라미터를 잘 넣어주면 적당한 모양의 뱃지 이미지가 생성된다. 또한 logo, logoColor, labelColor 등의 여러 쿼리를 함께 사용할 수 있다. 예를들어 위처럼 안드로이드 로고와 ‘Android’ 문구가 들어간 연두색의 뱃지를 생성하려면 아래 형식으로 가능하다. <img src="https://img.shields.io/badge/Android-3DDC84?style=flat-square&logo=Android&logoColor=white"/> 색상코드와 사용가능한 로고의 목록은 simpleicons.org에서 확인할 수 있다. 프로필 꾸미기(2) - Pined repo 활용하기 프로필 메인의 repository 고정 영역을 gist를 활용한 여러 라이브러리를 통해 꾸밀 수 있다. 나는 2개의 라이브러리를 사용해서 꾸며봤는데, 커밋시각을 분석해서 아침형 개발자인지 저녁형 개발자인지 알려주는 productive-box와 깃헙 stats를 나타내는 github-stats-box를 사용했다. productive-box : 커밋시각 통계 노출하기 나는 아침형 인간..! 사전 작업 gist.github.com에서 public으로 신규 gist를 생성한다. 제목과 내용은 향후 자동으로 업데이트 될 예정이므로 일단 아무렇게나 작성하면 된다. github 토큰생성 페이지에서 gist와 repo scope를 활성화하여 token을 발급한다. 이 때 발급된 토큰은 페이지를 빠져나가면 다시 얻을 수 없으니 클립보드 등에 잘 저장해둔다. 라이브러리 사용 productive-box repository를 fork한다. 우측 상단의 Fork 버튼을 누르면 된다. fork 된 나의 repository의 Action 탭에서 enabled 버튼을 눌러 Action을 활성화한다. .github/workflow/Schedule.yml 파일을 수정하여 환경변수를 작성해준다 GIST_ID: 사전 작업의 1번 step에서 생성된 gist의 id (gist URL은 gist.github.com//로 생성되기 때문에 주소창을 보면 된다.) TIMEZONE: 타임존을 적어준다. Asia/Seoul 형식으로 적어주면 된다. Settings 탭 > Secrets에 접속한 뒤 New repository secret 버튼을 클릭하여 환경변수를 설정해준다. GH_TOKEN: 사전 작업의 2번 step에서 발급받은 토큰 gist를 내 프로필에 고정한다. Action 주기(1시간)에 따라 자동으로 갱신 적용되나, 즉시 적용하고 싶다면 README.md 파일을 수정하는 등 파일에 변화를 주면 즉시 적용된다. github-stats-box : Github Status 노출하기 사전 작업 gist.github.com에서 public으로 신규 gist를 생성한다. 제목과 내용은 향후 자동으로 업데이트 될 예정이므로 일단 아무렇게나 작성하면 된다. github 토큰생성 페이지에서 gist와 repo scope를 활성화하여 token을 발급한다. 이 때 발급된 토큰은 페이지를 빠져나가면 다시 얻을 수 없으니 클립보드 등에 잘 저장해둔다. 라이브러리 사용 github-stats-box repository를 fork한다. 우측 상단의 Fork 버튼을 누르면 된다. fork 된 나의 repository의 Action 탭에서 enabled 버튼을 눌러 Action을 활성화한다. .github/workflow/Schedule.yml 파일을 수정하여 환경변수를 작성해준다 GIST_ID: 사전 작업의 1번 step에서 생성된 gist의 id (gist URL은 gist.github.com//로 생성되기 때문에 주소창을 보면 된다.) ALL_COMMITS: true일 경우 나의 전체 커밋을 카운트하고, false일 경우 작년 커밋만을 카운트한다. K_FORMAT: true일 경우 1.5k와 같이 숫자를 “k”로 포맷팅하여 노출한다. Settings 탭 > Secrets에 접속한 뒤 New repository secret 버튼을 클릭하여 환경변수를 설정해준다. GH_TOKEN: 사전 작업의 2번 step에서 발급받은 토큰 gist를 내 프로필에 고정한다. Action 주기에 따라 자동으로 갱신 적용되나, 즉시 적용하고 싶다면 README.md 파일을 수정하는 등 파일에 변화를 주면 즉시 적용된다. 그 외 더 많은 gists 라이브러리 찾아보기 matchai/awesome-pinned-gists에 여러 라이브러리들이 정리되어있다. Twitter를 연동하여 내 최근 트윗을 보여주거나 Spotify를 연동하여 최근 재생 음악을 보여줄 수 있고, 그 외 내가 많이 사용하는 언어 등의 정보들도 노출할 수 있다. 백준 solved.ac 랭킹 노출하기 나는.. 백준을 잘 애용하진 않아서(핑계임) 브론즈따리라 차마 갖다 쓰진 않았지만, 다른 개발자들은 mazassumnida/mazassumnida 라이브러리를 활용해서 solved.ac 랭킹을 많이들 노출하는 것 같다. (라이브러리 이름이 ‘마자씀니다’ 인가봄..) stats 등급 노출하기 나는 pinned gist를 활용해서 github stats를 노출했지만, anuraghazra/github-readme-stats 라이브러리도 있다. 이걸 활용하면 여러가지 테마로 stats를 노출하고, 등급 정보까지 산정(?)할 수 있다. 최저 B 등급부터 시작하는 개발자의 센스가 돋보이는 라이브러리다. 🌱 제 깃헙도 놀러오세요..!
-
if only VS if else
내 코드를 방해하는 else를 찾아서 🐠
2021-02-23 14:49
요즘 알고리즘 공부 차 매일 릿코드 문제를 랜덤으로 풀고 있는데, 문제를 풀던 중 흥미로운 점을 발견했다. // 1번 코드 if (condition) { var += A; } var += B; // 2번 코드 if (condition) { var += A + B; } else { var += B; } 1번 코드와 2번 코드는 룩은 달라도 동일한 로직을 수행하고 동일한 결과를 제공한다. condition이 true일 때는 var 변수에 A와 B가 추가되고, false일 때는 var변수에 B만 추가된다. 난 대게 Return elary pattern, Guard clauses refactoring 등의 패턴에 따라 1번 코드를 많이 봐왔고 또 1번 코드로 많이 짜왔지만, 사실 상 2번코드로 짠다고해서 큰 차이는 없다고 생각했기 때문에 코드리뷰 등의 과정에서 해당 패턴을 유심히 본 적은 없다. 릿코드의 824. Goat Latin 문제를 A개발자와 각각 풀면서 둘이 거의 유사한 로직을 구현했는데, 코드의 time complexity가 같음에도 불구하고 희한하게 두 코드에서 6ms 내외의 run time 차이가 있었다. 한줄 한줄 분석하며 원인을 찾다보니 한명은 1번 코드로 짰고 한명은 2번 코드로 짰는데 그 부분에서 run time이 차이난다는 것을 발견하게 되었다. else 구문의 비용? 참 희한한 일이다. else if도 아니고 단지 else일 뿐인데 이걸 사용하느냐 아니냐로 차이가 난다고? 처음에는 변수에 값이 assign 되는 시점의 차이인가하고 여러 테스트 케이스를 만들어 돌려봤는데, 변수 할당이나 공간 복잡도 등의 문제는 아닌 것 같다는 결론을 내렸다. else coast, early return time complexity 등의 키워드로 검색을 했으나 대체로 코딩 스타일과 가독성에서 1번 코드로 짜는 것이 좋다는 글들 말고는 딱히 속도와 비용에 대해서 이야기하는 글을 찾지 못했다. 그러던 중 If statement vs if-else statement, which is faster?라는 은혜로운 글을 발견하게 되었다! if only VS if else accepted 된 답변에서는 if only 케이스와 if else 두 케이스를 비교해서 컴파일 결과를 비교한다. if only: mov DWORD PTR [rbp-8], 5 cmp BYTE PTR [rbp-4], 0 je .L2 mov DWORD PTR [rbp-8], 6 .L2: mov eax, DWORD PTR [rbp-8] if else: cmp BYTE PTR [rbp-4], 0 je .L5 mov DWORD PTR [rbp-8], 6 jmp .L6 .L5: mov DWORD PTR [rbp-8], 5 .L6: mov eax, DWORD PTR [rbp-8] 컴파일러의 최적화 옵션이 적용되어 있지 않은 경우에는 어쨌든 if only가 더 효율적이라고는 한다. 그러나 이는 굉장히 미미함을 강조하고 있다. The latter looks slightly less efficient because it has an extra jump but both have at least two and at most three assignments so unless you really need to squeeze every last drop of performance (hint: unless you are working on a space shuttle you don’t, and even then you probably don’t) the difference won’t be noticeable. Return Early Pattern 호기심 때문에 if only VS if else를 비교하기는 했지만, 사실 요즘 컴파일러는 최적화 되어있을 뿐더러 유연하게 동작하기 때문에 차이라고 말하기엔 의미 없는 것으로 보인다. 그리고 속도/공간 복잡도를 이야기한다쳐도, 어느 정도의 의미있는 차이가 아니고서는 상호간의 이해와 유지보수가 편안한 코드를 작성하는 것이 중요하다고 생각한다. 추후 만약 누군가가 2번 코드로 작성한 것을 리뷰하게 되더라도 딱히 denied 하진 않겠지만, 가독성 및 유지보수 측면에서 1번 코드로 작성하도록 suggestion 정도는 할 것 같다. 1번 코드는 Return Early Pattern으로 통용되며, 이 패턴으로 작성했을 때의 장점은 하기 항목으로 정리할 수 있다. 들여쓰기의 깊이가 1레벨이기 때문에 선형적으로 코드를 읽을 수 있다. positive result를 함수 끝에서 빠르게 찾을 수 있다. 예외를 먼저 처리한 뒤 비즈니스 로직을 구현하기 때문에 불필요한 버그를 피할 수 있다. TDD 방식과 유사하므로 코드를 테스트하기가 더 용이하다. 오류가 발생되면 즉시 종료되므로 더 많은 코드가 실행될 가능성이 없다. 관련 내용은 관련 패턴인 Else Considered Smelly와 Arrow Anti Pattern의 내용을 읽어보면 도움이 많이 된다. 또한 구글링 중에 발견한 Return Early Pattern 글에 정리가 잘 되어있어서 생각을 정리하는데 크게 도움이 되었다.