Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [stellation-res] To what extent should literals be named?

On Tue, Sep 03, 2002 at 11:19:49AM -0400, Dave Shields wrote:
> 
> In his workspace code audit, Jonathan Gossage wrote:
> 
>   The second point concerns the use of literal constants. While these
>   are very commononly used they represent bugs-in-waiting, especially
>   with open source projects. There are two major problems with them:
>  
>   a) They become a maintenance nightmare whenever it is necessary to
>   change the value of a literal. This is made worse where the same
>   literal may be used for several purposes. Does the value 0 here mean
>   the same as the value 0 there for example.
> 
>   b) It is not possible to use browsers to find where those literals
>   that have meaning in a specific context are used.
> 
>   <start rant>
>   My own policy has been to never use literal values for anything except
>   things like strings in debug and log messages. Everything else is made
>   a static constant in the class where the literals are relevant, or
>   occasionally in classes of their own.
>   <end of rant/>
> 
> Many of his suggested changes are to follow this policy, assigning
> names to many of the string literals currently used in the code.
> 
> Current policy is to name literals rarely, and to hopefully write code
> so that the context in which a literal is used indicates what the
> literal is naming. An example of existing usage can be found in
> repos/artifact/Artifact.java
> 
>     /**
>      * Names the artifact types.
>      */
>     public interface Type {
>         /**
>          * Note that the type names used here must be the same that are
>          * used to enter artifact types in the repository. In particular
>          * they must be in the same case.
>          */
> 
>         /**
>          * A compound artifact has type "Compound".
>          */
>         public static final String COMPOUND = "Compound";
> 
> This is done since the name of a Compound artifact is used throughout
> the repository and workspace code, and in accessing the database.
> 
> Jonathan favors a view closer to the other end of the spectrum -- to
> name every literal except those used in debug and error messages.
> 
> Here are some examples taken from current code to indicate what effect
> the proposed change would have. The question is how much would these
> changes improve readability?
> 
> From the main loop of Svc:
> 
>         else if (command.equals("clean")) {
>             new Change(context).command();
>         }
>         else if (command.equals("checkout")) {
>             new Checkout(context).command();
>         }
> 
> would become
> 
>         public Interface Command {
>             public static final String CLEAN = "clean";
>                 ...
>         }
>         ...
>         else if (command.equals("SVC.Command.CLEAN)) {
>             new Change(context).command();
>         }
>         else if (command.equals(SVC.Command.CHECKOUT)) {
>             new Checkout(context).command();
>         }

Close, but still not perfect: think about I18N...

florin

> 
> and related code in Change
> 
>         else if(commandName.equals("mv"))
>             mv();
>         else if (commandName.equals("rm"))
>             rm();
> 
> would become
> 
>         else if(commandName.equals(SVC.Command.MOVE))
>             mv();
>         else if (commandName.equals(SVC.Command.REMOVE))
>             rm();
> 
> I find that in the existing code it is clear that "clean" and
> "checkout" are command names.
> 
> From LogEntry, current
> 
>     public String getAction() {
>         return getAttribute("action");
>     }
> 
> would become
> 
>     public String getAction() {
>         return getAttribute(LogEntry.Item.ACTION);
>     }
> 
> Here the use of "action" is actually an implementation detail, as the
> caller of the method getAction() doesn't know that the string "action"
> has a special meaning -- it's part of the implementation.
> 
> From Checkout:
> 
>         boolean force = getOptions().get("force") != null;
> 
> would become
> 
>         boolean force = getOptions().get(SVC.Options.FORCE) != null;
> 
> Here the use of 'getOptions()' indicates that "force" is an option
> name, so is a name really needed.
> 
> From Test:
> 
>       if (getOptions().get("verbose","").equals("true")) {
> 
> would become
> 
>       if(getOptions().get(SVC.Options.VERBOSE,"").equals(SVC.Options.TRUE_VALUE)) {
> 
> I find it clear from context that "verbose" is an option value, and
> "true" is a possible option value.
> 
> From Fork:       
> 
>             context.getWorkspace().setState("0", projectSignature);
> 
> would become
> 
>             context.getWorkspace().setState(Workspace.STATE_ZERO,projectSignature);
> 
> The Javadoc for setState indicates the first parameter is a workspace
> state:
> 
>     /**
>      * Saves the signature associated with a state.
>      *
>      * @param state the state to which the signature is to be assigned.
>      * @param signature signature for the specified state
>      */
>     public void setState(String state, String signature) {
> 
> so it's clear that "0" in this context represents a workspace state.
> 
> Re Jonathan's point
> 
>   b) It is not possible to use browsers to find where those literals
>   that have meaning in a specific context are used.
> 
> I tend to use 'fgrep' for this task in Unix. For example here is
> result of fgrep '"checkout"' *.java in Workspace:
> 
>   Checkout.java:        getWorkspace().setAttribute("checkout", checkoutTime);
>   Checkout.java:                      .add("action","checkout")
>   List.java:                String value =  getWorkspace().getAttribute("checkout");
>   LogManager.java:        if (action.equals("checkout") || action.equals("checkin")) {
>   LogManager.java:            if (command.equals("co")) command = "checkout";
>   LogManager.java:            else if (selection.equals("co")) selection = "checkout";
>   Svc.java:        else if (command.equals("checkout")) {
>   Svc.java:        .add("checkout")
>   Svc.java:            if (commandName.equals("co")) commandName = "checkout"; // 'co' and 'configure' clash
>   Svc.java:            if (command.equals("co"))  command = "checkout";
> 
> I find no trouble from this seeing what each instance of "checkout"
> refers to, but I'm probably biased since I wrote the code.
> 
> My own view is to avoid naming literals except where there is good
> reason to do so, but I would like to hear what others have to say
> about this.
> 
> dave
> 
> -- 
> Dave Shields, IBM Research, shields@xxxxxxxxxxxxxx. 
> _______________________________________________
> stellation-res mailing list
> stellation-res@xxxxxxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/stellation-res
> 

-- 

"If it's not broken, let's fix it till it is."

41A9 2BDE 8E11 F1C5 87A6  03EE 34B3 E075 3B90 DFE4

Attachment: pgp8q_Fuptt6A.pgp
Description: PGP signature


Back to the top