<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 陈科林</title>
    <description>The latest articles on DEV Community by 陈科林 (@_258cd27a94f80dc3fcdac).</description>
    <link>https://dev.to/_258cd27a94f80dc3fcdac</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3990007%2F7cc6539b-56c0-4be0-b39c-8dd21e122530.png</url>
      <title>DEV Community: 陈科林</title>
      <link>https://dev.to/_258cd27a94f80dc3fcdac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_258cd27a94f80dc3fcdac"/>
    <language>en</language>
    <item>
      <title>Building a Transparent Digital SAT Score Estimator Without Pretending It Is Exact</title>
      <dc:creator>陈科林</dc:creator>
      <pubDate>Sun, 21 Jun 2026 02:55:32 +0000</pubDate>
      <link>https://dev.to/_258cd27a94f80dc3fcdac/building-a-transparent-digital-sat-score-estimator-without-pretending-it-is-exact-c8e</link>
      <guid>https://dev.to/_258cd27a94f80dc3fcdac/building-a-transparent-digital-sat-score-estimator-without-pretending-it-is-exact-c8e</guid>
      <description>&lt;p&gt;Score calculators look simple from the outside: enter a number of correct answers, apply a conversion table, and display a score.&lt;/p&gt;

&lt;p&gt;The Digital SAT makes that approach unreliable.&lt;/p&gt;

&lt;p&gt;It is adaptive, its operational scoring model is not publicly reproducible, and College Board does not publish one universal raw-to-scaled conversion table for every test form. An independent calculator therefore has two choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;present false precision, or&lt;/li&gt;
&lt;li&gt;make uncertainty part of the product.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the second approach while building a free Digital SAT score estimator.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core product decision
&lt;/h2&gt;

&lt;p&gt;The most important decision was not a framework or library. It was deciding what the output should mean.&lt;/p&gt;

&lt;p&gt;The tool does &lt;strong&gt;not&lt;/strong&gt; claim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;that every question has a fixed point value;&lt;/li&gt;
&lt;li&gt;that the same number of correct answers always produces the same score;&lt;/li&gt;
&lt;li&gt;that it can identify a student's exact adaptive route; or&lt;/li&gt;
&lt;li&gt;that its result will match an official score report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, it answers a narrower question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Based on these practice-module results, what broad score range is useful for study planning?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That wording changes the implementation, interface, and content around the calculator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why module-level inputs still matter
&lt;/h2&gt;

&lt;p&gt;The Digital SAT contains two modules in each section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Math: 22 questions per module;&lt;/li&gt;
&lt;li&gt;Reading and Writing: 27 questions per module.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Performance in the first module affects the difficulty of the second module. The interface therefore asks for four inputs rather than one overall percentage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Math Module 1 correct;&lt;/li&gt;
&lt;li&gt;Math Module 2 correct;&lt;/li&gt;
&lt;li&gt;Reading and Writing Module 1 correct;&lt;/li&gt;
&lt;li&gt;Reading and Writing Module 2 correct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current estimator captures those module results separately but uses their section totals to select broad planning bands. It does &lt;strong&gt;not&lt;/strong&gt; infer which Module 2 route the student received. That limitation is shown directly in the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the implementation deliberately boring
&lt;/h2&gt;

&lt;p&gt;For this kind of tool, understandable code is more valuable than an impressive-looking formula.&lt;/p&gt;

&lt;p&gt;Here is the simplified Math estimator used by one calculator path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;estimateMath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;760-800&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;700-770&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;640-710&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;580-650&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;510-590&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;430-520&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;340-440&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;200-350&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Reading and Writing path follows the same pattern with thresholds appropriate to its 54-question total.&lt;/p&gt;

&lt;p&gt;Inputs are clamped before calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents negative values, values above the module limit, and empty inputs from producing impossible results.&lt;/p&gt;

&lt;p&gt;The interesting part is what the code intentionally does &lt;em&gt;not&lt;/em&gt; do. It does not hide a speculative formula behind decimal places. A result such as &lt;code&gt;700-770&lt;/code&gt; communicates the model's actual level of confidence better than an unsupported result such as &lt;code&gt;742&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treating limitations as part of the interface
&lt;/h2&gt;

&lt;p&gt;A disclaimer buried in a footer is easy to ignore. For an educational estimator, limitations should appear near the result.&lt;/p&gt;

