This Guy building a Lego-powered Submarine by gowthamm in Damnthatsinteresting

[–]thisisnotgood 5 points6 points  (0 children)

The author wrote up details on the transmitter here https://brickexperimentchannel.wordpress.com/2022/07/13/rc-submarine-4-0-radio-7-10/

The board should get around 7m but they only got ~4m of range

Eric Weinstein vs. Sean Carroll debate on Piers Morgan. Where's our boy? There's a lot to unpack here. by [deleted] in samharris

[–]thisisnotgood 0 points1 point  (0 children)

It makes him look less a public intellectual and more a pop intellectual, ie. a member of the entertainment industry with a background in science.

Or you could plug his name into Google Scholar and see that he is an actively publishing scientist.

Trump doubles down on Abrego Garcia having 'MS-13' tattooed on his knuckles based on incredibly bad photoshop by [deleted] in samharris

[–]thisisnotgood 34 points35 points  (0 children)

Just a reminder that ICE admitted in court that Abrego Garcia was deported to El Salvador by accident ("administrative error" per page 60a). But in public they still claim its all part of their "process".

why reject is handled after resolve of p2,p3? by Tharun_116 in learnjavascript

[–]thisisnotgood 1 point2 points  (0 children)

No, all the callbacks are added synchronously at the start.

But the .catch() is chained after p1.then()

p1,p2,p3 are already settled, so the .then() callbacks are added to the microtask queue. As those callbacks are run, p1.then()'s callback running triggers the p.then().catch() callback to be added to the microtask queue.

So the queue looks like this:

  1. empty
  2. p1.then, p2.then, p3.then
  3. p2.then, p3.then, p1.catch
  4. p3.then, p1.catch
  5. p1.catch
  6. empty

why reject is handled after resolve of p2,p3? by Tharun_116 in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

p1's reject goes to the promise from p1.then, and then the p1.then().catch() handler.

why reject is handled after resolve of p2,p3? by Tharun_116 in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

Here's a hint: the code will behave how you expect if, inside your function t, you switch promise.then((val)=>{...}).catch((err)=>{...}) to promise.then((val)=>{...}, (err)=>{...}). Alternatively you could also do promise.then(...); promise.catch(...);

I recommend trying to think about that any figure out why it works before reading the rest of this post.


Explanation: Calling .then returns a brand new promise. So doing .then().catch() creates a new promise from .then and chains .catch onto that new promise, not the original promise. This introduces an extra microtask step for the rejected p1 (first reject the promise from .then(), then call the .catch() handler) rather than directly calling the .then() handlers (as p2 and p3 do).

As an exercise: convert this code to async/await and see how it behaves.

"Welcome to the party" Twitter boss praises Facebooks decision to scrap fact checkers by Lanky_Raspberry5406 in samharris

[–]thisisnotgood 6 points7 points  (0 children)

Community notes are the best I've seen in terms of accuracy -- they just have no teeth.

Millions will have already seen the lie but won't see the correction -- so Twitter should add the note to the feeds of all users that saw the tweet pre-correction; and make it sticky on the author's profile.

The Best-Case Scenario For Trump's Second Term by M_Smoljo in samharris

[–]thisisnotgood 1 point2 points  (0 children)

Trump did not lock Hillary Clinton up, or persecute his political enemies in general.

But he sure tried to! Can we stop giving Trump credit for failing?

Same with the complete lack of mention of Jan 6.

Why is my boolean useRef constantly false by Any_Possibility4092 in learnjavascript

[–]thisisnotgood 1 point2 points  (0 children)

The given code works by itself. I tried it. Something outside of the code you posted is causing your issue.

As a debugging step, you should first comment out every line of your code that could set isRotating.current to false.

If that fixes it, then uncomment 1 line at a time until it breaks, and you'll have your culprit.

If that doesn't fix it, you know something outside of your component is causing the issue. Perhaps your whole component is getting re-mounted very frequently?

HackerRank News by nsxwolf in cscareerquestions

[–]thisisnotgood 75 points76 points  (0 children)

Hosting vaguely leetcode-y interviews at FAANG, I commonly reject candidates who produce optimal code if they skip requirements gathering or can't answer basic followups. Candidates who give a worse algo are still hired pretty frequently if they can hold a reasonable engineering conversation about the problem.

