How Do I Design a Technical Calculation Engine?

Author: Sercan Fidan · Published: 7 Ağustos 2026 · Updated: 2026-09-01 · Mühendislik Araçları

In an engineering team, calculation knowledge rarely lives in a single place. Some of it sits inside design reports, some in a spreadsheet prepared years ago, and some only in the mind of the person who knows the work best. In the projects I've worked on, I've seen the same calculation produce three different results across three different files; the formula was identical, but the unit conversion, rounding step, and default values differed. In this post I'll describe the approach I use to bring this scattered knowledge together: moving calculations into an independent, testable calculation engine.

Why isn't a spreadsheet enough?

A spreadsheet is excellent for a quick start; it's a poor host for a long-lived calculation infrastructure. The formula is embedded in the cell; which cell is an input and which is an intermediate value often lives only in the mind of whoever wrote the file. Units are nothing more than a note in the header row; you find out whether a value is in meters or millimeters from a factor of 1000 buried inside the formula. The most critical problem, though, is untestability: when you change a cell, there's no reliable mechanism showing which other results are affected.

Defining a calculation like a contract

The core idea of the engine is this: every calculation is a written contract. Five things are explicitly defined in this contract: the inputs, each input's unit, the validity limits, the intermediate values, and the results. An input definition isn't just a name; it's a complete statement like "L, in meters, between 0.01 and 50." A value outside the limits does not enter the calculation silently; the engine rejects it with an explicit error. I also make the intermediate values part of the contract, because the only way to defend a result is to be able to show the steps that led to it. In practice, I express this contract with a dataclass, and the calculation itself as a pure function: one that holds no state, never touches a file or a screen, and always returns the same result for the same input. These two properties make testing almost free and make the calculation completely independent of whatever application calls it.

I preserve this independence in the architecture as well: the engine must be unaware that a UI even exists. A desktop interface written with PyQt6, a command-line tool, and a test script should all be able to call the same engine. The UI layer collects input and displays the result; the data layer stores the calculation definitions and past results — SQLite is more than sufficient for this most of the time — and the engine only performs the calculation. The practical payoff of this separation is substantial: you can test the engine against hundreds of scenarios in seconds, without ever opening the UI.

Verification against reference values

The most honest way to claim that a calculation works correctly is to compare its result against an independent reference. For every calculation, I take at least one input-result pair from a textbook, a hand-solved example, or a previously verified table, and turn it into a unit test. I compare using relative tolerance rather than absolute, because the order of magnitude varies a great deal from one calculation to another. As the engine grows, these tests become a safety net: when I refactor a formula, I can relax once the reference cases still pass.

A calculation I cannot test is not yet a calculation for me; it's just a claim.

hesap_motoru.py
from dataclasses import dataclass

@dataclass(frozen=True)
class Girdi:
    ad: str; birim: str; alt: float; ust: float  # isim, birim, geçerlilik sınırları

# Serbest uca tekil yük F etkiyen ankastre kirişte uç sehimi: delta = F*L**3 / (3*E*I)
GIRDILER = (
    Girdi("F", "N", 0.0, 1e6),
    Girdi("L", "m", 0.01, 50.0),
    Girdi("E", "Pa", 1e9, 5e11),
    Girdi("I", "m^4", 1e-12, 1.0),
)

def dogrula(**degerler: float) -> None:
    for g in GIRDILER:  # sınır dışı girdi sessizce hesaba girmez
        d = degerler[g.ad]
        if not (g.alt <= d <= g.ust):
            raise ValueError(f"{g.ad}={d} {g.birim}: [{g.alt}, {g.ust}] aralığının dışında")

def uc_sehimi(F: float, L: float, E: float, I: float) -> float:
    dogrula(F=F, L=L, E=E, I=I)
    return F * L ** 3 / (3.0 * E * I)  # saf fonksiyon: durum tutmaz, ekrana dokunmaz

The best part of this approach is that it scales. Moving the first calculation into the engine takes some time; the second becomes a matter of filling in a template, and the tenth turns into routine. After a while, what you have isn't just a tool but a library that holds the team's calculation knowledge in one place, together with its units and limits. The scattered formulas in the documents can stay where they are; but the engine is now the single source of truth.

{{ T.nav.icerigeAtla }}
sercan ◆
© 2026

{{ T.palet.sonucYok }}

{{ T.palet.baskaAra }}

{{ it.label }}

{{ it.label }} {{ it.hint }}
↑↓ {{ T.palet.gezin }} ↵ {{ T.palet.sec }} esc {{ T.palet.kapat }}

{{ T.hero.kicker }}

{{ T.hero.baslikOn }}{{ T.hero.baslikVurgu }}{{ T.hero.baslikSon }}

{{ T.hero.altyazi }}

{{ T.home.tanitim1 }}

{{ T.home.tanitim2 }}

{{ T.home.oneCikanlar }}

{{ buyuk.tarih }} · {{ buyuk.dkOkuma }}

{{ buyuk.baslik }}

{{ buyuk.ozet }}

