RSS 2.0

Personal Info:

Joe Send mail to the author(s) leads the architecture of an experimental OS's developer platform, where he is also chief architect of its programming language. His current mission is to enable writing large-scale software that is reliable, secure, and scalable by-construction. Before this, Joe founded the Parallel Extensions to .NET project. He has been granted 19 patents, with 49 pending. When not working, Joe enjoys travelling with his wife, writing books, writing music, studying music theory & mathematics, and doing anything involving food & wine.

My books

My music

Disclaimer:
The content of this site are my own personal opinions and do not represent my employer's view in anyway.

© 2012, Joe Duffy

 
 Friday, June 04, 2004

...comes in many forms.

(defun fib (n)
  (if (< n 2)
    1
    (+ (fib (- n 1)) (fib (- n 2)))))
   

6/4/2004 6:20:34 PM (Pacific Daylight Time, UTC-07:00)  #   

Doug Purdy posted an amusing response (and here) to the whole "DataSets are evil" argument.

To be clear, my aversion to DataSets has nothing to do with their use in web services, but rather as an overall architectural principle. As he points out (and Dare reiterates), once it escapes your application we're simply talking about schema and XML data. (Note: it's interesting to question what "it" represents in the previous sentence; it sure as hell isn't an instance of a DataSet once it reaches the wire!) The programming model is an implementation detail, and is certainly hidden behind an interface.

So if application edges are rigid and abstracted by an interface which represents data as XML, who cares in what fashion such XML is constructed? Once could - if so inclined - represent objects internally in a picture perfect domain model, yet serialize them over the wire in a horrid alphabet soup of nonsensical tags; and, conversely a DataSet could manifest on the wire as a beautiful schema-driven thing of wonder.

So, again... who really cares?

Well, I do. My comments were made focused on proper separation of concerns within application boundaries (e.g. between tiers) and through the prism of proper domain modeling. So while advertising this as a web services-specific problem is a miscategorization, I still firmly believe it's a problem.

But then again, it's all about value delivered to the end consumer. My beliefs and experience are simply that careful domain modeling more often than not results in better value and agility in the end product. And thus, I stick to my story.

6/4/2004 2:30:48 PM (Pacific Daylight Time, UTC-07:00)  #   

 Thursday, June 03, 2004

"Human beings have been reduced to consumers."

"Americans are just now waking up to the real world [of Globalization]."

"Globalization has to be a two way traffic."

The Discovery channel is currently airing a special entitled "Thomas L. Fieldman Reporting: The Other Side of Outsourcing." Its content is mainly concerned with the impacts of outsourcing on India's traditionally family- and ritual-centric culture. I still need to digest some of the information, but it's definitely an eye-opening viewpoint.

6/3/2004 7:45:03 PM (Pacific Daylight Time, UTC-07:00)  #   

I usually don't post simply for “Mindless Link Propagation” - as Dare calls it - but this post is of particular importance.

Josh Ledgard, Chief Community Evangelist at Microsoft, talks about the legal implications and challenges (via Scoble) that arise when early community involvement is solicited in the product lifecycle. It sucks big time when such legal barriers have the potential to force one to sidestep in the wrong direction... but consider the consequences. Yikes.

(BTW, I find Scoble's response pretty ignorant and childish, and akin to a teenage fit of rebellion. Dude, there's a reason legal departments restrict certain things... because there are implications should these safeguards not be put into place. Microsoft owns its IP, and as such can tell anybody - yes, even Scoble - what they are or are not able to do with it. Regardless of on whose time it occurs.)

6/3/2004 4:06:39 PM (Pacific Daylight Time, UTC-07:00)  #   

 Wednesday, June 02, 2004

There has been a good deal of buzz over the last couple days about DataSets and their use for representing data across boundaries.

See here, here, and here.

I particularly like Scott's analogy that domain object is to DataSet what Apple is to a Bowl of Apple Descriptions.

I have what may be considered an old school, minimalist view on this matter. In fact, it is very similar to the movement in the Java community towards POJOs and away from heavyweight containers and intrusive abstractions, both of which comprimise one's domain modeling ability and freedom. DataSets, DataReaders, DataWhatever instances should seldom cross tier boundaries, especially never across application boundaries, and certainly should never allowed to leak into the business tier. (There are some exceptions to this guideline, for example within data-oriented applications where a domain model either does not exist or whose sole purpose is to facilitate interactions with the data tier (e.g. ad-hoc reporting applications).) These are simply mechanisms to represent the results of data store operation, belong in the data tier and only in the data tier, and should never see the light of day outside their little tikki hut.

