Flutter: Design to app like a pro

Posted on Leave a comment

Sharing with ya’ll the recording of my session from Sapient’s April 11 Flutter meetup.

Warning: This is a longish session (48 mins). Watch at your discretion. You have been warned.
(I really need to work on my time-boxing skills)

Do also see the other 🆒 sessions in this playlist:
https://www.youtube.com/playlist?list=PLfZqxzeCGmPUWopRNcf86Kmusrog73yhL

Use Flutter’s FutureBuilder with care

Posted on 1 Comment

I learned this the hard way. I knew Flutter’s stateless and stateful widget lifecycles well. But I was ignorant.

I made a grave, mostly fatal, mistake of doing something like this:

FutureBuilder<List<Product>>(
  future: this.productRepo.getProducts(),
  builder: (context, snapshot) {
    ...
)

class ApiProductRepo implements ProductRepo {
  Future<List<Product>> getProducts() async {
    // Call an API to get products
    // Return products
  }
}

Do you see the graveness of my code? No? Check again, I’ll wait.

Okay. Maybe you’ve guessed it, maybe not. See the code below. This is the culprit:

future: this.productRepo.getProducts()

FutureBuilder’s official docs say:

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateConfig, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder’s parent is rebuilt, the asynchronous task will be restarted.

A general guideline is to assume that every build method could get called every frame, and to treat omitted calls as an optimization.

https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

Commit the bolded line in memory. For like ever. Otherwise, you’ll end up in the same trap as I. Flutter makes app development so seamless and fun that at times you forget basic optimizations. In my case, I was using a third-party metered API and found myself hitting close to my daily quotas 4x sooner than anticipated. That’s because FutureBuilder was calling the API 4 times, once on each widget rebuild.

My fix was simple: convert my stateless widget to a stateful one and cache API response in state.

class ProductListScreen extends StatefulWidget {
  static const id = 'product_list';

  @override
  _ProductListScreenState createState() => _ProductListScreenState();
}

class _ProductListScreenState extends State<ProductListScreen> {
  List<Product> products;

  /// Returns recipes in cache-first fashion.
  Future<List<Product>> _getProducts() async {
    if (this.products != null) {
      return this.products;
    }

    final productRepo = Provider.of<ProductRepository>(context);
    this.products = await productRepo.getProducts();
    return this.products;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<List<Recipe>>(
        future: this._getProducts(),
        builder: (context, snapshot) {
          ...
        },
      ),
    );
  }
}

Follow this advice, and save tonnes of troubles later.

Mocking Firestore in Flutter

Posted on Leave a comment

I have been writing unit tests like crazy for my muse Flutter app, in my own TDD-like fashion. Writing meaningful tests and watch them go from red to green is a great feeling for real. If you aren’t doing that yet, I highly recommended.

Flutter comes with an excellent testing library called — wait a minute — test. It has one of the most comprehensive set of assertion matchers I have ever seen.

  • Want to test a type? Check.
  • Want to test a future? Check.
  • Want to test an error emitted by a stream? Check.
  • Want to test if your method accidentally rings your neighbor’s door? Umm, well, you gotta do it yourself.

A lot of times you will need to create mocks to avoid side effects in your production database or APIs. Mockito is an awesome package for that. While Mockito works great for general-purpose mocking, I found cloud_firestore_mocks to be closer to the real deal in my testing.

I have used it so extensively in my own tests that I found myself wanting for more. cloud_firestore_mocks, as awesome as it is, does not yet support 100% of Firestore’s APIs. For example, it does not yet support arrayContainsAny where query clause. Same is true for startAt and endAt.

I wanted it so much that I implemented it myself and sent a pull request to Ahn, cloud_firestore_mocks original author. The PR has been merged and the change will land on pub.dev soon. More power to open source!

If you are using Firestore with Flutter, check out cloud_firestore_mocks today and save yourself shit loads of time troubleshooting bugs later. Highly recommended.

A joke only Flutter developers would understand

Posted on Leave a comment

Developer: “YESSS! My world-class widget test is ready to run.”

(runs the test)

Debug Console: “Expected to see 1 widget, found none.”

Developer: What! Why, why, why!!!

(figures out all async calls in the widget; spends 4 hours re-reading about widget testing, exploring the source code of WidgetTester.pump() and setting up mock classes using Mockito.)

Developer: “Muwaha haha! I am the greatest mocker ever lived.”

(runs the test again)

Debug Console: “A RenderFlex overflowed by 20 pixels on the right.”

A compelling case for Next.js

Posted on Leave a comment
Nextjs logo

If GitHub stats are anything to go by, Next.js has received incredible attention of late.

Freelancers and enterprises alike are creating their next applications in or migrating their existing ones to Next.js. When I was recently on-boarded to my first account at Sapient, the departing senior XT architect highly recommended that we migrate to it.

But what is Next.js? Let’s first start with that.

The uninitiated probably know that Next.js has something to do with React. What exactly? Is it the next generation of React? Or something lighter and more performant (like Preact)?

I’ll attempt the simplest explanation possible. Next.js is a way to create server-side web pages all the while allowing you to compose your app using React components. It internally uses React’s server-side rendering principles (and perhaps ReactDOMServer?) to create SSR pages.

It’s okay if you don’t get it the first time. So I’ll quote from its official docs.

In the words of Zeit (people behind Next.js) themselves:

You may want to server-side render certain pages and statically prerender others (balancing SEO and speed).

Think about how webapps are created with PHP. You create some files, write PHP code, then simply deploy it. We don’t have to worry about routing much, and the app is rendered on the server by default.

That’s exactly what we do with Next.js. Instead of PHP, we build the app with JavaScript and React.

Wait. What?!

Are we going back to the server-side days? Weren’t we meant to move away from server-side on to client-side for performance reasons? Is creating single page client applications not the latest ritual? Besides, PHP, JSP, Ruby or Rails, ASP.NET… all can apparently do what Next.js promises.

To fully understand this, we must recap the pros and cons of server- and client-heavy apps.

Server-sideClient-side
Time to first byte (TTFB)Bad
(html is served after full processing on the server, taking its size up)
Good
(a bare-bones, ultra-lightweight html is served immediately)
Time to first meaningful paint (TTFMP)Good
(user can see the “primary” contents sooner)
Bad
(user has to wait for browser’s JS engine to execute all scripts to perceive a page’s “primary” contents)
SecurityLess surface area for vulnerabilities
(what happens on the server stays on the server)
More surface area for vulnerabilities
(increased scope for bad implementations of security due to exposed auth data)
SEO PerformanceGood
(crawlers can easily parse the entire html rendered then and there)
Bad
(crawlers that cannot execute JS code are just left out)
General PerformanceGoodDepends
(see the second article in links below)

I highly recommended reading the following articles once:

An Introduction to React Server-Side Rendering
Next.js vs. Create React App: Whose apps are more performant?
The Benefits of Server Side Rendering Over Client Side Rendering

The second article is especially unmissable, and makes a great point in favor of server-side rendering (SSR) in general. It explains with the help of key practical metrics why SSR wins over CSR in all important areas.

Personally, I have always been a BIG advocate of taking server-side along with client-side development. I don’t believe there’s any such thing as a front-end developer or a back-end developer. A front-end person who doesn’t not know their way around back-end code should not be called a developer in the first place! SSR or not, any app can be performant and secure only if its developers understand the full stack well.