Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Esran
Apr 28, 2008

Hippie Hedgehog posted:

To be fair, Gradle has several of those good properties that you like in Bazel, like reproducible builds and great staleness checks.

Sounds good, it's been a few years since I worked with Gradle, so the tool has probably improved since I used it. It's great that it does a good job with incremental builds. I think there's still a bit of a gap between Gradle and Bazel though, since Bazel runs build targets in a sandbox, which prevents access to any files you didn't declare as dependencies of the current target. This ensures that a build target is a pure function from declared inputs to declared outputs. That makes it a lot easier to ensure that features like incremental builds (and incremental tests), remote caching and remote execution behave correctly, since you can be sure that a build output or test result can be reused if the declared inputs didn't change.

I think the Gradle people have discussed adding a sandboxed mode for the same reasons.

Adbot
ADBOT LOVES YOU

Kuule hain nussivan
Nov 27, 2008

If given a large, lovely, monolithic project, are there any decent tools for creating graphs (class dependecy or method call) out of it and fiddling with them. Stuff like automatic clustering etc. I tried using IntelliJ diagrams but they're not really doing it for me.

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb
Is setting min & max heap sizes to the same value still a good idea?

I guess performance concerns aside, even if those aren't a big issue anymore, it seems like it's still a good idea to set min=max since it's possible for the JVM to get to that point anyways, so why not start there from the get-go?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
It very much depends on the application. If you have a command-line utility then you probably don't need an 8GB heap just to print your usage message, you know?

For long-running servlet-style applications then yeah it totally makes sense though.

Volguus
Mar 3, 2009

fletcher posted:

Is setting min & max heap sizes to the same value still a good idea?

I guess performance concerns aside, even if those aren't a big issue anymore, it seems like it's still a good idea to set min=max since it's possible for the JVM to get to that point anyways, so why not start there from the get-go?

If you're sure that the JVM won't get to that point then yes, it doesn't matter. But if it does, then there could be problems and how they're solved I guess it depends on the garbage collector and the amount of stress the application is under. Ideally you'd benchmark it, stress test it to figure out how
your app will behave when it reaches the limit, can it free objects fast enough to still be responsive? Will it lock for seconds at a time?

For IDEs I used to just put min=max to 4G or whatever and don't worry about it.

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb

Volguus posted:

If you're sure that the JVM won't get to that point then yes, it doesn't matter

I guess that's the main difference between my point of view and a colleague's. My thinking is that if min < max, then yes it's possible for it to get to max. Unlikely based on historical usage? Sure, but still technically possible for some unforeseen issue.

My colleague's point of view is that since historical usage is that actual usage is so far below max that it's not necessary to have them set to the same value. I guess the point to be made there would then be, why are we so over-provisioned?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
What's the context of this application?

If you have a server or container or w/e where this is the only thing running, you should definitely set it up to grab all the memory you've provisioned for it right away. It's not like that memory will be used for anything else anyway.

If this is a desktop application, then you'll want a lower min value, because the user of your application will want to multitask with other memory-intensive things, rather than having your application hogging memory that it isn't using.

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb

Jabor posted:

What's the context of this application?

If you have a server or container or w/e where this is the only thing running, you should definitely set it up to grab all the memory you've provisioned for it right away. It's not like that memory will be used for anything else anyway.

If this is a desktop application, then you'll want a lower min value, because the user of your application will want to multitask with other memory-intensive things, rather than having your application hogging memory that it isn't using.

Oh yeah forgot to mention that! It's a web based Java application running on a server. For the vast majority of the servers, it's the only thing running on the server (aside from logstash, telegraf, etc). There's a few odd cron jobs here and there that consume memory at times as well, though I'm pushing to get those off the app servers.

fletcher fucked around with this message at 08:02 on Jun 9, 2022

HamAdams
Jun 29, 2018

yospos
loving around with Spring in some side projects to get a little more familiar and something I haven't been able to settle on is whether to use constructor params or the @Autowired annotation. Is there any reason to use one versus the other? I'm guessing there's probably some gotchas that I just don't know about yet.

Objective Action
Jun 10, 2007



HamAdams posted:

loving around with Spring in some side projects to get a little more familiar and something I haven't been able to settle on is whether to use constructor params or the @Autowired annotation. Is there any reason to use one versus the other? I'm guessing there's probably some gotchas that I just don't know about yet.

