Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #12760 > unrolled thread

Designing Interfaces

Started byNovice <novice@example..com>
First post2012-03-08 00:27 +0000
Last post2012-03-11 23:29 +0000
Articles 7 — 3 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Designing Interfaces Novice <novice@example..com> - 2012-03-08 00:27 +0000
    Re: Designing Interfaces Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-08 08:28 -0400
    Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 09:11 -0500
      Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 09:35 -0500
        Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 19:24 -0500
          Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 19:36 -0500
    Re: Designing Interfaces Novice <novice@example..com> - 2012-03-11 23:29 +0000

#12760 — Designing Interfaces

FromNovice <novice@example..com>
Date2012-03-08 00:27 +0000
SubjectDesigning Interfaces
Message-ID<XnsA00FC7119110Ajpnasty@94.75.214.39>
This is actually a discussion that Lew and I started in the "Aspect 
Qustions" thread but it is so unwieldy know that I'm pushing it into a 
new thread. 

Here's the context so that everyone knows what the subject of discussion 
is. While this started as sort of a side conversation between Lew and I, 
as far as I'm concerned, anyone who has something to contribute is more 
than welcome to jump in on this. Even if you say the same thing as 
someone else, your wording might be more effective in making me see the 
point than the way the other person said it. Anyway, here's where we were 
in the other thread.


>>>>> Summary:
>>>>> Interface: what to do
>>>>> Class:     how to do it
> ...
>>> Give me an example of some unit of functionality you'd like to
>>> design, in broad terms, and I'll do just that.

>> I think that would be an interesting exercise. Let's do one that I've
>> already done myself and that you (probably) haven't. I'm sure I'll
>> learn some things by seeing how you approach it.

>> I have a project (that regularly undergoes polishing) to produce
>> resumes. More specifically, it creates various formats of my own
>> resume (and only my own resume.) Each of the resumes I generate
>> contains the exact same information obtained from a single file but I
>> generate it in several formats: an HTML version, a Java applet, an
>> ASCII text version, a PDF version (using iText), and a Word version.
>> I also generate supporting files, including a CSS file for the HTML
>> version of the resume, and a short PDF containing contact information
>> for references.

> What are the overall modules? For example: "Obtain resume from single
> file", "Export to format X", "Generate references document", ...

At the moment, I have a main program that simply generates each document 
in turn. It's called ResumeFileGenerator. Its constructor gets the 
resource bundle that drives the creation of the resumes. Each resume 
format is generated by a separate class and is passed an object that 
represents the data needed in the resume and the path and file name to be 
generated by that class. Then, the supporting documents are each 
generated by their own separate classes. They too are told the path and 
file name that should be generated but are not passed the resume object 
since they don't need it.

>> The program that generates the resumes and supporting files is
>> written in Java. The data file that is parsed to create each format
>> of the resume is a Java ResourceBundle of the "list" type. NOw, I'm
>> only producing the resumes

> Sorry, "list" type?

Sorry, that was sloppy shorthanding on my part. I meant the 
ResourceBundles that are based on ListResourceBundles, as shown at
http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html, versus 
the "text" and "message" types which are basically properties files. Some 
of my data consists of arrays like the list of editors I've used and the 
list of word processing programs I'm familiar with so the simpler 
property file type resource bundles don't work well for that.

>> in English so I should mention that I am open to the possibility of
>> creating the resume in additional languages - I have a working
>> knowledge of two other (human) languages - so I chose to use a
>> Resource Bundle so that I could easily generate resumes in additional
>> languages. Otherwise, I'd have probably just used a standard text
>> file or more likely a properties file.

>> Given the fact that several resumes containing the same data are
>> being generated there would seem to be obvious opportunities for
>> refactoring and probably at least one interface. This code has gone
>> through various permutations but I've used a single interface with a
>> single method in my existing code. The code works but I'm not at all
>> sure it is designed well.

> What interface? What method?

It's an interface I created as opposed to one that is in the API. It is
called ResumeFileWriter and has one empty method in it called 
writeResume. It has two parameters, a String that identifies the path and 
name of the file to be written and a Resume object that refers to the 
data contained in the Resource Bundle. Each of the classes that writes an 
actual resume (as opposed to a supporting file) implements it.

