To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.

摘要:

1、It can remove a significant amount of complexity from our programs and make our code easier to reason about.

2、The problem is that we rarely (read: never) are updating our output based on just one input/event. I can’t put it any better than the way Josh stated it:

“To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.”

3、In addition, these inputs are littered up and down our source file, all with slightly different interfaces for the developer to remember. We now have many related inputs looking very unrelated in our code, making the work of mentally mapping out their relationships difficult. In other words, it makes it hard to reason about our code.

4、Basically, we program in linear fashion;Our asynchronous callbacks and other events are still occurring in a linear fashion.

5、Whenever one of these events happens, we likely need to generate output. To do that, we need to combine the new information from this event with all the information from previous events relevant to this particular output.

6、We want to define the relationship between events (inputs), define their subsequent outputs, and then let the computer react appropriately whenever those events occur. State still exists somewhere in this event system, but it’s largely abstracted away from our day to day work. That’s a big win. The paper tape still exists, but it’s all under the hood.

Why

Anyone who builds things for a living should always be striving to improve their skillset. This means investigating new ways of doing and thinking whenever possible. As programmers one of the hardest things we have to do on a regular basis is to be able to reason about our code1; to have a mental map of the implementation used to solve a complex requirement. To me, this is the biggest gain provided by the reactive model of programming. It can remove a significant amount of complexity from our programs and make our code easier to reason about.

For a more authoratative read about reactive programming, you should go read the article “Inputs and Outputs” by Josh Abernathy, one of the creators of ReactiveCocoa. It’s an extremely well written article that I can only hope to supplement with a slightly different explanation. (I’ll be rehashing a bit of what he’s covered there.)

Inputs and Outputs

So what does Josh mean when he says it’s all Inputs and Outputs? The entirety of our job, the meat and potatoes of what we are doing when we build an app, is waiting for events to happen that provide some sort of information (inputs), and then acting on some combination of those inputs and generating some kind of output. Inputs come in all kinds. They provide us with varying levels and types of information:

This is just a sampling of the different kinds of inputs we deal with daily. The information they provide can be as simple as “This event happened”, or be accompanied by a lot of detail about the event such as “The user entered these new characters in the text field”. There are certainly reasons for all the different patterns above, not the least of which is the evolution of our craft and tools; but when it comes down to it they are ALL just telling us some event happened, and sometimes providing extra information about that event.

Outputs can be anything, but a few typical examples include updating a value on a server, storing something in core data; or most importantly, and most typically, updating the UI.

The problem is that we rarely (read: never) are updating our output based on just one input/event. I can’t put it any better than the way Josh stated it:

“To put it another way, the output at any one time is the result of combining all inputs. The output is a function of all inputs up to that time.”

I will add one point pertinent to this article. We often don’t really care what order these inputs came in from an application design perspective, but from an implementation perspective it’s something we are constantly dealing with. In addition, these inputs are littered up and down our source file, all with slightly different interfaces for the developer to remember. We now have many related inputs looking very unrelated in our code, making the work of mentally mapping out their relationships difficult. In other words, it makes it hard to reason about our code.

Paper Tape Computing (Linear Programming)

The issue here is one of time, or more accurately, the timeline of execution. Basically, we program in linear fashion, never wandering all that far from the way things were done on paper tape computers or punch cards. We have an understanding that there is a run loop, and that our code is going to be placed on a timeline and executed in order (ignoring multiple processes for the sake of argument.) Even our awesome block callbacks and delegates are just giving us another snippet of time on the timeline where we can execute code. In fact, all our code is driven by inputs (events) just giving us another chance to insert some paper tape, as shown in this beautiful (and super simplified) diagram.

Our asynchronous callbacks and other events are still occurring in a linear fashion. The period of time in which the data from these events is available to us is limited to a small spot on our linear execution timeline (scope).2 Even if all these events occurred at the same exact millisecond, the CPU would still have to handle one at a time. Our code is stuck executing in single file, with no knowledge of what happened before it.

Whenever one of these events happens, we likely need to generate output. To do that, we need to combine the new information from this event with all the information from previous events relevant to this particular output. Our blocks and delegate calls may be asynchronous, but we still have to deal with the consequence of when they occured on our timeline.

But how do we do that? The information from those previous events isn’t available in the same scope as the current event we’re dealing with.3 There’s no elegant mechanism provided for accessing past events, or combining the information from all relevent events. Since these inputs are essentially isolated from each other in this linear style of programming, we have to imperatively (directly) go and check the status of any dynamic information that other inputs could have changed beforehand. That is to say any time there is an event (input), and we’re given a chance to run some more paper tape, we do a lot of this type of thinking in code:

“Ok lets check what we’ve got here. User tapped a button eh? Well we’re going to want to show the menu then, but a couple things first: Is this user logged in? Good they are. And has the data for this menu loaded in or are we still pulling that from the server? Ahh good we already have that. Finally, the menu isn’t already showing is it? Ok it isn’t, in which case I’m going to go ahead and show it. Let’s write down that it’s showing now, so I know in the future.”

