HN user

luuio

372 karma
Posts10
Comments80
View on HN

Happy to continue :)

Where our conversation is at, it's not about RDBMS vs. NoSQL.

On the Redis INCR operation example (or an equivalent operation in any database, even in an RDBMS). In short, you don't always have the guarantee to know the result of the operation. This is part of what the 99.9% means when services advertise their reliability. 99.9% of the time you'll get an acknowledgement back, but not 100%.

The question comes to, what happens if I miss an INCR, or if I accidentally double INCR when I retry? For some use cases, it's acceptable: like counting the number of views on a Youtube video. For others, say a financial system counting money or making a payment, that's not OK. That's where idempotency really matters (btw this is why many redis operations have the NX option).

Let's go completely off track for a little bit, say you're Strava. You let devices and users upload workouts to your service. What happens when a phone sent you the workout, then disconnected due to bad receptions? In this case, the phone doesn't know if the operation succeeded so it's forced to retry. How do we make sure the workout isn't created and counted twice on Strava? Well, each workout has a unique UUID generated by the device. Strava uses this UUID to dedup when it receives an upload. The UUID is the idempotency "checkpoint".

In this case, it doesn't matter what kind of database Strava is using. The idempotency problem is the same.

Look up the two general problem on youtube. Unless the entire end to end operation is wrapped inside a giant transaction, no system in the world can give you the confirmation.

Imagine this: you issued a write, a few things can happen: 1. The callsite crashed, maybe due to an out of memory issue or whatever. You don't know if it succeeded

2. The database returned an acknowledgement, but then the callsite crashed before storing the acknowlwedgement for the next step.

let's say you have an object like this when you started: {count: 10, etag: 1}. then for some reason, something failed.

when you retry and load the object, you get {count: 12, etag: 3}. how do you know if your previous attempt had successfully persisted or not, or if the updates to the object came from other processes/requests?

you're mixing up conflict handling vs. idempotency

why wouldn't doing the same write twice produce an idempotent result

you can imagine this:

```

var thing = KVStore.Get<MyThing>(...);

if (things.Checkpoints.Contains(myUuid) == false) {

  thing.Counter += 1;
}

KVStore.Update(thing); ```

having an etag doesn't help you with retries, where we expect that `thing` could be mutated by another flow between your retries.

there is always more wisdom in what we throw away than what we innovate

i have found this to be true throughout my career. not that things cannot improve, they can always improve. but assuming the original work wasn't grossly incompetent, anything "new" tend to make the same [undocumented] mistakes

1. Beyond just querying, the stored proc spent a lot of time processing data. As in, looping through cursors, making business logic decisions, calculating things, etc.

2. Having the business logic (not just loading the data) inside the stored procs meant that a change in business logic that would normally only need to update application code, now invalidates the stored procedure's cached execution plan.

The KV store had etag support for conditional writes. Etags are only useful to make sure the data didn't change underneath between your read and your write.

Storing the checkpoints along with the mutation was for idempotency. If the checkpoint was in the document, that meant the mutation had succeeded and a retry should be no-op

Crusty Windows 3 years ago

Looking through that list, Windows XP logo has the perfect balance of:

- Simple solid modern colors, no halo/vignette effect like the Vista/7 logos

- Multiple colors, not just one single boring blue color like the newer logos

- The S-curve lines are just soft enough, yet not overly complicated, but also not boring straight lines

At least two reasons I'm not choosing Go:

- Go (the language) is missing the ability to declare something immutable. I don't mean making fields in a struct private then exposing getters. I mean the equivalent of an immutable reference in Rust or `const ref` in C++.

- Go mod and go workspace still can't get a cohesive story together [1]: - - If my module wants to depend on another module in a workspace, `go mod tidy` would freak out. - - If I use replace in my go mod file to point to the other modules in the same workspace, `go mod vendor` will copy these workspace modules to the vendor folder as well.

[1] https://github.com/golang/go/issues/50750

At least two reasons I'm not choosing Go:

- Go (the language) is missing the ability to declare something immutable. I don't mean making fields in a struct private then exposing getters. I mean the equivalent of an immutable reference in Rust or `const ref` in C++.

- Go mod and go workspace still can't get a cohesive story together [1]: - - If my module wants to depend on another module in a workspace, `go mod tidy` would freak out. - - If I use replace in my go mod file to point to the other modules in the same workspace, `go mod vendor` will copy these workspace modules to the vendor folder as well.

[1] https://github.com/golang/go/issues/50750

Everything you said is true. C++ gives you everything you need to be safe. But that's not the point. Rust makes it HARD (or very hard) to do things that are unsafe.

It's not what C++ can or cannot do, it's not what Rust can or cannot do. It's what the Rust language and compiler opinionatedly encourage you to do and not to do. This is what's lacking in C++.

Thanks for the call out! There are definitely companies that go with (A), but in all the companies I've been at, (B) is the model.

As others have responded, there are definitely trade offs with different models. The way I've seen (B) worked well is:

* Given a project, separate out the "level" of different axes. A project could have level N technical scope, but level N+1 collaboration scope, etc.

* Let the level-N engineer handle one level N+1 axis at a time, with supervision on other axes.

