Notes

About PDF

I get a complaint: a client can’t log into our customer portal. I check the database — the account is fine. So what’s the problem? I check the login and see a strange sight:

PDF

Above is what the user entered, and below is what’s in the database. My first thought: how on earth did a document end up in the string? :D

I’ll skip the further investigation. The key here is asking the right questions (otherwise, both Google and AI will be thinking about the popular file format, not the symbol). So, PDF in the context of Unicode means Pop Directional Formatting! It’s a symbol that controls text direction; it’s needed, for example, to properly render Arabic (which can contain both left-to-right and right-to-left text). The user obviously enters the login in RTL mode (or copies it from somewhere), and the portal does not understand this nuance.

In short, a piece of cake. However, I’d like to point out that the PDF file format existed long before the PDF symbol. I get that these are different technical fields, and the developers probably didn’t see the overlapping terminology as a significant issue. But deep down, I’m sure someone was smirking, anticipating today’s confusion.

6 September 2024 work

Rapture

I remember how amazed I was when I worked with window functions in PostgreSQL for the first time. You can adjust the calculation window for each row individually! And even segment it in advance. And all this is done natively, within a regular query, no extra add-ons needed. The standard aggregation with grouping and subqueries that I was used to in 1C suddenly turned into a pumpkin, just like Cinderella's carriage at midnight.

Recently, I’ve been learning Blender, and I suddenly felt the same excitement for the same reason. The fact that you can freely move objects around the 3D Viewport with the Move command was clear from the start, fine. However, when it hit me that each object is a set of polygons, and that each polygon can also be moved freely, leading to a natural reshaping of the object's geometry — that’s when it really got me.

Technology is amazing. Learning is awesome. Moments like these make me want to keep doing it over and over again :)

31 August 2024 PostgreSQL 3D

Nowhere To Run

Yesterday, I decided to take a break from work and go for a good run. I headed to the local park and did a few laps. Sitting there catching my breath, I grabbed my phone to switch the track, and there it was — a congratulations from my fitness tracker.

Oh hi

So much for taking a break. The platform is watching you, %username%!

P.S. But hey, now I’ve got a custom badge with the platform's logo. Gotta wear it with pride!

31 August 2024 sport

System Analysis

Amidst all these pet projects and the August whirlwind, I forgot to mention that I completed a course on system analysis, which I recently wrote about.

Certificate

The course was structured so that throughout the sessions, we worked on the same system, identifying problems and gradually solving them. Before the first lesson, we were asked to design the initial version of the system so that we could compare it with the final version at the end of the course and assess our progress. Well, I’m happy with the comparison — I mean, it’s really hard to look at that first version without laughing (or crying) :)

There wasn’t much time for reflection during the course, so I plan to continue working on the materials and turning the lessons into personal notes. It’s not that simple, given that our company deals heavily with solutions based on 1C:Enterprise, and much of my work involves various integrations of 1C instances with solutions outside the 1C stack.

However, 1C instances can be considered as monoliths with a specific set of characteristics (depending on the tasks being solved within them), and in most other respects, communication with them doesn’t differ much from traditional solutions: the same events (like RabbitMQ), the same incoming/outgoing HTTP calls, the same instability metric, and so on.

At this point, I’m definitely adopting (or have already adopted):

  1. Breaking down the technical specifications into numbered items (US-XXX) and storing them in one place with tags like "updated at," "canceled at," etc. This format seems quite effective.
  2. Maintaining an ADR (Architecture Decision Record). I’ve already implemented this, actually. However, it’s a bit concerning that some items occasionally get stored there that aren’t strictly architectural (e.g., logging principles for certain sections). Still, such things seem crucial for decision-making.
  3. Event Storming as a way to visualize business processes. I can’t say it’s a huge improvement over the patchwork we used before, but the result looks nice, and having a standard is better than having none.
  4. Application service diagrams with stickers indicating each service's characteristics. This is quite functional when you need to look at the project from a high level, and it’s not as dry as endless tables. That way, if the bus factor kicks in, the next person is more likely to notice these details.
  5. I want to work on BPMN and Activity Diagrams. I like the format, but so far, my attempts haven’t been satisfactory. I’ll keep trying.
  6. The concept of separating functionality to reduce dependencies unexpectedly resonated with me. It used to seem simpler to combine similar functionalities to reduce code volume, but now it seems this approach increases complexity and internal cohesion, potentially causing more harm than good.