It's entirely likely that this interface should do a lot more than it
currently does. That's why I'm very curious to get your take on this.

I've also got an abstract class called ResumeFileCreator. It has four
concrete methods: deleteFile, openOutputFile, closeOutputFile and
getGeneratedBy (which simply generates a string containing the name of a
class and the current date and time which I use to create comments in 
each of the files that are written). Each of the classes that writes a 
resume or supporting file subclasses ResumeFileCreator.

>> I'd be very curious to get your take on it. I expect that the design
>> has major flaws and I'd like to clean those up once I find out what
>> they are.

>> Does that sound reasonable to you? I'm basically asking you to talk
>> me through the way you would design it knowing what I've told you.
>> Naturally, you're free to ask as many questions as you like to
>> understand what I'm trying to do.

> We'll go step by step.

Works for me :-) 

-- 
Novice

[toc] | [next] | [standalone]


#12763

FromArved Sandstrom <asandstrom3minus1@eastlink.ca>
Date2012-03-08 08:28 -0400
Message-ID<JB16r.1675$M%7.503@newsfe10.iad>
In reply to#12760
On 12-03-07 08:27 PM, Novice wrote:
> This is actually a discussion that Lew and I started in the "Aspect 
> Qustions" thread but it is so unwieldy know that I'm pushing it into a 
> new thread. 
> 
> Here's the context so that everyone knows what the subject of discussion 
> is. While this started as sort of a side conversation between Lew and I, 
> as far as I'm concerned, anyone who has something to contribute is more 
> than welcome to jump in on this. Even if you say the same thing as 
> someone else, your wording might be more effective in making me see the 
> point than the way the other person said it. Anyway, here's where we were 
> in the other thread.
> 
> 
>>>>>> Summary:
>>>>>> Interface: what to do
>>>>>> Class:     how to do it
>> ...
>>>> Give me an example of some unit of functionality you'd like to
>>>> design, in broad terms, and I'll do just that.
> 
>>> I think that would be an interesting exercise. Let's do one that I've
>>> already done myself and that you (probably) haven't. I'm sure I'll
>>> learn some things by seeing how you approach it.
> 
>>> I have a project (that regularly undergoes polishing) to produce
>>> resumes. More specifically, it creates various formats of my own
>>> resume (and only my own resume.) Each of the resumes I generate
>>> contains the exact same information obtained from a single file but I
>>> generate it in several formats: an HTML version, a Java applet, an
>>> ASCII text version, a PDF version (using iText), and a Word version.
>>> I also generate supporting files, including a CSS file for the HTML
>>> version of the resume, and a short PDF containing contact information
>>> for references.
> 
>> What are the overall modules? For example: "Obtain resume from single
>> file", "Export to format X", "Generate references document", ...
> 
> At the moment, I have a main program that simply generates each document 
> in turn. It's called ResumeFileGenerator. Its constructor gets the 
> resource bundle that drives the creation of the resumes. Each resume 
> format is generated by a separate class and is passed an object that 
> represents the data needed in the resume and the path and file name to be 
> generated by that class. Then, the supporting documents are each 
> generated by their own separate classes. They too are told the path and 
> file name that should be generated but are not passed the resume object 
> since they don't need it.
> 
>>> The program that generates the resumes and supporting files is
>>> written in Java. The data file that is parsed to create each format
>>> of the resume is a Java ResourceBundle of the "list" type. NOw, I'm
>>> only producing the resumes
> 
>> Sorry, "list" type?
> 
> Sorry, that was sloppy shorthanding on my part. I meant the 
> ResourceBundles that are based on ListResourceBundles, as shown at
> http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html, versus 
> the "text" and "message" types which are basically properties files. Some 
> of my data consists of arrays like the list of editors I've used and the 
> list of word processing programs I'm familiar with so the simpler 
> property file type resource bundles don't work well for that.
> 
>>> in English so I should mention that I am open to the possibility of
>>> creating the resume in additional languages - I have a working
>>> knowledge of two other (human) languages - so I chose to use a
>>> Resource Bundle so that I could easily generate resumes in additional
>>> languages. Otherwise, I'd have probably just used a standard text
>>> file or more likely a properties file.
> 
>>> Given the fact that several resumes containing the same data are
>>> being generated there would seem to be obvious opportunities for
>>> refactoring and probably at least one interface. This code has gone
>>> through various permutations but I've used a single interface with a
>>> single method in my existing code. The code works but I'm not at all
>>> sure it is designed well.
> 
>> What interface? What method?
> 
> It's an interface I created as opposed to one that is in the API. It is
> called ResumeFileWriter and has one empty method in it called 
> writeResume. It has two parameters, a String that identifies the path and 
> name of the file to be written and a Resume object that refers to the 
> data contained in the Resource Bundle. Each of the classes that writes an 
> actual resume (as opposed to a supporting file) implements it.
> 
> It's entirely likely that this interface should do a lot more than it
> currently does. That's why I'm very curious to get your take on this.
> 
> I've also got an abstract class called ResumeFileCreator. It has four
> concrete methods: deleteFile, openOutputFile, closeOutputFile and
> getGeneratedBy (which simply generates a string containing the name of a
> class and the current date and time which I use to create comments in 
> each of the files that are written). Each of the classes that writes a 
> resume or supporting file subclasses ResumeFileCreator.
> 
>>> I'd be very curious to get your take on it. I expect that the design
>>> has major flaws and I'd like to clean those up once I find out what
>>> they are.
> 
>>> Does that sound reasonable to you? I'm basically asking you to talk
>>> me through the way you would design it knowing what I've told you.
>>> Naturally, you're free to ask as many questions as you like to
>>> understand what I'm trying to do.
> 
>> We'll go step by step.
> 
> Works for me :-) 
> 
Given all that, I prefer a design where the "resume" objects know how to
do things. If you start thinking of "writers" and "creators" you're
headed towards Martin Fowler's Anemic Domain Model (look it up) and
you're becoming quite procedural.

