wfleming
I’ve had people tell me I should try selling some of the furniture I make and my response is always that I made the mistake of turning a hobby into a career once, I don’t intend to make that mistake again, and at least software still pays pretty well.
Pass has a pretty good ecosystem of plugins/other clients, as well. There are open source iOS/Android clients and browser extensions so once you’re setup the day-to-day experience is not far off from any of the popular hosted password managers.
My only real issue is the dependency on gpg, as it’s pretty long in the tooth and a hassle to operate. (If you are not comfortable using gpg, spend some time learning that before you go all-in on pass!) There’s a fork[1] which swaps gpg for age, but it hasn’t attracted enough attention to get a similar ecosystem of mobile clients/browser extensions, so it’s not a very practical choice IMHO.
1. IE was the default browser for many users (i.e. anybody using Windows who didn't know better).
2. IE had a lot of bugs and and was often non-compliant with standards.
Those two things combined meant that supporting IE required additional work, and if you didn't put in that work you were going to get users from IE anyway they'd just get frustrated and confused when things broke. So "detect IE and tell them use something else" was at least a reasonable fixed-cost approach to not having users get totally stuck. (And IE went down to 2-3% at least in part because devs revolted against IE earlier and started serving those "don't use IE" messages when its usage was still higher.)
Neither factor is really true of FF. It's not the default for any major platform, its user-base at this point is largely power users who won't be easily confused, and outside of some non-standard APIs most sites don't need and some fairly edge-casey stuff, most sites that work on Chrome will work fine on FF as well without alteration. If anything, IME Safari is more likely to need special attention than FF (but of course Safari has much higher market share so it merits that effort).
So I totally get not wanting to spend QA budget on FF, and I could understand showing a small banner suggesting you use a different browser, but erroring/completely blocking usage of the site does feel excessive to me, and even a bit mean-spirited since it takes extra effort to detect FF to show the message and prevent using the site! I don't think these sites are going out of their way to block usage of other low-usage browsers (some of which can alter behavior that could break some sites even if they are Chromium-based).
- part 1: https://youtu.be/xnWKz7Cthkk
- part 2: https://youtu.be/xnWKz7Cthkk
- part 3: https://youtu.be/kFnVZXQD5_k
Edit: Wikipedia actually says associativity is definitionally about changing parens[0]. Mostly amounts to the same thing for standard arithmetic operators, but it’s an interesting distinction.
* ignoring the case of ethical assisted suicide for reasons of terminal illness and such, which doesn’t seem relevant to the case discussed here.
[1]: https://apps.apple.com/us/app/pass-password-store/id12058205...
I think this is wrong? If you memoize a callback with useCallback and that callback uses something from props without putting it in the dependency array, and then the props change & the callback runs, the callback will use the original/stale value from the props and that's almost certainly a bug.
They might be trying to say you just shouldn't use useCallback in that situation, but at best it's very confusingly written there because it sure sounds like it's saying using useCallback but omitting a dependency is acceptable.
IMHO useCallback is still a good idea in those situations presuming you care about the potential needless re-renders (which for a lot of smaller apps probably aren't really a perf issue, so maybe you don't). If component A renders component B and does not memoize its own callback that it passes to B as a prop, that is A's problem, not B's. Memoization is easy to get wrong by forgetting to memoize one spot which cascades downwards like the screenshots example, but that doesn't mean memoization is never helpful or components shouldn't do their best to optimize for performance.
You’re right that “most” houses can’t be within walking distance of a corner store outside cities, but my anecdata experience is those residential communities can definitely support those businesses. They might require a short drive, but they’re still a lot closer than the shopping center, and a mix of “ran out of one thing”, deli/breakfast sandwiches, and beer keeps them in business.
This behavior is why `SeparateDatabaseAndState` is a necessary hack in Django: sometimes you need to do an `AlterField` where the SQL Django would generate is really bad, so you need to write your own `RunSQL` to do the right thing, but you also need Django to see the `AlterField` as applied or you'll have problems with future migrations.
I suppose I could modify my preference to "run makemigrations and then wrap every single op in SeparateDatabaseAndState", but that does not sound fun :).
The point about Django’s choices about default and not-null though is that it can easily lead to crashes while you’re adding fields. If you add a string field with default=“” and don’t specify null=False, the generated schema will be a non-null field without a default value in SQL, but Django will backfill “” into all existing rows. To avoid downtime, you need to deploy migrations & apply them, then deploy the models.py/other code changes. But if anyone tries to write a new row before the new code finishes deploying after applying the migration, it will crash.
My explanation of Django's approach to migrations would involve a lot more expletives. It is by far my least favorite thing about the framework.
- Fields are not-null by default, the opposite of SQL itself
- Field declarations use argument names that sound like the SQL equivalents (default, on delete cascade/restrict), but they're fully enforced in python and don't make it into the SQL schema at all by default. I get that not every DB supports these features, and there are sometimes good reasons for doing something like a delete cascade in process (if you need to implement custom on-delete logic or something), but the DSL shouldn't read like SQL if it's not going to change the SQL schema. The default value thing combined with not-null by default is particularly easy to get bitten by adding a new field with default if you deploy migrations separately from deploying code (which you must do to avoid downtime): if you add a new field with a default value believing it's safe, you will probably get crashes in the interval between applying the migration & the new code deploying because you've got not-null column without a default value in the schema. They did finally add db_default recently, thankfully, but it took years!
- Django migrations cannot be understood in isolation, the sql a generated migration containing something like an AlterField operation will run depends on what earlier migrations say. You have to check with the sqlmigrate command and/or actually read earlier migrations to be sure you understand what the migration will do. Compared to Rails, where each migration can be read and understood in isolation (though you may still need to understand how a Rails migration DSL will translate to actual SQL of course). This also has a performance impact making Django migrations slower because Django has an in-memory model of what the schema should be at each migration point, so running a migration is not just "load the file and run the commands", it's "determine the schema that should exist after running this migration, diff that with the schema we think exists before this point, magically generate SQL for that diff, then run that".
- The makemigrations command to auto-generate pending migrations is very aggressive and will detect things as "changed" that don't impact the schema. If you changed some help text on a field, or a localization string, or the aforementioned only-in-python default value, makemigrations will see that as requiring a migration that does nothing. Leads to lots of cruft.
- Related to both of the above points, AlterField's auto-generated SQL can be dangerous and bad. Particularly, I've seen cases where very minor changes to a ForeignKey (like changing from nullable to not-nullable, or even not-schema-impacting changes like above) would, by default, have dropped the foreign key constraint & index, and then re-created them. Completely unnecessary and potentially dangerous since it could be locking a large table. I'm not positive, but in some cases I think these have been generated purely because of a django upgrade leading to it deciding the names of the indexes/constraints need to be changed for some reason.
- AlterField will also tend to stomp all over any tweaks you manually made to the schema to work around all these issues. If you manually wrote a SQL statement in an earlier migration to add a default value to a column, and then that column's definition gets tweaked months or years later the generated AlterField is gonna remove your default value. At a technical level this isn't surprising when you understand how Django is modeling the schema internally & generating the SQL changes, but it's definitely a bad user experience downstream of a lot of these design decisions.
Generally the field declaration/migrations system in Django feels to me designed to lead people down a garden path towards bad and dangerous behavior. If I had my druthers I'd enforce a policy in our Django app of "never run makemigrations, all migrations must be manually written SQL".
Combine that with the fact these languages are often used to make CRUD websites where I/O is likely to be a bigger performance factor than CPU and the faster alternatives look a lot less appealing.