Yuan Yijun (bbbush) wrote,
Yuan Yijun
bbbush

  • Music:

公司的 Meetup

公司有些热心人(推荐 follow 这位同事 Vivek),在 Meetup 上建了组,搞了很多场活动。一个是 MoMo,另一个是叫做 Morningstar Tech Talks,分别是关于 Mobile 和 DevOps。后者主题很杂,Meetup 上感兴趣的人也很多。

有些可能有用的地址 slideshare, vimeo, twitter, facebook, topsy, quora. 不过是否上传演示稿、视频,与活动和主持人都很有关系。

能参加这样的活动,得到一些培训,了解旁门左道的知识,感觉挺好的。Meetup 网站不错,已经参加过几个不同的活动,邮箱里还经常收到其他活动的推荐。每次活动都有二三十人参加,所以参与人数与 Meetup 组的成员数量不太相关,而与活动本身更有关系,比如提前多久布置、活动主题是否详细介绍、是否吸引人,等等,与 SZLUG 相仿。

周四参与的活动,是 Morningstar Tech Talks 的 Reactive Extensions (Rx) Workshop, 持续了大半天。上午是 Eric Meijer 主讲 Rx 的接口设计,下午是 Brian Beckman 讲 LINQPad 的用法,然后 Eric 讲了一个 thermal sensor 的应用。没来得及讲 Rxjs,只是介绍了地址和各种 bindings。Notes 如下:

* 书籍 Programming Rx and LINQ

* Rx 的设计有两个假定:首先待处理的数据是 streams of data,并不是 IEnumerable 那样已经准备好的集合。实际上 generators 也并没有完全准备好,Eric 提到 iterator 到 observable 模式的转换中,必须考虑 concurrency

* 使用硬币来讲解更易懂,比如告诉孩子 3 quarters 比 75% 容易

* Pull and Push model: who is in control? "I want next quarter" is IEnumerable style, program in control 但是需要等待;"here is a quarter" is observable style, environment in control

* Duality 在数学和物理中都有对偶的问题,举的例子是德摩根律,和电阻、电容的公式。(好像傅里叶变换也是这个意思;有个网页看起来很有意思。)

* IObservable 的设计思路是对偶,把 IEnumerable 的输入变成输出,输出变成输入

* IEnumerable 和 IEnumerator 的模版参数都是 <out T>, covariant, 而 IObservable 是 out T; IObserver 是 in T, contravariant,一个简便的记法是 out T 是返回值,in T 是参数,而 contra- 表示“相反”,所以用两次的 in 就会变成 out。
    public interface IObservable<out T>
    {
        IDisposable Subscribe(IObserver<T> observer);
    }
    public interface IObserver<in T>
    {
        void OnCompleted();
        void OnError(Exception error);
        void OnNext(T value);
    }

这里 IObserver.OnNext 用到了参数 T value,所以整个接口是 in T,可以赋给 I<derived T>;而 IObservable 的参数用到了 in T,两次的 in 就变成了 out,可以赋值给 I<base T> 变量。

* Accidental complexity: 很多接口的定义并不是用这种 academic 的方式定义的,最初分析中的小错误会导致接口庞大复杂,一错再错,像 java 的 Observable 就是如此。

* 如果实现中得到了错误的结果,应该自问:究竟是在 "do wrong thing" 还是在 "do right thing in a wrong way"。(这点在设计 IGroupDefinition 的 comparer 时深有体会。从最初就觉得必须用 comparer 来完成排序动作,但是搁了一年才搞清楚每个 comparer 应该放到什么地方。接口比实现容易,因为接口可以很直觉、很 academic 地分析出来,但是一个几行的接口就足够产生错误百出的实现了。)

* async 和 Task<T> 是 push model 在单个值上的应用。在 pull model 里,单个值叫做 IO<T> 或者简单的 T (there are saner way of doing side effects)

* Extension Methods. Eric 说他所有的 class methods 都改造成 extension methods,除非需要重载;至于成员变量,"make them public! That's a lie to hide them, you can find them with reflection anyway!" 显然这是夸张的说法。而且 extension methods 和 "make things public" 的问题是没办法搞 interface versioning。LWN 提到不严格检测 bitmap 的后果,就是未使用的 bit 可能无意间被设值,那么将来再想用它们时就会造成兼容性问题。同样的,一个 interface 不接受的方法,就不该假设 extension methods 可以用掉。

* FP language is more about closure and list 因为列表最适合保存 closure 状态(?)

* 演示文档里有写 F# 风格的 anonymous class,语法很漂亮!
IObservable<KeyPressEvent> GetKeyUp(this Control w)
{
  return new IObservable<KeyPressEvent>
  {
    IDisposable Subscribe(IObserver<KeyPressEvent> h)
    {
      var d = h.OnNext;
      w.KeyUp += d;
      return new IDisposable
      {
        void Dispose()
        {
          w.KeyUp -= d;
        }
      }
    }
  }
}