Overall, I’m very satisfied with the course. It seems like the best investment of effort over the past year. If you’re thinking of taking it but are unsure — go for it :)

25 August 2024 done meanwhile

My First Approach to Gen Models

I needed to quickly generate some images for a pet project. I grabbed the first tool at hand — WaifuDiffusion (a clone of StableDiffusion, but trained specifically on anime and manga).

Prompt:

A dimly lit, empty classroom with faintly visible music notes on the chalkboard. A young woman with long blue hair and blue eyes, is standing behind the teacher's desk, packing her things into a small handbag. She looks tired and worried.

Result:

Young woman

It seems like a great opportunity to talk about how far neural networks have come! The model instantly got the idea and decided to introduce into the scene... Hmm... A wise bearded man? Or perhaps it was suggesting that I should learn to appreciate unexpected surprises more?

I think WaifuDiffusion just wanted to brighten my mood. They say laughter extends life. In any case, I consider the first generation a success! But it definitely needs some calibration :)

25 August 2024 AI

Day Switcher for Obsidian

When you're actively working in daily notes in Obsidian, you often want to quickly peek into the note from yesterday or, conversely, for tomorrow. For example, when sorting today's tasks and wanting to postpone some of them for tomorrow.

I'm too lazy to type the exact date every time, so I wrote a script for this. It takes the note's date from its title (expects it to be in ISO 8601 format) and generates a tooltip with links to yesterday's and tomorrow's notes. The day of the week is displayed in the header for additional convenience:

Example

The script is written for the Dataview plugin since I'm already using it for other tasks. In general, it can easily be adapted for Templater, CustomJS, or even turned into a standalone plugin (again, I'm too lazy to bother with that).

If you plan to use it:

  1. In the noteLink() function, specify the path to your daily notes folder (currently, the path contains a 'Days' folder for example; I mean the path is indicated in the Daily notes/Template file location setting);
  2. Include the script in your daily note template (Daily notes/Template file location setting).

17 August 2024 Obsidian JavaScript

Clementine Will Remember That

When ChatGPT remembers a detail from a conversation for the future, it displays a "Memory updated" badge above its response. Like, got it:

Memory updated

Every time I see it, it makes me smile because it instantly reminds me of The Walking Dead and the meme “Clementine will remember that”. In that game, the characters surrounding the protagonist would remember his decisions, and it would influence their behavior. This included Clementine — a girl the main character saved at the beginning of the game.

Clementine will remember that

In the game, this mechanic was honestly implemented in a rather mediocre way, but when it comes to ChatGPT — it works. The attention to detail is so strong that sometimes I have to remind myself that I’m talking to a language model, not an extraordinarily attentive and very knowledgeable person.

9 August 2024 AI videogames

Make Window a Door

I was listening to Be Somebody by Thousand Foot Krutch yesterday and suddenly caught the phrase “you made my window a door”. I used to think that this idiom is rather funny: like, damn, the idea to replace a window with a door somehow sounds unsafe. You can fall from the tenth floor, you know?

At the same time, the song is wonderful and not about that at all! I got curious and started digging around to find out what meaning native speakers put into it.

It turned out that it is actually about two different positions: a passive observer and an active participant. That is, if there is a window in front of you, you only look through it at something or someone. But you can open the door and finally do something. Hence, “when I could only see the floor you made my window a door” means something like “when my hands dropped, you helped me up”.

By the way, there is another similar idiom — “to be a better window than a door”. The abstraction here is the same: if a person is like a window, and not a door — they hardly ever let people close to them, making passive observers even out of people very close to them.

4 August 2024 English

Yaga

I accidentally remembered that six months ago, one of my colleagues threw a link to Yaga into the work chat. It is a future (I guess) competitor of JIRA in Russia. Judging by the URL, the guys from Rostelecom are developing it. Here my curiosity was awakened — how is it there, did it take off?

