The transition that we made in 2012 was from an HTML5 based hybrid app to a fully native iOS app, which was a big change for us. I came in just after we started that rewrite as part of the original team of iOS developers that we had, and at that time it was a very small team, we all fit in one room and we could talk to each other, and so for us at Facebook the challenge that we faced was really one of scaling, we scaled up that iOS organization from a very small team of people to over 100 developers and many more committers that are occasional committers to the iOS repository. So we needed to find all kinds of things, ways to structure code, ways to design the APIs that scale in that fashion.
Alex: You just gave a talk at QCon about functional programming in iOS; what is it that the iOS developer needs to worry about when working on the main thread or with multiple threads.
I came here today to QCon to talk about functional programming in iOS which is kind of a rare combination, it’s not one you usually hear about. You hear about people using Scala or MapReduce, functional programming with MapReduce, but in iOS it’s very much still an imperative programming game because that’s what Apple’s frameworks and APIs encourage you to do. So, today I wanted to talk about how we’ve applied functional programming within traditional Objective C++. So we kind of code in a functional style and the reliability and testability benefits that gives us for News Feed on iOS, which we think it’s the really exciting part of this work that we are doing; it allows us to scale up to many developers working on News Feed and keep it reliable and testable because we use these functional style concepts.
Alex: And presumably the problem with the main thread is that if you block it then the user interfaces freezes and that’s obviously a bad thing in iOS apps.
Yes. So, the key for us is we want 60 frames per second scrolling and we are really not there yet, it'll take us a lot of effort to get there. But on iOS there's very much this concept of there is an anointed main thread and that’s where the UI work happens, the user interface, 60 times per second is going to update to show whatever the latest state is. So if you are doing a scroll and that user interface is scrolling, you need to make sure that nothing you are doing is blocking that main thread for more than 16 milliseconds and that’s an enormous challenge, especially on older, slower devices. So, we've needed to build frameworks and apply concepts that allow us to move work off that main thread as much as possible, and it’s one thing to do that for a simple app, imagine taking a simple object that has a few properties and moving that into the background. But when you have something as complex as Facebook where things are changing all the time, story renderings are immensely complex, there is all this nested attachments and stories and changes, finding a framework to do that was really challenging for us especially with a number of developers working on it that we do and the size of the code base. So functional programming allowed us to tame that complexity, tame the beast and be able to follow and understand and test code so that we have a more reliable and more robust News Feed for iOS.
Alex: And I guess the multithreading aspect really present problems when you’ve got mutable data structures with threads being able to update content as you are trying to relayout the sub-view, for example.
Yes. In Facebook for iOS we started out with a very much more traditional mutable data model system and we ran into problems with that where it was very difficult to follow what the code was doing when you jump between multiple threads, because you'd have all these ordering races, when you make five changes on different threads, the order in which those changes were applied to other threads would be unpredictable and it was difficult to understand how any one change would ripple through that system and what changes that would cause. And so for us to be able to understand the system and make it reliable, it was really key to use immutable data structures; that is if you have a story object in your News Feed and something changes, we don’t modify the existing object, we create an entirely new tree of model objects to represent the new state of the story. And this makes it far easier to reason about what the state of any given part of the code is going to have at any given time.
One of the first concerns that we heard from other developers when we proposed moving to a more functional style for News Feed was if you are going to use these deep immutable data structures you are absolutely going to waste a lot of CPU and memory, because whenever anything changes, if you change one little boolean down here, does the user like the story, changing that one boolean is going to ripple into an entirely new tree for that entire story and that seems incredibly wasteful. But it turns out that this is a well-studied problem in computer science; we’ve got this concept of persistent data structures where we can reuse parts of the tree that haven’t changed and so the actual amount of work we need to do to get these immutable guarantees is not as big as you might think, that was pretty vital for performance on something as small as an iPhone where you have limited CPU and RAM at your disposal.
Alex: And in fact that is how Git works under the covers for storing its data, so it’s pretty widely used even if people don’t know about it.
Precisely, and it gives you all kinds of guarantees, like in Git you can sign commits because they are immutable, you can sign them and that gives you those guarantees for knowing that your repository is secure. And it’s similar here, we are obviously not worried about security, these are our own applications that are sandboxed, we are communicating with the server using https, but it gives it a different kind of security, it’s a guarantee that when you have a model object you know it’s never going to change and so whatever computations you are deriving from that object are always going to be valid and then if you need to make some change you will do it in a whole new sandbox as it were, just like Git.
Alex: Now, I believe you talked about these things being components as both data structure and also factory for UIs. I wondered if you could explain a bit more about that and why you chose C++ rather than Objective C to store those data structures.
So the fundamental design of this system, we have this idea of a component and the component is an Objective C class but we also use Objective C++, which is a framework that lets you integrate C++ and Objective C seamlessly because they have compatible syntaxes. So we use C++ because it gives us a lot of nice performance benefits and it also gives us terse syntax which is really important for us, Objective C is a famously verbose language that causes us a lot of grief, if we are going to be fully functional and declarative we wanted something terser. So Objective C++ gives us this great balance where we have the nice semantics of Objective C and familiarity to regular Objective C developers and yet we get that power of C++. In fact we were worried about this in the beginning, would it be a challenge for iOS developers that don’t know C++ to come in and understand this system, turns out it hasn’t been a problem, they've had no issues at all.
Another benefit of using Objective C++ as opposed to regular Objective C is that it gives you the tools that C++ has for type safety and const safety. So, in standard Objective C you have an NSArray, which is an array, and what’s inside that array you don’t know, it’s not type checked by the compiler, there is no enforcement, and as a developer if you get some array in you have to read the documentation to find out what is in that array. And that struck us as really problematic, honestly. So, in C++ what you use is STL containers that are templatetized so you can actually get type safety; you can say this is a vector of components, so this is a vector of components layouts and we know that the type of the elements in that collection is going to be strongly typed. And similarly because immutability is so important to us we can say alright, the parameter input of this function is a const (whatever the type is) and we know the function can’t modify the argument because it’s defined as const, and that’s really important for us to have those reasoning guarantees to make it easy to follow and reason about what the code is doing.
The magic really happens for us in the infrastructure, we have an infrastructure component that is responsible for detecting when a brand new top level tree comes in due to some change, which is notified by an external store and then it says alright I need to build a new tree of components. And it does this off the main thread to avoid blocking that main thread so we have some users scrolling. So it goes off and builds that tree of components and the reason why it can do it off the main thread is because constructing that tree of components is essentially nothing more than a pure function from a set of inputs which in this case is the model object to an output which in this case is an immutable component data structure, that is basically just a list of instructions for how to create a view, not a view itself. Again, going back to the infrastructure, the infrastructure is responsible for saying this is the old component tree, this is the new component tree after you like the story, let’s reconcile those, so it steps through all the trees in parallel and recycles and reconfigures the view. And of course that means the dirty secret is that deep inside the infrastructure we are mutating UI views, we are still living with the reality that Apple's frameworks are mutable, but all that is hidden from the product developers, as the product developer working in News Feed, you know that you write a pure function and everything else is taken care of for you, you don’t need to worry about mutating things.
Alex: And so presumably this gives both productivity on the device, but also in terms of the developer teams behind it writing that code.
Exactly. So, we see benefits on both sides, it’s less tedious and error prone recycling code to try to make the recycling of UI views or the device optimal and from a developer productivity standpoint you know that if you write this one function that returns an immutable data structure, you don’t need to worry about all the thread safety, you don’t need to worry about locking, you don’t need to worry about deadlocks, it’s all wrapped up in one simple place for you and then it appears right in News Feed, which is fantastic.
Alex: There are some existing frameworks like ReactiveCocoa that try and do a similar sort of thing, I wonder if you can just compare the approach that you’ve done with components and the approach that ReactiveCocoa takes to updating the UI.
We are big fans of ReactiveCocoa at Facebook, we use it in other products, in other areas, we don’t use it in News Feed in particular. ReactiveCocoa is great because it encourages you to write in a declarative style, which is one of the reasons we use components and it encourages you to express things as functions rather than as a bunch of mutable state modifications. The issue here is we wanted a one way data flow where when you make a change it flows into the top of the system and then results in entirely new tree, whereas ReactiveCocoa is more familiar with the traditional system of mutable models and mutable state where it observes models for changes to a mutable object and then it ripple changes throughout the system by using bindings and what they call signals which is a great approach if you want to stay invested in a mutable traditional world, but we find that it also causes in really complex systems these really difficult to follow ripples where one change – like liking a post – will result in all these signals firing and it’s really hard to debug and follow what’s happening. So we prefer the somewhat more naïve and simpler approach of just starting an entirely new tree and then reconciling them in the infrastructure.
The key reason why we did this components infrastructure, why we switched to functional programming was because we were deluged in bugs, not just bugs but hard to reproduce bugs. As an engineer the absolute worst type of bug is one that you cannot reproduce because you cannot understand it. So we wanted a framework that would make easy to reproduce and understand problems and easy to test and understand the code. And so what we found, which is tremendously rewarding, is that it’s gotten a lot better as we did this functional programming switch, instead of a whole bunch of bug reports from our internal testers that had cases we could never reproduce, we can usually identify why something has gone wrong and correct it quickly and we can write a unit test that reproduces the problem and makes sure it won’t regress, which is fantastic as far as we are concerned.
Yes. We think that the concept of immutable data structures is one that has legs, it’s definitely is one that has come out of the functional programming world, we use it in the react framework for JavaScript, we also encourage immutable data models, and we would like to evangelize that kind of immutable data model structure on iOS. We are not yet at the stage where we have something to open source just yet, it’s all very tied to our infrastructure, we talked about what it would take to bring that to the outside world, but we are not there yet. So I encourage others to think about how they can apply those patterns in their code, how they can use immutable data models and hopefully we can come up with something that we can open-source and share with all the developers.
Alex: As a Facebook developer, is there a place where people can follow if any announcements happen then we’d be able to see it externally.
Oh, certainly. We’ve been open sourcing a lot of great stuff on iOS, we’ve got Pop which is this new animation framework that we used in the Paper app and a lot of other exciting things too. So, as time goes on, watch our GitHub, watch our developer blog and hopefully we’ll have more to announce.
The real hairpin twist in this story is that Apple has announced Swift which is a brand new programming language for writing apps for iOS and Swift has a lot of functional concepts inherited or put into its design which is really exciting. That means as a functional programming enthusiast, which I am, it’s a really exciting time to be an iOS developer because we are getting all these functional programming concepts filtered into iOS. So the question that is still unanswered is how is this going to integrate with everything that we’ve already done for Facebook for iOS, we may port what we’ve done to Swift, we may not in the short term, maybe in the longer term, we don’t know yet. But the good news is for everyone that is not working in Facebook on iOS which is the vast majority of iOS developers, it’s a great time to be applying these functional concepts to your code and to learning about Swift about how it operates and how it encourages that style of writing code because hopefully many more people will see the same benefits that we do, of immutability and understanding code, and we’re hopeful that will spread.
Alex: It’s an exciting time to be an iOS developer.
It’s a very exciting time.
Alex: Thank you very much.
Thank you, Alex.