Have you ever taken the wrong freeway entrance? You need to drive to the next exit to turn around, but you hate every inch of travel because you're going away from your goal.
― Andy Weir, "The Martian"
Programmers have exactly the same emotions when they spend a long time working on something. They suddenly realize that part of it should be designed differently. Moreover, this is exactly what you have to do since it solves several problems at once. This is where technical debt is born.
However, right now you don’t change anything but continue to work with the part of the code that already exists. After all, you are professional, and you have a release date! You have to make it on time and then pay the debt, but you hate every inch of code you write because you're going away from your goal.
2023-11-14 09:34:10 code smell
Some time ago, I was setting up Swagger for the internal API. While I was fiddling around, it became clear that some functionality did not need to be included in the documentation. I was looking for a way to do this without crutches and came across a funny question on GitHub.
What's funny, you ask? Well, I involuntarily remembered Mista. Among 1C developers, this is synonymous with the word “toxicity”: if you ask anything there, you get a bucket of slop by the collar instead of an answer. Here, of course, everything is not so neglected, but holy crap! These persistent guys who referring to the 14-page manual made me laugh a lot.
One thing is good: by the end of the thread, there appeared a brave rebel who just answered the question. They, like, named the required parameter for a FastAPI method's decorator, which is not supposed to be shown in the documentation. No links — could you imagine?
Not all heroes wear capes, I would say.
Making a password recover function via SMS for our customer portal. Got to the Twilio documentation related to alphanumeric sender ID support in different countries; this feature allows you to send messages so that the recipient sees not the sender's number but something meaningful (a company name, for example).
The feature is regulated differently everywhere: in some countries it just works, but in others registration is possible or even required.
Well, let's take a look:
- Portugal: yes
- Puerto Rico: no
- Qatar: yes (with registration)
- Reunion: yes
- Romania: yes (with registration) (but be afraid of Dracula)
I don’t know how else I can explain this cemetery.
UPD: Found the answer. Grave crosses mean you have to pay $700 to register.
To be frank, I like the explanation about Dracula much more.
Released a new version of my console timer for intermittent fasting. I wrote this app about a year ago, when I was once again upset by the Zero application for Android: some very primitive functions (like viewing a specific interval) did not work. Oh my gosh, guys, you had one job!
The main difference between 1.3.1 and 1.2.3 is that the console menu has been cut to hell in favor of the good old arguments and options. The menu concept looks convenient only if an application has few features. However, as soon as you take a step forward, the need to answer a list of questions each time you need something starts to irritate you.
I forgot to tell you that a couple of months ago I posted on GitHub an example of code that limits the number of requests per second that can be sent to some third-party resource from a 1C:Enterprise infobase.
The problem is solved through a constant that stores the date for the current second and the number of requests that have already been sent. Clients who run into a limitation are waiting. The queue is not guaranteed, but is more or less respected.
It can be useful for managing the load on an external system. For example, the cloud-based Bitrix24 requires not to send requests to it more than twice per second, and if you exceed it, it bans you.
The repository login form of the current platform (184.108.40.2063, to be precise) launched with the English interface:
You had one job, literally.
I heard some rumors that development of the Designer was stopped largely due to the monstrous amount of technical debt that slows down any new features. But here are interface glitches right on one of the first application windows! Curious how it got through the build tests.
Maybe they don't exist at all.
2023-05-14 10:15:16 1С
Recently, I was working with vocabulary in an attempt to describe my latest adventures to an English-speaking friend and got to know about the colorful idiom “to go postal”. It means something like “go crazy with anger”; appeared somewhere between the 80s and 90s in the USA after a series of rather insane incidents in which postal workers went crazy and attacked people around, including colleagues and visitors.
The expression sounds funny at first glance, but the story behind the scenes is painfully gloomy. I think I will continue to use the good old “to go ballistic”. Literally, “get angry that strong so you become a rocket which lost control”. Or, to simplify, “explode with anger”.
By the way, there are similar rocket-like connotations in Russian, but for some reason they are about a more manageable cases. Mostly, they implies something like "the fire in the ass was so damn strong that the poor guy left Earth and successfully landed on Mars". Sounds a bit better than a simple explosion — you didn't completely waste the precious resource, at least :-)
2023-05-08 09:12:34 English
An important detail: the CallPause method is not available in a client-server call; when a client calls a server method in which CallPause is called, the exception "Cannot call the CallPause method in a client-server call" will be thrown.
CallPause Method (RU)
What a strange restriction, to be frank. On the one hand, an experienced developer will not make an intentional pause in a client-server call anyway; on the other hand, whoever wants to make it makes it anyway (by checking time in a cycle, for example). Does security by obscurity worth the efforts?
At best, some junior will catch this exception, think “welp, it looks like I'm doing something wrong” and move in the right direction. However, putting the restriction on the platform for the sake of this case is like firing a cannon at sparrows. You know what? Let's implement a number limit as well — like, no more than 1000 pauses per session, otherwise users will suddenly think that the program is too slow :-)
2023-04-30 14:30:43 1С
The daily award for the most philosophical code goes to the author of this elegant way to check that two boolean variables are not equal to each other:
If DataStructure.Property("AmountVATIn") And ((DataStructure.AmountVATIn And NOT SearchPriceIncludesVAT) OR (NOT DataStructure.AmountVATIn And SearchPriceIncludesVAT)) Then Price = RecalculateAmountOnVATFlagsChange(Price, DataStructure.AmountVATIn, TabSectionLine.VATRate); EndIf;
I'm thinking of adding something like “And Not (DataStructure.AmountVATIn = SearchPriceIncludesVAT)” here to spice it up with a subtle note of insanity.
I like to notice things in the world around me that clearly have a story behind them. In video games, this is called “environmental storytelling”: they don’t tell you the story directly, but if you look around, you can guess which gun was hanging on the wall and who fired from it.
For example, I recently celebrated the company's 10th anniversary with colleagues at a local golf club. Balls had to be sent flying from the second floor; there are no railings for obvious reasons, but a net is stretched in case someone loses their balance.
Why are you talking about this, you ask? Well, there are warnings on the walls: jump into the net of your own free will and pay ten thousand dirhams. Recording this heroic leap of faith on camera is fine as well, just prepare five thousand more.
Do you feel the smell of a good history?
Another example: once flew to Turkey to rest and decided, just in case, to look through the rules of the airline (what can be taken on board, what can not). Among the list of items prohibited from being carried on board, I found “steel spear” and “steel flail” 😬
UPD: Another great example from somewhere on the Internet.
Usually the idea of developing is simple: the faster it works, the better. For example, the more requests an application manages to execute per unit of time, the faster the task for which these requests are needed will be solved.
However, it also happens the other way around: you need to reduce the number of operations that a program is able to perform. Let's imagine we exchange data with an external service and it bans if we hit it with requests too often. For example: the cloud version of Bitrix24 requires sending requests to it no more than two per second.
Here is an implementation of such a slowdown, which I wrote last week. There is no queue support; the main solved problem is to execute as many requests as possible without going beyond the limit (taking into account the fact that requests can be made from different sessions).
This week, I developed a REST service to set up our service manager (this is a configuration for managing a 1cFresh instance). Deploying the development environment is a regular task for us, and every time the manager's database had to be tuned by hand: tweaking the storefront, changing application addresses, overwriting scheduled tasks, and so on.
The implementation was simple. Come up with a JSON structure, write a parser, find a code in the configuration, make it work by external call, and make sure you don't break anything. Routine work, in general, but I love to do such things from time to time: I mean, to look around and try to figure out which of the daily tasks is annoying enough.
This one is a good example. To be frank, setting up the Service Manager wasn't a problem (launching the app and fiddling with the settings), but it was a thing to pay attention & spend time to. What do we have now:
- There is a JSON file with all the settings;
- There is a REST service for its processing;
- There is a script that will put the first into the second;
- There is a pipeline that will do it all by itself.
In short, a boot was rubbing a leg, and now it isn't. Yahoo!
The colleague grumbled that if you think like that, then the configurator will be Zhiguli, and the EDT will be Kama1 (this is an electric car that has been developed somewhere in the depths of KAMAZ for many years and still can’t gather strength and, finally, show the wonder to the world).
Well, I try to look at things with optimism. I think the platform and its IDE are such haul trucks. No one in their right mind rides them on household chores, but these beasts are irreplaceable on a cut!
2023-02-20 09:00:00 1С
The more I explore the Bitrix24 REST interface, the more I am amazed at how different its developers mindsets are. It is expressed in different ways.
Let's take, for example, the interface of deals and product rows related to them. There is no amount field in the table of the products: like, you need the amount for each line – count it yourself, that's it. However, there is the amount field at the document level! Can you guess what the field is named?
AMOUNT? DEAL_AMOUNT? DOCUMENT_AMOUNT? AMOUNT_TOTAL?
You didn't guess, the correct answer is OPPORTUNITY.
Where'd I digress? Yeah, a product line. It contains a product, a VAT rate, and a unit of measure. All three entities are completely independent: each has a separate table with auxiliary information and its own unique identifier. It is logical to assume that identifiers are stored in the product line: product ID, VAT rate ID, and unit ID.
Well, yes, but no. The product field actually contains ID, but for the VAT rate field it's a rate value. What's for the unit of measure field? Well, it contains a measurement code ¯\_(ツ)_/¯
Database normalization? What? What does it mean? Back off, man, you're distracting us from work.
For the last month I have been rewriting standard data exchange between FirstBit ERP and Bitrix for a client task. Co-workers doing the same on the Bitrix side prepared a huge mapping for this case: which field on the 1C side should be transferred to which Bitrix field (and vice versa).
They published this mapping as Google Docs tables, in the interface of which you can see users using any document at this moment — both logged in and anonymous. Anonymous ones traditionally are displaying as animals.
Colleagues generally prefer to work anonymously. As a result, I definetely used to feel like a Disney princess: you start working in the morning, and anonymous quokkas, penguins and chinchillas roll out from everywhere :-)
Slack, of course, is a thing to scold. For being slow, for having bugs, for notifications. However, I just love his stubs in case there are no new messages.
Look at this cuteness:
Why do we need psychotherapists at all?
Geez-Louise, Slack, hold on. You're not the first who advices this, believe me.
2022-08-25 19:02:53 meanwhile
Let's speak a bit about organization of the code. If you need to describe a set of objects with common properties, think about whether this description should be divided into separate methods, each of which intended to describe one specific object?
Let's look at this example — a method that describes tabular parts of documents suitable for some task:
SupportedTypes["Document.SupplierPricesEntering"] = "Prices"; SupportedTypes["Document.OpeningBalancesEntering"] = "CustomerAccounts,VendorAccounts"; SupportedTypes["Document.Requisition"] = "InventoryAndServices";
Everything seems fine, right? Descriptions are there; tabular parts are listed; splitting them by comma doesn't look expensive at all.
However, there are many documents in the method. Eventually, some colleague (or you) will need to refer to another tabular part of the document, which is already mentioned in the method. Something will distract they, they will forget to look for an existing line and something like this will turn out:
SupportedTypes["Document.SupplierPricesEntering"] = "Prices"; SupportedTypes["Document.OpeningBalancesEntering"] = "CustomerAccounts,VendorAccounts"; SupportedTypes["Document.Requisition"] = "InventoryAndServices"; <...> SupportedTypes["Document.OpeningBalancesEntering"] = "PayrollDeductions";
As a result, a part of description will be erased, and it's good if the related functionality is covered by tests.
Conclusion? Well, you can write a helper method that will take the document type and the name of one table part as input. The helper will add items to the SupportedTypes map and ensure that the data already added is not lost.
However, if you need a better solution, then consider doing as I wrote at the beginning of this note: split the method into auxiliary methods. One method contains description for one document only (for all its tabular sections). Something like:
Procedure AddOpeningBalancesEnteringDocument(SupportedTypes) TabularSections = New Array; TabularSections.Add("CustomerAccounts"); TabularSections.Add("VendorAccounts"); TabularSections.Add("PayrollDeductions"); SupportedTypes["Document.Requisition"] = StrConcat(TabularSections, ","); EndProcedure
What do we get here? Firstly, nobody will accidentally erase the description of the document. Secondly, SonarQube will be pleased: it is highly likely to begin swearing at repeating literals with the names of tabular parts, if the helper is implemented instead of code splitting.
2022-08-07 19:04:51 1С
Someone told me about the Croatian comic strips NOT/BUT at the beginning of last year, when I was seriously learning to draw. Each strip there is about some kind of traumatic or simply gloomy thought that comes into the artist’s head while working. The idea is to push a reader in the right direction and give them a more practical perspective on the situation they're in.
I quit drawing a year later, at the end of February: it became clear that I no longer had time for a hobby. But comics are completely universal; look through, even if you have no idea what a kneaded eraser is :-)
All these endless soul-searching are well known to any professional, and the way out of them is not always obvious. Especially if you are angry, tired, and the deadline for the project expired somewhere last week.
Oh, shoot! Just watched the video and realized that I got used to writing OK in morning statuses when asked “how do you feel today”. Like, everything is normal with me, I'm alive and doing well, nothing affects my work, etc.
Now I'm afraid to guess what colleagues thought about me. I hope they also did not know that okay in the answer to such a question does not mean okay at all :-)
The other day, I was working with cookies in one of my scripts. While searching for the optimal solution, I came across an absolutely charming (100% working, by the way) tip from StackOverflow:
You can get a CookieJar object from the session with session.cookies, and use pickle to store it to a file.
So, literally: keep your cookies in a jar, and to store them, pickle them. The jar with pickled cookies, by the way, can be put on the shelf later.
How can you not love python after that, huh?
P.S. While writing this post, I got curious – why pickle and not serialization? So, briefly: this is the way.
2022-05-28 21:34:38 Python
Earlier Ctrl + ↓