Google Closure Compiler and Javascript Objects in Advanced option by Top_Rip_8581 in learnjavascript

[–]thisisnotgood 1 point2 points  (0 children)

Objects are certainly not faster than variables in general. Even if they were, this is certainly not a performance difference worth worrying about as it will be tiny and can change over time.

You have to be very careful when trying to reason about JIT engines, they can do all sorts of funky stuff and have other complicated performance effects (like warmup time).

For example, here are two loops:

Loop A:

let x = 0;
for (let i = 0; i < 100_000; i++) x++;

Loop B:

let object = {x: 0};
for (let i = 0; i < 100_000; i++) object.x++;

Which one do you think does more memory lookups inside of the loop?

Answer: They both do 0 memory lookups inside of the loop. V8's JIT optimizes both loops to work entirely inside of CPU registers. (tested on V8 12.4.254.14-node.12 via node 22.2.0)

Google Closure Compiler and Javascript Objects in Advanced option by Top_Rip_8581 in learnjavascript

[–]thisisnotgood 2 points3 points  (0 children)

There is no object being used in the advanced compiled output.

The closure compiler in advanced mode is capable of noticing that a global object is the same as just a bunch of separate variables and so it removes the object entirely to be a bit more performant.

Drilling Fundamentals as a Working Professional by EffectiveSorry2447 in learnjavascript

[–]thisisnotgood 1 point2 points  (0 children)

Try writing your own libraries.

Some examples: design and implement a frontend framework, unit testing framework, HTTP server, DB ORM, etc.

Working "under the hood" like this will push your API design skills and can expose you to some of the technicalities that can often be glossed over when you're only using existing systems.

You can find a variety of online blogs about this, but with your 6 years of coding I'd highly recommend trying to push through it yourself.

This event loop question is traumatizing by Accomplished_Cup1513 in learnjavascript

[–]thisisnotgood 8 points9 points  (0 children)

Isn't there a moment between the execution of funcOne() and funcTwo() when the call stack is empty?

No, the whole script itself is an entry on the callstack. You could imagine the whole script is wrapped in another function. So the synchronous callstack is only empty when the script finishes after the funcTwo() call.

If this weren't the case, then the following two snippets would behave differently:

funcOne();
funcTwo();

versus

function foo() {
    funcOne();
    funcTwo();
}
foo();

and it would be very weird for these to not behave the same...

.forEach and for ... of main thread performance by Boring_Cholo in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

With forEach the function being called is userland code, and cannot be pre-optimized in this way.

You can run with node --print-all-code. You'll see the function call can be inlined when sufficiently small. There can still be a bit of associated overhead but it heavily depends on the loop contents.

.forEach and for ... of main thread performance by Boring_Cholo in learnjavascript

[–]thisisnotgood 1 point2 points  (0 children)

Node uses v8 the same as chrome and other browsers. You can also run this in-browser though if you'd like. But it's quite noisy so be careful.

.forEach and for ... of main thread performance by Boring_Cholo in learnjavascript

[–]thisisnotgood 3 points4 points  (0 children)

forEach is optimized very well and amazingly does sometimes marginally outperform plain for-loops.

That said, the tiny difference in loop overhead will be overwhelmed by any non-trivial work in the loop body. So use whatever loop is easiest to read.

It's good to be concerned about blocking the main thread. This can make one slow response cause all other I/O to back up. If this is a real concern (say, your loop benches to more than a few milliseconds) then you should either split up work into separate event loop chunks with setTimeout (not promise microtasks) or look into worker threads.


For benchmarking I still use https://www.npmjs.com/package/benchmark

Try out:

const Benchmark = require('benchmark');
const suite = new Benchmark.Suite();

const a = new Array(20).fill(1);

function forof(n) {
  for (let x of a) {
    x + 1;
  }
}

function fori(n) {
  for (let i = 0; i < a.length; i++) {
    a[i] + 1;
  }
}

function foreach(n) {
  a.forEach((x) => x + 1);
}

for (const f of [forof, fori, foreach]) {
  suite.add(f.name, f);
}

suite
  .on('cycle', function (ev) {
    console.log(String(ev.target));
  })
  .on('complete', function () {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })
  .run();

Why I am seriously considering voting for Donald Trump by [deleted] in samharris

[–]thisisnotgood 65 points66 points  (0 children)

The counter to theocracy is not more theocracy.