Basically anytime we get the opportunity to run a bit more code via some event, we are doing so with the memory of a goldfish.4 Each time we start with no idea what’s happened previously and have to go check a bunch of statuses to build enough context to correctly generate the output we need. The system is “dumb” and doesn’t know what information we might need for that particular output, so it can’t track it for us. We are left to our own devices to come up with a solution, and end up tracking any possibly relevant inputs ourselves using state.

STATE

State is what makes our job as programmers VERY hard sometimes. To be honest, I didn’t recognize this. That is to say, I knew when I had lots of different events and variables affecting my UI that it became really hard to manage; but I didn’t recognize it in a philosophical, definable way. It’s so ingrained in me that I just thought it was part of the deal with programming, and that maybe I wasn’t the best programmer for constantly struggling with it.

This is not the case. Everyone sucks at managing state. It is the source of an endless amount of bugs and blank stares. “I understand WHY it crashed. I just don’t understand how the user could have possibly gotten it in that state.” ← Programmer adds another state check.

So what is state? Are we just talking about enums and state machines like TCQuestionDetailViewControllerState? Nope. This is all state:

That should have made you cringe. I’m SURE you’ve seen (and written) similar code. If not you are a WAY better programmer than I am. UI’s are often very complex in code even when they appear simple to the user. In fact, the very reason a user may LOVE your app is the amount of power it delivers in an extremely simple interface.

Value is created by swallowing complexity for the user.  - CEO of my first startup

The problem here is that every time you add another state, you are increasing the possible number of combinations in an EXPONENTIAL manner. And that’s assuming your states are just BOOLs. I had an “aha!” moment when I saw a slide in a talk by Justin Spahr-Summers.

I looked at my code, like the interface above, and realized I was giving myself an unbelievably difficult task, requiring super-geek like abilities to pull off (to the tune of 4000+ different combinations I needed to handle if they were all relevant to the output). Obviously this is HIGHLY error prone.

To make matters worse, this type of code will often produce UI only bugs that are incredibly hard, if not impossible, to identify in any automated way. After a few times through this wringer, we’ve probably all ended up writing centralized update methods that check a bunch of properties and update things accordingly. We end up with methods like this littered throughout our code: updateViewCommentStatus updateChangeAnswerButtonText. Any time we add another event (input), we make sure it’s updating all the relevant states (e.g. properties) and call the appropriate centralized update methods.

We are expending an awful lot of mental energy dealing with the consequences of this linear code execution thing, this modern version of the paper tape computer. Despite the power of computers today, we are still doing a heck of a lot of work on their behalf. We’re programming to the way the computer hardware works; to the way that the run loop is creating a timeline and the cpu is processing bits in a single file. We are architecting our code around low level implementation details of computing. What if we were to harness the power of the computer, let it do more of the work, and allow ourselves to think and design our apps in a more sane manner?

What if we abstract away the whole pesky notion of linear code execution, explain to the computer what combinations of inputs we are interested in for a particular output, and let the computer track state over time for us? Seems like something the computer would be good at; and we’re certainly awful at it.

Compositional Event System (Non-Linear Programming)

I’m not a classically trained, CS Degree wielding programmer. I did a lot of multimedia before ending up programming for my day job. In that time I’ve seen a lot of tools make the jump from linear to a non-linear style of thinking and working. I’ll talk about tools in another post, but even auto-layout is a great example of moving towards a non-linear (and reactive) approach. Instead of waiting for certain events to occur, then checking the status of a bunch of views and imperatively updating frames, you just describe what the relationships between all the views are ahead of time and let the computer do the work.

In the discussion about the correct terminology to describe RAC and similar styles of programming, the term “Compositional Event System” has been brought up. I think it fits really well. Much like the shift in the multimedia tools I mentioned, what we really want to do is remove (for the most part) the need to account for the timeline of when events (inputs) happen, and therefor the need to manually keep track of them with state. We want to make the computer do that for us.

We want to define the relationship between events (inputs), define their subsequent outputs, and then let the computer react appropriately whenever those events occur. State still exists somewhere in this event system, but it’s largely abstracted away from our day to day work. That’s a big win. The paper tape still exists, but it’s all under the hood.

When you think about it, this concept is actually very simple, and not entirely foreign. Inputs and outputs 5:

Source

ReactiveCocoa

So how does ReactiveCocoa abstract away the timeline for us and step into the world of Non-Linear Programming? It does this by wrapping all those types of input from above (delegate, KVO, completion blocks, etc) in one unified interface called a Signal (RACSignal).

Think of a signal as a representation of future values from your input. It’s similar to a promise/future which you may have used, but more robust in that it can continually send values (it isn’t limited to just one). While this is similar to a KVO block repeatedly being executed as it observes changes, the difference here is that we now have an object representing those future values. We can take that representation and combine it with other signals to build relationships among our events, and describe how data will flow through our app. This is done with powerful operators that can transform and filter our data into new signals, eventually arriving at the data we need for our output.

http://www.sprynthesis.com/2014/06/15/why-reactivecocoa/

