Kujenga mfumo wa uendeshaji (OS) kuanzia mwanzo kunaonekana kama kazi ya kernel hackers wanaotumia C. Lakini unaweza kuanzisha simulation rahisi kwa kutumia Python ndani ya mchana mmoja, na utagundua haraka kwamba mantiki ya usimamizi wa michakato (process management) ni ngumu sawa na katika lugha za hali ya juu. Nilijifunza hili kwa njia ngumu. Nilikaa chini kuandika simulator ndogo ya OS. Lengo lilikuwa dogo: kutengeneza michakato michache, kuipanga (schedule), na kuionyesha kuwa imemaliza kazi yake. Code ilikuwa fupi. Mantiki ilionekana kuwa imara. Kisha nikaendesha, na hakuna mchakato uliokuwa unakoma.

Kwa Nini Uunde OS Ndogo kwa Kutumia Python?

Mfumo halisi wa uendeshaji husawazisha memory paging, mifumo ya faili (file systems), hardware interrupts, na device drivers. Simulation huondoa hayo yote na kukuwezesha kuzingatia wazo kuu: hali (state). Unafafanua mchakato (process). Una PID, burst time, na hali ya mzunguko wa maisha (lifecycle status). Ready. Running. Finished. Mzunguko wa scheduler (scheduler loop) huchagua mshiriki anayefuata, huendeleza hali yake, hufanya simulation ya muda (time slice), na kuubadilisha kuwa finished.

Python ni chombo bora kwa aina hii ya jaribio kwa sababu inakuwezesha kupuuza pointer arithmetic na memory alignment. Orodha ya dictionary inakuwa process table yako. while loop inakuwa kernel scheduler yako. Unaweza kutekeleza round-robin scheduling au priority queues bila kitu zaidi ya zana za maktaba ya kawaida (standard library). Inaonekana rahisi, ndiyo maana kosa lililofuata lilikuwa la kuchanganya sana.

Maandalizi

Simulation yangu ilitumia orodha iliyoitwa process_table. Kila sehemu ilikuwa dictionary iliyokuwa na muundo huu:

{
    "pid": 1,
    "burst_time": 3,
    "status": "ready"
}

Scheduler ilitumia while loop rahisi. Iliskani jedwali kutafuta mchakato wa kwanza ambapo hali yake haikuwa "finished". Ilipoupata, ilitaa kazi ya function msaidizi, execute_tick(p), ili kuendesha mchakato huo kwa mzunguko mmoja wa simulation. Ndani ya execute_tick, niliweka hali ya mchakato kuwa "running", nikapunguza burst time, na nikakagua ikiwa kazi iliyobaki ilikuwa imefika sifuri. Ikiwa ilikuwa hivyo, nilihusisha hali kuwa "finished". Loop ya nje ilipaswa kusimama mara tu kila mchakato ulipofikia hali ya finished.

Kwenye karatasi, mtiririko ulikuwa safi. Tafuta mchakato aliye tayari. Mendeshe. Angalia kama amemaliza. Rudia hadi imalizike. Nilijumuisha hata maelezo ya print ili kuona scheduler ikifanya kazi yake. Niliona michakato ikichaguliwa. Loop iliendelea kufanya kazi. Hata hivyo, michakato ilionekana kuingia katika hali ya "sasa ya milele", ikiendelea kufanya kazi milele, bila kamwe kumaliza.

Dalili

Hii ndiyo aina mbaya zaidi ya kufeli: ile ya kimya kimya. Hakuna stack trace iliyojitokeza kwenye terminal. Hakuna IndexError au KeyError iliyonipa mwongozo wa kufuata. Interpreter ilikuwa na furaha kabisa. Programu tu haikufanya kazi kama ilivyotarajiwa. Michakato ilianza, lakini haikuwahi kumaliza. Nilitumia saa nyingi nikijaribu kufuata mtiririko huo.

Je, sharti la loop lilikuwa kosa? Labda nilikuwa na kosa la "off-by-one" katika hesabu ya burst time. Je, process table ilikuwa inanakiliwa badala ya kusasishwa mahali pale pale? Je, sharti langu la kumaliza lilikuwa linakagua funguo (key) isiyo sahihi? Nilijumuisha print nyingi zaidi. Nilikagua kila usemi wa boolean. Nilihoji kila kitu isipokuwa mstari mmoja uliokuwa na umuhimu mkubwa.

Mhusika

Kisha nikaiona. Ndani ya execute_tick, nilikuwa nimeandika:

p["status"] == "running"

Alama mbili za sawa. Ulinganishi, siyo upangaji (assignment). Suluhisho lilikuwa karibu sana:

p["status"] = "running"

Katika Python, p["status"] == "running" ni usemi unaofaa kabisa. Unatoa matokeo ya True au False, na kisha interpreter inatupa matokeo hayo kwa sababu sikuwahi kuyaweka kwenye kitu chochote. Mstari huo haufanyi kazi yoyote ya maana. Kichentry cha dictionary kilibaki bila kuguswa, kikihifadhi hali yoyote iliyokuwa nayo kabla, na mchakato haukuwahi kup

You compound this with confirmation bias. You know you typed an assignment because you intended an assignment. When you read the code for the fifth time, your brain autocorrects the symbol. This is why rubber ducking works. It forces you to articulate each line slowly enough that the gap between what is written and what you meant becomes visible.

Small bugs like this are harder to find than dramatic crashes. A segfault or a syntax error announces itself immediately. A silent no-op simply corrupts the state and lets the program limp forward. The failure is downstream, and your instinct is to debug the symptom rather than the cause.

A Better Defense

You cannot trust your eyes alone. After this episode, I changed a few habits that would have caught the mistake earlier.

First, if you are maintaining state in a dictionary, consider using a dataclass or an enum.Enum for process states. Define your statuses as constants or enum members:

from enum import Enum

class ProcessState(Enum):
    READY = "ready"
    RUNNING = "running"
    FINISHED = "finished"

With explicit types, tools like mypy can flag suspicious comparisons during static analysis. An accidental comparison where an assignment should live becomes much easier to spot when the types do not align with expectations.

Second, write unit tests for state transitions before you write the scheduler logic. A simple test that creates a process with one tick of work, runs the scheduler, and asserts the final state is FINISHED would have failed immediately. That failure would have narrowed the search to the state update logic rather than letting me wander through the entire loop