Skip to content

DevelopmentGuidelines

David Nichols edited this page Jun 12, 2016 · 5 revisions

Qore Development Guidelines and Best Practices

Parse Options

Motivation: Code Maintainability, Performance, Forward-Compatibility

The following parse options are recommended for use in all Qore code.

Directive Description
%new-style allows for more a compact syntax and therefore less typing; note that the old2new script in the Qore source repository "examples/" directory can be used to convert code from old-style to new-style
%require-types serves for more maintainable code; old-style typeless code is much harder to understand and maintain, additionally, code with type declarations executes faster and more efficiently due to optimizations that can be made by the runtime engine when types are restricted in advance. Furthermore more programming errors can be caught at parse time which allows for faster and higher-quality development.
%strict-args eliminates NOOP and RUNTIME_NOOP code variants from being used and also causes errors with argument passing to be raised instead of being silently ignored (which can hide errors).
%enable-all-warnings allows for more errors to be caught at parse time, allowing for faster development at a higher quality.

Use of Modules

Motivation: Code Maintainability

Use existing binary and user modules when possible for the following reasons:

  • save development time: instead of re-inventing the wheel, use an already-implemented solution
  • reduce maintenance: by using well-documented shared infrastructure that all Qore programmers should be familiar with, the code should be clearer and easier to maintain

If a module does not do exactly what you require, then consider extending the module (for example: subclassing classes provided by the module).

Also please consider submitting patches to Qore if you have an improvement to an existing module; patches are always welcome!

Also please submit bug reports for bugs, and also feature suggestions are always welcome as well.

Working with SQL and Databases

Note: It's always good to ask somebody if you are working on something unusual, complicated, or with unclear performance characteristics when working with databases.

Use Bind by Value

Motivation: Performance / Operability

Always use "bind by value" (%v) if you have to use SQL directly; do not use dynamic SQL (ex: %s or %d with arguments or dynamically adding expressions to SQL strings); exceptions to this rule must have a solid justification.

See Oracle Bind By Value Howto.

Oracle databases in particular have an SQL statement cache, and by using dynamic SQL, the statement cache becomes less efficient and eventually unusable which adversely impacts the operability of the database server.

Use the SqlUtil Module for SQL

Motivation: Performance / Maintainability / Security

Using the SqlUtil module has the following advantages:

  • the SQL generated is database-independent
  • database-specific optimizations can be automatically employed by SqlUtil without requiring programming expertise for the specific database being used
  • eliminate dynamic SQL and therefore use the database server's SQL statement cache more efficiently (if applicable)
  • prevent SQL injection attacks

Exceptions to this rule are when SqlUtil's functionality cannot cover the desired use case, in this case provide feedback into product development to analyze if SqlUtil's API cannot be enhanced to cover the use case.

Use Indexing Appropriately

Motivation: Performance

When working with large databases or tables, it's important to write queries that effectively use the available indexes. Make sure you understand the indexing scheme on the tables you are using, and use indexes appropriately so that the SQL can be executed efficiently even with very large data volumes.

If the indexing scheme of a table is not clear in a specification and you believe that data volumes will be large enough at some point in time to make indexing relevant, ask for clarification, and if possible suggest some needed indexes for the operations to be executed by Qorus.

Always Use Efficient Streaming Processing When Possible

Motivation: Performance, Operability

Because we are processing very large amounts of data and have limited memory resources, it's necessary to use streaming or piecewise (ie SAX-style) processing rather than DOM-style processing whenever possible. Using "all-at-once" style processing is normally slower and could lead to memory starvation / system thrashing in extreme cases.

See the following sections for specific examples.

Use SAX Parsing Instead of DOM Parsing with XML

Motivation: Performance, Operability

Use FileSaxIterator and SaxIterator for XML parsing instead of DOM-style parse_xml(); for example:

FileSaxIterator recs(sd.filename, "stockinfo");
# perform mapping and submit row for bulk DML insertion
map mapper.queueBatchRow($1), recs;

Use the CsvUtil Module to Parse and Create CSV Files or Files with Flexible-Length Records

Motivation: Performance, Operability

The CsvUtil module contains classes for parsing and creating CSV or other similar flexible-length record file data using piecewise APIs.

Use the FixedLengthUtil Module to Parse and Create Files with Fixed-Length Records

Motivation: Performance, Operability

The FixedLengthUtil module contains classes for parsing and creating files based on fixed-length records using piecewise APIs.

Developing Modules or Shared APIs

Adhere to All "ProTips" for the Most Efficient Code

Motivation: Code Quality

Refer to this page and ProTips

Follow all Documentation Guidelines

Motivation: Code Reusability

follow all Documentation Guidelines to ensure that APIs are reusable by others and all behavior is known and documented.