Sure we've got a whole menagerie of Writers and Readers in core Java
APIs, but these are nuts and bolts _implementation_ classes and
interfaces. "Writers" and "Readers" in your own designs aren't illegal
but you want to think things through carefully before deciding that they
are the best solution.

Start with your domain entity, Resume. Maybe that's what ought to be an
interface. I'm just thinking aloud, this would be my first approach.
What would I want a Resume to be able to do? I suspect it ought to be
able to "write" itself: rather than "writeResume" in
"ResumeFileCreator", maybe you've got "write" in "Resume".

Hmmm, different formats? We'll be thinking design patterns in a bit. But
first off, it seems a reasonable conclusion that Resume, not some file
format library, knows how to convert itself to an abstract layout.
Regardless of whether the final format is PDF or HTML or Word or XML,
the Resume knows how to describe its output layout in terms of headers
and footers and paragraphs and so forth.

The nuances of this are open for vigorous debate, and I'll revisit this
below (see Layout vs Logical Structure).

So for writing a Resume, my first picture would be that when instructed
to write itself, a Resume object can decompose itself into abstract
write sub-operations: write the header, write the body, etc. These in
turn have smaller bits.

What are other choices? We have things like style of resume:
skills-oriented, chronology-oriented etc. Resume can certainly deal with
these (again, see Layout vs Logical Structure below). We also have
things like does the format support pagination, and what is the output
footprint (mobile screen, standard page etc), but this is not a Resume
concern necessarily.

Now, while Resume conceptually also knows everything about how to
convert itself to PDF or HTML or Word, and nothing else does, you don't
want Resume tied to a fixed set of output format choices either.
Besides, from a manageability standpoint you don't want your
implementation class(es) too large.

One idea is the Strategy design pattern. Come "write" time, an instance
of a Resume implementation class is supplied a ResumeWriteStrategy.
After all, it's the client code (presumably), not the Resume object,
that selects the actual output format. ResumeWriteStrategy is an
interface that defines the abstract write operations that have to be
implemented for each format; concrete classes (like
ResumePDFWriteStrategy) actually do the heavy lifting.

Your Resume "write" method now gets a strategy when it's invoked, and as
write works through its abstract layout, it delegates its real writing
to the supplied strategy object.

Let's call the Strategy approach Option A.

