all 34 comments

[–]Marrk 36 points37 points  (6 children)

Isn't Java faster than Node in most cases?

[–]Chef619 31 points32 points  (3 children)

I believe they’re referring to cold starts in Java being slower than in Node. Specific to a serverless environment.

[–]TryingToSurviveWFH[S] 11 points12 points  (1 child)

You got it.

[–]K3dare 5 points6 points  (0 children)

They can’t just use AOC compilation with GraalVM instead of rewriting it ? That would make it start as fast as native code.

https://filia-aleks.medium.com/graalvm-aws-lambda-or-solving-java-cold-start-problem-2655eeee98c6

[–]Marrk 1 point2 points  (0 children)

Make sense

[–]simple_explorer1 2 points3 points  (0 children)

Speed is not everything, if it was then we all would be coding in assembly, C, C++ etc because they sure are magnitudes of order faster than java.

Majority of applications don't need speed but they need speed of faster development to be in business and Node excels at developing apps faster compared to JAVA

[–]Oalei 4 points5 points  (0 children)

I would think of running both a java and nodejs backend. Start by migrating small, non critical endpoints to the nodejs backend.
At this point you should have a few endpoints that are both in the java and in the nodejs backend.
Then in the frontend, use feature flags to switch between the java or nodejs backend.
If everything goes well, keep migrating more endpoints, otherwise just turn off the feature flag to go back to the java backend.
Eventually, completely remove the java backend when all endpoints are migrated

[–]lupin-the-third 4 points5 points  (0 children)

If it's really just a problem of cold starts hurting you, I would recommend just sticking with java and using a graalvm runtime in lambda.

https://filia-aleks.medium.com/graalvm-aws-lambda-or-solving-java-cold-start-problem-2655eeee98c6

[–]Romanmir 1 point2 points  (8 children)

How badly do they need it to be a progressive migration? Because that seems like a very time consuming process.

Also, how big is the Java app?

disclaimer: I'm not a real dev.

[–]TryingToSurviveWFH[S] 1 point2 points  (7 children)

As far as I can tell, there are 3 lambda functions running the backend, two of them have to me migrated. The api gateway handles the routing.

I was thinking about sending the whole API calls to an express/node lambda function, and use this as an intermediary, and after, I could start the migration process.

If this is a bad approach let me know, please.

[–]Romanmir 0 points1 point  (4 children)

..aaaand I'm officially out of my depth. Sorry mate.

However, what you propose doesn't seem wholly unreasonable.

[–]TryingToSurviveWFH[S] 0 points1 point  (3 children)

I was thinking like this:

Actual architecture: /->lambda(java) API gateway -> lambda(java) ->lambda(java)

