Interfacing with Insanity

More and more we are becoming mutual support groups for the insanity around us, which also happen to write business apps on the side.

I set out a few weeks ago to intertwine a tall strong intelligent business object with a confident and independent business object. Seemed the perfect pairing.

While I can’t buy POCO and other things being responsible for common behaviors of business objects, I do have a deep appreciation for provider and injection patterns. It seems fine that the business object is self servicing – meaning it has a “save yourself” method, as long as it is passing the work off to someone else who can be switched out to match development, deployment and evolutionary needs.

This was a rite of passage for the common pattern I fall back on in business objects. I’ve had insight seeing people struggle to keep their UI and business layers clean. When we mound heaps of fabulous features into base classes it’s exceedingly difficult to keep the logical intent we start with – keeping the business logic and UI isolated. I’ve just lost faith that we can avoid using features that are sitting in the Intellisense drop down. I want the compiler in control of controlling me.

That means every layer has to talk to every other layer via an interface and providers. That means the business object starts with nothing but it’s own properties and three or four self-servicing methods. It has a base class that defines any further bases, and nothing in the base classes is protected. All, private.

That’s the theory. It was way more work than I expected to implement this against CSLA business objects, but it worked. The “way more work” part was partially because I accomplished two other things along the way. Please don’t get distracted about the fact I was using CSLA as a base. If you understand where I’m going here, it makes absolutely no difference. The interesting thing to talk about later is the interfaces. I’m quite happy with that outcome.

Then I dived into what I thought would be easy – the business collections. Items for budget, line items for invoices, etc. I spent an entire day thinking, ditzing, tinkering and got nowhere. Hmmm. What’s the root cause? It’s the fact I was trained as a scientist. When there seems to be something more going on – most likely there is more going on.

CSLA – and again, it makes no differences what implementation layer you have – I just want to use a good one and not write it from scratch – does a good job setting up bindable collections. But at what cost! I scribed out all the interfaces in play (many are in play multiple times so the order is a bit random. I’m including them below, but the punch line is Rocky implements 13 custom interfaces and 12 BCL interfaces with a total of 92 members. There are a few things in Rocky’s implementation having to do with n-tier deployment that you could potentially argue, but this is just what needs to be implemented to accomplish data binding.

That’s 92 things that are either directly available to the business collection or are available via interfaces. The interfaces are the killer – everything in any interface – all 92 members are potentially public. At the moment I’m primarily interested in isolating the programmer writing business logic – but all 92 interface members are available to the UI.

This isn’t a problem if we abandon the idea of independent business objects. Wow – NO WONDER WE DON’T DO A GOOD JOB OF INDEPENDENT BUSINESS OBJECTS.

Today, I’m just screaming. And walking. And maybe later drinking. Some place in this I’ll decide a solution for this client today. I’m still hoping to do a simple list, with a “AsBindingList” method for binding and a CSLA provider for persistence. But man does that look hard at the moment.

 

CSLA Interfaces

IEditableBusinessObject

   int EditLevelAdded { get; set;}

   void DeleteChild();

   void SetParent(IParent parent)

   void Delete();

IBusinessObject

ISupportUndo

   void BeginEdit();

   void CancelEdit();

   void ApplyEdit();

IUndoableObject

   int EditLevel { get; }

   void CopyState(int parentEditLevel, bool parentBindingEdit);

   void UndoChanges(int parentEditLevel, bool parentBindingEdit);

   void AcceptChanges(int parentEditLevel, bool parentBindingEdit);

ITrackStatus

   bool IsValid { get; }

   bool IsSelfValid { get; }

   bool IsDirty { get; }

   bool IsSelfDirty { get; }

   bool IsDeleted { get; }

   bool IsNew { get; }

   bool IsSavable { get; }

IUndoableObject

   int EditLevel { get; }

   void CopyState(int parentEditLevel, bool parentBindingEdit);

   void UndoChanges(int parentEditLevel, bool parentBindingEdit);

   void AcceptChanges(int parentEditLevel, bool parentBindingEdit);

ISavable

   object Save();

   void SaveComplete(object newObject);

   event EventHandler<SavedEventArgs> Saved;

IParent

   void RemoveChild(Core.IEditableBusinessObject child);

   void ApplyEditChild(Core.IEditableBusinessObject child);

IDataPortalTarget

   void MarkAsChild();

   void MarkNew();

   void MarkOld();

   void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e);

   void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e);

   void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex);

   void Child_OnDataPortalInvoke(DataPortalEventArgs e);

   void Child_OnDataPortalInvokeComplete(DataPortalEventArgs e);

   void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex);