I am a big fan of managing interactions between the domain and data tier through Set-like patterns. A Set is modifiable, maintains identity, allows finding items which match a particular criteria, and is an easy abstraction to work with. The Set translates business-sensical operations into concrete commands to the data tier, and is then responsible for constructing domain objects and mapping data resulting from database operations. Life is simple, and the business tier and its consumers are entirely ignorant of data concepts which are of no interest. Unfortunately, the Set I describe differs fundamentally from the DataSet, namely in that the DataSet attempts to represent the domain model in addition to the data interface. While the DataSet's query and database interface mechanisms may be useful for integrating with a data store, this is an implementation detail and should be hidden as such. If the DataSet query syntax is appropriate for the business tier, for example, simply supply a query to our Set which will relay it to an internal DataSet in the data tier to perform the operation. The mapping still takes place, and the result is either a single object graph or a collection of object graphs, each of which is a strongly typed domain entity.

I understand that today in ASP.NET and WinForms DataSets make binding situations much easier, but the decision to go in one direction versus the other should be a conscious tradeoff. With the new ObjectDataSource functionality in 2.0, proper domain modeling and easy data binding are no longer exclusive choices.

6/2/2004 6:36:42 PM (Pacific Daylight Time, UTC-07:00)  #   

ABC DEF

Anything significant about this sequence?

Yup. The seating pattern on the 737 I am currently flying on. In seat F.

Just a moment ago, man in seat D says to woman in seat E, "Huh, huh... if it smells in a minute, it's because I farted."

Loudly. He had headphones on, and some people's ears don't take to altitudes of 35,000 feet very well, so he may not have realized it. But that's no excuse. I heard it loud and clear. But even worse...

Moments later, man in seat D's ass particles entered my nostrils. Splendid.

6/2/2004 6:22:49 PM (Pacific Daylight Time, UTC-07:00)  #   

Krzysztof reminded me yesterday that

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.

(For some reason, I can't locate the ECMA BCL standard to find what it says about this situation, and unfortunately don't have my SLAR book with me. The previous excerpt was taken from the MSDN documentation of the IEnumerator interface.)

Given my earlier use of iterators to incrementally execute and return results from an algorithm, I wonder what impact this requirement has? Does it have an impact? I guess my confusion comes from not understanding if this is simply a documented optional behavior, or if it is a semantic constraint by the ECMA specification. The C# compiler is responsible for baking up such IEnumerator implementations from a given iterator, which has the indirect effect of requiring that people implementing iterators toss an InvalidOperationException from their iterator methods under certain circumstances. I'm not sure if this is very evident.

If the sequence to be calculated changes sometime after the IEnumerator creation, does this trigger an exception? How would we possibly recognize this situation? If the algorithm relies on input variables, all of which are locked down at the construction of our IEnumerable, this may be good enough; but, what if the nature of the algorithm is such that it relies on realtime input or needs to access input which cannot be copied or locked at creation? For example, one could imagine an iterator which uses sensor data that is read as quickly as the program can consume; a foreach loop is used to consume the data, while an iterator provides a reading when it is asked for the next value.

Unfortunately, I guess I have more answers than questions right now. Comments, answers, etc. would be great!

6/2/2004 6:41:05 AM (Pacific Daylight Time, UTC-07:00)  #   

Exhausting day yesterday. 80%, brain faltered in some key areas. Didn't step back enough. Sit back and wait.

Had some more curry last night, this time from Chutney's in downtown Belevue (via Don Box yet again). The food was awesome, albeit a little toned down (”Americanized”). I think my body is wondering what the hell I'm doing to it - extra spicy korma yesterday night (as hot as they could make it 7/7, a mistake in hindsight) and vindaloo last night (this time I went a little milder 4/5).

6/2/2004 5:51:22 AM (Pacific Daylight Time, UTC-07:00)  #   

 Monday, May 31, 2004

I'm in Redmond for a couple days (staying in Belevue actually). I've never been before, and have a couple of observations after one half day.

  • Hotel staff, Starbucks baristas, and random strangers engaged in conversation with me. People I've never met previously. Courtesy and friendliness? Does it really still exist?
  • In general, people seem to have a little less stick stuck up their bums in comparison to back home (MA).
  • Plenty of Indian restaurants. Lost in the yellow pages, I turned to an expert for some help. My take-out chicken korma, vegetable samosa, paneer naan, and gulab jamun from Kanishka were awesome. Unfortunately, I can't keep the leftovers as I don't have a fridge in my room.
  • Lots of trees, even more than New England.
  • It's almost 9pm, and it's still light out! (???)
5/31/2004 8:44:49 PM (Pacific Daylight Time, UTC-07:00)  #   

C# 2.0 comes packed with enough new syntactic sugar to keep your average developer on a high for a couple weeks. For those who wish to gain a good understanding of each of the newly added features, I highly recommend reading this. There’s no substitute for a well written technology specification.

I was playing with some combinations of these new constructs today on a flight, and the power really became apparent when I realized I was one step closer to Ruby-like concepts, yet still living in a relatively type-safe world.

The particular constructs I speak of are Generics, Anonymous Methods, and Iterators. For a great overview of each, refer to the document I mentioned above.

Taken from the Programming Ruby: The Pragmatic Programmer’s Guide, consider the following Ruby code to calculate a Fibonacci series:

def fibUpTo(max)
  i1, i2 = 1, 1        # parallel assignment
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end

