Thursday, August 29, 2024

Data Transfer Cost due to Internal ALB and NAT Gateway in the Same Subnet

 This is what I heard from my junior after he moved to a different company. They found an issue with data transfer cost due to internal ALB and NAT Gateway in the same subnet. Apparently, the internal application sends data to the ALB and it's being processed by the NAT gateway as well. I'm not exactly sure how it works, but it was a bad networking. They removed the NAT gateway and just let the ALB managed the traffic and save cost. 

Thursday, August 22, 2024

Python Package not Found

 Ok, this is a rookie issue. I had virtual environment created, activated and the package installed for that virtual environment, but somehow I bumped into this error:

Import could not be resolved [Pylance]

Turns out to be the interpreter is pointing to the wrong one in my VS code bottom right. Changing it to the one in virtual environment fixed that.

Cython Compile Error on Python 3.12 on Windows 10

 I have Python 3.12 installed on my Windows 10 machine. I tried to install a package using Pip. Apparently, the package contains Cython and needs to be compiled. However, the compilation failed with the following message:

Cannot open include file: 'io.h': No such file or directory

Ok, not a problem, I just go to Visual Studio Installer and install Desktop development with C++ package.


That fixed the first issue. But installing the package still failed. This time the error message is:

'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2

To fix the above, I had to downgrade python to 3.10 and the package is installed properly.





Tuesday, August 20, 2024

SL Command in Linux

 Most of the time we have to type fast, especially in today's world where speed is life. So, we are bound to mistype. In Linux, one of the commonly used command is "ls", so to "train" user to correct that, an "sl" command is created. SL stands for Steam Locomotive. Check it out in your Linux distro, search, install, and run the command and it will show a moving locomotive.


Thursday, August 15, 2024

Outlook Reminder doesn't Dismiss Old Meetings

My outlook somehow keeps reminding me on old meetings that occurred weeks before. Dismissing all or each one doesn't work. It keeps coming back. I tried the suggestion to remove cache, clear reminders and none works.

Finally, the only one that works for me is to open up the details of each one of the old meetings from the reminder and then dismiss them. They never showed up in the reminder ever since.

Cheap Way to Receive Email on Custom Domain

 I was looking for a budget friendly way to receive email on my custom domain. So, let say, I own example.com and I want to receive email on receive@example.com. 

As I did my research, I found various way on doing it:

  1. Just forward it. My domain name vendor apparently comes with free email forwarder, so I forward it to my non-custom domain email such as gmail.
  2. Just forward it (DIY). This is also a very cheap alternative and low cost. One way is to forward it through AWS SES. One such project is: https://github.com/arithmetric/aws-lambda-ses-forwarder
  3. Receive it through hosting. I thought about this especially when I already paid for hosting service, usually it comes with mail server for free.
Of course, we can always subscribe to some email service, but it will cost more but it has more features too.

Reviving Samsung Galaxy Note 4

 I have an old Samsung Galaxy Note 4 that was not turning on for a long time now. Out of curiosity, I read about it came back to life by putting it in the freezer, so I gave it a try. I took out the battery, put the phone in a ziploc bag and put in the freezer for at least 8 hours (so I can sleep or work through it).

I also make sure the battery is charged separately since I have a battery charger. After 8 hours, I take it out, put the battery in, and surprised that it turns on. However, it won't turn on anymore after I turn it off, so I placed it into the freezer the second time and it works again. My guess is the freezer probably takes some humidity out from the components and allows it to work better.

Wednesday, August 14, 2024

Jetpack Compose Infinite Recomposition Loop

 I finally got some time to get back to mobile development after many years. And Android has a new way to create an app with Jetpack Compose. At a glance, it is amazing, I managed to create a complex app much faster than using XAML, yep, you read that right, that's how I used to do it.

All is well until I encountered infinite loop when trying to remove item in a mutableList displayed using LazyColumn on a button click. Basically, the button click somehow causing a recomposition and then the recomposition retrigger the button click event again and again.

But it only happened when I remove an item, adding an item is fine. Here's the example of initial code:


data class Pet(var timestamp: Instant, var name: String)
  
@Composable
fun Screen() {
    val pets = remember { mutableStateListOf<Pet>() }
  
    fun addPet() {
        pets.add(Pet(Clock.System.now(), "Pochi"))
        if (pets.count() > 5) {
             pets.removeAt(0)
        }
    }
  
    addPet()
    
    Surface {
        LazyColumn {
            items(items = pets,
                  key = { it.timestamp.toEpochMilliseconds() }) {
                Text(text = it.name)
            }
        }
        Button(onClick = { addPet() }) {
             Text(text = "Add")
        }
    }
}


I did some searching, even using ChatGPT, but what helps me understand is this article:


Apparently, I accidentally did a backward write. I did a small experiment and the following code doesn't cause recomposition loop:

data class Pet(var timestamp: Instant, var name: String)
  
@Composable
fun Screen() {
    val pets = remember { mutableStateListOf<Pet>() }
  
    fun addPet() {
        pets.add(Pet(Clock.System.now(), "Pochi"))
    }
  
    addPet()
    
    Surface {
        LazyColumn {
            items(items = pets,
                  key = { it.timestamp.toEpochMilliseconds() }) {
                Text(text = it.name)
            }
        }
        Button(onClick = { 
             addPet() 
             
             // Moved from addPet()
             if (pets.count() > 5) {
                 pets.removeAt(0)
             }
             
             }) {
             Text(text = "Add")
        }
    }
}

Both snippets look very similar especially on what the button click will do. However, on the first snippet, pets.count() causes state read due to addPet() call and thus button onClick will cause a backwards write with pets.add().

Now the question is won't moving the pets.count() to within button onClick cause backwards write as well?

The answer is, it won't, because the recomposition scope is different. This article will be helpful in understanding more on the recomposition scope. The key is "Deferring state reads will ensure that Compose re-runs the minimum possible code on recomposition"


By moving the pets.count() to the onClick, we reduce the recomposition scope to only the button and because of that, the recomposition doesn't try to recompose everything including the button and its onClick which can cause recomposition loop because onClick will be triggered infinitely.