IIndexSearchable<T>

IEnumerable<T>

   SearchByExpression(Expression<Func<T, bool>> expr);

IPositionMappable<T>

   int PositionOf(T item);

IExtendedBindingList

   event EventHandler<RemovingItemEventArgs> RemovingItem;

Serialization.Mobile.IMobileObject

   void GetState(SerializationInfo info);

   void GetChildren(SerializationInfo info, MobileFormatter formatter);

   void SetState(SerializationInfo info);

   void SetChildren(SerializationInfo info, MobileFormatter formatter);

13 interfaces

43 members

————————————

BCL Interfaces

System.IClonable

   object Clone;

System.Collections.IQueryable<T>

System.Linq.IQueryable

   Type ElementType { get; }

   Expression Expression { get; }

   IQueryProvider Provider { get; }

System.Collections.Generic.IEnumerable<T>

   IEnumerator<T> GetEnumerator();

System.Collections.IEnumerable

   IEnumerator GetEnumerator();

System.ComponentModel IBindingList

   bool AllowEdit { get; }

   bool AllowNew { get; }

   bool AllowRemove { get; }

   bool IsSorted { get; }

   ListSortDirection SortDirection { get; }

   PropertyDescriptor SortProperty { get; }

   bool SupportsChangeNotification { get; }

   bool SupportsSearching { get; }

   bool SupportsSorting { get; }

   event ListChangedEventHandler ListChanged;

   void AddIndex(PropertyDescriptor property);

   object AddNew();

   void ApplySort(PropertyDescriptor property, ListSortDirection direction);

   int Find(PropertyDescriptor property, object key);

   void RemoveIndex(PropertyDescriptor property);

   void RemoveSort();

System.Collections.Generic.IList<T>

   T this[int index] { get; set; }

   int IndexOf(T item);

   void Insert(int index, T item);

   void RemoveAt(int index);

System.Collections.IList

   bool IsFixedSize { get; }

   bool IsReadOnly { get; }

   object this[int index] { get; set; }

   void Clear();

   bool Contains(object value);

   int IndexOf(object value);

   void Insert(int index, object value);

   void Remove(object value);

   void RemoveAt(int index);

System.Collections.Generic.ICollections<T>

   int Count { get; }

   bool IsReadOnly { get; }

   void Add(T item);

   void Clear();

   bool Contains(T item);

   void CopyTo(T[] array, int arrayIndex);

   bool Remove(T item);

System.Collections.ICollection

   int Count { get; }

   bool IsSynchronized { get; }

   object SyncRoot { get; }

   void CopyTo(Array array, int index);

System.ComponentModel.ICancelAddNew

   void CancelNew(int itemIndex);

   void EndNew(int itemIndex);

System.ComponentModel.IRaiseItemChangedEvents

   bool RaisesItemChangedEvents { get; }

12 interfaces

49 members

3 thoughts on “Interfacing with Insanity”

  1. I don’t use CSLA or any other framework for BO, so I cannot address these issues entirely accurately. But, the pattern I have used to do, what seems like similar things, is to use an explicit interface along with extension methods based on the interface. Therefore, you hide the methods/properties of the interface from the average developer, but your extension methods can still recognize that the interface is implemented and thus provide you with the higher level features you need. Perhaps I am misunderstanding your dilemma, but I thought it was a neat pattern worth mentioning anyway.

  2. IUndoableObject is listed twice.

    Aren’t are some attributes you can apply to these items to hide them from intellisense?

  3. There are attributes, and it’s a really good idea to take advantage of that control. But if the members are visible, you can’t control whether they are used. Thus it is vastly preferable to remove them entirely.

    I have overridden classes just so I could override or overload almost all the members and set the attribute to hide them. Pretty silly but sometimes helpful.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>