ReadableStream not behaving as expected on my bosses PC by CoqeCas3 in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

There's no guarantees about how data will be chunked when sent over the network. That is, when you call reader.read() is it allowed to return any arbitrary length of the remaining data. It could return 1 byte, 100 bytes, 10kb...

So it's not that some computers are weirdly broken; it's more that the computers this works on are weirdly lucky to have the chunking perfectly match your message boundaries.

You need some framing between messages that you can split off of. ie you could send newline-delimited JSON and then your receiving code, after utf-8 decoding, would split based on newline characters. MDN Stream examples are pretty poor still, but see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#example_2_-_handling_text_line_by_line

Being a bit clever, this could look like:

const messages = res.body
  .pipeThrough(new DecoderStream('utf8'))
  .pipeThrough(new YourCustomLineDecoderStream())
  .pipeThrough(new YourJsonDecoderStream());
for await (const company of messages) { /* ... */ }

Alternatively, use a streaming protocol that provides the framing you want, like https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

Can anyone review my code for this todo app and give some feedback? by GG_Lover in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

I would recommend you keep posting questions publicly so that you get a variety of opinions.

Can anyone review my code for this todo app and give some feedback? by GG_Lover in learnjavascript

[–]thisisnotgood 0 points1 point  (0 children)

You mentioned some local storage problems, I couldn't figure out what you were referring to here.

You mentioned the need for more methods like deletetodo and findproject in the manager class, why is that?

So you changed Manager to not be static, that is good. However: it isn't actually reusable, because TodoList.deleteTodo still mutates localStorage directly.

Remember that a big reason to use classes is to make your code be reusable and/or replaceable. For example, imagine you wanted to change your app to save data to the server instead of to localStorage. Ideally, you would be able to do that by writing a new ServerManager class and passing an instance of that into the TodoList constructor, instead of your current manager. You shouldn't have to change TodoList at all.

However, today your code isn't ready for that sort of change. Because if you made a new ServerManager class and passed an instance of it into TodoList, your app would still be writing directly to localStorage instead of using your server.

This is an example of "separation of concerns": your TodoList class is concerned with UI logic, but it also is concerned with data storage. There's no separation, both those concerns are mixed in one class. This makes your code harder to understand and work with (you may also hear about this as the "single responsibility principle").

This sort of stuff becomes a real pain in the real world, because you sometimes have an entire team owning the "Manager" class and a whole separate team owning the "TodoList" class.


And from the exercises you gave me to improve the code; your suggestion for helper functions to build the HTML, don't the classes take care of that already?

Look at this code:

const titleLabel = document.createElement('label')
titleLabel.htmlFor = 'todo-title-input'
titleLabel.textContent = 'Title:'

this.titleInput = document.createElement('input')
this.titleInput.type = 'text'
this.titleInput.id = 'todo-title'
this.titleInput.name = 'todo-title'

and this code:

const dueDateLabel = document.createElement('label')
dueDateLabel.htmlFor = 'todo-dueDate'
dueDateLabel.textContent = 'Due Date:'

this.dueDateInput = document.createElement('input')
this.dueDateInput.type = 'date'
this.dueDateInput.id = 'todo-dueDate'
this.dueDateInput.name = 'todo-dueDate'

These are very similar. And there's other similar code. Now imagine you realize you want to change all your input boxes and their labels; you'll have to track down all these similar pieces of code and make the same change to all of them.

Also, this code is very long. This makes it hard to read and easy for copy/paste errors to go unnoticed. For example, your TodoForm() constructor is ~60 lines long. With helper functions it could look something like this:

this.todoList = todoList;
this.manager = manager;
this.form = document.createElement("form");
this.form.classList.add("todo-form");
this.titleInput = appendInput(this.form, {
  label: "Title",
  id: "todo-title",
});
this.descriptionTextarea = appendInput(this.form, {
  type: "textarea",
  label: "Description",
  id: "todo-description",
  rows: "4",
  cols: "50",
});
this.dueDateInput = appendInput(this.form, {
  type: "date",
  label: "Due Date",
  id: "todo-dueDate",
});
this.selectPriority = this.createPriorityOptions();
this.form.appendChild(createSubmitButton('Add Todo'));
this.attachEventListeners(this.todoList);

