ReactiveCocoa

Me on Twitter last Saturday, when asked about ReactiveCocoa:

It’s a research experiment, and I’m glad it’s happening, but I myself wouldn’t use it in production code at this point.

This may sound dismissive, though that wasn’t my intention. ReactiveCocoa is important, and I’m glad it’s happening for two reasons:

  1. Functional reactive programming looks more and more like an important part of the future of programming.

  2. Research that can change how we build apps should happen not just inside Apple but outside too.

Some extremely intelligent people are working on this. I applaud and encourage them to find better ways to do what we do.

Because ReactiveCocoa is more ambitious than the average open source project, because it seeks to change at a fundamental level how we write Cocoa apps, because it’s applying the principles of functional reactive programming to a language and framework that’s only somewhat cooperative, I consider it a research project.

And I won’t use it in my production code. Not yet. (I’m the weirdo who can’t even quite bring himself to use Core Data.)

Here’s why. It has nothing to do with code quality. Rather, there’s a trade-off involved in using ReactiveCocoa that I’m not ready to make.

Remember that there are two ways to write bug-free code: 1) use techniques that make bugs less likely, and 2) write code that you can read and verify for yourself is bug-free.

(Obviously you should use both.)

I’ll borrow an example from NSHipter’s article on ReactiveCocoa (which you should read if you haven’t already).

Here’s some conventional code:

- (BOOL)isFormValid {
  return [self.usernameField.text length] > 0 &&
    [self.emailField.text length] > 0 &&
    [self.passwordField.text length] > 0 &&
    [self.passwordField.text isEqual:self.​passwordVerificationField.text];
}

#pragma mark - UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField
  shouldChangeCharactersInRange:(NSRange)range
  replacementString:(NSString *)string
{
  self.createButton.enabled = [self isFormValid];

  return YES;
}

Here’s the same thing using ReactiveCocoa:

RACSignal *formValid = [RACSignal
  combineLatest:@[
    self.username.rac_textSignal,
    self.emailField.rac_textSignal,
    self.passwordField.​rac_textSignal,
    self.passwordVerificationField.​rac_textSignal
  ]
  reduce:^(NSString *username, NSString *email, NSString *password, NSString *passwordVerification) {
    return @([username length] > 0 && [email length] > 0 && [password length] > 8 && [password isEqual:passwordVerification]);
  }];

RAC(self.createButton.enabled) = formValid;

After so many years of writing Cocoa code, I can read and understand the conventional version easily. The ReactiveCocoa version is very different from the code I’ve been writing all along, which makes it much harder for me to verify by reading that it’s correct.

That’s a choice every developer has to make. You may be willing to take the time to learn this so well that the ReactiveCocoa version reads naturally and easily. Me, I’m not willing, at least not yet.

(This assumes I’ve taken step one, which is to research functional reactive programming well enough so that I’m convinced of its benefits. I haven’t done so, though I’ve done enough reading to lean toward thinking it does have benefits.)

Here’s what may happen: ReactiveCocoa gains popularity, and it demonstrates that functional reactive programming is, in important respects, a better way to write apps. And then Apple — because only Apple can do this part — adds framework and language support, and does so in a way that makes for easily-readable code.

That’s my hope.

I most emphatically do not believe progress has stopped. There are better ways to do what we do, and everybody who’s trying to find these better ways has my thanks.

PS Highly recommended: Rob Rix on Postmodern Programming. I’ve read it twice already.

10 Mar 2014

Archive