{{ T.kart.yaziyiOku }}
{{ p.katAd }}

{{ p.baslik }}

{{ p.ozet }}

{{ p.tarih }} · {{ p.dkText }}

{{ T.home.seciliProjeler }}

{{ pr.gorselAlt }}
{{ pr.durumGorunen }} {{ pr.yil }}

{{ pr.ad }}

{{ pr.ozet }}

{{ pr.tekno }}

{{ T.home.simdiBaslik }}

{{ T.home.guncelleme }}{{ simdiGuncel }}

{{ k.etiket }}

  • {{ m }}

{{ simdiNot }}

{{ T.home.bultenEtiket }}

{{ T.home.bultenBaslik }}

{{ T.home.bultenAciklama }}

{{ T.home.bultenGecerliOn }}sercanfidan06@gmail.com

{{ T.home.bultenBasarili }}

{{ T.home.bultenBasariAciklama }}

{{ T.blog.etiket }}

{{ T.blog.baslik }}

{{ T.blog.aciklama }}

{{ T.blog.etiketEtiket }} {{ tagChip }}

{{ sonucText }}

{{ p.katAd }}

{{ p.baslik }}

{{ p.ozet }}

{{ p.tarih }} · {{ p.dkText }}

{{ T.blog.sonucYokEtiket }}

{{ T.blog.sonucYokBaslik }}

{{ T.blog.sonucYokAciklama }}

{{ yukleMetni }}

{{ pp.katAd }} {{ T.yazi.yazarEtiket }}: {{ pp.yazar }} · {{ pp.tarih }} · {{ pp.dkOkuma }}

{{ pp.baslik }}

{{ pp.lede }}

{{ pp.gorselAlt }}

{{ b.x }}

{{ b.x }}

{{ b.x }}

{{ b.dosya }}
{{ b.dil }}
{{ b.kod }}
  • {{ m }}
{{ b.alt }}
{{ b.altyazi }}

{{ T.yazi.paylasEtiket }}

{{ T.yazi.yorumlarEtiket }} ({{ yorumN }})

{{ T.yazi.yukleniyor }}

{{ T.yazi.yorumHata }}

{{ T.yazi.yorumYok }}

  • {{ y.ad }} {{ y.tarih }}

    {{ y.govde }}

{{ T.yazi.yorumBasarili }}

{{ yAdHata }}

{{ yEmailHata }}

{{ yMetinHata }}

{{ yKvkkHata }}

{{ T.yazi.ilgiliYazilar }}

{{ p.katAd }}

{{ p.baslik }}

{{ p.tarih }} · {{ p.dkText }}

{{ yukleMetni }}

{{ prp.durumGorunen }} {{ prp.yil }}

{{ prp.ad }}

{{ prp.ozet }}

{{ prp.gorselAlt }}

{{ T.proje.calismaKapsami }}

  • {{ d }}
{{ tk.t }}

{{ T.yazi.paylasEtiket }}

{{ T.yazi.yorumlarEtiket }} ({{ yorumN }})

{{ T.yazi.yukleniyor }}

{{ T.yazi.yorumHata }}

{{ T.yazi.yorumYok }}

  • {{ y.ad }} {{ y.tarih }}

    {{ y.govde }}

{{ T.yazi.yorumBasarili }}

{{ yAdHata }}

{{ yEmailHata }}

{{ yMetinHata }}

{{ yKvkkHata }}

{{ T.projeListe.etiket }}

{{ T.projeListe.baslik }}

{{ T.projeListe.aciklama }}

{{ pr.gorselAlt }}
{{ pr.durumGorunen }} {{ pr.yil }}

{{ pr.ozet }}

{{ pr.tekno }}

  • {{ d }}

{{ T.kaynak.etiket }}

{{ T.kaynak.baslik }}

{{ T.kaynak.aciklama }}

{{ T.kaynak.favoriAraclarim }}

{{ g.grup }}

{{ g.aciklama }}

{{ T.kaynak.oneriVarMi }}{{ T.kaynak.iyiKaynak }}

{{ T.hakkimda.etiket }}

Hi, I'm Sercan.

{{ pa }}

{{ dg }}

{{ T.hakkimda.nasilCalisirim }}

{{ c.baslik }}

{{ c.not }}

{{ T.hakkimda.zamanCizelgesi }}

{{ z.yil }}

{{ z.baslik }}

{{ z.not }}

Sercan Fidan — portrait

{{ T.hakkimda.uzmanlik }}

{{ u.alan }} {{ u.seviye }}

{{ T.hakkimda.etiketCumlesi }}

{{ T.hakkimda.iletisimEtiket }}

{{ T.hakkimda.iletisimBaslik }}

{{ T.hakkimda.iletisimAciklama }}

{{ adHata }}

{{ emailHata }}

{{ mesajHata }}

{{ kvkkHata }}

{{ T.iletisim.ulastiBaslik }}

{{ T.iletisim.ulastiAciklama }}

{{ T.kayip.etiket }}

{{ T.kayip.baslik }}

{{ T.kayip.aciklama }}