Skip to content

Instantly share code, notes, and snippets.

@sleemer
Last active November 3, 2016 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sleemer/5f43e70e8bb1fc35c3891a9d71462a7b to your computer and use it in GitHub Desktop.
Save sleemer/5f43e70e8bb1fc35c3891a9d71462a7b to your computer and use it in GitHub Desktop.
Notes for my presentation on WroclawDotNetMeetup#3 (03.11.2016)

Missing parts of the .Net Developer Days

This presintation is based on the true stories

Part I - The Art of Pain

I wonder what I could do with this that would make the Mads Torgersen wince?

Jon Skeet

The pain points could be found here

Disclaimer from author:

It's not about production C# code. You have never, ever use the code from this repo in production! All this code is just about having fun! No more, no less.

The most interesting paint points:

  • Saving state of AsyncStateMachine It allows us to preserve local variables and continue execution from the point where we left the execution. To understand this sample you should understand how compiler treats async/await under the hood. Basicly, it turns your async code into the state machine that is just a structure with fields storing the local variables of the async method and utils methods to go to the next state.
  • Reducing the noise of the Linq operators BasicDemo.cs one example...
    var funky = new[] { "hello", "world", "how", "are", "you" };
    var query = funky.Evil() - "world" + "today" 
                & (x => x.Length == 5)
                | (x => x.ToUpper());
    Console.WriteLine(query * 3);
    ...and another example...
    var xor1 = new[] { "foo", "bar", "baz" }.Evil();
    var xor2 = new[] { "qux", "bar" }.Evil();
    Console.WriteLine(xor1 ^ xor2);
    ...and one more...
    var employees = new[]
    {
      new { Name = "Dave", Department = "Accounting" },
      new { Name = "Bill", Department = "Sales" },
      new { Name = "Holly", Department = "Finance" },
      new { Name = "Fred", Department = "HR" },
      new { Name = "Diane", Department = "Engineering" },
      new { Name = "Betty", Department = "Sales" },
      new { Name = "Edward", Department = "Finance" },
      new { Name = "Tom", Department = "Engineering" }
    }.Evil();
    
    Console.WriteLine("Division by a function...");
    dynamic byDepartment = employees / (x => x.Department);
    foreach (IGrouping<dynamic, dynamic> result in byDepartment)
    {
      Console.WriteLine("{0}: {1}", result.Key, string.Join(", ", result.Select(x => x.Name)));
    }
    ... and what the heck is going on here ?!
      // Copyright 2013 Jon Skeet. All rights reserved. Use of this source code is governed by the Apache License 2.0, as found in the LICENSE.txt file.
      using System;
    
      namespace WhatTheHeck
      {
          class Program
          {
              static void Main(string[] args)
              {
                  var limit = 10;
                  limit = "five";
                  for (var x = 0; x < limit; x++)
                  {
                      Console.WriteLine(x);
                      Console.WriteLine("The current value of x is: {0}", x);
                  }
              }
          }
      }
    ... and so on and so on...

It's just insane to watch what this guy is doing with the language and if you are interesting in these kind of things and want even more pain I would definately recomend to watch this video or that video.

Part II - Rebirth

Essentially everyone, when they first build an enterprise application, makes the following 10 assumptions. All turn out to be false in the long run and all cause big trouble and painful learning experiences.

  1. The network is reliable
  2. Latency is zero
  3. Bandwidth is infinite
  4. The network is secure
  5. Topology doesn't change
  6. There is one administrator
  7. Transport cost is zero
  8. The network is homogeneous
  9. The system is monolithic
  10. The system is finished

Ted Neward