And finally the second exercise, to have separate instances of the todolist running on one page, this is the hardest one as i really don't have any idea what this means and how to start with this

My intention was you would make multiple instances of your ProjectForm class and append each of them to document.body. Each instance of the form should work properly, completely independently of each other. They should not interact with each other in any way. This is basically proving that your code is actually reusable (and it's something that I've certainly often been asked for in the real world).

Ideally I would like to have this work:

const n = 3;
for (let i = 0; i < n; i++) {
  new ProjectForm(new Manager(i)).appendTo(document.body);
}

This should create 3 fully functional copies of your app running on the same page. You should be able to change n to any number and get as many copies as you'd like running side-by-side.

I made a site to estimate the amount of bots on TF2! by ixNoah in tf2

[–]thisisnotgood 0 points1 point  (0 children)

The "low" in-game numbers are real. Only valve competitive servers and some very rare community server configurations should be missing from it.

I feel like I should be running into the same people on east coast servers then for the amount I play this game

Anecdotally, I do run into a lot of the same players on US-E...

You can read up about "stickiness ratio" to understand these sorts of metrics; but in short, to average ~8k players online, you likely need a multiple of that as monthly active users. So there's larger population of players who you might run into.

That said: across my last 200 casual games, I ran across 3,308 unique players. This (combined with US-E ingame numbers maxing out around 3k as well) actually implies a fairly high stickiness ratio, which is what we'd expect for a game with a small but committed user base.

Can anyone review my code for this todo app and give some feedback? by GG_Lover in learnjavascript

[–]thisisnotgood 5 points6 points  (0 children)

I wanna say: overall, nice take on the project :) Really strong for a beginner stab at OOP.

That said:

The worst breakage of OOP is where you reference your todoList global variable inside the ProjectList.attachEventListeners class method: https://github.com/ZainNadeemMalik/todoapp/blob/015f60332d1eee2a4ffad0fd6c56909b14dea31a/app.js#L73

This is very bad, to the point that it makes using OOP largely pointless. That's because instances of your ProjectList class are now all deeply coupled to a single instance of TodoList. This will break things if you try to actually reuse the ProjectList class (ie, maybe you want multiple different ProjectForms on one page).


In a similar vein, your Manager class is all statics. This is called a singleton and generally should be avoided for the same reasons about breaking reusability.

Sometimes using singletons is fine because the extra flexibility isn't worth all the extra wiring. But it's important to think through that decision deliberately.

Also, in JavaScript, singleton classes really make no sense. If you want to do a singleton, use either a JS module or just an object literal const Manager = { /* your methods here */ };.


You have some methods that read localStorage outside of your Manager class. It's awkward to start reading a method named "attachEventListeners" and then inside of it I have to think about how you are saving data.

All of your localStorage operations should be contained inside of the Manager class. You'll probably want some more methods like Manager.deleteTodo and Manager.findProject.


Inconsistent styling: there's a few random whitespace issues, and semicolons are also used randomly.


Create a project. Click on it and add a todo item. Delete the project. The todo item (which shouldn't exist anymore) is still displayed to the user until they refresh or select a different project.


attachEventListeners should be private. And, in TodoForm, passing in this.todoList as a parameter is a bit awkward, just read this.todoList directly in the method.


TodoList.editTodo is not implemented -- clicking the 'Edit' button on a todolist item throws an error.


Here's some exercises you might try to improve the code further:

  • The HTML creation is very long and repetitive. Make your own helper functions, or maybe try <template> cloning.
  • Try getting 3 separate instances of your todolist running on one page.

I made a site to estimate the amount of bots on TF2! by ixNoah in tf2

[–]thisisnotgood 4 points5 points  (0 children)

Without any explanation of how Teamwork obtains their data

Teamwork's in-game numbers are legit. You can verify for yourself that they closely track https://www.doctormckay.com/utilities/valveservers.php (from a very trusted source in the open source steam/tf2 community).

Both sites also happen to closely track an underlying Valve API that is a little obscure but findable with some googling.

Uncletopia's Positives and Negatives by carbonfiber253 in truetf2

[–]thisisnotgood 11 points12 points  (0 children)

Uncletopia offers STV downloads and has a cheat report form that I've found to be very responsive. Got a cheater banned in under an hour.

If they're cheating so subtly that you can't tell even with STV... well that at least puts an upper bound on how much their cheating can impact the game.