Alas, but looks like nope. At least, the landing page has the “leave a request and wait for a response beep” vibe. Only a simplified version is available for smaller teams that I can't touch as well: being not in Russia and clicking on the “Start using” button leads me to a ban. Welp, next time, maybe.

The naming is clickbait, of course. But I’m not sure if it’s really a good choice. For example, “1C” may provoke forced jokes (One s! Odin's ass! Haha), but if you google this, you are more likely to find information about the platform or at least the vendor. Not a bunch of articles, fan fiction, fan art, or video games, as in the case of Yaga.

Moreover, some wrong associations come to mind. What does Baba Yaga reminds you of? A hut on chicken legs? It looks like an initially poorly designed application that was somehow remade right on production. A mortar? A crutch? Damn, if you look at it from the point of view of programmers — these are not red flags, but real scarlet banners fluttering in the wind :)

One more thing: I'm probably spoiled, but when I hear the word “Yaga”, the first thing that pops into my head is not a powerful witch from Slavic folklore, but disgusting booze from the 2000s.

Now Baba with Yaga are no longer redneck, but a patriotic programmer!

― colleague

29 Jule 2024 meanwhile

Ibrahim

Recently, I took a system analysis course, which was taught by the guys from the “School of Strong Programmers”. I have two goals:

  1. First, I need to calibrate. I handle a dozen tech stacks that have different tool sets and concepts of beauty. This, of course, is a great development, but it distorts the perspective: I am drawn to solve the next problem, starting with minor technical things, simply because I am good at it. Meanwhile, if you look at the problem a little from above, think about it, and draw some diagrams, you will get a better or at least more meaningful solution. So I want to convince myself to do this more often.
  2. Secondly, I need to learn how to write clear documentation for developers. In practice, I rarely get around to it, and when I do, I don’t have time to keep it up-to-date. In short, time is short, and I would at least like to do the paperwork somehow so that the reader grasps the idea more quickly.

The course itself is made in the shape of iterations: every week you are told about the same project that the main character of the story, Ibrahim, is trying to design (that’s him on the landing page in the link above). Every week, there are more and more problems with this project, and the solutions that dude comes up with become more and more intricate.

In addition, students are regularly assigned homework for another project with similar issues. It needs to be analyzed and designed again and again, taking into account the new knowledge and limitations gained over the past week.

So far, it's going great. The main concern is a lack of time. I read relatively slowly and try to take notes on the most captivating or simply difficult passages. Meanwhile, there is a lot of material in the course, and all of it is interesting, even if you count only the main part of the content.

In addition, if you go to the additional links, you can even take away the saints. It takes six months, no less. I tried to read them at least diagonally, but it turned out to be a damn bad idea. I ended up seeing the main character of the course in a street advertisement :)

7 Jule 2024 meanwhile

Singapore Doll

Is it possible to love your country's currency more than the people of Saudi Arabia? It is a rhetorical question: the answer is no.

I'm currently looking at the website of their central bank. The country's currency is the Saudi riyal, and the Central Bank sets rates for other currencies in relation to it. Consequently, there is no point in asking the bank for the rate of the riyal itself. However, the website calmly suggests choosing it twice:

The selection form

For your information, the first option breaks the website, and the second one pedantically displays “1” for any date.

Another funny thing: colleagues seem to store currency names as 14-character strings. Otherwise, it is difficult to explain why, according to their data, Canada uses not the Canadian dollar but CANADIAN DOLLA, and Romania uses mysterious NEW ROMANIAN L instead of its leu. However, these two are rather lucky: Singapore, for example, conducts payments in SINGAPORE DOLL.

22 June 2024 work

Non-Unique Metadata

Once again, I came across a nasty bug when the platform broke the data history metadata table.

Outwardly, it looks like this: you update the database configuration, and when you try to restructure, the error “The data history metadata table contains duplicate records. Delete the duplicate records” pops up. The platform does not offer any clear way to find such records.

The data history metadata table contains duplicate records. Delete the duplicate records

The problem can be solved at the database level. The table referenced by the error is _DataHistoryMetadata. It contains metadata versions of each object for which data history is being maintained. This allows the platform to understand what attributes the object had at any point in time if the data history is maintained for the object.

