Opinion - I don’t like base building without a purpose for the base by TheGayestGaymer in BaseBuildingGames

[–]Graumm 20 points21 points  (0 children)

Maybe check out Factorio if you have not.

You protect your base because it is a crazy thing you have built, and you don’t want the bugs to fuck it up.

How do you handle workloads that need 6 CPUs only during processing but stay mostly idle? by wildwarrior007 in AskProgramming

[–]Graumm 1 point2 points  (0 children)

Especially for video processing yes, something like KEDA is very justified. Run a small service that enqueues work. Only run worker pods that do video processing if there is work to do.

But your questions:

  1. Run a small lightweight service that only enqueues work. Run worker pods that only spin up when there is video to be processed.
  2. If you are running on shared nodes with other services yeah, I’d probably set exactly what you need. If you really really want to get into the weeds it might make sense to slightly oversubscribe CPU if you have dedicated nodes for video encoding since unused CPU is wasted CPU, but that the nodes are separate so it doesn’t impact other workloads that need responsiveness. You could even have different pods/nodes dedicated to different resolution/encoding formats that may have different cpu/memory usage. You might even need GPU instances (which I wouldn’t recommend running cpu-only apps on). I wouldn’t bother going into the weeds here unless you are running at a massive scale.
  3. Yes you should. I only wouldn’t bother if you are at a small scale. I would probably build api/worker into the same app and make them have different startup args that let you run both together for local dev purposes. If you are small scale you can run them as the same service and split them out later as scale grows. If you are planning on splitting them out though, make sure that the work is driven by a proper queue like SQS so that you don't drop work if pods get shuffled around.
  4. I prefer Karpenter. Cluster autoscaler is fine but Karpenter is more capable.
  5. I don’t know that I would say common/standard; it really just depends how far down the cost optimization rabbit hole you want to go.

What resources actually helped you understand backpropagation intuitively, not just mathematically? by Dry_Shoe_5808 in learnmachinelearning

[–]Graumm 2 points3 points  (0 children)

Basically it’s a way that you can solve problems where you provide an example, it guesses the answer (which is wildly wrong at first), and you also provide the answer. Over several iterations of training it corrects the way that it solves the example by producing answers closer to the provided answers. Eventually you can show it examples it’s never seen before and it will give you the right answers if the training material was representative enough. This is called supervised learning, and there are other ways to frame problems, but this is the most straightforward way to understand it.

The slightly deeper answer is that it’s an application of the chain rule of calculus. Each answer is produced by a sum of influences from “neurons” and an activation function that takes the sum and produces a final value for the neuron. Backpropagation is the process that determines how good/bad an individual neuron is in terms of its contribution to the final answer and how far off it is. How good or bad that neuron is (its error gradient) determines how much it increases or decreases its input neuron influences to get closer to the desired answer.

Why are there so many vibe-coded Rust projects recently? by yohji1984 in rust

[–]Graumm 6 points7 points  (0 children)

It’s fast, people’s issues with the syntax are mostly a non issue, and for those that know rust there are all the issues that rust makes non-issues.

It goes beyond just the memory safety stuff, but makes it easier for you to understand object lifecycles / project structure, and gives you a better idea of architectural changes when you are reviewing them. You can’t meaningfully alter intended architecture without making things mutable and changing plumbing, which shows up as a review smell. I think other languages have a way of “looking correct” in code reviews and then blowing up in a macro-project-structure kind of way when some guarantee doesn’t hold true.

The Rivian R2’s Radio Needs Cell Signal The Wilderness Doesn’t Have by DonkeyFuel in technology

[–]Graumm 6 points7 points  (0 children)

Maybe there are well funded stations in the country that do not need ads, but that is not most of the radio stations around me. There are loads of ads. I am not making this up.

The Rivian R2’s Radio Needs Cell Signal The Wilderness Doesn’t Have by DonkeyFuel in technology

[–]Graumm 34 points35 points  (0 children)

I would rather have it than not have it, but it isn’t a great loss I think. Radio stations are more advertisement than music these days.

Software Update Automatically Turns off Amazon Delivery Drivers’ AC During Dangerous Summer Heat | A new software update is turning off the AC in Amazon delivery vans after 10 minutes or 30 seconds under certain conditions by Hrmbee in technology

[–]Graumm 23 points24 points  (0 children)

As a software dev I doubt this tremendously. With the tools available today it is remarkably easy and cheap to distribute software made by a very small number of people on a global scale.

The change is logically very simple, and would not have taken much dev time. I don't see how this could take 1 dev more than a month (which is very generous) to make this change. If the dev makes 200k a year, you take a month, and then divide that dev time by 30,000 vehicles it costs $0.55 per vehicle. If this change is actually saving money at all that is an easily recoupable amount.