Another option would be to have a top-level AbstractResume that does
basic implementation of Resume (the abstract layout in "write", for
example), and concrete resume classes for each output format that know
how to do the specific format. This isn't inherently bad: in either
approach you need to write a new "something" to handle a new output
format, and in any case your client code should only know about Resumes.
Lew keeps on mentioning interfaces as "types" - exposing any and all
incarnations of "resumes" to client code as a Resume, where Resume is an
interface, is an example of this.

This is Option B.

I'd dispute anyone who said that Option A was substantially better than
Option B, or vice versa. The only hitch with Option B is that when you
obtain an instance of Resume, you do actually decide the output format
right then and there. Whereas with Option A you simply have a "resume"
implementation class instance, that doesn't know from formats, and it's
only when the client code decides to have the resume output itself that
the decision needs to be made. Depending on system requirements this
could drive a choice.

Let's return to the Strategy option. You should see the difference here
between your ResumeFileWriter and my ResumeWriteStrategy. Your classes
that implement your "writeResume" may appear to be superficially similar
to what my strategy classes do, but there is one major difference: in
your design the resume is a dumb object. This equates to saying that
Resume doesn't know about its logical structure. Well, sure it does.

** Layout vs Logical Structure **

Now, logical structure isn't actually layout either, so as promised I'll
revisit this. We originally have the single "write" method knowing how
to layout at the abstract level. It uses logical structure elements to
do this. Resume (implementations) should be loaded with logical
structure, describing all the data that goes into a CV in an OO kind of way.

Now, there are really 2 output issues, not just one. There is layout,
and then there is output format. With a single "write" method in Resume
you've hardwired to one layout, and odds are you'd like to be flexible
here too. As mentioned before, Resume might want to switch between
skills-oriented layout and chronology-oriented layout, as an example.

There are also *style* type layout decisions: formal vs informal, for
example.

One can safely assume that these are all client code decisions. Not only
that, they can combine. You might have formal+skills, or
formal+chronology, or informal+chronology. So how to handle this? Adding
subclasses in Option B doesn't look appealing -
InformalChronologyHtmlResume is very klunky. I wouldn't want a
ResumeFormalSkillsPDFWriteStrategy either. :-)

Ultimately more interfaces. Interfaces in Java are the only "mixin"
we've got. Maybe we continue the strategy idea, and supply more of them
when we call "write".

** Summary **

None of this is authoritative, and I don't even claim it's the best way
to do things. It's my thought process today, and 2 weeks from now it
might be slightly different.

Usually what I do, well before I reach this point, is to code as I think
design. Nobody needs the "last mile" code at this point, which is to
write out the actual PDF or HTML into files or to some other stream;
you're just playing with interfaces and stubbed implementation classes,
and some simple client code.

Think other design patterns too. I've called out just one, and it's not
necessarily the only one or even the best one. There are a number of
other structural and behavioural patterns that should be thought of, and
examined, in this problem.

This is actually an excellent problem for learning Java and OO, so
leverage the hell out of it. :-) What I've set out here is one example
of a train of thought. If you remember anything from this, it's in my
first paragraph: avoid value objects that are weak in behaviour. Lots of
Java code that you will encounter is actually very procedural, not
really OO at all, so be careful about what you seize on as examples.

AHS
-- 
-- Gaiety is the most outstanding feature of the Soviet Union.
Josef Stalin, November 1935

[toc] | [prev] | [next] | [standalone]


#12764

FromJeff Higgins <jeff@invalid.invalid>
Date2012-03-08 09:11 -0500
Message-ID<jjael9$qbc$1@dont-email.me>
In reply to#12760
On 03/07/2012 07:27 PM, Novice wrote:
> This is actually a discussion  ...

import java.io.Writer;
import java.util.Locale;
public interface Resume {
   Writer write(Template t, Locale l);
}

public interface Template {
   Element root();
}

// ElementVisitor ana Element
// swiped from javax.lang.model

public interface ElementVisitor<R, P> {
   /**
    * Visits an element.
    * @param e  the element to visit
    * @param p  a visitor-specified parameter
    * @return a visitor-specified result
    */
   R visit(Element e, P p);
}

import java.util.List;
import java.util.Locale;
public interface Element {
   <R, P> R accept(ElementVisitor<R, P> v, P p);
   AttributeSet attributes();
   AttributeSet attributes(Locale l);
   Element enclosingElement();
   List<? extends Element> enclosedElements();
}

// AttributeSet
// swiped from javax.swing.text