fibUpTo(1000) { |f| print f, " " }

To accomplish something along these lines in C# 1.0, one would have to either insert the closure action (print f, " " in this case) right in the fibUpTo method:

void fibUpTo(int max)
{
  int i1 = 1;
  int i2 = 1;

  while (i1 < max)
  {
    Console.Out.WriteLine(“{0} “, i1);
    int t = i1;
    i1 = i2;
    i2 = t + i2;
  }

}

// ...
fibUpTo(1000);
// ...

Or, one could pass a delegate and create a method to execute this action.

void fibUpTo(int max, fibAction f)
{
  int i1 = 1;
  int i2 = 1;

  while (i1 < max)
  {
    f(i1);
    int t = i1;
    i1 = i2;
    i2 = t + i2;
  }

}

delegate void fibAction(int n);

void myFibAction(int n)
{
  Console.Out.WriteLine(“{0} “, n);
}

// ...
fibUpTo(1000, new fibAction(this.myFibAction));
// ...

The first approach has its obvious drawbacks of not allowing easy replacement of the iteration action without modifying the algorithm itself, while the second unnecessarily adds a callable unit of code where we might only want to use it for this particular case. With C# 2.0's anonymous methods, however, I can get even closer to the Ruby syntax:

void fibUpTo(int max, fibAction f)
{
  int i1 = 1;
  int i2 = 1;

  while (i1 < max)
  {
    f(i1);
    int t = i1;
    i1 = i2;
    i2 = t + i2;
  }

}

delegate void fibAction(int n);

// ...
fibUpTo(1000, delegate(int n) {
  Console.Out.WriteLine(“{0} “, n);
});
// ...

I like this quite a bit. Everything is where I would expect it to be. The algorithm is nice and clean, and the action to be executed is right inline where it’s being used. I could also use an iterator approach, reducing my lines of code, as follows:

IEnumerable fibUpTo(int max)
{
  int i1 = 1;
  int i2 = 1;

  while (i1 < max)
  {
    yield return i1;
    int t = i1;
    i1 = i2;
    i2 = t + i2;
  }

}

// ...
foreach (int n in fibUpTo(1000))
  Console.Out.WriteLine(“{0} “, n);
// ...

I like this quite a bit more. No delegates to worry about. Nice and clean. It's also pretty neat when you consider that this is in effect an incremental calculation of the algorithm.

In addition to the above, I find the following example particularly intriguing. Consider the following Ruby code, which dynamically selects items from a collection based on a conditional:

[ 1, 3, 5, 7, 9 ].find_all { |v| v*v > 30 }.each { |v| puts v }

With the following C# 2.0 hackery, such prose because almost possible. First, we define a wrapper around a standard IEnumerable<> object:

delegate bool FindCallback<T>(T current);

class Finder<T>
{

  public Finder(IEnumerable<T> e)
  {
    this.e = e;
  }

  IEnumerable<T> e;

  public IEnumerable<T> Find(FindCallback<T> callback)
  {
    foreach (T t in e)
      if (callback(t))
        yield return t;

  }

}

Now, we can do similar things to the above Ruby code. Wallah…

foreach (int v in new Finder(new int[] { 1, 3, 5, 7, 9 }).Find(delegate(int x) { return x*x > 30; }))
  Console.Out.WriteLine(v);

But we can of course do better. Forget the iterator altogether, and simply provide two anonymous methods: one for the selection criteria, the other to be executed upon a match.

The wrapper changes to:

delegate bool FindCallback<T>(T current);
delegate void ExecuteCallback<T>(T current);

class Finder<T>
{

  public Finder(IEnumerable<T> e)
  {
    this.e = e;
  }

  IEnumerable<T> e;

  public void Find(FindCallback<T> callback, ExecuteCallback<T> exec)
  {
    foreach (T t in e)
      if (callback(t))
        exec(t);
  }

}

And thus we have:

new Finder(Array.AsReadOnly(new int[] { 1, 3, 5, 7, 9 })).Find(delegate(int v) { return v*v > 30; }, delegate(int v) { Console.Out.WriteLine(v); });

This becomes a bit more legible when formatted more appropriately:

int[] numbers = new int[] { 1, 3, 5, 7, 9 };
Finder f = new Finder(Array.AsReadOnly(numbers));
f.Find(delegate(int v) { return v*v > 30; },
    delegate(int v) { Console.Out.WriteLine(v); });

While this is starting to look a lot like passing around function pointers in C/C++, a number of more expressive and powerful iteration techniques become possible with the new syntax additions to C# 2.0. I’m looking forward to unleashing such cryptic script-isms into the wild. ;)

Very cool.

[Note: After writing all of this, I took a closer look at the System.Collections.Generic API. Doh! Most of this is already in there. Look specifically at the Array class, which has a number of delegate-driven predicate methods. Oh well!]

5/31/2004 5:51:00 PM (Pacific Daylight Time, UTC-07:00)  #   

 

Recent Entries:

Search:

Browse by Date:
<June 2004>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Browse by Category:

Notables: