Scan barcode
apfelahmed's review against another edition
3.0
I loved the philosophy and spirit beyond the writing! Yet for some reason I do believe it was odd and old fashioned for some topics! Yet It is a good knowledge and good do pass by!
Merged review:
I loved the philosophy and spirit beyond the writing! Yet for some reason I do believe it was odd and old fashioned for some topics! Yet It is a good knowledge and good do pass by
Merged review:
I loved the philosophy and spirit beyond the writing! Yet for some reason I do believe it was odd and old fashioned for some topics! Yet It is a good knowledge and good do pass by
ktomalley's review against another edition
3.0
Read the first 5 chapters for a class! Easy read, but felt some of the information was directed to certain types of code and not all
lexish00's review against another edition
4.0
Super readable, I have a much better understanding of what people are talking about when they say "code smells". I definitely agree with Martin on the importance of having consistently formatted/understandable code, and most of his guidelines I like. I think it's useful to read this just to see the examples and where things can be improved in your own code. I skipped the chapters at the end that were extra java-focused. I read this as part of a technical book club and it generated great discussions which I think helps everyone write better code.
fbroom's review against another edition
5.0
Great Book, I would advise though to not get it on the kindle because reading large unformatted code on the kindle is impossible.
I still managed to learn a lot. (I read about 70% of the book)
I have a lot of notes:
3 Functions
1. Each function does one thing (Single Responsibility principle)
2. Statements within our functions should all be at the same level of abstraction
3. Functions should be short (20 lines of code)
4. Use descriptive names
5. Open closed principle (it will not change whenever new types are added)
6. Return a value, don’t use an output argument. In OO you don’t need them
7. Flag arguments are ugly, it implies the function is doing more than one thing break into two functions instead (if (key == update) else if (key == delete) ….)
8. User Exceptions rather than returning errors
9. Don’t repeat yourself (DRY)
4 Comments
1. When you have comments, it only means that you can’t express yourself through the code clearly. it means failure. Other examples of bad comments:
* Redundant comments
* Journal comments
* Noise comments
* Misleading comments
* Position marker, example: //////// Actions ///////
* Closing braces comments // if // while. it means code is unreadable
* Commenting code (makes no sense with version control)
* System wide information (comments should be local to that specific method)
* Too much information
2. Comments can be good sometimes (explanation of intent, clarifications if it’s out of hand (external library return codes), warnings, TODO comments)
5 Formatting
1. Small files are desirable, makes the code easier to understand
2. Adding blank lines between different concepts helps readability
3. Concepts close to each other should be kept vertically close to each other
4. Variables should be declared close to their usage as possible, if functions are small, they should appear at the top of each function
5. Control variables for loops should usually be declared within the loop statement
6. Instance variables should be declared at the top of the class
7. It is nice to have a function call dependencies to point in the downward direction (doesn’t apply to C, C++)
8. Lines should be short. you should never have to scroll to the right.
9. Unaligned declarations are better! yes!
10. no space between function name and its arguments
11. Indentation
12.
Factors don’t need spaces 2*a - 4*b + 3*c instead of 2 * b - 4 * b + 3 * c
6 Objects and Data Structures
1. Data Abstraction, hiding details and exposing abstractions is preferred, it’s not just about adding getting and setters, some thought is needed
2. Data Structures vs Objects. Example: You can make simple data structures (circle, rectangle, square) and then have some functions that would determine for example the area based on the type (if square, if circle). In this scenario (data structures) adding a new function will not change the data structures while adding a new shape will require that all functions change. In OO, you make a polymorphic area function and add it it to all shapes. Adding a new function is hard because you will change all the classes while adding a new shape is easy
3. The Law of Demeter: a method f of class C should only call methods in C, an object created by f, an object passed to f as an argument, an object held in an instance variable of C.
7 Error Handling
1. Don't return null! Just return an empty list and save yourself from checking if the return value is null
2. Don't pass null (worse than returning a null) maybe assertions but still review your code before passing null
8 Boundaries
1. Instead of asking your users to cast the variable to which ever type they need. It should be done in your class thru a method they can access (the sensors example)
2. Don’t pass boundary interfaces (like Maps in Java or third party ones like log4j), instead create an interface and make maintenance easy when the third party code changes
3. Write test code for third party apps that you use instead of learning how it works! Third party code should accessible from an interface (some boundary) so that when third party code changes we are safe
9 Unit Tests
1. Unit tests are first-class citizens
2. Clean tests are readable
3. One assert per test
4. Single concept per test
5. Tests should be fast
6. Tests should be independent
7. Tests should be repeatable in any environment
8. Tests should have a Boolean output
9. Tests should be written before production code
10 Classes
1. Classes should be small
2. Classes should have a single responsibility
3. Classes should have a small number of instance variables
11 Systems
1. An object should not take responsibility for instantiating dependencies itself
2. "It’s a myth that we can get systems right the first time, instead we should implement today’s stories then refactor and expand the system to implement new stories tomorrow. “incremental agility””
3. Use standards when they add demonstrable value
4. systems need domain-specific languages
12 Emergence
1. A design is simple if {runs all the tests, contains no duplications, expresses the intent of the programmer, minimizes the number of classes and methods}
13 Concurrency
1. Concurrency incurs some overhead, both in performance as well as writing additional code
2. Correct concurrency is complex
3. Concurrency often require a fundamental change in design strategy.
4. Keep concurrency related code separate from other code
5. Sometimes it is easier to use copies of data instead of sharing them
6. Use the synchronized keyword
7. Threads should be as independent as possible.
8. Know your library
9. Know your execution model
10. Don't use more than one method on a shared resource.
11. Keep your synchronized sections small
12. Try different platforms
14 Successive Refinement
This chapter is simply unreadable on the kindle. It’s the author’s large piece and code and the way he was able to refactor it and make it better.
1. One of the best ways to ruin the program is to make massive changes to its structure in the name of improvement, to avoid it use tests! and small incremental changes instead
15 JUnit Internals
Skipped
16 Refactoring SerialDate
Code review of David Gilbert’s SerialDate Class, again it hard to read this on a kindle
17 Smells and Heuristics
List of smells
1. Comments:
* Inappropriate comments
* obsolete comments
* redundant comments
* poorly written comments
* commented-out code
2. Environment:
* build requires more than one step
* tests require more than one step
3. Functions:
* too many arguments
* output arguments
* dead functions (never called)
4. General:
* multiple language in one source file
* obvious behavior is unimplemented
* incorrect behavior at the boundaries
* overridden safeties
* duplication
* code at wrong level of abstraction
* base classes depending on their derivates
* too much information (interfaces giving so much)
* dead code (code never executed)
* vertical separation
* inconsistency
* clutter
* artificial coupling (not needed)
* inappropriate static (when in doubt, make it non-static)
* use explanatory variables
* functions names should say what they do
* understand the algorithm
* prefer polymorphism to if/else or switch/case
* follow standard conventions
* replace magic numbers with named constants
* be precise (NO for using floats for currencies!)
* encapsulate conditionals
* avoid negative conditionals
* functions should do one thing
* don’t be arbitrary
* encapsulate boundary conditions
* functions should descend only one level of abstraction
* keep configurable data at a high level
* avoid transitive navigation
5. Java
* Avoid using long imports by using wild cards
* don’t inherit constants
* constants vs enums (use enums)
6. Names
* Use descriptive names (no i, j or k)
* Choose names at the appropriate level of abstractions
* use standard nomenclature where possible
* use unambiguous names
* use long names for long scopes (tiny names are okay for tiny scopes)
* avoid encodings (m_, s_)
* names should describe side-effects
7. Tests
* test everything
* use a coverage tool (to find modules that are not tested)
* don’t skip trivial tests
* an ignored test is a question about an ambiguity
* test boundary conditions
* exhaustively test near bugs
* patterns of failures are revealing (if tests are failing in a certain pattern, helps)
* test convergence patterns can be revealing
* tests should be fast
I still managed to learn a lot. (I read about 70% of the book)
I have a lot of notes:
3 Functions
1. Each function does one thing (Single Responsibility principle)
2. Statements within our functions should all be at the same level of abstraction
3. Functions should be short (20 lines of code)
4. Use descriptive names
5. Open closed principle (it will not change whenever new types are added)
6. Return a value, don’t use an output argument. In OO you don’t need them
7. Flag arguments are ugly, it implies the function is doing more than one thing break into two functions instead (if (key == update) else if (key == delete) ….)
8. User Exceptions rather than returning errors
9. Don’t repeat yourself (DRY)
4 Comments
1. When you have comments, it only means that you can’t express yourself through the code clearly. it means failure. Other examples of bad comments:
* Redundant comments
* Journal comments
* Noise comments
* Misleading comments
* Position marker, example: //////// Actions ///////
* Closing braces comments // if // while. it means code is unreadable
* Commenting code (makes no sense with version control)
* System wide information (comments should be local to that specific method)
* Too much information
2. Comments can be good sometimes (explanation of intent, clarifications if it’s out of hand (external library return codes), warnings, TODO comments)
5 Formatting
1. Small files are desirable, makes the code easier to understand
2. Adding blank lines between different concepts helps readability
3. Concepts close to each other should be kept vertically close to each other
4. Variables should be declared close to their usage as possible, if functions are small, they should appear at the top of each function
5. Control variables for loops should usually be declared within the loop statement
6. Instance variables should be declared at the top of the class
7. It is nice to have a function call dependencies to point in the downward direction (doesn’t apply to C, C++)
8. Lines should be short. you should never have to scroll to the right.
9. Unaligned declarations are better! yes!
10. no space between function name and its arguments
11. Indentation
12.
Factors don’t need spaces 2*a - 4*b + 3*c instead of 2 * b - 4 * b + 3 * c
6 Objects and Data Structures
1. Data Abstraction, hiding details and exposing abstractions is preferred, it’s not just about adding getting and setters, some thought is needed
2. Data Structures vs Objects. Example: You can make simple data structures (circle, rectangle, square) and then have some functions that would determine for example the area based on the type (if square, if circle). In this scenario (data structures) adding a new function will not change the data structures while adding a new shape will require that all functions change. In OO, you make a polymorphic area function and add it it to all shapes. Adding a new function is hard because you will change all the classes while adding a new shape is easy
3. The Law of Demeter: a method f of class C should only call methods in C, an object created by f, an object passed to f as an argument, an object held in an instance variable of C.
7 Error Handling
1. Don't return null! Just return an empty list and save yourself from checking if the return value is null
2. Don't pass null (worse than returning a null) maybe assertions but still review your code before passing null
8 Boundaries
1. Instead of asking your users to cast the variable to which ever type they need. It should be done in your class thru a method they can access (the sensors example)
2. Don’t pass boundary interfaces (like Maps in Java or third party ones like log4j), instead create an interface and make maintenance easy when the third party code changes
3. Write test code for third party apps that you use instead of learning how it works! Third party code should accessible from an interface (some boundary) so that when third party code changes we are safe
9 Unit Tests
1. Unit tests are first-class citizens
2. Clean tests are readable
3. One assert per test
4. Single concept per test
5. Tests should be fast
6. Tests should be independent
7. Tests should be repeatable in any environment
8. Tests should have a Boolean output
9. Tests should be written before production code
10 Classes
1. Classes should be small
2. Classes should have a single responsibility
3. Classes should have a small number of instance variables
11 Systems
1. An object should not take responsibility for instantiating dependencies itself
2. "It’s a myth that we can get systems right the first time, instead we should implement today’s stories then refactor and expand the system to implement new stories tomorrow. “incremental agility””
3. Use standards when they add demonstrable value
4. systems need domain-specific languages
12 Emergence
1. A design is simple if {runs all the tests, contains no duplications, expresses the intent of the programmer, minimizes the number of classes and methods}
13 Concurrency
1. Concurrency incurs some overhead, both in performance as well as writing additional code
2. Correct concurrency is complex
3. Concurrency often require a fundamental change in design strategy.
4. Keep concurrency related code separate from other code
5. Sometimes it is easier to use copies of data instead of sharing them
6. Use the synchronized keyword
7. Threads should be as independent as possible.
8. Know your library
9. Know your execution model
10. Don't use more than one method on a shared resource.
11. Keep your synchronized sections small
12. Try different platforms
14 Successive Refinement
This chapter is simply unreadable on the kindle. It’s the author’s large piece and code and the way he was able to refactor it and make it better.
1. One of the best ways to ruin the program is to make massive changes to its structure in the name of improvement, to avoid it use tests! and small incremental changes instead
15 JUnit Internals
Skipped
16 Refactoring SerialDate
Code review of David Gilbert’s SerialDate Class, again it hard to read this on a kindle
17 Smells and Heuristics
List of smells
1. Comments:
* Inappropriate comments
* obsolete comments
* redundant comments
* poorly written comments
* commented-out code
2. Environment:
* build requires more than one step
* tests require more than one step
3. Functions:
* too many arguments
* output arguments
* dead functions (never called)
4. General:
* multiple language in one source file
* obvious behavior is unimplemented
* incorrect behavior at the boundaries
* overridden safeties
* duplication
* code at wrong level of abstraction
* base classes depending on their derivates
* too much information (interfaces giving so much)
* dead code (code never executed)
* vertical separation
* inconsistency
* clutter
* artificial coupling (not needed)
* inappropriate static (when in doubt, make it non-static)
* use explanatory variables
* functions names should say what they do
* understand the algorithm
* prefer polymorphism to if/else or switch/case
* follow standard conventions
* replace magic numbers with named constants
* be precise (NO for using floats for currencies!)
* encapsulate conditionals
* avoid negative conditionals
* functions should do one thing
* don’t be arbitrary
* encapsulate boundary conditions
* functions should descend only one level of abstraction
* keep configurable data at a high level
* avoid transitive navigation
5. Java
* Avoid using long imports by using wild cards
* don’t inherit constants
* constants vs enums (use enums)
6. Names
* Use descriptive names (no i, j or k)
* Choose names at the appropriate level of abstractions
* use standard nomenclature where possible
* use unambiguous names
* use long names for long scopes (tiny names are okay for tiny scopes)
* avoid encodings (m_, s_)
* names should describe side-effects
7. Tests
* test everything
* use a coverage tool (to find modules that are not tested)
* don’t skip trivial tests
* an ignored test is a question about an ambiguity
* test boundary conditions
* exhaustively test near bugs
* patterns of failures are revealing (if tests are failing in a certain pattern, helps)
* test convergence patterns can be revealing
* tests should be fast
llanirev's review against another edition
3.0
Good practices and stuff every software engineer should adhere to, but the book is full with open doors. As a advanced Software Engineer you should already know these practices; either by logical thinking or thought by your peers or coach.
brycestevenwilley's review against another edition
informative
slow-paced
2.0
Eh, not worth reading. Good advice, sure, but there's so many wack examples and difficult/annoying to read/poorly formatted refactors, and outdated Java code (similar to the Elements of Java Style) that I strongly felt like I was wasting my time. Read some blogs about naming variables instead.