* 返回 IDisposable 用来 unsubscribe event,因为 unsubscribe 很容易用错。.NET 应该加入一条编码规则,只允许 event 加/减同一个 delegate。

* Rx merge: subscribe to both, return new observable

* Rx zip: convert two sequence to pairs

* Drag and drop example: favourite one!

* Rx let: duplicate input sequence. let 操作可以复制源序列,对 IObservable 而言是触发事件,对 IEnumerable 则是重复整个序列。很难对 IEnumerable 实现 let。(这个不知道对不对?)
public static class IEnumerableLetExtension
{
    public static void TestIEnumerableLetExtension()
    {
        var enumerable = CreateEnumerable();
        var sum = 0;
        enumerable.Let(myEnumerable =>
        {
            foreach (var v in myEnumerable())
            {
                sum += v;
                var sum2 = 0;
                foreach (var v2 in myEnumerable())
                {
                    sum2 += v2;
                    Console.WriteLine("send one $1m {0} {1}", sum, sum2);
                    if (sum2 > 2) break;
                }
                if (sum > 4) break;
            }
        });
    }

    static IEnumerable<int> CreateEnumerable()
    {
        while (true)
        {
            Console.WriteLine("received $1m");
            yield return 1;
        }
    }

    public static void Let<T>(this IEnumerable<T> source, Action<Func<IEnumerable<T>>> action)
    {
        if(source == null || action == null) throw new ArgumentNullException();
        action(Let(source));
    }

    static Func<IEnumerable<T>> Let<T>(IEnumerable<T> source)
    {
        if (source == null) throw new ArgumentNullException();
        var enumerator = source.GetEnumerator();
        var array = new List<T>();
        var dict = new Dictionary<int, int>();
        var index = 0;
        var end = 0;
        Func<int, T> getValue = n =>
        {
            int pos;
            lock (dict)
            {
                pos = dict[n];
            }
            T v;
            lock (array)
            {
                if (pos == array.Count)
                {
                    if (end == 1) return default(T);
                    if (!enumerator.MoveNext()) // NOTE(byuan): transfer $1m
                    {
                        end = 1;
                        return default(T);
                    }
                    array.Add(enumerator.Current);
                }
                v = array[pos];
            }
            lock (dict)
            {
                dict[n]++;
            }
            return v;
        };
        Func<int, bool> hasEnded = n =>
        {
            int pos;
            lock (dict)
            {
                pos = dict[n];
            }
            lock (array)
            {
                return pos == array.Count && end == 1;
            }
        };
        return () =>
        {
            var myId = Interlocked.Increment(ref index);
            lock (dict) dict[myId] = 0;
            return ConstructEnumerable(() => getValue(myId), () => hasEnded(myId));
        };
    }

    static IEnumerable<T> ConstructEnumerable<T>(Func<T> getValue, Func<bool> hasEnded)
    {
        while (true)
        {
            var v = getValue();
            if (hasEnded()) yield break;
            yield return v;
        }
    }
}


* marble diagrams,大约就是时序图

* Rx throttle: delay start, avoid UI flashing

* Rx until: discard earlier events

* ISubject is usually used in a wrong way. 尽量 subscribe 到最初的 event source,因为中间插一个 stateful 的对象妨碍了 query optimize

* 其他 push model 的例子有 windows powershell, workflow foundation 和 SSIS (最后一个不知道是不是SqlServer什么的)

* LINQPad 是一个简化的 visual studio ,可以用来教学 c# 和 LINQ,支持一个 .Dump 指令,很好用。Brian 编写了很多习题,把变量名定义成 "____",这样题干就成了 AssertEqual(____, ....),很有趣。

* 昨天的习题集 保存成 .linq 格式,然后用 LINQPad 打开。需要自己修改 library 路径,namespace 等等。这方面 LINQPad 和 Fiddler script editor 类似。

* Rx return: create a singleton

* Twilio 是一个可以发短信的服务。昨天讲到这里,已经是最后的一段,themal sensor 的读数可以精确到 0.01 度,也很灵敏,然后每秒钟可以给 Eric 发一条短信什么的。

* 最后就是各种广告,Rxjs, 还有 Rxx on codeplex,据说还有 RxUI。

* 用来解析地震情报的例子也很有趣,用 dynamics 来解析 json,貌似比 serializer 好太多了。

* 记下了两个词 cep 和 ifft 但是完全忘记了意思。所有记录都是用 kindle 的 My Checklist 做的,36 条,还算是很好用。

Tags: 广告
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments