<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>after-crud</title>
    <link>https://blogger26679.tistory.com/</link>
    <description>개발뿐만 아니라 개발 이후의 과정까지 기록하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 15 May 2026 22:22:53 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>after-crud</managingEditor>
    <image>
      <title>after-crud</title>
      <url>https://tistory1.daumcdn.net/tistory/8686811/attach/b5b3c5500da04bda816181db2cb9a421</url>
      <link>https://blogger26679.tistory.com</link>
    </image>
    <item>
      <title>정답은 서버에 두고, 플레이는 자연스럽게 만들기</title>
      <link>https://blogger26679.tistory.com/entry/%EC%A0%95%EB%8B%B5%EC%9D%80-%EC%84%9C%EB%B2%84%EC%97%90-%EB%91%90%EA%B3%A0-%ED%94%8C%EB%A0%88%EC%9D%B4%EB%8A%94-%EC%9E%90%EC%97%B0%EC%8A%A4%EB%9F%BD%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://after-crud.com/entry/%EC%8A%A4%EB%8F%84%EC%BF%A0-%EC%A0%95%EB%8B%B5%EC%9D%84-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-%EB%B3%B4%EB%82%B4%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 글&lt;/a&gt;에서는 랭킹이 있는 스도쿠 게임에서 정답을 브라우저에 보내면 왜 문제가 되는지 이야기했습니다. 이번 글에서는 Sudoku nodi가 이 문제를 어떻게 해결했는지 조금 더 구체적으로 정리해보려 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Keep-the-correct-answers-on-the-server-but-make-the-gameplay-feel-natural.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2ojHx/dJMcahj9rd7/VjYfY5v28ajKKuOiFv2mt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2ojHx/dJMcahj9rd7/VjYfY5v28ajKKuOiFv2mt1/img.png&quot; data-alt=&quot;브라우저와 서버의 역할을 나누고, 퍼즐 요청부터 제출, 검증, 기록까지의 흐름을 한눈에 보여주는 구조도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2ojHx/dJMcahj9rd7/VjYfY5v28ajKKuOiFv2mt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2ojHx%2FdJMcahj9rd7%2FVjYfY5v28ajKKuOiFv2mt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;723&quot; height=&quot;456&quot; data-filename=&quot;Keep-the-correct-answers-on-the-server-but-make-the-gameplay-feel-natural.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;브라우저와 서버의 역할을 나누고, 퍼즐 요청부터 제출, 검증, 기록까지의 흐름을 한눈에 보여주는 구조도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1827&quot; data-start=&quot;1668&quot; data-ke-size=&quot;size16&quot;&gt;핵심은 역할을 나누는 것입니다. 브라우저는 사용자가 편하게 플레이하도록 돕고, 서버는 기록을 믿을 수 있는지 판단합니다. 브라우저는 화면을 보여주고, 숫자 입력을 처리하고, 타이머를 표시합니다. 서버는 정답을 보관하고, 사용자가 제출한 풀이를 검증하고, 완료 시간과 점수를 계산합니다.&lt;/p&gt;
