Live
Black Hat USAAI BusinessBlack Hat AsiaAI BusinessRunning Local AI Models for Coding in 2026: When Cloud Tools Are Not the AnswerDev.to AIDay 4: I Built a Migration Tool for 500+ Developers in One HeartbeatDev.to AIHow I Stopped Blindly Trusting Claude Code Skills (And Built a 9-Layer Security Scanner)Dev.to AIAI Code Review Is the New Bottleneck: Why Faster Code Is Not Reaching Production FasterDev.to AIIntelligence vs. Orchestration: Why Coordination Alone Can't Run a BusinessDev.to AII Built a Memory System Because I Die Every 30 MinutesDev.to AIAutomating Repetitive Tasks with WorkanyDev.to AITop Skills by Category — 2026-04-04Dev.to AISandbox Results — Runtime Behavior — 2026-04-04Dev.to AIHigh-Risk Authors — Malicious Accounts — 2026-04-04Dev.to AIWhat the Architects of AI Are Actually Saying About Your CareerMedium AIGoogle Just Admitted the Internet Is Breaking (And Most People Missed It)Medium AIBlack Hat USAAI BusinessBlack Hat AsiaAI BusinessRunning Local AI Models for Coding in 2026: When Cloud Tools Are Not the AnswerDev.to AIDay 4: I Built a Migration Tool for 500+ Developers in One HeartbeatDev.to AIHow I Stopped Blindly Trusting Claude Code Skills (And Built a 9-Layer Security Scanner)Dev.to AIAI Code Review Is the New Bottleneck: Why Faster Code Is Not Reaching Production FasterDev.to AIIntelligence vs. Orchestration: Why Coordination Alone Can't Run a BusinessDev.to AII Built a Memory System Because I Die Every 30 MinutesDev.to AIAutomating Repetitive Tasks with WorkanyDev.to AITop Skills by Category — 2026-04-04Dev.to AISandbox Results — Runtime Behavior — 2026-04-04Dev.to AIHigh-Risk Authors — Malicious Accounts — 2026-04-04Dev.to AIWhat the Architects of AI Are Actually Saying About Your CareerMedium AIGoogle Just Admitted the Internet Is Breaking (And Most People Missed It)Medium AI
AI NEWS HUBbyEIGENVECTOREigenvector

Building a scoring engine with pure TypeScript functions (no ML, no backend)

DEV Communityby [CS] AlishoppingApril 2, 20264 min read2 views
Source Quiz

<p>We needed to score e-commerce products across multiple dimensions: quality, profitability, market conditions, and risk.</p> <p>The constraints:</p> <ul> <li>Scores must update in real time</li> <li>Must run entirely in the browser (Chrome extension)</li> <li>Must be explainable (not a black box)</li> </ul> <p>We almost built an ML pipeline — training data, model serving, APIs, everything.</p> <p>Then we asked a simple question:</p> <p><strong>Do we actually need machine learning for this?</strong></p> <p>The answer was no.</p> <p>We ended up building several scoring engines in pure TypeScript.<br> Each one is a single function, under 100 lines, zero dependencies, and runs in under a millisecond.</p> <h2> What "pure function" means here </h2> <p>Each scoring engine follows 3 rules:</p> <

We needed to score e-commerce products across multiple dimensions: quality, profitability, market conditions, and risk.

The constraints:

  • Scores must update in real time

  • Must run entirely in the browser (Chrome extension)

  • Must be explainable (not a black box)

We almost built an ML pipeline — training data, model serving, APIs, everything.

Then we asked a simple question:

Do we actually need machine learning for this?

The answer was no.

We ended up building several scoring engines in pure TypeScript. Each one is a single function, under 100 lines, zero dependencies, and runs in under a millisecond.

What "pure function" means here

Each scoring engine follows 3 rules:

  • No I/O → no network, no DB, no files

  • Deterministic → same input = same output

  • No side effects → no global state, no mutations

This makes them:

  • Easy to test

  • Easy to reason about

  • Portable (browser, Node.js, anywhere)

Core pattern: weighted scoring

interface ScoringInput {  qualityScore: number | null;  profitScore: number | null;  marketScore: number | null;  riskScore: number | null; }

type Verdict = 'strong_buy' | 'buy' | 'hold' | 'pass';

