Fog Creek Software
g
Discussion Board




Order of things (aka, advice on design of a class)

I am working on my project, and have designed a number of classes to hold some stuff.

I am stuggling with how the classes should best be fillled.

...I will outline my classes to explain.

This is my first real stab at writing something significant, so please be kind.

A 'style' object has:
    many 'types' objects

A 'type' object has:
    many 'inputcontrols' objects
    many 'variables' objects
    many 'function' objects

A 'variable' object has:
    many 'function' objects

A 'function' object has:
  many strings.

The objective of the 'style' class is to hold the details of everything relate to the 'style'.

My question is what is the best way to fill the class.

The way I see it you can build from the bottom up.
ie
fill the strings to create the 'function' object, when the correct 'function' objects are made, put them into the 'variable' object, when all the right 'variable' objects (and 'inputcontrols' etc) have been made, put them into a 'type' object. Once the 'type' object is made put it into the 'style' object.

The second method would be to access everything via the 'style' class, and implement methods that would allow the 'style' class to create everything it needs.

Does this make sense?

I like the first method, because it is simple, and would be simple to implement.
Make the second method somehow seems more object oriented?

Your thoughts would be appreciated.

Thanks.

Aussie Chick
Wednesday, November 19, 2003

Why Not have methods of the style class retrieve the data?

style.getall() or style.getByID(ID)

1) these methods would use other objects (DB Object, XML Object) to retrieve the data needed

2) then this method can create and populate the appropriate objects with the data returned

All of your code is encapsulated in the style object.

Cleanly SeparatesUI, Businesss logic, DB Code.....

GenX'er
Wednesday, November 19, 2003

Well, your option 1 is how all the .NET stuff works.

For example, if you want an edit control inside a group box on a form, you do this (please ignore the syntax):

editcontrol = new TextBox( )
groupbox = new GroupBox()
groupbox.Controls.Add( editcontrol )
form = new Form()
form.Controls.Add( groupbox )

This has a big flexibilty advantage over your second option, which would be to have factory functions on the top level object. The advantage is simply this - suppose you add a subclass of your Function objects. With option 2, you have to edit the top-level class to provide a different class when you build function objects (or create a second factory function). With option 1, you just do:

function1 = new MyNewNiftyFunctionObject( )
function2 = new PlainOldFunctionObject()

variable.Functions.Add( function1 )
variable.Functions.Add( function2 )

Or something along those lines.

So, in general, I think you're on the right track for this stuff. However, I generally get a little leery of deeply nested structures like you're describing, either in class hierarchy or containment hierarchy. I don't know if the names you've given are realistic or just fillins, but for example, "style" to me sounds like an attribute of an object, not a container for objects.

Chris Tavares
Wednesday, November 19, 2003

The data is all going to be in a text file (to allow anybody to create their own 'style').

I was going to have a function in the style class that read and parsed the text file. (almost a constructor I guess if VB have those)

style.initialise( textfile )

but even from within that style class.
should the style class read the textfile, and create all the other classes itself, or should it only ever talk directly to the 'type' class?

ie should the stylie.initialise() create the variable and then call:

    dim tF as function
    tf.addString("abc")
    dim tV as variable
    tV.addFunction(tF)
    dim tT as Type
    tT.addVariable(tV)


or should style.initialise() call;

    dim vI as integer
    vI = type.addVariable()  'where index of the new variable is returned
    dim fI as integer
    fI = type.variable(vI).addFunction()
    type.variable(vI).function(fI).addstring("abc")

ie again, I think I prefer the first method.

Aussie Chick
Wednesday, November 19, 2003

I'm not a great designer myself, so I'll leave that to others here.

I'd like to recommend that you run to the nearest book store and pick up the GoF book (Design Patterns). It describes things like the factory pattern (possibly useful here) and many other creational patterns. If you haven't read it, then go buy it and read it 4.5 times.

The most practical suggestion I can make is this: just write something. Even if you think it's bad, you can refactor or rewrite it later. But if you make mistakes you can learn from them. I have very much recently been falling into the trap of stopping when I hit a tough design problem. Just write it, you'll learn more from your mistakes than getting it done right the first time (which will never happen anyway. If it does, go build me the Next Big Thing).