&lt;p&gt;The calculator explains that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the range uses correct-answer totals;&lt;/li&gt;
&lt;li&gt;it does not reproduce College Board's operational scoring model;&lt;/li&gt;
&lt;li&gt;it cannot know the exact characteristics of the questions on a real test;&lt;/li&gt;
&lt;li&gt;different forms and adaptive paths can produce different official scores; and&lt;/li&gt;
&lt;li&gt;an official Bluebook score should take priority when one is available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not just defensive copy. It helps users understand why two students with the same number of correct answers may not receive identical official scores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources before formulas
&lt;/h2&gt;

&lt;p&gt;Before defining score bands, I started with the public structure and scoring language in College Board materials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://satsuite.collegeboard.org/scores/what-scores-mean/how-scores-calculated" rel="noopener noreferrer"&gt;How SAT Scores Are Calculated&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://satsuite.collegeboard.org/media/pdf/assessment-framework-for-digital-sat-suite.pdf" rel="noopener noreferrer"&gt;Digital SAT Suite Assessment Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://satsuite.collegeboard.org/practice/practice-tests/bluebook" rel="noopener noreferrer"&gt;Full-Length Practice Tests in Bluebook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those sources establish what an independent tool can responsibly say. They do not provide enough information to recreate the official scoring engine.&lt;/p&gt;

&lt;p&gt;That distinction matters. Public documentation can support an educational estimate without supporting a claim of exact prediction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product lessons from this small project
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Precision and accuracy are different
&lt;/h3&gt;

&lt;p&gt;Adding more digits makes an answer look precise. It does not make the underlying model more accurate.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Uncertainty can be useful output
&lt;/h3&gt;

&lt;p&gt;A range is not a failure when the data cannot support a point estimate. It is often the more honest product.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Explainability belongs in the main flow
&lt;/h3&gt;

&lt;p&gt;Users should be able to understand what inputs are used, what the output means, and what the model cannot know without reading legal text.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Educational tools need careful language
&lt;/h3&gt;

&lt;p&gt;Phrases such as "estimated range," "planning use," and "independent tool" are functional parts of the product, not marketing decorations.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Simple code is easier to audit
&lt;/h3&gt;

&lt;p&gt;Threshold-based bands are limited, but their behavior is visible. Future calibration can improve them without pretending the current version is more sophisticated than it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would improve next
&lt;/h2&gt;

&lt;p&gt;The next useful improvements are not cosmetic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;version the score-band assumptions;&lt;/li&gt;
&lt;li&gt;test all boundary values automatically;&lt;/li&gt;
&lt;li&gt;compare estimates against a larger set of official practice-test outcomes;&lt;/li&gt;
&lt;li&gt;communicate uncertainty more visually;&lt;/li&gt;
&lt;li&gt;explain why an official Bluebook result can differ; and&lt;/li&gt;
&lt;li&gt;keep methodology changes visible to users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The long-term goal is not to reverse-engineer an unpublished scoring system. It is to make a planning tool more transparent and better calibrated.&lt;/p&gt;

&lt;p&gt;I published the current assumptions, sources, and limitations on the project's &lt;a href="https://digitalsatcalc.com/methodology/" rel="noopener noreferrer"&gt;methodology page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project is independent and is not affiliated with or endorsed by College Board.&lt;/p&gt;

&lt;p&gt;If you have built calculators around incomplete public data, I would be interested to hear how you communicated uncertainty without making the tool feel unhelpful.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>learngoogleaistudio</category>
    </item>
    <item>
      <title>Building a Transparent Digital SAT Score Estimator Without Pretending It Is Exact</title>
      <dc:creator>陈科林</dc:creator>
      <pubDate>Sun, 21 Jun 2026 02:49:42 +0000</pubDate>
      <link>https://dev.to/_258cd27a94f80dc3fcdac/building-a-transparent-digital-sat-score-estimator-without-pretending-it-is-exact-171i</link>
      <guid>https://dev.to/_258cd27a94f80dc3fcdac/building-a-transparent-digital-sat-score-estimator-without-pretending-it-is-exact-171i</guid>
      <description>&lt;p&gt;Score calculators look simple from the outside: enter a number of correct answers, apply a conversion table, and display a score.&lt;/p&gt;

&lt;p&gt;The Digital SAT makes that approach unreliable.&lt;/p&gt;

&lt;p&gt;It is adaptive, its operational scoring model is not publicly reproducible, and College Board does not publish one universal raw-to-scaled conversion table for every test form. An independent calculator therefore has two choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;present false precision, or&lt;/li&gt;
&lt;li&gt;make uncertainty part of the product.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the second approach while building a free Digital SAT score estimator&lt;/p&gt;

</description>
      <category>top7</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>explainlikeimfive</category>
    </item>
  </channel>
</rss>