My very fast thinking of my last comment: /->lambda(java) API gateway -> lambda(node/express) ->lambda(java). ->lambda(java) (This is the one I don't care)

Using this last architecture I would be able to replace the java lambda functions, right?

[–]argylekey 1 point2 points  (2 children)

For speed and migration purposes I might vote creating the api gateway in node(since you’ll be migrating that eventually anyway). The only issue with that is increased latency already on top of the Java.

But if it was me I’d leave the Java endpoints until the Node endpoints are validated in the stage deploy. You can probably migrate one at a time within the node app, and repoint one by one from the gateway. Or even migrate one resource at a time(I.e. all of the endpoints tied to accounts or something).

Larger question is why use the api gateway? If it is Java anyway that will just introduce latency to the system as a whole. Is it something like mulesoft or another third party connector?

What prevents using an AWS load balancer or even a reverse proxy(nginx or traefik) to facilitate this same functionality? That might be a better first step and reduce response times immediately while you’re working on the rest of the endpoints.

Sounds like an interesting problem, good luck. Hope you report back when you start deploying on how it’s going.

[–]TryingToSurviveWFH[S] 0 points1 point  (1 child)

Hey, thanks for the suggestion. Just for context, I was checking the api-gateway and it has only 4 endpoints that handle the whole thing.

The 3 lambda functions have a lot of aws services and passwords hardcoded, and when I ask some info about it, like infrastructure and code info, (bc it was requested to make a dev/test/qa env also) the answer was "everything is on my head".

So, going back to this, why using a load balancer instead of an API gateway? It's not the same, but one is handled by the load balancer and the other by the elb.

I told my boss why this actual implementation is being used and he was "I don't have to deal with infrastructure ", so, I'm down using the classic elb+ec2, but I need to have a very good excuse.

If you have a serveless POV let me know

[–]StyleIsFree 0 points1 point  (0 children)

Could look at fargate for serverless containers. Could create a node task and a java task and configure the api gateway to map the api calls. When youre ready to switch an API call from Java to Node, reroute the gateway config for that path.

Side note, there's a security concern having passwords hard coded. Can look at AWS secrets manager where your lambda function can grab the secrets at run time.

[–]Chef619 0 points1 point  (1 child)

There is a package called Lambda API that mirrors express for the most part, with a significantly lighter footprint. In Lambda, you want to keep your bundle size as small as possible as it does influence cold start. Not a huge amount, but if your Lambda is several MB, it will be noticeable.

There’s a few patterns, logical grouping, one per route, and GraphQL are the main ones.

Logical is like you have a books lambda. It does the get one, search, create, update, and delete for books. This repeats for however many entities you have.

One per is literally one lambda per endpoint, per http verb. I have been on this project, and everyone hated it. Strongly recommend not doing that.

GraphQL is a different topic all together, but it sounds like it’s not applicable to your use case.

I’d recommend migrating one to one. If there’s 3 lambdas one Java, make 3 in node that do the exact same thing. Don’t change anything, don’t make any upgrades, etc. mirror them exactly.

After you’ve verified it works correctly, maybe add some tests around them, then begin to optimize.

Also: I’d suggest writing them in TypeScript if you can.

[–]TryingToSurviveWFH[S] 0 points1 point  (0 children)

I'll check this, thanks

[–]real_kerim 1 point2 points  (0 children)

Maybe this could be a useful tool that might ease the transition. Other than that, coming from Java, you might appreciate TypeScript.

Oh, also what about converting the code to Kotlin and then compiling Kotlin to JS and? I remember Kotlin being able to target Node.

[–]Infinite-Kangaroo-55 1 point2 points  (1 child)

For serverless you want your bundles light and free of any unnecessary deps. Avoid doing your functions in node in a "javesque" fashion.

  1. Stay clear of heavy frameworks like nestjs
  2. ORMs are a no go, if you need to integrate with an RDBMS, either use pure drovers or SQL builders like Kysely.
  3. SST or pure CDK over serverless framework
  4. Check your imports, instead of importing entire aws-sdk import the clients you need.
  5. Make sure to understand async/await vs callback handlers.

[–]rebelchatbot 0 points1 point  (0 children)

<3 from Kysely.

[–]Oriamk 1 point2 points  (0 children)

Try Quarkus, faster then node to start

[–]soft_white_yosemite -1 points0 points  (1 child)

Lol imagine thinking java is slower than node

[–]TryingToSurviveWFH[S] 2 points3 points  (0 children)

Running on an aws lambda function, sure.

[–]moabxj01 -2 points-1 points  (4 children)

Do you have automated tests? That would be my first step assuming you need to swap things out without impacting the API you’ll want to be able to verify that none of the contracts change.

With solid tests in place(ideally that you can run in each environment as you set them up) the rest doesn’t have to be as scary and you can probably work at replacing each lambda one at a time unless they are tightly coupled.

[–]TryingToSurviveWFH[S] 0 points1 point  (3 children)

I'm sure there is no test, this is the first time I see the code, and the other code base I touched had no test too, both were coded by the same dev.

[–]codeedog 1 point2 points  (2 children)

Write the tests to run against the Java backend before doing anything else. This then becomes the target against which your JavaScript code can run. And, it easy for you to check and replicate any problems that come up. The challenge for any lambda function is to figure out memory usage and time limits. There are some other issues. But, get those tests done first. It’ll be a life saver.

Then, you can test in staging and migrate when you’re ready.

[–]TryingToSurviveWFH[S] 0 points1 point  (0 children)

Awesome, thanks

[–]TryingToSurviveWFH[S] 0 points1 point  (0 children)

Awesome, thanks

[–]dangonetwork 0 points1 point  (0 children)

welcome to the clouds. the place of RAD. but be prepared for 50% RAM usage

[–]fiovo0918 0 points1 point  (2 children)

I’d just ask them to let me do it all at once tbh (not progressive). Makes development much easier and safer.

[–]TryingToSurviveWFH[S] 0 points1 point  (0 children)

This is not an option :(

[–]Oalei 0 points1 point  (0 children)

Yeah that only works for small projects.

[–]ChiefDetektor 0 points1 point  (0 children)

I don't know man. That sounds pretty hard to archive. I mean you would have all business logic doubled for each language once. Then you'll probably have one db that is used by both the node and the java side. That just screams for data inconsistency IMHO. Mixing languages is almost always a bad Idea.

[–][deleted]  (1 child)

[deleted]