How does it work? Well, when the list of an object’s attributes changes (for example, an attribute was added to the catalog), the platform writes its metadata: specifically, it adds a new entry to _DataHistoryMetadata and stores in it the current list of object attributes, as well as the version number of this list (for example, when history is enabled for an object, the first version of metadata is saved, when adding some attribute, the second version is saved, and so on).

The platform also puts a mark in the created record that this particular version of the object is the most actual, and then removes this mark from the version that was marked as actual before.

So, the problem is that the platform sometimes forgets to take the last step, and two versions appear in the table at once, marked as current. The Designer understands this but cannot do anything.

The solution follows from the algorithm above: you need to find conflicting versions and revoke the mark of actuality from the one that is older. It is better to use queries: data history is often enabled for a bunch of objects, and the list of their attributes is constantly changing — in general, there will be so many versions in the table that the devil will break his leg.

If you also encountered this problem and are therefore reading this text, you can use the queries that I wrote:

  1. get-issues.sql checks that there is an issue: it looks for metadata versions that are also marked as actual.
  2. fix-issues.sql removes the actuality mark from those versions that are actually outdated.

Both queries are written for Microsoft SQL Server. If you use PostgreSQL, then here they are for this DBMS.

The queries will require a slight adaptation to a specific database: they use the _fld626 field, which is the data separator. In your _DataHistoryMetadata table, this field may be called differently, so you need to update its name to the current one. It will be difficult to make a mistake — the table has only one field with the _fld prefix.

P.S. Please bear in mind that the license agreement prohibits access to the database, bypassing the platform’s tools, so you can only go for such experiments if there are no other options left.

8 June 2024 PostgreSQL MS SQL

The Main Issue of UUID

I came across a good text about the main problem that UUID brings with itself. It is also relevant for 1C: all platform reference objects (catalog items, documents, and so on) have their own UUID. They are stored in a database, actively used in searches, and, of course, extensively indexed (with all the ensuing consequences).

1C tries to suppress the issue by creating consistent UUIDs. It may not be perfect, but overall, this thing works, and the indexes turn out to be more or less compact. In general, the community has been talking about this for a long time: for example, the old thread on Mista (though the conversation here quickly turned into a chicken coop, and out of six dozen comments, at most one and a half are on point).

P.S. The remark about the probability of creating two identical UUIDs in one database made me laugh:

As an aside, for those worried about collisions: you should take up the lottery, since winning the jackpot twice in a row is a much more likely outcome than your system ever generating two identical random 128 bit numbers.

2 June 2024 PostgreSQL

Screenshot With Sound

Recently, we came up with the idea of dividing the internal ERP into several independent parts and organizing data exchange between them. We discussed the outlines of the task, the exchange model, transport, and roughly agreed on deadlines — in general, we did what we usually do.

I created a task for the stuff. We give them names in English, so I wrote in the first wording that came to mind.

Cut My Life Into Pieces

The title came out with sound. Okay, this one is funny, but what should I call it then? Well, let it be Distributed Internal ERP. Abbreviated... DIE?

I let the first one be. Long live Papa Roach :)

20 May 2024 work meanwhile

Timesheet for Obsidian

I made another Obsidian plugin, this time for daily notes. Draws a nice report: what tasks I worked on, what I did, and how much time I spent. I tried to describe how it works in the repository; will be glad if it is useful to someone else!

Funny thing: for the examples in the README, I used issue numbers FBI-1, FBI-2, and so on. This isn't a reference to the X-Files or Twin Peaks — it's just the first thing that came to mind. The fact is that our internal project for the development of FirstBit ERP is called First Bit Internal, abbreviated as FBI. The main pool of tasks we work on lives in it.

We’re already used to it, but our colleagues outside the company always find our screenshots from JIRA or SonarQube amusing. Did you imagine that you were Agent Cooper? Well, I almost don’t even need to :)

12 May 2024 done TypeScript Obsidian work

One Query More, One Query Less

One query more, one query less — it doesn’t matter, people often say. Like, the main thing is that the query must be cheap: it doesn’t read too much, uses index, and so on.

