10 interesting stories served every morning and every evening.
To combat malware and financial scams, Google announced today that only apps from developers that have undergone verification can be installed on certified Android devices starting in 2026.
This requirement applies to “certified Android devices” that have Play Protect and are preloaded with Google apps. The Play Store implemented similar requirements in 2023, but Google is now mandating this for all install methods, including third-party app stores and sideloading where you download an APK file from a third-party source.
Think of it like an ID check at the airport, which confirms a traveler’s identity but is separate from the security screening of their bags; we will be confirming who the developer is, not reviewing the content of their app or where it came from.
Google wants to combat “convincing fake apps” and make it harder for repeat “malicious actors to quickly distribute another harmful app after we take the first one down.” A recent analysis by the company found that there are “over 50 times more malware from internet-sideloaded sources than on apps available through Google Play.”
Google is explicit today about how “developers will have the same freedom to distribute their apps directly to users through sideloading or to use any app store they prefer.”
This new requirement sees Google create a new Android Developer Console for those that only distribute outside of Google Play. Students and hobbyists will get a separate workflow that differs from commercial developers.
Those that distribute via Google Play “likely already met these verification requirements through the existing Play Console process,” with a D-U-N-S number for organizations needed.
The first Android app developers will get access to verification this October, with the process opening to all in March 2026.
The requirement will go into effect in September 2026 for users in Brazil, Indonesia, Singapore, and Thailand. Google notes how these countries have been “specifically impacted by these forms of fraudulent app scams.” Verification will then apply globally from 2027 onwards.
At this point, any app installed on a certified Android device in these regions must be registered by a verified developer.
Google notes “supportive initial feedback” from government authorities and other parties:
* …with Indonesia’s Ministry of Communications and Digital Affairs praising it for providing a “balanced approach” that protects users while keeping Android open.
* …Thailand’s Ministry of Digital Economy and Society sees it as a “positive and proactive measure” that aligns with their national digital safety policies.
* In Brazil, the Brazilian Federation of Banks (FEBRABAN) sees it as a “significant advancement in protecting users and encouraging accountability.”
...
Read the original on 9to5google.com »
Today, we’re excited to introduce Gemini 2.5 Flash Image (aka nano-banana), our state-of-the-art image generation and editing model. This update enables you to blend multiple images into a single image, maintain character consistency for rich storytelling, make targeted transformations using natural language, and use Gemini’s world knowledge to generate and edit images. When we first launched native image generation in Gemini 2.0 Flash earlier this year, you told us you loved its low latency, cost-effectiveness, and ease of use. But you also gave us feedback that you needed higher-quality images and more powerful creative control.This model is available right now via the Gemini API and Google AI Studio for developers and Vertex AI for enterprise. Gemini 2.5 Flash Image is priced at $30.00 per 1 million output tokens with each image being 1290 output tokens ($0.039 per image). All other modalities on input and output follow Gemini 2.5 Flash pricing.
To make building with Gemini 2.5 Flash Image even easier, we have made significant updates to Google AI Studio’s “build mode” (with more updates to come). In the examples below, not only can you quickly test the model’s capabilities with custom AI powered apps, but you can remix them or bring ideas to life with just a single prompt. When you are ready to share an app you built, you can deploy right from Google AI Studio or save the code to GitHub. Try a prompt like “Build me an image editing app that lets a user upload an image and apply different filters” or choose one of the preset templates and remix it, all for free!A fundamental challenge in image generation is maintaining the appearance of a character or object across multiple prompts and edits. You can now place the same character into different environments, showcase a single product from multiple angles in new settings, or generate consistent brand assets, all while preserving the subject.We built a template app in Google AI Studio (that you can easily customize and vibe code on top of) to demonstrate the model’s character consistency capabilities.
Gemini 2.5 Flash Image enables targeted transformation and precise local edits with natural language. For example, the model can blur the background of an image, remove a stain in a t-shirt, remove an entire person from a photo, alter a subject’s pose, add color to a black and white photo, or whatever else you can conjure up with a simple prompt. To show these capabilities in action, we built a photo editing template app in AI Studio, with both UI and prompt-based controls.
Historically, image generation models have excelled at aesthetic images, but lacked a deep, semantic understanding of the real world. With Gemini 2.5 Flash Image, the model benefits from Gemini’s world knowledge, which unlocks new use cases. To demonstrate this, we built a template app in Google AI Studio that turns a simple canvas into an interactive education tutor. It showcases the model’s ability to read and understand hand-drawn diagrams, help with real world questions, and follow complex editing instructions in a single step.
Gemini 2.5 Flash Image can understand and merge multiple input images. You can put an object into a scene, restyle a room with a color scheme or texture, and fuse images with a single prompt. To showcase multi-image fusion, we built a template app in Google AI Studio which lets you drag products into a new scene to quickly create a new photorealistic fused image.
Check out our developer docs to start building with Gemini 2.5 Flash Image. The model is in preview today via the Gemini API and Google AI Studio but will be stable in the coming weeks. All of the demo apps we highlighted here were vibe coded in Google AI Studio so they can be remixed and customized with just a prompt. OpenRouter.ai has partnered with us to help bring Gemini 2.5 Flash Image to their 3M+ developers everywhere, today. This is the first model on OpenRouter — of the 480+ live today –that can generate images.We’re also excited to partner with fal.ai, a leading developer platform for generative media, to make Gemini 2.5 Flash Image available to the broader developer community.All images created or edited with Gemini 2.5 Flash Image will include an invisible SynthID digital watermark, so they can be identified as AI-generated or edited.
...
Read the original on developers.googleblog.com »
Generate, transform and edit images with simple text prompts, or combine multiple images to create something new. All in Gemini.
Reuse the same characters while changing their outfits, poses, the lighting, or the scene. Or reimagine yourself — across decades, in different places, or in your childhood dream job.
Prompt 1: Remove the door mirror. Prompt 2: Make the landscape snowy and mountainous. Prompt 3: Make her hair dyed cool blond at the top and magenta at the bottom. Prompt 4: She is wearing a yellow and dark blue flannel shirt
Prompt: A classic, faded photograph capturing a scene from a 1960s recording studio, featuring these two blue characters. They are depicted in the control room, surrounded by the warm glow of vacuum tubes and the complex array of a large-format mixing console. The larger of the two blue figures has a pair of bulky headphones placed slightly askew on its head and gazes peacefully through the soundproof glass at a musician in the live room. The smaller character, perched on a stool, wears a tiny pair of round, 1960s-style glasses and is turned slightly to adjust a knob on a reel-to-reel tape machine. The entire image has the aesthetic of an aged photograph, with a grainy texture, soft focus, and a desaturated, warm color palette.
Prompt: Change head piece to something made from red flowers
Prompt: Create 5 headshot polaroid prints, laid out on a clean table, all of which show me in various situations from the 1980′s
Prompt: Make woman underwater, and remove the couch and wallpaper
Prompt: A close-up shot of a romantic moment holding each other while it snows
Prompt 1: Show this man as a teacher. Prompt 2: Show this man as a sculptor. Prompt 3: Show this man as a nurse. Prompt 4: Show this man as a baker
Prompt: Recreate this dog as a 16-Bit Video Game character, and place the character in a level of a 2d 16-bit platform video game
Prompt 1: The t-rex is in a halloween costume. Prompt 2: Now try a more fun costume. Prompt 3: Fun. Now let’s try a cute costume. Prompt 4: How about a pirate costume?
Merge up to three images to create something new. Generate surrealist art, combine disparate photo elements, or seamlessly blend objects, colors, and textures.
Prompt: A hyper-detailed, high-fashion photograph capturing a woman floating within a massive, amorphous bubble of translucent, glass-like liquid on light blue background.
Prompt: Replace the astronaut on the right with the women and remove the helmet on the astronaut on the left to show the man’s face. The two are looking at each other.
Prompt: Combine these photos so that the synchronized swimmers are inside the lotus flower
Prompt: The man cuddles with his dog
Create and edit images with powerful control. Replace the background, restore faded images, and change characters’ outfits. Keep tweaking until you’re happy, all with natural language.
Prompt: Change the pose, ballerina is raising her arms
Prompt: Make this environment completely brand new and clean, no decay
Prompt 1: The house painted white. Prompt 2: Add flower beds with vibrant blooming flowers in front of the house. Prompt 3: Transformed into a fall setting. Prompt 4: Transform this image into a winter setting and decorate the houses
Prompt: Recreate this bird as red with hints of emerald green
Prompt: Change time of day to day with bright sun
Prompt: Fix the sign, make it say “GAS”
Experiment with creative directions, or bring them into different contexts. Apply specific patterns to visible surfaces, or test out colors for fashion, design, and interior decoration.
Prompt: Turn this into a stunning outfit of a woman walking through a luscious botanical garden
Prompt: Restyle this living room in a fresh dreamy style mixing woven materials and textures using the colour swatches
Prompt: Turn me into a cartoon like character on the front of a 1960′s cereal packet of ‘Adventure O’s’ along with other text you would find on a cereal box from the 1960′s. the packet sits in a breakfast table in a photo reminiscent of the 1970′s
Prompt: Show me what you can build with this blueprint
Prompt: A bedroom restyled in an over the top, maximalism style of ‘The Cassette-Futurist Room’: A 1980s vision of the future. Think clunky, beige plastic computers built into the walls, furniture with unnecessary vents and chunky buttons, and a colour palette of grey, orange, and brown. It’s the tech aesthetic seen in classic sci-fi films of that era.
Prompt: Fashion shot of a woman in a huge dress in origami paper red and white geometric pattern style
Prompt: Create another post stamp in the same series with a different mushroom
Prompt: Make this feathered texture into a stunning dress on a woman standing by a glacier lake
Prompt: Restyle this living room in nouveau antique art deco style using the colour swatches
Prompt: Woman walks in the dress with pattern from image 2 in the room with walls and floor from image 1
Generate multiple images using just one prompt to explore different creative avenues. Or create several images that work together to tell a complete story.
Prompt: Create a beautifully entertaining 8 part story with 8 images with two blue characters and their adventures in the 1960s music scene. The story is thrilling throughout with emotional highs and lows and ending on a great twist and high note. Do not include any words or text on the images but tell the story purely through the imagery itself.
Prompt: Create an addictively intriguing 12 part story with 12 images with these two characters in a classic black and white film noir detective story. Make it about missing treasure that they get clues for throughout and then finally discover. The story is thrilling throughout with emotional highs and lows and ending on a great twist and high note. Do not include any words or text on the images but tell the story purely through the imagery itself.
Prompt: Create a riveting epic 9 part story with 9 images with these two protagonists and their adventures as secret super heros. The story is thrilling throughout with emotional highs and lows and ending on a great twist and high note. Do not include any words or text on the images but tell the story purely through the imagery itself.
Upload images and share text instructions with Gemini to create complex and detailed images.
Use everyday language while creating images, and keep the conversation going to refine what the model generates.
Generate images that follow real-world logic, thanks to Gemini’s advanced reasoning capabilities.
Gemini 2.5 Flash Image is a state-of-the-art image generation and editing model, with lower latency compared to other leading models.
Gemini 2.5 Flash Image was tested on LMArena as nano-banana.
While Gemini can now create a wide range of images, we’re still working on improving key capabilities.
Not every image Gemini generates will be perfect – it can still struggle with small faces, accurate spelling, and fine details in images.
The model excels at character consistency, but it may not always get it right. We’re working to make this consistency even more reliable.
We use extensive filtering and data labeling to minimize harmful content in datasets and reduce the likelihood of harmful outputs. We also conduct red teaming and evaluations on content safety, including child safety, and representation. Image generation in Gemini has all our latest privacy and safety features. This includes SynthID, our tool that embeds an invisible digital watermark directly into an image, allowing it to be identified as AI generated.
...
Read the original on deepmind.google »
When designing software systems, do the simplest thing that could possibly work.
It’s surprising how far you can take this piece of advice. I genuinely think you can do this all the time. You can follow this approach for fixing bugs, for maintaining existing systems, and for architecting new ones.
A lot of engineers design by trying to think of the “ideal” system: something well-factored, near-infinitely scalable, elegantly distributed, and so on. I think this is entirely the wrong way to go about software design. Instead, spend that time understanding the current system deeply, then do the simplest thing that could possibly work.
System design requires competence with a lot of different tools: app servers, proxies, databases, caches, queues, and so on. As they gain familiarity with these tools, junior engineers naturally want to use them. It’s fun to construct systems out of many different components! And it feels very satisfying to draw boxes and arrows on a whiteboard - like you’re doing real engineering.
However, as with many skills, real mastery often involves learning when to do less, not more. The fight between an ambitious novice and an old master is a well-worn cliche in martial arts movies: the novice is a blur of motion, flipping and spinning. The master is mostly still. But somehow the novice’s attacks never seem to quite connect, and the master’s eventual attack is decisive.
In software, this means that great software design looks underwhelming. It doesn’t look like anything much is happening at all. You can tell you’re in the presence of great software design because you start having thoughts like “oh, I didn’t realise the problem was that easy” or “oh nice, you don’t actually have to do anything difficult”.
Unicorn is great software design, because it delivers all the most important guarantees in a web server (request isolation, horizontal scaling, crash recovery) by leaning on Unix primitives. The industry-standard Rails REST API is great software design, because it gives you exactly what you need for a CRUD app in the most boring way possible. I don’t think any of these are impressive software. But they’re impressive feats of design, because they do the simplest thing that could possibly work.
You should do that too! Suppose you’ve got a Golang application that you want to add some kind of rate limiting to. What’s the simplest thing that could possibly work? Your first idea might be to add some kind of persistent storage (say, Redis) to track per-user request counts with a leaky-bucket algorithm. That would work! But do you need a whole new piece of infrastructure? What if instead you kept those per-user request counts in-memory? Sure, you’d lose some rate limiting data when the application is restarted, but does that matter? Actually, are you sure your edge proxy doesn’t support rate limiting already? Could you just write a couple of lines in a config file instead of implementing the feature at all?
Maybe your edge proxy doesn’t support rate limiting. Maybe you can’t track it in-memory because you have too many server instances running in parallel, so the tightest rate limit you could enforce that way is too wide. Maybe it’s a dealbreaker if you ever lose rate limiting data, because people are hammering your service that hard. In that case, the simplest thing that could possibly work is adding persistent storage, so you should go and do that. But if you could do one of the easier approaches, wouldn’t you want to?
You really can build a whole application from scratch this way: start with the absolute simplest thing, and then only extend it when you have new requirements that force you to. It sounds silly, but it works. Think of it as taking YAGNI as the ultimate design principle: above single-responsibility, above choosing the best tool for the job, and above “good design”.
Of course, there are three big problems with always doing the simplest thing that could possibly work. The first is that, by not anticipating future requirements, you end up with an inflexible system or a big ball of mud. The second is that it’s not clear what “simplest” means, so at worst I’m saying “to design well, always do good design”. The third is that you ought to be building systems that can scale, not systems that just work right now. Let’s take those objections in order.
To some engineers, “do the simplest thing that could possibly work” sounds like I’m telling them to stop doing engineering. If the simplest thing is usually a quick kludge, does that mean this advice will inevitably lead to a complete mess? We’ve all seen codebases with hacks stacked on top of hacks, and they definitely don’t look like good design.
But are hacks simple? I actually don’t think so. The problem with a hack or a kludge is precisely that it isn’t simple: that it adds complexity to the codebase by introducing another thing you have to always remember. Hacks are just easier to think of. Figuring out the proper fix is hard because it requires having to understand the entire codebase (or large sections of it). In fact, the proper fix is almost always much simpler than the hack.
It is not easy to do the simplest thing that could possibly work. When you’re looking at a problem, the first few solutions that come to mind are unlikely to be the simplest ones. Figuring out the simplest solution requires considering many different approaches. In other words, it requires doing engineering.
Engineers disagree a lot about what constitutes simple code. If “simplest” already means “with good design”, is it just a tautology to say “you should do the simplest thing that could possibly work?” In other words, is Unicorn really simpler than Puma? Is adding in-memory rate limiting really simpler than using Redis? Here’s a rough, intuitive definition of simplicity:
Simple systems have fewer “moving pieces”: fewer things you have to think about when you’re working with them
Simple systems are less internally-connected. They are composed from components with clear, straightforward interfaces
Unix processes are simpler than threads (and thus Unicorn is simpler than Puma) because processes are less connected: they do not share memory. This makes a lot of sense to me! But I don’t think it gives you the tools to figure out what’s simpler in every case.
What about in-memory rate limiting vs Redis? On the one hand, in-memory is simpler because you don’t have to think about all the things involved in standing up a separate service with persistent memory. On the other hand, Redis is simpler because the rate limiting guarantees it offers are more straightforward - you don’t have to worry about the case where one server instance thinks a user is rate limited and another one doesn’t.
When I’m not sure what “seems” simpler to me, I like to use this tiebreaker: simple systems are stable. If you’re comparing two states of a software system, and one will require more ongoing work if no requirements change, the other one is simpler. Redis must be deployed and maintained, it can have its own incidents, it requires its own monitoring, it requires a separate deployment in any new environments the service finds itself in, and so on. Thus in-memory rate limiting is simpler than Redis.
A certain type of engineer is now screaming to themselves “but in-memory rate limiting won’t scale!” Doing the simplest thing that could possibly work will emphatically not deliver the most web-scale system. It will deliver a system that works well at the current scale. Is this irresponsible engineering?
No. In my view, the cardinal sin of big tech SaaS engineering is an obsession with scale. I’ve seen so much unavoidable pain caused by over-engineering systems to prepare for several orders of magnitude more than the current scale.
The main reason to not try this is that it doesn’t work. In my experience, for any non-trivial codebase, you can’t anticipate how it will behave at several orders of magnitude more traffic, because you don’t know ahead of time where all the bottlenecks are going to be. At most you can try to make sure you’re ready for 2x or 5x the current traffic, and then stand by to deal with problems as they come in.
The other reason not to try this is that it makes your codebase inflexible. It’s fun to decouple your service into two pieces so they can be scaled independently (I have seen this happen maybe ten times, and I have seen them actually be usefully scaled independently maybe once). But that makes certain features very hard to implement, because they now require coordination over the wire. In the worst case, they require transactions over the wire, which is a genuinely hard engineering problem. Most of the time you just don’t have to do any of this!
The longer I spend working in tech, the less optimistic I become about our collective ability to predict where a system is going. It’s hard enough to get your head around where a system currently is. And in fact, that’s the main practical difficulty in doing good design: getting an accurate big-picture understanding of the system. Most design is done without that understanding, and most design is thus pretty bad.
There are, broadly speaking, two ways to develop software. The first is to predict what your requirements might look like six months or a year from now, and then design the best system for that purpose. The second is to design the best system for what your requirements actually look like right now: in other words, to do the simplest thing that could possibly work.
edit: this article has gotten some comments on Hacker News.
One interesting comment thread says that simplicity of architecture doesn’t matter at scale, because the complexity of “state space exploration in implementation” (I think that means something like what I wrote about here) dominates any other complexity. I disagree - the more complex your feature interactions become, the more important a simple architecture becomes, because your “complexity budget” is almost exhausted.
I also want to credit Ward Cunningham and Kent Beck for inventing the expression - I genuinely thought I’d just come up with the wording myself, but I almost certainly just remembered it. Oops! Thanks to the HN user ternaryoperator for pointing this out.
...
Read the original on www.seangoedecke.com »
It is a living document, last update: August 2025. Your contributions are welcome!
There are so many buzzwords and best practices out there, but most of them have failed. We need something more fundamental, something that can’t be wrong.
Sometimes we feel confusion going through the code. Confusion costs time and money. Confusion is caused by high cognitive load. It’s not some fancy abstract concept, but rather a fundamental human constraint. It’s not imagined, it’s there and we can feel it.
Since we spend far more time reading and understanding code than writing it, we should constantly ask ourselves whether we are embedding excessive cognitive load into our code.
Cognitive load is how much a developer needs to think in order to complete a task.
When reading code, you put things like values of variables, control flow logic and call sequences into your head. The average person can hold roughly four such chunks in working memory. Once the cognitive load reaches this threshold, it becomes much harder to understand things.
Let’s say we have been asked to make some fixes to a completely unfamiliar project. We were told that a really smart developer had contributed to it. Lots of cool architectures, fancy libraries and trendy technologies were used. In other words, the author had created a high cognitive load for us.
We should reduce the cognitive load in our projects as much as possible.
Intrinsic - caused by the inherent difficulty of a task. It can’t be reduced, it’s at the very heart of software development.
Extraneous - created by the way the information is presented. Caused by factors not directly relevant to the task, such as smart author’s quirks. Can be greatly reduced. We will focus on this type of cognitive load.
Let’s jump straight to the concrete practical examples of extraneous cognitive load.
We will refer to the level cognitive load as follows:
🧠: fresh working memory, zero cognitive load
🧠++: two facts in our working memory, cognitive load increased
🤯: cognitive overload, more than 4 facts
Our brain is much more complex and unexplored, but we can go with this simplistic model.
if val > someConstant // 🧠+
&& (condition2 || condition3) // 🧠+++, prev cond should be true, one of c2 or c3 has be true
&& (condition4 && !condition5) { // 🤯, we are messed up by this point
isValid = val > someConstant
isAllowed = condition2 || condition3
isSecure = condition4 && !condition5
// 🧠, we don’t need to remember the conditions, there are descriptive variables
if isValid && isAllowed && isSecure {
if isValid { // 🧠+, okay nested code applies to valid input only
if isSecure { // 🧠++, we do stuff for valid and secure input only
stuff // 🧠+++
Compare it with the early returns:
if !isValid
return
if !isSecure
return
// 🧠, we don’t really care about earlier returns, if we are here then all good
stuff // 🧠+
We can focus on the happy path only, thus freeing our working memory from all sorts of preconditions.
We are asked to change a few things for our admin users: 🧠
Ohh, part of the functionality is in BaseController, let’s have a look: 🧠+
Basic role mechanics got introduced in GuestController: 🧠++
Things got partially altered in UserController: 🧠+++
Finally we are here, AdminController, let’s code stuff! 🧠++++
Oh, wait, there’s SuperuserController which extends AdminController. By modifying AdminController we can break things in the inherited class, so let’s dive in SuperuserController first: 🤯
Prefer composition over inheritance. We won’t go into detail - there’s plenty of material out there.
Method, class and module are interchangeable in this context
Mantras like “methods should be shorter than 15 lines of code” or “classes should be small” turned out to be somewhat wrong.
Deep module - simple interface, complex functionality
Shallow module - interface is relatively complex to the small functionality it provides
Having too many shallow modules can make it difficult to understand the project. Not only do we have to keep in mind each module responsibilities, but also all their interactions. To understand the purpose of a shallow module, we first need to look at the functionality of all the related modules. Jumping between such shallow components is mentally exhausting, linear thinking is more natural to us humans.
Information hiding is paramount, and we don’t hide as much complexity in shallow modules.
I have two pet projects, both of them are somewhat 5K lines of code. The first one has 80 shallow classes, whereas the second one has only 7 deep classes. I haven’t been maintaining any of these projects for one year and a half.
Once I came back, I realised that it was extremely difficult to untangle all the interactions between those 80 classes in the first project. I would have to rebuild an enormous amount of cognitive load before I could start coding. On the other hand, I was able to grasp the second project quickly, because it had only a few deep classes with a simple interface.
The best components are those that provide powerful functionality yet have a simple interface.
John K. Ousterhout
The interface of the UNIX I/O is very simple. It has only five basic calls:
open(path, flags, permissions)
read(fd, buffer, count)
write(fd, buffer, count)
lseek(fd, offset, referencePosition)
close(fd)
A modern implementation of this interface has hundreds of thousands of lines of code. Lots of complexity is hidden under the hood. Yet it is easy to use due to its simple interface.
P. S. If you think we are rooting for bloated God objects with too many responsibilities, you got it wrong.
All too often, we end up creating lots of shallow modules, following some vague “a module should be responsible for one, and only one, thing” principle. What is this blurry one thing? Instantiating an object is one thing, right? So MetricsProviderFactoryFactory seems to be just fine. The names and interfaces of such classes tend to be more mentally taxing than their entire implementations, what kind of abstraction is that? Something went wrong.
We make changes to our systems to satisfy our users and stakeholders. We are responsible to them.
A module should be responsible to one, and only one, user or stakeholder.
This is what this Single Responsibility Principle is all about. Simply put, if we introduce a bug in one place, and then two different business people come to complain, we’ve violated the principle. It has nothing to do with the number of things we do in our module.
But even now, this rule can do more harm than good. This principle can be understood in as many different ways as there are individuals. A better approach would be to look at how much cognitive load it all creates. It’s mentally demanding to remember that change in one place can trigger a chain of reactions across different business streams. And that’s about it, no fancy terms to learn.
This shallow-deep module principle is scale-agnostic, and we can apply it to microservices architecture. Too many shallow microservices won’t do any good - the industry is heading towards somewhat “macroservices”, i.e., services that are not so shallow (=deep). One of the worst and hardest to fix phenomena is so-called distributed monolith, which is often the result of this overly granular shallow separation.
I once consulted a startup where a team of five developers introduced 17(!) microservices. They were 10 months behind schedule and appeared nowhere close to the public release. Every new requirement led to changes in 4+ microservices. It took an enormous amount of time to reproduce and debug an issue in such a distributed system. Both time to market and cognitive load were unacceptably high. 🤯
Is this the right way to approach the uncertainty of a new system? It’s enormously difficult to elicit the right logical boundaries in the beginning. The key is to make decisions as late as you can responsibly wait, because that is when you have the most information at hand. By introducing a network layer up front, we make our design decisions hard to revert right from the start. The team’s only justification was: “The FAANG companies proved microservices architecture to be effective”. Hello, you got to stop dreaming big.
The Tanenbaum-Torvalds debate argued that Linux’s monolithic design was flawed and obsolete, and that a microkernel architecture should be used instead. Indeed, the microkernel design seemed to be superior “from a theoretical and aesthetical” point of view. On the practical side of things - three decades on, microkernel-based GNU Hurd is still in development, and monolithic Linux is everywhere. This page is powered by Linux, your smart teapot is powered by Linux. By monolithic Linux.
A well-crafted monolith with truly isolated modules is often much more flexible than a bunch of microservices. It also requires far less cognitive effort to maintain. It’s only when the need for separate deployments becomes crucial, such as scaling the development team, that you should consider adding a network layer between the modules, future microservices.
We feel excited when new features got released in our favourite language. We spend some time learning these features, we build code upon them.
If there are lots of features, we may spend half an hour playing with a few lines of code, to use one or another feature. And it’s kind of a waste of time. But what’s worse, when you come back later, you would have to recreate that thought process!
You not only have to understand this complicated program, you have to understand why a programmer decided this was the way to approach a problem from the features that are available. 🤯
These statements are made by none other than Rob Pike.
Reduce cognitive load by limiting the number of choices.
Language features are OK, as long as they are orthogonal to each other.
On the backend we return:
401 for expired jwt token
403 for not enough access
418 for banned users
The engineers on the frontend use backend API to implement login functionality. They would have to temporarily create the following cognitive load in their brains:
401 is for expired jwt token // 🧠+, ok just temporary remember it
403 is for not enough access // 🧠++
418 is for banned users // 🧠+++
Frontend developers would (hopefully) introduce some kind numeric status -> meaning dictionary on their side, so that subsequent generations of contributors wouldn’t have to recreate this mapping in their brains.
Then QA engineers come into play: “Hey, I got 403 status, is that expired token or not enough access?”
QA engineers can’t jump straight to testing, because first they have to recreate the cognitive load that the engineers on the backend once created.
Why hold this custom mapping in our working memory? It’s better to abstract away your business details from the HTTP transfer protocol, and return self-descriptive codes directly in the response body:
“code”: “jwt_has_expired”
Cognitive load on the frontend side: 🧠 (fresh, no facts are held in mind)
Cognitive load on the QA side: 🧠
The same rule applies to all sorts of numeric statuses (in the database or wherever) - prefer self-describing strings. We are not in the era of 640K computers to optimise for memory.
People spend time arguing between 401 and 403, making decisions based on their own mental models. New developers are coming in, and they need to recreate that thought process. You may have documented the “whys” (ADRs) for your code, helping newcomers to understand the decisions made. But in the end it just doesn’t make any sense. We can separate errors into either user-related or server-related, but apart from that, things are kind of blurry.
P. S. It’s often mentally taxing to distinguish between “authentication” and “authorization”. We can use simpler terms like “login” and “permissions” to reduce the cognitive load.
Do not repeat yourself - that is one of the first principles you are taught as a software engineer. It is so deeply embedded in ourselves that we can not stand the fact of a few extra lines of code. Although in general a good and fundamental rule, when overused it leads to the cognitive load we can not handle.
Nowadays, everyone builds software based on logically separated components. Often those are distributed among multiple codebases representing separate services. When you strive to eliminate any repetition, you might end up creating tight coupling between unrelated components. As a result changes in one part may have unintended consequences in other seemingly unrelated areas. It can also hinder the ability to replace or modify individual components without impacting the entire system. 🤯
In fact, the same problem arises even within a single module. You might extract common functionality too early, based on perceived similarities that might not actually exist in the long run. This can result in unnecessary abstractions that are difficult to modify or extend.
A little copying is better than a little dependency.
We are tempted to not reinvent the wheel so strong that we are ready to import large, heavy libraries to use a small function that we could easily write by ourselves.
All your dependencies are your code. Going through 10+ levels of stack trace of some imported library and figuring out what went wrong (because things go wrong) is painful.
...
Read the original on github.com »
In 2020, Apple released the M1 with a custom GPU. We got to work reverse-engineering the hardware and porting Linux. Today, you can run Linux on a range of M1 and M2 Macs, with almost all hardware working: wireless, audio, and full graphics acceleration.
Our story begins in December 2020, when Hector Martin kicked off Asahi Linux. I was working for Collabora working on Panfrost, the open source Mesa3D driver for Arm Mali GPUs. Hector put out a public call for guidance from upstream open source maintainers, and I bit. I just intended to give some quick pointers. Instead, I bought myself a Christmas present and got to work. In between my university coursework and Collabora work, I poked at the shader
instruction set.
One thing led to another. Within a few weeks, I drew a
triangle.
In 3D graphics, once you can draw a triangle, you can do anything.
Pretty soon, I started work on a shader
compiler. After my final exams that semester, I took a few days off from Collabora to bring up an OpenGL
driver capable of spinning gears with my new compiler.
Over the next year, I kept reverse-engineering
and improving the driver until it could run 3D
games on macOS.
Meanwhile, Asahi Lina wrote a kernel driver for the Apple GPU. My userspace OpenGL driver ran on macOS, leaving her kernel driver as the missing piece for an open source graphics stack. In December 2022, we shipped graphics
acceleration in Asahi Linux.
In January 2023, I started my final semester in my Computer Science program at the University of
Toronto. For years I juggled my courses with my part-time job and my hobby driver. I faced the same question as my peers: what will I do after graduation?
Maybe Panfrost? I started reverse-engineering of the Mali Midgard GPU back in 2017, when I was still in high school. That led to an internship at Collabora in 2019 once I graduated, turning into my job throughout four years of university. During that time, Panfrost grew from a kid’s pet project based on blackbox reverse-engineering, to a professional driver engineered by a team with Arm’s backing and hardware documentation. I did what I set out to do, and the project succeeded beyond my dreams. It was
time to move on.
What did I want to do next?
* Finish what I started with the M1. Ship a great driver.
* Bring full, conformant OpenGL drivers to the M1. Apple’s drivers are
not conformant, but we should strive for the industry standard.
* Bring full, conformant Vulkan to Apple platforms, disproving the
myth that Vulkan isn’t suitable for Apple hardware.
* Bring Proton gaming to Asahi Linux. Thanks to Valve’s work for the
Steam Deck, Windows games can run better on Linux than even on Windows.
Why not reap those benefits on the M1?
Panfrost was my challenge until we “won”. My next challenge? Gaming on Linux on M1.
Once I finished my coursework, I started full-time on gaming on Linux. Within a month, we shipped OpenGL 3.1
on Asahi Linux. A few weeks later, we passed official
conformance for OpenGL ES 3.1. That put us at feature parity with Panfrost. I wanted to go further.
OpenGL (ES) 3.2 requires geometry shaders, a legacy feature not supported by either Arm or Apple hardware. The proprietary OpenGL drivers emulate geometry shaders with compute, but there was no open source prior art to borrow. Even though multiple Mesa drivers need geometry/tessellation emulation, nobody did the work to get there.
My early progress on OpenGL was fast thanks to the mature common code in Mesa. It was time to pay it forward. Over the rest of the year, I implemented geometry/tessellation shader emulation. And also the rest of the owl. In January 2024, I passed conformance for the full OpenGL
4.6 specification, finishing up OpenGL.
Vulkan wasn’t too bad, either. I polished the OpenGL driver for a few months, but once I started typing a Vulkan driver, I passed 1.3
conformance in a few weeks.
What remained was wiring up the geometry/tessellation emulation to my shiny new Vulkan driver, since those are required for Direct3D. Et voilà, Proton
games.
Along the way, Karol
Herbst passed OpenCL 3.0 conformance on the M1, running my compiler atop his “rusticl” frontend.
Meanwhile, when the Vulkan 1.4 specification was published, we were ready and shipped
a conformant implementation on the same day.
After that, I implemented sparse texture support, unlocking Direct3D 12 via Proton.
We’ve succeeded beyond my dreams. The challenges I chased, I have tackled. The drivers are fully upstream in Mesa. Performance isn’t too bad. With the Vulkan on Apple myth busted, conformant Vulkan is now coming to macOS via LunarG’s
KosmicKrisp project building on my work.
Satisfied, I am now stepping away from the Apple ecosystem. My friends in the Asahi Linux orbit will carry the torch from here. As for me?
...
Read the original on rosenzweig.io »
OKLCH is a newer color model that is designed to be perceptually uniform. This means that colors are much more accurate in terms of how humans perceive them and it makes working with them much easier.
Before being able to understand how OKLCH differs from the other color models, it is important to understand some of the basic color concepts.
Color models are systems to describe colors. These include RGB, HSL, LCH, OKLCH and more. The model determines how easy it is to manipulate or think about a color.
Gamut is a playing field where the model lives and defines what colors are possible. Common gamuts include sRGB (the web default) and Display-P3 (used on modern devices).
There is a lot more nuance when you get into color spaces. They don’t just define a gamut, but also things like the white point and transfer function. I decided to leave those out for the sake of keeping the article simple.
OKLCH, same as LCH, consists of three values: Lightness, Chroma and Hue. The difference between the two is the underlying color space that the color model uses, which in case of OKLCH, is OKLab.
Lightness - Equal steps feel like equal changes in brightness. Ranges from value between 0 and 1 or percentage ranging from 0% to 100%.
Chroma - Controls intensity of the color, similar to saturation.
Hue - Controls the hue, measured in degrees ranging from 0 to 360.
Let’s say you want to create a couple of pill buttons and you want each one to have a different color. The usual workflow with sRGB colors would be defining the first color and then handpicking others to match it.
With OKLCH, you can use the same value for all of them and only change hue. That way you create colors that look and feel the same.
You can do the same thing with color models like HSL, but as you can see above, the colors don’t look uniform. Some are lighter, some darker, some pop more and some less.
This is one of the major advantages of OKLCH over other color models. Creating perceptually uniform color palettes and working with them is very easy.
It also works the other way around, where you can change the lightness value to create various color shades and there is no hue or saturation drift unlike in other color modes.
In the example above, you can see that the OKLCH colors maintain consistent blueness across all of the shades, while in the HSL example, the lighter shades drift to purple and the darker ones muddy out towards grayish.
The way gradients work in OKLCH is pretty different compared to sRGB. In sRGB, gradients are calculated in red, green, and blue values, which often leads to muddy midpoints and uneven brightness.
In OKLCH, the math follows lightness, chroma, and hue. In the example above you can see that the starting and ending points are the same but the colors the gradient passes through are quite different.
This can be a double edged sword. While some gradients might look smoother, you might also see colors that you’ve never defined. This is because hue in OKLCH is circular and gradients can take unexpected detours.
To avoid this, many tools use OKLAB for gradients, which interpolates in a straight line and gives more consistent results.
sRGB can’t reach a lot of colors that modern screens can show. In OKLCH you can write colors that are only possible to render on a screen that supports Display-P3 colors.
If you are on a display that supports Display-P3, you will see the right colors more vivid than the left ones. If you are on a display that only supports sRGB, the colors should look nearly identical, as the browser maps the out of gamut color back inside the sRGB gamut.
Keep in mind that grays are identical in sRGB and Display-P3, so there would be no difference there.
OKLCH can also define more colors than any real screen can show. It can specify values that don’t fit inside any actual gamut like sRGB or Display-P3.
Let’s take this color as an example color: oklch(0.7 0.4 40). It has a very high chroma value and it could mathematically exist but in practice it lies outside of any real display’s gamut. When this color is used, it will get clipped or mapped to the nearest representable color inside the gamut.
@layer base {
:root {
color: oklch(0.7 0.4 40);
Generally you don’t want this to happen, as the clipped color can often look very different from the defined one.
Therefore, there is a concept of a maximum chroma value, which calculates the maximum chroma that a display can show based on the lightness, hue and the selected gamut like sRGB or Display-P3.
OKLCH colors were introduced in CSS Color Module Level 4 and they are well supported across all modern browsers.
However, there are still some surfaces where OKLCH colors are not supported such as outdated browsers. In case you are worried about this, you can add fallbacks and use the @supports directive in CSS.
@layer base {
:root {
/* sRGB hex */
–color-gray-100: #fcfcfc;
–color-gray-200: #fafafa;
–color-gray-300: #f4f4f4;
@supports (color: oklch(0 0 0)) {
/* OKLCH */
–color-gray-100: oklch(0.991 0 0);
–color-gray-200: oklch(0.982 0 0);
–color-gray-300: oklch(0.955 0 0);
This way the browser uses OKLCH colors if the syntax is supported, otherwise it falls back to sRGB.
Keep in mind that this doesn’t magically change how the colors look. If an OKLCH color fits inside the sRGB gamut, it will look the same as the equivalent hex color. The difference is that OKLCH can also define colors outside of sRGB, like the Display-P3 gamut, which hex values can’t reach.
I built a small tool dedicated to OKLCH colors called oklch.fyi. It helps generate OKLCH colors palettes, it can take your existing CSS variables and convert them to OKLCH and more.
Try it out!
In case you have any questions reach me at jakub@kbo.sk or see more of my work on Twitter.
...
Read the original on jakub.kr »
We’ve spent recent months connecting Claude to your calendar, documents, and many other pieces of software. The next logical step is letting Claude work directly in your browser.
We view browser-using AI as inevitable: so much work happens in browsers that giving Claude the ability to see what you’re looking at, click buttons, and fill forms will make it substantially more useful.
But browser-using AI brings safety and security challenges that need stronger safeguards. Getting real-world feedback from trusted partners on uses, shortcomings, and safety issues lets us build robust classifiers and teach future models to avoid undesirable behaviors. This ensures that as capabilities advance, browser safety keeps pace.
Browser-using agents powered by frontier models are already emerging, making this work especially urgent. By solving safety challenges, we can better protect Claude users and share what we learn with anyone building a browser-using agent on our API.
We’re starting with controlled testing: a Claude extension for Chrome where trusted users can instruct Claude to take actions on their behalf within the browser. We’re piloting with 1,000 Max plan users—join the waitlist—to learn as much as we can. We’ll gradually expand access as we develop stronger safety measures and build confidence through this limited preview.
Within Anthropic, we’ve seen appreciable improvements using early versions of Claude for Chrome to manage calendars, schedule meetings, draft email responses, handle routine expense reports, and test new website features.
However, some vulnerabilities remain to be fixed before we can make Claude for Chrome generally available. Just as people encounter phishing attempts in their inboxes, browser-using AIs face prompt injection attacks—where malicious actors hide instructions in websites, emails, or documents to trick AIs into harmful actions without users’ knowledge (like hidden text saying “disregard previous instructions and do [malicious action] instead”).
Prompt injection attacks can cause AIs to delete files, steal data, or make financial transactions. This isn’t speculation: we’ve run “red-teaming” experiments to test Claude for Chrome and, without mitigations, we’ve found some concerning results.
We conducted extensive adversarial prompt injection testing, evaluating 123 test cases representing 29 different attack scenarios. Browser use without our safety mitigations showed a 23.6% attack success rate when deliberately targeted by malicious actors.
One example of a successful attack—before our new defenses were applied—was a malicious email claiming that, for security reasons, emails needed to be deleted. When processing the inbox, Claude followed these instructions to delete the user’s emails without confirmation.
As we’ll explain in the next section, we’ve already implemented several defenses that significantly reduce the attack success rate—though there’s still work to do in uncovering novel attack vectors.
The first line of defense against prompt injection attacks is permissions. Users maintain control over what Claude for Chrome can access and do:
* Site-level permissions: Users can grant or revoke Claude’s access to specific websites at any time in the Settings.
* Action confirmations: Claude asks users before taking high-risk actions like publishing, purchasing, or sharing personal data. Even when users opt into our experimental “autonomous mode,” Claude still maintains certain safeguards for highly sensitive actions (Note: all red-teaming and safety evaluations were conducted in autonomous mode).
We’ve also built additional safeguards in line with Anthropic’s trustworthy agents principles. First, we’ve improved our system prompts—the general instructions Claude receives before specific instructions from users—to direct Claude on how to handle sensitive data and respond to requests to take sensitive actions.
Additionally, we’ve blocked Claude from using websites from certain high-risk categories such as financial services, adult content, and pirated content. And we’ve begun to build and test advanced classifiers to detect suspicious instruction patterns and unusual data access requests—even when they arise in seemingly legitimate contexts.
When we added safety mitigations to autonomous mode, we reduced the attack success rate of 23.6% to 11.2%, which represents a meaningful improvement over our existing Computer Use capability (where Claude could see the user’s screen but without the browser interface that we’re introducing today).
We also conducted special red-teaming and mitigations focused on new attacks specific to the browser, such as hidden malicious form fields in a webpage’s Document Object Model (DOM) invisible to humans, and other hard-to-catch injections such as through the URL text and tab title that only an agent might see. On a “challenge” set of four browser-specific attack types, our new mitigations were able to reduce attack success rate from 35.7% to 0%.
Before we make Claude for Chrome more widely available, we want to expand the universe of attacks we’re thinking about and learn how to get these percentages much closer to zero, by understanding more about the current threats as well as those that might appear in the future.
Internal testing can’t replicate the full complexity of how people browse in the real world: the specific requests they make, the websites they visit, and how malicious content appears in practice. New forms of prompt injection attacks are also constantly being developed by malicious actors. This research preview allows us to partner with trusted users in authentic conditions, revealing which of our current protections work, and which need work.
We’ll use insights from the pilot to refine our prompt injection classifiers and our underlying models. By uncovering real-world examples of unsafe behavior and new attack patterns that aren’t present in controlled tests, we’ll teach our models to recognize the attacks and account for the related behaviors, and ensure that safety classifiers will pick up anything that the model itself misses. We’ll also develop more sophisticated permission controls based on what we learn about how users want to work with Claude in their browsers.
For the pilot, we’re looking for trusted testers who are comfortable with Claude taking actions in Chrome on their behalf, and who don’t have setups that are safety-critical or otherwise sensitive.
If you’d like to take part, you can join the Claude for Chrome research preview waitlist at claude.ai/chrome. Once you have access, you can install the extension from the Chrome Web Store and authenticate with your Claude credentials.
We recommend starting with trusted sites—always be mindful of the data that’s visible to Claude—and avoiding use of Claude for Chrome for sites that involve financial, legal, medical, or other types of sensitive information. You can find a detailed safety guide in our Help Center.
We hope that you’ll share your feedback to help us continue to improve both the capabilities and safeguards for Claude for Chrome—and help us take an important step towards a fundamentally new way to integrate AI into our lives.
...
Read the original on www.anthropic.com »
In Germany, we have the Clearingstelle Urheberrecht im Internet (CUII) - literally ‘Copyright Clearinghouse for the Internet’, a private organization that decides what websites to block, corporate interests rewriting our free internet. No judges, no transparency, just a bunch of ISPs and major copyright holders deciding what your eyes can see.
I decided to create a website, cuiiliste.de, to find blocked domains, as the CUII refuses to publish such a list. To read more about the CUII, check out one of my previous blog posts. Germany’s four biggest ISPs (Telekom, Vodafone, 1&1 and Telefonica (o2)) are all part of the CUII.
This week, Netzpolitik.org published an article about the CUII’s latest blunder, based on information I gathered. They managed to block domains that no longer even existed: websites that had already been seized and taken offline when they were blocked. It’s not the first time the CUII has tripped over its own feet, and this mistake likely didn’t sit well with them. In the past, it was really easy to find out if a domain was blocked by the CUII. If you asked an ISP’s DNS server (basically the internet’s phone book) for a site and got a CNAME to notice.cuii.info, you knew it was blocked.
What this basically means in case you’re not a tech nerd:
You can check the phone book of an ISP (the “DNS server”) where to find a website, and you’d receive a note saying “This site is blocked by the CUII” if the page is blocked. Automating this was simple, I could basically just ask “Hey, where can I find this site?” and immediately knew if it was blocked. The CUII apparently did not like the fact that it was so easy for me to check if a domain was blocked. They want to keep their list secret.
ISPs like Telekom, 1&1 and Vodafone actually all stopped using this response a few months ago, after older articles about the CUII’s past failures were published. Instead, they started pretending that blocked sites didn’t exist at all. Straight up erasing entries from the phone book. You could not tell if a site was blocked or just didn’t exist. Telefonica (the parent company of for example o2, Germany’s fourth-biggest ISP), apparently didn’t get this memo, and they still used notice.cuii.info in their DNS responses.
On cuiiliste.de, anyone can enter a domain, and see if it is blocked by the CUII, and which ISPs block it specifically.
Telefonica modified their DNS servers, specifically saying that blau-sicherheit.info was blocked by the CUII. At 11:06 AM last Friday, someone from Telefonica’s network checked if blau-sicherheit.info was blocked on my site. The twist? Telefonica seems to own this domain. Blau is one of their brands, and blau-sicherheit.info wasn’t some piracy hub - it appears to be a test domain of theirs. My tool flagged it as blocked because Telefonica’s DNS servers said so. Why would they block their own domain?
* Someone from Telefonica visits my website to check if I detect this
* I do in fact detect this
Two hours after this suspicious query, I was bombarded with Notifications. My program thought that the CUII had suddenly unblocked hundreds of domains.
The reason: Telefonica had altered their DNS servers to stop redirecting blocked domains to notice.cuii.info. Now they pretend that the domain doesn’t exist at all, after they specifically blocked their own domain, likely to find out how my website works.
I had to spend my entire Friday afternoon fixing this mess, and now everything is fully operational again.
The fix worked, but there’s a catch: without the notice.cuii.info redirect, it’s harder to confirm if a block is actually the CUII’s doing. Sometimes ISPs block sites for other reasons, like terrorism content (I wrote about that too). I try to compensate this by cross-checking domains against a list of known non-CUII-blocks.
The timing is more than suspicious. Right after Netzpolitik’s article exposed the CUII for blocking non-existent domains, they make it harder to track their mistakes. Coincidence? Or a move to bury future slip-ups? We can only speculate. Regardless of intent, the result is the same: less transparency and harder oversight. And that benefits the CUII, not the public.
In this context, Netzpolitik.org released another article (German):
Netzpolitik.org: Provider verstecken, welche Domains sie sperren
...
Read the original on lina.sh »
Create and modify tables with ease using Base’s visual table editor. No need to write complex CREATE or ALTER statements.
Add and organize columns and define constraints through a clean interface. The table editor makes database design accessible to everyone.
...
Read the original on menial.co.uk »
To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".
10HN is also available as an iOS App
If you visit 10HN only rarely, check out the the best articles from the past week.
If you like 10HN please leave feedback and share
Visit pancik.com for more.