Wpis
Spec Driven Development w praktyce: jak zbudowalem pakowarke szkolen SCORM (MP4 -> SCORM 2004)
Opis, jak zbudowalem minimalna paczke SCORM 2004 z MP4, stosujac Spec Driven Development: wymagania, specyfikacje i plan testow.
Stefan Tyllo
13 lutego 2026

Spec Driven Development w praktyce: jak zbudowalem pakowarke szkolen SCORM (MP4 -> SCORM 2004)
Kiedy ktos mowi "zrobmy paczke SCORM", latwo wpasc w pulapke myslenia, ze to po prostu ZIP z index.html. Dopoki nie trafisz na pierwszy LMS, ktory jest bardziej "interpretacja standardu" niz standardem. Wtedy okazuje sie, ze najdrozsze nie jest napisanie kilku plikow HTML/JS, tylko dowiezienie przewidywalnego zachowania: manifest musi byc poprawny, runtime musi gadac z API, a completion i scoring musza sie zapisac dokladnie tak, jak oczekuje platforma.
Dlatego ten projekt zrobilem swiadomie w podejsciu Spec Driven Development (SDD): najpierw spisalem wymagania, potem specyfikacje zachowania, potem plan testow, a dopiero na koncu zaczalem implementacje. Efekt? Zamiast "dziala u mnie", dostalem paczke, ktora ma jasny kontrakt, jest testowalna i latwa do utrzymania.
Co wlasciwie budowalem
Celem byla minimalna, "developer-controlled" paczka SCORM 2004 3rd Edition, ktora:
- uruchamia pojedyncza strone
index.html, - odtwarza jedno lub wiecej MP4 z katalogu
videos/, - zawiera test (10 pytan, 4 odpowiedzi, 1 poprawna) i prog zaliczenia 80%,
- raportuje ukonczenie i wynik do LMS przez SCORM 2004 API (
window.API_1484_11), - a po zaliczeniu wyswietla ekran ukonczenia i pozwala pobrac certyfikat jako PDF generowany po stronie przegladarki (tekst nakladany na PNG).
W wersji "manual" paczke skladam z gotowych statycznych plikow, a w wersji opcjonalnej mam generator w Next.js, ktory przyjmuje upload MP4 i metadane, sklada katalog zrodlowy i pakuje calosc.
Dlaczego SDD akurat tutaj zadzialalo
SCORM to specyficzna liga. Problemy zwykle nie wynikaja z braku funkcji, tylko z roznic interpretacyjnych miedzy LMS-ami oraz z "niewidzialnych" wymagan runtime: kolejnosc wywolan, wartosci statusow, commit w odpowiednim momencie, zachowanie na beforeunload.
W takim swiecie SDD jest jak pas bezpieczenstwa:
- Wymagania zamieniaja mgliste "ma dzialac w LMS" na liste zachowan, ktore da sie zweryfikowac.
- Specyfikacja zamienia wymagania w konkret: jakie pliki, jakie sciezki, jaki runtime flow.
- Plan testow daje mi procedure odbioru (SCORM Cloud / LMS), bez zgadywania.
To podejscie nie tylko redukuje ryzyko - ono przyspiesza, bo konczy dyskusje typu "czy to juz jest ukonczone?" albo "a czemu LMS nie widzi wyniku?".
Krok 1: wymagania jako kontrakt, nie lista zyczen
Zaczalem od spisania rzeczy, ktore maja byc prawda o produkcie. Bardzo konkretnie: standard (SCORM 2004 3rd Edition), struktura ZIP (manifest w root), launch file (index.html), MP4 w videos/, quiz 10 pytan i prog 80%, commit na ukonczenie i na unload oraz fallback, gdy API nie istnieje.
Dwa wymagania okazaly sie szczegolnie "game-changing":
-
"Jesli API SCORM nie istnieje, wideo nadal ma dzialac bez bledow."
To brzmi jak detal, ale w praktyce wymusza defensywna architekture runtime i eliminuje klase awarii typu "ktos odpalil paczke lokalnie i wszystko sie wywalilo". -
"Ekran ukonczenia i certyfikat tylko po zaliczeniu."
Dzieki temu nie ma rozjazdu miedzy UI a tym, co raportuje do LMS. Jesli uzytkownik widzi "ukonczone", LMS tez dostajepassed/completed.
Wymagania ustawily granice: pojedyncze SCO, MP4-only, bez frameworkow w runtime (kompatybilnosc), a jesli mam serwery pomocnicze - porty 4000-4999.
Krok 2: specyfikacja - czyli jak to ma dzialac w srodku
W specyfikacji zalezalo mi na prostocie: SCO ma byc mozliwie statyczne i przewidywalne.
Minimalna paczka runtime
Docelowa struktura byla krotka i "oczywista":
index.htmljako launch,scripts/scorm-again.min.jsiscripts/player.js(w tej kolejnosci),videos/*.mp4,- oraz zasoby certyfikatu:
assets/certificate.png,assets/certificate.json(uklad placeholderow), fontassets/JaneAust.ttf.
To jest celowo "oldschoolowe": plain HTML + vanilla JS + natywny <video>. Bez routerow, bez bundli, bez zaleznosci runtime, ktore czasem robia LMS-om krzywde.
Kontrakt zachowania SCORM
Najwazniejszy fragment specyfikacji dotyczyl flow SCORM 2004:
- Na
window.load: sprobowac znalezc API (window.API_1484_11) i wykonacInitialize(""). - Od razu ustawic minimum:
cmi.completion_status="incomplete",cmi.exit="", potemCommit(""). - Po ukonczeniu (test albo trigger zakonczenia wideo): ustawic scoring (
raw/min/max/scaled) +completion_status="completed"+success_status="passed|failed", potemCommit("")iTerminate(""). - Na
beforeunload: wykonacCommit/Terminateraz (guard idempotentny), jesli sesja byla zainicjalizowana.
Brzmi prosto, ale to wlasnie ten "prostokat" wywolan jest sednem kompatybilnosci. I to byl jeden z najwiekszych zyskow z SDD: zanim napisalem linijke kodu, wiedzialem w jakich momentach i co dokladnie ma byc zapisane.
Krok 3: plan testow - moj "SCORM checklist", ktory konczy spory
Trzeci dokument to test plan. I szczerze: w projektach SCORM to czesto najwazniejsza czesc calej pracy.
Plan testow rozpisalem tak, zeby przejsc od rzeczy najbardziej podstawowych do najbardziej zdradliwych:
- czy katalog zrodlowy ma wszystkie pliki (
index.html,player.js,scorm-again,videos/*.mp4), - czy ZIP ma
imsmanifest.xmlw root i czy manifest wskazujeindex.html, - czy kurs startuje w LMS bez bledow w konsoli,
- czy quiz ma 10 pytan, pokazuje prog 80% i liczy wynik,
- czy na starcie jest
Initialize+incomplete+Commit, - czy po ukonczeniu sa ustawione score + statusy +
CommitiTerminate, - czy po niezaliczeniu nie pojawia sie ekran ukonczenia,
- czy
beforeunloadrobi commit (bez dubli), - czy bez API (otwarcie lokalne) kurs dziala bez exceptionow.
To jest dokladnie ten moment, w ktorym SDD przestaje byc "ladna teoria" i staje sie narzedziem: kiedy LMS robi cos dziwnego, ja nie zgaduje - ja odpalam checkliste.
Implementacja: wypelnianie specyfikacji, a nie odkrywanie jej po drodze
Kiedy trzy artefakty byly gotowe, implementacja byla zaskakujaco spokojna. Nie budowalem "na czuja", tylko realizowalem konkretne zachowania.
Runtime "defensywny": dziala w LMS i dziala poza LMS
Najbardziej praktyczna decyzja to potraktowanie SCORM API jako opcjonalnego. W runtime to wyglada jak prosta zasada:
jezeli API jest - raportuj; jezeli nie ma - nie psuj doswiadczenia.
To bylo wymaganie wprost, wiec w kodzie wszystko, co SCORM-owe, jest opakowane tak, zeby brak API nie konczyl sie bledem.
Quiz i scoring: 80% jako jedno zrodlo prawdy
Quiz jest celowo "sztywny" (10 pytan, 4 opcje, 1 poprawna), a prog 80% jest pokazany przed startem. Po zakonczeniu wyswietlam wynik i pass/fail, a dopiero potem raportuje do LMS.
Dzieki temu UI i LMS maja spojna logike. Nie ma sytuacji, ze uzytkownik widzi "zaliczone", a LMS zapisuje "failed".
Certyfikat: maly feature, duza walidacja paczki
Certyfikat jest generowany client-side: tekst trafia na PNG zgodnie z ukladem placeholderow (JSON), a potem eksportuje to jako PDF do pobrania. To jest fajny element produktu, ale tez sprytna walidacja techniczna: jesli certyfikat dziala, to znaczy, ze assety sa poprawnie spakowane, sciezki sa poprawne, a runtime nie jest przesadnie "ciezki".
Pakowanie: manifest jako "miejsce, gdzie wszystko sie psuje" (wiec automatyzuje)
W SCORM najlatwiej przegrac na imsmanifest.xml: zla lokalizacja, zle namespacey, brak <file> dla assetu, niepoprawny href launch file. Dlatego w specyfikacji zalozylem, ze manifest jest auto-generowany przez simple-scorm-packager na podstawie katalogu zrodlowego.
W wariancie Next.js generator robi dokladnie to: sklada /tmp/scorm-source, wrzuca index.html, skrypty i MP4, a potem wywoluje packagera z wersja "2004 3rd Edition" i startingPage: "index.html", po czym streamuje ZIP do pobrania.
To podejscie jest pragmatyczne: nie chce recznie walczyc z XML-em, skoro moge testowac wynikowa paczke jako artefakt.
Co dalo mi SDD w tym projekcie (tak realnie)
Najwieksza korzysc nie byla "ladna dokumentacja". Najwieksza korzysc byla taka, ze:
- z gory wiedzialem, co znaczy "done" (a nie negocjowalem tego po implementacji),
- mialem testy, ktore tlumacza LMS-owi, co ma sie wydarzyc,
- i moglem iterowac bez strachu, bo jesli cos zepsuje, test plan od razu pokaze, gdzie.
W SCORM to jest bezcenne, bo regresje czesto sa subtelne: jedna zmiana w runtime i nagle LMS przestaje zapisywac wynik - ale tylko w konkretnym flow.
Co zrobilbym jeszcze lepiej nastepnym razem
Dwie rzeczy, ktore widze jako naturalny upgrade:
-
Jeszcze mocniej "produktowo" potraktowac trigger ukonczenia (koniec wideo vs koniec testu vs reczny przycisk) i zaprojektowac to jako swiadoma konfiguracje, bo to czesto zmienia sie na etapie wdrozenia. Specyfikacja juz dopuszcza konfiguracje triggera, ale warto to uczynic pierwszoplanowym elementem UI generatora.
-
Dodac automatyczna walidacje "manifest <-> pliki" jako krok CI: rozpakuj ZIP, przeczytaj
imsmanifest.xml, porownaj liste<file>z realnymi plikami. Test plan to opisuje, ale automatyzacja domknelaby temat w pelni.
Podsumowanie
Ten projekt byl dla mnie dobrym przypomnieniem, ze w SCORM sukces nie polega na tym, ze "strona sie otwiera". Sukces polega na tym, ze paczka ma przewidywalne zachowanie w LMS:
- startuje,
- raportuje,
- nie sypie sie na unload,
- i nie umiera, kiedy API nie jest dostepne.
Spec Driven Development bylo tu idealnym podejsciem: najpierw kontrakt (wymagania), potem mechanika (spec), potem dowod (test plan). Dopiero na koncu kod. I dokladnie tak powinno sie budowac rzeczy, ktore musza dzialac w cudzym ekosystemie.
Komentarze
0