Hacker Newsnew | past | comments | ask | show | jobs | submit | more zubspace's commentslogin

It's a shitty system, if one side just needs to succeed one time while the other side needs to succeed over and over again.

What really should be done is to disallow proposals, which are kinda the same. Once a mass surveillance proposal like this is defeated, it shouldn't be allowed to be constantly rebranded and reintroduced. We need a firewall in our legislative process that automatically rejects any future attempts at scanning private communications.


> What really should be done is to disallow proposals, which are kinda the same.

This very much exists in a lot of parliamentary rules authorities, but it's usually limited to once per "session." They just need to make rules that span sessions that raise the bar for introducing substantially similar legislation.

It can easily be argued that passing something that failed to pass before, multiple times, should require supermajorities. Or at least to create a type of vote where you can move that something "should not" be passed without a supermajority in the future.

It is difficult in most systems to make negative motions. At the least it would have to be tailored as an explicit prohibition on passing anything substantially similar to the motion in future sessions (without suspending the rules with a supermajority.)

I don't know as much about the French Parlement's procedure as I would like to, though.


Is there no way to codify a negative right, like “The right of the European people to privacy in their communications and security in their records through encryption shall not be infringed?” Negative rights reserved to the people should be more important than positive laws granting power to the government.


Yes; they could amend the definitely-not-a-constitution (for branding/eurosceptic-appeasement reasons, the EU constitution was rebranded as the Lisbon treaty before adoption). Arguably such a right may exist already and this legislation might find itself on a collision course with the ECJ if it passed (notably the ECJ nuked _another_ intrusive law, back in the day: https://en.wikipedia.org/wiki/Data_Retention_Directive).


In some ways yes but we've already seen with covid that governments are happy to behave unconstitutionally even when it's clear they will eventually lose in court - by then their targets have already been dragged through the mud.


This rule can really hurt. e.g. Theresa May tried passing a deal to keep the UK in the Customs Union. The speaker wouldn't allow it because the same deal had previously been rejected, even though she now had the support for it in the house.


I wonder if it'd be possible to fix a lot of these issues by having a constitution with damn near impossibly strict standards for changing it that rely on the entire population agreeing (or close to it)?

So there might be a right to privacy or freedom of speech enshrined in law, and the only way to change it would be for 90+% of the population to agree to change it. That way, it'd only take a minority disagreeing with a bad law to make it impossible to pass said law. Reactionaries and extremists would basically be defanged entirely, since they'd have to get most of their opponents to agree with any changes they propose, not just their own followers.


It exists. Except these mfs will not put the proposal to vote if they know it will not pass. Instead they try again and again to gather the votes.


Same here! Restarted my router and pi hole twice. Now i feel stupid.


I know this behavior all to well. I definitely think that this can be used to your advantage: You learn alot in the struggle and get a deep understanding of the problem.

But you really need to step back once in a while and contemplate, if the thing you're doing is really worthwhile.

One of the most precious resources is time. I didn't appreciate this insight a lot while I was young. But as I grew older I needed to be more careful how you I was spending it. In this regard like I like the saying "youth is wasted on the young". But this also enables you to be more focused in your approach. Fail fast is a lot better than spending years on a problem with bo end in sight


I’m already old.


Wouldn't it just solve a whole lot of problems if we could just add optional type declarations to json? It seems so simple and obvious that I'm kinda dumbfounded that this is not a thing yet. Most of the time you would not need it, but it would prevent the parser from making a wrong guess in all those edge cases.

Probably there are types not every parser/language can accept, but at least it could throw a meaningful error instead of guessing or even truncating the value.


I doubt that would fix the issue. The real cause is that programmers mostly deal in fixed-size integers, and that’s how they think of integer values, since those are the concepts their languages provide. If you’re going to write a JSON library for your favourite programming language, you’re going to reach for whatever ints are the default, regardless of what the specs or type hints suggest.

Haskell’s Aeson library is one of the few exceptions I’ve seen, since it only parses numbers to ‘Scientific’s (essentially a kind of bigint for rationals.) This makes the API very safe, but also incredibly annoying to use if you want to just munge some integers, since you’re forced to handle the error case of the unbounded values not fitting in your fixed-size integer values.

Most programmers likely simply either don’t consider that case, or don’t want to have to deal with it, so bad JSON libraries are the default.


This is actually a deliberate design choice, which the breathtakingly short JSON standard explains quite well [0]. The designers deliberately didn't introduce any semantics and pushes all that to the implementors. I think this is a defensible design goal. If you introduce semantics, you're sure to annoy someone.

There's an element of "worse is better" here [1]. JSON overtook XML exactly because it's so simple and solves for the social element of communication between disparate projects with wildly different philosophies, like UNIX byte-oriented I/O streams, or like the C calling conventions.

---

[0] https://ecma-international.org/publications-and-standards/st...

[1] https://en.wikipedia.org/wiki/Worse_is_better


It's an interesting discussion. There's always a divide when you slowly migrate from one thing to another.

What makes this interesting is that the difference between C code an Rust code is not something you can just ignore. You will lose developers who simply don't want or can spend the time to get into the intricacies of a new language. And you will temporarily have a codebase where 2 worlds collide.

I wonder how in retrospect they will think about the decisions they made today.


Most likely Rust will stay strictly on the driver side for several years still. It's a very natural Schelling fence for now, and the benefits are considerable, both in improving driver quality and making it less intimidating to contribute to driver code. It will also indirectly improve the quality of core code and documentation by forcing the many, many underspecified and byzantine API contracts to be made more rigorous (and hopefully simplified). This is precisely one of the primary things that have caused friction between RfL and the old guard: there are lots and lots of things you just "need to know" in order to soundly call many kernel APIs, and that doesn't square well with trying to write safe(r) Rust abstractions over them.


An example of the latter: drm_sched

https://vt.social/@lina/113051677686279824


What's the link for the lkml drama?


I'm not sure but I'm guessing it's this one https://lore.kernel.org/lkml/20230714-drm-sched-fixes-v1-0-c...


> and that doesn't square well with trying to write safe(r) Rust abstractions over them.

Or just using those kernel APIs, period.


I don't think changing to Rust code completely is something attainable. I guess some older or more closer to the metal parts will stay in C, but parts seeing more traffic and evolution will be more rusty after some time, and both will have its uses and have their islands inside the codebase.

gccrs will allow the whole thing to be built with GCC toolchain in a single swoop.

If banks are still using COBOL and FORTRAN here and there, this will be the most probable possibility in my eyes.


> I guess some older or more closer to the metal parts will stay in C

I suppose the biggest reason is that C programmers are more likely than not trained to kinda know what the assembly will look like in many cases, or have a very good idea of how an optimizer compiler will optimize things.

This reminds me I need to do some non-trivial embedded project with Rust to see how it behaves in that regard. I'm not sure if the abstraction gets in the way.


After writing some non-trivial and performance sensitive C/C++ code, you have feeling of how that code behave on the real metal. I have that kind of intuition, for example. I never had to dive to the level of generated ASM, but I can get ~80% of theoretical IPC with just minding what I'm doing in C++ (minimum branching, biasing branches towards a certain side, etc.).

So, I think if you do the same thing with Rust, you'll have that intuition, as well.

I have a friend who writes embedded Rust, and he said it's not as smooth as C, yet. I think Rust has finished the first 90% of its maturing, and has the other 90%.


I write embedded rust full-time and can say there's nothing that I can do in C that I can't do in rust. Sure the tools/frameworks are a lot more mature, but a combination of the PAC for register access (maybe a bit of community maintained HAL) and a framework like RTIC is pretty much all I need.


I am not convinced, given the amount of heavy lifting that the Rust type system does, that rusty Rust is nearly as brain-compilable as C. However, you can write the equivalent of C in many languages, and Rust is one of them. That kind of code is easy to compile in your head.


It's not brain-compilability, it's getting used to what that specific compiler does with your code you brain-compile.

So, I have a model for my code in my brain, and this code also has a real-world behavior after it's compiled by your favorite toolchain. You do both enough times, and you'll have a feeling for both your code and the compiler's behavior for your code.

This feeling breaks when you change languages. I can brain-compile Go for example, but compiler adds other things like GC and null-pointer protection (carry local variables to heap if you're going to hit a null pointer exception after returning a function). Getting used to this takes time. Same for Rust.


> I suppose the biggest reason is that C programmers are more likely than not trained to kinda know what the assembly will look like in many cases, or have a very good idea of how an optimizer compiler will optimize things

This is the only way Hellwig's objection makes any kind of sense to me. Obviously, intra-kernel module boundaries are no REST-APIs, where providers and clients would be completely separated from each other. Here I imagine that both the DMA module as well as its API consumers are compiled together into a monolithic binary, so if assumptions about the API consumers change, this could affect how the module itself is compiled.


I've done a non-trivial embedded project in C. (Quadcopter firmware). The language doesn't get in the way, but I had to write my own tooling in many areas.


Is there a layer where C is the sweet spot? Something too high-level for ASM, and too low-level for Rust? (not my area, so genuine question).


Many people still have the mistaken belief that C is still trivial to map to assembly instructions and thus has an advantage over C++ and Rust in areas where understanding that is important - but in practice the importance is overstated, and modern C compilers are so capable at optimising at high optimisation levels that many C developers would be surprised at what was produced if they looked much further than small snippets.

Like half the point of high-level systems languages is to be able to express the _effects_ of a program and let a compiler work out how to implement that efficiently (C++ famously calls this the as-if rule, where the compiler can do just about anything to optimise so long as it behaves in terms of observable effects as-if the optimisation hadn't been performed - C works the same). I don't think there's really any areas left from a language perspective where C is more capable than C++ or Rust at that. If the produced code must work in a very specific way then in all cases you'll need to drop into assembly.

The thing Rust really still lacks is maturity from being used in an embedded setting, and by that I mostly mean either toolchains for embedded targets being fiddly to use (or nonexistent) and some useful abstractions not existing for safe rust in those settings (but it's not like those exist in C to begin with).


Often the strong type system of C++ means that if take C code and compile it with a C++ compiler it will run faster. Though part of the reason it is faster C++ will allow the compiler to make assumptions that might be false and so there is a (very small IMHO) chance that your code will be wrong after those optimizations. C++ often has better abstractions that if you use will allow C++ to be faster than C can.

If Rust doesn't also compile faster than C because of the better abstractions that should be considered just a sign of compilers needing more work in the optimize and not that Rust can't be faster. Writing optimizers is hard and takes a long time, so I'd expect Rust to be behind.

Note that the above is about real world benchmarks, and is unlikely to amount to 0.03% difference in speed - it takes very special setups to measure these differences, while simple code changes can easially but several hundred percentage differences. Common microbenchmarks generally are not large enough for the type system to make a difference and so often show C as #1 even though in real world problems it isn't.


Rust is a systems programming language by design; bit-banging is totally within its remit, and I can't think of anything in the kernel that Rust can't do but that C could. If you want really, really tight control of exactly which machine instructions get generated, you would still have to go to assembler anyway, in either Rust or C.


The exact reason why it was created in first place, a portable macro assembler for UNIX, and should stayed there, leaving place for other stuff on userspace like Perl/Tcl/... on UNIX, or Limbo on Inferno, as the UNIX authors revised their ideas of what UNIX v3 should look like, already on UNIX v2 aka Plan 9, there was a first attempt with Alef.

Or even C++, that many forget was also born at Bell Labs on the UNIX group, the main reason being Bjarne Stroutroup never wanted to repeat his Simula to BCPL downgrade ever again, thus C with Classes was originally designed for a distributed computing Bell Labs research project on UNIX, that Bjarne Stroutroup certainly wasn't going to repeat the previous experience, this time with C instead of BCPL.


I'm not sure what you mean by "leaving place for". There was a place for Perl and Tcl on Unix. That's how we wound up with Perl and Tcl.

If you mean that C should have ceded all of user-space programming to Perl and Tcl, I disagree strongly. First, that position is self-contradictory; Perl was a user-space program, and it was written in C. Second, C was much more maintainable than Perl for anything longer than, say, 100 lines.

More fundamentally: There was a free market in developer languages on Unix, with C, Perl, Awk, Sed, and probably several others, all freely available (free both as in speech and as in beer). Of them, C won as the language that the bulk of the serious development got done in. Why "should" anything else have happened? If developers felt that C was better than Perl for what they were trying to write, why should they not use C?


This is kind of what I mean,

"Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue.... Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels? Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities."

-- Fran Allen interview, Excerpted from: Peter Seibel. Coders at Work: Reflections on the Craft of Programming

C's victory is more related to not having anything else as compiled language in the box than anything else regarding its marvelous technical capabilities, so worse is better approach, use C.

Even more so, when Sun started the trend that UNIX development tooling was paid extra, and it only contained C and C++ compilers, for additional compilers like Fortran and Ada, or IDE, it was even a bit more extra on top.

Which other UNIX vendors were quite fast to follow suit.


Thanks for the explanation.

But I've seen that quote before (I think from you, even). I didn't believe it then, and I don't believe it now.

There is nothing about the existence of C that prevents people from doing research on the kind of problem that Fran Allen is talking about. Nothing! Those other languages still exist. The ideas still exist. The people who care about that kind of problem still exist. Go do your research; nobody's stopping you.

What actually happened is that the people who wanted to do the research (and/or pay for the research) dried up. C won hearts and minds; Fran Allen (and you) are lamenting that the side you preferred lost.

It's worth asking why, even if Ada or Algol or whatever were extra cost, why weren't they worth the extra cost? Why didn't everybody buy them and use them anyway, if they were that much better?

The fact is that people didn't think they were enough better to be worth it. Why not? People no longer thought that these automatic optimization research avenues were worth pursuing. Why not? Universities were teaching C, and C was free to them. But universities have enough money to pay for the other languages. But they didn't. Why not?

The answer can't be just that C was free and the other stuff cost. C won too thoroughly for that - especially if you claim that the other languages were better.


Worse is better, and most folks are cheapy, if lemons are free and juicy sweet oranges have to be bought, they will drink bitter lemonande no matter what, eventually it will taste great.

Universities are always fighting with budgets, some of them can't even afford to keep the library running with good enough up to date books.


Well, why not? The price tag certainly is what did it for me.

I was twelve. C was free, the alternatives were not. By the time I could have paid for one, I’d been writing C for ten years…

Nowadays I wouldn’t touch it with a ten-foot stick.


> What actually happened is that the people who wanted to do the research (and/or pay for the research) dried up. C won hearts and minds; Fran Allen (and you) are lamenting that the side you preferred lost.

Eh, sort of. The rise of C is partially wrapped up in the rise of general-purpose hardware, which eviscerates the demand for optimizers to take advantage of the special capabilities of hardware. An autovectorizer isn't interesting if there's no vector hardware to run it on.

But it's also the case that when Java became an important language, there was a renaissance in many advanced optimization and analysis techniques. For example, alias analysis works out to be trivial in C--either you obviously prove they don't alias based on quite local information, or your alias analysis (no matter how much you try to improve its sensitivity) gives up and conservatively puts it in the everything-must-alias pile; there isn't much a middle ground.


Directly programming hardware with bit-banging, shifts, bitmasks and whatnot. Too cumbersome in ASM to do in large swaths, too low level for Rust or even for C++.

Plus for that kind of things you have "deterministic C" styles which guarantee things will be done your way, all day, every day.

For everyone answering: This is what I understood by chatting with people who write Rust in amateur and pro settings. It's not something of a "Rust is bad" bias or something. The general consensus was, C is closer to the hardware and allows handling of quirks of the hardware better, because you can do "seemingly dangerous" things which hardware needs to be done to initialize successfully. Older hardware is finicky, just remember that. Also, for anyone wondering. I'll start learning Rust the day gccrs becomes usable. I'm not a fan of LLVM, and have no problems with Rust.


> too low level for Rust or even for C++.

I'd love to hear a justification for why this is a thing. Doing bit-banging is no more difficult in Rust or C++ than in C.


You probably mean "C compatible-ish subset of C++98"


Two reasons I can think of off the top of my head.

The assembly outputted from C compilers tend to be more predictable by virtue of C being a simpler language. This matters when writing drivers for exotic hardware.

Sometimes to do things like make a performant ring buffer (without vec dequeue) you need to use unsafe rust anyway, which IMO is just taking the complexity of the rust language without any of the benefit.

I don’t really think there’s any benefit to using C++ over rust except that it interfaces with C code more easily. IMO that’s not a deal maker.


> The assembly outputted from C compilers tend to be more predictable by virtue of C being a simpler language.

The usual outcome of this assumption is that a user complains to the compiler that it doesn't produce the expected assembly code, which the compiler ignores because they never guaranteed any particular assembly output.

This is especially true for the kinds of implicit assembly guarantees people want when working with exotic hardware. Compilers will happily merge loads and stores into larger load/stores, for example, so if you need to issue two adjacent byte loads as two byte loads and not one 16-bit load, then you should use inline assembly and not C code.


I’m not saying every C compiler is always perfectly predictable, but by virtue of it being a simpler language it should Always be more predictable than rust, barring arcane optimizations.

I do agree that if someone actually cares about the assembly they should be writing it by hand.


> I’m not saying every C compiler is always perfectly predictable

No C compiler is predictable. First, there is the compiler magic of optimization.

Then you have Undefined Behavior, which in C, that's almost a guarantee, you'll experience inconsistent behavior between compilers, targets, optimization levels and the phases of the moon.

In Rust, use .iter a lot to avoid bound checks, or if you want auto-vectorization use a lot of fixed length arrays, and look how LLVM auto-vectorizes it. It takes getting used to it, but hey, so does literally every language if you care about SOURCE -> ASSEMBLY translation.


> The assembly outputted from C compilers tend to be more predictable by virtue of C being a simpler language.

That doesn't seem to be true, not in the presence of UB, different platforms and optimization levels.

> Sometimes to do things like make a performant ring buffer (without vec dequeue) you need to use unsafe rust anyway, which IMO is just taking the complexity of the rust language without any of the benefit.

If you write a data structure in Rust, it's expected to wrap the unsafe fiddly bits into a safer shell and provide unsafe access as needed. Sure, the inner workings of Vec, VecDeque, and Ring Buffers are unsafe, but the API used to modify them isn't (modulo any unsafe methods that have their prerequisite for safe access stated).

The idea is to minimize the amount of unsafe, not completely eradicate it.


Autovectorizing code is hardly predictable, or when folks land in UB mines that optimizers glady take advantage of.


Why exactly would it be too low-level for Rust?


> too low level for Rust or even for C++.

This doesn’t make any sense to me, could you explain why?


Rust does ok at this but typically works better with some tooling to make register and bit flag manipulation look more like normal rust functions. chiptool and svd2rust do this for microcontroller code using all rust. The only asm needed is going to be the bootup to setup enough to run rust (or C)


Honestly, if I need to do bit-banging, I'd go with Rust over C these days. Rust has a much richer set of bit primitives than C does.


"C is closer to the hardware" [citation needed]

This might have been true 50 years ago, I am unconvinced it was true 25 years ago, it would take a lot to convince me it's true today.


maybe generic implementations of crypto primitives and math kernels.


It strikes me that the former would profit from a strong type system, whereas the latter could profit from (enforced) strict aliasing.


> I wonder how in retrospect they will think about the decisions they made today.

The decision was not made today, what happens today (or, rather, a few days ago) is Linus calling out a C maintainer going out of his way to screw rust devs. Rust devs have also been called out for shitty behaviour in the process.

The decision to run a Rust experiment is a thing that can be (and is) criticized, but if you allow people to willfully sabotage the process in order to sink the experiment, you will also lose plenty of developers.


Do colors have any significance in those flame graphs? It's unfortunate that a post about them does not mention anything about colors. If you look at at the examples, there are bars, which have the same length, but the colors look random to me.


Yes they are random. See the blog about the inventor of the flame graph, how we know them today

> Neelakanth and Roch's visualizations used completely random colors to differentiate frames. I thought it looked nicer to narrow the color palette, and picked just warm colors initially as it explained why the CPUs were "hot" (busy). Since it resembled flames, it quickly became known as flame graphs.

https://www.brendangregg.com/flamegraphs.html


G'mic is a great tool. I use the QT-Plugin for Krita.

The only problem I have is that I don't use it very much and if I do, I'm just overwhelmed by all the effects and parameters. I'm sure there's great value there... But, if you don't know exactly what you're looking for? Well, be prepared to click around for ages finding something cool. I have no idea how to improve that, but I find it annoying.

It would be also great for the effects to not be destructive. Like using it with filter layers. But unfortunately this seems not to be possible.


Yeah, and if you do that long enough, eventually there will be generation of consumers which think that it is totally normal.

I remember a time, when I set specific firewall rules for each application. A time where I would never allow to share my location. A time where I would never link my google account to other services. But as I grew older I stopped caring because I have other stuff to do.

The problem is, that those companies have time on their side. They can do whatever they want, back out, constantly rebrand stuff and confuse their users until we eventually give up. And at some point a large part of the population stops caring, because it's a fight, which is very hard to win. I hate it, but I have not the strength, time and will to push back.


I avoided wordpress like a plague. Used stuff like django, flask, grav and who knows what. But recently I had to make a website with lots of unknowns which needed to be authored by dummy users and I just said ** it and went with wordpress.

What I struggled with are: 1) Interesting site design, 2) custom functionality through plugins, 3) making it easy to add pages and blog posts with a nice editor.

I'm glad open source solutions exist, but I swear, they always have drawbacks. Either they are code heavy, plugins are out of date, maintenance takes a lot of time or there is no way to easily design a page.

So for Wordpress I bought Oxygen, for which you can still buy a lifetime license for, and oh my god, even I can make a nice, responsive website without touching code. It's such a game changer.

I think lots of people avoid wordpress because of security. But that is not primarily a wordpress fault. Linux & PHP complicates it a lot. And I'm sure those other open source projects have severe bugs, too, but nobody knows or talks about them.

What could bring down wordpress, imho, are expensive license fees for plugins. Who wants to spend 50 to 100 bucks per year and per page for a builder plugin? Everyone wants one, but no one wants to pay yearly. And it seems that all plugin makers are starting to go that way.


I agree about builder plugins -- they are expensive mossy lock-in.

WordPress now has a full-site editing system that lets you GUI edit the templates that are in the normal flow. It is not what I would call easy to master at the code level, but there is a global styles system and a way to use Gutenberg blocks to control layout outside the main content flow.

So we are getting towards a point where page builder plugins won't be needed for skilled shops. But IMO until there are really easy to use themes based around FSE (there may be some), small design shops are still likely to use Elementor, which is a slow, frustrating experience (slower and more frustrating than Squarespace can be)


Reminds me of an article about the testing infrastructure of League and Legends [1] back in 2016. 5500 tests per build in 1 to 2 hours.

Games are extremely hard to test. For me it falls into the same category like GUI testing frameworks which imho are extremely annoying and brittle. Except that games are comparable to a user interface consisting of many buttons which you can short and long press and drag around while at the same time other bots are pressing the same buttons, sharing the same state influenced by a physics engine.

How do you test such a ball of mud which also constantly changes by devs trying to follow the fun? Yes you can unittest individual, reusable parts. But integration tests, which require large, time sensitive modules, all strapped together and running at the same time? It's mindboggling hard.

Moreover if you're in a conceptual phase of development and prototyping and idea, tests make no sense. The requirements change all the time and complex tests hold you back. But the funny thing is, that game development stays in that phase most of the time. And when the game is done, you start a new one with a completely different set of requirements.

There are exceptions, like League of Legends. The game left the conceptual phase many years ago and its rules are set in stone. And a game which runs successfully for that long is super rare.

[1] https://technology.riotgames.com/news/automated-testing-leag...


I recall some Minecraft tests being saved worlds with redstone logic that will light a beacon green if it is working or red if not. That's usefull for games like that.

For games like Starcraft 2 with replay functionality, you could probably record/use several matches and test that the behaviour matches the recorded behaviour. If you can make your game have a replay feature you can make use of this, even if you don't ship that replay code.

For things like CYOA type games or decision trees, you could have a logging mechanism that prints out the choices, player stats, hidden stats, etc. and then have a way to run through the decisions, then check the actual log output against the expected output. -- I've done something similar when writing parsers by printing out the parse tree (for AST parser APIs) or the parse events (for reader/SAX parser APIs).

I'm sure there are other techniques for testing other parts of the system. For example, you could test the rendering by saving the render to an image and comparing it against an expected image. IIRC, Firefox does something similar for some systems like the SVG renderer and the HTML paint code.

Various of these features (replay, screenshots) are useful to have in the main game.


You're right about parts, which are mostly state machines. The have a defined input and output. Tests are straightforward to implement and adjust.

But recording and replaying matches? Taking screenshots and comparing the output? Just think about it: If you have recorded a match and change the hitpoints of a single creature, the test could possibly fail. And then? Re-record the match?

The same applies to screenshots: What happens if models, sprites or colors change?

In my experience, tests like this are annoying, because:

1) They take a long time to create and adjust/recreate.