* And if they ace one axis, then back off and give them more responsibilities on the other axes, for the same project or subsequent projects.

Of course there are also scenarios where someone is just thrown into the deep end. They will either sink or swim :)

I share exactly your sentiment. The snappy on/off is what makes the checkbox satisfying for me. The "ding" whenever you check an item off the list in Wunderlist comes to mind.

@David, thanks, and completely aligned on why we don't use nuget packages anymore.

As for being intuitive, the default experience is to use the Web SDK. I didn't even get into SDKs but it does more than default the framework reference. It also exposes capabilities that tooling use to light up behaviors in the build and in the IDE.

It is these "does more than default framework reference" are precisely the things in discussion here. All of these hidden functionalities and dependencies are like a black box. What's the difference between what James shared here and the default Sdk=...Web, then? It's the lack of uniformity, where "ASP.NET is a first class citizen" rather than just another piece of the ecosystem that is a turn off.

Compared to other ecosystems, for example: Go, Rust, even Java for example, where everything is just code that one can pull in, and the customization is in the code, not the runtime/JVM.

It's not about if you should or should not search. It's about how often you have to do that, and how easy it is to search for what you want. It boils down to how much anti pattern a framework/ecosystem has. In this case, their default template caused me to search "dotnet core project multiple SDK", which yielded nothing, and is actually a completely wrong track.

The answer the asp.net team shared below, was instead of using the SDK attribute, use a completely different thing called FrameworkReference. Which can completely replace this SDK attribute, it seems.

Hence my question to them below was, why is framework reference not the default? Especially since it does lead to better searchability, and the template shows that one could have multiple of these per project, intuitively.

I, and a lot of other devs, would be able to solve this particular problem without looking up the docs

Look through the rest of this comment thread and see how many failed attempts at solving this problem there were before two high profile members of the ASP.NET team came in (JamesNK and davidfowl).

It's not about looking up or not looking up. The criticism here is that the way the framework is laid out is not intuitive enough. It's very "different" from the rest of the industry (in this case, there are 3 potential ways of pulling in dependencies for ASP.NET). This requires a lot of time investment for its users to solve these slight one-off issues.

My question to them below was why isn't what they shared here the default. If they had done that, it would be intuitive to know that one can add other "FrameworkReferences" in a project, or know what to search for. Instead, the default is "each project can only target one SDK".

Disagree here. This is where I would quote the principles of two other language.

From Python: have one way of doing things

From Go: explicit is bette than implicit.

Is Sdk=... is just a short cut to pull in a handful of framework references? Or are there actually more things happening under the hood?

https://news.ycombinator.com/item?id=30673710

What about the option to just make everything asp.net one single nuget package? And how come other ecosystems/languages don't have this issue? What's the difference?

The other question is, why isn't what you posted the default, but defaulting to this <Project Sdk=...>? To me, it's a lot more intuitive, signaling that each project can have multiple framework references, vs. just one SDK attribute.

Thanks! This is what I was looking for (not anymore, sorry switched to a different language/ecosystem for this project).

This still begs the question, or my original point still stands—why framework reference vs. nuget reference? I'm sure there's a perfectly rationale explanation, but this in itself, having at least two "official" ways of managing dependencies (framework reference vs. package reference on nuget), it's kind of a "code smell" imo.

You could just start with the default sdk and add the imports/targets yourself (or in practice: let the IDE do it for you.)

That's what I have been calling out. I have not had much luck in pulling in the right dependencies needed. Could not find any documentation on it. Everything relies on that Sdk=...Web thing on the official documentation.

Can you build with just these package references? because I did exactly did a while ago and I could not.

The whole point here is that the project does not target the Sdk.Web thing. Yours only works because the project is targeting Sdk.Web (instead of Sdk).

When I said console app, I literally meant using the project that you would create if you do `dotnet new console`.

To copy from my other comment:

That is exactly the thing. I do not want to have the Sdk=...Web/Worker. Imagine this scenario, you started a new project with the Sdk targeting Worker. Then you need that binary to also target web. What do you do?

- If you switch the project to Sdk=...Web, you won't have the dependencies to build the worker services.

- If you keep it as Sdk=...Worker, you won't have the dependencies to build asp.net

That is exactly the thing. I *do not* want to have the Sdk=...Web/Worker. Imagine this scenario, you started a new project with the Sdk targeting Worker. Then you need that binary to also target web. What do you do?

- If you switch the project to Sdk=...Web, you won't have the dependencies to build the worker services.

- If you keep it as Sdk=...Worker, you won't have the dependencies to build asp.net

Nope. Not the same thing. Again, I want them to be in the same binary. Like the example I gave you, have the user input a port number *at runtime*, then use that port to start an asp.net service.

That's just an example. The point is mixing a regular console app with an asp.net service.

Huh? I don't think you read what I'm saying.

Here's a simple challenge for you. Create a command line app (your csproj file should say Sdk="Microsoft.NET.Sdk"), ask the user to input a port number at runtime. Use this port number to start an ASP.NET service.

I have not had any luck to pull all the right nuget dependencies to do that so far. The only way to run asp.net app I could find is switching your whole project to be Sdk="Microsoft.NET.Sdk.Web"