[{"data":1,"prerenderedAt":135},["ShallowReactive",2],{"list-\u002Fprojects-en":3},[4,80],{"entry":5,"writtenIn":78,"onlyIn":79},{"id":6,"title":7,"body":8,"date":60,"description":61,"extension":62,"meta":63,"navigation":64,"path":65,"role":66,"seo":67,"stack":68,"stem":72,"tags":73,"year":76,"__hash__":77},"content_en\u002Fprojects\u002Ftypescript-migration.md","TypeScript in a SAPUI5 codebase",{"type":9,"value":10,"toc":51},"minimark",[11,16,20,24,27,31,34,37,41,44,48],[12,13,15],"h2",{"id":14},"context","Context",[17,18,19],"p",{},"An internal SAPUI5 application used daily by a logistics team. Around forty controllers, six years of history, and three people maintaining it. Every screen had been written in plain JavaScript against the UI5 module system.",[12,21,23],{"id":22},"problem","Problem",[17,25,26],{},"The failures that reached production were almost never logic errors. They were shape errors: a field renamed on the OData service, a model path that no longer resolved, a controller reading a property the entity set had stopped returning. None of it was visible until someone opened the screen.",[12,28,30],{"id":29},"approach","Approach",[17,32,33],{},"Migration ran one folder at a time, with feature work continuing in parallel. Type definitions were generated from the service metadata rather than written by hand, so the OData contract stayed the single source of truth. Controllers were converted only when they were being touched for other reasons, which kept the diff of any one pull request reviewable.",[17,35,36],{},"The build stayed on the existing UI5 tooling. Introducing a second bundler would have meant maintaining two build paths for the length of the migration.",[12,38,40],{"id":39},"result","Result",[17,42,43],{},"Not measured against a baseline — no error tracking existed before the migration, so any before-and-after number would be invented. What is observable: renames on the service now fail the build instead of a screen, and the three shape errors found during conversion had all been live in production.",[12,45,47],{"id":46},"lesson","Lesson",[17,49,50],{},"Generating types from the service metadata mattered more than the migration itself. Hand-written interfaces would have drifted from the backend within a release, and a type that lies is worse than no type at all.",{"title":52,"searchDepth":53,"depth":53,"links":54},"",2,[55,56,57,58,59],{"id":14,"depth":53,"text":15},{"id":22,"depth":53,"text":23},{"id":29,"depth":53,"text":30},{"id":39,"depth":53,"text":40},{"id":46,"depth":53,"text":47},"2026-05-12","A gradual migration of a large SAPUI5 application to TypeScript, done without a freeze on feature work.","md",{},true,"\u002Fprojects\u002Ftypescript-migration","Frontend engineer",{"title":7,"description":61},[69,70,71],"SAPUI5","TYPESCRIPT","NODE","projects\u002Ftypescript-migration",[74,75],"sapui5","typescript","2025 — 2026","UhbRaPUUHMvT8a2xIGcTX6VotUAmMwlEO2RWADt4Zi0","en",null,{"entry":81,"writtenIn":78,"onlyIn":79},{"id":82,"title":83,"body":84,"date":121,"description":122,"extension":62,"meta":123,"navigation":64,"path":124,"role":125,"seo":126,"stack":127,"stem":129,"tags":130,"year":133,"__hash__":134},"content_en\u002Fprojects\u002Fwarehouse-console.md","Warehouse console",{"type":9,"value":85,"toc":114},[86,88,91,93,96,98,101,104,106,109,111],[12,87,15],{"id":14},[17,89,90],{},"Warehouse operators handling inbound goods. The work is repetitive by design: scan, check, confirm, move on. Each pass previously touched four separate screens, and the same identifier had to be typed into three of them.",[12,92,23],{"id":22},[17,94,95],{},"The interface had been designed as if each screen were a destination. In practice nobody navigates a tool they use all day — they memorise positions and stop reading labels after the first week. Four destinations meant four sets of positions to hold in memory, and the retyping was where mistakes entered.",[12,97,30],{"id":29},[17,99,100],{},"The four screens collapsed into one console with a fixed layout: scan field always in the same place, current item in the centre, history to the side. Nothing moves between states, because a control that changes position is a control that has to be found again.",[17,102,103],{},"Keyboard first. Every action reachable without the mouse, since operators wear gloves and use a handheld scanner that emits keystrokes.",[12,105,40],{"id":39},[17,107,108],{},"Not measured formally — the team had no timing data before the change, and the number of passes per shift varies too much with inbound volume to compare months. What the operators reported: the retyping is gone, and training a new person now covers one screen instead of four.",[12,110,47],{"id":46},[17,112,113],{},"The gain came from removing navigation, not from redesigning any individual screen. Had the work started as a visual refresh of the four screens, the retyping would have survived it.",{"title":52,"searchDepth":53,"depth":53,"links":115},[116,117,118,119,120],{"id":14,"depth":53,"text":15},{"id":22,"depth":53,"text":23},{"id":29,"depth":53,"text":30},{"id":39,"depth":53,"text":40},{"id":46,"depth":53,"text":47},"2026-02-03","A single screen replacing four, built for operators who work the same interface for eight hours a day.",{},"\u002Fprojects\u002Fwarehouse-console","Design and frontend",{"title":83,"description":122},[69,70,128],"DOCKER","projects\u002Fwarehouse-console",[74,131,132],"enterprise","ux","2024 — 2025","qvFcUqp8ChHhuzfRpCzZVAh0My8ZjgJqek6ky665dY0",1788956392049]