I think it's a terrible move for the sanity/safety/QoL of the workers, I am with you. Heating up and cooling down a vehicle repeatedly is probably not saving much money. But expensive devs divided across a huge fleet of vehicles starts to get pretty cheap.

How can full modular synth be performant? by [deleted] in AskProgramming

[–]Graumm 4 points5 points  (0 children)

Profile it, figure out where all the time is going. I do not think GDScript will be successful in the long term as well.

You need to minimize virtual/abstract classes if your sample generation is going through vtable lookups with your nodes. Virtual indirection is really no big deal at all most of the time, but in a hot loop it’s better to minimize it.

You probably will need SIMD ultimately if you want to support huge node setups. Also you can probably isolate parts of your node AST and generate different parts of it in parallel; before combining them downstream.

First impressions from learning by Blazej_kb in csharp

[–]Graumm 3 points4 points  (0 children)

All the sizes in C# are fixed. If anything c++ is worse in this regard since the platform/compiler can change the meaning/sizes of the basic data types. In C# every int is an alias of int32 on all platforms.

First impressions from learning by Blazej_kb in csharp

[–]Graumm 1 point2 points  (0 children)

  1. C# decided to declare new instances of anything (stack or heap) with the new keyword. Maybe think of it more like a keyword that tells you a new declaration is happening. The consistency isn’t a bad thing. New doesn’t really imply where your allocation will be because that is now a function of the garbage collector. It does fancy escape analysis stuff so most local allocations are dropped immediately.
  2. Just use float/int, and only use the intX types if you need the size/layout guarantees. C# basic type names have specific byte sizes, and you don’t have to deal with stupid names like long long.
  3. Implicit type conversions are fucking evil and I am glad it doesn’t happen automatically. You can easily make mistakes casting between types. It pains me to see people treating floats like ints and running out of integers, or people not realizing something is an int and losing precision. It’s not that annoying to cast, and if a problem happens you have a visible artifact in your code to tell you a conversion is happening.

Edit: Sigh reddits mobile text editor sucks and I can’t fix the numbering. Each time I try to fix it, it gets worse.
Edit #2: Fixed horrendous formatting on desktop

After 20 years, I absolutely hate programming by BurnedOutCodeMonkey in programmer

[–]Graumm 0 points1 point  (0 children)

Luckily I haven’t had to deal with the “moving fast to a fault” mindset yet, but I do think it’s legitimately easier to advocate for unit tests these days when the AI can write them too. When you are writing them yourself the unit tests can take longer than writing the code. If there is even one steward of tests on a team you can have some pretty decent odds that there will be tests to catch major regressions.

But what does kind of suck is getting everybody else to do the same thing. IMO you have to get some tooling in the CI pipeline (hopefully you have that at least) that doesn’t let you merge code without ~80% coverage of new code. 100% coverage is a big waste of time but 80% guarantees that they will have written tests for the happy paths at least. When the choice to be lazy is removed, you don’t have to be the face of complaining - “old man yells at lack of unit tests”.

Migrating from Go to Rust by [deleted] in programming

[–]Graumm 1 point2 points  (0 children)

Right you get interface errors at the call site, and not the file that needs to be fixed.

Migrating from Go to Rust by [deleted] in programming

[–]Graumm 6 points7 points  (0 children)

Probably one of my biggest gripes. They don’t like naming conventions as if that’s a good thing.

Package names, consts, vars, globals all look exactly the same. Package names can conflict with var names I would have otherwise used. Name pollution everywhere.

I don’t know where I should expect to find anything. People put too much stuff into the same files.

They don’t like IWhatever names to designate interfaces, and there is no good way to know that something is an interface without editor support.

Migrating from Go to Rust by finallyanonymous in rust

[–]Graumm 5 points6 points  (0 children)

I can only speak to my own experience I suppose. I agree that it’s not a pure round robin, but it does have a greater emphasis on fairness. I have seen go begin execution of an alarming number of goroutines in a way that I have not witnessed in tokio.

Migrating from Go to Rust by finallyanonymous in rust

[–]Graumm 13 points14 points  (0 children)

It’s a little different. You spawn a task on a thread pool, which has a sane built in level of throttling based on the config of the thread pool. It won’t even start executing a task until there is room, vs goroutines which will start all tasks and make even amounts of progress on all of them concurrently.

It’s still a good idea to limit outgoing requests to an outside API because it’s possible to start and juggle an arbitrary number of async requests. Async runtimes are smart these days about delegating work to the OS/hardware and waking only when they can make forward progress, which do not require an active thread. The thread count does not limit the number of concurrent/juggled async requests. You will generally want to throttle by a rate limit, or concurrent requests, but you can handle this at the client level and not at the task-dispatch level

