Akash's Blog

_

Monday, January 13, 2025

How Stackoverflow helped me?

Introduction

Stackoverflow has been part of every programmers day to day work. From finding solution to the errors, looking for best approach of the solution or just helping other fellow programmers on the internet, stackoverflow is an excellent website. 

In the era of two poles of internet search nowadays, ChatGPT and Google Search, it may seem that stackoverflow is loosing it's charm. I have been a user for a decade and I really enjoy reading questions and answers, not necessarily I am actively contributing the way I used to do earlier but still I find is truly valueable for learning and understanding the concepts. 

Having said that, the stackoverflow community has been a great company to be with so that you can ensure continuous learning.

How did it helped me?

Stackoverflow is the reason I managed to grab my first job, I knew nothing and I know nothing. When I signed up, I did all the mistakes that any new member would do, try to answer questions without clear explanations, impulsive voting and flagging, focusing on gaining reputation rather than helping the people etc.

However, I stick to it for longer and slowly kept on improing the way I answer the questions and primarily focused on helping instead of just answering the questions for the sake of gaining points. In a long term it helped me in following ways and most probably to anyone who actively contributed for a year and so,

  • I started paying much more attention to the problem rather than solution.
  • I understood the value of community and open source.
  • I learned to explain things better.
  • I gained confidence to build things on my own. etc.
Initially you may feel bullish when you focus on reputation and badges but gradually you realise that the quality answers and genuine help can take you far instead of reputations and badges. It doesn't mean reputations and badges are useless but it simply means that these should not be your driving force for contributing on Stackoverflow.

Where am I currently?

I no longer actively contribute on Stackoverflow now but I do regularly read interesting questions, drop in comments, help community in any possible way I can do and even answer question if I feel to. 

Following is my Stackoverflow flair,


profile for Akash Thakare at Stack Overflow, Q&A for professional and enthusiast programmers

Is it still worth?

For anyone who is in to programming should contribute to it. You can learn from the experts directly, get into discussion with them through chat, comments, questions and even answers. It surely enhances your knowledge. You don't need to invest whole day but couple of hours of contribution in a week can make a huge difference to your overall programming skill which I can surely guarantee. You just need to remain focused into area of your interest for longer rather than reading anything and everything.

Summary

Stackoverflow is an exceptional place to be if you are in programming and software developement in general to stay connected and updated about the tools and technologies which are making difference to the world. Do not rush to gain more reputations and badges but stay aligned on the path of help and support. ♥️

Thursday, December 26, 2024

AWS Cloud Cost Optimization

Introduction

AWS Cloud is one of the biggest cloud player which has captured more than 31% of the cloud service market. The cost of the services is majorly on usage based, the more you use the more you pay. We as an individual or as an organization need to understand how much we can optimize the cost when it comes to AWS because there can be multiple ways to achieve desired results but we are specifically looking for most optimal way.

In many cases we can save cost by taking necessary actions, however, it’s important to understand that saving cost should not be the first focus. It can come on the way to building it or even it’s ready and now we have some dedicated time to attend the cost related aspect of it.

Pricing in AWS

This is what AWS say about pricing,

You pay for the service you need, for as long as you use them, without compex licensing.

We should understand the “actual” need and “probable” usage before deciding the components and their capacity in cloud service, however, many of times these are two unknows which we can not confidently claim from the start. We can start with a minimal infrastructure and make it flexible to scale which is usually doable in Cloud environment.

High cost is not a bigger challenge if the usage also brings high value and returns for the business which is usually the case, the more usage is the more business value it should extend at the end of the day.

We can also calculate the price beforehand using AWS Pricing Calculator.

Ways to save money

There can be several ways which you can use to cut down the overall cost. Not all of the options will work for you but based on you current structure you can take up one or two options which can save you some bucks.

When it comes to cost we should also consider the cost we need to pay to the person who is taking care of this optimisation. Someone in the team took that responsibility and spent 20 hours to reduce 1000$ per month and the person got paid 30$/hour is a still a good deal.

Service

Choosing the right service for the job is very important when it comes to cost. There are certain services in AWS which you can choose for the same sort of job. There are many options for same purpose, for example, S3 and EFS you can use for storage and both may fulfill the requirement. However, the cost different is significant, for 1 GB of storage S3 can cost around 0.03$/month while EFS can cost 0.36$/month (in US East - N. Verginia).