This point of view makes sense, but mindlessly machine-gunning queries is a dangerous idea. Even if everything looks good at the moment, the system may change slightly in the future. And then a seemingly harmless patch will burn your production server to the ground right on Friday.

Let me tell you about one example from recent practice. There is an ERP that contains a table with payment stages for customer orders. One of these stages is prepayment; until it is received, you cannot create an order for the supplier.

Technically, the purchase order simply stores the customer's order ID; if the field is filled (that is, if the purchase order is created by the customer's order), ERP needs to read the payment stages of the customer's order and understand whether the purchase can be made.

It sounds elementary, but monitoring shows that the operation is slow as hell and eats up memory as if it were the last time.

Welp, let's go find out. We saw something like this:

825701 records

What do we have here? Instead of taking two or three stages of payment for an order, ERP reads almost a million! How this could be possible?

It turned out that the problem was with those purchase orders that were not related to customer orders at all. The developer considered that the logic for them could not be changed: the customer’s order ID is empty and the query will not find payment stages for this ID. This means that the same result will be obtained as if there were no query at all. And an extra query — well... One query more, one query less... Not a big deal.

The deal turned out to be big. The table of payment stages contained data not only for customer orders, but also for other types of documents. Their customer order ID field was empty. As a result, ERP, when trying to find payment stages using an empty customer order ID, unexpectedly found them.

The query read about a gigabyte of data and wrote it to a temporary table. A gigabyte was read, then a gigabyte was written... History hit the disk, the DBMS buffer cache, and other components of the system (even the network, which had to drive this gigabyte back and forth without any benefit).

Do you know what I think? If the result of a query is known, there is probably no need to do it after all.

5 May 2024 optimization

Foodiary for Obsidian

Following my first plugin for Obsidian, I released the second one a couple of weeks ago. Counts calories, proteins, fats, and carbohydrates in food. It helps not to overeat out of nowhere — it’s rather difficult to judge by eye how much you’ve eaten today and whether you can afford that donut.

In short, a useful thing if you:

  1. Fatty (like me)
  2. Want to stop being fatty (like me)
  3. You take notes in Obsidian (like me) 🙂

In fact, there is a lot of software for this task. I tried some of them but was dissatisfied: it either has terrible design, is bugged, or is constantly trying to sell me a monthly subscription. In short, it's more annoying than helpful. I wanted something native, built into the usual routine; so, if routine settles in Obsidian, then the solution seems to suggest itself.

You can install the plugin directly from the program — the developers have already approved it. Otherwise, everything is simple: you write in a daily note what you ate and how much it weighed, and you receive a simple table sorted by calories with numbers by proteins, fats, and carbohydrates.

There are examples in the repository at the link above.

14 April 2024 done TypeScript Obsidian

Fastimer's Look

I just implemented Fastimer's rendering through callouts: this is an Obsidian mechanic that allows you to turn an ordinary quote into a designed block of text that attracts the reader's attention. You've probably seen blocks like “advice” and “pay attention” — these are callouts.

You can read more in Obsidian Help.

As a result, the timer now takes on a different color depending on the state: blue for an active fast, green for completed, and red for a failed one.

In addition, I made the text more compact and worked on styling:

Example

It turned out to be way nicer than the block of preformatted text as it was before.

9 Marth 2024 Obsidian TypeScript

Small Pleasures

I was wasting time at the supermarket checkout: it’s evening, there aren’t many customers anymore, but the elderly cashier is clearly tired and isn’t in too much of a hurry. Standing in front a tall, gray-haired man with a luxurious beard whiles away the time studying the rack of chocolates next to the cash register.

Finally, he takes a Snickers, twirls it in his hands thoughtfully. Then he pushes two more towards himself and, broadly, with visible pleasure, smiles into his mustache :)

6 Marth 2024 meanwhile Georgia

Not Only Everything

This commentary in the documentation for the WriteJSON() method of XDTOSerializer is enviably deep, I would say:

Not only everyhing

Well, yes. The method dumps data into JSON, not XML. So it’s hard to argue that not all value types can be packed into XML using it (to be precise, none). Such a pity that there is an obvious copy-paste from the help for WriteXML() further in the text! I almost decided that it was an Easter egg from the developers :)

25 February 2024

Earlier Ctrl + ↓