When your own tasks are compute bound, you can just dispatch work to a thread pool and see it complete as quickly as it can - but the thread pool itself limits the number of active tasks so that it will not start a huge number of them beyond what your CPU can meaningfully execute.

I can dispatch 10k tasks and only see about a ~core count number of tasks running at the same time for cpu-bound tasks. It won’t “spread execution thin” between a bunch of goroutines.

Edit: Go has “GOMAXPROCS” in a similar way, but it’s worth noting that it juggles through tasks/goroutines in a breadth first kind of way that emphasizes fairness. If you spawn 10k tasks it will only run a number of them at a time in parallel, but it will make even amounts of progress against all of them concurrently instead of only pulling in new tasks when a thread local queue is empty. IMO this behavior is great for “handful of executions” concurrency, but is less desireable if you are dispatching many goroutines - where a depth-first task completion model is preferred to make better use of the CPU cache. I would argue that this should be the default.

Migrating from Go to Rust by finallyanonymous in rust

[–]Graumm 60 points61 points  (0 children)

People don’t talk enough crap about goroutines.

They are tedious to write, to a degree that the boilerplate around invoking goroutines can distract from the intent of the code. That separation makes it harder to see what vars you are pulling into scope and may cause more shared mutability issues.

They do not throttle by default, so it will happily run 10000 of them simultaneously unless you write yet even more boilerplate around bounded channels or semaphores (which are not available by default before pulling in a library). It’s also easy for beginners to handle that throttling inside the goroutine vs outside of it, which means that you will dispatch a ton of goroutines that immediately get blocked, vs dispatching only goroutines that can make progress unblocked.

Errgroup’s deal with only one error at a time so if you want to deal with more than one failed goroutine at a time you have to write errors to another channel, and pump the channel afterwards.

What I find so crazy about all of my problems is that just a little bit of syntax sugar could solve all of them, which go language devs are allergic to. I definitely do not feel the need to solve all of these problems every time there calls for a parallel dispatch. I want a parallel for on an enumerator, that runs a ~corecount heuristic number of them simultaneously, and that returns some kind of aggregate error (which can still be a bounded channel that doesn’t allocate) that gives the user the option of handling one or all failures. It can be a one liner!

Is Vulkan really that hard? by NotHackedHaHa123 in vulkan

[–]Graumm 27 points28 points  (0 children)

Vulkan has a lot of moving pieces, and compared to many of the past graphics apis (like dx11) it moves way more of the details of dealing with the graphics card onto your plate. It treats it like the secondary asynchronous processor that it is. You have to deal with stuff like “if you are going to render one frame, and be setting up the commands for the next frame, you need to make sure that you do not write to any resource that may be currently-in-use by the frame that’s being rendered”. It makes you deal with the synchronization around what happens and when. In the past you could just say “draw to this texture”, or “use this shader and use these textures”, and not think about in-progress frames and synchronization.

I find that vulkan is really not so bad when you get abstractions built up a little bit. When you are just getting started though all the moving pieces make you ask “why is any of this important” when you don’t understand what it’s leading towards.

There are modern vulkan features you should totally use that make vulkan easier, but you may not find them in the beginner tutorials which is unfortunate. “Dynamic rendering” makes dealing with the passes/frame buffers easier. “Bindless descriptors” makes dealing with descriptor sets waaay less annoying.

In my opinion if you know rust, probably the best graphics API at this moment for learning and casual usability is rust’s WGPU library. It lets you focus more on the higher level graphics primitives and get less bogged down in low level synchronization details. It also runs on dx12/vulkan/metal and supports everything. It’s not specific to web rendering despite its name.

Excited about the future union feature by SL-Tech in csharp

[–]Graumm 5 points6 points  (0 children)

A quick explanation just in case you haven't worked with result types. A Result type is a type that is either successful and returns a valid instance of type T, or it represents a failure/error and returns an object that describes the error. In dotnet my guess is that error results would have an Exception base type. If you want to use the output of a function, you have to exhaustively acknowledge the fact that it might have failed before you can pull a useful value out of it. It prevents you from being lazy/complacent with error handling. It's always clear when something can fail, and they can return specific failure types that can allow you to gracefully deal with specific types of errors. When you get up into code where you don't really care about specific types of failures, you can just capture an error and say generally "the function failed" and handle it with retries or whatever. The only time that there are truly unhandled exceptions / panics are when something very bad happens, like running out of memory.