public interface AttributeSet {
   public int count();
   public Object get(Object key);
   public boolean contains(Object name, Object value);
   public boolean containsAttributes(AttributeSet attributes);
   public AttributeSet parent();
}

[toc] | [prev] | [next] | [standalone]


#12765

FromJeff Higgins <jeff@invalid.invalid>
Date2012-03-08 09:35 -0500
Message-ID<jjag32$2nj$1@dont-email.me>
In reply to#12764
On 03/08/2012 09:11 AM, Jeff Higgins wrote:
> On 03/07/2012 07:27 PM, Novice wrote:
>> This is actually a discussion ...
>
> import java.io.Writer;
> import java.util.Locale;
> public interface Resume {
   Writer write(Template t);
> Writer write(Template t, Locale l);
> }
>
> public interface Template {
> Element root();
> }
>
> // ElementVisitor ana Element
> // swiped from javax.lang.model
>
> public interface ElementVisitor<R, P> {
> /**
> * Visits an element.
> * @param e the element to visit
> * @param p a visitor-specified parameter
> * @return a visitor-specified result
> */
> R visit(Element e, P p);
> }
>

Oops. skip the AttributeSet, you can include it in the P parameter.

> import java.util.List;
> public interface Element {
> <R, P> R accept(ElementVisitor<R, P> v, P p);
> Element enclosingElement();
> List<? extends Element> enclosedElements();
> }
>

[toc] | [prev] | [next] | [standalone]


#12784

FromJeff Higgins <jeff@invalid.invalid>
Date2012-03-08 19:24 -0500
Message-ID<jjbiio$p8v$1@dont-email.me>
In reply to#12765
On 03/08/2012 09:35 AM, Jeff Higgins wrote:
> On 03/08/2012 09:11 AM, Jeff Higgins wrote:
>> On 03/07/2012 07:27 PM, Novice wrote:
>>> This is actually a discussion ...
>>
>> import java.io.Writer;
>> import java.util.Locale;
>> public interface Resume {

Nah, skip all of that. I've decided to store my resume data in an 
instance of Candidate[1] and my resume output style in a stylesheet and 
transform via JAXP.

HR-XML Standards 3.2 Release
<http://www.hr-xml.org/>

[toc] | [prev] | [next] | [standalone]


#12786

FromJeff Higgins <jeff@invalid.invalid>
Date2012-03-08 19:36 -0500
Message-ID<jjbj84$t07$1@dont-email.me>
In reply to#12784
On 03/08/2012 07:24 PM, Jeff Higgins wrote:
> On 03/08/2012 09:35 AM, Jeff Higgins wrote:
>> On 03/08/2012 09:11 AM, Jeff Higgins wrote:
>>> On 03/07/2012 07:27 PM, Novice wrote:
>>>> This is actually a discussion ...
>>>
>>> import java.io.Writer;
>>> import java.util.Locale;
>>> public interface Resume {
>
> Nah, skip all of that. I've decided to store my resume data in an
> instance of Candidate[1] and my resume output style in a stylesheet and
> transform via JAXP.
>
> HR-XML Standards 3.2 Release
> <http://www.hr-xml.org/>

If you hate XML as a data storage format or already have a bunch of data 
in format X see:
<http://docs.oracle.com/javase/tutorial/jaxp/xslt/generatingXML.html>

[toc] | [prev] | [next] | [standalone]


#12889

FromNovice <novice@example..com>
Date2012-03-11 23:29 +0000
Message-ID<XnsA013C63B02665jpnasty@94.75.214.39>
In reply to#12760
Novice <novice@example..com> wrote in
news:XnsA00FC7119110Ajpnasty@94.75.214.39: 

[snip]

I think I need to put these questions aside for a bit and focus on more 
pressing programming needs, especially logging and error handling. In fact, 
that's pretty much what I HAVE been doing for the last several days ;-)

I probably shouldn't have started this thread until I had a bit more time 
to devote to it. I have read the responses Arved and Jeff made so far and 
found them interesting and thought-provoking. But I don't have the time 
just now to really follow through properly on the theme of this discussion. 

I'll start another thread on design of interfaces when I have more time.

Thanks to Jeff and Arved for their ideas!
-- 
Novice

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web