Why Reactive(Cocoa)?-时间线、输入、输出、复杂性、异步、状态、聚合的更多相关文章

  1. 模拟n个人参加选举的过程,并输出选举结果:假设候选人有四人,分别用A,B,C,D表示,当选某候选人时,直接输入其编号(编号由计算机随机产生,若输入的不是A,B,C,D则视为无效票,选举结束后按得票数从高到底输出候选人编号和所得票数.

    模拟n个人参加选举的过程,并输出选举结果:假设候选人有四人,分别用A,B,C,D表示,当选某候选人时,直接输入其编号(编号由计算机随机产生,若输入的不是A,B,C,D则视为无效票,选举结束后按得票数从 ...

  2. H面试程序(1)编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的 下一秒

    编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的下一秒. 如输入 2004 年 12 月 31 日 23 时 59 分 59 秒,则输出 2005年 1 月 1 日 0 时 0 分 0 秒. ...

  3. qemu:///system 没有连接驱动器可用;读取数据时进入文件终点: 输入/输出错误

    原因 1. KVM的相关包 装少了 2KVM的相关包 重新安装 3 May 31 15:22:55 localhost libvirtd: 2019-05-31 07:22:55.554+0000: ...

  4. [HMLY]9.深入浅出-iOS Reactive Cocoa的常见用法

    简介 今天的主角是Reactive Cocoa,聊聊Reactive Cocoa的常见使用:KVO.Target.Delegate.Notification. Reactive Cocoa 是一个重量 ...

  5. iOS-Reactive Cocoa的常见用法

    今天是周末,临近年底,工作上遇到不可抗力,会有点一些变动!这多少会让人有一点静不下来,但需克制,Reactive Cocoa是今天的主角! 废话不多说,今天聊聊Reactive Cocoa的常见使用! ...

  6. 设计Twitter 时间线

    「design Twitter」是 LeetCode 上第 335 道题目,不仅题目本身很有意思,而且把合并多个有序链表的算法和面向对象设计(OO design)结合起来了,很有实际意义,本文就带大家 ...

  7. 输入/输出系统的四种不同工作方式对CPU利用率比较

    程序控制工作方式:输入/输出完全由CPU控制,整个I/O过程中CPU必须等待其完成,因此对CPU的能力限制很大,利用率较低 程序中断工作方式:CPU不再定期查询I/O系统状态,而是当需要I/O处理时再 ...

  8. [转]C语言文件输入/输出ACM改进版(freopen函数)

    C语言文件输入/输出ACM改进版(freopen函数) 2009年5月27日 10:379,457 浏览数发表评论阅读评论   文章作者:姜南(Slyar) 文章来源:Slyar Home (www. ...

  9. ubuntu12.04软件中心打开错误和 ubuntu 包管理之“:E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件包的列表或是状态文件。”的解决

    执行ubuntu软讲中心时打不开.老是崩溃,从终端也下载不了软件. 执行包管理的update或者search等等会报错: E: 读错误 - read (5: 输入/输出错误) E: 无法解析或打开软件 ...

随机推荐

  1. laravel数据迁移

    创建数据库迁移: php artisan make:migration create_表名_table 回车后就会创建迁移版本   回滚数据库迁移: php artisan migrate 会将数据按 ...

  2. 微信WeUI入门2

    引入需要的样式文件 最重要的css文件为 weui.min.css 基本的框架如下: <!DOCTYPE html> <html lang="zh-CN"> ...

  3. angularjs 过滤掉textarea输入内容中夹带的特殊字符

    <body ng-app="app"> <div ng-controller="main"> <textarea ng-model ...

  4. C# 之正则表达式运用

    C#正则验证大全 Regex.IsMatch()正则表达式验证 需要引入命名空间 using System.Text.RegularExpressions;    #region 验证文本框输入为数字 ...

  5. 添加FB登陆时,需要curl扩展

    安装curl扩展遇到一个傻逼问题 [root@xxx openssl]# /usr/local/php/bin/phpizeCannot find config.m4.Make sure that y ...

  6. 集群搭建之Hive配置要点

    注意点: 在启动Hive 的时候要先启动Hadoop和MySQL服务. Mysql 和 Hive 搭建在 yan00机器上. part1:MySQL配置相关 安装和配置相关命令: Yum instal ...

  7. 【SSH网上商城项目实战06】基于DataGrid的数据显示

    转自:https://blog.csdn.net/eson_15/article/details/51322262 1. 回顾一下第4节内容 在第4节中,我们使用EasyUI搭建好了左侧菜单栏,并且通 ...

  8. 第一个Windows窗口应用程序

    学习目的 熟悉开发工具Visual C++ 6.0和MSDN 2001的使用. 应用Windows API函数, 手工编写具有最基本构成的Windows窗口应用程序(包含WinMain入口函数, 消息 ...

  9. js在ie6下的一个bug—未结束标签的错误

    在IE6下,如果在body标签没结束前,用代码获取body对象就会出现错误.如: <html> <head> <script type="text/javasc ...

  10. [Code+#4]最短路

    考虑xor运算的自反性 我们可以直接枚举二进制位异或来进行转移 这样边数大约是\(n \log n\)级别的 总复杂度\(\Theta((n\log n+m)\log n)\) #include&qu ...