I'd recommend using @Autowired on the constructor parameters rather than the fields directly. Makes it easier to build specific instances manually, makes the signature explicit, makes tests easier, etc. Also more options later if you want to change out the DI for another implementation like Dagger or Micronaut that pre-compiles.

Just my opinion though.

Objective Action fucked around with this message at 17:13 on Jul 4, 2022

CPColin
Sep 9, 2003

Big ol' smile.
Agreed from a Kotlin perspective that services and controllers with constructor parameters is nice and easy to work with, especially when it's time to stuff a bunch of mocks into them during tests.

smackfu
Jun 7, 2004

Yeah, field injection seems like something most people decided was a bad design decision. “Let’s have private fields that are set via reflection!”

Volguus
Mar 3, 2009
Constructor injection has the additional benefit of making you think twice before you add the 15th parameter to that constructor. By that point you probably should have split your service already, as it does too much.

On the other hand ... it's not the end of the world if you do private field injection. Try to avoid it though.

HamAdams
Jun 29, 2018

yospos
all good points, thanks!

MrQueasy
Nov 15, 2005

Probiot-ICK
Anyone know a good way to do handle result paging with CompletableFuture without potentially infinite recursion or just arbitrarily checking the depth?

pseudocode:
code:
CompletableFuture<List<Result>> getResults() {
    var responseF = externalService.query().thenCompose(response -> {
	    if (response.hasNextPageToken()) {
		  return getResults(token, response.results)
            } else {
                  return completedFuture(List.of());
           }
 }  

CompletableFuture<List<Result>> getResults(Token token, List<Results> results) {
        var responseF = externalService.query(token).thenCompose(response -> {
	    if (response.hasNextPageToken()) {
		  return getResults(token, results + response.results)
            } else {
                  return completedFuture(results);
           }
}

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The easy way would be to query a non-paging variant of the API. You're not "handling" the paging in any meaningful sense, just bypassing it.

RandomBlue
Dec 30, 2012

hay guys!


Biscuit Hider

MrQueasy posted:

Anyone know a good way to do handle result paging with CompletableFuture without potentially infinite recursion or just arbitrarily checking the depth?

pseudocode:
code:
CompletableFuture<List<Result>> getResults() {
    var responseF = externalService.query().thenCompose(response -> {
	    if (response.hasNextPageToken()) {
		  return getResults(token, response.results)
            } else {
                  return completedFuture(List.of());
           }
 }  

CompletableFuture<List<Result>> getResults(Token token, List<Results> results) {
        var responseF = externalService.query(token).thenCompose(response -> {
	    if (response.hasNextPageToken()) {
		  return getResults(token, results + response.results)
            } else {
                  return completedFuture(results);
           }
}

Why would you want to call an async method recursively? If recursion needs to be used instead of a simple loop (which is what I'd go with here) then move the recursive code into a synchronous method called from the async methods.

MrQueasy
Nov 15, 2005

Probiot-ICK

Jabor posted:

The easy way would be to query a non-paging variant of the API. You're not "handling" the paging in any meaningful sense, just bypassing it.

Lets imagine for a second that we're dealing with an api that does NOT have a non-paging variant.


RandomBlue posted:

Why would you want to call an async method recursively? If recursion needs to be used instead of a simple loop (which is what I'd go with here) then move the recursive code into a synchronous method called from the async methods.

Can you clarify what you mean by this? I may be mistaken in how CompletedFuture works.

If I do this in the normal blocking while loop way, it will block until all N pages load (of which there are sadly arbitrarily many... probably less than 100?). I would like to start up other downloads (that operate similarly) while I wait for these calls to resolve.

The only way to tell if there are more pages is if there is a token. I can't just walk the pages and tell it to stop when it starts erroring.

(Ugh... I've been in clojure too long... this stuff is relatively straightforward with lazy loading or tail-call optimization)

RandomBlue
Dec 30, 2012

hay guys!


Biscuit Hider

MrQueasy posted:

Can you clarify what you mean by this? I may be mistaken in how CompletedFuture works.

I didn't realize the externalService.query() method was returning a CompletableFuture, so nevermind. I don't know what best practices for a use case like this are so I'll stop offering bad advice.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

MrQueasy posted:


(Ugh... I've been in clojure too long... this stuff is relatively straightforward with lazy loading or tail-call optimization)

Calling functions asynchronously like you're doing isn't going to blow out the thread stack, if that's what you're worried about. Each call to thenCompose() allocates a lambda on the heap with the current context, the thread stack never gets particularly deep unless the request somehow completes in between you calling query() and then calling thenCompose() on the result. If you're worried about that then you could call thenComposeAsync() instead.

MrQueasy
Nov 15, 2005

Probiot-ICK

Jabor posted:

Calling functions asynchronously like you're doing isn't going to blow out the thread stack, if that's what you're worried about. Each call to thenCompose() allocates a lambda on the heap with the current context, the thread stack never gets particularly deep unless the request somehow completes in between you calling query() and then calling thenCompose() on the result. If you're worried about that then you could call thenComposeAsync() instead.

Thank you, this has taken a load off of my mind... (despite sending me down a rabbit hole about how and when to use the *async methods)

hooah
Feb 6, 2006
WTF?
Does anyone have any recommendations for generating an OpenAPI 2 / Swagger document from annotations using Spring Boot 2.6.x? We're currently stuck using OpenAPI 2 at work, and Springfox doesn't work with Spring Boot above 2.5.x.

Objective Action
Jun 10, 2007



hooah posted:

Does anyone have any recommendations for generating an OpenAPI 2 / Swagger document from annotations using Spring Boot 2.6.x? We're currently stuck using OpenAPI 2 at work, and Springfox doesn't work with Spring Boot above 2.5.x.

I use https://springdoc.org/ but that's OpenAPI 3. To my knowledge the only option for 2.0 (that was anywhere near usable) was Springfox. If it absolutely has to be 2.0 I think your only option might be to check for forks or fork Springfox yourself?

Methanar
Sep 26, 2013

by the sex ghost
So I have a jar (two, actually which are unrelated) that I'm decompiling with quiltflower for 'fun' to make some changes. Seems to work mostly okay. I get a few non-fatal errors about failure to understand enums but for the most part I seem to get mostly real, if unreadable and stripped down, java out.


There are a few problems though.
1) Every java file comes with a few megabytes of empty lines and random @ symbols lol. That's annoying but I was able to clean up the files to the point they were useable with sed.
2) The decompile seems to be incomplete with some variables and functions simply not having proper declarations?.
3) The pom.xml for some dependencies seems to be broken out of the box and I can't figure out how to even fix it because I don't understand Maven.
4) vscode seems to properly understand the project and allow me to jump between references and declarations easily for things that actually exist, but intellj does not.

Are these just normal problems to be expected from using quiltflower?

I can't even figure out how to learn to understand what I need to fix these problems. Like the fixing the maven issues. Some dependencies are fine like gson and logback-core, but logback classic is broken and referencing manifest files that don't exist.
I clearly don't understand how to use my IDEs, either vscode or intellj properly either because I have different problems with each.

Honestly if I could figure out how to actually get this to recompile, I could probably hack and cheat my way to my solution with enough time and breakpoints.

Overall 0/10 experience. Only thing I've learned is how incompetent and in over my head I am.

Methanar fucked around with this message at 01:04 on Aug 15, 2022

Tesseraction
Apr 5, 2009

Are those jars closed source? It could be the developer put stuff in to mess with decompilers, it could also be that Quiltflower seems to be specifically maintained by Minecraft modders. You might find it beneficial using other decompilers?

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.
You might try the Jetbrains decompiler? I've had success with that, it's pretty nice.

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
Intellij has a built-in decompiler

e:fb

necrotic
Aug 2, 2005
I owe my brother big time for this!
You can use it standalone, too. Someone pulled it out of the IntelliJ source tree https://github.com/fesh0r/fernflower

Methanar
Sep 26, 2013

by the sex ghost

Tesseraction posted:

Are those jars closed source? It could be the developer put stuff in to mess with decompilers, it could also be that Quiltflower seems to be specifically maintained by Minecraft modders. You might find it beneficial using other decompilers?

I did actually find upstream fernflower to be better.

These jars are just obfuscated to all hell which is why I was so confused. Coming back to this a few days later with a somewhat cleaner head, I'm actually somewhat enjoying the tedious, repetitive uncreative process of deobfuscating for now.

A few sed statements later and I was able to get reasonably sized java files out without several hundred megabytes of padding

code:
for i in *.java; do (sed -i /^\s*$/d $i; sed -i /@/d $i)&; done
code:
   private static void IlIlIlll() {
      IIIlIIIl = new int[38];
      IIIlIIIl[0] = " ".length() << (" ".length() << " ".length()) & (" ".length() << (" ".length() << " ".length()) ^ -" ".length());
      IIIlIIIl[1] = "   ".length();
      IIIlIIIl[2] = 178 ^ 183;
      IIIlIIIl[3] = " ".length();
      IIIlIIIl[4] = " ".length() << " ".length();
All constants and function names and static strings and integers are locked up in these god awful arrays of bit abuse.

The first step has been to decode these into real values again. And then walk everything that calls the big array of obfuscated values with string replacing to get slightly more readable code. really just continuing that process of renaming things back to something readable, fixing weird decompiler type errors, removing dead code, removing obfuscator logic and making educated guesses about what function names should be based on what they are doing and the interfaces they implement.

Some functions actually did decompile down to useful names, names of standard java libraries and the included 3rd party libraries, I guess my decompiler had the symbols handy somehow? Or maybe they didnt get obfuscated in the first place. Not sure on that one.

Lucky for me, one of the internal packages included in this app did not get obfuscated properly so I have a full library of proper internal things with no obfuscation! There's still some unresolvable function names that I don't have the definitions for. I suspect this is because the internal package did not get obfuscated, the useless obfuscated undeclared ililil names are supposed to be referring to some class declared within that.

For the int obfuscation, which is all just bit math, I am copy pasting the lines into a ruby interpreter because that's actually valid ruby and its just easiest way I could think to do it lol.

I made my own little decoder tool for the nastier string decoding which is full of casting char to ints and bit mathing that and md5 poo poo. The decompiler seemed to have made a lot of type errors which is honestly not a great sign but intellj has been able to auto suggest what to do so whatever.



But for now i'm just enjoying my tedium of decoding static ints and strings and guessing function names. I can't believe I am enjoying deobfuscating java.

Methanar fucked around with this message at 06:31 on Aug 18, 2022

Mycroft Holmes
Mar 26, 2010

by Azathoth
For class, I have to program a recursive solution to the following word problem and I have no idea how. I'm not good at math puzzles. " A frog wants to cross a river that is 11 feet across. One side of the river -> stone1 -> stone2 -> stone3 -> stone4 -> stone5 -> stone6 -> stone7 -> stone8 -> stone9 -> stone10 -> the other side of the river. There are 10 stones in a line leading across the river, separated by 1 foot, and the frog is only ever able to jump either one foot or two feet forward to the next stone. In how many different ways can he jump exactly 11 feet to the other side of the river?"

I have no idea how to go about this.

hooah
Feb 6, 2006
WTF?

Mycroft Holmes posted:

For class, I have to program a recursive solution to the following word problem and I have no idea how. I'm not good at math puzzles. " A frog wants to cross a river that is 11 feet across. One side of the river -> stone1 -> stone2 -> stone3 -> stone4 -> stone5 -> stone6 -> stone7 -> stone8 -> stone9 -> stone10 -> the other side of the river. There are 10 stones in a line leading across the river, separated by 1 foot, and the frog is only ever able to jump either one foot or two feet forward to the next stone. In how many different ways can he jump exactly 11 feet to the other side of the river?"

I have no idea how to go about this.

Does the class have a TA? Or have you talked to the professor at all? They should be able to help you at least wrap your brain around what the puzzle is asking. I've been coding for ~9 years (6 years professionally) and nothing comes to mind to me after 30 seconds, so this at least isn't trivial.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
A good way to start with this is to think about smaller problems.

- If the river were only one foot across, how many ways would the frog be able to jump it?
- If the river were only two feet across, how many ways?
- Three feet across?
- Four feet?

These are small enough that you can work out the answers by hand easily enough, but after doing that you might be able to see a pattern that you can then apply to the full-scale problem.

Charles 2 of Spain
Nov 7, 2017

Yeah, think about how you would systematically write down every way you could cross. Then you transfer that method to a structure in your code and loop through it recursively.

Tesseraction
Apr 5, 2009

hooah posted:

Does the class have a TA? Or have you talked to the professor at all? They should be able to help you at least wrap your brain around what the puzzle is asking. I've been coding for ~9 years (6 years professionally) and nothing comes to mind to me after 30 seconds, so this at least isn't trivial.

The puzzle is asking you to come up with all possible configurations of adding 1 or 2 to make 11. The point of making it recursive is to make it so that the 11 is arbitrary, so you can't hard-code the solution after working it out by hand.

hooah
Feb 6, 2006
WTF?

Tesseraction posted:

The puzzle is asking you to come up with all possible configurations of adding 1 or 2 to make 11. The point of making it recursive is to make it so that the 11 is arbitrary, so you can't hard-code the solution after working it out by hand.

This is the kind of thing that makes me really glad I don't have to devise algorithms for my job. I do not miss this kind of crap from school.

Mycroft Holmes
Mar 26, 2010

by Azathoth
looked up the riddle. Turns out it's an example of the Fibonacci sequence, so I can now code that.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If you wanted to identify it yourself without having to look it up, you can notice that there are really only two ways of reaching exactly distance n:
- You get to exactly distance n-1, then take a one-foot hop
- You get to exactly distance n-2, then take a two-foot hop

So the total number of different ways is the number of different ways to get to exactly n-1, plus the number of different ways to get to exactly n-2, which is the definition of the fibonacci sequence.

ulmont
Sep 15, 2010

IF I EVER MISS VOTING IN AN ELECTION (EVEN AMERICAN IDOL) ,OR HAVE UNPAID PARKING TICKETS, PLEASE TAKE AWAY MY FRANCHISE

Mycroft Holmes posted:

For class, I have to program a recursive solution to the following word problem and I have no idea how. I'm not good at math puzzles. " A frog wants to cross a river that is 11 feet across. One side of the river -> stone1 -> stone2 -> stone3 -> stone4 -> stone5 -> stone6 -> stone7 -> stone8 -> stone9 -> stone10 -> the other side of the river. There are 10 stones in a line leading across the river, separated by 1 foot, and the frog is only ever able to jump either one foot or two feet forward to the next stone. In how many different ways can he jump exactly 11 feet to the other side of the river?"

I have no idea how to go about this.

Every recursive solution works the same way.

1. Check to see if you have solved the problem. If you have, output the answer and stop.
2. If you haven't, identify a way to turn the current problem into subproblems.
3. Then start solving the subproblems.
4. Repeat.

So here:

1. Have you outputted all possible ways to complete your solution? Here you only end when you get to stone 10 (1 way to jump to the other side of the river) or the other side of the river (0 ways to jump to the other side of the river). In this case your function countRiverCrossings(stone10, river) returns 1 and your function countRiverCrossings(river) returns 0.
2. If no, how many possible solutions do you have from where you start? Well, if your function is something like countRiverCrossings(river, stone1, stone 2, [etc], river), then you know that from the river the frog can only jump to either stone 1 or stone 2, right? So your answer of total ways is...0 (your current result) + countRiverCrossings(stone1, stone2, [etc], river) (this assumes the frog jumps to stone 1) + countRiverCrossings(stone2, [etc], river) (this assumes the frog jumps directly to stone 2).

Pedestrian Xing
Jul 19, 2007

Somebody in this forum (can't remember which thread) once said that all recursive algorithms can also be expressed as a while(true) loop with a manual break condition and it really made them way easier to approach.

Adbot
ADBOT LOVES YOU

ulmont
Sep 15, 2010

IF I EVER MISS VOTING IN AN ELECTION (EVEN AMERICAN IDOL) ,OR HAVE UNPAID PARKING TICKETS, PLEASE TAKE AWAY MY FRANCHISE

Pedestrian Xing posted:

Somebody in this forum (can't remember which thread) once said that all recursive algorithms can also be expressed as a while(true) loop with a manual break condition and it really made them way easier to approach.

Yeah, that's the same concept, although it isn't as clear about "solve all the obvious subproblems" and turning a recursive algorithm into a while(true) is often going to require a lot of list manipulation to manage your intermediate results.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply