A study of privacy-related data collected by Android apps
submitted by /u/throwaway16830261 [link] [留言]
找到 2540 篇相关文章
submitted by /u/throwaway16830261 [link] [留言]
Most developers building frontend applications spend a lot of time writing code that communicates with their backend due to the traditional approach (using APIs). This is not because the logic is hard to implement, but because the communication itself is complex. When using standard APIs, we build routes, define request and response models, generate clients, and keep multiple layers on track with application updates. Instead of exposing backend functionality through REST endpoints and consuming it through HTTP clients, Graftcode exposes backend methods directly and generates packages that applications can install and use as dependencies. The result is a communication model that is like you are calling a library rather than consuming an API with strongly typed clients. Working with Graftcode is very simple: install your library and call its functions. In this article, we'll be building a simple task tracker or to-do list application using React and a TypeScript backend to see what working with Graftcode looks like. In this blog post, we will learn the following: Why API layers require you to maintain APIs manually How Graftcode exposes backend functionality through Graftcode Gateway How Graftcode Vision helps discover backend capabilities Familiarity with APIs and fetch() requests How React applications can use TypeScript backend logic without building API routes Why strongly-typed backend packages can improve developer experience Prerequisites Let’s get our hands a bit dirty, but before we do, there are some need-to-haves to get you started. Let’s have a look at that in this section: Latest Node version installed on your machine Basic knowledge of React and TypeScript Familiarity with how APIs and fetch requests work (for understanding how easy Graftcode’s approach is) A Graftcode account Graftcode gateway installed on your local machine With these prerequisites, you’ll first understand why most to-do list applications rely heavily on APIs for their logic and what c
submitted by /u/Webfuse [link] [留言]
Building in public You explain your deploy setup to your assistant. It helps. Tomorrow you explain the same setup again. And the day after. You are not training it. You are re-typing. The tool nobody asked for I did not set out to build a product. I set out to stop repeating myself. My setup is four servers with names that mean nothing to anyone else, a tunnel with a numbering scheme I keep getting wrong, and a dozen small traps that only exist because of decisions I made two years ago. Every new session started from zero. So I gave the assistant a place to write things down, and a way to read them back before it started working. Two calls: one to save what was learned, one to recall it. That was the whole idea. For six weeks it had exactly one user. Nobody else could have used it, because I had not written a single line of documentation. Six weeks of being my own only customer That stretch turned out to be the most valuable part, and not because of what got built. Because of what got measured. When you are the only user, every rough edge lands on you within a day. A recall that returns the wrong thing costs you the next hour. A save that silently drops a field costs you the next week, when you go looking for it. I kept a count of the times the memory actually prevented a mistake. Not a feeling, a count. After six weeks it was high enough that I stopped arguing with myself about whether the thing was worth the effort. The uncomfortable part: several of those saved lessons were about mistakes I had already made twice. The tool did not make me smarter. It made me stop paying for the same lesson. The moment it stopped being a personal tool The thought that changed it was not a market analysis. It was smaller and more honest: if I find this useful, and my setup is not special, then somebody else is retyping their own servers right now. That is a weak argument on its own. Plenty of internal tools are useful precisely because they fit one person. So I looked for the part
submitted by /u/norman-complete [link] [留言]
submitted by /u/existential_ducks [link] [留言]
📺 Prefer to watch? 90-second YouTube Short · 💬 Telegram Originally published on software-engineer-blog.com . You fixed the CSS. You deployed. You opened the site and checked it yourself — perfect. Then a customer sends a screenshot of last week's layout. Nothing is broken. No deploy failed, no CDN is lying to you, no file is corrupt. The browser is doing exactly what you told it to do, several days ago, in a header you probably never wrote by hand. This is the part of web performance that gets skipped, because caching looks like a setting rather than a contract. It is a contract. And like any contract, the interesting part is not what it gives you — it is what you can no longer do once you have signed it. Throughout this post I will use one running example: PlantPal , a small plant shop. One stylesheet ( app.css ), one logo ( logo.png ), one API endpoint ( /api/products ). The floor: a page load is not one thing Before caching means anything, you have to see what it is acting on. Loading PlantPal's homepage is not a request. It is roughly 40 separate requests — the HTML, the stylesheet, a few fonts, the logo, a dozen product images, the JavaScript bundle, the product API. Each one is a full round trip: DNS is probably warm, but you still pay connection setup, the request, the server's think time, and the bytes coming back. The numbers for a first visit: ~40 requests 1.2 MB transferred 2.1 s to a usable page Which gives us the only sentence in this post that you actually need to remember: The fastest request is the one the browser never sends. Not a faster server. Not a closer edge node. Not a smaller file. No request at all. Everything below is a way of getting closer to that. max-age: buying silence The blunt instrument is Cache-Control : HTTP / 1.1 200 OK Content-Type : text/css Cache-Control : max-age=31536000 31536000 is one year in seconds. You are telling every browser that receives this response: keep this copy and use it for a year without asking me again. O
Short version, so you do not have to click: flex: 1 expands to flex: 1 1 0%. That 0% is a percentage basis and resolves against the parent's height. A panel that is height: auto under a max-height cap has no definite height, so the percentage has nothing to resolve against and the child contributes zero. flex: 1 1 auto fixes it, because the basis becomes the content's own height. The reason it took me an evening: Chromium quietly does what you meant, and the engine that broke it was WKWebView. Every test was green because Playwright ships its own WebKit build rather than the system one. I have not worked out whether the spec requires that collapse or merely permits it, so I cannot say which engine is wrong. If you know which reading applies to a max-height-capped auto-height parent, I would like to hear it. submitted by /u/HolidayChard9706 [link] [留言]
submitted by /u/mttd [link] [留言]
Imagine you have a complex microservice. For local development, you need it connected to a message queue, a telemetry collector, and a database. But for your E2E testing, you need a slightly modified version (different env vars, an extra mock dependency, maybe a different port). Most engineers solve this by maintaining two massive, almost-identical YAML files. It is a nightmare to sync changes. Or they simply do this: $ docker compose -f compose.yml -f e2e-compose.yml up --build -d I do NOT like neither of them. Instead use YAML Anchors (&) , Merge Keys (<<:) , and Compose Profiles to create a single, DRY (Don't Repeat Yourself) configuration file. # ------------------------------------------------------------ # 1. REUSABLE BUILDING BLOCKS (Anchors) # ------------------------------------------------------------ x-backend-depends-on : &backend-depends-on message-queue : condition : service_healthy telemetry-collector : condition : service_started x-backend-config : &backend-config build : . user : " 1000:1000" ports : - " 3000:$PORT" env_file : - .env healthcheck : test : [ " CMD" , " curl" , " -f" , " http://localhost:${PORT:-3000}/health" ] interval : 5s timeout : 5s retries : 12 start_period : 10s depends_on : *app-depends-on # ------------------------------------------------------------ # 2. SERVICES # ------------------------------------------------------------ services : # --- Production / Dev Service --- backend : << : *backend-config profiles : [ " dev" ] # --- E2E Test Variant --- backend-e2e : << : *app-config profiles : [ " e2e" ] # Only starts when explicitly called environment : # Override specific ENV vars for testing RETRY_DELAY_MS : " 100" TIMEOUT_MS : " 200" depends_on : << : *app-depends-on # Inherit all base dependencies e2e-fixture : # ADD an extra dependency for testing condition : service_healthy # ... So now how this changes your workflow: Local: docker compose --profile dev up starts only backend + services in default/dev profile. E2E testing:
There are two kinds of MCP server, they solve different problems, and almost nothing tells you which one you are building until you are deep enough in to have already made the wrong choice. I worked this out from a submission form. More on that below, because it turns out to be the clearest signal in the whole ecosystem and it is buried in a footnote. The two shapes Local (stdio). The server runs as a process on the user's own machine. The client — Claude Desktop, Cursor, whatever — spawns it and talks to it over stdin/stdout. It is a package the user installs. Remote (Streamable HTTP). The server is a service you host. The client connects out to a URL with a token in an Authorization header. Nothing is installed locally. That is the entire distinction, and it determines everything else. What actually differs Who runs the code. Local: the user, on their hardware. Remote: you, on yours. This is the real decision. Everything below follows from it. Where secrets live. Local servers read credentials from the user's own environment — their shell profile, their config file. You never see them. Remote servers require the user to hold a token you issued, which means you own the entire credential lifecycle: issuing, scoping, rotating, revoking. What the server can reach. A local server can read the user's filesystem, hit localhost, talk to their Docker daemon. A remote server can see none of that, and should not want to. Update path. Remote: you deploy, everyone is on the new version immediately. Local: users run whatever version they installed, possibly forever. Failure surface. A local server fails on one machine. A remote server fails for everyone at once. Pick your poison. Choosing Local if you need the user's filesystem, local processes, a local database, or hardware. Or if the data must not leave their machine. Remote if the server fronts a service you already run. If your MCP server's job is to call your own API, making users install a process that proxies to your HTT
Hi, I’m a Principal Architect with 15+ years of experience designing and delivering scalable, resilient, high-availability Java SaaS platforms. My work sits at the intersection of distributed systems, real-time data platforms, and the emerging enterprise generative AI stack. I enjoy turning complex technical challenges into secure, maintainable systems that create measurable business value. Architectural Foundation I lead technical direction for platforms built with JDK 17–25 and Spring Boot 3.x, with a strong focus on microservices, transactional consistency, and operational resilience. My experience includes: Designing services around ACID transaction requirements Managing distributed workflows with Saga and Outbox patterns Applying strategic Domain-Driven Design (DDD) Defining bounded contexts that align software architecture with business capabilities Using Architecture Decision Records (ADRs) to make technical decisions transparent and durable Real-Time and Distributed Systems I build the “nervous systems” of enterprise platforms using Kafka, Redis, and MongoDB. My focus is on event-driven architectures that support real-time processing, high throughput, low latency, and global availability. I am particularly interested in infrastructure-aware design: making sure application architecture, data flow, deployment topology, and observability work together rather than being treated as separate concerns. Generative AI and Agentic Systems A significant part of my current work involves AI/ML and generative AI initiatives, especially Retrieval-Augmented Generation (RAG) and agentic workflows for enterprise use cases. Areas I am actively exploring include: JVM-native inference: Running inference with ONNX Runtime to reduce network overhead and improve predictability Agent orchestration: Building production-ready workflows with LangChain4j and Spring AI Build vs. buy decisions: Evaluating emerging AI platforms against enterprise requirements AI guardrails: Designing secur
Go 1.27 landed in August 2024, and while it doesn’t introduce earth-shattering changes, it polishes the language in ways that add up. If you’re maintaining production services or building new ones, these updates can save you time and headaches. Let’s cut through the noise and focus on what actually affects your code. Performance: Faster Without Changing a Line The compiler and runtime received several under-the-hood optimizations. Benchmarks show a 3-5% speedup in typical server workloads, with some microbenchmarks hitting 10%. This isn’t magic, it’s the result of better inlining decisions and reduced memory allocation overhead. The best part? You get this for free. Just recompile your existing code with Go 1.27 and measure the difference. One standout improvement is in garbage collection. The GC now handles large heaps more efficiently, which matters if you’re running services with hundreds of gigabytes of live data. Latency spikes during GC cycles should be less pronounced, though you’ll still want to monitor this in production. Language Tweaks: Small but Useful Go 1.27 introduces a few language changes that simplify common patterns. The most notable is the addition of the new built-in function clear. It works on slices, maps, and type parameters, letting you reset collections without reallocating them. This is particularly handy for pooling or reusing buffers. For slices, clear sets all elements to their zero value and truncates the slice to length zero. For maps, it removes all entries, leaving the map empty but with the same capacity. For type parameters, it behaves based on the underlying type, useful for generic code. Another small but welcome change is the ability to use //go:linkname with methods. This was previously restricted to functions, which made certain low-level optimizations awkward. Now you can link methods directly, which is useful for writing highly optimized libraries or interfacing with C code. Tooling: Better Debugging and Dependency Manageme
I gave my LLM a 29-question order-reading exam. Last time was how to build the exam. Today: grading. Grading gets its own post for a reason. Build the grading wrong, and the score lies to you. 5 wrong out of 29 — can I ship? No idea. Because "which 5" is missing. If it missed 5 typo-riddled questions, ship it. But if one of those 5 was reading "please cancel my order" as a NEW order? Then even with everything else perfect, you can't ship. That program sends goods to a customer who just cancelled. So don't grade by count. Grade by severity. Severity = "can a human undo this?" My grader has 4 grades. One criterion — is it reversible? In this program, the irreversible moment is when the wrong goods get loaded onto a truck. FATAL Wrong goods on the truck. Cannot be undone RISKY Confirmed something ambiguous without asking. Right this time — fatal next time MISSED Dropped an order. The customer calls. Fixable HARMLESS Over-asked "please confirm." Just slower One principle falls out of this: A wrong confirmation is worse than no confirmation. Sounds obvious. In production you'll be tempted to flip it. Someone complains "it asks for confirmation too often," so you lower the confidence bar. The screen gets cleaner. And the accidents start happening off-screen. The same 28/29 splits two ways FATAL 0 · MISSED 1 → Ship it. Humans catch what it drops FATAL 1 · everything else perfect → Don't ship. You don't know when that 1 comes back Same score. Opposite fates. Two accidents my grader caused The grader is code I wrote. Like all code I write, it had bugs. Accident one — zero points over formatting. A model answer was perfect in content, but the JSON wrapper arrived with the tail cut off. The grader ruled "broken format = fatal." A 100-point answer, zeroed over one missing brace. The fix is simple: count the open brackets and close what's missing (ignoring brackets inside strings). The actual code is in parse_json in the repo . Accident two — penalizing a good answer. For "250 b
Last time I gave my LLM an order-reading exam and lost 5 times as the exam author. Today: how that exam was built. Conclusion first — nice questions are a waste of paper. You'll want to start with the happy path Ask anyone to write a test and they start with the case that works. "5 boxes of the 250 shipping boxes please" → shipping box 250, 5 boxes. It passes. Feels good. Reassuring. But that's wasted points. Models rarely fail the normal cases. What fails is everything that isn't normal. My 29 questions broke down like this: Normal orders 4 Things that aren't orders 6 ← the biggest group Changes & cancellations 4 Ambiguous ones 5 Typos & extreme shorthand 3 After learning kicks in 7 Normal is the smallest group. On purpose. Why "not an order" gets the most questions The worst accident for this program is shipping something nobody ordered. So the exam should aim at that accident more than anything else. What are the dimensions of the 250 shipping box? Product name: present. Number: present. But it's not an order. It's a question. A program that treats "product name spotted" as "order detected" calls the truck right here. So I planted six of these: price inquiries, stock inquiries, delivery questions, greetings, a tax-invoice request. Changes and cancellations are nastier. I ordered 5 boxes of the 250 — please send only 3 Two numbers. Read only the first half and it's a perfect order. Treat it as a new order and the goods ship twice. Plant traps in the catalog too It's not just about hard questions. Make the data itself messy. Two kinds of clear tape — 48mm and 60mm Five products starting with "250" Different pack sizes per box — 50, 40, 25, 10 sheets A few loose items with no box unit at all One reason: real data already looks like this. A real product catalog always has near-twins. Run the exam on a clean catalog and here's what happens — everything passes. Then you plug in production data and it collapses. If the exam passed but production has accidents, that's no
submitted by /u/Iamsodarncool [link] [留言]
submitted by /u/cdb_11 [link] [留言]
submitted by /u/NegotiationInner7307 [link] [留言]
When we write: const result = add ( 10 , 20 ); it feels like the computer simply "runs the code." But the CPU doesn't understand JavaScript. There are several layers between the code we write and the hardware actually executing instructions. That's what I wanted to understand first. From JavaScript to the CPU In Node.js, JavaScript is handled by V8 , the JavaScript engine. A simplified view looks like this: JavaScript ↓ V8 ↓ Bytecode ↓ JIT compilation ↓ Machine instructions ↓ CPU V8 doesn't simply "interpret JavaScript" or "compile JavaScript" once and forget about it. It can start with bytecode and progressively compile frequently executed ("hot") code into more optimized machine code. Eventually, the CPU is executing instructions that operate at a much lower level than the JavaScript we originally wrote. What does the CPU actually do? At its core, a CPU repeatedly executes instructions. A simplified mental model is: Fetch → Decode → Execute → Repeat The CPU has several important pieces involved in this process. Registers are tiny, extremely fast storage locations inside the CPU. They're used to hold values the CPU is actively working with. The ALU (Arithmetic Logic Unit) performs many arithmetic and logical operations. The Program Counter (PC) keeps track of where the next instruction comes from. And the CPU runs according to a clock, measured in GHz. A 3 GHz CPU has roughly 3 billion clock cycles per second, but that does not mean it executes 3 billion instructions per second. Different instructions and architectures have different costs. Modern CPUs are far more sophisticated than this simplified model, using pipelining, multiple execution units, branch prediction, out-of-order execution, and more. But the basic model is enough to start reasoning about performance. The CPU doesn't get everything from RAM One of the most important things I learned here is that where data lives matters . A simplified hierarchy looks like: Registers ↓ L1 Cache ↓ L2 Cache ↓ L3 Cache
Framework says it's replacing some out-of-warranty AMD mainboards.