Ofcourse this doesn’t mean you must choose s3 over EFS, both have their right use cases to serve. We need to understand which one we can pick and atleast review the cost as well before deciding the service to use.

Capacity

Capacity of the instances we are using in infrastructure makes a huge difference in billing. We can typically guage the machine requirements early based on the processes that we are planning to run on these machines. We usually know beforehand about whether it’s computation heavy or memory heavy operations, we usually know approaximately how much primary and secondary storage is required.

There are multiple types of instances available, we need to review our need and find the most suitable one with required configurations.

Details of all instance types can be found here.

Even though I specifically mentioned EC2 but it applies to RDS as well. Similar strategy can also be applied while deciding S3 storage tier and even the bucket policies to move between tiers for the sake of cost.

We can also review this in AWS Cost Explorer which can help in right sizing the instances.

Reserve

Choose reserved instances over on demand instance if we are sure that we will need them for atleast year or ever more than that. Reserved instance pricing is locked in and not completely based on usage, while on demand will be billed on usage. Ultimately, you end up saving upto 70% for 3 year term.

If we choose reserved t3.large instance for three years vs on demand instnace the monthly expense reduces by 50%. This difference will increase for high end instances upto 75%.

Alerts

We can enable the billing alerts based on the billing metrics so that in advance we get to know about the possible cost for given month. We can get an estimation in advance so that we can prepare and even take action to reduce the cost if possible.

Auto Transition

There are different options available in AWS to save money by shifting to tier as per the user. S3 Intelligent Tiering is one of the good example. It automatically detects the right fit for the object and moves it to most cost effective storage. Not necessarily this will fit all the usecases but we should explore such options for the service so that we don’t miss an opportunity to save money.

Review & Clean Up

Regular review and cleaning up unused resources may look unproductive or boring but 30 minute connect every month or quarter can definitely help to save a lot of money. Work pressure or busy schedule may pile up some unused ec2 machines, volumes, buckets etc. which we should regularly keep in check.

Alternative Cloud

This is not an option all the time but nowadays most major cloud provider services are durable and robust, if cost can be major factor, don’t stick to one cloud provider and explore other alternatives which can be a huge saving in a longer run, rest assured quality and performance is not compromised.

Conclusion

In current situation of booming cloud services and competitive environment between cloud providers, we should be vigilant about the different factors in the service that we consume and the long term repurcissions, when it comes to cost. There are several ways which we can try to cut down cost as much as possible without compromising on the quality and performance of the system. However, being ignorant about cost and pricing may end up with wasting your money which could have been utilised better.

Saturday, October 19, 2024

Observer Pattern

Observer pattern is widely used in many real time applications. It is one of the behavioural design patterns. In this post we will try to understand it and try to answer questions around it.

Let’s understand it with an example of stock market.

Basic idea is to observe something and get notified based on some condition so that observer can take necessary action accordingly.

With following Java program it becomes a bit more cleared on how this design pattern fundamentally works.

class Stock {
    String name;

    double price;

