diff --git a/.gitignore b/.gitignore
index 5a7890f..25e86e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-
# Created by https://www.toptal.com/developers/gitignore/api/intellij+all
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all
@@ -81,10 +80,12 @@ fabric.properties
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
+*.iml
+/.idea
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
-*.iml
+
modules.xml
.idea/misc.xml
*.ipr
@@ -93,6 +94,7 @@ modules.xml
.idea/sonarlint
# Build output
-build/
+!added/to/make/code/build/
+/build/
# End of https://www.toptal.com/developers/gitignore/api/intellij+all
diff --git a/README.md b/README.md
index 7f679dd..2beb7be 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,31 @@
-# CleanCode
-A sample project to work with clean code concepts
+# Clean Code, A bottom-up approach
+Comprehensive notes for the clean code concepts
+
+
+
+## Table of content
+- [Introduction*](notes/00_Introduction.md)
+- [Chapter 1: Clean code*](notes/01_Chapter_1_Clean_code.md)
+- [Chapter 2: Meaningful names*](notes/02_Chapter_2_Meaningful_names.md)
+- [Chapter 3: Functions*](notes/03_Chapter_3_Functions.md)
+- [Chapter 4: Comments*](notes/04_Chapter_4_Comments.md)
+- [Chapter 5: Formatting*](notes/05_Chapter_5_Formatting.md)
+- [Chapter 6: Objects and Data structures*](notes/06_Chapter_6_Objects_and_Data_structures.md)
+- [Chapter 7: Error handling*](notes/07_Chapter_7_Error_Handling.md)
+- [Chapter 8: Boundaries*](notes/08_Chapter_8_Boundaries.md)
+- [Chapter 9: Unit tests](notes/09_Chapter_9_Unit_tests.md)
+- [Chapter 10: Classes](notes/10_Chapter_10_Classes.md)
+- [Chapter 11: Systems](notes/11_Chapter_11_Systems.md)
+- [Chapter 12: Emergence](notes/12_Chapter_12_Emergence.md)
+- [Chapter 13: Concurrency](notes/13_Chapter_13_Concurrency.md)
+- [Chapter 14: Successive Refinement](notes/14_Chapter_14_Successive_Refinement.md)
+- [Chapter 15: Junit Internals](notes/15_Chapter_15_Junit_Internals.md)
+- [Chapter 16: Refactoring SerialDate](notes/16_Chapter_16_Refactoring_SerialDate.md)
+- [Chapter 17: Smells and Heuristics](notes/17_Chapter_17_Smells_and_Heuristics.md)
+- [Appendix A: Concurrency ii](notes/18_Appendix_A_Concurrency_ii.md)
+
+(*) These chapters also have ppt presentation slides
+
+## Source code examples
+- [Snippets](src/main/java/clean/code)
+- [Tests](src/test/java)
diff --git a/build.gradle b/build.gradle
index 7e6c62a..ac9f5b8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ plugins {
id 'java'
}
-group 'ir.logicbase.cleancode'
+group 'clean.code'
version '1.0'
repositories {
diff --git a/img/book_cover.jpg b/img/book_cover.jpg
new file mode 100644
index 0000000..2cb5b92
Binary files /dev/null and b/img/book_cover.jpg differ
diff --git a/img/code_quality_measurement.png b/img/code_quality_measurement.png
new file mode 100644
index 0000000..383961b
Binary files /dev/null and b/img/code_quality_measurement.png differ
diff --git a/notes/00_Introduction.md b/notes/00_Introduction.md
new file mode 100644
index 0000000..2f42e8d
--- /dev/null
+++ b/notes/00_Introduction.md
@@ -0,0 +1,11 @@
+# Introduction [[Slide](../slides/00_Introduction.pptx)]
+
+## How to know if code is dirty
+
+When reading someones code, if you find a portion of code ambigious
+you say WTF is this (Use surprise word for public, it's more polite)
+how am I supposed to know what's going on here
+
+**Code quality = WTFs/Minute**
+
+
\ No newline at end of file
diff --git a/notes/01_Chapter_1_Clean_code.md b/notes/01_Chapter_1_Clean_code.md
new file mode 100644
index 0000000..d35de4f
--- /dev/null
+++ b/notes/01_Chapter_1_Clean_code.md
@@ -0,0 +1,87 @@
+# Chapter 1: Clean code [[Slide](../slides/01_Chapter_1_Clean_code.pptx)]
+
+## Bad code
+we write bad code because:
+- trying to go fast and reach irrational deadline
+- you're in **rush**
+- you feel that you don't have **time** to do a **good job**
+- you're boss will be angry if you took the time to clean up your code
+- you were just tired of working on this program and wanted it to be over
+- you looked at the **backlog** of other stuff that you had promised to get done and realized that you needed to slam this module together so you could move on to the next.
+
+## Costs of bad code
+As the mess piles on top of each other, **productivity** decreases toward zero
+
+### The Grand Redesign in the Sky
+
+1. new tiger team selected to redesign system **from scratch**
+2. current system must be **maintained** until new one is ready
+3. two teams are in race, tiger team must build everything that old system does meanwhile keeping up with changes that are continuously being made to old system
+4. it takes long time for both teams to reach focal point
+5. when its done, members demand new system to be redesigned because it's such a mess
+
+### Attitude
+- If good code rot so quickly into bad code, it's all **our fault**, we are **unprofessional**
+- The managers and marketers look to us for the information they need to make **promises** and **commitments**
+- It is unprofessional for programmers to bend to the will of managers who don’t understand the **risks of making messes**.
+
+### The Primal Conundrum
+- You will not make the **deadline** by making the mess.
+- Indeed, the mess will slow you down instantly, and will force you to miss the deadline.
+- The only way to make the deadline—the only way to go fast—is to `keep the code as clean as possible at all times`.
+
+## The Art of Clean Code?
+- being able to recognize clean code from dirty code does not mean that we know how to write clean code
+- A programmer with **code-sense** will look at a messy module and see options and variations
+
+## What Is Clean Code?
+### Bjarne Stroustrup, inventor of C++
+- clean code is pleasing to read.
+- Bad code tempts the mess to grow! When others change bad code, they tend to make it worse.
+
+### Pragmatic Dave Thomas
+A building with broken windows looks like nobody cares about it. So other people stop caring.
+
+### Grady Booch, author of Object Oriented Analysis and Design with Applications
+- our code should contain only what is **necessary**.
+- clean code should read like well-written prose (can you see images, sounds, humors, … when reading a novel?)
+
+### “Big” Dave Thomas, founder of OTI, godfather of theEclipse strategy
+- clean code makes it easy for **other people** to enhance it
+- smaller codebase the better
+
+### Michael Feathers, author of Working Effectively with Legacy Code
+- Clean code always looks like it was written by someone who cares
+
+### Ron Jeffries, author of Extreme Programming Installed and Extreme ProgrammingAdventures in C#
+- Duplicate code is a sign there is an idea in our mind that is not well represented in the code
+
+### Ward Cunningham, inventor of Wiki
+- Clean code is a code that is pretty much what you expect it to do
+- Beautiful code makes the language look like it was made for the problem.
+
+## Schools of Thought
+- Often master martial artists will form their own schools of thought and gather students to learn from them
+- These recommendations are controversial, you might agree or disagree our point of view
+
+## We Are Authors
+- authors have readers
+- the ratio of time spent reading vs. writing is well over 10:1.
+- if you want your code to be easy to write, make it easy to read. (you read surrounding code all the times)
+
+## The Boy Scout Rule
+`Leave the campground cleaner than you found it`
+Examples:
+- Change one variable name for the better
+- break up one function that’s a little too large
+- eliminate one small bit of duplication
+- clean up one composite if statement
+
+## Prequel and Principles
+This book is prequel to the book :
+Agile Software Development: Principles, Patterns, and Practices (PPP)
+by uncle bob 2002
+
+## Conclusion
+Books on art don’t promise to make you an artist. All they can do is give you some of the
+tools, techniques, and thought processes that other artists have used.
\ No newline at end of file
diff --git a/notes/02_Chapter_2_Meaningful_names.md b/notes/02_Chapter_2_Meaningful_names.md
new file mode 100644
index 0000000..69f2d2d
--- /dev/null
+++ b/notes/02_Chapter_2_Meaningful_names.md
@@ -0,0 +1,72 @@
+# Chapter 2: Meaningful names [[Slide](../slides/02_Chapter_2_Meaningful_names.pptx)]
+
+## Use Intention-Revealing Names
+Using `d` instead of `elapsedTimeInDays`.
+
+## Avoid Disinformation
+- Using names like `hp`, `aix` where it has different meaning in different contexts.
+- Using `AccountList` for group of accounts where there is no list
+
+## Make Meaningful Distinctions
+- Using `a1` and `a2` instead of `source` and `destination`.
+- what's the difference between `TheCustomer`, `CustomerData`, `CustomerInfo` and `Customer`
+
+## Use Pronounceable Names
+Don't compact names for sake of smaller words, eg. `pref`, `mnger`, `genymdhms`.
+
+## Use Searchable Names
+Using constants and complete names make it easy to find them with search, eg. `WORK_DAYS_PER_WEEK`
+
+## Avoid Encodings
+### Hungarian Notation
+In the modern IDE's there is no need to prefix with HN, eg. `frmReserve`, `tblStudent`.
+
+### Member Prefixes
+Don't use stupid m prefix for field names, eg. `mLatitude`, `mContext`
+
+### Interfaces and Implementations
+Prefer to suffix Implementation class, rather than Interface class
+eg. `ShapeFactory` for the interface and `ShapeFactoryImpl` for the implementation.
+
+## Avoid Mental Mapping
+Readers shouldn’t have to mentally translate your names into other names they already know.
+
+## Class Names
+noun or noun phrases
+
+## Method Names
+- methods should have verb or phrase names
+ eg. `deletePage()`, `save()`, `isEven()`, `setPoint()`, `hasElement()`
+- prefer factory methods for multiple constructors
+
+## Don’t Be Cute
+Using `whack()` instead of `kill()`, `eatMyShorts()` instead of `abort()`, `nukeTable()` instead of `deleteAll()`
+
+## Pick One Word per Concept
+eg. `fetch`, `retrieve` and `get`
+
+## Don’t Pun
+Avoid using the same word for two purposes. Using the same term for two different ideas
+is essentially a pun.
+eg. using `add` instead of `insert` for a method which is putting single parameter to a collection is a pun
+
+## Use Solution Domain Names
+use computer science (CS) terms, algorithm names, pattern names, math terms
+
+## Use Problem Domain Names
+When there is no “programmer-eese” for what you’re doing, use the name from the problem
+domain.
+
+## Add Meaningful Context
+Separate your concerns using well-named :
+- Constant
+- Function
+- Class
+- Namespace
+- Package
+- Module
+
+When all else fails, then prefixing the name may be necessary as a last resort.
+
+## Don’t Add Gratuitous Context
+eg. `GSDAccountAddress`
diff --git a/notes/03_Chapter_3_Functions.md b/notes/03_Chapter_3_Functions.md
new file mode 100644
index 0000000..3ba73eb
--- /dev/null
+++ b/notes/03_Chapter_3_Functions.md
@@ -0,0 +1,126 @@
+# Chapter 3: Functions [[Slide](../slides/03_Chapter_3_Functions.pptx)]
+
+## Small
+- **Line counts** should not be longer than a **screen size**
+- **Line width** smaller than `150` characters
+- **Line counts** smaller than `100` lines
+
+## Blocks and Indenting
+- blocks within conditional (if/when/while...) statements should be **one line long**
+- 1 or 2 indentation level at most
+
+## Do One Thing
+`FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL.
+THEY SHOULD DO IT ONLY.`
+- another way to know that a function is doing more than **one thing** is if you can
+ extract another function from it with a name that is not merely a restatement of its implementation
+
+## Sections within Functions
+Functions that do one thing cannot be reasonably divided into sections.
+
+## One Level of Abstraction per Function
+Mixing level's of abstraction make's function confusing
+
+## Reading Code from Top to Bottom: The Stepdown Rule
+We want the code to read like a top-down narrative.
+We want every function to be followed by those at the next level of abstraction so that we can read the program, descending one level of abstraction at a time as we read down the list of functions
+
+## Switch Statements
+they can be tolerated if they appear only once, are used to create polymorphic objects, and are hidden behind an inheritance relationship so that the rest of the system can’t see them.
+
+## Use Descriptive Names
+- Don’t be afraid to make a name long. A long descriptive name is better than a short
+ enigmatic name
+- A long descriptive name is better than a long descriptive comment
+- Don't be afraid to change names
+
+## Function Arguments
+- The ideal number of arguments for a function is zero (*niadic*).
+- Next comes one (*monadic*), followed closely by two (*dyadic*).
+- Three arguments (*triadic*) should be avoided where possible.
+- More than three (*polyadic*) requires very special justification—and then shouldn’t be used anyway.
+
+## Common Monadic Forms
+- condition arg to decide what to do
+- argument to transform into something else
+- event
+
+`Using an output argument instead of a return value for a transformation is confusing`
+
+## Flag Arguments
+should be avoided, it is loudly proclaiming that this function does more than one thing
+
+## Dyadic Functions
+you can simply convert these functions to monadic by moving it to right class as a member function
+
+## Triads
+same applies to this
+
+## Argument Objects
+using objects for group of variables that declare a concept is better than passing every single one of variables
+
+## Argument Lists
+eg. `varargs`
+functions with these arguments are simply monadic, dyadic and traids
+so same rules applies to them
+
+## Verbs and Keywords
+functions and arguments should form a very nice verb/noun pairs eg. `write(name)`
+we can use keywords as well to make them more clear eg.
+```kotlin
+firstOrNull(predicate)
+assertExpectedEqualsActual(expected, actual)
+```
+
+## Have No Side Effects
+### temporal coupling
+Temporal coupling is coupling that occurs when there are two or more members of a class that need to be invoked in a particular order. eg:
+```
+var calculator = new PriceCalculator();
+calculator.UpdateCurrencyRates(eur: 1.02, gbp: 1.25);
+decimal price = calculator.CalculatePrice(myShoppingCart);
+```
+[Reference](https://enterprisecraftsmanship.com/posts/temporal-coupling-and-immutability)
+
+Here, currency rates required to calculate the price of a shopping cart.
+
+## Output Arguments
+should be avoided
+
+## Command Query Separation
+```
+public boolean set(String attribute, String value);
+if (set("username", "unclebob"))…
+if (attributeExists("username")) {
+ setAttribute("username", "unclebob");
+ ...
+}
+```
+
+## Prefer Exceptions to Returning Error Codes
+returning **error code*** will result in **nested conditional** checks
+
+## Extract Try/Catch Blocks
+extract each block to another function
+
+## Error Handling Is One Thing
+a function that handles errors should do nothing else
+
+## The Error.java Dependency Magnet
+having one enum class for all error codes will force compiler to rebuild every time there is a change in this enum, because all other parts of code have imported this
+## Don’t Repeat Yourself
+Duplication may be the root of all evil in software
+
+## Structured Programming
+### Dijkstra's rule for functions
+`every function, and every block within a function, should have one entry and one exit.`
+
+if you keep your functions small, then the occasional multiple return, break, or
+continue statement does no harm and can sometimes even be more expressive than the single-
+entry, single-exit rule.
+
+## How Do You Write Functions Like This?
+you cannot reach clean code at the first try!
+when you start writing code, just jot down your thoughts into any clumsy code that pop's up into your mind, duplicate code, complicated loops, it's all O.K
+then you start iterating through your code and refine them to smaller functions and clean design
+while keeping unit tests passing.
diff --git a/notes/04_Chapter_4_Comments.md b/notes/04_Chapter_4_Comments.md
new file mode 100644
index 0000000..6d01d47
--- /dev/null
+++ b/notes/04_Chapter_4_Comments.md
@@ -0,0 +1,106 @@
+# Chapter 4: Comments [[Slide](../slides/04_Chapter_4_Comments.pptx)]
+
+`Don’t comment bad code—rewrite it". Brian W. Kernighan`
+
+## Comments Do Not Make Up for Bad Code
+Clear and expressive code with few comments is far superior to cluttered and complex
+code with lots of comments
+
+## Explain Yourself in Code
+prefer using separate function instead of commenting on if statement with multiple conditions
+
+## Good Comments
+### Legal Comments
+copyright
+
+### Informative Comments
+- function return intention
+- comments to show eligible format patterns
+
+### Explanation of Intent
+important decisions that can be questionable by other programmers
+
+### Clarification
+when you don't have access to api and, you are just consumer of it and there need to be some clarification for it
+
+### Warning of Consequences
+eg. SimpleDateFormat is not thread safe, so we need to create each instance independently.
+
+Don't run unless you have some time to kill.
+
+### ToDo
+It's okay to put todo comments when you don't have a good solution at the moment
+
+### Amplification
+indicate higher importance of notice
+
+### Javadocs in Public APIs
+public api's must have java docs
+
+## Bad Comments
+### Mumbling
+eg. putting in comments for **catch** in try/catch blocks, just to satisfy IDE inspector.
+
+### Redundant Comments
+Don't repeat code in comment, add something that has more value and meaning
+
+### Misleading Comments
+comment should describe code accurately, otherwise it will mislead other programmers
+
+### Mandated Comments
+Not all functions and variables should have java doc, it will just clutter up the code
+
+### Journal Comments
+log of changes to code should be maintained in **version control** system, not in code
+
+### Noise Comments
+commenting something that we **already know** about code is called noise
+
+eg. // this is default constructor
+
+### Scary Noise
+**copy pasting** variable name in comment is a horrible scray noise!
+
+### Don’t Use a Comment When You Can Use a Function or a Variable
+eg. section comments, if statement comments
+
+### Position Markers
+eg. // Actions //////////////////////////////////
+
+### Closing Brace Comments
+separate your code into functions instead of commenting closing braces
+eg.
+```
+for(~) {
+ while(~) {
+ if() {
+ } // if
+ } // while
+} // for
+```
+
+### Attributions and Bylines
+use version control instead of adding author name at top of classes
+
+### Commented-Out Code
+leaving commented out code is not a good practice anymore because we have VCS now.
+
+### HTML Comments
+If you want to put HTML docs, make sure your tool is displaying human readable format
+
+### Nonlocal Information
+referencing global configurations and information in a local function will quickly turn it into a **lie** when those information changes
+
+### Too Much Information
+Don’t put interesting **historical discussions** or irrelevant descriptions of details into your comments.
+
+### Inobvious Connection
+- The connection between a comment and the code it describes should be obvious
+- The purpose of a comment is to explain code that does not explain itself. It is a **pity** when a comment needs its own explanation.
+
+### Function Headers
+Short functions don’t need much description.
+
+### Javadocs in Nonpublic Code
+nonpublic code doesn't need javadocs for all single parameters
+
diff --git a/notes/05_Chapter_5_Formatting.md b/notes/05_Chapter_5_Formatting.md
new file mode 100644
index 0000000..f79a7a3
--- /dev/null
+++ b/notes/05_Chapter_5_Formatting.md
@@ -0,0 +1,57 @@
+# Chapter 5: Formatting [[Slide](../slides/05_Chapter_5_Formatting.pptx)]
+
+Formatting your code show's your professional attitude and care to details
+
+## The Purpose of Formatting
+- The functionality that you create today has a good chance of changing in the next release, but the **readability** of your code will have a profound effect on all the changes that will ever be made
+- Your style and discipline survives, even though your code does not
+
+## Vertical Formatting
+Small files are usually easier to understand than large files are.
+
+## The Newspaper Metaphor
+The topmost parts of the source file should provide the high-level concepts and algorithms. Detail should increase as we move downward, until at the end we find the lowest level functions and details in the source file
+
+## Vertical Openness Between Concepts
+Use blank lines to separate different concepts in your code. Eg. Properties, functions, companion object, …
+
+## Vertical density
+Lines of code that are tightly related should appear vertically dense. Eg. Related properties like two way data bindings
+
+## Vertical distance
+Concepts that are closely related should be kept vertically close to each other.
+
+### Variable Declarations
+Variables should be declared close to their usage.
+
+### Instance variables
+Put all instance variables of a class at the top of class.
+
+### Dependent Functions
+Functions that are dependent on each other should be close Caller above the callee.
+
+### Conceptual affinity
+Certain bits of code want to be near other bits.
+
+## Vertical Ordering
+Source code dependencies must be downward, details goes down.
+Just like newspaper that we see most important subjects abstracted out at top of page.
+
+## Horizontal Formatting
+Use 120 characters for line width in your IDE for better readability
+
+### Horizontal openness and density
+Put white space between separate concepts, eg. Function arguments, math statements
+
+### Horizontal alignment
+There is no need to use horizontal alignment for statements, because code automatic reformating will change it
+
+## Indentation
+Every scope of code structure, eg. File, class, method, statement block, … is indented one level to the right.
+Don't break indentation rule in single line lambda or anonymous blocks, I know this is tempting for make code smaller, but it makes it less readable instead.
+
+### Dummy scopes
+In one line statements like `while` with captured resource loop use indentation and braces to make it more visible
+
+## Team rules
+When you write code in a team, agree upon a coding style and follow team rules for it
diff --git a/notes/06_Chapter_6_Objects_and_Data_structures.md b/notes/06_Chapter_6_Objects_and_Data_structures.md
new file mode 100644
index 0000000..05bbd1b
--- /dev/null
+++ b/notes/06_Chapter_6_Objects_and_Data_structures.md
@@ -0,0 +1,52 @@
+# Chapter 6: Objects and Data structures [[Slide](../slides/06_Chapter_6_Objects_and_Data_structures.pptx)]
+
+## Data abstraction
+- We keep our variables private to prevent unintended dependency on them, so that we can change implementation.
+- If you expose your implementation detail to user, the chance of mistake and bug will raise
+
+## Data/Object Anti-Symmetry
+- `Procedural code is easy to add new functions without changing existing data structures
+ Object Oriented code is easy to add new classes without changing existing functions`
+- Procedural code is hard to add new data structures
+ OO code is hard to add new functions (because all classes must change)
+- Procedural code is complementory of OO code
+
+## The Law of Demeter
+`a module should not know about the innards of the objects it manipulates`
+
+Below code is violating the law of demeter:
+```java
+final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
+```
+
+### Train wrecks
+Calling multiple functions after returning object, one after another is called Train Wrecks.
+
+This would violate the law of demeter.
+
+If above code was returning only data structure instead of object, it wouldn't violate the law of demeter.
+```java
+final String outputDir = ctxt.options.scratchDir.absolutePath;
+```
+
+### Hybrids
+having functions, mutators, accessors for public and private variables makes a Hybrid code.
+
+It will makes it hard to add new functions and data structures.
+
+### Hiding Structure
+result of law of demeter is:
+```
+BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);
+```
+
+## Data Transfer Objects
+## DTO
+a data structure with public variables and no functions.
+
+### Bean
+private variables manipulated by getters and setters.
+
+### Active Record
+Special form of DTO. data structure with public (or bean-accessed) variables with extra navigational methods like save and find. (example: Model class in Laravel)
+- Putting business rules into these classes makes it a Hybrid structure and hard to change.
diff --git a/notes/07_Chapter_7_Error_Handling.md b/notes/07_Chapter_7_Error_Handling.md
new file mode 100644
index 0000000..d02479e
--- /dev/null
+++ b/notes/07_Chapter_7_Error_Handling.md
@@ -0,0 +1,35 @@
+# Chapter 7: Error Handling [[Slide](../slides/07_Chapter_7_Error_Handling.pptx)]
+
+Error handling is important, but if it obscures logic, it’s wrong.
+
+## Use Exceptions Rather Than Return Codes
+Using exception for error handling helps separate business logic from error code
+
+## Write Your Try-Catch-Finally Statement First
+Your catch has to leave your program in a consistent state, no matter what happens in the try.
+
+So writing try-catch statement first ensures your code is not jeopardizing consistency, and it will make structure of code simpler.
+
+## Use Unchecked Exceptions
+Checked exceptions force any change in low level code to affect higher levels.
+
+This will clearly violate Open/Closed principle.
+
+## Provide Context with Exceptions
+write a good and self-explanatory message with enough context to be shown in exception stack trace console
+
+## Define Exception Classes in Terms of a Caller’s Needs
+- Use wrapper class to compound different exceptions thrown from a function into a common exception type we care about
+- Use different classes only if there are times when you want to catch one exception and allow the other one to pass through.
+
+## Define the Normal Flow
+Encapsulate **special cases** inside your code so that the caller don't have to deal with default values when there is an exception
+
+## Don’t Return Null
+Instead of returning null you can return a special object like **Failure**
+or if you're returning a list of object you can simple return an **empty list**
+if you really need to return null, mention it in your function name like: getFirstOrNull()
+
+## Don’t Pass Null
+- avoid passing null when your argument does not support null
+- If you really want to pass null at least use a **nullable** type or **annotation** or any other proper means to declare your parameter as nullable
diff --git a/notes/08_Chapter_8_Boundaries.md b/notes/08_Chapter_8_Boundaries.md
new file mode 100644
index 0000000..08dede5
--- /dev/null
+++ b/notes/08_Chapter_8_Boundaries.md
@@ -0,0 +1,24 @@
+# Chapter 8: Boundaries [[Slide](../slides/08_Chapter_8_Boundaries.pptx)]
+
+We seldom control all the software in our systems. Sometimes we buy third-party packages
+or use open source. Other times we depend on teams in our own company to produce
+components or subsystems for us.
+
+## Using Third-Party Code
+- Interface providers strive for broad applicability, while interface users want it to be focused on their needs
+- Don’t pass map outside of system (eg. Public API) boundaries
+
+## Exploring and learning boundaries
+Learning test:
+We call third-party API, as we expect to use it in our application
+
+## Learning log4j
+We write test to see how it works
+
+## Learning tests are better than free
+Learning tests helps us to find boundary tests and ease our migrations if there is any breaking change in new releases
+
+## Clean boundaries
+Change is inevitable in software
+
+Code at the boundaries needs clear separation and tests that define expectations
diff --git a/notes/09_Chapter_9_Unit_tests.md b/notes/09_Chapter_9_Unit_tests.md
new file mode 100644
index 0000000..77d5125
--- /dev/null
+++ b/notes/09_Chapter_9_Unit_tests.md
@@ -0,0 +1,48 @@
+# Chapter 9: Unit tests
+
+## The three laws of TDD
+## First law
+You may not write production code until you have written a failing unit test.
+
+### Second law
+You may not write more of a unit test than is sufficient to fail, and not compliling is failing.
+
+### Third law
+You may not write more production code than is sufficient to pass the currently failing test.
+
+## Keeping Tests Clean
+- Tests must change as the production code evolves. The dirtier the tests, the harder they are to change.
+
+This section is important (all of it)
+
+## Tests enable the -ilities
+- If you have tests, you do not fear making changes to the code!
+- Tests enable all the -ilities because it enables CHANGE
+
+## Clean Tests
+Readability makes a test clean.
+clarity, simplicity, and density of expression makes test readable.
+Use BUILD-OPERATE-CHECK pattern for your tests.
+
+## Domain-Specific Testing Language
+Building functions and utilities become a specialized API used by the tests.
+
+## A Dual Standard
+There are things that you might never do in a production environment that are perfectly fine in a test environment. Usually they involve issues of memory or CPU efficiency. But they never involve issues of cleanliness
+
+## One Assert per Test
+the number of asserts in a test ought to be minimized (ideally one assert per test).
+
+## Single Concept per Test
+the best rule is that you should minimize the number of asserts per concept and test just one concept per test function.
+
+## F.I.R.S.T rule
+**Fast**: Tests should be fast, so that we could run them frequently.
+
+**Independent**: Tests should not depend on each other.
+
+**Repeatable**: Tests should be repeatable in any environment.
+
+**Self-Validating**: The tests should have a boolean output. Either they pass or fail.
+
+**Timely**: Unit tests should be written just before the production code that makes them pass.
diff --git a/notes/10_Chapter_10_Classes.md b/notes/10_Chapter_10_Classes.md
new file mode 100644
index 0000000..f918723
--- /dev/null
+++ b/notes/10_Chapter_10_Classes.md
@@ -0,0 +1,33 @@
+# Chapter 10: Classes
+
+## Class organization
+Put most important parts of code at top of class, eg. Public properties and functions
+
+## Encapsulation
+Keep variables and utility functions, private. Unless you need it in tests or other good reason.
+
+## Classes should be small!
+With functions we measured size by counting physical lines, with classes we use a different measure, we count responsibilities.
+
+## The single responsibility principle
+- A class or module should have one and only one reason to change
+- We can reuse codes with **SRP** priciple
+- Programmers have fear of breaking problems into too many small parts because they are afraid it would look complex
+- Larger portions of code hampers us by insisting we wade through lots of stuff we don't need to know right now.
+
+## Cohesion
+When Instance variables of a class are used in most of it's methods. We say this class has HIGH cohesion.
+Separating related variables and methods into more classes makes them more cohesive.
+
+## Maintaining cohesion results in many small classes
+- When classes lose cohesion, split them.
+- Breaking a large function into many smaller functions often gives us the opportunity to split several smaller classes out as well.
+
+## Organizing for change
+In clean system we organize our classes so as to reduce the risk of change.
+
+## Isolating from change
+Needs will change, therefore code will change.
+Instead of depending upon implementation details, create more abstractions and inject them with DIP (Dependency inversion principle)
+Code must be les coupled and more cohesive.
+Talk about **Cohesion** VS **Coupling**
diff --git a/notes/11_Chapter_11_Systems.md b/notes/11_Chapter_11_Systems.md
new file mode 100644
index 0000000..c72677a
--- /dev/null
+++ b/notes/11_Chapter_11_Systems.md
@@ -0,0 +1,71 @@
+# Chapter 11: Systems
+
+`Complexity kills. It sucks the life out of developers,
+it makes products difficult to plan, build, and test.`
+
+—Ray Ozzie, CTO, Microsoft Corporation
+
+## How would you build a city?
+- cities have teams of people who manage particular parts of the city, the water systems, power systems, traffic, law enforcement, building codes, and so forth
+- Although software teams are often organized like that too, the systems they work on
+ often don’t have the same separation of concerns and levels of abstraction.
+
+## Separate constructing a System from Using it
+Software systems should separate the startup process, when the application objects are
+constructed and the dependencies are “wired” together, from the runtime logic that takes
+over after startup.
+- Lazy initialization
+- Separation of concerns
+- Test double
+- Mock object
+
+## Separation of Main
+move all aspects of construction to main, or modules called by main, and to design the rest of the system assuming that all objects have been constructed and wired up appropriately
+
+## Factories
+To create instances of models use ABSTRACT FACTORY pattern . In this case you can easily swap factories in your test.
+
+## Dependency injection
+- Separating construction from use
+- Move responsibility of construction to another authoritative mechanism
+
+### Lazy initialization
+Don't create instance of object unless it's used
+
+## Scaling up
+It is a myth that we can get systems "right the first time."
+
+We implement only today's stories. Then refactor and expand the system to implement new stories tomorrow.
+This is the essence of iterative and incremental agility.
+
+TDD + Refactoring + Clean code
+
+## Cross-cutting concerns
+Research about AOP (aspect-oriented programming)
+Laravel environment might be using this approach
+
+## Java Proxies
+Annotation processors might be using this approach, take a look at mockfit
+
+## Pure Java AOP Framework
+- Android room library might be using this approach check it out
+- Decorator pattern
+
+## AspectJ aspects
+An extension language of Java to provide aspect programming
+
+## Test drive the system architecture
+- It is not necessary to do a Big Design Up Front. You can start your architecture so simple to meet user stories and evolve gradually
+- Even well-designed apis can be over-kill when they aren't really needed
+
+## Optimize decision making
+- **Modularity** and **Separation of concerns** make decentralized management and decision making possible.
+- You always have to make a choice, even if you’re not 100% sure if it’s the right one. It’s always better to take your best guess, and see how things work out, rather than spend endless hours debating one choice or another. (Analysis paralysis - Head first OOAD)
+
+## Use standards wisely, when they add demonstratble value
+You might have different frameworks or standards to do a job. In web development eg. Laravel, Django, Flask, Ktor, Asp.net, …
+
+If one minimal framework suffices your customer needs, don't obsessed with big luxiory tools that will only delay delivery
+
+## Systems need domain-specific languages
+Good DSL minimizes the "communication gap" between a domain concept and the code. Eg. Gradle, SQL, Html, …
diff --git a/notes/12_Chapter_12_Emergence.md b/notes/12_Chapter_12_Emergence.md
new file mode 100644
index 0000000..4f7256d
--- /dev/null
+++ b/notes/12_Chapter_12_Emergence.md
@@ -0,0 +1,26 @@
+# Chapter 12: Emergence
+
+Kent Beck's four rules of Simple Design in XPE book
+A design is simple if it follows these rules:
+1. Runs all the tests
+2. Contains no duplication
+3. Expresses the intent of the programmer
+4. Minimizes the number of classes and methods
+
+## Simple design rule 1: Runs all the tests
+If there is no simple way to verify that the system actually works as intended, then all the paper effort on design is questionable.
+Writing tests leads to better designs, because we will have to use dependency injection, interfaces, abstraction and more to make it simpler and minimize coupling.
+
+## Simple design rule 2-4: Refactoring
+The fact that we have tests, eliminates the fear that cleaning up the code will break it.
+
+## No duplication
+Duplication is the primary enemy of a well-designed system.
+Understanding how to achieve reuse in the small is essential to achieving reuse in large
+Template method pattern is a common technique for removing higher-level duplication
+
+## Expressive
+It's easy to write code that we understand, because at the time we write it we're deep in an understanding of the problem we're trying to solve.
+
+## Minimal classes and methods
+We must keep our functions and class counts low as well as making classes and methods small
diff --git a/notes/13_Chapter_13_Concurrency.md b/notes/13_Chapter_13_Concurrency.md
new file mode 100644
index 0000000..d68a237
--- /dev/null
+++ b/notes/13_Chapter_13_Concurrency.md
@@ -0,0 +1,112 @@
+# Chapter 13: Concurrency
+
+## Why Concurrency?
+- Decoupling what gets done from when it gets done.
+- Request constraints in web apps (eg. crawler, download manager, …)
+- IO, UI, CPU threads
+- Provide more efficient response time
+
+## Myths and Misconceptions
+- Concurrency always improves performance.
+- Design does not change when writing concurrent programs
+- Understanding concurrency issues is not important when working with a container
+ such as a Web or EJB container.
+
+### Truth
+- Concurrency incurs some overhead
+- Correct concurrency is complex
+- Concurrency bugs aren’t usually repeatable
+- Concurrency often requires a fundamental change in design strategy
+
+## Challenges
+**Race** condition
+
+## Concurrency Defense Principles
+### Single Responsibility Principle
+The SRP states that a given method/class/component should have a **single reason to change**.
+Recommendation: Keep your concurrency-related code separate from other code.
+
+### Corollary: Limit the Scope of Data
+Use **synchronized** keyword to protect shared objects.
+Restrict the number of places using shared objects.
+Recommendation: Take data encapsulation to heart; severely limit the access of any
+data that may be shared.
+
+### Corollary: Use Copies of Data
+Immutability matters
+
+if using copies of objects allows the code to avoid synchronizing, the savings in avoiding the intrinsic lock will likely make up for the additional creation and garbage collection overhead.
+
+### Corollary: Threads Should Be as Independent as Possible
+Recommendation: Attempt to partition data into independent subsets than can be
+operated on by independent threads, possibly in different processors.
+
+## Know Your Library
+- Thread safety
+- Executor framework
+- Nonblocking
+
+## Know Your Execution Models
+- Bound Resources
+- Mutual Exclusion
+- Starvation
+- Deadlock
+- Livelock
+
+### Producer-Consumer
+`One or more producer threads create some work and place it in a buffer or queue. One or
+more consumer threads acquire that work from the queue and complete it.`
+
+### Readers-Writers
+When you have a shared resource that primarily serves as a source of information for readers,
+but which is occasionally updated by writers
+
+### Dining Philosophers
+Each philosopher eat with two forks, and put down both forks when finished.
+
+## Beware Dependencies Between Synchronized Methods
+Avoid using more than one method on a shared object
+
+## Keep Synchronized Sections Small
+extending synchronization beyond the minimal critical section increases
+contention and degrades performance
+
+## Writing Correct Shut-Down Code Is Hard
+Think about shut-down early and get it working early.
+
+## Testing Threaded Code
+Write tests that have the potential to expose problems and then run them frequently
+
+### Treat Spurious Failures as Candidate Threading Issues
+Do not ignore system failures as one-offs.
+
+### Get Your Nonthreaded Code Working First
+Do not try to chase down nonthreading bugs and threading bugs
+at the same time. Make sure your code works outside of threads.
+
+### Make Your Threaded Code Pluggable
+Make your thread-based code especially pluggable so that you can run it in various configurations.
+
+### Make Your Threaded Code Tunable
+Getting the right balance of threads typically requires trial an error.
+
+### Run with More Threads Than Processors
+The more frequently your tasks swap, the more
+likely you’ll encounter code that is missing a critical section or causes deadlock
+
+### Run on Different Platforms
+Run your threaded code on all target platforms early and often.
+
+### Instrument Your Code to Try and Force Failures
+only a very few pathways out of the many thousands of possible pathways through a vulnerable
+section actually fail.
+
+## Code instrumentation: Hand-coded
+There are many problems with this approach:
+- You have to manually find appropriate places to do this.
+- How do you know where to put the call and what kind of call to use?
+- Leaving such code in a production environment unnecessarily slows the code down.
+- It’s a shotgun approach. You may or may not find flaws. Indeed, the odds aren’t with you.
+
+## Code instrumentation: Automated
+Use jiggling strategies to ferret out errors.
diff --git a/notes/14_Chapter_14_Successive_Refinement.md b/notes/14_Chapter_14_Successive_Refinement.md
new file mode 100644
index 0000000..52da100
--- /dev/null
+++ b/notes/14_Chapter_14_Successive_Refinement.md
@@ -0,0 +1,11 @@
+# Chapter 14: Successive Refinement
+
+This chapter is a case study in successive refinement. You will see a module that started
+well but did not scale. Then you will see how the module was refactored and cleaned.
+
+## Notes
+- To write clean code, you must first write dirty code and then clean it.
+- One of the best ways to ruin a program is to make massive changes to its structure in the name of improvement
+- using TDD, I am not allowed to make a change to the system that breaks that system
+- It is not enough for code to work. Code that works is often badly broken.
+ Programmers who satisfy themselves with merely working code are behaving unprofessionally.
diff --git a/notes/15_Chapter_15_Junit_Internals.md b/notes/15_Chapter_15_Junit_Internals.md
new file mode 100644
index 0000000..8d00e35
--- /dev/null
+++ b/notes/15_Chapter_15_Junit_Internals.md
@@ -0,0 +1,3 @@
+# Chapter 15: Junit Internals
+
+This chapter is about a ComparisonCompactor class and **refactoring** to a better version of it
\ No newline at end of file
diff --git a/notes/16_Chapter_16_Refactoring_SerialDate.md b/notes/16_Chapter_16_Refactoring_SerialDate.md
new file mode 100644
index 0000000..e647bdb
--- /dev/null
+++ b/notes/16_Chapter_16_Refactoring_SerialDate.md
@@ -0,0 +1,11 @@
+# Chapter 16: Refactoring SerialDate
+
+We have a **SerialDate** class from `org.jfree.date` and we want to refactor it.
+
+## First make it work
+we added some unit tests to cover %92 of code which was covered only %50 before.
+
+found some bugs and fixed along the way
+
+## Then make it right
+We refactored and splitted code into more pieces to make it more readable.
diff --git a/notes/17_Chapter_17_Smells_and_Heuristics.md b/notes/17_Chapter_17_Smells_and_Heuristics.md
new file mode 100644
index 0000000..fed0f26
--- /dev/null
+++ b/notes/17_Chapter_17_Smells_and_Heuristics.md
@@ -0,0 +1,218 @@
+# Chapter 17: Smells and Heuristics
+
+## Comments
+### C1: Inappropriate Information
+Comments should be reserved for technical notes about the code and design
+
+### C2: Obsolete Comment
+If you find an obsolete comment, it is best to update it or get rid of it as quickly as possible
+
+### C3: Redundant Comment
+A comment is redundant if it describes something that adequately describes itself
+
+### C4: Poorly Written Comment
+If you are going to write a comment, take the time to make sure it is the best comment you can write
+
+### C5: Commented-Out Code
+When you see commented-out code, delete it! Don’t worry, the source code control system still remembers it.
+
+## Environment
+### E1: Build Requires More Than One Step
+Building a project should be a single trivial operation.
+
+### E2: Tests Require More Than One Step
+You should be able to run all the unit tests with just one command.
+
+## Functions
+### F1: Too Many Arguments
+More than three is very questionable and should be avoided with prejudice.
+
+### F2: Output Arguments
+Readers expect arguments to be inputs, not outputs.
+
+### F3: Flag Arguments
+Boolean arguments loudly declare that the function does more than one thing.
+
+### F4: Dead Function
+Methods that are never called should be discarded.
+
+## General
+### G1: Multiple Languages in One Source File
+We should take pains to minimize both the number and extent of extra languages in our source files.
+
+### G2: Obvious Behavior Is Unimplemented
+The Principle of Least Surprise
+If the code surprisingly do something else than expected, users of code lose their trust in the original author and must fall back on reading the details of the code
+
+### G3: Incorrect Behavior at the Boundaries
+Don’t rely on your intuition. Look for every boundary condition and write a test for it.
+
+### G4: Overridden Safeties
+Turning off safety inspections may be soothing at first. but will result endless debugging sessions
+
+### G5: Duplication
+Don't repeat yourself (DRY)
+
+### G6: Code at Wrong Level of Abstraction
+Don't mix lower level and higher level of abstractions. separate them into good components.
+
+### G7: Base Classes Depending on Their Derivatives
+base classes should know nothing about their derivatives.
+
+### G8: Too Much Information
+Expose as little information as possible.
+
+### G9: Dead Code
+Dead code is code that isn’t executed.
+
+### G10: Vertical Separation
+Related codes must have least vertical distance from each other.
+
+### G11: Inconsistency
+Stick to your conventions across codebase.
+
+### G12: Clutter
+Redundant and unused codes makes clutter
+
+### G13: Artificial Coupling
+artificial coupling is a coupling between two modules that serves no direct purpose.
+
+### G14: Feature Envy
+Reaching other objects internals in a function.
+
+### G15: Selector Arguments
+Passing argument to a function in order to select the behavior of the function.
+
+### G16: Obscured Intent
+Using notations and symbols to shorten code would obscure our intent to reader.
+
+### G17: Misplaced Responsibility
+Code should be placed where a reader would naturally expect it to be.
+
+### G18: Inappropriate Static
+Prefer using nonstatic methods instead of static methods.
+
+### G19: Use Explanatory Variables
+Intermediate variables make it obvious what the outputs are.
+
+### G20: Function Names Should Say What They Do
+If you have to look at the implementation (or documentation) of the function to know
+what it does, then you should work to find a better name or rearrange the functionality.
+
+### G21: Understand the Algorithm
+Writing function to just work is not enough, make sure you understand how it works.
+
+### G22: Make Logical Dependencies Physical
+If one module depends upon another, that dependency should be physical, not just logical.
+The dependent module should not make assumptions (in other words, logical dependencies)
+about the module it depends upon. Rather it should explicitly ask that module for all
+the information it depends upon.
+
+### G23: Prefer Polymorphism to If/Else or Switch/Case
+There may be no more than one switch statement for a given type of selection. The cases in that switch statement must create polymorphic objects that take the place of other such switch statements in the rest of the system.
+
+### G24: Follow Standard Conventions
+Every team should follow a coding standard based on common industry norms.
+
+### G25: Replace Magic Numbers with Named Constants
+it is a bad idea to have raw numbers in your code.
+
+### G26: Be Precise
+Ambiguities and imprecision in code are either a result of disagreements or laziness.
+
+### G27: Structure over Convention
+Enforce design decisions with structure over convention.
+
+### G28: Encapsulate Conditionals
+Extract functions that explain the intent of the conditional.
+
+### G29: Avoid Negative Conditionals
+Negatives are just a bit harder to understand than positives.
+
+### G30: Functions Should Do One Thing
+It is often tempting to create functions that have multiple sections that perform a series of
+operations.
+
+### G31: Hidden Temporal Couplings
+Make the temporal coupling explicit by returning result from functions and putting as argument for next operation.
+
+### G32: Don’t Be Arbitrary
+Have a reason for the way you structure your code, and make sure that reason is communicated
+by the structure of the code.
+
+### G33: Encapsulate Boundary Conditions
+Boundary conditions are hard to keep track of. Put the processing for them in one place.
+
+### G34: Functions Should Descend Only One Level of Abstraction
+Mixing multiple levels of abstraction make's code harder to understand and change.
+
+### G35: Keep Configurable Data at High Levels
+If you have a constant such as a default or configuration value that is known and expected
+at a high level of abstraction, do not bury it in a low-level function.
+
+### G36: Avoid Transitive Navigation
+In general, we don’t want a single module to know much about its collaborators. More specifically, if A collaborates with B, and B collaborates with C, we don’t want modules that use A to know about C.
+
+## Java
+### J1: Avoid Long Import Lists by Using Wildcards
+If you use two or more classes from a package, then import the whole package with wildcards.
+
+### J2: Don’t Inherit Constants
+Instead of inheriting constants from interfaces, you can use static import
+
+### J3: Constants versus Enums
+Prefer using enums instead of constants.
+
+## Names
+### N1: Choose Descriptive Names
+Don’t be too quick to choose a name. Make sure the name is descriptive. your name must be pretty much what reader expect it to do.
+
+### N2: Choose Names at the Appropriate Level of Abstraction
+Don’t pick names that communicate implementation; choose names the reflect the level of
+abstraction of the class or function you are working in.
+
+### N3: Use Standard Nomenclature Where Possible
+Names are easier to understand if they are based on existing convention or usage.
+
+### N4: Unambiguous Names
+Choose names that make the workings of a function or variable unambiguous.
+
+### N5: Use Long Names for Long Scopes
+The longer the scope of the name, the longer and more precise the name should be.
+
+### N6: Avoid Encodings
+Keep your names free of Hungarian pollution.
+
+### N7: Names Should Describe Side-Effects
+Don’t hide side effects with a name. Don’t use a simple verb to describe a function that does more than just that simple action.
+
+## Tests
+### T1: Insufficient Tests
+The tests are insufficient so long as there are conditions that have not been explored by the
+tests or calculations that have not been validated.
+
+### T2: Use a Coverage Tool!
+Coverage tools reports gaps in your testing strategy.
+
+### T3: Don’t Skip Trivial Tests
+They are easy to write and have high documentary value.
+
+### T4: An Ignored Test Is a Question about an Ambiguity
+Sometimes we are uncertain about a behavioral detail because the requirements are
+unclear.
+
+### T5: Test Boundary Conditions
+often get the middle of an algorithm right but misjudge the boundaries.
+
+### T6: Exhaustively Test Near Bugs
+You’ll probably find that the bug was not alone.
+
+### T7: Patterns of Failure Are Revealing
+Sometimes just seeing the pattern of red and green on the test report is enough to spark the “Aha!” that leads to the solution.
+
+### T8: Test Coverage Patterns Can Be Revealing
+Looking at the code that is or is not executed by the passing tests gives clues to why the
+failing tests fail.
+
+### T9: Tests Should Be Fast
+do what you must, to keep your tests fast.
diff --git a/notes/18_Appendix_A_Concurrency_ii.md b/notes/18_Appendix_A_Concurrency_ii.md
new file mode 100644
index 0000000..017ee37
--- /dev/null
+++ b/notes/18_Appendix_A_Concurrency_ii.md
@@ -0,0 +1,187 @@
+# Appendix A: Concurrency ii
+
+## Client/Server Example
+We have a client/server socket connecting to each other to get data.
+We test performance of this code in a 10 seconds timeout.
+What factors affect performance ?
+- I/O—using a socket, connecting to a database, waiting for virtual memory swapping,
+ and so on.
+ - Threading will be benefitial
+- Processor—numerical calculations, regular expression processing, garbage collection,
+ and so on.
+ - Threading will not be benefitial that much
+
+### Adding Threading
+Applying concurrency and threads comes with some limitations in platform.
+we fixed this using Executor framework to handle it for us.
+There are different responsibilities to handle:
+- Socket connection management
+- Client processing
+- Threading policy
+- Server shutdown policy
+
+## Possible Paths of Execution
+```java
+public class IdGenerator {
+ int lastIdUsed;
+
+ public int incrementValue() {
+ return ++lastIdUsed;
+ }
+}
+```
+How many path's of execution might be when 2 threads call incrementValue() method?
+- Thread 1 gets the value of 94, thread 2 gets the value of 95, and lastIdUsed is now 95.
+- Thread 1 gets the value of 95, thread 2 gets the value of 94, and lastIdUsed is now 95.
+- Thread 1 gets the value of 94, thread 2 gets the value of 94, and lastIdUsed is now 94.
+
+### Number of Paths
+For this simple case of N instructions in a sequence, no looping or conditionals, and T
+threads, the total number of possible execution paths is equal to:
+
+`(NT)!/(N!)^T`
+
+for above example we have 8 lines of java bytecode so result is:
+
+`(8*2)!/(8!)^2 = 12,870`
+
+if we change method signature to :
+```java
+public synchronized void incrementValue() {
+ ++lastIdUsed;
+}
+```
+The number of possible execution pathways becomes two for two threads and **N!** in the
+general case.
+
+### Digging Deeper
+In Jvm specification assignment to a 32-bit value (eg. int) is uninterruptable. so this operation is **Atomic**. but 64-bit value like long is 2 atomic operations.
+
+## Knowing Your Library
+### Executor Framework
+Executor framework works with classes that implement Runnable or Callable and also supports Future
+
+**Runnable**: an interface to execute instructions without return value.
+
+**Callable**: an interface to execute instructions with a return value.
+
+**Future**: when code needs to execute multiple, independent operations and wait for both to finish.
+
+### Nonblocking Solutions
+In modern processors there is an operation called Compare and Swap (CAS) which allows us to use one single atomic operation for any assignment.
+see. AtomicBoolean, AtomicInteger and AtomicReference in Java.
+
+### Nonthread-Safe Classes
+- SimpleDateFormat
+- Database Connections
+- Containers in java.util
+- Servlets
+
+There are thread-safe classes in java.util.concurrent eg. `ConcurrentHashMap`
+
+## Dependencies Between Methods Can Break Concurrent Code
+Having multiple synchronized methods have a subtle side effect.
+if client use these methods and have some conditionals to choose between method calls, there will be boundary problems and inconsistencies.
+
+### Tolerate the Failure
+Sometimes you can set things up such that the failure causes no harm.
+
+### Client-Based Locking
+We can use synchronized lock for all of the clients using server code.
+This brings the risk of forgetting a client to lock and blowing system. and also violates DRY.
+
+### Server-Based Locking
+create a single method containing all concurrent operations in the server.
+In general, you should prefer server-based locking for these reasons:
+- It reduces repeated code
+- It allows for better performance
+- It reduces the possibility of error
+- It enforces a single policy
+- It reduces the scope of the shared variables
+
+If you don’t own server code, use **ADAPTER** pattern to wrap server call in a single place.
+
+## Increasing Throughput
+Consider a page reader program, which downloads some pages and prints statistics
+
+### Single-Thread Calculation of Throughput
+Lets assume following facts:
+- I/O time to retrieve a page (average): 1 second
+- Processing time to parse page (average): 0.5 seconds
+
+Total execution time = 1.5 seconds * N (pages)
+
+### Multithread Calculation of Throughput
+We aquire T times faster throughput where T is thread count.
+
+## Deadlock
+When some processes are waiting for each other to release shared resources.
+To really solve the problem of deadlock, we need to understand what causes it.
+There are four conditions required for deadlock to occur:
+- Mutual exclusion
+- Lock & wait
+- No preemption
+- Circular wait
+
+### Mutual exclusion
+hen multiple threads need to use the same resources and those resources :
+- Cannot be used by multiple threads at the same time.
+- Are limited in number.
+
+eg. Database connection, a file open for write
+
+**How to break?**
+- Using resources that allow simultaneous use, for example, AtomicInteger.
+- Increasing the number of resources such that it equals or exceeds the number of competing threads.
+- Checking that all your resources are free before seizing any.
+
+### Lock & Wait
+Once a thread acquires a resource, it will not release the resource until it has acquired all
+of the other resources it requires and has completed its work.
+
+**How to break?**
+refuse to wait, Check each resource before you seize it, and release all resources and start over if you run into one that’s busy.
+
+Problems:
+- Starvation
+- Livelock
+
+### No Preemption
+One thread cannot take resources away from another thread. Once a thread holds a
+resource, the only way for another thread to get it is for the holding thread to release it.
+
+**How to break?**
+When a thread discovers that a resource is busy, it asks the owner to release it. If the owner is also waiting for some other resource, it releases them all and starts over.
+
+### Circular Wait
+This is also referred to as the **deadly embrace**. Imagine two threads, T1 and T2, and two
+resources, R1 and R2. T1 has R1, T2 has R2. T1 also requires R2, and T2 also requires R1.
+
+**How to break?**
+if all threads can agree on a global ordering of resources and if they all allocate resources in that order, then deadlock is impossible.
+
+## Testing Multithreaded Code
+```java
+public class ClassWithThreadingProblem {
+ int nextId;
+
+ public int takeNextId() {
+ return nextId++;
+ }
+}
+```
+Here’s a description of a test that will prove the code is broken:
+- Remember the current value of nextId.
+- Create two threads, both of which call takeNextId() once.
+- Verify that nextId is two more than what we started with.
+- Run this until we demonstrate that nextId was only incremented by one instead of two.
+
+Using this approach, the chance that we pass this test is so low (once in million).
+- We can use a continuous integration server to run these tests for us with different configurations.
+- Run the test on every one of the target deployment platforms.
+- Run the tests on a machine with varying loads.
+
+`Make sure to carefully log the conditions under which the test failed.`
+
+## Tool Support for Testing Thread-Based Code
+Eg. ConTest from IBM
\ No newline at end of file
diff --git a/slides/00 - Introduction.pptx b/slides/00_Introduction.pptx
similarity index 100%
rename from slides/00 - Introduction.pptx
rename to slides/00_Introduction.pptx
diff --git a/slides/01 - Chapter 1 - Clean code.pptx b/slides/01_Chapter_1_Clean_code.pptx
similarity index 95%
rename from slides/01 - Chapter 1 - Clean code.pptx
rename to slides/01_Chapter_1_Clean_code.pptx
index 1c0ad51..695a561 100644
Binary files a/slides/01 - Chapter 1 - Clean code.pptx and b/slides/01_Chapter_1_Clean_code.pptx differ
diff --git a/slides/02 - Chapter 2 - Meaningful names.pptx b/slides/02_Chapter_2_Meaningful_names.pptx
similarity index 100%
rename from slides/02 - Chapter 2 - Meaningful names.pptx
rename to slides/02_Chapter_2_Meaningful_names.pptx
diff --git a/slides/03 - Chapter 3 - Functions.pptx b/slides/03_Chapter_3_Functions.pptx
similarity index 100%
rename from slides/03 - Chapter 3 - Functions.pptx
rename to slides/03_Chapter_3_Functions.pptx
diff --git a/slides/04 - Chapter 4 - Comments.pptx b/slides/04_Chapter_4_Comments.pptx
similarity index 96%
rename from slides/04 - Chapter 4 - Comments.pptx
rename to slides/04_Chapter_4_Comments.pptx
index b0704a9..a197691 100644
Binary files a/slides/04 - Chapter 4 - Comments.pptx and b/slides/04_Chapter_4_Comments.pptx differ
diff --git a/slides/05_Chapter_5_Formatting.pptx b/slides/05_Chapter_5_Formatting.pptx
new file mode 100644
index 0000000..9f960e3
Binary files /dev/null and b/slides/05_Chapter_5_Formatting.pptx differ
diff --git a/slides/06_Chapter_6_Objects_and_Data_structures.pptx b/slides/06_Chapter_6_Objects_and_Data_structures.pptx
new file mode 100644
index 0000000..d1528ad
Binary files /dev/null and b/slides/06_Chapter_6_Objects_and_Data_structures.pptx differ
diff --git a/slides/07_Chapter_7_Error_Handling.pptx b/slides/07_Chapter_7_Error_Handling.pptx
new file mode 100644
index 0000000..037153f
Binary files /dev/null and b/slides/07_Chapter_7_Error_Handling.pptx differ
diff --git a/slides/08_Chapter_8_Boundaries.pptx b/slides/08_Chapter_8_Boundaries.pptx
new file mode 100644
index 0000000..55d0133
Binary files /dev/null and b/slides/08_Chapter_8_Boundaries.pptx differ
diff --git a/src/main/java/MainEntry.java b/src/main/java/MainEntry.java
deleted file mode 100644
index a97f400..0000000
--- a/src/main/java/MainEntry.java
+++ /dev/null
@@ -1,6 +0,0 @@
-public class MainEntry {
-
- public static void main(String[] args) {
- System.out.println("Hello uncle bob!");
- }
-}
diff --git a/src/main/java/clean/code/added/to/make/code/build/Account.java b/src/main/java/clean/code/added/to/make/code/build/Account.java
new file mode 100644
index 0000000..81ce938
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/Account.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class Account {
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/AnnualDateRule.java b/src/main/java/clean/code/added/to/make/code/build/AnnualDateRule.java
new file mode 100644
index 0000000..ad7f05d
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/AnnualDateRule.java
@@ -0,0 +1,12 @@
+package clean.code.added.to.make.code.build;
+
+public class AnnualDateRule {
+ public SerialDate getDate(int year) {
+ return null; //TODO: Auto-generated
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return new Object();
+ }
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/Blah.java b/src/main/java/clean/code/added/to/make/code/build/Blah.java
new file mode 100644
index 0000000..d186e72
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/Blah.java
@@ -0,0 +1,7 @@
+package clean.code.added.to.make.code.build;
+
+public class Blah {
+ public PageCrawler getPageCrawler() {
+ return null; //TODO: Auto-generated
+ }
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/Column.java b/src/main/java/clean/code/added/to/make/code/build/Column.java
new file mode 100644
index 0000000..ae27187
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/Column.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class Column {
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/added/to/make/code/build/Criteria.java b/src/main/java/clean/code/added/to/make/code/build/Criteria.java
new file mode 100644
index 0000000..8c63c37
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/Criteria.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class Criteria {
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/DayAndMonthRule.java b/src/main/java/clean/code/added/to/make/code/build/DayAndMonthRule.java
new file mode 100644
index 0000000..4b95ab7
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/DayAndMonthRule.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class DayAndMonthRule extends AnnualDateRule {
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/PageCrawler.java b/src/main/java/clean/code/added/to/make/code/build/PageCrawler.java
new file mode 100644
index 0000000..04e92cb
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/PageCrawler.java
@@ -0,0 +1,15 @@
+package clean.code.added.to.make.code.build;
+
+public class PageCrawler {
+ public void setDeadEndStrategy(VirtualEnabledPageCrawler virtualEnabledPageCrawler) {
+ //TODO: Auto-generated
+ }
+
+ public WikiPage getPage(Blah root, WikiPagePath path) {
+ return null; //TODO: Auto-generated
+ }
+
+ public WikiPagePath getFullPath(WikiPage page) {
+ return null; //TODO: Auto-generated
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/added/to/make/code/build/PageCrawlerImpl.java b/src/main/java/clean/code/added/to/make/code/build/PageCrawlerImpl.java
new file mode 100644
index 0000000..65a44a1
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/PageCrawlerImpl.java
@@ -0,0 +1,7 @@
+package clean.code.added.to.make.code.build;
+
+public class PageCrawlerImpl {
+ public static WikiPage getInheritedPage(Object suite_setup_name, WikiPage wikiPage) {
+ return null; //TODO: Auto-generated
+ }
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/PageData.java b/src/main/java/clean/code/added/to/make/code/build/PageData.java
new file mode 100644
index 0000000..e8bcf04
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/PageData.java
@@ -0,0 +1,23 @@
+package clean.code.added.to.make.code.build;
+
+public class PageData {
+ public WikiPage getWikiPage() {
+ return null; //TODO: Auto-generated
+ }
+
+ public boolean hasAttribute(String test) {
+ return false; //TODO: Auto-generated
+ }
+
+ public Object getContent() {
+ return null; //TODO: Auto-generated
+ }
+
+ public void setContent(String s) {
+ //TODO: Auto-generated
+ }
+
+ public String getHtml() {
+ return null; //TODO: Auto-generated
+ }
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/PathParser.java b/src/main/java/clean/code/added/to/make/code/build/PathParser.java
new file mode 100644
index 0000000..47f6f14
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/PathParser.java
@@ -0,0 +1,11 @@
+package clean.code.added.to.make.code.build;
+
+public class PathParser {
+ public static WikiPagePath parse(String resource) {
+ return null; //TODO: Auto-generated
+ }
+
+ public static String render(WikiPagePath fullPath) {
+ return null; //TODO: Auto-generated
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/added/to/make/code/build/SerialDate.java b/src/main/java/clean/code/added/to/make/code/build/SerialDate.java
new file mode 100644
index 0000000..4d0c218
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/SerialDate.java
@@ -0,0 +1,22 @@
+package clean.code.added.to.make.code.build;
+
+public class SerialDate {
+ public static final int PRECEDING = 0;
+ public static final int NEAREST = 1;
+ public static final int FOLLOWING = 2;
+ public static int MINIMUM_YEAR_SUPPORTED;
+ public static int MAXIMUM_YEAR_SUPPORTED;
+ public static int MONDAY;
+
+ public static SerialDate getPreviousDayOfWeek(int dayOfWeek, SerialDate base) {
+ return null; //TODO: Auto-generated
+ }
+
+ public static SerialDate getNearestDayOfWeek(int dayOfWeek, SerialDate base) {
+ return null; //TODO: Auto-generated
+ }
+
+ public static SerialDate getFollowingDayOfWeek(int dayOfWeek, SerialDate base) {
+ return null; //TODO: Auto-generated
+ }
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/SuiteResponder.java b/src/main/java/clean/code/added/to/make/code/build/SuiteResponder.java
new file mode 100644
index 0000000..bb67d76
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/SuiteResponder.java
@@ -0,0 +1,6 @@
+package clean.code.added.to.make.code.build;
+
+public class SuiteResponder {
+ public static String SUITE_SETUP_NAME;
+ public static String SUITE_TEARDOWN_NAME;
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/VirtualEnabledPageCrawler.java b/src/main/java/clean/code/added/to/make/code/build/VirtualEnabledPageCrawler.java
new file mode 100644
index 0000000..52234d2
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/VirtualEnabledPageCrawler.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class VirtualEnabledPageCrawler {
+}
diff --git a/src/main/java/clean/code/added/to/make/code/build/WikiPage.java b/src/main/java/clean/code/added/to/make/code/build/WikiPage.java
new file mode 100644
index 0000000..9cb45cb
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/WikiPage.java
@@ -0,0 +1,15 @@
+package clean.code.added.to.make.code.build;
+
+public class WikiPage {
+ public PageData getData() {
+ return null; //TODO: Auto-generated
+ }
+
+ public PageCrawler getPageCrawler() {
+ return null; //TODO: Auto-generated
+ }
+
+ public WikiPagePath getFullPath(WikiPage page) {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/added/to/make/code/build/WikiPagePath.java b/src/main/java/clean/code/added/to/make/code/build/WikiPagePath.java
new file mode 100644
index 0000000..c65f4c0
--- /dev/null
+++ b/src/main/java/clean/code/added/to/make/code/build/WikiPagePath.java
@@ -0,0 +1,4 @@
+package clean.code.added.to.make.code.build;
+
+public class WikiPagePath {
+}
diff --git a/src/main/java/clean/code/appendixA/ClassWithThreadingProblem.java b/src/main/java/clean/code/appendixA/ClassWithThreadingProblem.java
new file mode 100644
index 0000000..9187ca5
--- /dev/null
+++ b/src/main/java/clean/code/appendixA/ClassWithThreadingProblem.java
@@ -0,0 +1,9 @@
+package clean.code.appendixA;
+
+public class ClassWithThreadingProblem {
+ public int nextId;
+
+ public int takeNextId() {
+ return nextId++;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/appendixA/Example.java b/src/main/java/clean/code/appendixA/Example.java
new file mode 100644
index 0000000..af855c9
--- /dev/null
+++ b/src/main/java/clean/code/appendixA/Example.java
@@ -0,0 +1,17 @@
+package clean.code.appendixA;
+
+/**
+ * Example class to demonstrate bytecode
+ * and concurrency issue with non atomic operations
+ */
+public class Example {
+ int lastId;
+
+ public void resetId() {
+ lastId = 0;
+ }
+
+ public int getNextId() {
+ return ++lastId;
+ }
+}
diff --git a/src/main/java/clean/code/appendixA/MessageUtils.java b/src/main/java/clean/code/appendixA/MessageUtils.java
new file mode 100644
index 0000000..a771efb
--- /dev/null
+++ b/src/main/java/clean/code/appendixA/MessageUtils.java
@@ -0,0 +1,24 @@
+package clean.code.appendixA;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class MessageUtils {
+ public static void sendMessage(Socket socket, String message)
+ throws IOException {
+ OutputStream stream = socket.getOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(stream);
+ oos.writeUTF(message);
+ oos.flush();
+ }
+
+ public static String getMessage(Socket socket) throws IOException {
+ InputStream stream = socket.getInputStream();
+ ObjectInputStream ois = new ObjectInputStream(stream);
+ return ois.readUTF();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/appendixA/nonthreaded/Server.java b/src/main/java/clean/code/appendixA/nonthreaded/Server.java
new file mode 100644
index 0000000..9cede32
--- /dev/null
+++ b/src/main/java/clean/code/appendixA/nonthreaded/Server.java
@@ -0,0 +1,82 @@
+package clean.code.appendixA.nonthreaded;
+
+import clean.code.appendixA.MessageUtils;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+public class Server implements Runnable {
+ ServerSocket serverSocket;
+ volatile boolean keepProcessing = true;
+
+ public Server(int port, int millisecondsTimeout) throws IOException {
+ serverSocket = new ServerSocket(port);
+ serverSocket.setSoTimeout(millisecondsTimeout);
+
+ }
+
+ public void run() {
+ System.out.printf("Server Starting\n");
+
+ while (keepProcessing) {
+ try {
+ System.out.printf("accepting client\n");
+ Socket socket = serverSocket.accept();
+ System.out.printf("got client\n");
+ process(socket);
+ } catch (Exception e) {
+ handle(e);
+ }
+ }
+
+ }
+
+ private void handle(Exception e) {
+ if (!(e instanceof SocketException)) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stopProcessing() {
+ keepProcessing = false;
+ closeIgnoringException(serverSocket);
+ }
+ void process(Socket socket) {
+ if (socket == null)
+ return;
+
+ try {
+ System.out.printf("Server: getting message\n");
+ String message = MessageUtils.getMessage(socket);
+ System.out.printf("Server: got message: %s\n", message);
+ Thread.sleep(1000);
+ System.out.printf("Server: sending reply: %s\n", message);
+ MessageUtils.sendMessage(socket, "Processed: " + message);
+ System.out.printf("Server: sent\n");
+ closeIgnoringException(socket);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private void closeIgnoringException(Socket socket) {
+ if (socket != null)
+ try {
+ socket.close();
+ } catch (IOException ignore) {
+ }
+
+ }
+
+ private void closeIgnoringException(ServerSocket serverSocket) {
+ if (serverSocket != null)
+ try {
+ serverSocket.close();
+ } catch (IOException ignore) {
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/appendixA/threaded/Server.java b/src/main/java/clean/code/appendixA/threaded/Server.java
new file mode 100644
index 0000000..6c05b36
--- /dev/null
+++ b/src/main/java/clean/code/appendixA/threaded/Server.java
@@ -0,0 +1,91 @@
+package clean.code.appendixA.threaded;
+
+import clean.code.appendixA.MessageUtils;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+public class Server implements Runnable {
+ ServerSocket serverSocket;
+ volatile boolean keepProcessing = true;
+
+ public Server(int port, int millisecondsTimeout) throws IOException {
+ serverSocket = new ServerSocket(port);
+ serverSocket.setSoTimeout(millisecondsTimeout);
+
+ }
+
+ public void run() {
+ System.out.printf("Server Starting\n");
+
+ while (keepProcessing) {
+ try {
+ System.out.printf("accepting client\n");
+ Socket socket = serverSocket.accept();
+ System.out.printf("got client\n");
+ process(socket);
+ } catch (Exception e) {
+ handle(e);
+ }
+ }
+
+ }
+
+ private void handle(Exception e) {
+ if (!(e instanceof SocketException)) {
+ e.printStackTrace();
+ }
+ }
+
+ public void stopProcessing() {
+ keepProcessing = false;
+ closeIgnoringException(serverSocket);
+ }
+
+ void process(final Socket socket) {
+ if (socket == null)
+ return;
+
+ Runnable clientHandler = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ System.out.printf("Server: getting message\n");
+ String message = MessageUtils.getMessage(socket);
+ System.out.printf("Server: got message: %s\n", message);
+ Thread.sleep(1000);
+ System.out.printf("Server: sending reply: %s\n", message);
+ MessageUtils.sendMessage(socket, "Processed: " + message);
+ System.out.printf("Server: sent\n");
+ closeIgnoringException(socket);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ Thread clientConnection = new Thread(clientHandler);
+ clientConnection.start();
+
+ }
+
+ private void closeIgnoringException(Socket socket) {
+ if (socket != null)
+ try {
+ socket.close();
+ } catch (IOException ignore) {
+ }
+
+ }
+
+ private void closeIgnoringException(ServerSocket serverSocket) {
+ if (serverSocket != null)
+ try {
+ serverSocket.close();
+ } catch (IOException ignore) {
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter02/GuessStatisticsMessage.java b/src/main/java/clean/code/chapter02/GuessStatisticsMessage.java
new file mode 100644
index 0000000..7725185
--- /dev/null
+++ b/src/main/java/clean/code/chapter02/GuessStatisticsMessage.java
@@ -0,0 +1,42 @@
+package clean.code.chapter02;
+
+public class GuessStatisticsMessage {
+ private String number;
+ private String verb;
+ private String pluralModifier;
+
+ public String make(char candidate, int count) {
+ createPluralDependentMessageParts(count);
+ return String.format(
+ "There %s %s %s%s",
+ verb, number, candidate, pluralModifier );
+ }
+
+ private void createPluralDependentMessageParts(int count) {
+ if (count == 0) {
+ thereAreNoLetters();
+ } else if (count == 1) {
+ thereIsOneLetter();
+ } else {
+ thereAreManyLetters(count);
+ }
+ }
+
+ private void thereAreManyLetters(int count) {
+ number = Integer.toString(count);
+ verb = "are";
+ pluralModifier = "s";
+ }
+
+ private void thereIsOneLetter() {
+ number = "1";
+ verb = "is";
+ pluralModifier = "";
+ }
+
+ private void thereAreNoLetters() {
+ number = "no";
+ verb = "are";
+ pluralModifier = "s";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter03/HtmlUnit.java b/src/main/java/clean/code/chapter03/HtmlUnit.java
new file mode 100644
index 0000000..fd2c5f0
--- /dev/null
+++ b/src/main/java/clean/code/chapter03/HtmlUnit.java
@@ -0,0 +1,70 @@
+package clean.code.chapter03;
+
+import clean.code.added.to.make.code.build.*;
+
+public class HtmlUnit {
+ public static String testableHtml(
+ PageData pageData,
+ boolean includeSuiteSetup
+ ) throws Exception {
+ WikiPage wikiPage = pageData.getWikiPage();
+ StringBuffer buffer = new StringBuffer();
+ if (pageData.hasAttribute("Test")) {
+ if (includeSuiteSetup) {
+ WikiPage suiteSetup =
+ PageCrawlerImpl.getInheritedPage(
+ SuiteResponder.SUITE_SETUP_NAME, wikiPage
+ );
+ if (suiteSetup != null) {
+ WikiPagePath pagePath =
+ suiteSetup.getPageCrawler().getFullPath(suiteSetup);
+ String pagePathName = PathParser.render(pagePath);
+ buffer.append("!include -setup .")
+ .append(pagePathName)
+ .append("\n");
+ }
+ }
+ WikiPage setup =
+ PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);
+ if (setup != null) {
+ WikiPagePath setupPath =
+ wikiPage.getPageCrawler().getFullPath(setup);
+ String setupPathName = PathParser.render(setupPath);
+ buffer.append("!include -setup .")
+ .append(setupPathName)
+ .append("\n");
+ }
+ }
+ buffer.append(pageData.getContent());
+ if (pageData.hasAttribute("Test")) {
+ WikiPage teardown =
+ PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);
+ if (teardown != null) {
+ WikiPagePath tearDownPath =
+ wikiPage.getPageCrawler().getFullPath(teardown);
+ String tearDownPathName = PathParser.render(tearDownPath);
+ buffer.append("\n")
+ .append("!include -teardown .")
+ .append(tearDownPathName)
+ .append("\n");
+ }
+ if (includeSuiteSetup) {
+ WikiPage suiteTeardown =
+ PageCrawlerImpl.getInheritedPage(
+ SuiteResponder.SUITE_TEARDOWN_NAME,
+ wikiPage
+ );
+ if (suiteTeardown != null) {
+ WikiPagePath pagePath =
+ suiteTeardown.getPageCrawler().getFullPath (suiteTeardown);
+ String pagePathName = PathParser.render(pagePath);
+ buffer.append("!include -teardown .")
+ .append(pagePathName)
+ .append("\n");
+ }
+ }
+ }
+ pageData.setContent(buffer.toString());
+ return pageData.getHtml();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter03/SetupTeardownIncluder.java b/src/main/java/clean/code/chapter03/SetupTeardownIncluder.java
new file mode 100644
index 0000000..f59c33a
--- /dev/null
+++ b/src/main/java/clean/code/chapter03/SetupTeardownIncluder.java
@@ -0,0 +1,106 @@
+package clean.code.chapter03;
+
+import clean.code.added.to.make.code.build.*;
+
+public class SetupTeardownIncluder {
+ private PageData pageData;
+ private boolean isSuite;
+ private WikiPage testPage;
+ private StringBuffer newPageContent;
+ private PageCrawler pageCrawler;
+
+ public static String render(PageData pageData) throws Exception {
+ return render(pageData, false);
+ }
+
+ public static String render(PageData pageData, boolean isSuite)
+ throws Exception {
+ return new SetupTeardownIncluder(pageData).render(isSuite);
+ }
+
+ private SetupTeardownIncluder(PageData pageData) {
+ this.pageData = pageData;
+ testPage = pageData.getWikiPage();
+ pageCrawler = testPage.getPageCrawler();
+ newPageContent = new StringBuffer();
+ }
+
+ private String render(boolean isSuite) throws Exception {
+ this.isSuite = isSuite;
+ if (isTestPage())
+ includeSetupAndTeardownPages();
+ return pageData.getHtml();
+ }
+
+ private boolean isTestPage() throws Exception {
+ return pageData.hasAttribute("Test");
+ }
+
+ private void includeSetupAndTeardownPages() throws Exception {
+ includeSetupPages();
+ includePageContent();
+ includeTeardownPages();
+ updatePageContent();
+ }
+ private void includeSetupPages() throws Exception {
+ if (isSuite)
+ includeSuiteSetupPage();
+ includeSetupPage();
+ }
+
+ private void includeSuiteSetupPage() throws Exception {
+ include(SuiteResponder.SUITE_SETUP_NAME, "-setup");
+ }
+
+ private void includeSetupPage() throws Exception {
+ include("SetUp", "-setup");
+ }
+
+ private void includePageContent() throws Exception {
+ newPageContent.append(pageData.getContent());
+ }
+
+ private void includeTeardownPages() throws Exception {
+ includeTeardownPage();
+ if (isSuite)
+ includeSuiteTeardownPage();
+ }
+
+ private void includeTeardownPage() throws Exception {
+ include("TearDown", "-teardown");
+ }
+
+ private void includeSuiteTeardownPage() throws Exception {
+ include(SuiteResponder.SUITE_TEARDOWN_NAME, "-teardown");
+ }
+
+ private void updatePageContent() throws Exception {
+ pageData.setContent(newPageContent.toString());
+ }
+
+ private void include(String pageName, String arg) throws Exception {
+ WikiPage inheritedPage = findInheritedPage(pageName);
+ if (inheritedPage != null) {
+ String pagePathName = getPathNameForPage(inheritedPage);
+ buildIncludeDirective(pagePathName, arg);
+ }
+ }
+
+ private WikiPage findInheritedPage(String pageName) throws Exception {
+ return PageCrawlerImpl.getInheritedPage(pageName, testPage);
+ }
+
+ private String getPathNameForPage(WikiPage page) throws Exception {
+ WikiPagePath pagePath = pageCrawler.getFullPath(page);
+ return PathParser.render(pagePath);
+ }
+
+ private void buildIncludeDirective(String pagePathName, String arg) {
+ newPageContent
+ .append("\n!include ")
+ .append(arg)
+ .append(" .")
+ .append(pagePathName)
+ .append("\n");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter04/GeneratePrimes.java b/src/main/java/clean/code/chapter04/GeneratePrimes.java
new file mode 100644
index 0000000..3369c1d
--- /dev/null
+++ b/src/main/java/clean/code/chapter04/GeneratePrimes.java
@@ -0,0 +1,81 @@
+package clean.code.chapter04;
+
+/**
+ * This class Generates prime numbers up to a user specified
+ * maximum. The algorithm used is the Sieve of Eratosthenes.
+ *
+ * Eratosthenes of Cyrene, b. c. 276 BC, Cyrene, Libya -- + * d. c. 194, Alexandria. The first man to calculate the + * circumference of the Earth. Also known for working on + * calendars with leap years and ran the library at Alexandria. + *
+ * The algorithm is quite simple. Given an array of integers
+ * starting at 2. Cross out all multiples of 2. Find the next
+ * uncrossed integer, and cross out all of its multiples.
+ * Repeat untilyou have passed the square root of the maximum
+ * value.
+ *
+ * @author Alphonse
+ * @version 13 Feb 2002 atp
+ */
+
+public class GeneratePrimes
+{
+ /**
+ * @param maxValue is the generation limit.
+ */
+ public static int[] generatePrimes(int maxValue)
+ {
+ if (maxValue >= 2) // the only valid case
+ {
+ // declarations
+ int s = maxValue + 1; // size of array
+ boolean[] f = new boolean[s];
+ int i;
+ // initialize array to true.
+ for (i = 0; i < s; i++)
+ f[i] = true;
+
+ // get rid of known non-primes
+ f[0] = f[1] = false;
+
+ // sieve
+ int j;
+ for (i = 2; i < Math.sqrt(s) + 1; i++)
+ {
+ if (f[i]) // if i is uncrossed, cross its multiples.
+ {
+ for (j = 2 * i; j < s; j += i)
+ f[j] = false; // multiple is not prime
+ }
+ }
+
+ // how many primes are there?
+ int count = 0;
+ for (i = 0; i < s; i++)
+ {
+ if (f[i])
+ count++; // bump count.
+ }
+
+ int[] primes = new int[count];
+
+ // move the primes into the result
+ for (i = 0, j = 0; i < s; i++)
+ {
+ if (f[i]) // if prime
+ primes[j++] = i;
+ }
+
+ return primes; // return the primes
+ }
+ else // maxValue < 2
+ return new int[0]; // return null array if bad input.
+ }
+
+ public static void main(String[] args) {
+ for (int i: generatePrimes(50)) {
+ System.out.print(i + " ");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter04/PrimeGenerator.java b/src/main/java/clean/code/chapter04/PrimeGenerator.java
new file mode 100644
index 0000000..20d6f25
--- /dev/null
+++ b/src/main/java/clean/code/chapter04/PrimeGenerator.java
@@ -0,0 +1,81 @@
+package clean.code.chapter04;
+
+/**
+ * This class Generates prime numbers up to a user specified
+ * maximum. The algorithm used is the Sieve of Eratosthenes.
+ * Given an array of integers starting at 2:
+ * Find the first uncrossed integer, and cross out all its
+ * multiples. Repeat until there are no more multiples
+ * in the array.
+ */
+
+public class PrimeGenerator {
+ private static boolean[] crossedOut;
+ private static int[] result;
+
+ public static int[] generatePrimes(int maxValue) {
+ if (maxValue < 2)
+ return new int[0];
+ else {
+ uncrossIntegersUpTo(maxValue);
+ crossOutMultiples();
+ putUncrossedIntegersIntoResult();
+ return result;
+ }
+ }
+
+ private static void uncrossIntegersUpTo(int maxValue) {
+ crossedOut = new boolean[maxValue + 1];
+ for (int i = 2; i < crossedOut.length; i++)
+ crossedOut[i] = false;
+ }
+
+ private static void crossOutMultiples() {
+ int limit = determineIterationLimit();
+ for (int i = 2; i <= limit; i++)
+ if (notCrossed(i))
+ crossOutMultiplesOf(i);
+ }
+
+ private static int determineIterationLimit() {
+ // Every multiple in the array has a prime factor that
+ // is less than or equal to the root of the array size,
+ // so we don't have to cross out multiples of numbers
+ // larger than that root.
+ double iterationLimit = Math.sqrt(crossedOut.length);
+ return (int) iterationLimit;
+ }
+
+ private static void crossOutMultiplesOf(int i) {
+ for (int multiple = 2 * i;
+ multiple < crossedOut.length;
+ multiple += i)
+ crossedOut[multiple] = true;
+ }
+
+ private static boolean notCrossed(int i) {
+ return crossedOut[i] == false;
+ }
+
+ private static void putUncrossedIntegersIntoResult() {
+ result = new int[numberOfUncrossedIntegers()];
+ for (int j = 0, i = 2; i < crossedOut.length; i++)
+ if (notCrossed(i))
+ result[j++] = i;
+ }
+
+ private static int numberOfUncrossedIntegers() {
+ int count = 0;
+ for (int i = 2; i < crossedOut.length; i++)
+ if (notCrossed(i))
+ count++;
+
+ return count;
+ }
+
+ public static void main(String[] args) {
+ for (int i : generatePrimes(50)) {
+ System.out.print(i + " ");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter04/wc.java b/src/main/java/clean/code/chapter04/wc.java
new file mode 100644
index 0000000..e874f02
--- /dev/null
+++ b/src/main/java/clean/code/chapter04/wc.java
@@ -0,0 +1,29 @@
+package clean.code.chapter04;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class wc {
+ public static void main(String[] args) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String line;
+ int lineCount = 0;
+ int charCount = 0;
+ int wordCount = 0;
+ try {
+ while ((line = in.readLine()) != null) {
+ lineCount++;
+ charCount += line.length();
+ String words[] = line.split("\\W");
+ wordCount += words.length;
+ } //while
+ System.out.println("wordCount = " + wordCount);
+ System.out.println("lineCount = " + lineCount);
+ System.out.println("charCount = " + charCount);
+ } // try
+ catch (IOException e) {
+ System.err.println("Error:" + e.getMessage());
+ } //catch
+ } //main
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter05/CodeAnalyzer.java b/src/main/java/clean/code/chapter05/CodeAnalyzer.java
new file mode 100644
index 0000000..ab87e45
--- /dev/null
+++ b/src/main/java/clean/code/chapter05/CodeAnalyzer.java
@@ -0,0 +1,117 @@
+package clean.code.chapter05;
+
+import javax.naming.directory.Attributes;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class CodeAnalyzer implements JavaFileAnalysis {
+ private int lineCount;
+ private int maxLineWidth;
+ private int widestLineNumber;
+ private LineWidthHistogram lineWidthHistogram;
+ private int totalChars;
+
+ public CodeAnalyzer() {
+ lineWidthHistogram = new LineWidthHistogram();
+ }
+
+ public static List
+ * Used by the SerialDate and RegularTimePeriod classes.
+ *
+ * @author David Gilbert
+ */
+ public interface MonthConstants {
+
+ /** Constant for January. */
+ public static final int JANUARY = 1;
+
+ /** Constant for February. */
+ public static final int FEBRUARY = 2;
+
+ /** Constant for March. */
+ public static final int MARCH = 3;
+
+ /** Constant for April. */
+ public static final int APRIL = 4;
+
+ /** Constant for May. */
+ public static final int MAY = 5;
+
+ /** Constant for June. */
+ public static final int JUNE = 6;
+
+ /** Constant for July. */
+ public static final int JULY = 7;
+
+ /** Constant for August. */
+ public static final int AUGUST = 8;
+
+ /** Constant for September. */
+ public static final int SEPTEMBER = 9;
+
+ /** Constant for October. */
+ public static final int OCTOBER = 10;
+
+ /** Constant for November. */
+ public static final int NOVEMBER = 11;
+
+ /** Constant for December. */
+ public static final int DECEMBER = 12;
+
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/original/SerialDate.java b/src/main/java/clean/code/chapter16/original/SerialDate.java
new file mode 100644
index 0000000..aa39ad5
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/original/SerialDate.java
@@ -0,0 +1,1132 @@
+package clean.code.chapter16.original;
+
+/* ========================================================================
+ * JCommon : a free general purpose class library for the Java(tm) platform
+ * ========================================================================
+ *
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+ *
+ * Project Info: http://www.jfree.org/jcommon/index.html
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
+ * in the United States and other countries.]
+ *
+ * ---------------
+ * SerialDate.java
+ * ---------------
+ * (C) Copyright 2001-2005, by Object Refinery Limited.
+ *
+ * Original Author: David Gilbert (for Object Refinery Limited);
+ * Contributor(s): -;
+ *
+ * $Id: SerialDate.java,v 1.7 2005/11/03 09:25:17 mungady Exp $
+ *
+ *
+ * Changes (from 11-Oct-2001)
+ * fixme (1) : changelog is redundant here
+ * --------------------------
+ * 11-Oct-2001 : Re-organised the class and moved it to new package
+ * com.jrefinery.date (DG);
+ * 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate
+ * class (DG);
+ * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate
+ * class is gone (DG); Changed getPreviousDayOfWeek(),
+ * getFollowingDayOfWeek() and getNearestDayOfWeek() to correct
+ * bugs (DG);
+ * 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
+ * 29-May-2002 : Moved the month constants into a separate interface
+ * (MonthConstants) (DG);
+ * 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
+ * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
+ * 13-Mar-2003 : Implemented Serializable (DG);
+ * 29-May-2003 : Fixed bug in addMonths method (DG);
+ * 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
+ * 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);
+ *
+ */
+
+import java.io.Serializable;
+import java.text.DateFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+/**
+ * An abstract class that defines our requirements for manipulating dates,
+ * without tying down a particular implementation.
+ * fixme (2): html tags are redundant
+ *
+ * Be aware that there is a deliberate bug in Excel that recognises the year
+ * 1900 as a leap year when in fact it is not a leap year. You can find more
+ * information on the Microsoft website in article Q181370:
+ *
+ * http://support.microsoft.com/support/kb/articles/Q181/3/70.asp
+ *
+ * Excel uses the convention that 1-Jan-1900 = 1. This class uses the
+ * convention 1-Jan-1900 = 2.
+ * The result is that the day number in this class will be different to the
+ * Excel figure for January and February 1900...but then Excel adds in an extra
+ * day (29-Feb-1900 which does not actually exist!) and from that point forward
+ * the day numbers will match.
+ *
+ * @author David Gilbert
+ */
+public class SpreadsheetDate extends SerialDate {
+
+ /** For serialization. */
+ private static final long serialVersionUID = -2039586705374454461L;
+
+ /**
+ * The day number (1-Jan-1900 = 2, 2-Jan-1900 = 3, ..., 31-Dec-9999 =
+ * 2958465).
+ */
+ private int serial;
+
+ /** The day of the month (1 to 28, 29, 30 or 31 depending on the month). */
+ private int day;
+
+ /** The month of the year (1 to 12). */
+ private int month;
+
+ /** The year (1900 to 9999). */
+ private int year;
+
+ /** An optional description for the date. */
+ private String description;
+
+ /**
+ * Creates a new date instance.
+ *
+ * @param day the day (in the range 1 to 28/29/30/31).
+ * @param month the month (in the range 1 to 12).
+ * @param year the year (in the range 1900 to 9999).
+ */
+ public SpreadsheetDate(final int day, final int month, final int year) {
+
+ if ((year >= 1900) && (year <= 9999)) {
+ this.year = year;
+ }
+ else {
+ throw new IllegalArgumentException(
+ "The 'year' argument must be in range 1900 to 9999."
+ );
+ }
+
+ if ((month >= MonthConstants.JANUARY)
+ && (month <= MonthConstants.DECEMBER)) {
+ this.month = month;
+ }
+ else {
+ throw new IllegalArgumentException(
+ "The 'month' argument must be in the range 1 to 12."
+ );
+ }
+
+ if ((day >= 1) && (day <= SerialDate.lastDayOfMonth(month, year))) {
+ this.day = day;
+ }
+ else {
+ throw new IllegalArgumentException("Invalid 'day' argument.");
+ }
+
+ // the serial number needs to be synchronised with the day-month-year...
+ this.serial = calcSerial(day, month, year);
+
+ this.description = null;
+
+ }
+
+ /**
+ * Standard constructor - creates a new date object representing the
+ * specified day number (which should be in the range 2 to 2958465.
+ *
+ * @param serial the serial number for the day (range: 2 to 2958465).
+ */
+ public SpreadsheetDate(final int serial) {
+
+ if ((serial >= SERIAL_LOWER_BOUND) && (serial <= SERIAL_UPPER_BOUND)) {
+ this.serial = serial;
+ }
+ else {
+ throw new IllegalArgumentException(
+ "SpreadsheetDate: Serial must be in range 2 to 2958465.");
+ }
+
+ // the day-month-year needs to be synchronised with the serial number...
+ calcDayMonthYear();
+
+ }
+
+ /**
+ * Returns the description that is attached to the date. It is not
+ * required that a date have a description, but for some applications it
+ * is useful.
+ *
+ * @return The description that is attached to the date.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Sets the description for the date.
+ *
+ * @param description the description for this date (
+ * The codes are defined in the {@link SerialDate} class as:
+ *
+ * This method will return true ONLY if the object is an instance of the
+ * {@link SerialDate} base class, and it represents the same day as this
+ * {@link SpreadsheetDate}.
+ *
+ * @param object the object to compare (
+ * 1-Jan-1900 = 2.
+ *
+ * @param d the day.
+ * @param m the month.
+ * @param y the year.
+ *
+ * @return the serial number from the day, month and year.
+ */
+ private int calcSerial(final int d, final int m, final int y) {
+ final int yy = ((y - 1900) * 365) + SerialDate.leapYearCount(y - 1);
+ int mm = SerialDate.AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH[m];
+ if (m > MonthConstants.FEBRUARY) {
+ if (SerialDate.isLeapYear(y)) {
+ mm = mm + 1;
+ }
+ }
+ final int dd = d;
+ return yy + mm + dd + 1;
+ }
+
+ /**
+ * Calculate the day, month and year from the serial number.
+ */
+ private void calcDayMonthYear() {
+
+ // get the year from the serial date
+ final int days = this.serial - SERIAL_LOWER_BOUND;
+ // overestimated because we ignored leap days
+ final int overestimatedYYYY = 1900 + (days / 365);
+ final int leaps = SerialDate.leapYearCount(overestimatedYYYY);
+ final int nonleapdays = days - leaps;
+ // underestimated because we overestimated years
+ int underestimatedYYYY = 1900 + (nonleapdays / 365);
+
+ if (underestimatedYYYY == overestimatedYYYY) {
+ this.year = underestimatedYYYY;
+ }
+ else {
+ int ss1 = calcSerial(1, 1, underestimatedYYYY);
+ while (ss1 <= this.serial) {
+ underestimatedYYYY = underestimatedYYYY + 1;
+ ss1 = calcSerial(1, 1, underestimatedYYYY);
+ }
+ this.year = underestimatedYYYY - 1;
+ }
+
+ final int ss2 = calcSerial(1, 1, this.year);
+
+ int[] daysToEndOfPrecedingMonth
+ = AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH;
+
+ if (isLeapYear(this.year)) {
+ daysToEndOfPrecedingMonth
+ = LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH;
+ }
+
+ // get the month from the serial date
+ int mm = 1;
+ int sss = ss2 + daysToEndOfPrecedingMonth[mm] - 1;
+ while (sss < this.serial) {
+ mm = mm + 1;
+ sss = ss2 + daysToEndOfPrecedingMonth[mm] - 1;
+ }
+ this.month = mm - 1;
+
+ // what's left is d(+1);
+ this.day = this.serial - ss2
+ - daysToEndOfPrecedingMonth[this.month] + 1;
+
+ }
+
+ }
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/solution/DateInterval.java b/src/main/java/clean/code/chapter16/solution/DateInterval.java
new file mode 100644
index 0000000..39925e7
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/solution/DateInterval.java
@@ -0,0 +1,26 @@
+package clean.code.chapter16.solution;
+
+public enum DateInterval {
+ OPEN {
+ public boolean isIn(int d, int left, int right) {
+ return d > left && d < right;
+ }
+ },
+ CLOSED_LEFT {
+ public boolean isIn(int d, int left, int right) {
+ return d >= left && d < right;
+ }
+ },
+ CLOSED_RIGHT {
+ public boolean isIn(int d, int left, int right) {
+ return d > left && d <= right;
+ }
+ },
+ CLOSED {
+ public boolean isIn(int d, int left, int right) {
+ return d >= left && d <= right;
+ }
+ };
+
+ public abstract boolean isIn(int d, int left, int right);
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/solution/DateUtil.java b/src/main/java/clean/code/chapter16/solution/DateUtil.java
new file mode 100644
index 0000000..d580147
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/solution/DateUtil.java
@@ -0,0 +1,32 @@
+package clean.code.chapter16.solution;
+
+import java.text.DateFormatSymbols;
+
+public class DateUtil {
+ private static DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
+
+ public static String[] getMonthNames() {
+ return dateFormatSymbols.getMonths();
+ }
+
+ public static boolean isLeapYear(int year) {
+ boolean fourth = year % 4 == 0;
+ boolean hundredth = year % 100 == 0;
+ boolean fourHundredth = year % 400 == 0;
+ return fourth && (!hundredth || fourHundredth);
+ }
+
+ public static int lastDayOfMonth(Month month, int year) {
+ if (month == Month.FEBRUARY && isLeapYear(year))
+ return month.lastDay() + 1;
+ else
+ return month.lastDay();
+ }
+
+ public static int leapYearCount(int year) {
+ int leap4 = (year - 1896) / 4;
+ int leap100 = (year - 1800) / 100;
+ int leap400 = (year - 1600) / 400;
+ return leap4 - leap100 + leap400;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/solution/Day.java b/src/main/java/clean/code/chapter16/solution/Day.java
new file mode 100644
index 0000000..e01b666
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/solution/Day.java
@@ -0,0 +1,54 @@
+package clean.code.chapter16.solution;
+
+import java.util.Calendar;
+import java.text.DateFormatSymbols;
+
+public enum Day {
+ MONDAY(Calendar.MONDAY),
+ TUESDAY(Calendar.TUESDAY),
+ WEDNESDAY(Calendar.WEDNESDAY),
+ THURSDAY(Calendar.THURSDAY),
+ FRIDAY(Calendar.FRIDAY),
+ SATURDAY(Calendar.SATURDAY),
+ SUNDAY(Calendar.SUNDAY);
+
+ private final int index;
+ private static DateFormatSymbols dateSymbols = new DateFormatSymbols();
+
+ Day(int day) {
+ index = day;
+ }
+
+ public static Day fromInt(int index) throws IllegalArgumentException {
+ for (Day d : Day.values())
+ if (d.index == index)
+ return d;
+ throw new IllegalArgumentException(
+ String.format("Illegal day index: %d.", index));
+ }
+
+ public static Day parse(String s) throws IllegalArgumentException {
+ String[] shortWeekdayNames =
+ dateSymbols.getShortWeekdays();
+ String[] weekDayNames =
+ dateSymbols.getWeekdays();
+
+ s = s.trim();
+ for (Day day : Day.values()) {
+ if (s.equalsIgnoreCase(shortWeekdayNames[day.index]) ||
+ s.equalsIgnoreCase(weekDayNames[day.index])) {
+ return day;
+ }
+ }
+ throw new IllegalArgumentException(
+ String.format("%s is not a valid weekday string", s));
+ }
+
+ public String toString() {
+ return dateSymbols.getWeekdays()[index];
+ }
+
+ public int toInt() {
+ return index;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/solution/DayDate.java b/src/main/java/clean/code/chapter16/solution/DayDate.java
new file mode 100644
index 0000000..c961d67
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/solution/DayDate.java
@@ -0,0 +1,154 @@
+package clean.code.chapter16.solution;
+
+/* ========================================================================
+ * JCommon : a free general purpose class library for the Java(tm) platform
+ * ========================================================================
+ *
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+.
+*/
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An abstract class that represents immutable dates with a precision of
+ * one day. The implementation will map each date to an integer that
+ * represents an ordinal number of days from some fixed origin.
+ *
+ * For example, Good Friday can be specified as 'the Friday PRECEDING Easter
+ * Sunday'.
+ *
+ * @author David Gilbert
+ */
+ public class RelativeDayOfWeekRule extends AnnualDateRule {
+
+ /** A reference to the annual date rule on which this rule is based. */
+ private AnnualDateRule subrule;
+
+ /**
+ * The day of the week (SerialDate.MONDAY, SerialDate.TUESDAY, and so on).
+ */
+ private int dayOfWeek;
+
+ /** Specifies which day of the week (PRECEDING, NEAREST or FOLLOWING). */
+ private int relative;
+
+ /**
+ * Default constructor - builds a rule for the Monday following 1 January.
+ */
+ public RelativeDayOfWeekRule() {
+ this(new DayAndMonthRule(), SerialDate.MONDAY, SerialDate.FOLLOWING);
+ }
+
+ /**
+ * Standard constructor - builds rule based on the supplied sub-rule.
+ *
+ * @param subrule the rule that determines the reference date.
+ * @param dayOfWeek the day-of-the-week relative to the reference date.
+ * @param relative indicates *which* day-of-the-week (preceding, nearest
+ * or following).
+ */
+ public RelativeDayOfWeekRule(final AnnualDateRule subrule,
+ final int dayOfWeek, final int relative) {
+ this.subrule = subrule;
+ this.dayOfWeek = dayOfWeek;
+ this.relative = relative;
+ }
+
+ /**
+ * Returns the sub-rule (also called the reference rule).
+ *
+ * @return The annual date rule that determines the reference date for this
+ * rule.
+ */
+ public AnnualDateRule getSubrule() {
+ return this.subrule;
+ }
+
+ /**
+ * Sets the sub-rule.
+ *
+ * @param subrule the annual date rule that determines the reference date
+ * for this rule.
+ */
+ public void setSubrule(final AnnualDateRule subrule) {
+ this.subrule = subrule;
+ }
+
+ /**
+ * Returns the day-of-the-week for this rule.
+ *
+ * @return the day-of-the-week for this rule.
+ */
+ public int getDayOfWeek() {
+ return this.dayOfWeek;
+ }
+
+ /**
+ * Sets the day-of-the-week for this rule.
+ *
+ * @param dayOfWeek the day-of-the-week (SerialDate.MONDAY,
+ * SerialDate.TUESDAY, and so on).
+ */
+ public void setDayOfWeek(final int dayOfWeek) {
+ this.dayOfWeek = dayOfWeek;
+ }
+
+ /**
+ * Returns the 'relative' attribute, that determines *which*
+ * day-of-the-week we are interested in (SerialDate.PRECEDING,
+ * SerialDate.NEAREST or SerialDate.FOLLOWING).
+ *
+ * @return The 'relative' attribute.
+ */
+ public int getRelative() {
+ return this.relative;
+ }
+
+ /**
+ * Sets the 'relative' attribute (SerialDate.PRECEDING, SerialDate.NEAREST,
+ * SerialDate.FOLLOWING).
+ *
+ * @param relative determines *which* day-of-the-week is selected by this
+ * rule.
+ */
+ public void setRelative(final int relative) {
+ this.relative = relative;
+ }
+
+ /**
+ * Creates a clone of this rule.
+ *
+ * @return a clone of this rule.
+ *
+ * @throws CloneNotSupportedException this should never happen.
+ */
+ public Object clone() throws CloneNotSupportedException {
+ final RelativeDayOfWeekRule duplicate
+ = (RelativeDayOfWeekRule) super.clone();
+ duplicate.subrule = (AnnualDateRule) duplicate.getSubrule().clone();
+ return duplicate;
+ }
+
+ /**
+ * Returns the date generated by this rule, for the specified year.
+ *
+ * @param year the year (1900 <= year <= 9999).
+ *
+ * @return The date generated by the rule for the given year (possibly
+ * true if the supplied integer code represents a
+ * valid day-of-the-week, and false otherwise.
+ *
+ * @param code the code being checked for validity.
+ * @return true if the supplied integer code represents a
+ * valid day-of-the-week, and false otherwise.
+ * fixme (29): We can remove this function because we can use Day enum
+ */
+ public static boolean isValidWeekdayCode(final int code) {
+
+ switch (code) {
+ case SUNDAY:
+ case MONDAY:
+ case TUESDAY:
+ case WEDNESDAY:
+ case THURSDAY:
+ case FRIDAY:
+ case SATURDAY:
+ return true;
+ default:
+ return false;
+ }
+
+ }
+
+ /**
+ * fixme (30): java doc is not adding worthwhile information => remove javadoc
+ * fixme (33): this method does not really belong here => Move to Day.parse() function
+ * Converts the supplied string to a day of the week.
+ *
+ * @param s a string representing the day of the week.
+ * @return -1 if the string is not convertable, the day of
+ * the week otherwise.
+ */
+ public static int stringToWeekdayCode(String s) {
+
+ // fixme (31): declaring these variables as final does not do any purpose
+ final String[] shortWeekdayNames
+ = DATE_FORMAT_SYMBOLS.getShortWeekdays();
+ final String[] weekDayNames = DATE_FORMAT_SYMBOLS.getWeekdays();
+
+ int result = -1;
+ s = s.trim();
+ for (int i = 0; i < weekDayNames.length; i++) {
+ // TODO (0): 5/1/2021 we just changed equals to equalsIgnoreCase here and 4 lines below
+ // fixme (32): What's the point of duplicate if statements here? we can use || operator
+ if (s.equalsIgnoreCase(shortWeekdayNames[i])) {
+ result = i;
+ break;
+ }
+ if (s.equalsIgnoreCase(weekDayNames[i])) {
+ result = i;
+ break;
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Returns a string representing the supplied day-of-the-week.
+ *
+ * Need to find a better approach.
+ *
+ * @param weekday the day of the week.
+ * @return a string representing the supplied day-of-the-week.
+ * fixme (34): this method does not really belong here => Move to Day.toString() function
+ */
+ public static String weekdayCodeToString(final int weekday) {
+
+ final String[] weekdays = DATE_FORMAT_SYMBOLS.getWeekdays();
+ return weekdays[weekday];
+
+ }
+
+ /**
+ * Returns an array of month names.
+ *
+ * @return an array of month names.
+ * fixme (36): this method is not used
+ */
+ public static String[] getMonths() {
+
+ return getMonths(false);
+
+ }
+
+ /**
+ * Returns an array of month names.
+ *
+ * @param shortened a flag indicating that shortened month names should
+ * be returned.
+ * @return an array of month names.
+ * fixme (35): function name is not good, it's returning only name of month
+ */
+ public static String[] getMonths(final boolean shortened) {
+
+ if (shortened) {
+ return DATE_FORMAT_SYMBOLS.getShortMonths();
+ } else {
+ return DATE_FORMAT_SYMBOLS.getMonths();
+ }
+
+ }
+
+ /**
+ * Returns true if the supplied integer code represents a valid month.
+ *
+ * @param code the code being checked for validity.
+ * @return true if the supplied integer code represents a
+ * valid month.
+ */
+ // fixme (6): using Month constant you can get rid of this method because everything is using enum
+ public static boolean isValidMonthCode(final int code) {
+
+ switch (code) {
+ case JANUARY:
+ case FEBRUARY:
+ case MARCH:
+ case APRIL:
+ case MAY:
+ case JUNE:
+ case JULY:
+ case AUGUST:
+ case SEPTEMBER:
+ case OCTOBER:
+ case NOVEMBER:
+ case DECEMBER:
+ return true;
+ default:
+ return false;
+ }
+
+ }
+
+ /**
+ * Returns the quarter for the specified month.
+ *
+ * @param code the month code (1-12).
+ * @return the quarter that the month belongs to.
+ * @throws IllegalArgumentException
+ *
+ */
+ // fixme (7): using Month constant you can get rid of this method because everything is using enum
+ public static int monthCodeToQuarter(final int code) {
+
+ switch (code) {
+ case JANUARY:
+ case FEBRUARY:
+ case MARCH:
+ return 1;
+ case APRIL:
+ case MAY:
+ case JUNE:
+ return 2;
+ case JULY:
+ case AUGUST:
+ case SEPTEMBER:
+ return 3;
+ case OCTOBER:
+ case NOVEMBER:
+ case DECEMBER:
+ return 4;
+ default:
+ throw new IllegalArgumentException(
+ "SerialDate.monthCodeToQuarter: invalid month code.");
+ }
+
+ }
+
+ /**
+ * Returns a string representing the supplied month.
+ *
+ * The string returned is the long form of the month name taken from the
+ * default locale.
+ *
+ * @param month the month.
+ * @return a string representing the supplied month.
+ * fixme (37): this function does not belong here => move to Month class and use a better name
+ */
+ public static String monthCodeToString(final int month) {
+
+ return monthCodeToString(month, false);
+
+ }
+
+ /**
+ * Returns a string representing the supplied month.
+ *
+ * The string returned is the long or short form of the month name taken
+ * from the default locale.
+ *
+ * @param month the month.
+ * @param shortened if true return the abbreviation of the
+ * month.
+ * @return a string representing the supplied month.
+ * @throws IllegalArgumentException
+ * fixme (38): this function does not belong here => move to Month class and use a better name
+ */
+ public static String monthCodeToString(final int month,
+ final boolean shortened) {
+
+ // check arguments...
+ if (!isValidMonthCode(month)) {
+ throw new IllegalArgumentException(
+ "SerialDate.monthCodeToString: month outside valid range.");
+ }
+
+ final String[] months;
+
+ if (shortened) {
+ months = DATE_FORMAT_SYMBOLS.getShortMonths();
+ } else {
+ months = DATE_FORMAT_SYMBOLS.getMonths();
+ }
+
+ return months[month - 1];
+
+ }
+
+ /**
+ * Converts a string to a month code.
+ *
+ * This method will return one of the constants JANUARY, FEBRUARY, ...,
+ * DECEMBER that corresponds to the string. If the string is not
+ * recognised, this method returns -1.
+ *
+ * @param s the string to parse.
+ * @return -1 if the string is not parseable, the month of the
+ * year otherwise.
+ * fixme (39): this function does not belong here => move to Month class and use a better name
+ */
+ public static int stringToMonthCode(String s) {
+
+ final String[] shortMonthNames = DATE_FORMAT_SYMBOLS.getShortMonths();
+ final String[] monthNames = DATE_FORMAT_SYMBOLS.getMonths();
+
+ int result = -1;
+ s = s.trim();
+
+ // first try parsing the string as an integer (1-12)...
+ try {
+ result = Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ // suppress
+ }
+
+ // now search through the month names...
+ if ((result < 1) || (result > 12)) {
+ // TODO (1, 2): 5/1/2021 just added result = -1 and changed s.equals to s.equalsIgnoreCase at two of below statements
+ result = -1;
+ for (int i = 0; i < monthNames.length; i++) {
+ if (s.equalsIgnoreCase(shortMonthNames[i])) {
+ result = i + 1;
+ break;
+ }
+ if (s.equalsIgnoreCase(monthNames[i])) {
+ result = i + 1;
+ break;
+ }
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Returns true if the supplied integer code represents a valid
+ * week-in-the-month, and false otherwise.
+ *
+ * @param code the code being checked for validity.
+ * @return true if the supplied integer code represents a
+ * valid week-in-the-month.
+ * fixme (40): redundant method because we moved these constants to WeekInMonth
+ */
+ public static boolean isValidWeekInMonthCode(final int code) {
+
+ switch (code) {
+ case FIRST_WEEK_IN_MONTH:
+ case SECOND_WEEK_IN_MONTH:
+ case THIRD_WEEK_IN_MONTH:
+ case FOURTH_WEEK_IN_MONTH:
+ case LAST_WEEK_IN_MONTH:
+ return true;
+ default:
+ return false;
+ }
+
+ }
+
+ /**
+ * Determines whether or not the specified year is a leap year.
+ *
+ * @param yyyy the year (in the range 1900 to 9999).
+ * @return true if the specified year is a leap year.
+ */
+ public static boolean isLeapYear(final int yyyy) {
+ // fixme (41): not readable code, also it can be moved to a DateUtil class instead
+ if ((yyyy % 4) != 0) {
+ return false;
+ } else if ((yyyy % 400) == 0) {
+ return true;
+ } else if ((yyyy % 100) == 0) {
+ return false;
+ } else {
+ return true;
+ }
+
+ }
+
+ /**
+ * Returns the number of leap years from 1900 to the specified year
+ * INCLUSIVE.
+ *
+ * Note that 1900 is not a leap year.
+ *
+ * @param yyyy the year (in the range 1900 to 9999).
+ * @return the number of leap years from 1900 to the specified year.
+ * fixme (42): this function is used only in SpreadsheetDate class => move it there
+ */
+ public static int leapYearCount(final int yyyy) {
+
+ final int leap4 = (yyyy - 1896) / 4;
+ final int leap100 = (yyyy - 1800) / 100;
+ final int leap400 = (yyyy - 1600) / 400;
+ return leap4 - leap100 + leap400;
+
+ }
+
+ /**
+ * Returns the number of the last day of the month, taking into account
+ * leap years.
+ *
+ * @param month the month.
+ * @param yyyy the year (in the range 1900 to 9999).
+ * @return the number of the last day of the month.
+ * fixme (43): This function does not belong here => move it to Month class
+ */
+ public static int lastDayOfMonth(final int month, final int yyyy) {
+
+ final int result = LAST_DAY_OF_MONTH[month];
+ if (month != FEBRUARY) {
+ return result;
+ } else if (isLeapYear(yyyy)) {
+ return result + 1;
+ } else {
+ return result;
+ }
+
+ }
+
+ /**
+ * Creates a new date by adding the specified number of days to the base
+ * date.
+ *
+ * @param days the number of days to add (can be negative).
+ * @param base the base date.
+ * @return a new date.
+ * fixme (44): this function must be instance method not static
+ */
+ public static SerialDate addDays(final int days, final SerialDate base) {
+
+ final int serialDayNumber = base.toSerial() + days;
+ return SerialDate.createInstance(serialDayNumber);
+
+ }
+
+ /**
+ * Creates a new date by adding the specified number of months to the base
+ * date.
+ *
+ * If the base date is close to the end of the month, the day on the result
+ * may be adjusted slightly: 31 May + 1 month = 30 June.
+ *
+ * @param months the number of months to add (can be negative).
+ * @param base the base date.
+ * @return a new date.
+ * fixme (45): this function must be instance method not static
+ */
+ public static SerialDate addMonths(final int months,
+ final SerialDate base) {
+ // fixme (46): algorithm and namings are a bit complicated
+ // fixme (47): instead of getYYYY() name use getYear()!
+ final int yy = (12 * base.getYYYY() + base.getMonth() + months - 1)
+ / 12;
+ final int mm = (12 * base.getYYYY() + base.getMonth() + months - 1)
+ % 12 + 1;
+ final int dd = Math.min(
+ base.getDayOfMonth(), SerialDate.lastDayOfMonth(mm, yy)
+ );
+ return SerialDate.createInstance(dd, mm, yy);
+
+ }
+
+ /**
+ * Creates a new date by adding the specified number of years to the base
+ * date.
+ *
+ * @param years the number of years to add (can be negative).
+ * @param base the base date.
+ * @return A new date.
+ * fixme (48): this function must be instance method not static
+ */
+ public static SerialDate addYears(final int years, final SerialDate base) {
+
+ final int baseY = base.getYYYY();
+ final int baseM = base.getMonth();
+ final int baseD = base.getDayOfMonth();
+
+ final int targetY = baseY + years;
+ final int targetD = Math.min(
+ baseD, SerialDate.lastDayOfMonth(baseM, targetY)
+ );
+
+ return SerialDate.createInstance(targetD, baseM, targetY);
+
+ }
+
+ /**
+ * Returns the latest date that falls on the specified day-of-the-week and
+ * is BEFORE the base date.
+ *
+ * @param targetWeekday a code for the target day-of-the-week.
+ * @param base the base date.
+ * @return the latest date that falls on the specified day-of-the-week and
+ * is BEFORE the base date.
+ * fixme (49): this function must be instance method not static
+ */
+ public static SerialDate getPreviousDayOfWeek(final int targetWeekday,
+ final SerialDate base) {
+
+ // check arguments...
+ if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
+ throw new IllegalArgumentException(
+ "Invalid day-of-the-week code."
+ );
+ }
+
+ // fixme (50): Use some explaining temporary variables for god sake!
+ // find the date...
+ final int adjust;
+ final int baseDOW = base.getDayOfWeek();
+ if (baseDOW > targetWeekday) {
+ adjust = Math.min(0, targetWeekday - baseDOW);
+ } else {
+ adjust = -7 + Math.max(0, targetWeekday - baseDOW);
+ }
+
+ return SerialDate.addDays(adjust, base);
+
+ }
+
+ /**
+ * Returns the earliest date that falls on the specified day-of-the-week
+ * and is AFTER the base date.
+ *
+ * @param targetWeekday a code for the target day-of-the-week.
+ * @param base the base date.
+ * @return the earliest date that falls on the specified day-of-the-week
+ * and is AFTER the base date.
+ * fixme (51): this function must be instance method not static
+ */
+ public static SerialDate getFollowingDayOfWeek(final int targetWeekday,
+ final SerialDate base) {
+
+ // check arguments...
+ if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
+ throw new IllegalArgumentException(
+ "Invalid day-of-the-week code."
+ );
+ }
+
+ // fixme (52): Use some explaining temporary variables for god sake!
+ // find the date...
+ final int adjust;
+ final int baseDOW = base.getDayOfWeek();
+ // TODO (3): 5/1/2021 changed below condition from > to >=
+ if (baseDOW >= targetWeekday) {
+ adjust = 7 + Math.min(0, targetWeekday - baseDOW);
+ } else {
+ adjust = Math.max(0, targetWeekday - baseDOW);
+ }
+
+ return SerialDate.addDays(adjust, base);
+ }
+
+ /**
+ * Returns the date that falls on the specified day-of-the-week and is
+ * CLOSEST to the base date.
+ *
+ * @param targetDOW a code for the target day-of-the-week.
+ * @param base the base date.
+ * @return the date that falls on the specified day-of-the-week and is
+ * CLOSEST to the base date.
+ * fixme (53): this function must be instance method not static
+ */
+ public static SerialDate getNearestDayOfWeek(final int targetDOW,
+ final SerialDate base) {
+
+ // check arguments...
+ if (!SerialDate.isValidWeekdayCode(targetDOW)) {
+ throw new IllegalArgumentException(
+ "Invalid day-of-the-week code."
+ );
+ }
+
+ // fixme (54): Use some explaining temporary variables for god sake!
+ // find the date...
+ int delta = targetDOW - base.getDayOfWeek();
+ int positiveDelta = delta + 7;
+ int adjust = positiveDelta % 7;
+ if (adjust > 3)
+ adjust -= 7;
+ // TODO (4): 5/1/2021 below algorithm is wrong and above is correct
+// final int baseDOW = base.getDayOfWeek();
+// int adjust = -Math.abs(targetDOW - baseDOW);
+// if (adjust >= 4) {
+// adjust = 7 - adjust;
+// }
+// if (adjust <= -4) {
+// adjust = 7 + adjust;
+// }
+ return SerialDate.addDays(adjust, base);
+
+ }
+
+ /**
+ * Rolls the date forward to the last day of the month.
+ *
+ * @param base the base date.
+ * @return a new serial date.
+ * fixme (55): What's the use of passing current object in argument?
+ */
+ public SerialDate getEndOfCurrentMonth(final SerialDate base) {
+ final int last = SerialDate.lastDayOfMonth(
+ base.getMonth(), base.getYYYY()
+ );
+ return SerialDate.createInstance(last, base.getMonth(), base.getYYYY());
+ }
+
+ /**
+ * Returns a string corresponding to the week-in-the-month code.
+ *
+ * Need to find a better approach.
+ *
+ * @param count an integer code representing the week-in-the-month.
+ * @return a string corresponding to the week-in-the-month code.
+ * fixme (56): Move this function to where it belongs (WeekInMonth)
+ */
+ public static String weekInMonthToString(final int count) {
+
+ switch (count) {
+ case SerialDate.FIRST_WEEK_IN_MONTH:
+ return "First";
+ case SerialDate.SECOND_WEEK_IN_MONTH:
+ return "Second";
+ case SerialDate.THIRD_WEEK_IN_MONTH:
+ return "Third";
+ case SerialDate.FOURTH_WEEK_IN_MONTH:
+ return "Fourth";
+ case SerialDate.LAST_WEEK_IN_MONTH:
+ return "Last";
+ default:
+ // todo (5): fixed test by throwing exception instead of returning string
+ throw new IllegalArgumentException("SerialDate.weekInMonthToString(): invalid code.");
+// return "SerialDate.weekInMonthToString(): invalid code.";
+ }
+
+ }
+
+ /**
+ * Returns a string representing the supplied 'relative'.
+ *
+ * Need to find a better approach.
+ *
+ * @param relative a constant representing the 'relative'.
+ * @return a string representing the supplied 'relative'.
+ */
+ public static String relativeToString(final int relative) {
+
+ switch (relative) {
+ case SerialDate.PRECEDING:
+ return "Preceding";
+ case SerialDate.NEAREST:
+ return "Nearest";
+ case SerialDate.FOLLOWING:
+ return "Following";
+ default:
+ // todo (6): fixed test by throwing exception instead of returning string
+ throw new IllegalArgumentException("ERROR : Relative To String");
+// return "ERROR : Relative To String";
+ }
+
+ }
+
+ /**
+ * Factory method that returns an instance of some concrete subclass of
+ * {@link SerialDate}.
+ *
+ * @param day the day (1-31).
+ * @param month the month (1-12).
+ * @param yyyy the year (in the range 1900 to 9999).
+ * @return An instance of {@link SerialDate}.
+ */
+ public static SerialDate createInstance(final int day, final int month,
+ final int yyyy) {
+ return new SpreadsheetDate(day, month, yyyy);
+ }
+
+ /**
+ * Factory method that returns an instance of some concrete subclass of
+ * {@link SerialDate}.
+ *
+ * @param serial the serial number for the day (1 January 1900 = 2).
+ * @return a instance of SerialDate.
+ */
+ // fixme (13): Really?!! current class is abstract and here we are returning one of it's Implementation (SpreadsheetDate)
+ // => abstract class should not know about implementation use ABSTRACT FACTORY pattern and create a DayDateFactory
+ public static SerialDate createInstance(final int serial) {
+ return new SpreadsheetDate(serial);
+ }
+
+ /**
+ * Factory method that returns an instance of a subclass of SerialDate.
+ *
+ * @param date A Java date object.
+ * @return a instance of SerialDate.
+ */
+ public static SerialDate createInstance(final java.util.Date date) {
+
+ final GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(date);
+ return new SpreadsheetDate(calendar.get(Calendar.DATE),
+ calendar.get(Calendar.MONTH) + 1,
+ calendar.get(Calendar.YEAR));
+
+ }
+
+ /**
+ * Returns the serial number for the date, where 1 January 1900 = 2 (this
+ * corresponds, almost, to the numbering system used in Microsoft Excel for
+ * Windows and Lotus 1-2-3).
+ *
+ * @return the serial number for the date.
+ */
+ // fixme (4): This is not a descriptive name, given date is more like offset than serial number
+ // => more descriptive name might be ordinal
+ public abstract int toSerial();
+
+ /**
+ * Returns a java.util.Date. Since java.util.Date has more precision than
+ * SerialDate, we need to define a convention for the 'time of day'.
+ *
+ * @return this as java.util.Date.
+ * fixme (57): Why is this method abstract? it can be implemented here
+ */
+ public abstract java.util.Date toDate();
+
+ /**
+ * Returns a description of the date.
+ *
+ * @return a description of the date.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Sets the description for the date.
+ *
+ * @param description the new description for the date.
+ */
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ /**
+ * Converts the date to a string.
+ *
+ * @return a string representation of the date.
+ */
+ public String toString() {
+ return getDayOfMonth() + "-" + SerialDate.monthCodeToString(getMonth())
+ + "-" + getYYYY();
+ }
+
+ /**
+ * Returns the year (assume a valid range of 1900 to 9999).
+ *
+ * @return the year.
+ */
+ public abstract int getYYYY();
+
+ /**
+ * Returns the month (January = 1, February = 2, March = 3).
+ *
+ * @return the month of the year.
+ */
+ public abstract int getMonth();
+
+ /**
+ * Returns the day of the month.
+ *
+ * @return the day of the month.
+ */
+ public abstract int getDayOfMonth();
+
+ /**
+ * Returns the day of the week.
+ *
+ * @return the day of the week.
+ * fixme (58): why is this method abstract? this method can be implemented here
+ */
+ public abstract int getDayOfWeek();
+
+ /**
+ * Returns the difference (in days) between this date and the specified
+ * 'other' date.
+ *
+ * The result is positive if this date is after the 'other' date and
+ * negative if it is before the 'other' date.
+ *
+ * @param other the date being compared to.
+ * @return the difference between this and the other date.
+ * fixme (59): why is this method abstract? this method can be implemented here
+ */
+ public abstract int compare(SerialDate other);
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ * @return true if this SerialDate represents the same date as
+ * the specified SerialDate.
+ * fixme (60): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isOn(SerialDate other);
+
+ /**
+ * Returns true if this SerialDate represents an earlier date compared to
+ * the specified SerialDate.
+ *
+ * @param other The date being compared to.
+ * @return true if this SerialDate represents an earlier date
+ * compared to the specified SerialDate.
+ * fixme (61): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isBefore(SerialDate other);
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ * @return true if this SerialDate represents the same date
+ * as the specified SerialDate.
+ * fixme (62): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isOnOrBefore(SerialDate other);
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ * @return true if this SerialDate represents the same date
+ * as the specified SerialDate.
+ * fixme (63): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isAfter(SerialDate other);
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ * @return true if this SerialDate represents the same date
+ * as the specified SerialDate.
+ * fixme (64): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isOnOrAfter(SerialDate other);
+
+ /**
+ * Returns true if this {@link SerialDate} is within the
+ * specified range (INCLUSIVE). The date order of d1 and d2 is not
+ * important.
+ *
+ * @param d1 a boundary date for the range.
+ * @param d2 the other boundary date for the range.
+ * @return A boolean.
+ * fixme (65): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isInRange(SerialDate d1, SerialDate d2);
+
+ /**
+ * Returns true if this {@link SerialDate} is within the
+ * specified range (caller specifies whether or not the end-points are
+ * included). The date order of d1 and d2 is not important.
+ *
+ * @param d1 a boundary date for the range.
+ * @param d2 the other boundary date for the range.
+ * @param include a code that controls whether or not the start and end
+ * dates are included in the range.
+ * @return A boolean.
+ * fixme (66): why is this method abstract? this method can be implemented here
+ */
+ public abstract boolean isInRange(SerialDate d1, SerialDate d2,
+ int include);
+
+ /**
+ * Returns the latest date that falls on the specified day-of-the-week and
+ * is BEFORE this date.
+ *
+ * @param targetDOW a code for the target day-of-the-week.
+ * @return the latest date that falls on the specified day-of-the-week and
+ * is BEFORE this date.
+ */
+ public SerialDate getPreviousDayOfWeek(final int targetDOW) {
+ return getPreviousDayOfWeek(targetDOW, this);
+ }
+
+ /**
+ * Returns the earliest date that falls on the specified day-of-the-week
+ * and is AFTER this date.
+ *
+ * @param targetDOW a code for the target day-of-the-week.
+ * @return the earliest date that falls on the specified day-of-the-week
+ * and is AFTER this date.
+ */
+ public SerialDate getFollowingDayOfWeek(final int targetDOW) {
+ return getFollowingDayOfWeek(targetDOW, this);
+ }
+
+ /**
+ * Returns the nearest date that falls on the specified day-of-the-week.
+ *
+ * @param targetDOW a code for the target day-of-the-week.
+ * @return the nearest date that falls on the specified day-of-the-week.
+ */
+ public SerialDate getNearestDayOfWeek(final int targetDOW) {
+ return getNearestDayOfWeek(targetDOW, this);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/original/SpreadsheetDate.java b/src/main/java/clean/code/chapter16/original/SpreadsheetDate.java
new file mode 100644
index 0000000..386ab3f
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/original/SpreadsheetDate.java
@@ -0,0 +1,496 @@
+package clean.code.chapter16.original;
+
+/* ========================================================================
+ * JCommon : a free general purpose class library for the Java(tm) platform
+ * ========================================================================
+ *
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+ *
+ * Project Info: http://www.jfree.org/jcommon/index.html
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
+ * in the United States and other countries.]
+ *
+ * --------------------
+ * SpreadsheetDate.java
+ * --------------------
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+ *
+ * Original Author: David Gilbert (for Object Refinery Limited);
+ * Contributor(s): -;
+ *
+ * $Id: SpreadsheetDate.java,v 1.8 2005/11/03 09:25:39 mungady Exp $
+ *
+ * Changes
+ * -------
+ * 11-Oct-2001 : Version 1 (DG);
+ * 05-Nov-2001 : Added getDescription() and setDescription() methods (DG);
+ * 12-Nov-2001 : Changed name from ExcelDate.java to SpreadsheetDate.java (DG);
+ * Fixed a bug in calculating day, month and year from serial
+ * number (DG);
+ * 24-Jan-2002 : Fixed a bug in calculating the serial number from the day,
+ * month and year. Thanks to Trevor Hills for the report (DG);
+ * 29-May-2002 : Added equals(Object) method (SourceForge ID 558850) (DG);
+ * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
+ * 13-Mar-2003 : Implemented Serializable (DG);
+ * 04-Sep-2003 : Completed isInRange() methods (DG);
+ * 05-Sep-2003 : Implemented Comparable (DG);
+ * 21-Oct-2003 : Added hashCode() method (DG);
+ *
+ */
+
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Represents a date using an integer, in a similar fashion to the
+ * implementation in Microsoft Excel. The range of dates supported is
+ * 1-Jan-1900 to 31-Dec-9999.
+ * null
+ * permitted).
+ */
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ /**
+ * Returns the serial number for the date, where 1 January 1900 = 2
+ * (this corresponds, almost, to the numbering system used in Microsoft
+ * Excel for Windows and Lotus 1-2-3).
+ *
+ * @return The serial number of this date.
+ */
+ public int toSerial() {
+ return this.serial;
+ }
+
+ /**
+ * Returns a java.util.Date equivalent to this date.
+ *
+ * @return The date.
+ */
+ public Date toDate() {
+ final Calendar calendar = Calendar.getInstance();
+ calendar.set(getYYYY(), getMonth() - 1, getDayOfMonth(), 0, 0, 0);
+ return calendar.getTime();
+ }
+
+ /**
+ * Returns the year (assume a valid range of 1900 to 9999).
+ *
+ * @return The year.
+ */
+ public int getYYYY() {
+ return this.year;
+ }
+
+ /**
+ * Returns the month (January = 1, February = 2, March = 3).
+ *
+ * @return The month of the year.
+ */
+ public int getMonth() {
+ return this.month;
+ }
+
+ /**
+ * Returns the day of the month.
+ *
+ * @return The day of the month.
+ */
+ public int getDayOfMonth() {
+ return this.day;
+ }
+
+ /**
+ * Returns a code representing the day of the week.
+ * SUNDAY, MONDAY, TUESDAY,
+ * WEDNESDAY, THURSDAY, FRIDAY, and
+ * SATURDAY.
+ *
+ * @return A code representing the day of the week.
+ */
+ public int getDayOfWeek() {
+ return (this.serial + 6) % 7 + 1;
+ }
+
+ /**
+ * Tests the equality of this date with an arbitrary object.
+ * null permitted).
+ *
+ * @return A boolean.
+ */
+ public boolean equals(final Object object) {
+
+ if (object instanceof SerialDate) {
+ final SerialDate s = (SerialDate) object;
+ return (s.toSerial() == this.toSerial());
+ }
+ else {
+ return false;
+ }
+
+ }
+
+ /**
+ * Returns a hash code for this object instance.
+ *
+ * @return A hash code.
+ */
+ public int hashCode() {
+ return toSerial();
+ }
+
+ /**
+ * Returns the difference (in days) between this date and the specified
+ * 'other' date.
+ *
+ * @param other the date being compared to.
+ *
+ * @return The difference (in days) between this date and the specified
+ * 'other' date.
+ */
+ public int compare(final SerialDate other) {
+ return this.serial - other.toSerial();
+ }
+
+ /**
+ * Implements the method required by the Comparable interface.
+ *
+ * @param other the other object (usually another SerialDate).
+ *
+ * @return A negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ */
+ public int compareTo(final Object other) {
+ return compare((SerialDate) other);
+ }
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ *
+ * @return true if this SerialDate represents the same date as
+ * the specified SerialDate.
+ */
+ public boolean isOn(final SerialDate other) {
+ return (this.serial == other.toSerial());
+ }
+
+ /**
+ * Returns true if this SerialDate represents an earlier date compared to
+ * the specified SerialDate.
+ *
+ * @param other the date being compared to.
+ *
+ * @return true if this SerialDate represents an earlier date
+ * compared to the specified SerialDate.
+ */
+ public boolean isBefore(final SerialDate other) {
+ return (this.serial < other.toSerial());
+ }
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ *
+ * @return true if this SerialDate represents the same date
+ * as the specified SerialDate.
+ */
+ public boolean isOnOrBefore(final SerialDate other) {
+ return (this.serial <= other.toSerial());
+ }
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ *
+ * @return true if this SerialDate represents the same date
+ * as the specified SerialDate.
+ */
+ public boolean isAfter(final SerialDate other) {
+ return (this.serial > other.toSerial());
+ }
+
+ /**
+ * Returns true if this SerialDate represents the same date as the
+ * specified SerialDate.
+ *
+ * @param other the date being compared to.
+ *
+ * @return true if this SerialDate represents the same date as
+ * the specified SerialDate.
+ */
+ public boolean isOnOrAfter(final SerialDate other) {
+ return (this.serial >= other.toSerial());
+ }
+
+ /**
+ * Returns true if this {@link SerialDate} is within the
+ * specified range (INCLUSIVE). The date order of d1 and d2 is not
+ * important.
+ *
+ * @param d1 a boundary date for the range.
+ * @param d2 the other boundary date for the range.
+ *
+ * @return A boolean.
+ */
+ public boolean isInRange(final SerialDate d1, final SerialDate d2) {
+ return isInRange(d1, d2, SerialDate.INCLUDE_BOTH);
+ }
+
+ /**
+ * Returns true if this SerialDate is within the specified range (caller
+ * specifies whether or not the end-points are included). The order of d1
+ * and d2 is not important.
+ *
+ * @param d1 one boundary date for the range.
+ * @param d2 a second boundary date for the range.
+ * @param include a code that controls whether or not the start and end
+ * dates are included in the range.
+ *
+ * @return true if this SerialDate is within the specified
+ * range.
+ */
+ public boolean isInRange(final SerialDate d1, final SerialDate d2,
+ final int include) {
+ final int s1 = d1.toSerial();
+ final int s2 = d2.toSerial();
+ final int start = Math.min(s1, s2);
+ final int end = Math.max(s1, s2);
+
+ final int s = toSerial();
+ if (include == SerialDate.INCLUDE_BOTH) {
+ return (s >= start && s <= end);
+ }
+ else if (include == SerialDate.INCLUDE_FIRST) {
+ return (s >= start && s < end);
+ }
+ else if (include == SerialDate.INCLUDE_SECOND) {
+ return (s > start && s <= end);
+ }
+ else {
+ return (s > start && s < end);
+ }
+ }
+
+ /**
+ * Calculate the serial number from the day, month and year.
+ * null).
+ */
+ public SerialDate getDate(final int year) {
+
+ // check argument...
+ if ((year < SerialDate.MINIMUM_YEAR_SUPPORTED)
+ || (year > SerialDate.MAXIMUM_YEAR_SUPPORTED)) {
+ throw new IllegalArgumentException(
+ "RelativeDayOfWeekRule.getDate(): year outside valid range.");
+ }
+
+ // calculate the date...
+ SerialDate result = null;
+ final SerialDate base = this.subrule.getDate(year);
+
+ if (base != null) {
+ switch (this.relative) {
+ case(SerialDate.PRECEDING):
+ result = SerialDate.getPreviousDayOfWeek(this.dayOfWeek,
+ base);
+ break;
+ case(SerialDate.NEAREST):
+ result = SerialDate.getNearestDayOfWeek(this.dayOfWeek,
+ base);
+ break;
+ case(SerialDate.FOLLOWING):
+ result = SerialDate.getFollowingDayOfWeek(this.dayOfWeek,
+ base);
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/clean/code/chapter16/solution/SpreadsheetDate.java b/src/main/java/clean/code/chapter16/solution/SpreadsheetDate.java
new file mode 100644
index 0000000..4933d05
--- /dev/null
+++ b/src/main/java/clean/code/chapter16/solution/SpreadsheetDate.java
@@ -0,0 +1,169 @@
+package clean.code.chapter16.solution;
+
+/* ========================================================================
+ * JCommon : a free general purpose class library for the Java(tm) platform
+ * ========================================================================
+ *
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+ *
+
+ *
+ */
+
+ import java.util.*;
+ import static clean.code.chapter16.solution.Month.FEBRUARY;
+ /**
+ * Represents a date using an integer, in a similar fashion to the
+ * implementation in Microsoft Excel. The range of dates supported is
+ * 1-Jan-1900 to 31-Dec-9999.
+ *