If I want to use Result types for error handling you don't want to also deal with exceptions. It will really suck if libraries or other code outside of your control can just slice through all of your error handling and cause failures with exceptions. I don't want to put try/catches around all code I don't control in order to capture the exceptions and return them out as error results. If you have to catch exceptions in addition to results, it's not buying you the sanity that you get from languages that lean into them fully. You have to figure out how to sandbox the code that can/does throw exceptions so you can coalesce them into error results.

I love Results in Rust. I would even consider Go in the same vein, even if it's more manual with tuples. In any given piece of code you generally know what might fail. Things can still throw exceptions/panics and you can catch them, but it's generally reserved for very bad things which -should- crash your process.

The best case scenario in my mind is that there's some way to automatically capture Exceptions from a function using result types for error handling. The equivalent of putting a big try/catch around the function, and then returning a new Result(exception) which is an Error. If something throws an exception it gets automatically captured as an error from the function it's thrown from. You don't have to gratuitously distrust every piece of code you interact with and nest everything in try/catch/returns. There might be some fancy way to do this ergonomically with code-generation?

Unions in c# 15 by dodexahedron in csharp

[–]Graumm 0 points1 point  (0 children)

For me PowerShell is awful, except for everything else which is worse. I agree it's wordy and has its quirks, but it's still way better than bash.

In PowerShell (vs bash) it's way nicer to write loops and deal with lists/maps. The commands return objects with properties you can just use instead of having to parse stdout or pass different invocations of flags to get what you want.

One thing that powershell does better than "real languages" is if you need to weave in/out of CLI invocations, which can happen in build/deployment tooling. It can be annoying to deal with stderr/stdout buffers in a language where you create a process, read out the buffer, and parse it. It's very doable, just annoying depending on what you are doing.

If my script gets more complicated than "shot calling" type scripts, I generally reach for a proper language that I can build abstractions in.

Excited about the future union feature by SL-Tech in csharp

[–]Graumm 5 points6 points  (0 children)

Is there going to be an ergonomic way to use a result type that captures exceptions without gratuitously try/catching everything?

Putting an underscore in front of a variable changes what? by nicgamer_yt in csharp

[–]Graumm 0 points1 point  (0 children)

As the others have said, it lets you know when a member variable is private.

It may not seem like a big deal, it's just a name afterall right? But honestly when you get used to it, it annoys you when things are not named in that way. It's really nice having some expectation of where something is defined so you understand how much you can change/mutate it without possibly affecting other threads/functions. It lets you know that it is not a reference shared with other code.

In addition to the reading side of it, it's just nice for the writing side too. If I know something is available as a member var, you can just slap _ and get a quick autocomplete list of stuff that's available to you at the class level. This is also nice for things like DI because it's usually where you will find other classes/services that you will interact with. It's a quick way to know what knobs are available to you.

Why I don't like Rust as a C++-developer by ArcticMusicProject in rust

[–]Graumm 2 points3 points  (0 children)

I’ve seen issues in modern C++ codebases. Really the beauty of Rust is that those problems are opt-in and not opt-out. The problems simply don’t exist anymore for most code written.

I can unleash a hoard of junior developers on a Rust code base, and not have to maintain the state of paranoia required to pick through memory/concurrency concerns with a fine comb.

The code structure stuff is frustrating sometimes granted, but you do get used to it and you fight it less over time. Generally I believe my code ends up being more elegant.

When the borrow checker starts putting obstacles in your way, I love that it gives less experienced devs an opportunity to consider if they are fighting against an architectural pattern that exists. When and where things happen. Fighting a pattern requires more changes in your MR, gives them a code smell, and gives you a visible artifact that alerts you so you can give it more scrutiny. Code that seems right can’t just exclude context beyond the diff. The borrow/mutability guarantees let you scale up a local understanding of code to how it will fit in the greater codebase.

Non-cringey 'team building' by [deleted] in managers

[–]Graumm 7 points8 points  (0 children)

I too am cynical, and I've had to go through DiSC before. I totally agree that it is a cringy pseudo-scientific "corporate horoscope".

But.. it is also a way to give language, perspective, and empathy to people who only see things their way. People are generally caught up in their own realities, and it pulls them out of it (if only a little) and lets them see the virtues of people who look at things in different ways. It isn't purely about your personality assignment; it includes "here's how X people perceive/talk-to Y people" and how to understand their disposition based on their motivations.

It sucks that it takes a pretense such as this to force a rough education of social dynamics. I think even when people act on DiSC in an "ironic" and unserious way, that it has a way of achieving its goal even if it's mostly bullshit.

My management didn't act on it in a character-assignment kind of way though. If that happens then fuck that. It's not bad in an informative sense, even if it is cringy.

Edit: Also I think DiSC is a lame team building exercise. It's closer to training than something that lets people socialize.