Use CVS or some revision control system. Write the new part of your system, and if you don't like it, roll back and do it again.

Mike Swieton
Wednesday, November 19, 2003

mmm..girl geek....sexy...

hiding under a pseudonym
Wednesday, November 19, 2003

Chris,

for the record.

the 'style' refers to a referencing style (think bibliographies and the 'harvard' method, or the 'APA' style).

My text file will look a bit like this.

I know the function names are a bit ambiguous (am working on that).
The variables hold each of the +variable objects below. Each variable can have a number of 'if' possibilities (these are the 'functions')

So have have trouble seeing how I can lessen the next classes. The 'style' class acts almost like a database. and I cannot reduce the 1-to-many relationships.

/******************************
/nb. I understand this may be confusing at first glance, I spent a number of days thinking about it, to make it as least confusing as possible.
/**************************
STYLE "Harvard"
STYLE_VERSION "1"
SOFTWARE_VERSION "1.0"

TYPE "Book"
    ADD _Title        (0, "Title:",...
    ADD _AUTHOR        (1, "Author/s...
    ADD _Publisher    (2, "Publishe...
    ADD _Location    (3, Electroni...
    ADD _Year        (4, "Year Pub...
    ADD _Page        (5, "Page Num...
    ADD _Volume        (6, "Volume:"...
    ADD _Accessed    (7, "Accessed

+TranslatedWork
    If _Translator "(Translated b...
    If _ForeignLanguage "(Transla...
    If _ForeignLanguage/_Translat...

+LimitedCirc
    If _LimitedCirc "(Available f...

+Abstract
    If _Abstract "(Abstract)"...

+Revised
    If _Revised "~_Revised~ editi...

+Chapter
    If _Chapter "~_Chapter~ in"...

+AuthorType
    If _Editor "(Editor)."
    If _Editor(multiple) "(Editor...

DEFAULT_FILTER
<f>_Author<n> +AuthorType (_Year)...

FILTERS
If _ForeignTitle
<f>_Author<n> +AuthorType (_Year)....

Aussie Chick
Wednesday, November 19, 2003

oops, should have noted that I have truncated the lines for reability.

Each 'style' will have more then just one 'type'.

And why have the 'typo' police never found me...I am a shocker for them.

Aussie Chick
Wednesday, November 19, 2003

>mmm..girl geek....sexy...
>hiding under a pseudonym

Hmm, well.  'hiding under a pseudonym', you may think so, but apparently, (judging by the email I just received) not everyone does!!

-----Original Message-----
From: o'my [mailto:cybersonly@yahoo.com]
Sent: Thursday, 20 November 2003 8:15 AM
To: Aussie Chick
Subject: Order of things (aka, advice on design of a class)


I think you're a moron.



-------------------------------------------------------------------
This message was sent on behalf of cybersonly@yahoo.com, from
"The Joel on Software Forum" in reply to your posting:
http://discuss.fogcreek.com/joelonsoftware/?cmd=show&ixpost=88316

Your email address is never revealed to the sender. Please report abuse
to customer-service@fogcreek.com.

Aussie Chick
Wednesday, November 19, 2003

I just have to put in a plug for XML here.  I hate soundlng like a Microsoft flaky, but...

If you can use VB.Net (or C#) you can define your Style object and the nested child objects using an XML schema.  Your users can edit the properties of the style objects in any XML editor (or Notepad, for that matter.)  You can then generate VB classes that correspond to the XML schema -- either automagically by using the XSD.exe utility, or by hand. 

With a few lines of VB code, you can then deserialize (instantiate) the objects from the XML file.  It works beautifully. 

(You can also work in the opposite direction -- first define your VB classes, and then use XSD.exe to generate an XML schema that maps to thoses classes.)

There are lots of good articles on MSDN.  Here are a few:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet07082003.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet07082003.asp

You can probably get some of this XML functionality using VB6, but VB.Net should make this task much easier.

Robert Jacobson
Wednesday, November 19, 2003

"I think you're a moron."

wasn't me I promise.

seems a little harsh really..I though you were asking good, intelligent questions.

hiding under a pseudonym
Wednesday, November 19, 2003

I have to put in another plug for XML here. Aussie Chick, it looks like the file you shows defines a schema (i.e. the data layout) rather than the contents of the data itself. Am I correct in this supposition?

In .NET, I'd define the layouts as XML schemas, and use the .NET tools to generate classes from them. But I don't know your actual application domain, so I don't know if that'll help you much or not.

I'm guessing your app lets users enter a book (or grab it from a database) and spit out a bibliography entry for that book in a user defined format. (If it is, I can see why you're thinking college students would want this!) So you're looking for a way to define your bibliographic style?

Essentially, what you're building is a report designer; something like Crystal reports or Active Reports, only more specialized.

Personally, I'd pull out a parser generator, and let the grammar handle building the data structure in memory at parse time, but I don't know what environment you're working with so I can't recommend a tool.

Chris Tavares
Wednesday, November 19, 2003

Chris, Robert,

I had a quick skim through the XML article. It does seem alot like I would want, but I would have to read more.

I am using VB6.0, I have a 60-day trial copy of the .Net studio, but have not started it yet, and I didn't want to start learning a new language at the same time as trying to write this.

>I'm guessing your app lets users enter a book (or grab it from a database) and spit out a bibliography entry for that book in a user defined format. (If it is, I can see why you're thinking college students would want this!) So you're looking for a way to define your bibliographic style?

Chris, yes exactly!

I want the style to be defined using text so that it can be changed/experimented with by anyone, anywhere.

The one thing that makes me want to hold back from XML is that I have never used it. I could probably write this parser and bunch of classes in the next day or so.
But as for learning XML I think it would take me a bit longer.

Also I am thinking I would need to be using the .Net studio?

In reality I think I will keep it in mind for the next 'upgrade'.

>Personally, I'd pull out a parser generator, and let the grammar handle building the data structure in memory at parse time
I am sorry, what do you mean by this?

Aussie Chick
Wednesday, November 19, 2003

One other thing... you can make your own simple XML editor by binding the XML to a datagrid.  (Technically, you'd read the XML into a dataset, and then bind the dataset to the datagrid.)  That way, you could provide a very clean user interface so your users would just plug the correct values into the datagrid.  The underlying XML would be completely transparent, so your users wouldn't have to worry about brackets and backslashes

The Microsoft datagrid itself is a wretched control (very limited in functionality), but there are plenty of good third-party datagrid components that can display data in a hierarchical format.

I did this for my own application, just to make it easier to edit a complex set of objects.  If you want a sample, send me an email.

Robert Jacobson
Wednesday, November 19, 2003

I think that you should parse the file externally from your data. 

The style object would then only look at what is relevent to it and pass the remaining data to the next level.

ParsedFile = new ParsedFile(filename);
style.initialize(parseFile);

The style.initialize() function would then create as many types are stored in the file but wouldn't initialize them.  Instead, it would then call initialize (or use the constructor) on the type objects and pass the relevant part of parsedFile to them.  The type objects would then create inputcontrols, variables, and function objects and pass the next relevant part of the file to them.

This would probably be best done with XML (it's really simple to use, just get a library to handle it).  If you create a DOM (document object model) from the XML file you can just pass that into the initialize function and then pass the relevant nodes to each object as you create them.

Boy..  I hope that makes sense.  Anyway, the idea is that the style object knows about type objects but only as opaque entities -- it doesn't concern itself at all with what types contain.  The same is true at each level.

Almost Anonymous
Wednesday, November 19, 2003

almost anonymous,

I understand what you are saying, which is basically the 'second' method I have been talking about, though a slightly different way to do it.

I am not sure about parsing it first though.

ie parse it into what? 3 strings (STYLE, STYLE_VERSION, and SOFTWAREVERSION) and 23 blocks of text labelled "TYPE"

then for each of the 23 "TYPES" create a type inside the 'style' and then pass it the block of text.
type(0).initialise (blockOfText1)
type(1).initialise (blockOfText2)
...
type(n-1).initialise (blockOfTextn)

with each "class" having a built in 'parser' to be able to take what it needs from the text, and pass a smaller block of text to the next nested class.?

Well I would say, that this would be a much better way then my idea for the 'second' method.

Is it better then the first way?

Aussie Chick
Wednesday, November 19, 2003

You'd probably want Visual Studio .Net Professional, if you can afford it (in the U.S. it costs around $700.)  There's Visual Basic .Net Standard Edition for about $100, but it has some crippled functionality, like the inability to define class libraries.  (It's more like a "learning edition" package.)

http://msdn.microsoft.com/vbasic/howtobuy/choosing.aspx

The next version of Visual Studio, the "Whidbey" release, is supposed to come out sometime next year (probably later in the year.)

http://msdn.microsoft.com/vstudio/productinfo/roadmap.aspx

However, if you think VB.net would be right for you, it would be better just to jump in now -- it's much easier to develop an application from the ground up as a VB.Net application, rather than starting with VB6 and later porting it.

Robert Jacobson
Wednesday, November 19, 2003

Robert,

given that I know nothing about XML, do you think it is realistic attempting this method at the moment? (not a sarcastic comment, it is a serious question).

I think I would be trying to learn what I needed as I go, (as opposed to at least having a few weekends to play around).

I once helped a friend out with a UI, had never used VB before, and was trying to use a datagrid, I spent all day researching to find the answer to a very simple problem.
I would hate to see this project go like that because I decided to try something new in the middle of it.

Aussie Chick
Wednesday, November 19, 2003

You don't necessarily have to parse it ahead of time (although that's pretty easy with XML).  Instead, pass the contents of the file to style.initialize().  It breaks the file down on the first level.  So it would read in all the style elements from the file and the type element.  Then from your example file it would pass a string containing the next level to the type object:

    ADD _Title        (0, "Title:",...
    ADD _AUTHOR        (1, "Author/s...
    ADD _Publisher    (2, "Publishe...
    ADD _Location    (3, Electroni...
    ADD _Year        (4, "Year Pub...
    ADD _Page        (5, "Page Num...
    ADD _Volume        (6, "Volume:"...
    ADD _Accessed    (7, "Accessed

The type object would then parse that string.  And create the appropriate child objects and pass in smaller strings to them.

Almost Anonymous
Wednesday, November 19, 2003

Robert,

re switching to .Net now.
It would not be an option. The old catch-22, can afford the software until I write a decent program to make a bit of money...

After christmas I can save for it, and under other circumstances I would agree, but I want this written by christmas, it is only a small program, most of my time is being spent pondering the design of the UI etc.

The actual code itself is pretty light.

Aussie Chick
Wednesday, November 19, 2003

almost anon,

yes that is what I thought you meant.

XML aside (thanks guys for the thoughts, but I don't think I can make it happen yet), would this method (parsing unparsed blocks of text do the next class), be better then creating each function from the bottom up?


'from within the initialisation function of the style class

parse the data file into:
3 strings (STYLE, STYLE_VERSION, and SOFTWAREVERSION)
23 blocks of text labelled "TYPE"

then for each of the 23 "TYPES" create a type inside the 'style' and then pass it the block of text.
type(0).initialise (blockOfText1)
type(1).initialise (blockOfText2)
...
type(22).initialise (blockOfText23)


Or
having the 'style' class do all the parsing
'from within the initilisation function of the style class
    dim tF as function
    tf.addString("abc")
    dim tV as variable
    tV.addFunction(tF)
    dim tT as Type
    tT.addVariable(tV)

I know this is the same question I have been banding around, perhaps I should just take Mike Sweiton's advice and just "do something".

In which case I will go with the method that "almost anon" has suggested.

Thanks for your help.

I appreciate your comments about XML and .Net.

Aussie Chick
Wednesday, November 19, 2003

What I meant by using a parser generator:

There are lots of tools that let you define the grammar for a language (using a variation of something called Backus-Naur Form or BNF) in a text file. Once you have your grammar, you can run it through the tool and it'll spit out code that recognizes files in that language. And, more importantly, you can embed operations on the data into the grammar file and it'll end up being called automatically.

What I would do in your situation is define the grammar for your "style definition file" using a parser generator, and in the handlers for the various productions (also known as "bits of the grammar that are recognized in the input") build the appropriate objects.

Unfortunately, all the free tools I know of are for either Java or C++, so I guess that won't help you much. Depending on your grammar, you can build something called a recursive descent parser by hand without much trouble, but if you're not familiar with what I'm talking about it'd be kinda hard to explain.

Chris Tavares
Wednesday, November 19, 2003

Chris,

I recall BNF from university, we spent an entire unit designing a program language and creating a parser and compiler for it.

That is why I wasn't to put off by having to create a parser by hand, I have done it (albeit in a small way) a couple of times.

And I don't think this project will go out of the scope of what I capable of doing.

Especially if I do as 'almost anon' has suggested, and pass each block to the next class.
ie each class will have a small built-in parser, which will turn a large potentially hairy job into a number of smaller simpler jobs.

Aussie Chick
Wednesday, November 19, 2003

It's a fair question.  I switched from VB6 to VB.Net last year, and there was a fairly steep learning curve.  However, I think it paid off in the long run, since VB.Net is a much more capable and robust language IMO.

It really depends on what your goals are.  If you want to get this done ASAP, you should stick with the tools you know.  It could be dangerous to switch languages if you're in a hurry -- it's better to take time to become familiar VB.Net when your not under time pressure.

On the other hand, I think that using XML with object serialization/deserialization would ultimately be your best choice for accomplishing the task you've described.  Also, my belief is that VB.Net is better suited for developing robust commercial applications.

The only advice I can give is, if you can, take some time to read up on VB.Net and play around with it.  (Two good books are "Programming in VB.Net: A Guide for Experienced Programmers" and "Moving to VB.Net: Strategies, Concepts and Code," both from Apress.)  There are lots of good articles and code samples available on MSDN.

Alternatively, you could look into using object serialization in Visual Basic 6.  I never tried it, so I can't say how difficult it would be.

Robert Jacobson
Wednesday, November 19, 2003

"It's a fair question.  I switched from VB6 to VB.Net last year, and there was a fairly steep learning curve.  However, I think it paid off in the long run, since VB.Net is a much more capable and robust language IMO."

Why did you switch to VB.Net over C#?  I'm a VB6 programmer and, while I have VisualStudio.Net installed, I haven't really had a chance to play with it.  However, I'm planning to skip VB.net and just learn C#.  If VB.net was VB6-for-Net rather than just another skin for C# I suspect my decision would be different.

Almost Anonymous
Wednesday, November 19, 2003

I agree with AA, for what it's worth.

Pass the complete block of text to your top-level object.

Have it create a collection of child objects, one per block that it identifies as "other stuff". Pass each block to a child object. And recurse, until you get down to an object that knows what all the text it holds, means.

To reverse the procedure and "save" a complete block, start from the top, have the top level object put in the bits it holds, then ask each of its children for its block, which in turn... You get the idea.

I've moved from VB6 to C#. There's a lot to learn. Move eventually (or to VB.NET, it matters not), but not when you're in a hurry for results!

And yes, XML *is* a good way to do this. And no, I wouldn't bother at this stage.

Dave Hallett
Wednesday, November 19, 2003

At the time, I didn't give it much thought -- I'd programmed exclusively in VB5 and VB6, so VB.Net seemed like the way to go.  Since then I've learned enough C# to be dangerous.  <g>

Today I'm fairly agnostic when it comes to the languages -- both are equally capable, in my opinion.  (I don't like curly braces or case sensitivity, but obviously those are just personal preferences.)  In the end, I think the language choice really doesn't matter much.

OTOH, I don't think there's any reason to avoid VB.Net -- the persistent notion that it's somehow a "second class citizen" in the Net hierarchy is rubbish.  Your comment about VB being a "skin" for C# is somewhat apt, since they share the same foundation, but I view that as a plus -- you get all the benefits of C# (great Framework class library, full object-oriented support, structured exception handling) with the more "user friendly" language constructs of VB.  Also, Microsoft is planning major improvements to VB.Net for the Whidbey release.

You might like these resources:

Whitepaper "Differences Between Visual Basic .NET and Visual C# .NET"
http://support.microsoft.com/?kbid=308470

Dan Appleman ebook, VB.Net or C#: Which to Choose?
http://www.desaware.com/Ebook2L2.htm

Microsoft Developer Tools Roadmap
http://msdn.microsoft.com/vstudio/productinfo/roadmap.aspx

Robert Jacobson
Wednesday, November 19, 2003

*  Recent Topics

*  Fog Creek Home