Difference between revisions of "Agile TDD for Embedded Systems and Legacy Code: Course PLUS Your-Legacy-Code Clinic"

 
(2 intermediate revisions by the same user not shown)
Line 8: Line 8:
  
  
TDD is powerful and practical. It’s the practice of always writing test code before the code to be tested, in small micro-test-and-develop cycles. In addition to the obvious benefits that (1) tests actually get written and executed for most code with thorough test coverage and (2) the practice and mindset of "building quality in" by test-FIRST rather than test-LAST (which tries to "inspect old defects out"), a more subtle but important benefit is that (3) when we start by thinking very concretely—with code—in the role of a calling client to the new code before it is written, it (4) clarifies our design, (5) tends to create better designs with lower coupling, higher cohesion, and flexible dependency injection, (6) and becomes a more fun and creative way to combine writing tests with code. Hence, TDD is far more than "just testing" — it is a kind of creative micro-design step.
+
TDD is powerful and practical. It’s the practice of always writing test code before the code to be tested, in small micro-test-and-develop cycles. In addition to the obvious benefits that (1) tests actually get written and executed for most code with thorough test coverage and (2) the practice and mindset of "building quality in" by test-FIRST rather than test-LAST (which tries to "inspect old defects out"), a more subtle but important benefit is that (3) when we start by thinking very concretely—with code—in the role of a calling client to the new code before it is written, it (4) clarifies our design, (5) tends to create better designs with lower coupling, higher cohesion, and flexible dependency injection, (6) and becomes a more fun and creative way to combine writing tests with code. Hence, TDD is far more than "just testing" — it is a kind of creative micro-design step that drives better design.
<br>
+
 
<br>
+
 
In this course you will learn how to think in and apply test-driven design and programming, and establish it as a consistent method for your development team. You’ll learn and work with the popular TDD framework JUnit (if Java, or one of the other popular xUnit frameworks if working in another language).  
+
In this course you will learn how to think in and apply TDD, and establish it as a consistent behavior for your development team, in the context of embedded-systems design and C++ and/or C. You’ll learn and work with a popular free open-source TDD frameworks useful for embedded systems, such as Google Test, CppUTest, Unity, Google Mock, and C Mock.
<br>
+
 
<br>
+
 
 
TDD quickly leads developers to see the need for and value of reducing coupling in their code, and for techniques to break dependencies so that tests can be run quickly in isolation. Thus, a critical adjunct skill in TDD is learning how to create and inject alternate “test doubles” (fakes, stubs, ...). In this course you will learn how to create stubs, fakes, mocks, object factories/mothers, how to break dependencies, and how to  apply  dependency injection methods.  
 
TDD quickly leads developers to see the need for and value of reducing coupling in their code, and for techniques to break dependencies so that tests can be run quickly in isolation. Thus, a critical adjunct skill in TDD is learning how to create and inject alternate “test doubles” (fakes, stubs, ...). In this course you will learn how to create stubs, fakes, mocks, object factories/mothers, how to break dependencies, and how to  apply  dependency injection methods.  
<br>
+
 
<br>
+
 
Learning how to break dependencies for testing in isolation is especially important in the context of legacy code; in this course you will to work with legacy code to “bring it under test” and apply TDD.
+
Learning how to break dependencies for testing in isolation is especially important in the context of legacy code; in this course you will to work with your legacy code to break dependencies, “bring it under test”, introduce flexible configuration in your code, and apply TDD.
<br>
+
 
<br>
+
 
Refactoring is a disciplined design skill to improve the structure of code without changing its external behavior. And refactoring is part of the TDD cycle. Thus, in this course you will learn the various “code smells” and the refactorings to clean them up. Refactoring depends on automated refactoring tools built into popular IDEs or editors, such as Netbeans, Eclipse, SlickEdit, or emacs; thus in this course you will learn to apply an automated refactoring tool.
+
Refactoring is a disciplined design skill to improve the structure of code without changing its external behavior. And refactoring is part of the TDD cycle. Thus, in this course you will learn the various “code smells” and the refactorings to clean them up. Refactoring is aided on automated refactoring tools built into popular IDEs or editors, such as the Eclipse CDT, SlickEdit, or emacs; thus in this course you will learn to apply an automated refactoring tool, in addition to manual refactoring.
Finally, the course includes a brief introduction to the companion agile methods practice called Acceptance TDD—executable requirements with automated verification. You will learn about the popular FIT framework and the Acceptance TDD methodology.
+
 
 +
 
 +
