what can go wrong and how to fix it

What was the task

So, the task is to validate the UI depending on whether we have a log file in the file system or not. A 10-minute task, I thought then.

I wrote actor and a method in it that goes to the file system and checks two parameters:

  1. The very presence of a file by a certain “tail”, that is, the final file name.

  2. “Empty” file. That is, the method checked that the file I needed was created and its size ≠ 0.

I chose actor for a very logical reason: to avoid a data race. Otherwise, we could simultaneously write and read along the same root path. And everything worked for me! The UI—buttons for sending and deleting logs—was validated in both directions.

The method in the ViewModel looked like this:

I submitted the feature for testing and forgot about it. As it turned out, in vain.

Something went wrong

After some time, Q&A returns this task to me and says that validation does not work on one of the devices. I checked it myself – everything works. I started looking for errors in my implementation. The next day, another fellow developer wrote: it didn’t work for him either. I checked it on my other devices – it works.

After that, our team assembled a test group and found out that out of about 15 test models on four random devices (different iPhone models and iOS versions), validation did not work. To say that I was surprised is to say nothing.

I started digging. The button to send logs was invalid, so I couldn’t view them on devices where the feature didn’t work.

How I tried everything and found the reason

I searched for the reason for several days. And now I was able to reproduce the problem on the simulator. Then I identified a list of possible problems that could lead to this behavior:

  1. Synchronization problem. Between the creation of the file (turning on the tag) and the recording of logs, time should pass – a few seconds.

  2. The problem is in the UI itself. That is, with its reactive update.

  3. Data race problem.

To test these hypotheses, I made a delay between creating the file and writing to it. Didn't work. I rewrote the actor's method for receiving a file and checking its size, wrote custom Combine Subjects – in general, I did my best. But on some devices the validation still did not work. At the same time, a log file was created in the file directory, but it was empty. It seemed like I had tried everything.

After a few more days, I despaired and simply hardcoded the initial validation of the button so that after scratch install it would be valid. Then I started the simulator. The button is valid, the file is created, and it is not empty – a great solution (not). Then I removed the hardcode and started the simulator again. And then a miracle happened!

Validation began to work as it should in both directions without subsequent hardcode! That is, when we created a file and immediately wrote to it, the button for sending logs was validated – as was the button for deleting logs when the file size was 0.

Now it is 100% clear that the problem is in the file system. That is, after installing the application, some users could not send logs because the button was invalid. In this case, a log file is created when the engine is turned on, but nothing is written to it.

The reason for this behavior is the incorrect operation of the file system update after creating a file and instantly writing to it. And this is how I solved this problem.

In didFinishLaunchingWithOptions we create an empty file (absolutely any) and after a couple of seconds we delete it. This is necessary to forcefully update the file system and prepare it for work.

Method for creating and deleting an empty file in AppLogsService:

Then – a challenge. I always leave comments on such niche cases:

To remember

An empty file is created at startup because the main log file is created by enabling the corresponding option in the application settings. If at the start you create the file you need so that you can write to it later, then this method most likely will not work for you. Because you simply won’t have such a problem. But if suddenly you have it and it is associated with recording logs, and not any other data, you can try calling the flushLogs method – the name may differ from library to library. This needs to be done after you have started interacting with the file system – for example, you have created a file, that is, you have called the file system update.

This is the solution I came up with – on the one hand, it’s a crutch, but on the other hand, it’s quite usable. I hope this article will help save a lot of your time on research and solving the problem. Write in the comments if you have encountered this, and if so, how you solved it. You can write about similar cringe problems in general – it will be interesting to read!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *