Updated for release version: 1.0.21-alpha
This page introduces the concept of coding standards, and how they are implemented in the modelGUI project.
Introduction
Coding standards are a set of guidelines and regulations that should be followed when developing a software project. This is particularly important for projects which are intended to be released to and extended by a community process, because it facilitates the process of interfacing with existing code, understanding existing implementation details, and scaling a project without sacrificing its conceptual simplicity.
Naming and Case Styles
Classes should be given names that best describe their purpose, and should use upper camel case: MyClassName
Methods should be given names that clearly indicate their function, including the standard "get" and "set". They should use camel case: getSomeValue()
Arguments and variables should have longer names that clearly indicate what value they represent (i.e., "column_name" rather than "cname"). They should use snake case: my_variable_name.
Note: You may notice that in existing ModelGUI code, these styles are not always followed. This is a legacy issue; a good practice is to refactor these names as you encounter them to improve compliance. For well-used classes or methods, this is best accomplished using an IDE like Eclipse.
Header Stuff
Every class should start with a copyright and license comment, followed by package and import statements. The latter should be organized into blocks, separated by single lines. IDEs like Eclipse can organize this automatically.
/* * Copyright (C) 2021 The ModelGUI Project <http://mgui.wikidot.com> * * This file is part of ModelGUI[core] (mgui-core). * * ModelGUI[core] is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ModelGUI[core] is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ModelGUI[core]. If not, see <http://www.gnu.org/licenses/>. */ package mgui.interfaces; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; import javax.vecmath.Point3f; import mgui.geometry.Mesh3D; import mgui.interfaces.InterfaceSession; import mgui.interfaces.logs.LoggingType; import mgui.numbers.MguiFloat; import mgui.numbers.MguiInteger;
API Documentation
API documentation is best done in Java through the use of Javadoc. This means that much of the documentation can be contained directly in the source code it describes. In Sun's terminology, these type of comments are called "Doc comments", and are well described here. In the mgui project, all class declarations and public methods should have doc comments. In the case of class declarations, these should contain at least a description of the class's purpose, and tags for the author and version; here is the declaration of the DataSource class:
/************************* * Acts as a port into the JDBC interface. Specific data source objects should extend this * class's basic implementations. In general, communicates to database drivers (e.g. LDBC?) * to retrieve, modify, and store data using SQL statements. * * <p>Can also: * * <ul> * <li>Build a DataTableSet from meta data * <li>Create/delete databases * </ul> * * @author Andrew Reid * @version 1.0 * @since 1.0 * */ public class DataSource extends AbstractInterfaceObject implements Cloneable, IconObject{ ... }
Method comments should describe what the method does; they can be thought of as a contract between the method and its caller. All public methods should be prefaced by doc comments which describe their purpose, the parameters they take (and their expected value range), the values they return (if any), and their expected behaviour. An example is the getProjectedPoint method from the GeometryFunctions class:
/************************* * Project point <code>pt</code> onto plane <code>plane</code>, along <code>plane</code>'s * normal vector. Return a <code>Point2f</code> whose coordinates are relative to <code>plane</code>'s base * point and x- and y-axes. * * @status approved * @param pt Point to test * @param plane Plane to test * @return */ public static Point2f getProjectedPoint(Point3f pt, Plane3D plane){ ... }
You may note the custom Javadoc tag "@status". This is an mgui-specific tag which informs a developer of whether the method should be trusted or not. Its possible values are:
approved: The method has been tested and approved for use.
experimental: The method has been implemented, but not tested, so the results are not necessarily correct.
unimplemented: The method has not been implemented.
If such a tag is not provided, it can be assumed to be approved.
You may also note the use of the <code>..</code> wrapper. In line with Sun's guidelines, all references to classes or methods should be wrapped in this way so that they appear as teletype in the Javadoc documentation (you might notice that the same standard is applied to this wiki site).
Annotation
Overridden methods, or methods which implement an interface, should use the "@Override" annotation before their declarations, which is useful information for developers, and an easy way to prevent silly mistakes, such as misspelling an overridden method name, etc. There is a discussion of this here. See the "Inheritance" section for an example.
Packages
The organization of classes into packages is a very useful way to relate implementation to the underlying conceptual model. This provides a useful guide for developers and helps modularize the code base for the purpose of scalability. mgui defines a number of key package names which are summarized in the following table. The table is sorted by precedence, which indicates the order in which packages should be arranged, if they are combined; for instance, since the interfaces name has a higher precedence than the io name, a combined package would be interfaces.io, rather than io.interfaces.
package name | descripton |
---|---|
mgui | This is the top-level package for all classes included in the mgui project. Thus every package should be a subpackage of mgui. |
interfaces | This name indicates that all classes and subpackages are related to instances of InterfaceObject. This includes all instances of InterfacePanel and InterfaceGraphic. |
io | This name indicates that all classes and subpackages are related to I/O functions. This includes all instances of FileLoader and FileWriter, and helper classes such as InterfaceIOOptions. |
domestic | This name indicates that all classes and subpackages are related to (generally I/O related) functions which are domestic to mgui. |
foreign | This name indicates that all classes and subpackages are related to (generally I/O related) functions which are foreign to mgui. |
datasources | This name indicates that the classes and subpackages are related to JDBC data connectivity. |
geometry | This name indicates that all classes and subpackages are related to geometric entities or functions. This includes all instances of Shape, and all utility classes, such as GeometryFunctions, which implement Utility. |
shapes | This name indicates that all classes and subpackages are related to shapes and shape functions. This includes all instances of Shape or InterfaceShape. |
trees | This name indicates that all classes and subpackages are related to tree functionality; i.e., classes which are used to render tree nodes and/or interact with events on InterfaceTree and InterfaceTreePanel. |
util | This name indicates that all classes and subpackages perform or facilitate the performance of utility functions, such as mathematics, numbers, or any computationally expensive algorithms. |
Inheritance
Wherever possible, inheritance should be utilized to provide a hierarchical structure of entity classes, with the most generic form as a root and the most specific form as a leaf. This is demonstrated, for instance, by the inheritance path Mesh3DInt extends Shape3DInt extends InterfaceShape extends AbstractInterfaceObject implements InterfaceObject. Additionally, an effort should be made to ensure that any methods which can be implemented (at least in part) at a high level, should be thus implemented. This is demonstrated, for instance, by the getTreeNode method of the abstract class AbstractInterfaceObject:
/********************************************************* * Issues a new tree node and sets it using {@link setTreeNode}. The tree node is stored in this object, which * facilitates their destruction when necessary (e.g., when this object is destroyed). All issued tree nodes can * informed of changes to their user object using the method {@link updateTreeNodes}. * * @return a new <code>InterfaceTreeNode</code> */ @Override public InterfaceTreeNode getTreeNode(){ InterfaceTreeNode treeNode = new InterfaceTreeNode(this); setTreeNode(treeNode); treeNodes.add(treeNode); return treeNode; }
This structure allows method implementations which operate on top-level classes, rather than defining individual methods for "leaf" classes. The higher up a class hierarchy can implement its methods, the simpler the code will be to understand and to extend or modify.
Exception Handling and Logging
Exceptions should always be handled (see this discussion). ModelGUI provides a standard means of reporting and dealing with caught exceptions. Firstly, explicit stack trace dumps should be avoided. If stack traces are desired (e.g., for testing and debugging), they can be passed to the static method InterfaceSession.handleException. This method will display stack traces only if the session is set to Debug or Verbose logging modes.
Logging an Exception can be done via the static method InterfaceSession.log. This method logs the event, with an optional timestamp, based upon the logging mode of the current session, and the logging type specified as an argument (see LoggingType).
try{ ...some I/O operation... }catch (IOException ex){ InterfaceSession.handleException(ex); InterfaceSession.log("Some exception occurred.", LoggingType.Errors); }
The logging types are:
- Errors: Will always be logged
- Concise: Will always be logged unless environment logging type is Errors
- Verbose: Will only be logged if environment logging type is Verbose or Debug
- Debug: Will only be logged is environment logging type is Debug