2) They fail for minor reasons.

3) It takes time to understand, what such tests even measure, if someone else made them.

4) You need a large, self made framework to support such tests.

5) It takes a long time to run them, because they are time dependent.

6) They hinder you to make large changes.

7) It's cheaper to make some low wage game testers play your game. Or better, make the game early access and let 1000s of players test your game for free, while even making money out of them


Yes, when you are trying to intentionally change the output, you simply regenerate the gold file to be used as reference (and yes, it should be easy). It’s brittle for sure but it does catch unintentional changes and should be used where relevant (if sparingly). There are definitely existing frameworks that do this (eg Jest calls this snapshot testing and has tooling to make it easy).

I’m sorry your experiences with this kind of stuff have been bad. I’ve generally had good experiences in the machine learning space where we used it judiciously where appropriate but didn’t overdo it.

I don’t see how it can ever hinder you though - you can always choose to go “I don’t care that the output has changed dramaticallly - it’s the new ground truth” as long as you communicate that’s what happening in your commit. What it doesn’t let you do is that the output is different every time you run it but that’s generally a positive (randomness should be intentionally injected deterministically).


I doubt Dota 2 devs are writing code like this to test. The game is far too complicated, even more so than league, and changes a lot over the years, for this to be viable.

Dota 2 and openai had a collaboration in 2018ish, and during this time the Dota 2 bots system was reworked completely. They already can generate videos of every spell in action [1], and I would assume this is done by asking AI bots to demonstrate the spell. My guess is that before pushing out an update, a human looks at these videos and other more complex interaction videos for every major change, along with relevant numbers (damage, healing, movement speed), and see if everything makes sense.

