diff --git a/blog/assets/make-diagrams.py b/blog/assets/make-diagrams.py index fd48e368..559716f4 100644 --- a/blog/assets/make-diagrams.py +++ b/blog/assets/make-diagrams.py @@ -2,7 +2,10 @@ """The diagrams for the abap2UI5 Know-How series. Run from the repository root: python3 blog/assets/make-diagrams.py -Writes blog/assets/diagrams/*.svg, one per article that needs one. +Writes docs/public/insights/*.svg, one per article that needs one - the pages +reference them absolutely (/insights/...), because generate-llms.mjs copies +every page into docs/public/ as raw markdown and a relative asset path does not +resolve from that copy. WHY SVG AND NOT PNG. These are boxes, arrows and words - the one thing a raster format is worst at. An SVG stays sharp at any width, diffs as text when @@ -20,7 +23,8 @@ """ import os -OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'diagrams') +ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +OUT = os.path.join(ROOT, 'docs', 'public', 'insights') R, R2, RL = '#D03C4A', '#A83232', '#F6E3E5' CREAM, SAND, WHITE = '#FAF2EC', '#F0DFD2', '#FFFFFF' INK, MUTED, LINE = '#3A2A2E', '#9C8A8E', '#D8C7BC' diff --git a/blog/teaser-posts.md b/blog/teaser-posts.md new file mode 100644 index 00000000..48e8bdab --- /dev/null +++ b/blog/teaser-posts.md @@ -0,0 +1,554 @@ +# LinkedIn teaser posts + +The posts that introduce each article. Plain text — LinkedIn renders no +markdown. Kept here rather than on the published pages: they are publishing +material, not documentation. + +## Somewhere on the Way to UI5, We Lost RTTS + +Plain text — LinkedIn renders no markdown. The article link comes from the +attached article preview, so the post carries no inline URL. 744 characters. + +> In the past, screens were routinely built for tables nobody had seen. +> cl_salv_table=>factory( ) took any internal table and drew it — RTTS read the +> structure at runtime, the DDIC supplied the labels, and a whole category of +> ABAP tooling was built that way. +> +> With Fiori Elements, RAP or freestyle UI5, that path goes through a typed +> OData service: the entity type has to exist first, at design time. Exactly +> right when the client does not know your backend — but a dead end for those +> tools. +> +> New article 🎉 abap2UI5 can give a runtime-typed model a UI5 face, and be a +> perfect complement to the UI5 and RAP solutions you already run. +> +> Where do you still use RTTS in UIs today? And how do you get around the +> design-time bottleneck? +> +> #ABAP #SAP #UI5 + +## abap2UI5 is not a Programming Model + +Plain text — LinkedIn renders no markdown. + +> The useful question about a UI framework is not what it can do. It is what it +> wants from you: a structure to follow, a lifecycle to fit into, layers to fill +> in. +> +> abap2UI5 fits its answer on a page — one interface, one method. No data model, +> no service, no binding, no annotations, no BSP per app, no frontend artefact +> to transport. +> +> Which is why it composes instead of competing. The new article shows one app +> and three save handlers: EML against a business object, MODIFY against a +> table, and a BAPI call. The framework never learns which — it could just as +> well be the EWM classes, or whatever SAP releases next. +> +> New article 🎉 +> +> What does your UI framework ask of your architecture? +> +> #ABAP #SAP #UI5 + +## The Cost of a Screen + +Plain text — LinkedIn renders no markdown. + +> A maintenance view for a customising table. A cockpit showing what last +> night's job did. An approval step for one department. +> +> The logic behind each is about thirty lines. The cost of putting a UI in front +> of thirty lines is not thirty lines, and it does not scale down: a data model, +> a service, a binding, a frontend artefact, a deployment — and an object that +> has to be transported, survive upgrades, and one day be deprecated by someone +> who never met the department that asked for it. +> +> So the screen never gets built. Every system has a Z package full of the ones +> that became a selection screen and an ALV grid instead. +> +> New article 🎉 with a job monitor as a complete abap2UI5 app — and an honest +> note on where this is the wrong trade. +> +> Which screen in your system stayed an ALV grid because a proper UI was never +> worth the effort? +> +> #ABAP #SAP #UI5 + +## No Annotation in Between + +Plain text — LinkedIn renders no markdown. + +> A metadata-driven screen is described, not written — and the description has a +> vocabulary. What the vocabulary covers arrives in an afternoon. What it does +> not becomes an extension point. +> +> abap2UI5 has no vocabulary of its own to run out of. It sends a UI5 XML view, +> so the vocabulary is the UI5 control library itself, all of it, at whatever +> version the launchpad already serves. The new article builds a three-step +> sap.m.Wizard in one ABAP class to show what that means in practice. +> +> The price is on the same page: nothing writes the layout for you. +> +> New article 🎉 +> +> Which control did you last want, and not have a way to ask for? +> +> #ABAP #SAP #UI5 + +## UI5 Over-the-Wire + +Plain text — LinkedIn renders no markdown. + +> UI5 does not render from objects you assemble by hand. It renders from an XML +> view, bound to its data. The view is a document — and documents can travel. +> +> So what if the backend sent the view too? That is the whole of abap2UI5: every +> request is answered with two strings, a UI5 XML view and a UI5 JSON model. +> Neither is a protocol the framework invented, and the frontend does what it +> always did. +> +> What changes is who owns the view. Not an artefact deployed beside the app — +> a string an ABAP class produced for this request. +> +> New article 🎉 +> +> Where would you draw the line between a frontend and a renderer? +> +> #ABAP #SAP #UI5 + +## The Frontend That Does Not Know What It Shows + +Plain text — LinkedIn renders no markdown. + +> The UI5 app that abap2UI5 sends to the browser does not contain the screen. +> Not the fields, not the table, not the buttons. It is a shell: enough UI5 to +> render a view and a model that arrive from the server, and to send events +> back. +> +> It cannot tell whether it is showing a table or a wizard, and it does not know +> which action follows the next click. PBO builds, PAI decides — the dialog step +> just became an AJAX call. +> +> Which means there is one shell, shared by every app in the system. Not one +> deployed frontend per app, each pinned to whichever UI5 version someone last +> had time for. +> +> New article 🎉 +> +> How many separately deployed frontends does your system carry right now? +> +> #ABAP #SAP #UI5 + +## One Service for Every App + +Plain text — LinkedIn renders no markdown. + +> Count what one screen usually costs in backend artefacts: a CDS view or two, a +> service definition, a service binding, a behavior definition and its +> implementation — each named, transported, reviewed, and each belonging to +> exactly one app. +> +> An abap2UI5 app adds none of them. Every app is served by the same generic +> handler, which does not know the app, the view or the model — it moves two +> strings. Set a breakpoint and look at the call stack: one frame. +> +> It can be generic because nothing about the data is agreed in advance. The +> model travels with every response, so every response may carry a different one. +> +> New article 🎉 +> +> How many of the objects in your last transport existed only to get one screen +> onto a display? +> +> #ABAP #SAP #UI5 + +## Only the Changed Part + +Plain text — LinkedIn renders no markdown. + +> If the backend sends the view on every request, does the screen rebuild itself +> on every click? +> +> It would — and the user would feel it. A rebuilt view is a new set of +> controls: focus lost, half-typed input gone, table scrolled back to the top. +> +> So the view is not sent every time. It is one IF in the app. When it is +> skipped, the response carries only the model, and UI5 data binding updates +> exactly the controls bound to what changed. No diffing, no virtual DOM, no +> reconciler — a mechanism UI5 has had all along. +> +> New article 🎉 +> +> Where has a full re-render cost you a user's input? +> +> #ABAP #SAP #UI5 + +## PUBLIC Means Persisted + +Plain text — LinkedIn renders no markdown. + +> Every abap2UI5 request lands on a fresh instance of the app class. No session +> holds the previous one, and the next request may not even reach the same app +> server. +> +> So how does what the user typed three clicks ago still exist? The app class is +> serializable, and after each request the framework serializes it into a draft +> table. What survives is exactly the PUBLIC SECTION. +> +> Which makes one keyword a performance decision. A catalogue parked in a public +> attribute is not cached — it is written to the database and shipped to the +> browser after every click. State public, working data protected. +> +> New article 🎉 +> +> Where in your code does a keyword quietly decide what travels? +> +> #ABAP #SAP #UI5 + +## Swapping the View at Runtime + +Plain text — LinkedIn renders no markdown. + +> In abap2UI5 the view is a string the app produced for this request. So what +> stops the next request from producing a different one? +> +> Nothing does. One IF in the app class, and the table is a list — not a table +> with hidden columns, not a second app behind a navigation step. A different +> control, chosen in ABAP. +> +> A screen assembled at design time varies only where somebody anticipated +> variation and left a switch. A screen assembled per request varies wherever +> the code branches. +> +> New article 🎉 +> +> Which screen in your system would you rebuild differently per user, if it cost +> you an IF? +> +> #ABAP #SAP #UI5 + +## index.html Lives in a String + +Plain text — LinkedIn renders no markdown. + +> Somebody has to deliver the first HTML page. In the SAP world that normally +> means a BSP: a frontend artefact, built somewhere, deployed, transported on +> its own path, invalidated from its own caches. +> +> abap2UI5 does not have one. The initial GET is answered from ABAP source — +> the page is a string in the handler. +> +> So the project is nothing but ABAP: abapGit and activate, no npm install, no +> bundler, no dist folder. No build output to go stale, so no cache to +> invalidate. And no dependency tree that somebody has to audit, pin and answer +> for. +> +> New article 🎉 +> +> How much of your last frontend incident was the pipeline rather than the code? +> +> #ABAP #SAP #UI5 + +## Where Your Own JavaScript Goes + +Plain text — LinkedIn renders no markdown. + +> Sooner or later an app needs what an XML view cannot express: a chart library, +> an unwrapped control, or a UI5 method that exists only as a method — +> sap.m.Carousel moves through setActivePage( ) and nothing else. +> +> abap2UI5 has no plugin system for that, on purpose. It has three declared +> seams: an imperative method reached by control id from ABAP, a custom control +> living in its own BSP behind a reserved resource root, and extra JavaScript +> for the initial page set once through the framework exit. +> +> None lets an app change the framework. None makes the framework change for an +> app. +> +> New article 🎉 +> +> When you last needed a custom control, what did it cost to get it in? +> +> #ABAP #SAP #UI5 + +## Four Verbs + +Plain text — LinkedIn renders no markdown. + +> The first view builder in abap2UI5 had one method per UI5 control — hundreds +> of them, properties as named parameters. Good reason: ADT code completion +> listed them, so the frontend API was imported into backend tooling. +> +> Hard edge: a control the class had no method for could not be written at all. +> Every new UI5 control was a pull request. +> +> Its successor has four verbs — ele, tag, a, end. None of them names a control, +> which is exactly why every control is reachable. The completion list is gone; +> the compiler and the linter still check the chain. +> +> New article 🎉 +> +> Wrapper or raw API — which side do you land on, and why? +> +> #ABAP #SAP #UI5 + +## The Class That Runs + +Plain text — LinkedIn renders no markdown. + +> The smallest ABAP program that does something is a class with +> if_oo_adt_classrun: one interface, one method, F9. No transaction, no program, +> nothing beside it. +> +> abap2UI5 copied that silhouette exactly. Same shape, different destination — +> it renders in a browser, follows the Fiori guidelines, and goes to a colleague +> as a URL instead of "open ADT and press F9". +> +> Which leaves a property that has quietly become valuable: the whole app is one +> file. Anything that has to reason about it — a reviewer, a successor, a search, +> an agent — can hold all of it at once. +> +> New article 🎉 +> +> What is the smallest complete app in your system, measured in files? +> +> #ABAP #SAP #UI5 + +## Where the Selection Screen Went + +Plain text — LinkedIn renders no markdown. + +> Before anyone called it full-stack, ABAP had PARAMETERS. Four lines and every +> layer is there: a typed, labelled input with a default and value help, plus +> validation and event handling. Nobody wrote a frontend, because declaring the +> variable was writing the frontend. +> +> That trade is what disappeared on the way to the browser: the variable and the +> field became two artefacts in two places, kept in step by a service in between. +> +> _bind puts them back together. The attribute is not a field name in a string — +> it is the ABAP variable. +> +> New article 🎉 +> +> How many places does one input field touch in your current stack? +> +> #ABAP #SAP #UI5 + +## No Cache, No Deploy, Any IDE + +Plain text — LinkedIn renders no markdown. + +> The abap2UI5 loop is: change the class, activate, refresh the browser. +> +> What is missing from that sentence is the point. No deployment — activating is +> the deployment. No cache to invalidate — the UI is built per request, so +> nothing can be stale. No IDE agreement, because it is ABAP. No context switch +> to debug: a breakpoint in the method that built the view stops there. +> +> Individually, conveniences. Together, the reason a screen gets tried at all — +> when an experiment costs a class and a refresh, "could we just show this?" +> stops being a project. +> +> New article 🎉 +> +> What is your current edit-to-see-it time on a Fiori change? +> +> #ABAP #SAP #UI5 + +## One Codebase, 7.02 to ABAP Cloud + +Plain text — LinkedIn renders no markdown. + +> Most SAP landscapes are two landscapes right now: something old running the +> business, something new beside it, and a migration measured in years. Anything +> written for one side usually gets written again for the other. +> +> abap2UI5 needs almost nothing from the release, because it only produces two +> strings and moves them over HTTP. The one real SAP dependency is GUID +> creation, written for both language versions in a single code line — and +> abaplint generates the 7.02 branch automatically, so the downport cannot drift. +> +> UI5 comes from a CDN, so the UI5 version is configuration, not a property of +> the release. +> +> New article 🎉 +> +> How much of what you build today will survive your next release upgrade? +> +> #ABAP #SAP #UI5 + +## 2,300 Lines + +Plain text — LinkedIn renders no markdown. + +> The communication core of abap2UI5 is one HTTP handler, two interfaces and one +> database table — originally around 2,300 lines of ABAP. +> +> It is small because of what it does not do. It does not build views, apps do. +> It does not decide flow, apps do. It does not wrap UI5 controls, so it does +> not grow when UI5 does. +> +> Which matters past elegance: a framework in the request path sees every input, +> every response, every user. There is a difference between trusting a package +> because it is popular and being able to open it and find out. +> +> New article 🎉 +> +> When did you last read a framework you depend on? +> +> #ABAP #SAP #UI5 + +## Where the Line Is + +Plain text — LinkedIn renders no markdown. + +> Eighteen articles is enough credit to say what abap2UI5 does not do. +> +> Offline is out — every event asks the server what happens next; take the +> server away and there is no app left. Pushdown to HANA is indirect, and a +> frontend fuzzy search help is not available. Real-time and collaborative UIs +> are the wrong shape for a request-per-event model. Separate frontend and +> backend teams lose the contract between them. And where a Fiori Elements +> floorplan fits, it fits — that is less work, not more. +> +> What is left is still most business software: forms, tables, dashboards, +> approvals, the small screens nobody funds a project for. +> +> New article 🎉 +> +> Where would you put the line? +> +> #ABAP #SAP #UI5 + +## Cloud-Ready Is a Property of Your App + +Plain text — LinkedIn renders no markdown. + +> abap2UI5 is ABAP Cloud compliant: written in ABAP for Cloud, released APIs +> only, no modifications, installs on BTP and S/4HANA Public Cloud. +> +> None of that says anything about the app you build with it. +> +> SELECT FROM i_salesorder, or SELECT FROM vbak. Same screen, same framework — +> one survives the next upgrade and can move to a cloud system, the other +> cannot. Nothing about the UI is involved in the difference. +> +> Clean core is not a property a dependency grants your application. It is +> decided in the SELECT. +> +> New article 🎉 +> +> Where does your team actually check this — review, ATC, or after the upgrade? +> +> #ABAP #SAP #UI5 + +## Twenty-Five Years of ABAP on the Web + +Plain text — LinkedIn renders no markdown. + +> ITS 2000. BSP 2001. Web Dynpro 2003. UI5 Freestyle 2010. RAP and Fiori +> Elements 2019. abap2UI5 2023. +> +> Read as a line, it is not a march away from the server. For the first ten +> years ABAP built the HTML. Then rendering left for the browser — and it stays +> there, because that is where a modern UI belongs. +> +> What has been moving back ever since is not the rendering but the definition +> of the screen: first as annotations, then as the view itself. +> +> New article 🎉 +> +> Which of these six did you write your first web app in? +> +> #ABAP #SAP #UI5 + +## Where the View Lives + +Plain text — LinkedIn renders no markdown. + +> Three ways to get a UI5 screen in front of a user on an ABAP stack. All three +> render in the browser, same control library, same framework. What differs is +> where the view is defined — and therefore when it is fixed. +> +> UI5 Freestyle: a file in a frontend project, fixed at build time. +> RAP with Fiori Elements: UI annotations on CDS, fixed when they are activated. +> abap2UI5: an XML string an ABAP class produced for this request. +> +> Everything else follows from that axis — what gets deployed per app, what a +> screen costs in artefacts, what can still change at runtime. Not a ranking: +> fixed early standardises well, fixed late adapts well. +> +> New article 🎉 +> +> Where does the view live in the app you are working on today? +> +> #ABAP #SAP #UI5 + +## RAP or abap2UI5 — When to Use Which + +Plain text — LinkedIn renders no markdown. + +> RAP or abap2UI5? Most systems end up with both, so the real question is never +> "which framework" but "which one for this screen". +> +> RAP when the behaviour matters more than the screen: a transactional object +> with validations, drafts and authorizations, and more than one consumer for it. +> +> abap2UI5 when the screen is the deliverable: one consumer, one purpose, often a +> short life — an ops tool, a correction screen, a dashboard for one team. Or when +> the shape is only known at runtime, or the release is too old for RAP. +> +> And they compose: an abap2UI5 app calls a RAP business object through EML like +> any other consumer. +> +> New article 🎉 +> +> Which of your screens is really a behaviour, and which is really just a screen? +> +> #ABAP #SAP #UI5 + +## UI5 Freestyle or abap2UI5 — When to Use Which + +Plain text — LinkedIn renders no markdown. + +> UI5 Freestyle or abap2UI5? Both give you the whole UI5 control library, so the +> choice is not about what is possible — it is about where the work happens. +> +> Freestyle when the browser has to be smart: offline, client-side state between +> roundtrips, genuinely interactive UIs. Also when a frontend team with its own +> release cycle owns the app — there the contract between front and back is a +> feature. +> +> abap2UI5 when the backend already knows everything: the data, the rules and the +> decisions are in ABAP, and a separate frontend project would be a second place +> to maintain for a screen whose logic never left the server. +> +> New article 🎉 +> +> Iteration speed or client richness — which one is actually scarce for you? +> +> #ABAP #SAP #UI5 + +## Low-Code or abap2UI5 — When to Use Which + +Plain text — LinkedIn renders no markdown. + +> A commercial low-code platform and abap2UI5 answer the same question: modern +> UIs for SAP systems without a frontend stack per app. A visual designer on a +> licensed platform, or plain ABAP in an open-source framework. +> +> Low-code when the requirement is outside code: offline-capable native mobile, +> a bundled workflow or portal suite, contractual SLAs, or app building by +> non-developers — a designer exists so that a non-developer can produce +> something, and no code-first framework replaces that. +> +> abap2UI5 when apps should be code in your own system: diffable, transportable, +> unit-testable, nothing recurring per seat. And code-first is what AI agents are +> actually good at — a visual designer needs a human in front of it. +> +> New article 🎉 +> +> Is your bottleneck building the apps, or governing them afterwards? +> +> #ABAP #SAP #UI5 diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs index b51acc08..be03a973 100644 --- a/docs/.vitepress/config.mjs +++ b/docs/.vitepress/config.mjs @@ -545,15 +545,6 @@ export default defineConfig({ }, ], }, - // "Technical Insight" was a group of its own here: eight narrative - // pages on what the framework does under the app. They were - // converted into the abap2UI5 Know-How article series and removed; - // the git history holds them (see the commit that deletes them). - // What is left of that reading is the toolchain group below, which - // was always a different kind of page - reference on somebody - // else's project rather than narrative on this one - and so stands - // on its own now rather than nested under a heading with nothing - // else beneath it. { // Every one of these is somebody else's project, which is what // this group is: the toolchain abap2UI5 stands on. It used to be @@ -581,6 +572,45 @@ export default defineConfig({ { text: "abapmerge", link: "/technical/tools/abapmerge" }, ], }, + { + // The article series. It replaced eight narrative pages that used + // to stand here as "Technical Insight" - the same reading, cut + // into one claim per article so each can be read on its own and + // posted on its own. Last in this section on purpose: it is the + // part read after the app runs, not on the way in, and a reader + // who opens Advanced Topics for a how-to should meet the how-tos + // first. + text: "Technical Insights", + link: "/advanced/insights/01-somewhere-on-the-way-to-ui5", + collapsed: true, + items: [ + { text: "Somewhere on the Way to UI5, We Lost RTTS", link: "/advanced/insights/01-somewhere-on-the-way-to-ui5" }, + { text: "abap2UI5 is not a Programming Model", link: "/advanced/insights/02-not-a-programming-model" }, + { text: "The Cost of a Screen", link: "/advanced/insights/03-the-cost-of-a-screen" }, + { text: "No Annotation in Between", link: "/advanced/insights/04-no-annotation-in-between" }, + { text: "UI5 Over-the-Wire", link: "/advanced/insights/05-ui5-over-the-wire" }, + { text: "The Frontend That Does Not Know What It Shows", link: "/advanced/insights/06-the-frontend-that-does-not-know" }, + { text: "One Service for Every App", link: "/advanced/insights/07-one-service-for-every-app" }, + { text: "Only the Changed Part", link: "/advanced/insights/08-only-the-changed-part" }, + { text: "PUBLIC Means Persisted", link: "/advanced/insights/09-public-means-persisted" }, + { text: "Swapping the View at Runtime", link: "/advanced/insights/10-swapping-the-view-at-runtime" }, + { text: "index.html Lives in a String", link: "/advanced/insights/11-index-html-lives-in-a-string" }, + { text: "Where Your Own JavaScript Goes", link: "/advanced/insights/12-where-your-own-javascript-goes" }, + { text: "Four Verbs", link: "/advanced/insights/13-four-verbs" }, + { text: "The Class That Runs", link: "/advanced/insights/14-the-class-that-runs" }, + { text: "Where the Selection Screen Went", link: "/advanced/insights/15-where-the-selection-screen-went" }, + { text: "No Cache, No Deploy, Any IDE", link: "/advanced/insights/16-no-cache-no-deploy-any-ide" }, + { text: "One Codebase, 7.02 to ABAP Cloud", link: "/advanced/insights/17-one-codebase-702-to-abap-cloud" }, + { text: "2,300 Lines", link: "/advanced/insights/18-2300-lines" }, + { text: "Where the Line Is", link: "/advanced/insights/19-where-the-line-is" }, + { text: "Cloud-Ready Is a Property of Your App", link: "/advanced/insights/20-cloud-ready-is-a-property-of-your-app" }, + { text: "Twenty-Five Years of ABAP on the Web", link: "/advanced/insights/21-abap-on-the-web" }, + { text: "Where the View Lives", link: "/advanced/insights/22-where-the-view-lives" }, + { text: "RAP or abap2UI5 — When to Use Which", link: "/advanced/insights/23-rap-or-abap2ui5" }, + { text: "UI5 Freestyle or abap2UI5 — When to Use Which", link: "/advanced/insights/24-freestyle-or-abap2ui5" }, + { text: "Low-Code or abap2UI5 — When to Use Which", link: "/advanced/insights/25-low-code-or-abap2ui5" }, + ], + }, ], }, { diff --git a/blog/01-somewhere-on-the-way-to-ui5.md b/docs/advanced/insights/01-somewhere-on-the-way-to-ui5.md similarity index 86% rename from blog/01-somewhere-on-the-way-to-ui5.md rename to docs/advanced/insights/01-somewhere-on-the-way-to-ui5.md index c0ab92a9..7e3da19d 100644 --- a/blog/01-somewhere-on-the-way-to-ui5.md +++ b/docs/advanced/insights/01-somewhere-on-the-way-to-ui5.md @@ -4,7 +4,7 @@ ![The dinosaur at a classic ALV grid, the sheep and the sloth at the same table rendered in UI5, with cl_abap_structdescr->get_components( ) bridging the -two](assets/01-rtti-header.png) +two](/insights/01-rtti-header.png) ABAP developers have always built screens for tables whose structure is unknown when the code is written. With ALV you either assemble the field catalog @@ -157,28 +157,3 @@ So next time you reach for RTTS and need a UI, give abap2UI5 a try. It may be a good complement to the UI5 solutions you already run. Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. The article link comes from the -attached article preview, so the post carries no inline URL. 744 characters. - -> In the past, screens were routinely built for tables nobody had seen. -> cl_salv_table=>factory( ) took any internal table and drew it — RTTS read the -> structure at runtime, the DDIC supplied the labels, and a whole category of -> ABAP tooling was built that way. -> -> With Fiori Elements, RAP or freestyle UI5, that path goes through a typed -> OData service: the entity type has to exist first, at design time. Exactly -> right when the client does not know your backend — but a dead end for those -> tools. -> -> New article 🎉 abap2UI5 can give a runtime-typed model a UI5 face, and be a -> perfect complement to the UI5 and RAP solutions you already run. -> -> Where do you still use RTTS in UIs today? And how do you get around the -> design-time bottleneck? -> -> #ABAP #SAP #UI5 diff --git a/blog/02-not-a-programming-model.md b/docs/advanced/insights/02-not-a-programming-model.md similarity index 85% rename from blog/02-not-a-programming-model.md rename to docs/advanced/insights/02-not-a-programming-model.md index 854ce82a..9c3aadfe 100644 --- a/blog/02-not-a-programming-model.md +++ b/docs/advanced/insights/02-not-a-programming-model.md @@ -1,7 +1,5 @@ # abap2UI5 is not a Programming Model -*abap2UI5 Know-How #2 — draft* - The useful question about a UI framework is not what it can do. It is what it wants from you: a structure to follow, a lifecycle to fit into, layers to fill in. @@ -30,6 +28,7 @@ and calling the ICF endpoint is the deployment. That is a statement about scope, not size — and it is why the data behind the screen can come from wherever it already lives: + ```abap CLASS zcl_travel_edit DEFINITION PUBLIC. @@ -169,28 +168,3 @@ What it is not, plainly: no data model, no transactional buffer, no generated user interface. Applications needing those need something that provides them. Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The useful question about a UI framework is not what it can do. It is what it -> wants from you: a structure to follow, a lifecycle to fit into, layers to fill -> in. -> -> abap2UI5 fits its answer on a page — one interface, one method. No data model, -> no service, no binding, no annotations, no BSP per app, no frontend artefact -> to transport. -> -> Which is why it composes instead of competing. The new article shows one app -> and three save handlers: EML against a business object, MODIFY against a -> table, and a BAPI call. The framework never learns which — it could just as -> well be the EWM classes, or whatever SAP releases next. -> -> New article 🎉 -> -> What does your UI framework ask of your architecture? -> -> #ABAP #SAP #UI5 diff --git a/blog/03-the-cost-of-a-screen.md b/docs/advanced/insights/03-the-cost-of-a-screen.md similarity index 81% rename from blog/03-the-cost-of-a-screen.md rename to docs/advanced/insights/03-the-cost-of-a-screen.md index b5c3963c..db85e3e3 100644 --- a/blog/03-the-cost-of-a-screen.md +++ b/docs/advanced/insights/03-the-cost-of-a-screen.md @@ -1,7 +1,5 @@ # The Cost of a Screen -*abap2UI5 Know-How #3 — draft* - An ABAP team needs a screen. Not an application — a screen. A maintenance view for a customising table nobody wants to explain in SM30. A cockpit showing what last night's job actually did. An approval step for one department. @@ -123,29 +121,3 @@ Fiori Elements will beat this by a distance. Knowing which of the two you are looking at is most of the skill. Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> A maintenance view for a customising table. A cockpit showing what last -> night's job did. An approval step for one department. -> -> The logic behind each is about thirty lines. The cost of putting a UI in front -> of thirty lines is not thirty lines, and it does not scale down: a data model, -> a service, a binding, a frontend artefact, a deployment — and an object that -> has to be transported, survive upgrades, and one day be deprecated by someone -> who never met the department that asked for it. -> -> So the screen never gets built. Every system has a Z package full of the ones -> that became a selection screen and an ALV grid instead. -> -> New article 🎉 with a job monitor as a complete abap2UI5 app — and an honest -> note on where this is the wrong trade. -> -> Which screen in your system stayed an ALV grid because a proper UI was never -> worth the effort? -> -> #ABAP #SAP #UI5 diff --git a/blog/04-no-annotation-in-between.md b/docs/advanced/insights/04-no-annotation-in-between.md similarity index 83% rename from blog/04-no-annotation-in-between.md rename to docs/advanced/insights/04-no-annotation-in-between.md index 915b2bf1..252c4361 100644 --- a/blog/04-no-annotation-in-between.md +++ b/docs/advanced/insights/04-no-annotation-in-between.md @@ -1,7 +1,5 @@ # No Annotation in Between -*abap2UI5 Know-How #4 — draft* - In a metadata-driven UI a screen is described rather than written. The description has a vocabulary — line items, selection fields, facets, identification — and a generator turns it into UI5 at runtime. Whatever the @@ -115,26 +113,3 @@ Reaching every control is not the same as being handed one. promise, and takes nothing off the table either.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> A metadata-driven screen is described, not written — and the description has a -> vocabulary. What the vocabulary covers arrives in an afternoon. What it does -> not becomes an extension point. -> -> abap2UI5 has no vocabulary of its own to run out of. It sends a UI5 XML view, -> so the vocabulary is the UI5 control library itself, all of it, at whatever -> version the launchpad already serves. The new article builds a three-step -> sap.m.Wizard in one ABAP class to show what that means in practice. -> -> The price is on the same page: nothing writes the layout for you. -> -> New article 🎉 -> -> Which control did you last want, and not have a way to ask for? -> -> #ABAP #SAP #UI5 diff --git a/blog/05-ui5-over-the-wire.md b/docs/advanced/insights/05-ui5-over-the-wire.md similarity index 74% rename from blog/05-ui5-over-the-wire.md rename to docs/advanced/insights/05-ui5-over-the-wire.md index 1e399602..75ef54bc 100644 --- a/blog/05-ui5-over-the-wire.md +++ b/docs/advanced/insights/05-ui5-over-the-wire.md @@ -1,7 +1,5 @@ # UI5 Over-the-Wire -*abap2UI5 Know-How #5 — draft* - A UI5 freestyle app is a single-page application. The view is deployed with the app in the frontend, the backend delivers data through OData, and the browser puts the two together and renders the HTML. @@ -30,7 +28,7 @@ and the model that fills it: { "MODEL": { "NAME": "test" } } ``` -![The backend answers with a view and its model; the browser renders both.](assets/diagrams/05-two-strings.svg) +![The backend answers with a view and its model; the browser renders both.](/insights/05-two-strings.svg) *The backend answers with a view and its model; the browser renders both.* @@ -59,26 +57,3 @@ Happy ABAPing! 🦖🦕🦣 *This article and the ones that follow it are cut from [Under the Hood of abap2UI5](https://community.sap.com/t5/technology-blog-posts-by-members/abap2ui5-7-technical-background-under-the-hood-of-abap2ui5/ba-p/13566459), published on the SAP Community — the long version, with the diagrams.* - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> UI5 does not render from objects you assemble by hand. It renders from an XML -> view, bound to its data. The view is a document — and documents can travel. -> -> So what if the backend sent the view too? That is the whole of abap2UI5: every -> request is answered with two strings, a UI5 XML view and a UI5 JSON model. -> Neither is a protocol the framework invented, and the frontend does what it -> always did. -> -> What changes is who owns the view. Not an artefact deployed beside the app — -> a string an ABAP class produced for this request. -> -> New article 🎉 -> -> Where would you draw the line between a frontend and a renderer? -> -> #ABAP #SAP #UI5 diff --git a/blog/06-the-frontend-that-does-not-know.md b/docs/advanced/insights/06-the-frontend-that-does-not-know.md similarity index 69% rename from blog/06-the-frontend-that-does-not-know.md rename to docs/advanced/insights/06-the-frontend-that-does-not-know.md index 74211e15..c1292079 100644 --- a/blog/06-the-frontend-that-does-not-know.md +++ b/docs/advanced/insights/06-the-frontend-that-does-not-know.md @@ -1,7 +1,5 @@ # The Frontend That Does Not Know What It Shows -*abap2UI5 Know-How #6 — draft* - The first GET request delivers a UI5 app to the browser. It is worth asking what is actually in it. @@ -21,7 +19,7 @@ rebuild to change either, an HDA renders what the server sends and knows nothing else. It is the sweet spot those two leave open, and it is where htmx, Hotwire and LiveView all sit. -![Multi-page, single-page, hypermedia-driven — and what each has to rebuild.](assets/diagrams/06-mpa-spa-hda.svg) +![Multi-page, single-page, hypermedia-driven — and what each has to rebuild.](/insights/06-mpa-spa-hda.svg) *Multi-page, single-page, hypermedia-driven — and what each has to rebuild.* @@ -42,28 +40,3 @@ keep current, and every app is current with it. to be redeployed when the app changes.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The UI5 app that abap2UI5 sends to the browser does not contain the screen. -> Not the fields, not the table, not the buttons. It is a shell: enough UI5 to -> render a view and a model that arrive from the server, and to send events -> back. -> -> It cannot tell whether it is showing a table or a wizard, and it does not know -> which action follows the next click. PBO builds, PAI decides — the dialog step -> just became an AJAX call. -> -> Which means there is one shell, shared by every app in the system. Not one -> deployed frontend per app, each pinned to whichever UI5 version someone last -> had time for. -> -> New article 🎉 -> -> How many separately deployed frontends does your system carry right now? -> -> #ABAP #SAP #UI5 diff --git a/blog/07-one-service-for-every-app.md b/docs/advanced/insights/07-one-service-for-every-app.md similarity index 65% rename from blog/07-one-service-for-every-app.md rename to docs/advanced/insights/07-one-service-for-every-app.md index 33ec09fd..7649b3e5 100644 --- a/blog/07-one-service-for-every-app.md +++ b/docs/advanced/insights/07-one-service-for-every-app.md @@ -1,7 +1,5 @@ # One Service for Every App -*abap2UI5 Know-How #7 — draft* - Count what a screen usually costs in backend artefacts. A CDS view or two, a service definition, a service binding, a behavior definition and its implementation, a projection — each one named, transported, reviewed, and each @@ -12,7 +10,7 @@ either. Every app in the system is served by the same generic HTTP handler, and it is generic in a specific way: it does not know the app, the view or the model. It moves two strings. -![A service per screen, against one handler that knows none of them.](assets/diagrams/07-one-service.svg) +![A service per screen, against one handler that knows none of them.](/insights/07-one-service.svg) *A service per screen, against one handler that knows none of them.* @@ -36,28 +34,3 @@ is the one that was never created. again for the next one.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Count what one screen usually costs in backend artefacts: a CDS view or two, a -> service definition, a service binding, a behavior definition and its -> implementation — each named, transported, reviewed, and each belonging to -> exactly one app. -> -> An abap2UI5 app adds none of them. Every app is served by the same generic -> handler, which does not know the app, the view or the model — it moves two -> strings. Set a breakpoint and look at the call stack: one frame. -> -> It can be generic because nothing about the data is agreed in advance. The -> model travels with every response, so every response may carry a different one. -> -> New article 🎉 -> -> How many of the objects in your last transport existed only to get one screen -> onto a display? -> -> #ABAP #SAP #UI5 diff --git a/blog/08-only-the-changed-part.md b/docs/advanced/insights/08-only-the-changed-part.md similarity index 67% rename from blog/08-only-the-changed-part.md rename to docs/advanced/insights/08-only-the-changed-part.md index e1803a07..cd5a52f1 100644 --- a/blog/08-only-the-changed-part.md +++ b/docs/advanced/insights/08-only-the-changed-part.md @@ -1,7 +1,5 @@ # Only the Changed Part -*abap2UI5 Know-How #8 — draft* - If the backend sends the view on every request, does the screen rebuild itself on every click? @@ -30,7 +28,7 @@ in the browser is the one already standing, and UI5 does what UI5 does with a changed model: data binding updates the controls bound to what changed, and touches nothing else. -![What a response carries decides what survives on the screen.](assets/diagrams/08-partial-update.svg) +![What a response carries decides what survives on the screen.](/insights/08-partial-update.svg) *What a response carries decides what survives on the screen.* @@ -46,26 +44,3 @@ just a model that changed and a binding that noticed. **Sending the whole view is the exception, not the rhythm.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> If the backend sends the view on every request, does the screen rebuild itself -> on every click? -> -> It would — and the user would feel it. A rebuilt view is a new set of -> controls: focus lost, half-typed input gone, table scrolled back to the top. -> -> So the view is not sent every time. It is one IF in the app. When it is -> skipped, the response carries only the model, and UI5 data binding updates -> exactly the controls bound to what changed. No diffing, no virtual DOM, no -> reconciler — a mechanism UI5 has had all along. -> -> New article 🎉 -> -> Where has a full re-render cost you a user's input? -> -> #ABAP #SAP #UI5 diff --git a/blog/09-public-means-persisted.md b/docs/advanced/insights/09-public-means-persisted.md similarity index 68% rename from blog/09-public-means-persisted.md rename to docs/advanced/insights/09-public-means-persisted.md index 3cece629..6066eb5f 100644 --- a/blog/09-public-means-persisted.md +++ b/docs/advanced/insights/09-public-means-persisted.md @@ -1,7 +1,5 @@ # PUBLIC Means Persisted -*abap2UI5 Know-How #9 — draft* - Every request lands on a fresh instance of the app class. No session holds the previous one, and the next request may not even reach the same application server. @@ -14,7 +12,7 @@ for every app, not a typed draft table per data model — and reads it back on t next one. What survives is exactly the `PUBLIC SECTION`; nothing else is part of the serialized state. -![Every request is a new instance; z2ui5_t_01 is what carries the last one forward.](assets/diagrams/09-draft.svg) +![Every request is a new instance; z2ui5_t_01 is what carries the last one forward.](/insights/09-draft.svg) *Every request is a new instance; z2ui5_t_01 is what carries the last one forward.* @@ -47,27 +45,3 @@ or replicated between nodes. which section an attribute belongs in.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Every abap2UI5 request lands on a fresh instance of the app class. No session -> holds the previous one, and the next request may not even reach the same app -> server. -> -> So how does what the user typed three clicks ago still exist? The app class is -> serializable, and after each request the framework serializes it into a draft -> table. What survives is exactly the PUBLIC SECTION. -> -> Which makes one keyword a performance decision. A catalogue parked in a public -> attribute is not cached — it is written to the database and shipped to the -> browser after every click. State public, working data protected. -> -> New article 🎉 -> -> Where in your code does a keyword quietly decide what travels? -> -> #ABAP #SAP #UI5 diff --git a/blog/10-swapping-the-view-at-runtime.md b/docs/advanced/insights/10-swapping-the-view-at-runtime.md similarity index 71% rename from blog/10-swapping-the-view-at-runtime.md rename to docs/advanced/insights/10-swapping-the-view-at-runtime.md index 77f683ff..29510147 100644 --- a/blog/10-swapping-the-view-at-runtime.md +++ b/docs/advanced/insights/10-swapping-the-view-at-runtime.md @@ -1,7 +1,5 @@ # Swapping the View at Runtime -*abap2UI5 Know-How #10 — draft* - The view is a string the app produced for this request. Which raises an uncomfortable question: what stops the next request from producing a different one? @@ -44,7 +42,7 @@ Nothing does. ENDMETHOD. ``` -![Same data, same class — the control is chosen in an IF.](assets/diagrams/10-view-swap.svg) +![Same data, same class — the control is chosen in an IF.](/insights/10-view-swap.svg) *Same data, same class — the control is chosen in an IF.* @@ -66,27 +64,3 @@ things a screen can adapt to are no longer fixed on the day it was designed. **A view that is built is a view that can be built differently.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> In abap2UI5 the view is a string the app produced for this request. So what -> stops the next request from producing a different one? -> -> Nothing does. One IF in the app class, and the table is a list — not a table -> with hidden columns, not a second app behind a navigation step. A different -> control, chosen in ABAP. -> -> A screen assembled at design time varies only where somebody anticipated -> variation and left a switch. A screen assembled per request varies wherever -> the code branches. -> -> New article 🎉 -> -> Which screen in your system would you rebuild differently per user, if it cost -> you an IF? -> -> #ABAP #SAP #UI5 diff --git a/blog/11-index-html-lives-in-a-string.md b/docs/advanced/insights/11-index-html-lives-in-a-string.md similarity index 64% rename from blog/11-index-html-lives-in-a-string.md rename to docs/advanced/insights/11-index-html-lives-in-a-string.md index bdfa8a57..3b528fe3 100644 --- a/blog/11-index-html-lives-in-a-string.md +++ b/docs/advanced/insights/11-index-html-lives-in-a-string.md @@ -1,7 +1,5 @@ # index.html Lives in a String -*abap2UI5 Know-How #11 — draft* - Somebody has to deliver the first HTML page. In the SAP world that normally means a BSP application: a frontend artefact, built somewhere, deployed to the ABAP stack, transported on its own path, and invalidated from its own caches @@ -11,7 +9,7 @@ abap2UI5 does not have one. The initial GET is answered from ABAP source code the page and the frontend files it needs are strings inside the handler, and serving them is a method call. -![Four steps, or a method that returns a string.](assets/diagrams/11-initial-request.svg) +![Four steps, or a method that returns a string.](/insights/11-initial-request.svg) *Four steps, or a method that returns a string.* @@ -36,27 +34,3 @@ transported by the system that already governs everything else. **The cheapest build pipeline is the one that was never introduced.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Somebody has to deliver the first HTML page. In the SAP world that normally -> means a BSP: a frontend artefact, built somewhere, deployed, transported on -> its own path, invalidated from its own caches. -> -> abap2UI5 does not have one. The initial GET is answered from ABAP source — -> the page is a string in the handler. -> -> So the project is nothing but ABAP: abapGit and activate, no npm install, no -> bundler, no dist folder. No build output to go stale, so no cache to -> invalidate. And no dependency tree that somebody has to audit, pin and answer -> for. -> -> New article 🎉 -> -> How much of your last frontend incident was the pipeline rather than the code? -> -> #ABAP #SAP #UI5 diff --git a/blog/12-where-your-own-javascript-goes.md b/docs/advanced/insights/12-where-your-own-javascript-goes.md similarity index 73% rename from blog/12-where-your-own-javascript-goes.md rename to docs/advanced/insights/12-where-your-own-javascript-goes.md index 8b7e0cf1..ca8b8f41 100644 --- a/blog/12-where-your-own-javascript-goes.md +++ b/docs/advanced/insights/12-where-your-own-javascript-goes.md @@ -1,7 +1,5 @@ # Where Your Own JavaScript Goes -*abap2UI5 Know-How #12 — draft* - Sooner or later an app needs something the XML view cannot express. A chart library. A control nobody has wrapped. A UI5 method that exists only as a method — `sap.m.Carousel` moves through `setActivePage( )` and through nothing @@ -50,27 +48,3 @@ for either. the boundary is.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Sooner or later an app needs what an XML view cannot express: a chart library, -> an unwrapped control, or a UI5 method that exists only as a method — -> sap.m.Carousel moves through setActivePage( ) and nothing else. -> -> abap2UI5 has no plugin system for that, on purpose. It has three declared -> seams: an imperative method reached by control id from ABAP, a custom control -> living in its own BSP behind a reserved resource root, and extra JavaScript -> for the initial page set once through the framework exit. -> -> None lets an app change the framework. None makes the framework change for an -> app. -> -> New article 🎉 -> -> When you last needed a custom control, what did it cost to get it in? -> -> #ABAP #SAP #UI5 diff --git a/blog/13-four-verbs.md b/docs/advanced/insights/13-four-verbs.md similarity index 68% rename from blog/13-four-verbs.md rename to docs/advanced/insights/13-four-verbs.md index bada4e4d..bdd0b659 100644 --- a/blog/13-four-verbs.md +++ b/docs/advanced/insights/13-four-verbs.md @@ -1,7 +1,5 @@ # Four Verbs -*abap2UI5 Know-How #13 — draft* - The first view builder in abap2UI5 had one method per UI5 control. `button( )`, `input( )`, `table( )` — hundreds of them, each with the control's properties as named parameters. @@ -16,7 +14,7 @@ written at all. Every new UI5 control was a pull request, and a wrapper is a translation — it can be behind, and it can be wrong, in a way the browser only discovers at runtime. -![The four verbs, and where each one leaves the cursor in the tree.](assets/diagrams/13-four-verbs.svg) +![The four verbs, and where each one leaves the cursor in the tree.](/insights/13-four-verbs.svg) *The four verbs, and where each one leaves the cursor in the tree.* @@ -38,26 +36,3 @@ API is worth more than a shortcut around part of it. **Four verbs that know no controls can build every control.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The first view builder in abap2UI5 had one method per UI5 control — hundreds -> of them, properties as named parameters. Good reason: ADT code completion -> listed them, so the frontend API was imported into backend tooling. -> -> Hard edge: a control the class had no method for could not be written at all. -> Every new UI5 control was a pull request. -> -> Its successor has four verbs — ele, tag, a, end. None of them names a control, -> which is exactly why every control is reachable. The completion list is gone; -> the compiler and the linter still check the chain. -> -> New article 🎉 -> -> Wrapper or raw API — which side do you land on, and why? -> -> #ABAP #SAP #UI5 diff --git a/blog/14-the-class-that-runs.md b/docs/advanced/insights/14-the-class-that-runs.md similarity index 67% rename from blog/14-the-class-that-runs.md rename to docs/advanced/insights/14-the-class-that-runs.md index 75f6b88f..bf2377f5 100644 --- a/blog/14-the-class-that-runs.md +++ b/docs/advanced/insights/14-the-class-that-runs.md @@ -1,7 +1,5 @@ # The Class That Runs -*abap2UI5 Know-How #14 — draft* - Every ABAP developer already knows the smallest program that does something: ```abap @@ -26,6 +24,9 @@ That is the shape abap2UI5 copied: CLASS zcl_app_ui5 DEFINITION PUBLIC. PUBLIC SECTION. INTERFACES z2ui5_if_app. + + PROTECTED SECTION. + PRIVATE SECTION. ENDCLASS. CLASS zcl_app_ui5 IMPLEMENTATION. @@ -53,27 +54,3 @@ confidently, and there is not much of that around. **The unit of an abap2UI5 application is a file somebody can read.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The smallest ABAP program that does something is a class with -> if_oo_adt_classrun: one interface, one method, F9. No transaction, no program, -> nothing beside it. -> -> abap2UI5 copied that silhouette exactly. Same shape, different destination — -> it renders in a browser, follows the Fiori guidelines, and goes to a colleague -> as a URL instead of "open ADT and press F9". -> -> Which leaves a property that has quietly become valuable: the whole app is one -> file. Anything that has to reason about it — a reviewer, a successor, a search, -> an agent — can hold all of it at once. -> -> New article 🎉 -> -> What is the smallest complete app in your system, measured in files? -> -> #ABAP #SAP #UI5 diff --git a/blog/15-where-the-selection-screen-went.md b/docs/advanced/insights/15-where-the-selection-screen-went.md similarity index 68% rename from blog/15-where-the-selection-screen-went.md rename to docs/advanced/insights/15-where-the-selection-screen-went.md index 97c0db17..b81fd973 100644 --- a/blog/15-where-the-selection-screen-went.md +++ b/docs/advanced/insights/15-where-the-selection-screen-went.md @@ -1,7 +1,5 @@ # Where the Selection Screen Went -*abap2UI5 Know-How #15 — draft* - Before anyone called it full-stack, ABAP had this: ```abap @@ -43,26 +41,3 @@ variable. variable and the field were the same declaration.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Before anyone called it full-stack, ABAP had PARAMETERS. Four lines and every -> layer is there: a typed, labelled input with a default and value help, plus -> validation and event handling. Nobody wrote a frontend, because declaring the -> variable was writing the frontend. -> -> That trade is what disappeared on the way to the browser: the variable and the -> field became two artefacts in two places, kept in step by a service in between. -> -> _bind puts them back together. The attribute is not a field name in a string — -> it is the ABAP variable. -> -> New article 🎉 -> -> How many places does one input field touch in your current stack? -> -> #ABAP #SAP #UI5 diff --git a/blog/16-no-cache-no-deploy-any-ide.md b/docs/advanced/insights/16-no-cache-no-deploy-any-ide.md similarity index 66% rename from blog/16-no-cache-no-deploy-any-ide.md rename to docs/advanced/insights/16-no-cache-no-deploy-any-ide.md index 48213db4..31fad82b 100644 --- a/blog/16-no-cache-no-deploy-any-ide.md +++ b/docs/advanced/insights/16-no-cache-no-deploy-any-ide.md @@ -1,7 +1,5 @@ # No Cache, No Deploy, Any IDE -*abap2UI5 Know-How #16 — draft* - The loop is: change the class, activate, refresh the browser. That is the whole article, and it is worth spelling out what is missing from it. @@ -34,26 +32,3 @@ tried at all: when an experiment costs a class and a refresh, the answer to **Iteration speed is not a nice-to-have. It decides which ideas get built.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The abap2UI5 loop is: change the class, activate, refresh the browser. -> -> What is missing from that sentence is the point. No deployment — activating is -> the deployment. No cache to invalidate — the UI is built per request, so -> nothing can be stale. No IDE agreement, because it is ABAP. No context switch -> to debug: a breakpoint in the method that built the view stops there. -> -> Individually, conveniences. Together, the reason a screen gets tried at all — -> when an experiment costs a class and a refresh, "could we just show this?" -> stops being a project. -> -> New article 🎉 -> -> What is your current edit-to-see-it time on a Fiori change? -> -> #ABAP #SAP #UI5 diff --git a/blog/17-one-codebase-702-to-abap-cloud.md b/docs/advanced/insights/17-one-codebase-702-to-abap-cloud.md similarity index 67% rename from blog/17-one-codebase-702-to-abap-cloud.md rename to docs/advanced/insights/17-one-codebase-702-to-abap-cloud.md index 509be220..5508fd98 100644 --- a/blog/17-one-codebase-702-to-abap-cloud.md +++ b/docs/advanced/insights/17-one-codebase-702-to-abap-cloud.md @@ -1,7 +1,5 @@ # One Codebase, 7.02 to ABAP Cloud -*abap2UI5 Know-How #17 — draft* - Most SAP landscapes are currently two landscapes. Something old that runs the business, something new that is being built beside it, and a migration between them measured in years rather than sprints. Anything written for one side is @@ -26,7 +24,7 @@ And the frontend does not age with the backend. UI5 is bootstrapped from a CDN, so the UI5 version is a configuration decision rather than a property of the SAP release. A current UI5 control works on a system that has never heard of it. -![Where UI5 comes from decides whether its version follows the SAP release.](assets/diagrams/17-bootstrap.svg) +![Where UI5 comes from decides whether its version follows the SAP release.](/insights/17-bootstrap.svg) *Where UI5 comes from decides whether its version follows the SAP release.* @@ -38,27 +36,3 @@ The screen built for the system being replaced is not thrown away with it. when the release changes.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Most SAP landscapes are two landscapes right now: something old running the -> business, something new beside it, and a migration measured in years. Anything -> written for one side usually gets written again for the other. -> -> abap2UI5 needs almost nothing from the release, because it only produces two -> strings and moves them over HTTP. The one real SAP dependency is GUID -> creation, written for both language versions in a single code line — and -> abaplint generates the 7.02 branch automatically, so the downport cannot drift. -> -> UI5 comes from a CDN, so the UI5 version is configuration, not a property of -> the release. -> -> New article 🎉 -> -> How much of what you build today will survive your next release upgrade? -> -> #ABAP #SAP #UI5 diff --git a/blog/18-2300-lines.md b/docs/advanced/insights/18-2300-lines.md similarity index 65% rename from blog/18-2300-lines.md rename to docs/advanced/insights/18-2300-lines.md index cb8561d9..a8d8205c 100644 --- a/blog/18-2300-lines.md +++ b/docs/advanced/insights/18-2300-lines.md @@ -1,7 +1,5 @@ # 2,300 Lines -*abap2UI5 Know-How #18 — draft* - The communication core of abap2UI5 is one HTTP handler class, two interfaces and one database table. Originally about 2,300 lines of ABAP. The framework has grown since — most visibly the optional view builder — but the part that carries @@ -10,7 +8,7 @@ every request is still that. It is a small number, and the interesting thing is what it is small *because* of. -![The whole request path.](assets/diagrams/18-footprint.svg) +![The whole request path.](/insights/18-footprint.svg) *The whole request path.* @@ -35,26 +33,3 @@ developer in the room can read. **A framework you can read all of is a framework you can be responsible for.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> The communication core of abap2UI5 is one HTTP handler, two interfaces and one -> database table — originally around 2,300 lines of ABAP. -> -> It is small because of what it does not do. It does not build views, apps do. -> It does not decide flow, apps do. It does not wrap UI5 controls, so it does -> not grow when UI5 does. -> -> Which matters past elegance: a framework in the request path sees every input, -> every response, every user. There is a difference between trusting a package -> because it is popular and being able to open it and find out. -> -> New article 🎉 -> -> When did you last read a framework you depend on? -> -> #ABAP #SAP #UI5 diff --git a/blog/19-where-the-line-is.md b/docs/advanced/insights/19-where-the-line-is.md similarity index 68% rename from blog/19-where-the-line-is.md rename to docs/advanced/insights/19-where-the-line-is.md index e87b0eb6..e2570e6e 100644 --- a/blog/19-where-the-line-is.md +++ b/docs/advanced/insights/19-where-the-line-is.md @@ -1,7 +1,5 @@ # Where the Line Is -*abap2UI5 Know-How #19 — draft* - Eighteen articles is enough credit to say what this does not do. **Offline is out.** Every event asks the server what happens next. Take the @@ -38,27 +36,3 @@ for. shape, and the shape has edges.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Eighteen articles is enough credit to say what abap2UI5 does not do. -> -> Offline is out — every event asks the server what happens next; take the -> server away and there is no app left. Pushdown to HANA is indirect, and a -> frontend fuzzy search help is not available. Real-time and collaborative UIs -> are the wrong shape for a request-per-event model. Separate frontend and -> backend teams lose the contract between them. And where a Fiori Elements -> floorplan fits, it fits — that is less work, not more. -> -> What is left is still most business software: forms, tables, dashboards, -> approvals, the small screens nobody funds a project for. -> -> New article 🎉 -> -> Where would you put the line? -> -> #ABAP #SAP #UI5 diff --git a/blog/20-cloud-ready-is-a-property-of-your-app.md b/docs/advanced/insights/20-cloud-ready-is-a-property-of-your-app.md similarity index 69% rename from blog/20-cloud-ready-is-a-property-of-your-app.md rename to docs/advanced/insights/20-cloud-ready-is-a-property-of-your-app.md index f701e632..434c3ecf 100644 --- a/blog/20-cloud-ready-is-a-property-of-your-app.md +++ b/docs/advanced/insights/20-cloud-ready-is-a-property-of-your-app.md @@ -1,7 +1,5 @@ # Cloud-Ready Is a Property of Your App -*abap2UI5 Know-How #20 — draft* - The framework is ABAP Cloud compliant. It is written in the ABAP for Cloud language version, it calls released APIs only, it modifies no standard SAP code, and it installs on BTP ABAP Environment and S/4HANA Public Cloud. @@ -14,7 +12,7 @@ Virtual Data Model — the CDS views SAP publishes and maintains as an API — i the way in, and that is exactly what keeps an app upgrade-stable when the tables beneath it change. -![The released view is the shape SAP keeps stable across the upgrade.](assets/diagrams/20-vdm.svg) +![The released view is the shape SAP keeps stable across the upgrade.](/insights/20-vdm.svg) *The released view is the shape SAP keeps stable across the upgrade.* @@ -53,27 +51,3 @@ is a property of what the application reads and writes, and it is decided in the the reason one is not.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> abap2UI5 is ABAP Cloud compliant: written in ABAP for Cloud, released APIs -> only, no modifications, installs on BTP and S/4HANA Public Cloud. -> -> None of that says anything about the app you build with it. -> -> SELECT FROM i_salesorder, or SELECT FROM vbak. Same screen, same framework — -> one survives the next upgrade and can move to a cloud system, the other -> cannot. Nothing about the UI is involved in the difference. -> -> Clean core is not a property a dependency grants your application. It is -> decided in the SELECT. -> -> New article 🎉 -> -> Where does your team actually check this — review, ATC, or after the upgrade? -> -> #ABAP #SAP #UI5 diff --git a/blog/21-abap-on-the-web.md b/docs/advanced/insights/21-abap-on-the-web.md similarity index 69% rename from blog/21-abap-on-the-web.md rename to docs/advanced/insights/21-abap-on-the-web.md index 9f911b1f..9e34843b 100644 --- a/blog/21-abap-on-the-web.md +++ b/docs/advanced/insights/21-abap-on-the-web.md @@ -1,7 +1,5 @@ # Twenty-Five Years of ABAP on the Web -*abap2UI5 Know-How #21 — draft* - Worth laying out end to end, because the shape of it is not what most people remember. @@ -26,7 +24,7 @@ annotations, and a runtime in the browser turns them into the app. **abap2UI5, 2023.** The backend sends the XML view itself, and a static UI5 app renders it. -![Twenty-three years, and the one move that did not reverse.](assets/diagrams/21-timeline.svg) +![Twenty-three years, and the one move that did not reverse.](/insights/21-timeline.svg) *Twenty-three years, and the one move that did not reverse.* @@ -44,25 +42,3 @@ browser. home.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> ITS 2000. BSP 2001. Web Dynpro 2003. UI5 Freestyle 2010. RAP and Fiori -> Elements 2019. abap2UI5 2023. -> -> Read as a line, it is not a march away from the server. For the first ten -> years ABAP built the HTML. Then rendering left for the browser — and it stays -> there, because that is where a modern UI belongs. -> -> What has been moving back ever since is not the rendering but the definition -> of the screen: first as annotations, then as the view itself. -> -> New article 🎉 -> -> Which of these six did you write your first web app in? -> -> #ABAP #SAP #UI5 diff --git a/blog/22-where-the-view-lives.md b/docs/advanced/insights/22-where-the-view-lives.md similarity index 68% rename from blog/22-where-the-view-lives.md rename to docs/advanced/insights/22-where-the-view-lives.md index 2e3ccf8f..e6c6523e 100644 --- a/blog/22-where-the-view-lives.md +++ b/docs/advanced/insights/22-where-the-view-lives.md @@ -1,7 +1,5 @@ # Where the View Lives -*abap2UI5 Know-How #22 — draft* - Three ways to put a UI5 screen in front of a user on an ABAP stack. All three render in the browser, with the same control library, through the same framework. What differs is one thing: where the view is defined, and therefore @@ -23,7 +21,7 @@ for this request, rendered by a shell app that is the same for every application. It is fixed when the request is answered, and the next request may answer differently. -![One axis: when the definition of the screen stops being changeable.](assets/diagrams/22-where-the-view-lives.svg) +![One axis: when the definition of the screen stops being changeable.](/insights/22-where-the-view-lives.svg) *One axis: when the definition of the screen stops being changeable.* @@ -41,27 +39,3 @@ properties, not different amounts of the same one. made for you.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> Three ways to get a UI5 screen in front of a user on an ABAP stack. All three -> render in the browser, same control library, same framework. What differs is -> where the view is defined — and therefore when it is fixed. -> -> UI5 Freestyle: a file in a frontend project, fixed at build time. -> RAP with Fiori Elements: UI annotations on CDS, fixed when they are activated. -> abap2UI5: an XML string an ABAP class produced for this request. -> -> Everything else follows from that axis — what gets deployed per app, what a -> screen costs in artefacts, what can still change at runtime. Not a ranking: -> fixed early standardises well, fixed late adapts well. -> -> New article 🎉 -> -> Where does the view live in the app you are working on today? -> -> #ABAP #SAP #UI5 diff --git a/blog/23-rap-or-abap2ui5.md b/docs/advanced/insights/23-rap-or-abap2ui5.md similarity index 66% rename from blog/23-rap-or-abap2ui5.md rename to docs/advanced/insights/23-rap-or-abap2ui5.md index 0dbb98b0..de20418b 100644 --- a/blog/23-rap-or-abap2ui5.md +++ b/docs/advanced/insights/23-rap-or-abap2ui5.md @@ -1,7 +1,5 @@ # RAP or abap2UI5 — When to Use Which -*abap2UI5 Know-How #23 — draft* - The honest answer is that most systems end up with both, and the question is never "which framework" but "which one for this screen". @@ -33,28 +31,3 @@ front of it. use it. Build the screen wherever it is cheapest.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> RAP or abap2UI5? Most systems end up with both, so the real question is never -> "which framework" but "which one for this screen". -> -> RAP when the behaviour matters more than the screen: a transactional object -> with validations, drafts and authorizations, and more than one consumer for it. -> -> abap2UI5 when the screen is the deliverable: one consumer, one purpose, often a -> short life — an ops tool, a correction screen, a dashboard for one team. Or when -> the shape is only known at runtime, or the release is too old for RAP. -> -> And they compose: an abap2UI5 app calls a RAP business object through EML like -> any other consumer. -> -> New article 🎉 -> -> Which of your screens is really a behaviour, and which is really just a screen? -> -> #ABAP #SAP #UI5 diff --git a/blog/24-freestyle-or-abap2ui5.md b/docs/advanced/insights/24-freestyle-or-abap2ui5.md similarity index 65% rename from blog/24-freestyle-or-abap2ui5.md rename to docs/advanced/insights/24-freestyle-or-abap2ui5.md index 2c911d86..5017e15e 100644 --- a/blog/24-freestyle-or-abap2ui5.md +++ b/docs/advanced/insights/24-freestyle-or-abap2ui5.md @@ -1,7 +1,5 @@ # UI5 Freestyle or abap2UI5 — When to Use Which -*abap2UI5 Know-How #24 — draft* - Both give full access to the UI5 control library. Neither limits what a screen can contain. So the choice is not about what is possible — it is about where the work happens and who does it. @@ -30,27 +28,3 @@ work on a tablet with no signal. either way, and the controls are the same controls.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> UI5 Freestyle or abap2UI5? Both give you the whole UI5 control library, so the -> choice is not about what is possible — it is about where the work happens. -> -> Freestyle when the browser has to be smart: offline, client-side state between -> roundtrips, genuinely interactive UIs. Also when a frontend team with its own -> release cycle owns the app — there the contract between front and back is a -> feature. -> -> abap2UI5 when the backend already knows everything: the data, the rules and the -> decisions are in ABAP, and a separate frontend project would be a second place -> to maintain for a screen whose logic never left the server. -> -> New article 🎉 -> -> Iteration speed or client richness — which one is actually scarce for you? -> -> #ABAP #SAP #UI5 diff --git a/blog/25-low-code-or-abap2ui5.md b/docs/advanced/insights/25-low-code-or-abap2ui5.md similarity index 65% rename from blog/25-low-code-or-abap2ui5.md rename to docs/advanced/insights/25-low-code-or-abap2ui5.md index bf69463c..f02cb80e 100644 --- a/blog/25-low-code-or-abap2ui5.md +++ b/docs/advanced/insights/25-low-code-or-abap2ui5.md @@ -1,7 +1,5 @@ # Low-Code or abap2UI5 — When to Use Which -*abap2UI5 Know-How #25 — draft* - A commercial low-code platform and abap2UI5 answer the same question: modern UIs for SAP systems without a full frontend stack per app. The models could hardly be further apart — a visual designer on a licensed platform, or plain @@ -33,28 +31,3 @@ hundred UI5 sample ports were produced that way and are guarded by CI. one costs an abapGit pull and an afternoon.** Happy ABAPing! 🦖🦕🦣 - ---- - -## LinkedIn teaser post - -Plain text — LinkedIn renders no markdown. - -> A commercial low-code platform and abap2UI5 answer the same question: modern -> UIs for SAP systems without a frontend stack per app. A visual designer on a -> licensed platform, or plain ABAP in an open-source framework. -> -> Low-code when the requirement is outside code: offline-capable native mobile, -> a bundled workflow or portal suite, contractual SLAs, or app building by -> non-developers — a designer exists so that a non-developer can produce -> something, and no code-first framework replaces that. -> -> abap2UI5 when apps should be code in your own system: diffable, transportable, -> unit-testable, nothing recurring per seat. And code-first is what AI agents are -> actually good at — a visual designer needs a human in front of it. -> -> New article 🎉 -> -> Is your bottleneck building the apps, or governing them afterwards? -> -> #ABAP #SAP #UI5 diff --git a/docs/public/insights/01-rtti-header.png b/docs/public/insights/01-rtti-header.png new file mode 100644 index 00000000..a3942a65 Binary files /dev/null and b/docs/public/insights/01-rtti-header.png differ diff --git a/blog/assets/diagrams/05-two-strings.svg b/docs/public/insights/05-two-strings.svg similarity index 100% rename from blog/assets/diagrams/05-two-strings.svg rename to docs/public/insights/05-two-strings.svg diff --git a/blog/assets/diagrams/06-mpa-spa-hda.svg b/docs/public/insights/06-mpa-spa-hda.svg similarity index 100% rename from blog/assets/diagrams/06-mpa-spa-hda.svg rename to docs/public/insights/06-mpa-spa-hda.svg diff --git a/blog/assets/diagrams/07-one-service.svg b/docs/public/insights/07-one-service.svg similarity index 100% rename from blog/assets/diagrams/07-one-service.svg rename to docs/public/insights/07-one-service.svg diff --git a/blog/assets/diagrams/08-partial-update.svg b/docs/public/insights/08-partial-update.svg similarity index 100% rename from blog/assets/diagrams/08-partial-update.svg rename to docs/public/insights/08-partial-update.svg diff --git a/blog/assets/diagrams/09-draft.svg b/docs/public/insights/09-draft.svg similarity index 100% rename from blog/assets/diagrams/09-draft.svg rename to docs/public/insights/09-draft.svg diff --git a/blog/assets/diagrams/10-view-swap.svg b/docs/public/insights/10-view-swap.svg similarity index 100% rename from blog/assets/diagrams/10-view-swap.svg rename to docs/public/insights/10-view-swap.svg diff --git a/blog/assets/diagrams/11-initial-request.svg b/docs/public/insights/11-initial-request.svg similarity index 100% rename from blog/assets/diagrams/11-initial-request.svg rename to docs/public/insights/11-initial-request.svg diff --git a/blog/assets/diagrams/13-four-verbs.svg b/docs/public/insights/13-four-verbs.svg similarity index 100% rename from blog/assets/diagrams/13-four-verbs.svg rename to docs/public/insights/13-four-verbs.svg diff --git a/blog/assets/diagrams/17-bootstrap.svg b/docs/public/insights/17-bootstrap.svg similarity index 100% rename from blog/assets/diagrams/17-bootstrap.svg rename to docs/public/insights/17-bootstrap.svg diff --git a/blog/assets/diagrams/18-footprint.svg b/docs/public/insights/18-footprint.svg similarity index 100% rename from blog/assets/diagrams/18-footprint.svg rename to docs/public/insights/18-footprint.svg diff --git a/blog/assets/diagrams/20-vdm.svg b/docs/public/insights/20-vdm.svg similarity index 100% rename from blog/assets/diagrams/20-vdm.svg rename to docs/public/insights/20-vdm.svg diff --git a/blog/assets/diagrams/21-timeline.svg b/docs/public/insights/21-timeline.svg similarity index 100% rename from blog/assets/diagrams/21-timeline.svg rename to docs/public/insights/21-timeline.svg diff --git a/blog/assets/diagrams/22-where-the-view-lives.svg b/docs/public/insights/22-where-the-view-lives.svg similarity index 100% rename from blog/assets/diagrams/22-where-the-view-lives.svg rename to docs/public/insights/22-where-the-view-lives.svg diff --git a/scripts/check-examples.mjs b/scripts/check-examples.mjs index c317a1dc..d6706041 100644 --- a/scripts/check-examples.mjs +++ b/scripts/check-examples.mjs @@ -87,6 +87,19 @@ const unmigrated = []; * anything else is calling a method of the frozen one. */ const VERBS = new Set(['ele', 'tag', 'a', 'end', 'stringify']); +/* The THIRD fluent chain in this documentation, after the view builder and + * z2ui5_cl_ajson: RTTS. `CAST cl_abap_tabledescr( … )->get_table_line_type( )` + * is `)->method(` like any view step, and the mid-chain regex below cannot see + * the receiver that would tell it apart — the same reason ajson is skipped by + * name rather than by receiver. Skipping the whole fence is wrong here: a page + * that derives a type at runtime usually builds a view from it in the SAME + * fence, and that view is exactly what this gate is for. So the RTTS calls are + * named instead, and the view chain around them stays checked. */ +const RTTI_CALLS = new Set([ + 'get_components', 'get_table_line_type', 'get_relative_name', 'get_ddic_field_list', + 'describe_by_data', 'describe_by_name', 'get_ddic_header', 'applies_to_data', +]); + /* The gate had one blind spot, and it cost four more pages. `)->input( )` is * caught from its first character, but the SAME call written on its receiver - * `page->input( )` - is not, because the regex needs the closing paren of a @@ -144,13 +157,14 @@ function legacyFragments() { if (/z2ui5_cl_ajson/i.test(code)) continue; /* mid-chain: `)->input( )` */ for (const call of code.matchAll(/\)->([a-z_][a-z0-9_]*)\(/gi)) { - if (!VERBS.has(call[1].toLowerCase())) out.push({ page, call: `)->${call[1]}(` }); + const verb = call[1].toLowerCase(); + if (!VERBS.has(verb) && !RTTI_CALLS.has(verb)) out.push({ page, call: `)->${call[1]}(` }); } /* on the receiver: `page->input( )` */ const nodes = viewNodes(code); for (const call of code.matchAll(/\b([a-z_][a-z0-9_]*)->([a-z_][a-z0-9_]*)\(/gi)) { if (!nodes.has(call[1].toLowerCase())) continue; - if (VERBS.has(call[2].toLowerCase())) continue; + if (VERBS.has(call[2].toLowerCase()) || RTTI_CALLS.has(call[2].toLowerCase())) continue; out.push({ page, call: `${call[1]}->${call[2]}(` }); } }