STEP ONE - Course (2-3 days): You will learn to apply all these skills in the context of an exercise to develop a device driver or other low-level embedded-systems components in C or C++ while applying TDD and refactoring.
 +
 
 +
 
 +
STEP TWO - Clinic/Workshop (2-3 days): Now, onwards to the messy reality of your existing legacy code. The teacher/coach will start by demonstrating how to work with your embedded-systems legacy code, to break dependencies and apply TDD and refactoring, in a "coding dojo" style workshop. This is followed by small groups of the developers (for example, 2 people together), working in parallel on different sections of their legacy code to break dependencies, bring it "under test", and start to apply TDD and refactoring to it. During this phase, the coach will rotate across all the groups, giving guidance and feedback. There will also be some periods of "show and tell", looking at the existing solutions the smaller groups are creating with your legacy code.  
  
  
Line 37: Line 42:
  
 
== Prerequisites ==
 
== Prerequisites ==
skill in an object-oriented programming language
+
skill in programming; knowledge of your legacy code
  
  
Line 43: Line 48:
 
Upon completion of this course, students should be able to:
 
Upon completion of this course, students should be able to:
 
* apply TDD
 
* apply TDD
* break dependencies and create “test doubles” (fakes, mocks, stubs, ...)
+
* break dependencies in your legacy code and create “test doubles” (fakes, mocks, stubs, ...)
 
* inject dependencies with flexible techniques
 
* inject dependencies with flexible techniques
* separate test set up code into object factories or “object mothers”
+
* separate test set up code into clear, reusable elements
 +
* create low-level embedded components (such as a device driver) with TDD
 +
* write "clean code"
 
* identify code smells
 
* identify code smells
 
* apply refactorings
 
* apply refactorings
* use an xUnit framework such as Junit
+
* use embedded-suitable xUnit frameworks such as Google Test, CppUTest, Unity, Google Mock, or C Mock
 
* bring legacy code “under test”
 
* bring legacy code “under test”
* define acceptance TDD and the FIT framework
 
  
  
== Outline ==
+
== Special C, C++ and Embedded Topics (introduced as needed) ==
* Test-Driven Development
+
* implementing abstract data types (ADTs) in C -- "objects in C"
* Method and motivation
+
* single-instance and multi-instance ADTs
* Writing tests first
+
* agile modeling with ADTs, and mapping agile models to C
* The TDD lifecycle
+
* weak versus strong ADTs
* Testing in an iterative and agile method
+
* unit TDD for C/C++
* Categories of TDD: unit, acceptance
+
* test doubles for C/C++ with polymorphic- ,link- , preprocessor- , meta-programming-  (functors and function pointers), and configuration seams
* TDD tools and frameworks
+
* test-doubles for lower-level components: device drivers, etc.  
* Testing in different architectural layers
+
* create device drivers and other low-level components with TDD in C++ and/or C
* TDD Tools
+
* clean code and refactoring in C/C++
* JUnit
+
* dual targeting and TDD
* Unit TDD
+
* mock objects in C and C++
* Practice with XUnit
+
* combining C, C++, assembler, and inline assembler
* Code smells
 
* Refactorings, including Extract Method, Introduce Explaining Variable, and dozens more
 
* Test Doubles: Fakes, Stub and Mock Objects
 
* Integration vs. unit testing
 
* Setting up the test environment
 
* Mock generation tools
 
* Object factories
 
* Object Mother pattern
 
* Dependency injection
 
* Dependency injection with Spring
 
* Continuous Integration and TDD
 
* Information radiators for CI
 
* Why do people delay integration?
 
* Acceptance TDD with FIT
 
* TDD and Legacy Code
 
* Characterization tests
 
* The Legacy TDD life cycle
 
  
  
 
== Related Courses ==
 
== Related Courses ==
Before:
+
* [[Embedded C - Agile Software Development: Hands-on Practices, Principles, Agile Modeling, and TDD]]
* [[Agile Software Development: Hands-on Practices, Principles, Agile Modeling, and TDD]]
+
* [[Embedded C++ - Agile Software Development: Hands-on Practices, Principles, Agile Modeling, and TDD]]
After:
 
* [[Agile Acceptance Test-Driven Development: Requirements as Executable Tests]]
 
 
 
  
  

Latest revision as of 16:53, 4 June 2011

Overview

4-5 days.

This is a combination of a 2-3 day course with structured learning exercises, FOLLOWED BY a 2-3 day "clinic" or workshop applying the skills to your existing legacy code. (For a total of 4-5 days; the exact timing is content dependent on the knowledge of the developers, the state of the legacy code, and the legacy problems to tackle).


