A Decade of D - dconf.org · Umbrello UML Modeller Umbrello UML Modeller 2 supports ActionScript,...
Transcript of A Decade of D - dconf.org · Umbrello UML Modeller Umbrello UML Modeller 2 supports ActionScript,...
We Inform Passengers● countrywide systems, deployed all over europe● train, bus, tram, planes, ...● automated, manual intervention trouble situations● wide range of different interfaces● multilingual● announcements, displays, mobile, ...
Copyright: https://www.rosenheim24.de/bayern/muenchen-gueterzug-entgleist-umschlagbahnhof-riem-stoerungen-bahnbetrieb-9824593.html
Quality Requirements● highly reliable● high level of customization● maintainability
○ Test○ Clean Code○ Reviews
Why D?● neither C++ nor Java● new language to break old habits● run fast: native code● modern, convenient● unittest built-in
Tango with DPros
○ fast XML parser○ logging○ network protocols○ familiar class library
Cons
○ not what later became“The D Programming Language”
Short History● 2008: First experiment in Tango with D● 2009: Second experiment● 2010: Tango: “Tickets for the community”● 2010: Alexandrescu: “The D Programming Language”● 2011: Alexandrescu: “D1 to be discontinued on December 31, 2012”● 2012: SiegeLord: “Tango for D2: All user modules ported”● 2012: Poor poll results for D at Funkwerk● 2012: Porting to D2 and Phobos
Short History
● 2013: DConf: “Code Analysis for D with AnalyzeD”● 2015: GitHub: funkwerk● 2016: Meetup: Munich D Programmers● 2016: Add std.algorithm.iteration.cumulativeFold● 2017: Greenfield Passenger Information System in D● 2018: DConf: “A Decade of D”
Effective D● Prefer foreach loops to traditional for loops● Use std.algorithm or std.range instead● Take advantage of UFCS
○ 5.minutes
○ function chaining
● Take advantage of UFCS where appropriate○ don’t: “hello”.writeln○ don’t: “%s”.format(42) like in Python
(thankfully it’s format!”%s”(42) by now)
● ...
Contract Programmingassert
● evaluates expression● if the value is false,
AssertError is thrown● language keyword● for verifying the logic of the program● in principle provable● no run-time checks for -release version
enforce
● evaluates expression● if the value is false,
Exception (Throwable) is thrown● function template from std.exception● for validating data
Example: Theory and Practiceint div(int x, int y)
in
{
assert(y != 0);
}
out(z)
{
assert(x == y * z + x % y);
}
body
{
...
}
DIP 1003: Remove body as a Keywordint div(int x, int y)
in
{
assert(y != 0);
}
out(z)
{
assert(x == y * z + x % y);
}
do
{
...
}
DIP 1009: Add Expression-Based Contract Syntaxint div(int x, int y)
in(y != 0)
out(z; x == y * z + x % y)
{
...
}
Design by Contract● Non-Redundancy principle● Assertion Violation rule● Reasonable Precondition principle● Precondition Availability rule● Assertion Evaluation rule● Invariant rule
Design by Contract● Non-Redundancy principle
○ Under no circumstances shall the body of a routineever test for the routine’s precondition.
● Assertion Violation rule● Reasonable Precondition principle● Precondition Availability rule● Assertion Evaluation rule● Invariant rule
Design by Contract● Non-Redundancy principle● Assertion Violation rule
○ A run-time assertion violation is the manifestation of a bug in the software.○ A precondition violation is the manifestation of a bug in the client.○ A postcondition violation is the manifestation of a bug in the supplier.
● Reasonable Precondition principle● Precondition Availability rule● Assertion Evaluation rule● Invariant rule
Design by Contract● Non-Redundancy principle● Assertion Violation rule● Reasonable Precondition principle
○ Every routine precondition must satisfy the following requirements:■ The precondition appears in the official documentation
distributed to authors of client modules.■ It is possible to justify the need for the precondition
in terms of the specification only.
● Precondition Availability rule● Assertion Evaluation rule● Invariant rule
Design by Contract● Non-Redundancy principle● Assertion Violation rule● Reasonable Precondition principle● Precondition Availability rule
○ Every feature appearing in the precondition of a routinemust be available to every client to which the routine is available.
● Assertion Evaluation rule● Invariant rule
Design by Contract● Non-Redundancy principle● Assertion Violation rule● Reasonable Precondition principle● Precondition Availability rule● Assertion Evaluation rule
○ During the process of evaluating an assertion at run-time,routine calls shall be executed without any evaluation of the associated assertions.
● Invariant rule
Design by Contract● Non-Redundancy principle● Assertion Violation rule● Reasonable Precondition principle● Precondition Availability rule● Assertion Evaluation rule● Invariant rule
○ An assertion I is a correct class invariant for a class Cif and only if it meets the following two conditions:
■ Every creation procedure of C, when applied to arguments satisfying its preconditionin a state where the attributes have their default values, yields a state satisfying I.
■ Every exported routine of the class, when applied to arguments and a statesatisfying both I and the routine's precondition, yields a state satisfying I.
Subcontracting● Parents’ Invariant rule
○ The invariants of all the parents of a class apply to the class itself.
● Assertion Redeclaration rule
Subcontracting● Parents’ Invariant rule● Assertion Redeclaration rule
○ A routine redeclaration may only replace the original precondition by one equal or weaker,and the original postcondition by one equal or stronger.
In, Out and Inheritanceinterface I
{
int foo(int x)
in(x != 0)
out(y; y != 0);
}
class C : I
{
override int foo(int x)
in(false)
out(; true)
{
...
}
}
In, Out and Inheritanceinterface I
{
int foo(int x)
in(x != 0)
out(y; y != 0);
}
class C : I
{
override int foo(int x)
in(x != 0)
out(y; y != 0)
{
...
}
}
Contract ProgrammingPros
○ “null safety” instead of segmentation faults○ clear statement what is required and ensured○ clear statement who is to blame○ living documentation
Cons
○ often misused as wish machine○ gaps between synchronized in, out, and body○ Issue 15984 - [REG2.071]
Interface contracts retrieve garbage instead of parameters
Theoretical Unit Testingint div(int x, int y)
in(y != 0)
out(z; x == y * z + x % y)
{
...
}
// Don’t Try This at Home
unittest
{
div(5, 2);
div(-5, 2);
div(5, -2);
div(-5, -2);
}
xUnit Testing FrameworkHow to get as much information as possibleout of a failed test run?
GitHub: linkrope/dunit
○ replacement of Dunit (for D1)○ forked from GitHub: jmcabo/dunit○ user-defined attributes @Test, ...○ by now, based on latest version JUnit 5
Example: Testcase Classclass TrainTest
{
mixin UnitTest;
@BeforeEach
void setUp() ...
@Test
void testCase1() ...
@Test
void testCase2() ...
@AfterEach
void tearDown() ...
}
xUnit Testing Framework for DPros
○ tests are organized in classes○ tests are always named○ tests can reuse a shared fixture○ all failed tests are shown at once○ more information about failures○ progress indication○ XML test report in JUnitReport format
Cons
○ mixin UnitTest; is mandatory
Sentence Style for Naming Unit Testsclass TrainTest
{
mixin UnitTest;
@BeforeEach
void setUp() ...
@Test
void canBeDelayed() ...
@Test
void canBeCanceled() ...
@AfterEach
void tearDown() ...
}
@DisplayName...@("train can be delayed")
unittest
{
...
}
@("train can be canceled")
unittest
{
...
}
Pulling the Fixture into the unittestunittest
{
with (Fixture())
{
...
}
}
struct Fixture
{
static Fixture opCall() ... // set up
~this() ... // tear down
}
Test ExecutionGitHub: atilaneves/unit-threaded
○ tests can be named○ tests can be run selectively○ tests can be run in parallel○ subset of the features is compatible with built-in unittest
Expectations● assert
○ assert(answer == 42);
○ [email protected](5): unittest failure
● static assert
● assertEquals
● Fluent Assertions
Expectations● assert
● static assert○ static assert(answer == 42);
○ test.d(5): Error: static assert: 54 == 42 is false
● assertEquals
● Fluent Assertions
Expectations● assert
● static assert
● assertEquals○ assertEquals(42, answer);
○ [email protected](5): expected: <42> but was: <54>
● Fluent Assertions
Expectations● assert
● static assert
● assertEquals○ assertEquals(42, answer);
○ [email protected](5): expected: <42> but was: <54>
○ answer.assertEquals(42);
○ [email protected](5): expected: <54> but was: <42>
● Fluent Assertions
Expectations● assert
● static assert
● assertEquals
● Fluent Assertions○ answer.should.equal(42);
○ TBD
Mock Object FrameworkGitHub: funkwerk/dmocks
○ forked from GitHub: QAston/DMocks-revived○ reactivation of DMocks
Code CoverageWe use separate src and unittest directories.
GitHub: ohdatboi/covered
○ shows coverage result per file○ shows average coverage○ moves *.lst files out of the way
Umbrello UML ModellerUmbrello UML Modeller 2 supports ActionScript, Ada, C++, C#, D, IDL, Java™, Javascript, MySQL, andPascal source code.
UML to Duxmi2d
○ forward engineeringfrom class diagramsto D skeleton code
○ tries to keep existing code○ for Umbrello’s XMI
UML to Daxmi2d
○ forward engineeringfrom class diagramsto D skeleton code
○ tries to keep existing code○ for ArgoUML’s XMI
UML to DPros
○ living documentation○ generation of getters and setters○ documentation comments for contracts○ enforced style
■ one class per file■ fields first, then member functions■ (alphabetical) order of attributes
Cons
○ refactoring with a drawing tool sucks
PlantUMLASTVisitor <|-- Outliner
Outliner -> "*" Classifier
Classifier --> "*" Field
Classifier --> "*" Method
D to UMLGitHub: funkwerk/d2uml
○ reverse engineeringfrom D source codeto PlantUML class outlines
Example: Self-Portrait!include classes.plantuml
main .> Outliner
ASTVisitor <|-- Outliner
Outliner -> "*" Classifier
Classifier --> "*" Field
Classifier --> "*" Method
Outliner ..> outliner
D to UMLPros
○ living documentation○ easy retrofitting
Cons
○ no support for relationships between classes(good arrangement is essential for creating effective diagrams)
○ no code generation
Generate Getters, SettersGitHub: funkwerk/accessors
import accessors;
class C
{
@Read
@Write
private int bar_;
mixin(GenerateFieldAccessors);
}
Generate Getters, SettersGitHub: funkwerk/accessors
import accessors;
class C
{
@Read
@Write
private int bar_;
mixin(GenerateFieldAccessors);
}
Generate Getters, Setters and EverythingGitHub: funkwerk/boilerplate
import boilerplate;
class C
{
...
mixin(GenerateFieldAccessors);
mixin(GenerateInvariants);
mixin(GenerateThis);
mixin(GenerateToString);
}
Dependency Tool“The overall structure of the system may never have been well defined.If it was, it may have eroded beyond recognition.” (Big Ball of Mud)
GitHub: funkwerk/depend
○ visualizes import dependencies○ checks actual import dependencies
against a UML model of target dependencies○ considers module or package dependencies
Example: model-view-controllerpackage model {}
package view {}
package controller {}
controller ..> view
controller ..> model
view .> model
depend: Check Dependencies
error: unintended dependency controller.controller -> model.modelerror: unintended dependency controller.controller -> view.viewerror: unintended dependency view.view -> model.model
SummaryCode For The Maintainer
○ Use Contract Programming○ Write Helpful Unit Tests○ Safeguard the Structure