    public Stock(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

class StockMarket {

    private List<Stock> stocks;

    private List<StockObserver> observers;

    StockMarket() {
        observers = new ArrayList<>();

        stocks = new ArrayList<>();
        stocks.add(new Stock("Apple", 1000.23));
        stocks.add(new Stock("Google", 1000.23));
        stocks.add(new Stock("Microsoft", 1000.23));
        stocks.add(new Stock("Facebook", 1000.23));
        stocks.add(new Stock("Tesla", 1000.23));

    }

    public void start() throws InterruptedException {
        Random random = new Random();

        while(true) {
            Thread.sleep(1000);
            Stock stock = stocks.get(random.nextInt(stocks.size()));
            stock.price = random.nextDouble();
            observers.forEach(o -> o.movement(stock));
        }
    }

    public void register(StockObserver observer) {
        this.observers.add(observer);
    }

}

interface StockObserver {

    void movement(Stock stock);

}


class Trader implements StockObserver {

    @Override
    public void movement(Stock stock) {
        System.out.printf("%s stock price %f\n", stock.name, stock.price);
    }
}

Note that the StockMarket is completely unaware of the underlying observer. Any class can be a observer not necessarily it to be a Trader. However, every Trader will be a StockObserver by default.

Consider a scenario where a Trader is interested in specific stock and not all stock. We can think of two options here,

  1. StockMarket can register Trader for specific Stock.
  2. Trader can act on specific Stock and ignore the other movements.

Which option is more suitable here and why?

Preferred choice may be first one as it stops flow of unneccessary information to Observer which they are not interested in and saves function calls.

What if StockMarket is overloaded with lot of observers?

Considering the example, there can be lot of Traders observing the stock market and wants a real time information. For each and every stock the pattern used will not likely going to scale. It may work but it may end up with higher latency.

What if one of the Observer call fails!?

All the subsequent observers should get notifications. Otherwise we may need to perform check to see whether the observer is active or not before notifying. In above example, if any of the observer fails it will not notify remaining observers.

Should StockMarket be responsible for notifying observers?

That’s a valid question. It can be moved to separate class to filter out events and notify to respective observers.

This is pretty simple implementation of the observer pattern. We may need to look into other aspects of the system to deal with the issues arising in current design. For example, rather than immediately updating we can build a queue to fan out. But that’s not the solution in all use cases. We need to take a wholestic view of the business and system requirements into consideration to decide the possible approach.

Summary

The observer pattern is a behavioural pattern which can be used to notify one or more observers of the subject in case of any state change. It’s crutical to understand the scalability, performance concerns and heavy dependency on observer interface before adapting this pattern on a large scale use case.

Saturday, September 28, 2024

Platform vs. Virtual Threads

This blog post is a raw comparison of platform and virtual threads. We will use both the types of threads and see how they behave and perform.

It is important to note that the execution time and other matrics may vary system to system, however, it can definitely give a rough idea about the overall picture. We will try to keep this comparison as fair as possible, if I fail to do so, feel free to post comment below.

My System

  • MacBook Pro
    • RAM 16 GB
    • Processor 2.6 GHz 6-Core Intel Core i7
  • Java 21

Time to start

Platform Threads : 21 ms

private static void platform() {
    long start = System.currentTimeMillis();
    for(int i = 0; i < 100; i++) {
        Thread t = new Thread(() -> System.out.println(Thread.currentThread().getThreadGroup().getName()));
        t.start();
    }
    long end = System.currentTimeMillis();
    System.out.println("Platform : " + (end - start) + " ms");
}

Virtual Threads : 18 ms

private static void virtual() {
    long start = System.currentTimeMillis();
    for(int i = 0; i < 100; i++) {
        Thread.startVirtualThread(() -> System.out.println(Thread.currentThread().getThreadGroup().getName()));
    }
    long end = System.currentTimeMillis();
    System.out.println("Virtual : " + (end - start) + " ms");
}

For 100 Threads the difference doesn’t look significant. However, If I increase the count of threads from 100 to 1000 the difference increases drastically.

  • Platform Threads : 235 ms
  • Virtual Threads : 29 ms

Reason

Even though the time taken to initialize threads are different, underlying operation would have taken same amount of time. Virtual threads enables better utilisation of the resources compared platform threads (virtual thread actually uses platform threads internally).

The major difference here is that the platform thread managed by OS are blocking, but virtual thread which are managed by JVM are non-blocking. So, in case of virtual thread it will wait for the platform thread to be available but won’t block the execution of the program.

Speed

Platform : 24 ms

private static void platform() {
    Thread t = new Thread(() -> {
        long start = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getThreadGroup().getName());
        }
        long end = System.currentTimeMillis();
        System.out.println("Platform : " + (end - start) + " ms");
    });
    t.start();
}

In case of virtual thread, there is no output in console. Looks like it didn’t print anything to console, the thread didn’t start.

private static void virtual() {
    Thread.startVirtualThread(() -> {
        long start = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getThreadGroup().getName());
        }
        long end = System.currentTimeMillis();
        System.out.println("Virtual : " + (end - start) + " ms");
    });
}

It seems we need to use join here.

private static void virtual() throws InterruptedException {
    Thread.startVirtualThread(() -> {
        long start = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getThreadGroup().getName());
        }
        long end = System.currentTimeMillis();
        System.out.println("Virtual : " + (end - start) + " ms");
    }).join();
}

And it worked, but took comparatively more time than platform thread, almost double.

Virtual : 49 ms

Let’s try to be fair here,