&lt;p data-end=&quot;1827&quot; data-start=&quot;1668&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1939&quot; data-start=&quot;1829&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 오늘의 스도쿠를 열면 서버는 문제판만 보내줍니다. 여기에는 처음부터 채워져 있는 숫자와 빈칸 정보가 들어 있습니다. 하지만 완성된 정답판은 보내지 않습니다. 정답은 서버 안에 저장해둡니다.&lt;/p&gt;
&lt;p data-end=&quot;1939&quot; data-start=&quot;1829&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2089&quot; data-start=&quot;1941&quot; data-ke-size=&quot;size16&quot;&gt;그리고 사용자가 실제로 풀이를 시작하면 서버는 하나의 풀이 기록을 만듭니다. 이것을 쉽게 말하면 &amp;ldquo;이 사용자가 이 퍼즐을 지금부터 풀기 시작했다&amp;rdquo;는 기록입니다. 이 기록에는 시작 시간, 어떤 퍼즐인지, 힌트를 몇 번 썼는지, 나중에 완료했는지 같은 정보가 쌓입니다.&lt;/p&gt;
&lt;p data-end=&quot;2089&quot; data-start=&quot;1941&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2235&quot; data-start=&quot;2091&quot; data-ke-size=&quot;size16&quot;&gt;브라우저가 아무 일도 하지 않는 것은 아닙니다. 사용자가 같은 줄에 같은 숫자를 두 번 입력했거나, 같은 작은 박스 안에 중복된 숫자를 넣었다면 바로 알려줄 수 있습니다. 이런 검사는 정답을 몰라도 가능합니다. 스도쿠의 기본 규칙만 확인하면 되기 때문입니다.&lt;/p&gt;
&lt;p data-end=&quot;2381&quot; data-start=&quot;2237&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &amp;ldquo;이 칸의 숫자가 정답과 다르다&amp;rdquo;는 판단은 브라우저가 하지 않습니다. 그 판단을 하려면 정답판이 필요하고, 정답판을 브라우저에 보내는 순간 처음의 목적이 무너집니다. 그래서 브라우저는 빠른 반응과 편한 조작을 담당하고, 정답 여부는 서버가 담당합니다.&lt;/p&gt;
&lt;p data-end=&quot;2381&quot; data-start=&quot;2237&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2383&quot; data-ke-size=&quot;size16&quot;&gt;힌트도 같은 방식으로 처리합니다. 사용자가 특정 칸의 힌트를 요청하면 서버는 전체 정답을 보내지 않고, 그 칸 하나의 값만 알려줍니다. 그리고 힌트를 사용했다는 사실도 서버에 기록합니다. 랭킹을 계산할 때 힌트를 많이 쓴 기록과 힌트를 쓰지 않은 기록을 똑같이 비교하면 공정하지 않기 때문입니다.&lt;/p&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2383&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2717&quot; data-start=&quot;2550&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 퍼즐을 다 풀고 제출하면, 브라우저는 현재 입력된 판을 서버로 보냅니다. 서버는 자신이 보관하고 있던 정답판과 비교합니다. 맞으면 완료 처리하고, 시작 시간과 완료 시간을 기준으로 실제 풀이 시간을 계산합니다. 틀렸다면 정답을 알려주지 않고, 어떤 위치가 잘못되었는지만 알려줄 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;2717&quot; data-start=&quot;2550&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2863&quot; data-start=&quot;2719&quot; data-ke-size=&quot;size16&quot;&gt;타이머도 마찬가지입니다. 화면에 보이는 타이머는 사용자가 시간을 느끼기 위한 표시입니다. 실제 랭킹에 쓰이는 시간은 서버가 기록한 시작 시간과 완료 시간을 기준으로 계산합니다. 그래야 새로고침을 하거나 화면의 값을 조작하더라도 기록이 쉽게 흔들리지 않습니다.&lt;/p&gt;
&lt;p data-end=&quot;2863&quot; data-start=&quot;2719&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3008&quot; data-start=&quot;2865&quot; data-ke-size=&quot;size16&quot;&gt;이 방식은 단순히 화면에서 정답을 비교하는 것보다 구현이 복잡합니다. 서버는 퍼즐, 정답, 풀이 기록, 힌트 사용, 완료 시간 등을 모두 관리해야 합니다. 하지만 대신 얻는 것이 있습니다. 기록을 더 믿을 수 있고, 랭킹을 더 공정하게 운영할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;3008&quot; data-start=&quot;2865&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;3185&quot; data-start=&quot;3010&quot; data-ke-size=&quot;size16&quot;&gt;대부분의 스도쿠 게임은 정답을 서버에만 두는 이유는 단순한 보안 때문만은 아닙니다. 오늘의 스도쿠와 일일 랭킹이 제대로 의미를 가지려면, 사용자가 만든 기록을 믿을 수 있어야 합니다. 클라이언트는 즐거운 플레이를 만들고, 서버는 그 기록의 신뢰성을 지키는 것. 이 책임 분리가 서버 검증 기반 구조의 핵심입니다.&lt;/p&gt;</description>
      <category>개발/백엔드 설계</category>
      <category>1인 개발</category>
      <category>개발</category>
      <category>백엔드 설계</category>
      <category>스도쿠</category>
      <author>after-crud</author>
      <guid isPermaLink="true">https://blogger26679.tistory.com/2</guid>
      <comments>https://blogger26679.tistory.com/entry/%EC%A0%95%EB%8B%B5%EC%9D%80-%EC%84%9C%EB%B2%84%EC%97%90-%EB%91%90%EA%B3%A0-%ED%94%8C%EB%A0%88%EC%9D%B4%EB%8A%94-%EC%9E%90%EC%97%B0%EC%8A%A4%EB%9F%BD%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0#entry2comment</comments>
      <pubDate>Thu, 14 May 2026 12:00:12 +0900</pubDate>
    </item>
    <item>
      <title>스도쿠 정답을 브라우저에 보내면 안 되는 이유</title>
      <link>https://blogger26679.tistory.com/entry/%EC%8A%A4%EB%8F%84%EC%BF%A0-%EC%A0%95%EB%8B%B5%EC%9D%84-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-%EB%B3%B4%EB%82%B4%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Why-You-Shouldn't-Send-Sudoku-Answers-to-Your-Browser.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmH7c/dJMcagFxjuk/NzKGLPjc48XoSBHkpfqcX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmH7c/dJMcagFxjuk/NzKGLPjc48XoSBHkpfqcX1/img.png&quot; data-alt=&quot;브라우저로 정답이 전달되면 개발자 도구 등을 통해 쉽게 확인할 수 있습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmH7c/dJMcagFxjuk/NzKGLPjc48XoSBHkpfqcX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmmH7c%2FdJMcagFxjuk%2FNzKGLPjc48XoSBHkpfqcX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;551&quot; data-filename=&quot;Why-You-Shouldn't-Send-Sudoku-Answers-to-Your-Browser.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;브라우저로 정답이 전달되면 개발자 도구 등을 통해 쉽게 확인할 수 있습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스도쿠 게임을 만들 때 가장 쉬운 방법은 문제와 정답을 함께 준비해두는 것입니다. 사용자가 숫자를 입력하면, 화면 안에서 정답과 바로 비교하면 됩니다. 맞으면 넘어가고, 틀리면 표시해주면 됩니다. 혼자 즐기는 게임이라면 이런 방식도 크게 문제가 되지 않습니다.&lt;/p&gt;
