The document discusses test-driven development (TDD) and refactoring. It provides examples of unit test fixtures, exercising the system under test (SUT), and verifying results. It also discusses refactoring code to remove smells like duplicated code through techniques like extracting methods. The goal is to use TDD to write code that works and is clean through small, incremental changes while ensuring it continues to work by passing all tests.
What is Code Refactoring?
Refactoring refers to structuring the code to:
- Increase readability of code
- Fix bugs easily
- Enhance design
- Introduce flexibility to code.
Refactoring is to restructure or rewrite source code to improve internal consistency, readability, etc. without changing its function.
This presentation is continuation to “Software Craftsmanship - Code Smells - Couplers”. Here we will cover fourth category of code smells – “Object Orientation Abusers”.
Learn how to get the best out of Camunda Tasklist, an HTML 5 application for human workflow management. You will also hear how to benefit from the Camunda Javascript forms SDK in your very own frontend applications.
What is Code Refactoring?
Refactoring refers to structuring the code to:
- Increase readability of code
- Fix bugs easily
- Enhance design
- Introduce flexibility to code.
Refactoring is to restructure or rewrite source code to improve internal consistency, readability, etc. without changing its function.
This presentation is continuation to “Software Craftsmanship - Code Smells - Couplers”. Here we will cover fourth category of code smells – “Object Orientation Abusers”.
Learn how to get the best out of Camunda Tasklist, an HTML 5 application for human workflow management. You will also hear how to benefit from the Camunda Javascript forms SDK in your very own frontend applications.
Tutorial on developing a Solr search component pluginsearchbox-com
In this set of slides we give a step by step tutorial on how to develop a fully functional solr search component plugin. Additionally we provide links to full source code which can be used as a template to rapidly start creating your own search components.
Fighting Fear-Driven-Development With PHPUnitJames Fuller
This talk was designed for PHP developers with limited or no experience in unit testing. I focus on describing the problem of fear-driven-development, and how test-driven-development can be used to improve the quality of your code.
Breaking Dependencies to Allow Unit TestingSteven Smith
Unit testing software can be difficult, especially when the software wasn't designed to be testable. Dependencies on infrastructure concerns and software we don't control are one of the biggest contributors to testing difficulty. In this session, you'll learn the difference between unit tests and other kinds of tests, how to recognize and invert dependencies, and how to unit test your code's interactions with these dependencies without testing the infrastructure itself.
Presented at FalafelCON 2014, San Francisco, September 2014
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014FalafelSoftware
Unit testing software can be difficult, especially when the software wasn't designed to be testable. Dependencies on infrastructure concerns and software we don't control are one of the biggest contributors to testing difficulty. In this session, you'll learn the difference between unit tests and other kinds of tests, how to recognize and invert dependencies, and how to unit test your code's interactions with these dependencies without testing the infrastructure itself.
Property Based Testing is an process to build robust systems.
It facilitates a deeper understanding of the system under test. It can be used on any testing level: unit, integration or functional.
The presentation introduces how Property Based Testing works, how to use it with PHPUnit, and in what way it differentiates from example based tests.
It talks about strategies to find good properties to check for.
This presentation was built for the Meet-Magento conference 2020 in Mumbai.
www.denizoguz.com-For an in company JDK 7 orientation I have prepared a presentation which summaries new features of JDK 7. I would like to make it public for everyone who needs it.
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)Jen Wong
FitNesse is a wiki-based software testing tool that can be a powerful addition to your Continuous Integration Environments. Its greatest advantages include providing visibility into tests and results, and providing access to test-writing by non-technical team members. We will:
* look at specific examples and code,
* discuss the advantages and drawbacks of using FitNesse as a test framework
* implement, deploy, and use a simple fixture in a fitnesse test
* review different kinds of fixtures, including decision table, script, query, html, and selenium webtest fixtures
* discuss some of the more interesting fixture extensions we've implemented, including JSON-based verification and the ability to pass in javascript code for dynamic verification
* use Hudson/Jenkins to run your FitNesse tests as a step in your Continuous Integration/Deployment process
TDD is now mainstream but a lot people don't know or don't remember what is its purpose. TDD is about software design not testing or catching bug. TDD helps developers to shape and create software with "good" design, what is a "good" design is something that we will discuss in the topic.
This workshop is a hands-on training where a real Zend Framework application is used as an example to start improving QA using tools to test, document and perform software metric calculations to indicate where the software can be improved. I also explain the reports produced by a CI system.
What went wrong for my clients in the past 6 years trying to implement Microservice Architectures? This is a retrospective, a list of things we must to avoid to gainable with this kind of software architecture.
Not so many years have passed since we started programming computers and even less since programming computers has been recognised as a profession. Even still, so many things depend on the quality of our work. What does it mean to be professional? What are we expected to do? Are we up for the task? I will talk about my journey of becoming the programmer of my dreams, the obstacles I've faced and the strategies that I've applied to overcome them
Tutorial on developing a Solr search component pluginsearchbox-com
In this set of slides we give a step by step tutorial on how to develop a fully functional solr search component plugin. Additionally we provide links to full source code which can be used as a template to rapidly start creating your own search components.
Fighting Fear-Driven-Development With PHPUnitJames Fuller
This talk was designed for PHP developers with limited or no experience in unit testing. I focus on describing the problem of fear-driven-development, and how test-driven-development can be used to improve the quality of your code.
Breaking Dependencies to Allow Unit TestingSteven Smith
Unit testing software can be difficult, especially when the software wasn't designed to be testable. Dependencies on infrastructure concerns and software we don't control are one of the biggest contributors to testing difficulty. In this session, you'll learn the difference between unit tests and other kinds of tests, how to recognize and invert dependencies, and how to unit test your code's interactions with these dependencies without testing the infrastructure itself.
Presented at FalafelCON 2014, San Francisco, September 2014
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014FalafelSoftware
Unit testing software can be difficult, especially when the software wasn't designed to be testable. Dependencies on infrastructure concerns and software we don't control are one of the biggest contributors to testing difficulty. In this session, you'll learn the difference between unit tests and other kinds of tests, how to recognize and invert dependencies, and how to unit test your code's interactions with these dependencies without testing the infrastructure itself.
Property Based Testing is an process to build robust systems.
It facilitates a deeper understanding of the system under test. It can be used on any testing level: unit, integration or functional.
The presentation introduces how Property Based Testing works, how to use it with PHPUnit, and in what way it differentiates from example based tests.
It talks about strategies to find good properties to check for.
This presentation was built for the Meet-Magento conference 2020 in Mumbai.
www.denizoguz.com-For an in company JDK 7 orientation I have prepared a presentation which summaries new features of JDK 7. I would like to make it public for everyone who needs it.
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)Jen Wong
FitNesse is a wiki-based software testing tool that can be a powerful addition to your Continuous Integration Environments. Its greatest advantages include providing visibility into tests and results, and providing access to test-writing by non-technical team members. We will:
* look at specific examples and code,
* discuss the advantages and drawbacks of using FitNesse as a test framework
* implement, deploy, and use a simple fixture in a fitnesse test
* review different kinds of fixtures, including decision table, script, query, html, and selenium webtest fixtures
* discuss some of the more interesting fixture extensions we've implemented, including JSON-based verification and the ability to pass in javascript code for dynamic verification
* use Hudson/Jenkins to run your FitNesse tests as a step in your Continuous Integration/Deployment process
TDD is now mainstream but a lot people don't know or don't remember what is its purpose. TDD is about software design not testing or catching bug. TDD helps developers to shape and create software with "good" design, what is a "good" design is something that we will discuss in the topic.
This workshop is a hands-on training where a real Zend Framework application is used as an example to start improving QA using tools to test, document and perform software metric calculations to indicate where the software can be improved. I also explain the reports produced by a CI system.
What went wrong for my clients in the past 6 years trying to implement Microservice Architectures? This is a retrospective, a list of things we must to avoid to gainable with this kind of software architecture.
Not so many years have passed since we started programming computers and even less since programming computers has been recognised as a profession. Even still, so many things depend on the quality of our work. What does it mean to be professional? What are we expected to do? Are we up for the task? I will talk about my journey of becoming the programmer of my dreams, the obstacles I've faced and the strategies that I've applied to overcome them
URLs are not meant to be given to the clients but they should be discovered through the interaction with the server inside the representation of the resources. But thinking about URLs it's like thinking about names and relations between your domain resources. Creating a good URL grammar helps a good resource design. A good resource design is more stable and more extensible.
Node.js is one of those technologies that should not exist. Definitely, theoretically, is not supposed to have this kind of success. But like the bumblebee he don't know he can't and so it goes :-)
Neuro-symbolic is not enough, we need neuro-*semantic*Frank van Harmelen
Neuro-symbolic (NeSy) AI is on the rise. However, simply machine learning on just any symbolic structure is not sufficient to really harvest the gains of NeSy. These will only be gained when the symbolic structures have an actual semantics. I give an operational definition of semantics as “predictable inference”.
All of this illustrated with link prediction over knowledge graphs, but the argument is general.
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Tobias Schneck
As AI technology is pushing into IT I was wondering myself, as an “infrastructure container kubernetes guy”, how get this fancy AI technology get managed from an infrastructure operational view? Is it possible to apply our lovely cloud native principals as well? What benefit’s both technologies could bring to each other?
Let me take this questions and provide you a short journey through existing deployment models and use cases for AI software. On practical examples, we discuss what cloud/on-premise strategy we may need for applying it to our own infrastructure to get it to work from an enterprise perspective. I want to give an overview about infrastructure requirements and technologies, what could be beneficial or limiting your AI use cases in an enterprise environment. An interactive Demo will give you some insides, what approaches I got already working for real.
Accelerate your Kubernetes clusters with Varnish CachingThijs Feryn
A presentation about the usage and availability of Varnish on Kubernetes. This talk explores the capabilities of Varnish caching and shows how to use the Varnish Helm chart to deploy it to Kubernetes.
This presentation was delivered at K8SUG Singapore. See https://feryn.eu/presentations/accelerate-your-kubernetes-clusters-with-varnish-caching-k8sug-singapore-28-2024 for more details.
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualityInflectra
In this insightful webinar, Inflectra explores how artificial intelligence (AI) is transforming software development and testing. Discover how AI-powered tools are revolutionizing every stage of the software development lifecycle (SDLC), from design and prototyping to testing, deployment, and monitoring.
Learn about:
• The Future of Testing: How AI is shifting testing towards verification, analysis, and higher-level skills, while reducing repetitive tasks.
• Test Automation: How AI-powered test case generation, optimization, and self-healing tests are making testing more efficient and effective.
• Visual Testing: Explore the emerging capabilities of AI in visual testing and how it's set to revolutionize UI verification.
• Inflectra's AI Solutions: See demonstrations of Inflectra's cutting-edge AI tools like the ChatGPT plugin and Azure Open AI platform, designed to streamline your testing process.
Whether you're a developer, tester, or QA professional, this webinar will give you valuable insights into how AI is shaping the future of software delivery.
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf91mobiles
91mobiles recently conducted a Smart TV Buyer Insights Survey in which we asked over 3,000 respondents about the TV they own, aspects they look at on a new TV, and their TV buying preferences.
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Ramesh Iyer
In today's fast-changing business world, Companies that adapt and embrace new ideas often need help to keep up with the competition. However, fostering a culture of innovation takes much work. It takes vision, leadership and willingness to take risks in the right proportion. Sachin Dev Duggal, co-founder of Builder.ai, has perfected the art of this balance, creating a company culture where creativity and growth are nurtured at each stage.
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...DanBrown980551
Do you want to learn how to model and simulate an electrical network from scratch in under an hour?
Then welcome to this PowSyBl workshop, hosted by Rte, the French Transmission System Operator (TSO)!
During the webinar, you will discover the PowSyBl ecosystem as well as handle and study an electrical network through an interactive Python notebook.
PowSyBl is an open source project hosted by LF Energy, which offers a comprehensive set of features for electrical grid modelling and simulation. Among other advanced features, PowSyBl provides:
- A fully editable and extendable library for grid component modelling;
- Visualization tools to display your network;
- Grid simulation tools, such as power flows, security analyses (with or without remedial actions) and sensitivity analyses;
The framework is mostly written in Java, with a Python binding so that Python developers can access PowSyBl functionalities as well.
What you will learn during the webinar:
- For beginners: discover PowSyBl's functionalities through a quick general presentation and the notebook, without needing any expert coding skills;
- For advanced developers: master the skills to efficiently apply PowSyBl functionalities to your real-world scenarios.
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
Keynote at DIGIT West Expo, Glasgow on 29 May 2024.
Cheryl Hung, ochery.com
Sr Director, Infrastructure Ecosystem, Arm.
The key trends across hardware, cloud and open-source; exploring how these areas are likely to mature and develop over the short and long-term, and then considering how organisations can position themselves to adapt and thrive.
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Jeffrey Haguewood
Sidekick Solutions uses Bonterra Impact Management (fka Social Solutions Apricot) and automation solutions to integrate data for business workflows.
We believe integration and automation are essential to user experience and the promise of efficient work through technology. Automation is the critical ingredient to realizing that full vision. We develop integration products and services for Bonterra Case Management software to support the deployment of automations for a variety of use cases.
This video focuses on the notifications, alerts, and approval requests using Slack for Bonterra Impact Management. The solutions covered in this webinar can also be deployed for Microsoft Teams.
Interested in deploying notification automations for Bonterra Impact Management? Contact us at sales@sidekicksolutionsllc.com to discuss next steps.
3. Bugfixing
Cost
Bugs
• Cost of bugfix = Number of bugs x Cost per fix, but...
• How many bugs do you plan to have?
• How hard do you think they are to fix?
4. Bugfixing
Tests
Cost
Bugs/Features
• Cost of tests = Number and complexity of features
• How many features do you plan to have?
• How complex they are?
12. Fixture Teardown
Fixture
Steps
SUT
Fixture Setup
Exercise SUT
Verify Result
Fixture Teardown
13. a test is a good one if...
• Is really automatic
• Should be easy to invoke one or more tests
• Must determine for itself whether it passed
or failed
• Test everything that’s likely to break
• Must be independent from the environment
and each other test
• Should be repeatable, could be run over and
over again, in any order and produce the same
results
• The code is clean as the production code
14. the kind of test is not
determined by the used tool
15. Unit tests
A test is not a unit test if:
1. It talks to a database
2. It communicates across the network
3. It touches the file system
4. You have to do things to your environment
to run it (eg, change config files)
Tests that do this are integration tests
Michael Feathers
16. public void marriageIsSimmetric() {
Customer alice = new Customer("alice");
Customer bob = new Customer("bob");
bob.marry(alice);
assertTrue(bob.isMarriedTo(alice));
assertTrue(alice.isMarriedTo(bob));
}
Simple Unit Test
17. public void marriageIsSimmetric() {
Customer alice = new Customer("alice");
Customer bob = new Customer("bob");
bob.marry(alice);
assertTrue(bob.isMarriedTo(alice));
assertTrue(alice.isMarriedTo(bob));
}
Fixture Setup
18. public void marriageIsSimmetric() {
Customer alice = new Customer("alice");
Customer bob = new Customer("bob");
bob.marry(alice);
assertTrue(bob.isMarriedTo(alice));
assertTrue(alice.isMarriedTo(bob));
}
Exercise SUT
19. public void marriageIsSimmetric() {
Customer alice = new Customer("alice");
Customer bob = new Customer("bob");
bob.marry(alice);
assertTrue(bob.isMarriedTo(alice));
assertTrue(alice.isMarriedTo(bob));
}
Verify Result
21. As a developer,
I want to learn TDD,
so that I can write
clean code that works
22. Clean code that works
Clean code is simple and direct. Clean code
reads like well-written prose. Clean code never
obscures the designer’s intent but rather is full
of crisp abstractions and straightforward lines
of control
Grady Booch
23. Clean code that works
Clean code always looks like it was written by
someone who cares. There is nothing obvious
that you can do to make it better. All of those
things were thought about by the code’s
author, and if you try to imagine improvements,
you’re led back to where you are, sitting in
appreciation of the code someone left for you,
code left by someone who cares deeply about
the craft.
Michael Feathers
24. Clean code that works
You know you are working on clean code when
each routine you read turns out to be pretty
much what you expected.You can call it beautiful
code when the code also makes it look like the
language was made for the problem
Ward Cunningham
25. Simple design
The code is simple enough when it:
0. Pass all the tests
1. Expresses every idea that we need to express
2. Contains no duplication
3. Has the minimum number of classes and functions
(In this order)
Adapted from Extreme Programming Installed by Ron Jeffries et al.
26. Clean code that works
• First we'll solve the “that works” part
• Then we'll solve the “clean code” part
28. ... then Refactor
Is the process of changing a software
system in such a way that it does not
alter the external behaviour of the
code yet improves its internal structure
Martin Fowler
30. ... fight the Smells
Smell Common Refactorings
Duplicated Code Extract Method, Extract Class, Pull-Up Method, Template Method
Feature Envy Move Method, Move Field, Extract Method
Extract Class, Extract Subclass, Extract Interface, Replace Data
Large Class
Value with Object
Extract Method, Replace Temporary Variable with Query, Replace
Long Method
Method with Method Object, Decompose Conditional
31. ... fight the Smells
Smell Common Refactorings
Shotgun Surgery Move Method, Move Field, Inline Class
Replace Parameter with Method, Introduct Parameter Object,
Long Parameter List
Preserve Whole Object
Data Class Move Method, Encapsulate Field, Encapsulate Collection
Comments Extract Method, Introduce Assertion
35. import java.util.*;
public class FileDetail {
make it
private Date lastModified;
private String fileName;
public FileDetail(Date lastModified, String fileName) {
this.lastModified = lastModified;
compile
this.fileName = fileName;
}
public Date getModificationDate() {
return this.lastModified;
}
public String getName() {
return this.fileName;
}
}
public class MainFrame {
}
public static final String WATCHED_DATA = "/dev/null";
stub
public class ScpTo {
public static void send(String filePathToSend) {
}
// TODO: no need to implement :-(
dependencies
}
41. Characterization Test
public class VobasBackupServiceCharacterizationTest {
private List<File> directoriesToCleanup;
@Before public void setUp() throws Exception {
directoriesToCleanup = new ArrayList<File>();
}
@After public void tearDown() throws Exception {
for (File directoryToCleanup : directoriesToCleanup) {
deleteDirectory(directoryToCleanup);
}
ScpTo.sended = new ArrayList<String>();
}
@Test public void backupOneDirectoryWithOneFreshFile() throws Exception {
VobasBackupService service = new VobasBackupService();
File oneDirectoryWithOneFile = createDirectoryToBackupWithFiles(1);
File listOfDirectoriesToBackup = listOfDirectoriesToBackupIntoFile(oneDirectoryWithOneFile);
service.backup(listOfDirectoriesToBackup.getAbsolutePath());
assertEquals(1, ScpTo.sended.size());
directoriesToCleanup.add(oneDirectoryWithOneFile);
}
42. Characterization Test
@Test public void backupOneDirectoryWithTwoFreshFiles() throws Exception {
VobasBackupService service = new VobasBackupService();
File oneDirectoryWithTwoFiles = createDirectoryToBackupWithFiles(2);
File listOfDirectoriesToBackup = listOfDirectoriesToBackupIntoFile(oneDirectoryWithTwoFiles);
service.backup(listOfDirectoriesToBackup.getAbsolutePath());
assertEquals(2, ScpTo.sended.size());
directoriesToCleanup.add(oneDirectoryWithTwoFiles);
}
@Test public void backupTwoDirectoriesWithOneFreshFile() throws Exception {
VobasBackupService service = new VobasBackupService();
File oneDirectoryWithOneFile = createDirectoryToBackupWithFiles(1);
File anotherDirectoryWithOneFile = createDirectoryToBackupWithFiles(1);
File listOfDirectoriesToBackup = listOfDirectoriesToBackupIntoFile(
oneDirectoryWithOneFile, anotherDirectoryWithOneFile);
service.backup(listOfDirectoriesToBackup.getAbsolutePath());
assertEquals(2, ScpTo.sended.size());
directoriesToCleanup.add(oneDirectoryWithOneFile);
directoriesToCleanup.add(anotherDirectoryWithOneFile);
}
43. Magic Number
@Test public void backupOneDirectoryWithTwoFreshFiles() throws Exception {
VobasBackupService service = new VobasBackupService();
File oneDirectoryWithTwoFiles = createDirectoryToBackupWithFiles(2);
File listOfDirectoriesToBackup = listOfDirectoriesToBackupIntoFile(oneDirectoryWithTwoFiles);
service.backup(listOfDirectoriesToBackup.getAbsolutePath());
assertEquals(2, ScpTo.sended.size());
directoriesToCleanup.add(oneDirectoryWithTwoFiles);
}
replace Magic Number with Expression
@Test public void backupOneDirectoryWithTwoFreshFiles() throws Exception {
VobasBackupService service = new VobasBackupService();
File oneDirectoryWithTwoFiles = createDirectoryToBackupWithFiles(2);
File listOfDirectoriesToBackup = listOfDirectoriesToBackupIntoFile(oneDirectoryWithTwoFiles);
service.backup(listOfDirectoriesToBackup.getAbsolutePath());
assertEquals(oneDirectoryWithTwoFiles.list().length, ScpTo.sended.size());
directoriesToCleanup.add(oneDirectoryWithTwoFiles);
}
44. Syntax Noise
private void deleteDirectory(File directoryToDelete) throws Exception {
if (directoryToDelete.isDirectory()) {
String[] children = directoryToDelete.list();
for (int i=0; i<children.length; i++) {
deleteDirectory(new File(directoryToDelete, children[i]));
}
}
if (!directoryToDelete.delete()) {
throw new Exception("unable to delete " + directoryToDelete.getAbsolutePath());
}
}
replace For with Loop
private void deleteDirectory(File directoryToDelete) throws Exception {
if (directoryToDelete.isDirectory()) {
for (File child : directoryToDelete.listFiles()) {
deleteDirectory(child);
}
}
assert directoryToDelete.delete() : "unable to delete " + directoryToDelete.getAbsolutePath());
}
45. Syntax Noise
private void deleteDirectory(File directoryToDelete) throws Exception {
if (directoryToDelete.isDirectory()) {
String[] children = directoryToDelete.list();
for (int i=0; i<children.length; i++) {
deleteDirectory(new File(directoryToDelete, children[i]));
}
}
if (!directoryToDelete.delete()) {
throw new Exception("unable to delete " + directoryToDelete.getAbsolutePath());
}
}
replace Test with Assertion
private void deleteDirectory(File directoryToDelete) throws Exception {
if (directoryToDelete.isDirectory()) {
for (File child : directoryToDelete.listFiles()) {
deleteDirectory(child);
}
}
assert directoryToDelete.delete() : "unable to delete " + directoryToDelete.getAbsolutePath());
}
46. now we can play safe
// read all directories to backup from a file
BufferedReader reader = new BufferedReader(new FileReader(directoryPathToBackup));
// for each of those directory
String directoryName = reader.readLine();
while (directoryName != null) {
// get details on files in these directory
Map fileDetails = new Hashtable();
File fileData = new File(directoryName, ".vobas");
if (!fileData.exists()) {
fileData.createNewFile();
} else {
ObjectInputStream fileDetailsReader = new ObjectInputStream(
new FileInputStream(fileData));
FileDetail fileDetail = (FileDetail) fileDetailsReader.readObject();
while (fileDetail != null) {
fileDetails.put(fileDetail.getName(), fileDetail);
try {
fileDetail = (FileDetail) fileDetailsReader.readObject();
} catch (EOFException e) {
break;
}
}
}
47. now we can play safe
// select only files to backup in directory
File[] files = new File(directoryName).listFiles(new FilenameFilter() {
public boolean accept(File directory, String fileName) {
return ! fileName.equals(".vobas");
}
});
// for each of those files
for (File file : files) {
FileDetail fileDetail = (FileDetail) fileDetails.get(file.getName());
// if no previous details are given
if (fileDetail == null) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
// if details are given but file has been modified
} else if (file.lastModified() > fileDetail.getModificationDate().getTime()) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.remove(file.getName());
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
}
}
48. now we can play safe
// save all details on files to .vobas file
ObjectOutput objectOutput = new ObjectOutputStream(
new FileOutputStream(new File(directoryName, ".vobas")));
for (Object value : fileDetails.values()) {
FileDetail fileDetail = (FileDetail) value;
objectOutput.writeObject(fileDetail);
}
objectOutput.close();
// next directory to backup please...
directoryName = reader.readLine();
}
reader.close();
49. narrow your target
and your tests
// for each of those directory
String directoryName = reader.readLine();
while (directoryName != null) {
Comment
// read details on files in directory
Map fileDetails = new Hashtable();
File fileData = new File(directoryName, ".vobas");
if (!fileData.exists()) {
fileData.createNewFile();
} else {
ObjectInputStream fileDetailsReader = new ObjectInputStream(
new FileInputStream(fileData));
FileDetail fileDetail = (FileDetail) fileDetailsReader.readObject();
while (fileDetail != null) {
fileDetails.put(fileDetail.getName(), fileDetail);
try {
fileDetail = (FileDetail) fileDetailsReader.readObject();
} catch (EOFException e) {
break;
}
}
}
50. Extract Method
// for each of those directory
String directoryName = reader.readLine();
while (directoryName != null) {
// read details on files in directory
Map fileDetails = new Hashtable();
File fileData = new File(directoryName, ".vobas");
if (!fileData.exists()) {
fileData.createNewFile();
} else {
ObjectInputStream fileDetailsReader = new ObjectInputStream(
new FileInputStream(fileData));
FileDetail fileDetail = (FileDetail) fileDetailsReader.readObject();
while (fileDetail != null) {
fileDetails.put(fileDetail.getName(), fileDetail);
try {
fileDetail = (FileDetail) fileDetailsReader.readObject();
} catch (EOFException e) {
break;
}
}
}
51. Extract Method
public Map readDetailsOnFilesFrom(String directoryPath) throws ... {
Map fileDetails = new Hashtable();
File fileData = new File(directoryPath, ".vobas");
if (!fileData.exists()) {
fileData.createNewFile();
} else {
ObjectInputStream fileDetailsReader = new ObjectInputStream(
new FileInputStream(fileData));
FileDetail fileDetail = (FileDetail) fileDetailsReader.readObject();
while (fileDetail != null) {
fileDetails.put(fileDetail.getName(), fileDetail);
try {
fileDetail = (FileDetail) fileDetailsReader.readObject();
} catch (EOFException e) {
break;
}
}
}
return fileDetails;
}
52. Extract Method
// for each of those directory
String directoryName = reader.readLine();
while (directoryName != null) {
// read details on files in directory
Map fileDetails = readDetailsOnFilesFrom(directoryName);
// select only files to backup in directory
File[] files = new File(directoryName).listFiles(new FilenameFilter() {
public boolean accept(File directory, String fileName) {
return ! fileName.equals(".vobas");
}
});
...
53. Extract Method
// for each of those directory
String directoryName = reader.readLine();
while (directoryName != null) {
Map fileDetails = readDetailsOnFilesFrom(directoryName);
// select only files to backup in directory
File[] files = new File(directoryName).listFiles(new FilenameFilter() {
public boolean accept(File directory, String fileName) {
return ! fileName.equals(".vobas");
}
});
...
54. Duplicated Code, Complex Conditional
// if no previous details are given
if (fileDetail == null) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
// if details are given but file has been modified
} else if (file.lastModified() > fileDetail.getModificationDate().getTime()) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.remove(file.getName());
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
}
55. Consolidate duplicated conditional fragments
// if no previous details are given
if (fileDetail == null) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
// if details are given but file has been modified
} else if (file.lastModified() > fileDetail.getModificationDate().getTime()) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.remove(file.getName());
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
}
56. Consolidate duplicated conditional fragments
// if no previous details are given
if (fileDetail == null) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
// if details are given but file has been modified
} else if (file.lastModified() > fileDetail.getModificationDate().getTime()) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
}
57. Consolidate duplicated conditional fragments
// if no previous details are given or
// if details are given but file has been modified
if ((fileDetail == null) ||
(file.lastModified() > fileDetail.getModificationDate().getTime())) {
// send to backup
ScpTo.send(directoryName + File.separatorChar + file.getName());
// save details
fileDetails.put(file.getName(), new FileDetail(new Date(), file.getName()));
}
76. Inconsistent Name
public void backupDirectory(String directoryPath) throws ... {
BackupReport lastBackupReport = BackupReport.readFrom(directoryPath);
for (File file : filesToBackupInto(directoryPath)) {
if (lastBackupReport.needBackup(file)) {
backupFile(file);
lastBackupReport.update(file);
}
}
lastBackupReport.save();
}
77. Rename Class, Replace Data Value with Object
public void backupDirectory(File directoryToBackup) throws ... {
DirectoryBackupStatus directoryBackupStatus = new DirectoryBackupStatus(directoryToBackup);
for (File file : filesToBackupInto(directoryToBackup)) {
if (directoryBackupStatus.needBackup(file)) {
backupFile(file);
directoryBackupStatus.update(file);
}
}
directoryBackupStatus.save();
}
78. public void run() {
try {
backupDirectories(listOfDirectoriesToBackup(MainFrame.WATCHED_DATA));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void backupDirectories(List<File> listOfDirectoriesToBackup) throws ... {
for (File directoryToBackup : listOfDirectoriesToBackup) {
backupDirectory(directoryToBackup);
}
}
public void backupDirectory(File directoryToBackup) throws ... {
DirectoryBackupStatus directoryBackupStatus = new DirectoryBackupStatus(directoryToBackup);
for (File file : filesToBackupInto(directoryToBackup)) {
if (directoryBackupStatus.needBackup(file)) {
backupFile(file);
directoryBackupStatus.update(file);
}
}
directoryBackupStatus.save();
}
79.
80. class BackupPlan {
public BackupPlan(File configuration) throws BackupFailedException {
this.directoriesToBackup = directoriesToBackup(backupPlan);
}
public void runWith(BackupService backupService) throws BackupFailedException {
for (File directoryToBackup : directoriesToBackup) {
new DirectoryBackupService(directoryToBackup).backupWith(backupService);
}
}
private List<File> directoriesToBackup(File configuration) throws BackupFailedException {
...
}
private List<File> directoriesToBackup;
}
81. class DirectoryBackupService {
public DirectoryBackupService(File directoryToBackup) throws BackupFailedException {
readBackupStatusFrom(directoryToBackup);
}
public void backupWith(BackupService backupService) throws BackupFailedException {
for (File file : listOfFilesToBackup()) {
if (needBackup(file)) {
backupService.backup(file);
update(file);
}
}
save();
}
...
}
83. Write a test
public class AdderTest {
@Test
public void testTwoPlusThree() {
Adder a = new Adder();
assertEquals(5, a.add(2, 3));
}
}
84. Now it compiles
public class AdderTest {
@Test
public void testTwoPlusThree() {
Adder a = new Adder();
assertEquals(5, a.add(2, 3));
}
}
public class Adder {
public int add(int a, int b) { return 0; }
}
85. Red bar!
public class AdderTest {
@Test
public void testTwoPlusThree() {
Adder a = new Adder();
assertEquals(5, a.add(2, 3));
}
}
public class Adder {
public int add(int a, int b) { return 0; }
}
Expected 5, was 0
86. Just pretend
public class AdderTest {
@Test
public void testTwoPlusThree() {
Adder a = new Adder();
assertEquals(5, a.add(2, 3));
}
}
public class Adder {
public int add(int a, int b) { return 5; }
}
87. Remove the duplicated “5”
public class AdderTest {
@Test
public void testTwoPlusThree() {
Adder a = new Adder();
assertEquals(5, a.add(2, 3));
}
}
public class Adder {
public int add(int a, int b) { return a+b; }
}
88. The procedure
1. Write a test
2. Make it compile
Expected 5, was 0
3. Make it pass
4. Refactor
92. Clean code, why?
• Design is the great accelerator:
• If you drop quality for speed, you will get neither
• If you aim for quality...
• ... and you know how to get it...
• ... you will also be fast!
93. Test first, why?
• You think code from the point of view of the
caller
• This perspective makes for better design
• Test coverage is a useful byproduct
95. Refactor, why?
• What is clean code today could be bad code
tomorrow
• Refactoring is when I do design
• Design emerges, with thought, care and small
steps
• I don’t claim I can guess the right design
• Because I can: the tests support refactoring
96. No silver bullet
• Needs lots of practice
• Requires discipline
• Must think and be alert at all times!