I think this, because a lot of times recently, changes in one hero often cause an un-updated hero to break, because they had some backend similarity. And the patch is released with the bug.

Then again, there is no public info, so all the above are wild speculations.

[1] example https://www.dota2.com/hero/treantprotector


> They already can generate videos of every spell in action [1]

I'm fairly certain those videos are all handmade. (Yes, all 500+ of them.) Notice that the videos for each hero are recorded in different locations on the map, and the "victim" hero isn't always the same.


In my experience (full stack web development), unit tests are mostly useless and it is the high-level system tests which add real value. Unfortunately it can take a fair amount of work or skill to architect the test suite in the first place, but once it’s working you can write elegant tests that verify large swathes of code with fairly few lines of test code.

I think UI testing in general is hard though, and given how large a part of games involves UI, that’d be the real reason games don’t have much tests.


Agreed. We don't have a lot of UI unit tests in our software in our day job (almost none), but we have extensive tests for utility and data processing functions.

And that's pretty much the same for me in the game I'm making in my spare time. I have no unit tests for UI (it's not worth it, I can easily see when something in the UI isn't working, it's more important for me to just log the bug so I don't forget about it).

But for game logic, like verifying calculations for A.I. are happening as expected, or functions that manipulate numbers on the screen in different ways (scores, power adjustment, etc), yeah I write unit tests for those. And to the article's point, sometimes I have to significantly adjust or redo or even scrap them because I happened to think of a different mechanism and it seems to play better.

There was a long time (over about a dozen games I made) where I never bothered to write a unit test, and I still might not for a tiny game. But for my most recent bigger game (which I started a few years ago), I finally decided to write a few for some tricky numeric logic in the game, and it immediately helped me resolve a logic bug I was seeing periodically but was having a hard time pinning down the cause of it with breakpoints and logs. So I do try to do it more often for checking those things.


Part of it is terminology. You get "unit testing" and "functional testing" and "integration testing" and "system testing" thrown around, often with people meaning different things by these, and vague definitions that partially or wholly overlap.

My rule of thumb is really simple: a test should always be defined in terms of what the user expects. Thus for most apps you should, at the minimum, have tests corresponding to their functional specification. In addition, if the app contains functionality that is consistently reused inside (i.e. embedded libraries), then users of those libraries are the code that calls into them, and so there should also be tests at that boundary (but only after you wrote the high-level tests). Repeat recursively until you get to the bottom.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: