Architetural Decisions

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

I'm on my way to my first OOP-for-real project in C#, and having some big
trouble with code architeture.

I have four namespaces:
- Layout
- Info - Where I hold empty structs with business objects
- DB - Where I fill my Info objects
- Classes - Where I do all the business stuff with the return from DB

A snapshot from my database:

- Table Orders, Fields: ID, Date, ClientID
- Table OrdersDetails, Fields: OrderID, ProductID, Price, Quant, Discount

What I need, is to compute the total of an individual OrderDetail, and of
the entire order. I create this total fields with sum in sql, the fastest
way, and it's working nice.

But... This calc is bussiness logic, and it should be in my "Classes"
namespace, isn't that right? Cause if I have some special discount to apply,
for example, I'm in trouble. But, the only way to do this logic in the
"Classes" namespace, is looping through each object of the collection I have
already created - this sucks.

What concept I am misleading? What should I do?

Thanks in advance
Bruno Rodrigues.
 
Bruno Rodrigues said:
Hi,

I'm on my way to my first OOP-for-real project in C#, and having some big
trouble with code architeture.
A snapshot from my database:

Did you just say OOP-for-real and then describe the design problem by
telling us about your database structure?

What I need, is to compute the total of an individual OrderDetail, and of
the entire order. I create this total fields with sum in sql, the fastest
way, and it's working nice.

But... This calc is bussiness logic, and it should be in my "Classes"
namespace, isn't that right? Cause if I have some special discount to
apply,
for example, I'm in trouble. But, the only way to do this logic in the
"Classes" namespace, is looping through each object of the collection I
have
already created - this sucks.

If looping through a collection sucks then there are a lot of sucky
applications out there. And when an order item changes and you have still
not persisted this change back to the database, how were you planning on
getting the updated order total?
What concept I am misleading? What should I do?

OOP like you said you were doing

SP
 
SP is correct. Database design should be coming much later in your design.
If you want a short course on OOAD in a couple hundred words or so, start
with requirements, from requirements begin to create use cases. Turn your
use cases into a static class design. At that point you have begun to
identify your business layer objects (classes) and their behavior (methods)
including such things as ApplyDiscount() and Total().

So, the direct answer to your question is that you are correct. The
functionality you describe probably does belong in your business layer, not
in the database, at least from an intitial design standpoint. Your Orders
class should have a zero to many attribute of type OrderDetail. Class
OrderDetail should have a price and a quant(ity - why abbreviate it?)
attribute. These all participate in the OrderDetail::Total() and
Order::Total() operations which provide you the values you want.

Then, you begin to design your database as a means of persisting your class
design. When you get to that phase, you'll end up changing things a little;
you'll break the theoretical class design by normalizing your database and
by implementation requirements versus your design requirementes, but
basically, you should end up pretty close to your paper design in your use
cases and class design. You may find that if orders have very many detail
items but they get modified very seldom, it is easier to break all those
rules and store a detail total in the OrderDetail table and an order total
in the Orders table. Both these violate normalization principles and
present data consistency risks, but they could actually improve performance.
I tend to be a strict normalization kind of DBA but even so, there are times
and situations where rules should be broken.

The problems with doing it your way, though, database first, is that you end
up not having all the things you need in the data, and having a lot of
things in your data design that you don't need. This applies to design and
structure as well as to tables and fields. When you design from the bottom
up, you will end up spending much more work patching, modifying, and
otherwise re-working your implementation as the business requirements
trickle down from the top of the design. It is always more efficient to
spend the time doing the design right in the first place.

Because OOAD is the topic of much academic study and research, as well as
being a production methodology, you'll find more information about OOAD on
the web than you could consume in a life time. Depending on the scope of
your project, you may want to look into things like:

Agile Software Development at http://www.agilealliance.org/home
Extreme Programming at http://www.extremeprogramming.org/
or, for larger scale projects,
Rational Unified Process at http://www.ibm.com/rational/

And in all cases, http://www.uml.org

HTH

Dale Preston
MCAD, MCDBA, MCSE
 
Hi,

I'm on my way to my first OOP-for-real project in C#, and having some big
trouble with code architeture.
What concept I am misleading? What should I do?

Thanks in advance
Bruno Rodrigues.


Youve been given some good advice.

Let me muddy the waters a little by recommending that before
proceeding any further (I assume this is an academic project) you buy,
read and then study the following :-


http://www.amazon.com/exec/obidos/t...102-0726059-1555314?v=glance&s=books&n=507846
( Design Patterns : A New perspective on Object-Oriented Design (2nd
Ed)

The problem you discuss is even examined under the "stragegy" pattern.

While I cant evangelise design patterns (yet) there are some very
interesting perspectives there that are well worth adding to your
designer toolbox...

regards
 
I'm on my way to my first OOP-for-real project in C#, and having some big
trouble with code architeture.

Well, as both SP and Dale have said, you are starting off on the wrong foot
if you are trying to design classes out of tables :-)
I have four namespaces:
- Layout
- Info - Where I hold empty structs with business objects
- DB - Where I fill my Info objects
- Classes - Where I do all the business stuff with the return from DB

I would disagree with your 'namespaces'. In OO architecture we often talk
about layered architecture and certainly you could represent those layers in
namespaces; but you would not separate what you have put in your Info
namespace from your classes namespace. Rather try these layers:

Business
Persistence
Presentation

The Business layer should include classes that not only describe youor data
but also the related logic inside those classes. You will sometimes find
*some* classes that are 'data-only' classes; also *some* classes that are
'logic-only'; but the majority of your classes will include both data and
logic in the same place.
A snapshot from my database:

- Table Orders, Fields: ID, Date, ClientID
- Table OrdersDetails, Fields: OrderID, ProductID, Price, Quant,
Discount

So here is your first problem with designing from a database to a class; but
to be fair, you will get the same problem in reverse without the solution
that the Persistence layer should provide.

A good OPF (Object Persistence Framework) should allow you to translate
between the OO model and the RDB model, as there is what is known as an
'impedance mismatch'

If we take your Order scenario as a starting point, you should have classes
that look like this :

Order
{
ID
Client
Date
Details
Total
}

OrderDetail
{
ID
Quantity
Product
Price
Discount
Total
}

Now, if you compare this to your table definitions, you will se some
differences :

Where in a table you would talk about storing IDs of foreign keys, in
classes you should always use references to 'real objects'; so in Order you
have a Client property which holds an instance of the Client class, not a
ClientID integer property.

You will notice that there is no reference to the Order in the OrderDetail
class, even though this exists in the database. This is very important as
classes should reflect the real world, not a relational interpretation of
it.

OrderDetail instances should not be instantiable outside of the Order class
as the relationship between the two classes is said to be that of
Composition.

<side note>
There are two ways of describing containment of objects inside other
objects: Aggreagation and Composition.
Aggregation describes a scenario where an object contains a list of other
objects, but those contained objects have a life of their own outside of the
containing object; essentially the containing object has a list of
references to external objects.
Composition describes a scenario where the objects contained by another
object are owned by that object and live and die with the containing object;
this is the case with the concept of an Order.
</side note>

One way of expressing Composition in your Order class is to ensure that the
only way to access the OrderDetail items is by way of a read-only list or
perhaps even just an enumerator. Either way do not rely on exisiting classes
like ArrayList to be the type of a list, but rather create your own typesafe
lists. This can be tedious in .NET 1.1, but generics in .NET 2.0 make it a
real breeze.

Or you can just implement the list functionality in the Order class in a way
that it is impossible to create Details that are not part of the Order.

public class OrderDetail
{
private int id;

private int quantity;

private Product product;

private decimal price;

public int ID
{
get { return id; }
set { id = value; }
}

public int Quantity
{
get { return quantity; }
set { quantity = value; }
}

public Product Product
{
get { return product; }
set { product = value; }
}

public decimal Price
{
get { return price; }
set { price = value; }
}

public decimal Total
{
get { return quantity * price; }
}
}

public class Order
{
private int id;

private string number;

private Customer customer;

private DateTime date;

private ArrayList details = new ArrayList();

public int ID
{
get { return id; }
set { id = value; }
}

public string Number
{
get { return number; }
set { number = value; }
}

public Customer Customer
{
get { return customer; }
set { customer = value; }
}

public DateTime Date
{
get { return date; }
set { date = value; }
}

public OrderDetail Add()
{
OrderDetail newItem = new OrderDetail();
details.Add(newItem);
return newItem;
}

public void Remove(OrderDetail item)
{
details.Remove(item);
}

public void Remove(int idx)
{
details.RemoveAt(idx);
}

public OrderDetail this[int Idx]
{
get { return (OrderDetail) details[Idx]; }
}

public decimal Total
{
get
{
decimal total = 0.0M;
foreach(OrderDetail d in details)
total += d.Total;
return total;
}
}
}
What I need, is to compute the total of an individual OrderDetail, and of
the entire order. I create this total fields with sum in sql, the fastest
way, and it's working nice.

But... This calc is bussiness logic, and it should be in my "Classes"
namespace, isn't that right? Cause if I have some special discount to apply,
for example, I'm in trouble. But, the only way to do this logic in the
"Classes" namespace, is looping through each object of the collection I have
already created - this sucks.

What is wrong with iterating a small list ?

If you look at my example Order class, you will see how to place the logic
for calculating the Order Total. Now this can be stored in a database if you
want, but the time taken to calculate it in memory is usually less than the
time taken to read it from disk :-)
What concept I am misleading? What should I do?

The translation between the OO ideas and the RDB ideas is the 'missing
link'. That missing link is best handled in th Persistence layer by a
hierarchy of mapping classes that allow you to translate the property layout
of classes to the column layout of tables.

Take a look at this paper on OPFs by Scott Ambler,

http://www.ambysoft.com/persistenceLayer.pdf

I have written several OPFs based on some of the ideas in this paper, with
some modifications. To cope with the difference between referencing Details
in Order and OrderID in OrderDetail, look at the concept he talks about of
Association Maps. This is the piece of magic that allows you to keep your
object model free from RDB concepts.

Also you might like to look at some of the articles on Persistence on my
website; they are written for a Delphi audience, but the principles are the
same, whatever the language :-)

www.carterconsulting.org.uk

Joanna
 
Hello Bruno,

Joanna's advice is top quality, as is the paper she referenced from Scott
Ambler.

I would add a "process" note to this advice.

<Note>

Do not be overwhelmed by the advice to create an Object Persistence
Framework. 80% of all applications are small, department-level apps, used
by less than 30 people (ever) that will never undergo the stresses that
would justify a full featured OPF.

I'm a bit of an agilist these days. I would say this: encapsulate
persistence in a layer (as all of the postings suggest). Within your
persistence layer, do the simplest thing possible. If you find that your
application needs to support multiple db connections, or needs to be able to
connect to any vendor's db in a trivial manner, or needs to provide cursors
to the application through your persistence layer, then consider the advice
to jump over to an OPF.

That would be a good thing to do... but DON'T do it first. Let your design
evolve.

</Note>

To add to the information presented so far:

The Layers pattern is an architectural pattern, not a design pattern. As
such, it is a powerful structure that is as applicable in non-OO systems as
in OO systems. In that sense, it is an easy leap from where you are at.

If you wish to further your journey into object oriented _design_, you may
want to consider educating yourself on design patterns themselves. I
blogged this topic:
http://blogs.msdn.com/nickmalik/archive/2004/12/21/328727.aspx

The book to start with is not the Gang of Four book (Design Patterns by
Gamma Helm Johnson and Vlissides) as another post suggested, but rather a
slim volume written from a less pedantic perspective: "Design Patterns
Explained" by Shalloway and Trott. Once you have been introduced to the
patterns literature, there are about two dozen books that are useful, both
from a design standpoint and an architectural standpoint.

Good Luck,

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
The book to start with is not the Gang of Four book (Design Patterns by
Gamma Helm Johnson and Vlissides) as another post suggested,
<snip>
Unless someone else recommended the GoF book I was also suggesting the
Shalloway and Trott book....

And both your and Joannas' advice is superb; might I sidetrack things
a little and ask what resources/books you would suggest on OO
Architecture patterns? Im new to patterns myself and hadnt encountered
the differentiation before....

Regards
 
Amazon List:
http://www.amazon.com/exec/obidos/t...YU3/ref=cm_aya_av.lm_more/104-0692560-9975161

Specifically, these two:
Patterns of Enterprise Application Architecture
by Martin Fowler (Hardcover)

Pattern-Oriented Software Architecture, Volume 1: A System of Patterns
by Frank Buschmann, et al (Hardcover)

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
I also add my apologies: I hadn't followed your link to Amazon before I had
replied. The title that you placed in your post was just similar enough to
the GoF title that I mistook it.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
Amazon List:
http://www.amazon.com/exec/obidos/t...YU3/ref=cm_aya_av.lm_more/104-0692560-9975161

Specifically, these two:
Patterns of Enterprise Application Architecture
by Martin Fowler (Hardcover)

Pattern-Oriented Software Architecture, Volume 1: A System of Patterns
by Frank Buschmann, et al (Hardcover)

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.

Cheers Nick.
 
Do not be overwhelmed by the advice to create an Object Persistence
Framework. 80% of all applications are small, department-level apps, used
by less than 30 people (ever) that will never undergo the stresses that
would justify a full featured OPF.

I would also agree with Nick's note here. You should start with a simple
interface to a Persistence Layer that has functionality like :

ObjectStore
{
bool StoreObject(object obj);
bool RetrieveObject(object obj);
bool DeleteObject(object obj);
IList RetrieveCollectionForType(Type objectType);
}

This interface is adequate for the CRUD basics of any application.

Of course you then might go on to want to retrieve objects that meet certain
criteria, and that is achieved by having a RetrieveCollectionForCriteria
method that adds a Criteria object to the parameter list that contains the
field name and value to match. These Criteria objects can be added to each
other to give complex boolean logic if required.

OTOH, until you get around to writing a generic SQL writing mechanism, you
can just add methods Like RetrieveCustomersForName, etc that are very
specific.
I'm a bit of an agilist these days. I would say this: encapsulate
persistence in a layer (as all of the postings suggest). Within your
persistence layer, do the simplest thing possible. If you find that your
application needs to support multiple db connections, or needs to be able to
connect to any vendor's db in a trivial manner, or needs to provide cursors
to the application through your persistence layer, then consider the advice
to jump over to an OPF.

As Nick says, keep it simple and don't try to design a complete OPF to start
with, just do what is necessary to keep your database completely out of the
business layer :-))

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
 
Back
Top