function computeScore(input: ScoringInput) { const quality = input.qualityScore ?? 50; const profit = input.profitScore ?? 50; const market = input.marketScore ?? 50; const risk = input.riskScore ?? 50;

const overall = Math.round( quality * 0.3 + profit * 0.3 + market * 0.2 + risk * 0.2 );

let verdict: Verdict; if (overall >= 80) verdict = 'strong_buy'; else if (overall >= 60) verdict = 'buy'; else if (overall >= 40) verdict = 'hold'; else verdict = 'pass';

return { overall, verdict }; }`

Enter fullscreen mode

Exit fullscreen mode

Handling missing data (critical)

All inputs are nullable.

We default to 50 (neutral).

Why not:

  • Skip missing values → breaks comparability

  • Default 0 → unfairly penalizes

  • Default 100 → artificially inflates

Neutral = safest assumption.

Normalization + clamp

All scores must be 0–100.

function clamp(value: number, min: number, max: number) {  return Math.max(min, Math.min(max, value)); }

const profitScore = clamp(marginPercent * 2, 0, 100); const marketScore = clamp(100 - saturationPercent, 0, 100); const riskScore = clamp(100 - rawRiskScore, 0, 100);`*

Enter fullscreen mode

Exit fullscreen mode

Without clamp:

  • values can exceed bounds

  • negative values break logic

  • NaN propagates silently

Choosing weights

Not all dimensions are equal.

We weighted:

  • Quality + Profit → higher (controllable)

  • Market + Risk → lower (external factors)

We considered user-configurable weights but dropped it: → too complex for non-technical users

Threshold calibration

Initial thresholds (75 / 50 / 25) were too optimistic.

We:

  • Scored hundreds of products

  • Compared with human judgment

  • Iterated

Lesson: Never guess thresholds — calibrate them.

Composition > monolith

We built multiple small engines:

  • Product score

  • Market score

  • Platform score

Then combine:

function computeFinalVerdict(  productScore: number | null,  marketScore: number | null,  platformScore: number | null ) {  const product = productScore ?? 50;  const market = marketScore ?? 50;  const platform = platformScore ?? 50;

const score = Math.round( market * 0.4 + product * 0.35 + platform * 0.25 );*

const confidence = Math.round( Math.min(product, market, platform) * 0.8 + 20 );*

const reasons: string[] = [];

if (market >= 70) reasons.push('Favorable market conditions'); if (market < 40) reasons.push('Challenging market'); if (product >= 70) reasons.push('Strong product'); if (product < 40) reasons.push('Weak product');

return { score, confidence, reasons }; }`

Enter fullscreen mode

Exit fullscreen mode

Key ideas:

  • Confidence = weakest dimension

  • Reasons = explainability

Example

Input:

  • Quality: 75

  • Profit: 84

  • Market: 65

  • Risk: 80

Result:

  • Score: 77

  • Verdict: buy

If profit increases → score crosses 80 → strong_buy

This kind of reasoning is trivial with pure functions, impossible with black-box ML.

When you SHOULD use ML

Use ML if:

  • You analyze images or text

  • You need pattern discovery

  • You have high-dimensional data (50+ features)

Otherwise: → pure functions are simpler, faster, more transparent

Key takeaways

  • Start with pure functions

  • Default missing data to neutral

  • Always clamp values

  • Weight by controllability

  • Compose small engines

  • Calibrate with real data

No training data. No APIs. No latency. Runs in-browser in under 1ms.

Not for every problem — but for structured scoring, it’s hard to beat.

Curious: Have you used similar scoring patterns? Or did you go with ML instead?

Try it free: https://chromewebstore.google.com/detail/alishopping-%E2%80%94-aliexpress/agiaehdeifaihlndhnhcmopjpjijnfap?utm_source=devto

Was this article helpful?

Sign in to highlight and annotate this article

AI
Ask AI about this article
Powered by Eigenvector · full article context loaded
Ready

Conversation starters

Ask anything about this article…

Daily AI Digest

Get the top 5 AI stories delivered to your inbox every morning.

More about

modeltrainingupdate

Knowledge Map

Knowledge Map
TopicsEntitiesSource
Building a …modeltrainingupdateproductplatformfeatureDEV Communi…

Connected Articles — Knowledge Graph

This article is connected to other articles through shared AI topics and tags.

Knowledge Graph100 articles · 210 connections
Scroll to zoom · drag to pan · click to open

Discussion

Sign in to join the discussion

No comments yet — be the first to share your thoughts!

More in Products