When you are done with all that pain and you don't want mess it all up anymore and you just want to feel the ground... here it is, the Solution from Ted Neward!

  1. Be cynical
    • Question the assumptions
    • Look for hidden costs
    • Investigate the implementations
    • The presenter should also be able to tell you where it should NOT be used
  2. Forget and forgive the best practices (they just don't exist) - embrace "paterns and practices" instead. Because the term "best practices" means somthing that you can allways rely on, without thinking. While the term "patterns" always mean thinking about the context where it is apropriate to use.
  3. Resist the temptation of the familiar
    • Every project is different
    • Reject the "goal of reuse" (yagni) until you have written the same system the third time
    • This is the most prominent cause of failure for projects
  4. Create an evaluation function of your own for each technology/pattern/practice introduced into your awareness
    • Context matters

The great source of inspiration and a good source of food for your brain is the tech blogs of Netflix team. And the one I would recomend in the context of rethinking enterprise.

Part III - Immortality

Links

So why do we want immutability?

  • Thread safety
  • Efficiency (potentially) - no defensive copying
  • Easier to reason about code

Kinds of immutability

  • Mutable

    public sealed class Mutable
    {
        public int Value { get; set; }
    }
  • ShallowImmutable

    public sealed class ShallowImmutable
    {
        public int Value { get; }
        public Mutable Value2 { get; }
    }
  • Popsicle

    public sealed class Popsicle
    {
        public bool Frozen { get; private set; }
    
        private int value;
        public int Value
        {
            get { return value; }
            set
            {
                if (Frozen)
                {
                    throw new InvalidOperationException("Couldn't keep it in, heaven knows I tried!");
                }
                this.value = value;
            }
        }
    
        public void Freeze()
        {
            Frozen = true;
        }
    }
  • Observable Immutable

    public sealed class ObservablyImmutable
    {
        private int cachedHash;
    
        public string Name { get; }
    
        public ObservablyImmutable(string name)
        {
            this.Name = Name;
        }
    
        public override bool Equals(object obj)
        {
            var other = obj as ObservablyImmutable;
            if (other == null)
            {
                return false;
            }
            return other.Name == Name;
        }
    
        public override int GetHashCode()
        {
            if (cachedHash == 0)
            {
                cachedHash = Name.GetHashCode();
            }
            return cachedHash;
        }
    }
  • Really obvious Immutable

    public sealed class ReallyObviouslyImmutable
    {
        public string Name { get; }
    
        public int Value { get; }
    
        public ReallyObviouslyImmutable(string name, int value)
        {
            this.Name = name;
            this.Value = value;
        }
    }

How has C# evolved over time, in terms of immutability?

C# 1

  • Value types (yay!)
  • Immutable string type (yay!) and StringBuilder (yay!)
  • Unsealed by default (boo!)
  • Property get/set with single access (boo!)

C# 2

  • public string Name { get; private set; }

C# 3

  • Anonymous types (compare and contrast with VB)
  • LINQ (encourage no-side-effects thinking)
  • Object and collection initializers (hmm...)

C# 4

  • Optional parameters and named arguments (yes, but...)

C# 5

  • tumbleweed

C# 6 (cheers!)

  • Read-only autoprops (finally!)
  • Default values for autoprops
  • Expression-bodied members encourage feeling of immutability

What immutability means personaly for me and where I see it can be usefull...

... being immortal

// Arrange
var you = HeroBuilder.Create()
                     .WithName('Hero')
                     .WithHealth(100)
                     .Build();
var monsterCastle = new MonsterCastel();
// Act
monsterCastel.Visit(you);
// Assert
Assert.AreEqual(100, you.Health);   // that's good :)
Assert.IsTrue(you.HasEmptyPockets); // ... and that's not that good ;(

... and get all things done!

// Arrange
var you = HeroBuilder.Create()
                     .WithName('Hero')
                     .WithHealth(100)
                     .Build();
var monsterCastle = new MonsterCastel();
// Act
var maybeDeadClone = monsterCastel.Visit(you);
you = HeroBuilder.Clone(you)
                 .WithItemsInThePocket(maybeDeadClone.Pockets);
// Assert
Assert.AreEqual(100, you.Health);   // that's good :)
Assert.IsTrue(you.HasSomethingInThePockets); // ... and that's cool!

...but to be able to do that you have to write code similar to ones below...

    public sealed class Hero
    {
        public string Name { get; }
        public int Health { get; }
        public ImmutableList<string> Pockets { get; }

        public bool HasSomethingInThePockets { get { return !Pockets.IsEmpty; } }

        private Hero(HeroBuilder builder)
        {
            Name = builder.Name;
            Health = builder.Health;
            Pockets = ImmutableList<string>.Empty.AddRange(builder.Pockets);
        }

        public sealed class HeroBuilder
        {
            public string Name { get; set; }
            public int Health { get; set; }
            public List<string> Pockets { get; }

            public HeroBuilder WithName(string name)
            {
                Name = name;
                return this;
            }
            public HeroBuilder WithHealth(int health)
            {
                Health = health;
                return this;
            }
            public HeroBuilder WithItemsInThePocket(IEnumerable<string> items)
            {
                foreach (var item in items)
                {
                    Pockets.Add(item);
                };
                return this;
            }
            
            public static HeroBuilder Create()
            {
                return new HeroBuilder();
            }
            public Hero Build()
            {
                return new Hero(this);
            }
            public Hero Clone(Hero original)
            {
                return Create()
                     .WithName(original.Name)
                     .WithHealth(original.Health)
                     .WithItemsInThePocket(original.Pockets)
                     .Build();;
            }
        }
    }

Conclusions

From my perspective conferences are usefull for two things

  1. To know something new exists. That would be a starting point to dig it down lately.
  2. To summorise your knowledge about sometning that you have alredy known, but maybe it wasn't so clear to you. And now you just "get it".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment