I am flying home from React Conf 2018, hosted at the Westin Hotel in Lake Las Vegas. Some of the key takeaways of this year’s conference:
The conference started out strong with Dan Abramov demonstrating new React hooks to the crowd. I heard many, many audible gasps from the crowd as Dan walked us through using hooks to replace traditional React classes. I had the feeling that I was watching a new version of React being demoed right before our eyes. Although the API is unstable and experimental at this point (it’s just an RFC right now), it is immediately clear that this is the future of React. I am very grateful I was there to hear the announcement in person.
So, what are hooks going to do for you? Well, first of all, you’re going to be writing a lot less boilerplate class code. React 16.7 (alpha) allows us to use functions rather than classes as our components.
State management will be handled by React’s
useState (docs) function - I will say that I felt a little strange about the ergonomics of
useState (you have to call it sequentially, ordering matters). I think that for complex components that require lots of state updates, I would still write traditional classes. This
useState pattern seems best suited for simpler components that only hold a couple values in state.
Instead of manually tracking side effects of components using
componentWillUnmount we can use (no pun intended) the new
useEffect (docs) functions that React provides in 16.7 Alpha. This is probably the most promising feature I saw from Dan Abramov’s presentation.
Rather than segmenting application logic throughout these various lifecycle components:
We will now be able to import the
useEffect function and use it like this:
That’s really it. It may seem a bit magical (it certainly feels like it), but React will now perform the same duties that it used to, but with all of the logic nicely grouped together! This makes writing and debugging side effects much easier.
One more big change.
One of the worst parts of React was dealing with boilerplate code, particularly when it comes to
shouldComponentUpdate is rarely used for much more than checking if the
nextProps based on some criteria.
This is some very typical
shouldComponentUpdate boilerplate that I’m sure you’re familiar with:
We are just checking if the incoming props have a different
id than the props we already have. This is a fairly standard check for a lot of React components. What if React could just diff our props for us, and only update when necessary?
Did I mention that when you use function components, there is no more binding to
this? That alone is a compelling reason to begin exploring using React Hooks.
async functions - once a single function is async, everything in the codebase eventually follows suit. That’s never personally been a problem for me (I greatly enjoy using the asynchronous features of JS).
James argued that the asynchronous nature of React Native’s interaction with native API’s was harming UX. He showed some compelling examples of janky scrollng behavior that occurs when the React Native asynchronous processes fall behind the screen render.
His solution: Block the main thread. Don’t let other tasks interrupt crucial animation rendering. What’s the best way to do that? Get rid of
async, and allow synchronous flow between native API’s and React Native.
Speaking of talks I enjoyed, I greatly enjoyed Conor Hasting’s talk about GraphQL.
In a typical REST API setup, a consumer requests data from an endpoint. The consumer has little to no control over what is delivered to them. To use Conor’s analogy, it’s like calling a pizza parlor for pizza delivery, and since they don’t know what toppings you like, they put 40 different toppings on the pizza, deliver it to your house, and tell you to pick off the ingredients you don’t like.
When you’re working on a front-end application and constantly consuming API’s for varying amounts of data, this can get exhausting. Want to get only the
timestamp of a given set of rows? Too f’ing bad. Now your front-end application is stuck having to munge, filter, and extract data, even though we know exactly what we want. It’s like calling the pizza parlor, asking for pepperoni, and getting 40 toppings.
GraphQL seeks to enforce the concept of getting only what you need, when you need it. This concept is not limited to any sort of technology stack or implementation - it is simply (in my eyes) a philosophy of API design. With GraphQL, your frontend can intelligently query the API for only the data it wants.
This saves time in two huge ways:
As someone who has a hard time hearing, I really, really appreciated the real-time captions provided by the conference. They were incredibly precise, accurate, and they made my conference experience a lot better. I am used to only hearing 50-60% of a speaker’s talk, and I really loved being able to look to the caption monitors and follow along.
My latest work project has involved writing a custom Django API from scratch. Due to the numerous business logic and front-end requirements, something like Django Restful Framework wasn’t really a great option. I learned a great deal about the finer points of Python and Django performance while delivering an API capable of delivering thousands of results quickly.
I’ve consolidated some of my tips below.
Be careful using model managers, especially when working with Django
Prefetch data. You will incur additional lookup queries for the operations that your manager performs, as well as any other operations your manager performs on the data (
Do everything you can with properly written Models, queries, and prefetch objects. Once you start using Python, you will significantly impact the performance of your application.
Django is fast. Databases are fast. Python is slow.
Learning to use
prefetch_related will save you a ton of time and debugging. It will also improve your query speeds! As I mentioned above, be careful mixing Model managers with these utilities - also, whenever you begin introducing multiple relationships in a query, you will want to use
order_by(). Having said that…
If you are using advanced Django queries that span multiple relationships, you may notice that duplicate rows are returned. No problem, we’ll just call
.distinct() on the queryset, right?
If you only call
distinct(), and you forget to call
order_by() on your queryset, you will still receive duplicate results! This is a known Django “thing” - beware.
"When you specify field names, you must provide an order_by() in the QuerySet, and the fields in order_by() must start with the fields in distinct(), in the same order."
- Django Docs
You can’t fix what you don’t measure. Make sure
DEBUG=True in your Django
settings.py file, and then drop this snippet into your code to output the queries being run.
mapwhen performance matters AND the functions are complex AND you are using named functions. Use list comprehensions for everything else.
map is a built-in function written in C. Using
map produces performance benefits over using list comprehensions in certain cases.
Please note that if you consume an anonymous lambda as your
map function, rather than a named function, you lose the optimization benefits of
map and it will in fact be much slower than an equivalent list comprehension. I will give you an example of this gotcha below.
To test the performance of these functions, we create an array with 10,000 numbers, and go through the array squaring each value. Pretty simple stuff. Check out the wild differences in runtime and performance:
mapwith named function: 10006 function calls in 0.050 seconds
Moral of the story? If you are doing simple list operations, use list comprehensions with anonymous lambdas. They are faster, more readable, and more pythonic.
When you’re munging complex data in Python, it’s a good idea to handle the data modification in a named function and then use map to call that function. You must always profile your code before and after using
map to ensure that you are actually gaining performance and not losing it!
You might be asking so, when should I use map?
A good candidate for
map is any long or complex function that will perform conditional operations on the provided arguments.
map functions are great for iterating through objects and assigning properties based on data attributes, for example.
Here’s an example of
map being significantly faster than list comprehensions (shamelessly taken from Stack Overflow):
If you’re using inline
try/except statements (where it’s no big deal if the
try block fails), just attempt to do the thing you want to do, rather than using extraneous
Here’s some sample code and real profiling results to guide your decisions.
Our profiler results are below - using an
if took 0.098 seconds - using only
try/except shaved off one-third of the compute time, down to 0.065 seconds
Notice that our function using
if incurs twice as many function calls as our plain old
If you’re planning on taking the AWS Security Specialty exam, I’ve compiled a quick list of tips that you may want to remember headed into the exam.
I passed the exam on August 18th, 2017. Before taking this exam, I held all three Associate certifications. This exam was harder than any Associate exam by far!
Here is what I think I know, as of April 2018. This guidance is heavily biased by working with Electron/React/Node, all over the stack, over multiple types of projects.
Developing a modern JS application without typing is both painful and tedious. I helped write a 25k+ LOC Node codebase without any form of typing - let me tell you, when you are debugging a year-old function you wrote and try to piece together what the data structure must have been at the time - it’s nearly impossible.
Any codebase that goes beyond a toy/prototype level must immediately implement
Flow, or some form of typing, even if it is just a ridiculously long comment above each function describing the expected inputs/outputs (don’t actually do this - oh wait, this basically describes working with Python).
If you frequently find yourself writing code like this:
Let me give you some advice. One day, one of your amazing engineers is going to write
dogg instead of
dog, and you’re going to miss it because you’re too busy making coffee, and that dumb code is going to end up in production, and your users are going to be rudely greeted by a stupid cat (or an error) instead of an awesome dog when they click “SHOW ME DOGS” on your new app, DogCatHorseShow!.
Instead, try this. The first time you write a comparison like above, stop yourself, take a deep breath, and do this.
Create a file called
constants.ts (you’re using TypeScript, right? :))
The file should look like this:
And now, your business logic file should look like this:
Now you and your co-workers can safely compare values and you know that you’re all working with the same strings. If this example seems contrived, I want you to know that I just spent a lot of time fixing errors related to
Consolidate your business logic EARLY, or you’ll end up with important comparisons scattered everywhere and subtle errors permeating your code.
Although the Chrome team is making admirable gains in performance here, it is ALWAYS slower to include mixed data types in an array.
You can see this performance impact for yourself here: JSPerf
The V8 engine can’t optimize functions that are passed varying data types. If you really are trying to eke out every bit of performance, write pure functions that accept consistent data types, and make sure you only use them as intended!
Abusing functions like this, while convenient for the programmer, can lead to a nearly 50% reduction in speed.
This one is probably a no-brainer, but consider batching any events or actions that rely on external resources to complete.
When you’re updating a JSON file or a database somewhere, you’re going to deal with incredible asynchronous headaches if your code has a theme of “each individual action manages itself.”
Consider writing your code in a way that lends itself to batching of updates - whether you’re doing HTTP requests, file updates, DOM reflows, or DB calls. Focusing on batching early in your codebase will allow you to scale faster when you start handling more actions and events.
You should already do this just for cleanliness and understandability, but you should also know that the length of your written function (including comments(!!)) has an impact on performance.
The takeaway here should still be to keep functions small. At the moment we still have to avoid over-commenting (and even whitespace) inside functions. - from v8-perf discussion on Github
In a greenfield codebase, every feature added to the codebase should have an accompanying test. This prevents code rot from setting in, and it keeps the codebase style reasonable and testable from an early stage.
Especially when you’re doing open-source driven work, you’re frequently going to have subtle breakages when you upgrade/update your
npm packages. Automated tests are the only way you’re going to catch it - yes, even for your weekend project that you’ll definitely never pick up again.
Look, I’m not saying you gotta go all TDD on your personal projects, but… one day you’ll want to go back to that project and use it, but you won’t be able to touch the code without breaking it. Been there, done that, learned my lesson.