asdf
Martin "Nethar" Doležal
https://ancestry.nethar.cz/aj.php
asdf
I've wrote about TDD (Test-Driven Development), and the truth is, despite how I like the idea, I've never had enough time to do it for all the parts. Well, until now... kinda :-)
A really good documentation is important for the project, along with enough “how to” examples. I've decided to do such examples as a showcase of the component, which is basically to test everything it offers. And then throw some invalid values at it and mistreat it a little bit.
I have to say, I expected this approach to reveal a few bugs, but to my amazement more than bugs it revealed some concept mistakes and forgotten functionalities. That's what I like about TDD, you simply write the test as a “wish”, if you will, how you'd like it to perform, and then try to get as close as possible to the target.
For example, I know I want to be able to abuse items in enums. I want them to support almost anything. So, I started with proper array of objects, then went to array of strings and numbers and ultimately ended up with key-value object, where key is item.value
and value is item.text
.
I even found a new approaches how to use Components in a different and sometimes more convenient way. I also found the current framework suits me well and I hardly feel there is something that should be done differently.
The main pitfall is I need to create enough unique scenarios, which is sometimes hard to achieve, mostly in cases I need to test uninitialized properties, that are used later for sibling Components. I want to cover as much as possible, without feeling it's all the same.
Similarly how I discovered most GUI elements are either elem, form, list or view, parts of those components could be also grouped, at least their DOM converters.
INPUT
SELECT
SELECT MULTI
TABS
The first “desktop experience” I created back in 2002, with a simulated web-based Windows desktop. Next attempt was two years later, this time a true “window manager” for QeX 4 and later for my personal website.
User was able to maximize, minimize or drag around the window. It either displayed an internal content, or external content in an iframe. Properties of each window, like position or state, was stored in a session and in user's profile.
Tiles in Win8 Start Menu is a great concept.
If the answer is YES, use checkbox. If the answer is A or B (or C, D or E), use radio. If there are more options, than five, use listbox. And if user can enter own custom value instead of offered choices, use combobox (textbox + listbox) or textbox with autocomplete.
☑ Do you want an ice cream?
Which ice cream do you want?🔘 Vanilla🔘 Chocolate
In Qedy, there are two kinds of textboxes with autocomplete. One based on "text" type, allowing to add any value, with autocompleted options only as a faster way of adding common values, and one based on "enum" type, where user is forced to pick one of the options from the menu.
In other words, text.autocomplete
is more fancy text box and it's best used in situations where you want push users towards certain values (also dealing with letter capitalization or accents), while enum.autocompelete
is text based select for situations, where listbox would have too many options.
With the team we finished a module for subjects (people and companies). We were hoping to get a shortcut, but the customer disagreed :-), so in the last months of many improvements and fixes I was forced to add a lot of technical debt to the codebase.
Another setback was the customer is still using IE11 and the original Edge, which added more complexity to the code, as various polyfills were required and also separate stylesheets, because there's no way to distinguish between the two using just media queries:
This was our first deployment of QedyJS, where we gathered awful lot of experience, and also the module is only a temporary solution for the customer, because he contracted another company, that are unable to provide their solution at the moment for legal reasons.
So I took the opportunity and created basically a working “demo” of what the final version of QedyJS should be capable of, only without all the hacks, tweaks and crutches. It's always easier to think of what to do differently, than what to do. This demo became a foundation for the Mk. III announced back in January and was largely enhanced since – Mk. IIIb, if you will.
There were some approaches I didn't like, some of them didn't work, some of them were sub-optimal, some of them was proven and will be kept, some of them were introduced for the first time and some of them were put aside for the time being.
I gathered all of the above and started once again with a clean plate. This time not as my primary project, but rather as a side project to pamper and enjoy. I wanted to have the time to do it really properly, to be able to elaborate on ideas, to have an incubator for them.
…Adding styles in QedyJS v3
.style(...)
(+) Snadné na implementaci, snadné použití
(-) Vždy budou kombinované selektory .comp.style a bude jich HODNĚ.
.style(...) => o... + i...
(+) Snadné na implementaci, snadné použití
(+) Jedna sada stylů
(-) Matoucí, v CSS nebude existovat styl, který zadám do .style(xxx); vždy bude prefixovaný
.styleInner(...) + .styleOuter(...)
(+) Jasné, málo kdy budou styly stejné
(-) Příliš mnoho psaní, rád bych měl jen .style(...), aby to korespondovalo se specifikací komponenty
(-) Dvě sady stylů v definici komponenty
.style(..., true)
(+) Ideální varianta
(-) Druhý parametr již je boolean na "force" (ala classList.toggle)
(-) Dvě sady stylů v definici komponenty
After the blog conquered PageSpeed Insights, it's time to do the same with Lighthouse.
It's conveniently embedded with Chromium-based browsers and the new Edge is no different. Simply open DevTools and go to “Audits” page, which may be hidden under the “»”. There select desired categories, maybe some community plugins, and pick a target device (mobile or desktop). Then click the “Generate report” button and wait.
It will refresh the page couple of times and after a few seconds it shows scores between 0 (worst) and 100 (best) for Performance, Accessibility, Best Practices, SEO and where applicable, Progressive Web App (PWA).
In every section it will tell you what passed and what failed, with description how to improve it. Sometimes it's may be impossible to score 100 simply due to webhosting limitations, if you e.g. can't define headers for static files.
In Dev Console I sometimes got a warning, that page reflow took so much ms. And because I'm curious, I looked up what it means.
Reflow is basically recalculation of dimensions and positions for some or all layout elements on the page. Just from this description you may understand it's pretty expensive (performance-wise) task.
Reflow can be triggered by manipulating DOM, changing visuals (computed styles and classes), resizing browser's window and more. Different browser engines have slightly different triggers and time required for the particular reflow type, but the general idea remains.
You can speed up the reflow process by reducing DOM depth, CSS rules and complex selectors; or moving complex rendering (e.g. animations) out of the flow using absolute or fixed position for the element.
There are basically three major approaches:
My approach is a combination of all of the above, with incremental saves prevalence. But, as usual, things aren't as simple as they may seem. In forms you can save data only after all required fields are filled. In editing long text there are no partial changes, so there's no cue when to save.
Therefore I have two ways of auto-save in a text. I define a 5 secs timer, that saves the text after it's not changed, which means e.g. arrow keys do not stop this from firing. The other way is I save after Enter key is pressed.
Before each change of text I create a “backup”, to have an undo option in case I or the editor mess it up. After the text is verified, those backups are deleted.
I also try to show saving in some unobtrusive way, like dimming header color or change it's background.
I started with a single “master” scope for all components and data elements. It went well, until it didn't :-) I needed to separate elems in lists (table columns), because they also got filled by the .data method.
The obvious choice was to create a per-component scope, but problems were single data elements can appear in multiple components and at the same time a single form can be composed of multiple other components.
So I tried keep all elems in the global scope and separate all elems in lists. It worked well and it solved the issue I had.
But I still had one issue, I wasn't able to declare a custom temporary form or a form-in-form. So the ultimate decision (and hopefully the last major rewrite of the whole thing) was to have somewhat hybrid scenario with per-major-component scopes – besides separate scope for lists, all nested forms will inherit scope from the initial parent form.
This way the nested parent form will have separate scope and a custom form, e.g. in a modal window, will also have it's own scope.
And to make it even more complex, I had to add a scope-groups, because I allow to load multiple modules at once (module-in-module) and I know what scopes to remove with closing the nested module. The former way didn't look right anyway :-)
I'm often oldschool and even I keep an eye on contemporary approaches, I don't really pay much attention to them. I'm probably worried it's just a short term fashion or an upcoming dead end, but sometimes I miss a lot for a long time – like this time.
I prefer server side HTML rendering, because it's a single solution for both users and robots. I perceive Node.js as yet another Java and I have no problem switching between languages, so using JavaScript also on the server is not that appealing to me.
Years ago I participated on project, where client side was created using GWT in JavaScript, while servlet only provided data via API in a form of JSON messages. I liked the idea, but I didn't see myself doing such thing.
Few years after that I participated on a project with the same approach once again and still didn't see what it's all about. As a sole programmer on most of my projects I don't have the need to divide the code. But this time I finally wanted to try it. My opportunity came in less than a year.
The project for it was perfect – transforming old intranet app, created in Microsoft Access, into a modern web app. Because of the Microsoft ecosystem in their IT department, my proposal to try the “recently” released ASP.NET Core looked like an obvious choice.
I was little worried the Core platform may lack some features, but version 2.x was mature enough to provide everything I needed and I had QetriX up and running in just a few days.
For the client side I created standalone HTML templates, that defined a layout and components. Because nowadays the DOM is optimized enough, I opted out of virtual DOM, defined custom properties as “data” attributes and the rest as QetriX Modules.
It worked surprisingly well, but I also encountered some drawbacks. First of all, I worked with a lot of numbers, but values and data attributes are strings, so I had to convert data types all the time. Second of all...
One of the biggest pains, when dealing with user bug reports, is when the bug isn't immediately apparent and it requires to investigate previous user's actions. Some bugs only appear after a certain action, so this is critical for the investigation.
First of all, in the error handler I added sending a bug report to a server. I used a custom fetch and not HTTP Service, because I need to catch possible errors in data exchange or with Services as well, so this way it won't go into infinite loop.
That helped me immensely. Now I basically almost don't need to get bug reports from testers and users any more, because they arrive automatically. There are rare cases, when the bug is so severe the error hander doesn't catch it, but for most bugs it just works.
Second of all, I've added a recording of some user interactions. I tried to balance between usefulness and privacy intrusion, but I'd need a user's consent anyway, so I went with more data. It stores latest 20 user actions, like clicks, value modifications and module loads. If it's not a Component, the element is identified by its selector.
EDIT: Source code for the selector generator is available on StackOverflow.
I created it modular, because some components could also be used for website analytics, like click maps or scroll maps.
The search box is asking for being abused as a command line, for several reasons: It's everywhere, it's easy to reach, it's simple and you can type anything into it. So I do, actually I've been guilty of that for ages - since QeX.
I usually prefix commands. I started by simply adding a space before the command, but sometimes there are spaces in the pasted text, so using a whitespace is not good idea.
So the next best thing is using two dashes before the command. The advantage of dashes is there are two keys for them on the keyboard, one of which is neatly in the corner of numpad, so it's very easy to find.
MVC (Model-View-Controller) is a popular software design pattern for user services. It divides the code into three independent parts:
Model contains data, data structure and the internal application logic around it, like methods to add a new record or edit an existing one. For server-side apps the model is entirely on the server, but with advent of web application frameworks and increasing capabilities of web browsers this “thin client” approach is slowly fading away.
View is how the model is presented to the user, in web apps it's HTML and CSS.
Controller is binding between events and functions that handles them. The rule is that model and view never talk to each other directly, but always use controller.
MVC allows to better handle your code, but if you try to implement it in small projects, most of the code will be for MVC itself, rather than the actual app. So it's more suitable for bigger tasks.
There are several variations of MVC, most notable is MVP (Model-View-Presenter).