CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Greg Young [MVP]

  • Bellware Driven Design

    When I was down in Seattle last week Scott Bellware did a talk about BDD for a few people. Its not a very formal talk (which I prefer) and its a bit slow to start but there are some gems in here. My camera died after the first hour but definitely worth checking out.

     

    Enjoy!

     

    Posted Jul 19 2008, 08:19 PM by Greg with 1 comment(s)
    Filed under:
  • Alt.Net Canada

     

    canada So its actually going to happen! August 15-17 in Calgary. Registration is now open! http://www.altnetconfcanada.com/

     

    Registration is now open to the first hundred people so forget your Canada Day celebrations and sign on up!

     

     

    btw: for those from the states, yes people in Calgary live in igloos, if you have never stayed in an igloo I would highly recommend the experience.

  • DDDD Moved

    After some conversations with Scott and others I have decided that I will be writing up alot more on DDDD (I have already started). I will be releasing it under a creative commons license as opposed to going with a brick and mortar publisher. Over the next few weeks I will begin pushing stuff out to a small group for review. The completed work will be available for download on my blog. There will also be atleast 1 reference application provided.

    My reasoning for releasing under creative commons is I want to get this out to as many people as possible. I may offer one of those "get a printed copy of this" or something but am more so focused on trying to get the ideas to market quickly (my estimate with a brick and mortar publisher was almost 2 years ... I think I can do it quicker otherwise).

    I am looking for a small (<10 group of reviewers) to read through things and provide feedback as they are written over the next few months. Drop me an email offline.

    Also as I am new to this if anyone has suggestions (as an example I was going to setup JIRA for reviewer comments) please let me know, or if you are a professional editor who wants to help my atrocious grammar that would be appreciated too :-)

  • Dynamic Languages vs Static Verification

    At alt.net Seattle as some may remember I was doing a bunch of interviews for infoq.com. On of those quick videos was a talk with Rustan Leino, Mike Barnett, John Lam, and Matt Podwysocki about dynamic languages and static verification. This came from the starting fish bowl on polygot programming. I had to cut it a bit short in terms of time because John had to go but there are some interesting thoughts brought out (in particular the annealing of software over time).  Anyways ... here is the video, enjoy!

     

  • devTeach Talk

    Here is my devTeach talk ... I got a bit of a late start and had a lot of material to try to get in so I had to push away from a few good discussions but I will answer those discussions in a post here ... and be kind I only knew I was speaking 2 weeks in advance ;-)

     

    Enjoy!

     

  • EF Long Term Plans

    I was reading through what is actually a reasonable comparison of EF to other technologies on Dan Simmons' blog.

    Dave, Jeremy, and Jimmy have already discussed many issues but ...

     

    One bit caught my attention:

    Long-term we are working to build EDM awareness into a variety of other Microsoft products so that if you have an Entity Data Model, you should be able to automatically create REST-oriented web services over that model (ADO.Net Data Services aka Astoria), write reports against that model (Reporting Services), synchronize data between a server and an offline client store where the data is moved atomically as entities even if those entities draw from multiple database tables on the server, create workflows from entity-aware building blocks, etc. etc.  Not only does this increase the value of the data model by allowing it to be reused for many parts of your overall solution, but it also allows us to invest more heavily in common tools which will streamline the development process, make developer learning apply to more scenarios, etc.  So the differentiator is not that the EF supports more flexible mapping than nHibernate or something like that, it's that the EF is not just an ORM--it's the first step in a much larger vision of an entity-aware data platform.

     

    DDDD is something very similar to this but I think they have completely missed the boat. I have a single slide in my deck from devTeach that summarizes my objections quite succinctly.

     

    DDDD

     

    I have since rewritten this slide to be more generic in "A single model cannot possibly be appropriate for all facets of your application including transactional behaviors, searching, and reporting"

     

    In DDDD I deal with this by recognizing that the Entity is of limited importance and should be different in different places ... It is what happens to the entity that REALLY matters and it is the recognition and the making explicit of EVENTS in the domain that allows you to easily support multiple concurrent parallel models. These events should not be automatically generated object->field changed messages but should be DOMAIN CONCEPTS.

     

    let me say for the 1000th time. If you are reporting off your transactional model you are seeking trouble!

    On the DDD list people often ask "How do I use my domain to report" ... the answer "You don't" they are different models with different goals. It pains me that MS intends to push people into what is an anti-pattern, even for small systems.

     

     

    Jimmy Bogard was also right on the money when he mentions that I should not expose my model outside of my Bounded Context. I highly doubt a system like EF and what they suggest would work beyond trivial cases and is (as proposed) one small step up from using sprocs and linked servers as your integration model.

     

    I could say MUCH more about this but instead I will try to rework my talk a bit in Victoria Wednesday to try to include some of this.

  • Revenge of the Statically Typed Languages

     

    darth There have been some great posts recently going around about the merits of static vs dynamic languages ...

    Dynamic Languages Strike Back by Steve Yegge

    Return of the Statically Typed Languages by Cedric

     

    I have to admit that I was really waiting for the Java/C# "Attack of the Clones" reference...

     

     

    Which are then summarized and moved towards polygot programming by Ola Bini in A New Hope: Polygotism.

     

     

    Quoting Ola's summary:

    So let's see. Distilled, Steve thinks that static languages have reached the ceiling for what's possible to do, and that dynamic languages offer more flexibility and power without actually sacrificing performance and maintainability. He backs this up with several research papers that point to very interesting runtime performance improvement techniques that really can help dynamic languages perform exceptionally well.


    On the other hand Cedric believes that Scala is bad because of implicits and pattern matching, that it's common sense to not allow people to use the languages they like, that tools for dynamic languages will never be as good as the ones for static ones, that Java generics isn't really a problem, that dynamic language performance will improve but that this doesn't matter, that static languages really hasn't failed at all and that Java is still the best language of choice, and will continue to be for a long time.

     

    On a side note Cedric has a big point on the tooling side of dynamic languages; it will never be there as it can't be logically. Since so many things are dynamic at runtime I will eventually end up running into the halting problem trying to figure out what happens at runtime.

     

    I think however that this entire discussion of static vs dynamic languages is fundamentally flawed as shown later in Ola's post when he describes the debate as:

    So, we have three categories of languages here. The strongly statically checked ones, like Haskell. The weakly statically checked ones, like Java. And the dynamically checked ones, like Ruby.

    It seems to me to be rather silly to have this discussion of static vs dynamic languages without bringing in the concept of static verification of more than just types.

     

    Enter DbC

     

    E. W. Dijkstra arguably one of the most influential computer scientists of our time recognized the importance of static verification and the provability of computer programs. In "The Cruelty of Really Teaching Computer Science" he even went so far as to make a proposal for an introductory programming course for freshmen that consisted of Hoare logic.

     

    There are languages out there that do more than verify just your types. Most of them currently are in the lineage of of Betrand Meyer's Eiffel programming language and can be considered DbC (Design by Contract).

     

    Sure DbC is pretty obscure now but it is a hot area of research due to the ability to use theorem provers on the contracts of the system. These theorem provers are not looking solely at type safety in a statically verifiable way they are also looking at your code and contracts to be sure that they cannot be broken at runtime! This is not a new idea (research in this area goes back to the beginnings of DbC) but the exponential growth of processor and memory resources have made this a much more obtainable goal. There are now two fairly mainstream projects working on this now, the JML (Java Modeling Language) project and the Spec# project from MSR.

     

    Their working is best seen in an example (although this is an extremely naive example, for more in depth examples check out the samples in the spec# install)

     

    using System;
    using Microsoft.Contracts;

    public class Program
    {
      static void Main(string![]! args) {
          Console.Write("Entry? : ");
          string response = Console.ReadLine();
          Console.WriteLine(response.Substring(response.Length - 6, 6));
      }
    }

     

    This code will give 3 compile time errors.

     

    C:\crap\Project1\Project1\Program.ssc(9,22): warning CS2663: Call of string.Substring(int startIndex, int length), unsatisfied precondition: 0 <= startIndex
    C:\crap\Project1\Project1\Program.ssc(9,41): warning CS2663: Possible null dereference
    C:\crap\Project1\Project1\Program.ssc(9,41): warning CS2614: Receiver might be null (of type 'string')

     

    Note that you can treat these as errors as well (and they show up in the ide as normal errors).

     

    These errors result from two basic problems with the code. The first problem is that Console.ReadLine() may return null in which case the Substring call and the Length access would cause problems. The second problem is that the length of the string returned from the ReadLine may be less than 6 in length. By placing some defensive code we can prove to the prover that we understand and are handling those cases.

     

    using System;
    using Microsoft.Contracts;

    public class Program
    {
      static void Main(string![]! args) {
          Console.Write("Entry? : ");
          string response = Console.ReadLine();
          if(response != null && response.Length >=6) {
                Console.WriteLine(response.Substring(response.Length - 6, 6));
          }
      }
    }

     

    Which will give no errors as the spec# compiler parses the code and understands the branching enough to realize that I have now proven that those bad circumstances can no longer happen. The key thing to notice here is that even without unit tests it is finding problems in terms of verification of my code (I said my code runs within these rules and I am breaking my own rules). These tools will REVOLUTIONIZE the development industry.

     

    Note: These contracts do not get rid of things like unit testing or TDD they complement them. There is a difference between verifying (Do I play by my own rules that I set up) vs validating (does this thing do anything of value)

     

    There are many scenarios where this can benefit us but one of the main ones I see is in dealing with invariants that deal with multiple methods and/or objects (these are often very difficult to unit test). A simple example of this can be seen in List<T>, in particular there is an invariant between List<T>.Count and the number of items in a List<T>. These tools will allow you to make it so you can insure mathematically that this invariant is never broken as opposed to sprinkling around state based tests and hoping that you actually covered all of the places where the invariant is being accessed. These problems are obviously magnified when we introduce an invariant that spans multiple objects ...

     

    Another scenario where theorem proving can help us greatly is in our refactoring. The compiler will not let us break our previously distributed contract providing we don't change it. To provide the same level of support with unit tests tends to cost us many unit tests for complex contracts with many preconditions.

     

    Does DbC play well with others?

     

    Coming back to the concept of polygot programming; it is reasonably easy with dynamic and static languages in general as can be illustrated by the existence of the DLR. There is however a much larger disconnect between the world of theorem proving and dynamic languages. Dynamic languages are in their definition runtime defined and static verification is in its definition compile-time defined, the use of a dynamic language makes the concept of statically verifying your code at compile time impossible. To try to verify dynamic code at compile time would likely walk you straight into the halting problem just like it would for many kinds of tooling.

     

    I took some time at alt.net seattle to pull aside Mike Barnett and Rustan Leino from the spec# team and John Lam from the IronRuby team to talk for a few minutes on video about how we can effectively use these ideas together. Many interesting ideas came out of this discussion in particular the recognizing of the merits of dynamic languages for change and the possibility of starting in dynamic languages and annealing software into compile time proven languages. I have submitted this video and am hoping it will be coming out soon!

  • DDDD 12 [How long?]

    One of the most difficult parts of becoming eventually consistent is getting people out of the mind set that everything is always consistent. Years ago before they introduced their system that used to be legacy that everyone now can after over a decade finally laugh about; they probably ran with paper (or maybe they ran with scissors who knows). Paper was awesome because it never gave the impression of global consistency and it is the thinking that went into the optimization of paper processes that can help us optimize our transactional systems.

    Then again getting to that point can be tough so we will focus more on that in the next post ... For now we will look at getting through the barrier of assumed global consistency.

     

    SME: So yeah this <data, let's call it a purchase order> is edited by the user and can be searched by others or viewed in our reports.

    Me: OK, how long of a period is generally acceptable between the time that they enter the data and the time others can see it, is it different for reports vs searches?

    SME: It should be available for all of those things immediately.

    Me: The "purchase orders" sound pretty important, what happens when part of the system goes down? How long of being unavailable would be considered a catastrophic failure?

    SME: Well in our current system when things are down everything is down so I can't say that we have dealt with that but 30 minutes of the current system being down and not being able to enter purchase orders would cost our company $237,123 in lost productivity and possibly lost orders (of course they have spent the time of analysts to calculate this exact number but they have never really tried fixing the problem before). This is why we are rewriting the system.

    Me: Entering purchase orders sounds like it is the life blood of your business; is that correct?

    SME: Of course without purchase orders we have no business!

     

    What has happened here is that we have turned the conversation from everything always being consistent to discussions about the needs of various parts of the system in terms of risk management. Talking about what should happen when things go wrong in the system is a very effective way of turning the discussion away from global consistency as global consistency generally means global failures.

     

    Me: What if you could still enter new purchase orders but you couldn't run your daily sales report? How would that impact your business?

    SME: Well our managers might have to revert to the former manual process of taking all the printed copies of the "Purchase Orders" and adding them up in a spreadsheet. We could probably even deal with this for a few days but not more and it couldn't happen often.

    Me: How timely does the data need to be on the report? If the data is two minutes old but was correct as of two minutes ago how would that affect your business.

    SME (laughing): Awww hell, not at all those lazy managers generally print the document and stop at the water cooler for at least 10 minutes before they get the printed document.

     

    So we have very different architectural requirements for two parts of the system. This is one way of putting things into Bounded Contexts by identifying architectural requirements upon the data. We have realized here that the thing that gets the data for the Daily Summary report should not be in the same Bounded Context that manages purchases orders because they have drastically different requirements. We could have also come to a similar conclusion by using CQS (command/query separation). Generally speaking you will find not one but many reasons to put data into a different Bounded Context or Parallel Model when you only find one reason to do so you should question whether or not it should actually be segregated.

     

    Me: What about the searching for customers to add to Purchase Orders i.e. to lookup Discount information, what if only that one part failed.

    SME: We would still need to be able to look up information like that in order to function.

    Me: Ok, let's talk a bit about how that information gets entered and changed in the process. As an example, I am a new client what happens.

    SME: Well your company would make arrangements between sales and account receivable. We would establish a credit line for you and setup any agreed upon discounts.

    Me: Ok does this generally happen in a few minutes? What is generally the time from accounts receivable getting the person setup with a credit line?

    SME: Well that can vary, usually a while but sometimes right away.

    Me: Right away in a human sense or a computer sense?

    SME: Right away in the sense that after they get setup they may be transferred back to sales to make a purchase.

     

    Where is this going? What sorts of things are we learning about the domain and how things interact?

     

    The introduction of talking about how long things should take in terms of SLAs between contexts/models provides us with a lot of detailed information about the domain even if we do not intend to use it to provide SLAs within our system. As such we as DDD practitioners should be introducing this type of discussion regardless of whether or not we intend to move towards messaging.

  • devTeach: Strategic Domain Driven Design

    Here is Dave Laribee's session on Strategic Domain Driven Design from devTeach.

     

     

     

    I have always admired the simplicity and art of Dave's slides, this time I particularly enjoyed the Mr. Roger's slide!

     

    Of course Dave provides some awesome technical content as well good artistic taste; enjoy!

  • devTeach after thoughts

    Just got home from the airport; what a trip. I flew out Tuesday night on a red eye arriving at about 6:30 am in Toronto (On my way out I listened to the new altdotnet podcast this is great stuff!). I spent all of Wednesday in a barely-able-to-walk-because-I-was-so-tired state popping in and out of various sessions and hanging out with many of the great people at the conference.

    Today I checked out a few sessions including Owen's continuous integration and Dave Laribee's Strategic Domain Driven Design (I took videos of my session and Dave's session and will be placing them up here in the next few days). I really wanted to see two of Oren's talks (DSLs and advanced DI but was unable to make either). I also wanted to see JP's DDD session but it was unfortunately scheduled at the same time as my talk so I was unable to make it. 

    On a side note I would really love it if at one of these conferences we could do a bunch of sessions like this one after another (or a pre/post con tutorial) to jump start people who are not familiar with the subject (drop me a line if something like a pre/post con tutorial would interest you as I am curious on the level of interest). As an example at devTeach we could have come close to this with some small schedule changes as the sessions could almost be seen in a progression of JP->Dave->Me with each session adding to the knowledge learned in the session before. If we were to add in another 2-3 sessions there could be a huge amount of effective knowledge transfer. Maybe I will look at following up on this idea for devTeach Montreal but there are actually 2 of these tracks coming up!

    Unfortunately the two tracks are both in the same week in November :( One being Oredev in Sweden and the other being QCon SF. To be honest I don't know how Eric does it, it sounds insane to me to be presenting in Sweden and in SF within 2 days... You may notice that there is also an alt.net track listed for QCon ... cool stuff! QCon is the best/highest level conference I have ever been to, its will be great to have a good showing from the .NET community.

    As always, the discussions outside of the sessions were great. When you get so many smart people in one place good things are bound to happen!

    JR and crew did an great job (as always) with the conference. Setup was good, especially the ability to find power for my laptop. I heard there were problems with the wireless early in the conference but my experience with it was great.

    Posted May 15 2008, 08:49 PM by Greg with 4 comment(s)
    Filed under:
  • DDDD 11 [Basic Consistency]

    So I was bad last week and didn't get much written shame on me... hopefully I can get back on track. In DDDD 10 we looked at Command Query Seperation, now we are going to take that idea a little bit further as we really need to break it down a bit more than commands and queries.

     

    Let's say that I have a domain with a Customer Aggregate Root. When I want to update this Customer I need to issue a query to get its current state so I can validate whether my current changes would make the object en up in an invalid state. Generally for these types of reads one would want consistent data. Why bother with all of my nice validation if it can be bypassed by inconsistency? One of the key concepts in domain driven design is that I know that certain things about my objects are true.

     

    In that same domain I may also be able to search for customers with a first name of "Greg". In this type of situation it is no longer a technical requirement (may still be a business requirement) that my search is completely consistent (for future reference I call any read such as this a "Report" even though they may not meet your personal criteria of a report).

     

    If my search does not need to be completely consistent I can do many very neat things with my data such as having it come from a different model than my transactional model (i.e. query a reporting database). I can also do other things like cache the data with expirations. These types of operations can allow me to become much more scalable and they are a key concept we will be later exploiting in moving towards distributing our systems.

     

     

    Because of how important our gains are; let's make some rules.

     

    Aggregate roots provide the boundary for where data is always consistent. Anytime you deal with data that belongs to an aggregate from outside of an aggregate you should make your new default to assume it to be eventually consistent.

     

    Bounded Contexts are always considered to be eventually consistent. If you have Bounded Contexts where this is not true there is probably something wrong with your model.

     

     

    When I say you should make it your new default; I mean that:

    Unless it is explicitly stated otherwise and a business reason is provided with the story; it will be eventually consistent.

     

     

     

     

    One problem that you will run into with this transition is managing expectations. Domain Experts like most non-technical (and most technical for that matter) people have been trained to think that everything should be instantaneous with computers ("You mean when I click save and it says it saved it takes 45 seconds to show up in the search?"). They have sucked from the evil tit of the RDBMS and its global consistency for far too long. The next post will be about getting over this hurdle.

  • I Want Spec#

                                                   spec#

    Scott Hanselman has recently put up a new hanselminutes of an interview with the spec# team. This interview was done at altdotnet; one of the key points of discussion both in general and in the interview was "how can we get spec#?". The simple answer is we have to want spec# and Microsoft needs to know that we want it. The more people who want it the more likely we are to get it or to get it in pieces. The best way for them to know is for us to tell them!

     

    Let's give Mike and the whole spec# team the best compliment possible on their research; asking for it to become integrated in products and/or to be available with a commercial license!

    I want verifiable software...

    I WANT SPEC#!

     

     

     

    Here is a reusable bumper sticker for your blog to make it easier to express how you feel.

     

    spec 

     

    Drop a note here so I can try to keep track of people!

     

    If you don't know about spec# now may be a great time to watch the recent presentation from altdotnet

  • Knuth: Wow

    Donald Knuth is a mainstay of computer science from the last what 30 years? He recently did an interview with InformIT talking about some more modern concepts.. Here are some quotes I found quite interesting!

     

    On the multi-core problem

    Donald: I don’t want to duck your question entirely. I might as well flame a bit about my personal unhappiness with the current trend toward multicore architecture. To me, it looks more or less like the hardware designers have run out of ideas, and that they’re trying to pass the blame for the future demise of Moore’s Law to the software writers by giving us machines that work faster only on a few key benchmarks! I won’t be surprised at all if the whole multithreading idea turns out to be a flop, worse than the "Titanium" approach that was supposed to be so terrific—until it turned out that the wished-for compilers were basically impossible to write.

    later ...

    They think a magic bullet will come along to make multicores speed up my kind of work; I think it’s a pipe dream. (No—that’s the wrong metaphor! "Pipelines" actually work for me, but threads don’t. Maybe the word I want is "bubble.")

     

    I agree; pipelines rock!

     

    On unit testing and mocking

    As to your real question, the idea of immediate compilation and "unit tests" appeals to me only rarely, when I’m feeling my way in a totally unknown environment and need feedback about what works and what doesn’t. Otherwise, lots of time is wasted on activities that I simply never need to perform or even think about. Nothing needs to be "mocked up."

     

    On extreme programming

    Still, I hate to duck your questions even though I also hate to offend other people’s sensibilities—given that software methodology has always been akin to religion. With the caveat that there’s no reason anybody should care about the opinions of a computer scientist/mathematician like me regarding software development, let me just say that almost everything I’ve ever heard associated with the term "extreme programming" sounds like exactly the wrong way to go...with one exception. The exception is the idea of working in teams and reading each other’s code. That idea is crucial, and it might even mask out all the terrible aspects of extreme programming that alarm me.

     

    On reusable code

    I also must confess to a strong bias against the fashion for reusable code. To me, "re-editable code" is much, much better than an untouchable black box or toolkit. I could go on and on about this. If you’re totally convinced that reusable code is wonderful, I probably won’t be able to sway you anyway, but you’ll never convince me that reusable code isn’t mostly a menace.

     

    At the least these words should be stopped and thought of.

  • DDDD 10 [CQS]

     

    Boring Sunday night so I figured I would get ahead on my posts for the week (I have not been good enough about hitting 5 but I am trying). This post is probably out of order but the concepts are simple, very important, and I will want to link to this later. Also this post and concept is valuable whether or not you are intending to use messaging.

     

    At altdotnet one thing I talked a bunch about that most people had not really dealt with before was Command Query Separation( Martin Fowler also has a good post about it as well ). This is still a running theme in these posts; what I am talking about is rarely if ever new.

     

    I know its a really big surprise that Greg is into things that are based in DbC ... but later in our systems we will care *a lot* about what is mutating the state of the system and the consistency that is required for various actions.

     

    Basically all things that change mutable state are commands and anything that only reads data is a query. Personally I like to add some further distinctions to this like "Only reads immutable state" vs "Reads mutable state" as with the latter I need to worry about the consistency of those reads but command and query are the roots.

     

    To help think about Commands and Queries let's look at them in terms of SQL as it has good separation (usually)

     

    Command = Insert, Update, Delete
    Query = Select (yeah surprisingly a query is a query :))

     

    Not surprisingly commands and queries have quite different interactions in a SQL database (in fact most of what your transaction isolation levels (Read Commited, etc) talk about is how commands and queries interact with each other). This concept has largely been lost from our code and thought (largely because we rely on databases too much) though some have pushed greatly for this separation. Most systems allow too many things to become commands and queries at once leading to difficult to understand code... Patrick: this is a key metric ;-)

     

    This may seem quite weird to many people at first but one key point on commands vs queries is that commands should not return a value. Only a query is allowed to return a value though a command can technically change state that is passed into it so ...

     

    public void Foo(something s) {
        //modifies state 
        s.somevalue = "greg";
    }

     

    is ok but ..

     

    public string Foo() {
         //modifies state
         return "greg";
    }

     

    is not!! this is a funny distinction eh?

     

    In general I would prefer you in your code to follow an even TIGHTER distinction and assume that things passed into you are *also* immutable (The reason for this is that handling byref data in anything that crosses serialization boundaries is troublesome, but there are some cases where this can be ok (like setting something in a context)). It may feel really weird and unnatural at first but eventually it will become second nature; I promise. The only thing you are allowed to do is mutate state in some way (or add to an observable state hint hint).

     

    We will get more into this later but as a critical thought what does this do to the concept of request/response? Maybe tomorrow?

     

     

    Side Effect Free Functions and CQS

    In Domain Driven Design, Eric Evans pushes Side Effect Free functions which are great and should be in your tool bag. What side effect free functions essentially do is change a command into a query. Instead of changing mutable state they create immutable state that is only visible to the caller. Since it is only visible to the caller it can be seen as a query as it is understood to be in a transient state and not visible to other queries.

  • Altdotnet Spec# Session

    Here is another video in the videos from altdotnet. We had Rustan and Mike of the spec# come out from their cave (j/k) at MSR to talk about spec#, boogie, and the future of compile time proving!

     

     

    Enjoy it and as always feel free to leave feedback! 

     

     the video is not the best quality but hey ... it was taken on a phone!

More Posts Next page »