private static void platform() throws InterruptedException {
    Thread t = new Thread(() -> {
        long start = System.currentTimeMillis();
        for(int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getThreadGroup().getName());
        }
        long end = System.currentTimeMillis();
        System.out.println("Platform : " + (end - start) + " ms");
    });
    t.start();
    t.join();
}

Platform : 26 ms

For some reason, platform thread is winning here.

I thought of replacing System.out.println(Thread.currentThread().getThreadGroup().getName()); with System.out.println("."); to keep it simpler.

If we run both methods together from the main method,

public class Test {

    public static void main(String[] args) throws InterruptedException {
        platform();
        virtual();
    }

    private static void virtual() throws InterruptedException {
        Thread.startVirtualThread(() -> {
            long start = System.currentTimeMillis();
            for(int i = 0; i < 1000; i++) {
                System.out.println(".");
            }
            long end = System.currentTimeMillis();
            System.out.println("Virtual : " + (end - start) + " ms");
        }).join();
    }

    private static void platform() throws InterruptedException {
        Thread t = new Thread(() -> {
            long start = System.currentTimeMillis();
            for(int i = 0; i < 1000; i++) {
                System.out.println(".");
            }
            long end = System.currentTimeMillis();
            System.out.println("Platform : " + (end - start) + " ms");
        });
        t.start();
        t.join();
    }
}

Multiple executions,

  • Platform : 19 ms and Virtual : 15 ms
  • Platform : 21 ms and Virtual : 24 ms
  • Platform : 21 ms and Virtual : 16 ms
  • Platform : 22 ms and Virtual : 14 ms
  • Platform : 22 ms and Virtual : 29 ms

After changing the sequence of methods the result changes dramatically,

...
public static void main(String[] args) throws InterruptedException {
    virtual();
    platform();
}
...

Multiple executions,

  • Platform : 17 ms and Virtual : 60 ms
  • Platform : 7 ms and Virtual : 35 ms
  • Platform : 10 ms and Virtual : 47 ms
  • Platform : 9 ms and Virtual : 35 ms
  • Platform : 6 ms and Virtual : 30 ms

Okay, lot of confusion here. Let’s find answers of each one by one.

Reason

Why virtual thread couldn’t execute?

In first case the problem is that the main thread exits before the virtual thread completes it’s execution. We can definitely join the virtual thread to our main thread which we did. Again the non blocking behaviour made it behave this way.

public static void main(String[] args) throws InterruptedException {
    virtual();
    Thread.sleep(50000);
}

This gives Virtual : 33 ms

Why platform thread executed faster with join?

In case of virtual threads JVM has to deal with additional work underneath, which leads to slight delay in the execution. Even though it’s one thread and we are joining it to main, compared to platform thread it took more time to finish. This ovehead may include things like park/unpark the task based on JVM or CPU bound decision making.

How sequence of method is impacting the thread task execution time?

Again the blocking nature of platform thread makes life of virtual thread easier. For platform thread executed first the JVM, CPU or I/O is managed differently compared to virtual thread if executed first. Since the task is pretty simple the impact is significantly lower but such differences can make developer wonder if not understood properly.

Sunday, August 11, 2024

JavaFX Project Setup

Introduction

Using JavaFX platform, we can build applications for desktop, mobile or embessed systems. It has large set of components to design rich user interface.

JavaFX allows,

  • designing the user interface interactively using Scene Builder.
  • testing the user inteface using TestFX.
  • styling the user interface with the help of CSS.

JavaFX historically used to part of Java installation, however, now it is a standalone component which works on top of JDK.

I faced multiple challenges during setting up the JavaFX with Java 21 to build a simple application recently. I would like to share the setup I ended up with which may help you as well.

We will be going to use following tools,

Here we will going to use Maven which will take care of downloading required modules, however, you can use JavaFX SDK as well.

Project Setup

IntelliJ bundles JavaFX plugin in it.

Create New Project in IntelliJ.

Select JavaFX in side bar. Select Project SDK as Java 21.

For now, we do not need any additional dependencies, we will just click on Finish.

This will take time finish setting up project and indexing.

Once it’s ready we can simply run the Main class which is HelloApplication.java in this case.

It should run successfully and show a window with a button “Hello!”.

As you can see some gibberish text is shown. You may see following logs in Console.

