I’m not saying you’re wrong or that Web Environment Integrity is a good thing, but a primary source and citation is needed for this statement:
It enforces the original markup and code from a server to be the markup and code that the browser interprets and executes, preventing any post-loading modifications.
Circular dependencies can be removed in almost every case by splitting out a large module into smaller ones and adding an interface or two.
In your bot example, you have a circular dependency where (for example) the bot needs to read messages, then run a command from a module, which then needs to send messages back.
v-----------\
bot command_foo
\-----------^
This can be solved by making a command conform to an interface, and shifting the responsibility of registering commands to the code that creates the bot instance.
main <---
^ \
| \
bot ---> command_foo
The bot
module would expose the Bot
class and a Command
instance. The command_foo
module would import Bot
and export a class implementing Command
.
The main
function would import Bot
and CommandFoo
, and create an instance of the bot with CommandFoo
registered:
// bot module
export interface Command {
onRegister(bot: Bot, command: string);
onCommand(user: User, message: string);
}
// command_foo module
import {Bot, Command} from "bot";
export class CommandFoo implements Command {
private bot: Bot;
onRegister(bot: Bot, command: string) {
this.bot = bot;
}
onCommand(user: User, message: string) {
this.bot.replyTo(user, "Bar.");
}
}
// main
import {Bot} from "bot";
import {CommandFoo} from "command_foo";
let bot = new Bot();
bot.registerCommand("/foo", new CommandFoo());
bot.start();
It’s a few more lines of code, but it has no circular dependencies, reduced coupling, and more flexibility. It’s easier to write unit tests for, and users are free to extend it with whatever commands they want, without needing to modify the bot
module to add them.
This may be an unpopular opinion, but I like some of the ideas behind functional programming.
An excellent example would be where you have a stream of data that you need to process. With streams, filters, maps, and (to a lesser extent) reduction functions, you’re encouraged to write maintainable code. As long as everything isn’t horribly coupled and lambdas are replaced with named functions, you end up with a nicely readable pipeline that describes what happens at each stage. Having a bunch of smaller functions is great for unit testing, too!
But in Java… yeah, no. Java, the JVM and Java bytecode is not optimized for that style of programming.
As far as the language itself goes, the lack of suffix functions hurts readability. If we have code to do some specific, common operation over streams, we’re stuck with nesting. For instance,
var result = sortAndSumEveryNthValue(2,
data.stream()
.map(parseData)
.filter(ParsedData::isValid)
.map(ParsedData::getValue)
)
.map(value -> value / 2)
...
That would be much easier to read at a glance if we had a pipeline operator or something like Kotlin extension functions.
var result = data.stream()
.map(parseData)
.filter(ParsedData::isValid)
.map(ParsedData::getValue)
.sortAndSumEveryNthValue(2) // suffix form
.map(value -> value / 2)
...
Even JavaScript added a pipeline operator to solve this kind of nesting problem.
And then we have the issues caused by the implementation of the language. Everything except primitives are an object, and only objects can be passed into generic functions.
Lambda functions? Short-lived instances of anonymous classes that implement some interface.
Generics over a primitive type (e.g. HashMap<Integer, String>
)? Short-lived boxed primitives that automatically desugar to the primitive type.
If I wanted my functional code to be as fast as writing everything in an imperative style, I would have to trust that the JIT performs appropriate optimizations. Unfortunately, I don’t. There’s a lot that needs to be optimized:
I’m sure some of those are implemented, but as far as benchmarks have shown, Streams are still slower in Java 17. That’s not to say that Java’s functional programming APIs should be avoided at all costs—that’s premature optimization. But in hot loops or places where performance is critical, they are not the optimal choice.
Outside of Java but still within the JVM ecosystem, Kotlin actually has the capability to inline functions passed to higher-order functions at compile time.
/rant
It’s possible that Google doesn’t, although that would be weird since the ability to push apps is probably standardized and baked into the stock Android OS source code.
Or maybe you just used MVNOs that don’t purposefully install anything that isn’t strictly necessary.
Android OS developers or software devs working for cell providers would probably know the answer, though.
Anecdotally, I can confirm otherwise. I bought an unlocked Galaxy phone directly from Samsung, and putting in a SIM card provisioned it for my cell provider and installed their apps.
Thankfully, I’m not on a provider that pushes adware.
Oh cool, there’s a 200mp camera. Something that only pro photographers care about lol.
Oh this is a fun one! Trained, professional photographers generally don’t care either, since more megapixels aren’t guaranteed to make better photos.
Consider two sensors that take up the same physical space and capture light with the same efficiency/ability, but are 10 vs 40 megapixels. (Note: Realistically, a higher density would mean design trade-offs and more generous manufacturing tolerances.)
From a physics perspective, the higher megapixel sensor will collect the same amount of light spread over a more dense area. This means that the resolution of the captured light will be higher, but each single pixel will get less overall light.
So imagine we have 40 photons of light:
More Pixels Less Pixels
----------- -----------
1 2 1 5
2 6 2 3 11 11
1 9 0 1 15 3
4 1 1 1
When you zoom in to the individual pixels, the higher-resolution sensor will appear more noisy. This can be mitigated by pixel binning, which groups (or “bins”) those physical pixels into larger, virtual ones—essentially mimicking the lower-resolution sensor. Software can get crafty and try to use some more tricks to de-noise it without ruining the sharpness, though. Or if you could sit completely still for a few seconds, you could significantly lower the ISO and get a better average for each pixel.
Strictly from a physics perspective (and assuming the sensors are the same overall quality), higher megapixel sensors are better simply because you can capture more detail and end up with similar quality when you scale the picture down to whatever you’re comparing it against. More detail never hurts.
… Except when it does. Unless you save your photos as RAW (which take a massice amount of space), they’re going to be compressed into a lossy image format like JPEG. And the lovely thing about JPEG, is that it takes advantage of human vision to strip away visual information that we generally wouldn’t perceive, like slight color changes and high frequency details (like noise!)
And you can probably see where this is going: the way that the photo is encoded and stored destroys data that would have otherwise ensured you could eventually create a comparable (or better) photo. Luckily, though, the image is pre-processed by the camera software before encoding it as a JPEG, applying some of those quality-improving tricks before the data is lost. That leaves you at the mercy of the manufacturer’s software, however.
In summary: more megapixels is better in theory. In practice, bad software and image compression negate the advantages that a higher resolution provides, and higher-density sensors likely mean lower-quality data. Also, don’t expect more megapixels to mean better zoom. You would need an actual lense for that.
It’s a “feature,” in fact…
Under What to expect on this support page, it says:
The phone branding, network configuration, carrier features, and system apps will be different based on the SIM card you insert or the carrier linked to the eSIM.
The new carrier’s settings menus will be applied.
The previous carrier’s apps will be disabled.
The correct approach from a UX perspective would have been to display an out-of-box experience wizard that gives the user an option to either use the recommended defaults, or customize what gets installed.
Unfortunately, many manufacturers don’t do that, and just install the apps unconditionally and with system-level permissions. And even if they did, it’s likely that many of the carrier apps will either have a manifest value that requires them to be installed, be unlabeled (e.g. com.example.carrier.msm.mdm.MDM), or misleadingly named to appear essential (e.g. “Mobile Services Manager”).
I bought an unlocked phone directly from the manufacturer and still didn’t get the choice.
Inserting a SIM card wiped the phone and provisioned it, installing all sorts of carrier-provided apps with system-level permissions.
As far as I’ve found, there’s a few possible solutions:
Unlock the bootloader and install a custom ROM that doesn’t automatically install carrier-provided apps. (Warning: This will blow the E-fuse on Samsung devices, disabling biometrics and other features provided by their proprietary HSM).
Manually disable the apps after they’re forcibly installed for you. Install adb
on a computer and use pm disable-user --user 0 the.app.package
on every app you don’t want. If your OEM ROM is particularly scummy, it might go out of its way to periodically re-enable some of them, though.
Find a SIM card for a carrier that doesn’t install any apps, then insert that into a fresh phone and hope that the phone doesn’t adopt the new carrier’s apps (or wipe the phone) when you insert your actual SIM.
I went to one of their concerts, and their lead singer, David Draiman, was one of the most wholesome and honest guys I’ve ever seen. Funny headline, but I hope he recovers quickly and without any long-term effects.