&lt;p data-end=&quot;439&quot; data-start=&quot;299&quot; data-ke-size=&quot;size16&quot;&gt;하지만 대부분 스도쿠 게임에는 오늘의 스도쿠와 일일 랭킹 기능이 있습니다. 여러 사람이 같은 퍼즐을 풀고, 누가 더 빠르게 풀었는지 기록으로 비교합니다. 이때부터는 단순히 &amp;ldquo;게임이 잘 작동하는가&amp;rdquo;보다 &amp;ldquo;그 기록을 믿을 수 있는가&amp;rdquo;가 더 중요해집니다.&lt;/p&gt;
&lt;p data-end=&quot;608&quot; data-start=&quot;441&quot; data-ke-size=&quot;size16&quot;&gt;여기서 말하는 브라우저는 사용자가 실제로 보는 화면입니다. 스도쿠 판, 숫자 버튼, 타이머, 힌트 버튼처럼 눈에 보이는 부분이 브라우저에서 실행됩니다. 반대로 서버는 사용자 눈에 보이지 않는 뒤쪽 시스템입니다. 퍼즐을 만들고, 정답을 보관하고, 사용자가 제출한 풀이가 맞는지 확인하는 역할을 합니다.&lt;/p&gt;
&lt;p data-end=&quot;608&quot; data-start=&quot;441&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;814&quot; data-start=&quot;610&quot; data-ke-size=&quot;size16&quot;&gt;문제는 브라우저가 완전히 숨겨진 공간이 아니라는 점입니다. 화면에 정답을 보여주지 않더라도, 정답 데이터가 브라우저로 전달되었다면 사용자는 개발자 도구 같은 방법으로 그 데이터를 확인할 수 있습니다. 쉽게 말해, 택배 상자 안에 정답지를 넣어 보내놓고 &amp;ldquo;겉으로는 안 보이니까 괜찮다&amp;rdquo;고 말하는 것과 비슷합니다. 상자를 열어볼 수 있다면 정답은 숨겨진 것이 아닙니다.&lt;/p&gt;
&lt;p data-end=&quot;814&quot; data-start=&quot;610&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;976&quot; data-start=&quot;816&quot; data-ke-size=&quot;size16&quot;&gt;스도쿠에서는 정답판이 따로 있습니다. 처음 보이는 문제판에는 빈칸이 있지만, 정답판에는 모든 칸이 채워져 있습니다. 이 완성된 정답판을 브라우저에 보내면 사용자는 실제로 퍼즐을 풀지 않고도 정답을 확인할 수 있습니다. 그리고 그 값을 그대로 입력하면 아주 빠른 기록을 만들 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;976&quot; data-start=&quot;816&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1139&quot; data-start=&quot;978&quot; data-ke-size=&quot;size16&quot;&gt;혼자 하는 게임이라면 이것은 개인의 선택일 수 있습니다. 하지만 랭킹이 있는 게임에서는 다릅니다. 누군가는 직접 고민해서 퍼즐을 풀고, 누군가는 정답을 보고 입력한다면 두 기록은 같은 의미를 가질 수 없습니다. 결국 랭킹의 공정성이 흔들리고, 성실하게 플레이한 사용자의 경험도 나빠집니다.&lt;/p&gt;
&lt;p data-end=&quot;1290&quot; data-start=&quot;1141&quot; data-ke-size=&quot;size16&quot;&gt;그래서 스도쿠 게임에서는 정답을 브라우저에 보내지 않는 방향이 맞습니다. 사용자가 보는 화면에는 문제판만 전달하고, 완성된 정답판은 서버 안에만 보관합니다. 브라우저는 사용자가 편하게 플레이하도록 돕고, 서버는 나중에 제출된 답이 정말 맞는지 판단합니다.&lt;/p&gt;
&lt;p data-end=&quot;1290&quot; data-start=&quot;1141&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1421&quot; data-start=&quot;1292&quot; data-ke-size=&quot;size16&quot;&gt;이 구조가 모든 부정행위를 완벽하게 막아주는 것은 아닙니다. 누군가는 외부 도구로 스도쿠를 풀 수도 있고, 반복해서 시도할 수도 있습니다. 하지만 적어도 정답이 게임 화면 뒤에 그대로 숨어 있는 가장 쉬운 문제는 막을 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1421&quot; data-start=&quot;1292&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1510&quot; data-start=&quot;1423&quot; data-ke-size=&quot;size16&quot;&gt;결국 핵심은 단순합니다. 랭킹이 있는 게임에서는 기록이 믿을 만해야 합니다. 그리고 기록을 믿으려면 정답을 사용자의 브라우저가 아니라 서버에 두어야 합니다.&lt;/p&gt;
&lt;p data-end=&quot;1510&quot; data-start=&quot;1423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/백엔드 설계</category>
      <category>1인 개발</category>
      <category>개발</category>
      <category>백엔드 설계</category>
      <category>스도쿠</category>
      <author>after-crud</author>
      <guid isPermaLink="true">https://blogger26679.tistory.com/1</guid>
      <comments>https://blogger26679.tistory.com/entry/%EC%8A%A4%EB%8F%84%EC%BF%A0-%EC%A0%95%EB%8B%B5%EC%9D%84-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-%EB%B3%B4%EB%82%B4%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0#entry1comment</comments>
      <pubDate>Wed, 13 May 2026 19:16:41 +0900</pubDate>
    </item>
  </channel>
</rss>