This looked like some issue with the fonts. So I had to add following line in main method of HelloApplication.java.

scene.getRoot().setStyle("-fx-font-family: 'serif'");

After running it again it appeared like following,

Changes in POM

If you go to Project Structure > Modules you will find many OpenFX dependencies are added.

If we look into pom.xml file, we can see following dependecies are add for JavaFX.

...
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-controls</artifactId>
    <version>11.0.2</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-fxml</artifactId>
    <version>11.0.2</version>
</dependency>
...

By default the selected version is 11.0.2 which we will going to change to recent version 22.

<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-controls</artifactId>
    <version>22</version>
</dependency>
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-fxml</artifactId>
    <version>22</version>
</dependency>

However, the build started failing with module error.

I had no clue what could have went wrong, so I did clean up and try to build again but didn’t work.

Surprisingly, when I executed with command line using mvn it worked!

mvn clean compile
mvn javafx:run

Strangely, there is no error in module-info.java, from command line it worked well but failing when I run it from IntelliJ. I felt this issue is something specific to IntelliJ and not to JavaFX.

I found the similar problem is discussed on the forum.

I was using IntelliJ CE version shown in following image,

Moreover, importing the same project to IntelliJ Ultimate Edition worked miraculously without any modifications.

The javafx-maven-plugin is already on latest version, thus we are not changing anything here for now.

...
<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>0.0.8</version>
    <executions>
        <execution>
            <!-- Default configuration for running with: mvn clean javafx:run -->
            <id>default-cli</id>
            <configuration>
                <mainClass>com.example.hellojavafx/com.example.hellojavafx.HelloApplication</mainClass>
                <launcher>app</launcher>
                <jlinkZipName>app</jlinkZipName>
                <jlinkImageName>app</jlinkImageName>
                <noManPages>true</noManPages>
                <stripDebug>true</stripDebug>
                <noHeaderFiles>true</noHeaderFiles>
            </configuration>
        </execution>
    </executions>
</plugin>
...

Initialisation Error

During build and trying some maven command, I ended up with following error,

Error occurred during initialization of boot layer
java.lang.module.FindException: Module com.example.hellojavafx not found

some articles were suggesting to validate Java and JavaFX versions but that wasn’t the issue. Strangely, deleting target directory and running the application worked as it is.

Also, while running through command for the first time you may get following error,

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project hello-javafx: Fatal error compiling: error: invalid target release: 0 

I noticed that in maven-compiler-plugin the source and target version was 0 which I changed to 21 to fix this issue.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>0</source>
        <target>0</target>
    </configuration>
</plugin>

Module Info

Apart from pom.xml, you will find one module-info.java shown below. Here we can see module dependency on javafx.controls and javafx.fxml is mentioned. Also, javafx.fxml needs to access controllers we will define in out package thus we are opening it.

module com.example.hellojavafx {
    requires javafx.controls;
    requires javafx.fxml;


    opens com.example.hellojavafx to javafx.fxml;
    exports com.example.hellojavafx;
}

Whenever you introduce new dependency which you want to be available in your package or you want to open your package to external dependency. Make sure to declare it in module-info.java file.

Executable JAR

To make a runnable .jar I used maven-shade-plugin.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.hellojavafx.HelloApplication</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

I simple ran mvn clean package to create the jar file. However when I ran the jar with following command.

java -jar target/hello-javafx-1.0-SNAPSHOT.jar

It gave me following error,

Error: JavaFX runtime components are missing, and are required to run this application

To solve this, I had to declare an entry point class which can point to my Application class.

package com.example.hellojavafx;

public class EntryPoint {

    public static void main(String[] args) {
        HelloApplication.main(args);
    }
}

This new class I had to use in plugin instead of HelloApplication.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.hellojavafx.EntryPoint</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

And this time it worked! (with warning)

➜  hello-javafx java -jar target/hello-javafx-1.0-SNAPSHOT.jar
Aug 10, 2024 10:35:43 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @673ba40c'

The shade plugin adds everything to the classpath and since JavaFX relies on modules this setup breaks the execution. Thus, as a workaround we introduce another class which can be an entry point to the execution instead of JavaFX starter application.

Basically, if JavaFX application is loaded through classpath it actually breaks the encapsulation provided by modular approach. Here is the ticket for this warning.

↑ Back to Top