# Software Design

Software Design is a secondary research project aiming at creating a library of software design practices: short pieces of software design advice, like Make if condition positive, Create "deep" functions, or Extract loosely coupled parts of a class into smaller classes.

## Goals
### Collect questions for code review checklists

Most practices have a section "Checklist questions" in the beginning of the article. Accumulated from all pages, these questions could be used selectively in code review checklists.

### Connect ideas from books and online resources

A number of books are written on the topic of software design: "The Pragmatic Programmer", "Refactoring", "Clean Code", "A Philosophy of Software Design", "The Art of Readable Code", and many other popular books such as "Programming Pearls", "Effective Java", "Effective C++" include significant number of discrete software design advice, but all these books seldom reference each other. A goal of the Software Design project is to connect the software design ideas across programming languages by referring to the books from the corresponding articles on practices.
There are also online resources which should also be linked whenever relevant:
* C++ Core Guidelines
* .NET Framework Design Guidelines
* Effective Go and Go Code Review Comments
* Articles in the Software design category on Wikipedia
* Etc. (see more examples in Similar projects section below.

### Promote static analysis tools

When a software design practice or a convention can be enforced using an automated rule in some available static analysis tools, they should be linked from the article.

## Non-Goals
### Cover broader software development and engineering topics

The main scope of the Software Design project is the "static" properties of software, not the dynamics of engineering teams, project management, communication practices, development methodologies, etc. However, the effectiveness of software design practices cannot be analyzed in full separation from the broader software engineering topics, so the pages in this project are expected to discuss some aspects of software outside of the narrow scope of software design (such as testing, operations, reliability engineering), for example, making arguments for some practices.

## Research method

The research method of the project is analyzing how every practice affects the qualities of the software: whether it makes the code better or worse in terms of a specific quality.

#### Primary vs. high-level qualities

Many resources on software design operate with high-level qualities such as usability, steepness of learning curve, readability, understandability, maintainability, flexibility, easiness of change, and complexity (in a broader sense rather than in the narrower sense used in the project). These qualities are derived from a blend of lower-level primary qualities which are sometimes even at odds with each other. For example, readability is derived from obviousness, clarity, structuredness, and naturality.
Practices in the project should be analyzed in the context of primary, not high-level qualities. Consider these two statements:
* var c = a / b
* var yieldPerHectare: Double = totalYield / numHectares
The first is clearer, the second is more obvious. Which one is more readable is subjective because it depends on whether the reader prefers clarity or obviousness in code, as well as his familiarity with the codebase, the surrounding code, and other factors. Therefore, appealing to high-level qualities might be ambiguous and subjective which doesn't align with the goals of Software Design project.
Criterion for defining a quality: independence (at least, sometimes) from all other qualities.

### Neutral point of view

Software design is a subjective topic: different programmers value different primary software qualities differently. The Software Design project aims to maintain neutrality by objectively presenting how each practice and refactoring affects different primary software qualities, but not arguing that one quality is more important than another (after all, apart from being a subject for personal preferences, the relative importance of different primary qualities varies a lot from project to project, and even in different contexts and at different times within the same project).
The project includes completely opposite practices, for example:
* Call function's return variable "result" and Avoid a variable called "result"
* Create "deep" functions and Break up too large and complex functions

## Structure
### Practices

Practices are relatively focused, self-contained pieces of software design advice. The title for a practice should ideally be specific enough to be actionable alone: for this reason, for example, practice Extract parts of a class into smaller classes was renamed to Extract loosely coupled parts of a class into smaller classes.
The template for practice articles can be found on page Software Design/Practice. An example of a relatively well-developed practice article is Break up too large and complex functions. Many of the practice articles are currently of stub-level quality.
Practices are categorized by the level of software elements to which they are applied:
* Practices applying to statements, expressions, and variables
* Practices applying to functions
* Practices applying to configuration
* Practices applying to classes (also data structures, types, source code files, etc.)
More categories of this kind might be added in the future if some practices will be written, e. g. applying to packages, (sub)systems, components, if they cannot be generalized as practices applying to classes.
Another dimension in which practices are classified is the "area" of software design, such as naming, error handling, complexity management, etc. So far, these areas were added haphazardly as the practices were written. The list of currently identified areas is not complete nor coherent. It's likely that they will be reorganized when as more practices are written.

### Refactorings

There is no clear boundary between practices and refactorings: some articles can be classified as both, for example, Extract loosely coupled parts of a class into smaller classes. The structure and the [#Research method|analysis method]] for refactorings is the same as for practices: see the previous section.

### Qualities

Qualities in the Software Design project correspond to system quality attributes All qualities are broadly split into three categories:
* Software qualities, or external qualities: (money) cost, speed, resource usage, reliability, (binary) size, etc.
* Interface qualities: hard/easy to misuse, reliability, interface size (the number of elements), naturality, etc.
* Code qualities: complexity, modularity, easiness of change, robustness (against programming error), (screen) size, etc.
The template for quality articles can be found on page Software Design/Quality. An example of a relatively well-developed article about a quality is Software Design/Code robustness.

### Conventions
## Programming language of examples

Code examples in the project are mostly written in Kotlin but this is not a hard rule. val keyword should be avoided (var should be used instead) to make many examples also valid JavaScript, TypeScript, or Swift code.

## Terminology

For consistency, articles in the Software Design project should ideally use the same term for the same concept, even though many different names for the term exist, which is usually the case in different programming languages.

## Similar projects

* C++ Core Guidelines
* The Physics of Software
* Principles Wiki
* Java Practices
* CMU SEI Wiki