This information-packed and hands-on course shows developers and technical leaders how to apply test-driven development (TDD) and refactoring in the context of embedded systems and your related legacy code — almost always, C and/or C++, perhaps combined with some assembler.


TDD is powerful and practical. It’s the practice of always writing test code before the code to be tested, in small micro-test-and-develop cycles. In addition to the obvious benefits that (1) tests actually get written and executed for most code with thorough test coverage and (2) the practice and mindset of "building quality in" by test-FIRST rather than test-LAST (which tries to "inspect old defects out"), a more subtle but important benefit is that (3) when we start by thinking very concretely—with code—in the role of a calling client to the new code before it is written, it (4) clarifies our design, (5) tends to create better designs with lower coupling, higher cohesion, and flexible dependency injection, (6) and becomes a more fun and creative way to combine writing tests with code. Hence, TDD is far more than "just testing" — it is a kind of creative micro-design step that drives better design.


In this course you will learn how to think in and apply TDD, and establish it as a consistent behavior for your development team, in the context of embedded-systems design and C++ and/or C. You’ll learn and work with a popular free open-source TDD frameworks useful for embedded systems, such as Google Test, CppUTest, Unity, Google Mock, and C Mock.


TDD quickly leads developers to see the need for and value of reducing coupling in their code, and for techniques to break dependencies so that tests can be run quickly in isolation. Thus, a critical adjunct skill in TDD is learning how to create and inject alternate “test doubles” (fakes, stubs, ...). In this course you will learn how to create stubs, fakes, mocks, object factories/mothers, how to break dependencies, and how to apply dependency injection methods.


Learning how to break dependencies for testing in isolation is especially important in the context of legacy code; in this course you will to work with your legacy code to break dependencies, “bring it under test”, introduce flexible configuration in your code, and apply TDD.


Refactoring is a disciplined design skill to improve the structure of code without changing its external behavior. And refactoring is part of the TDD cycle. Thus, in this course you will learn the various “code smells” and the refactorings to clean them up. Refactoring is aided on automated refactoring tools built into popular IDEs or editors, such as the Eclipse CDT, SlickEdit, or emacs; thus in this course you will learn to apply an automated refactoring tool, in addition to manual refactoring.


STEP ONE - Course (2-3 days): You will learn to apply all these skills in the context of an exercise to develop a device driver or other low-level embedded-systems components in C or C++ while applying TDD and refactoring.


STEP TWO - Clinic/Workshop (2-3 days): Now, onwards to the messy reality of your existing legacy code. The teacher/coach will start by demonstrating how to work with your embedded-systems legacy code, to break dependencies and apply TDD and refactoring, in a "coding dojo" style workshop. This is followed by small groups of the developers (for example, 2 people together), working in parallel on different sections of their legacy code to break dependencies, bring it "under test", and start to apply TDD and refactoring to it. During this phase, the coach will rotate across all the groups, giving guidance and feedback. There will also be some periods of "show and tell", looking at the existing solutions the smaller groups are creating with your legacy code.


Methods of Education

Discussion, presentation, Q&A, workshop exercises


Audience

Developers, architects, test engineers, technical leaders.


Level

Intermediate: This course introduces concepts and techniques that the attendee will apply during the workshop.


Prerequisites

skill in programming; knowledge of your legacy code


Objectives

Upon completion of this course, students should be able to:

  • apply TDD
  • break dependencies in your legacy code and create “test doubles” (fakes, mocks, stubs, ...)
  • inject dependencies with flexible techniques
  • separate test set up code into clear, reusable elements
  • create low-level embedded components (such as a device driver) with TDD
  • write "clean code"
  • identify code smells
  • apply refactorings
  • use embedded-suitable xUnit frameworks such as Google Test, CppUTest, Unity, Google Mock, or C Mock
  • bring legacy code “under test”


Special C, C++ and Embedded Topics (introduced as needed)

  • implementing abstract data types (ADTs) in C -- "objects in C"
  • single-instance and multi-instance ADTs
  • agile modeling with ADTs, and mapping agile models to C
  • weak versus strong ADTs
  • unit TDD for C/C++
  • test doubles for C/C++ with polymorphic- ,link- , preprocessor- , meta-programming- (functors and function pointers), and configuration seams
  • test-doubles for lower-level components: device drivers, etc.
  • create device drivers and other low-level components with TDD in C++ and/or C
  • clean code and refactoring in C/C++
  • dual targeting and TDD
  • mock objects in C and C++
  • combining C, C++, assembler, and inline assembler


Related Courses


Maximum Participants

16


Environment - Room, Tools, Texts

Course Environment - Workshop Style4