Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn Performance

DevTools Network and Memory views you should actually use — hướng dẫn Flutter

Most production fires are leaks or chatty APIs. DevTools finds both. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Finding leaked images and chatty APIs in ten minutes. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Snapshot memory before and after a navigation loop. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu,...

DevTools Network and Memory views you should actually use

Most production fires are leaks or chatty APIs. DevTools finds both. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Finding leaked images and chatty APIs in ten minutes. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Snapshot memory before and after a navigation loop. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent...

const constructors: the cheapest Flutter performance win — hướng dẫn Flutter

const widgets can be skipped entirely on rebuilds. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi How const rebuilds become free and where teams forget them. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Lint for const and review lists/dialogs first. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả string...

const constructors: the cheapest Flutter performance win

const widgets can be skipped entirely on rebuilds. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence How const rebuilds become free and where teams forget them. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Lint for const and review lists/dialogs first. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent and calls the bo...

Ship only the assets each platform needs — hướng dẫn Flutter

One assets list used to mean every platform received every file. 3.41 filters by platform. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi pubspec platforms: keys keep desktop files out of mobile APKs. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Store size metrics and download friction improve immediately. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary ...

Setting a frame budget your product team understands — hướng dẫn Flutter

Budgets stick when tied to user-visible outcomes. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi 16ms is engineering language. Translate it to UX outcomes. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Define jank SLOs per critical flow (scroll, checkout, camera). Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, kh...

Multiple Flutter instances in one host app — hướng dẫn Flutter

Some hosts need two Flutter surfaces. Engines are not free. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Memory cost, engines, and when a single engine is enough. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Prefer FlutterEngineGroup to share resources. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả ...

Why your device lab needs a mid-tier Android — hướng dẫn Flutter

Flagship-only testing hides the jank your users feel. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi The phone most users have is not the phone engineers carry. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Keep one $200-300 Android as a release blocker device. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không...

Isolates and compute() without the myths — hướng dẫn Flutter

Parsing large JSON on the UI thread drops frames. Isolates help. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi What actually leaves the UI thread and what does not. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế compute() is fine for one-shot work; use long-lived isolates for streams. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặ...

Image caching and decode budgets in Flutter lists — hướng dẫn Flutter

Image decode is one of the most common raster-thread hogs in feed apps. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi precache, ResizeImage, and avoiding 12MP avatars in chat lists. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Always decode near display size, not camera size. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failu...

Cold start budgets for Flutter apps

Users judge apps by the first frame. Cold start is a product metric. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence What actually shows up first and how to shave hundreds of milliseconds. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Defer heavy packages, avoid sync IO in main, and measure with timeline events. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. ...

Flutter cold start: measuring the time before your first frame

“The app takes three seconds to open” is a complaint, not a measurement. Three seconds from what — the tap, the process spawning, the engine coming up, or the moment your main() runs? Each of those is a different problem with a different fix, and optimising the wrong one is how teams spend a sprint moving startup from 2.9 s to 2.8 s. Cold start in a Flutter app has four phases, and they are separable. The four phases 1. Process launch. The OS creates the process, loads the executable and its shared libraries, and hands control to the platform runner. Nothing in your Dart code affects this. What does affect it is binary size (see the app size discussion) and, on Android, the number of libraries to link. 2. Engine initialisation. The Flutter engine starts, the Dart VM comes up, and — in release builds — the AOT snapshot is mapped in. Plugin registration happens on the platform side here. 3. Dart main() to runApp() . Your code. This is the phase you control completely, and the o...

Slivers that scroll without jank

Slivers give precise control over when layout work happens during scroll. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence CustomScrollView, SliverList.builder, and avoiding layout thrash. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model builder constructors keep off-screen children unbuilt. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case ...

Slivers, properly: the protocol behind every Flutter scroll effect

Most Flutter developers meet slivers the way you meet a pothole: something in a design calls for a header that shrinks as you scroll, the search turns up SliverAppBar , it is pasted in, it works, and the mental model stops there. Then the next design needs a header that sticks per section , or a grid that becomes a list halfway down, and the pasted answer has nothing to say. The thing worth understanding is that a sliver is not a special widget. It is a different layout protocol , running inside the same framework. Ordinary widgets ask “how big may I be?” and answer “this big.” Slivers ask a much richer question — “how much of the viewport is left, how far have I been scrolled past, how much of me is visible?” — and give a much richer answer. Once you can read those two objects, every scroll effect in the framework becomes a small variation on a theme. Box layout versus sliver layout Regular Flutter layout is the box protocol: a parent passes down BoxConstraints (min/max width and ...