session roadmap

  • Week 1: Software Craftsmanship
  • Week 2: Software Craftsman journey
  • Week 3: TDD/BDD
  • Week 4: Spring ecosystem I
  • Week 5: Spring ecosystem II
  • Week 6: REST
  • To be completed/ confirmed ...

Software craftsmanship







Carlos Cornejo

Why we're here?

  • Share experiences and tips gathered while developing in different contexts.
  • Review foundations, principles and concepts of OOD.
  • Tools, techniques and best practices that can help while designing software.
  • Understand how to couple modelling and testing to drive the development of software.
  • Think and understand different approaches to test software.

Initial thoughts

"Programs are read more than they written"

"The way code is written defines a developer"

"There is no such thing as done"
....that's why should we have friday's refactoring sessions

"A good developer is not someone that writes code that no one understands .... but someone that writes code in a fashion that any developer can"

Make sure that the code is readable in a way that the intentions and functionality of it are clear

roadmap

  1. Theory session
    1. Web of Objects
    2. SOLID principles
    3. Other SD principles
  2. Practice session
    1. Refactoring
      1. Examples
    2. Types of tests
    3. Verification vs Design
    4. BDD
    5. Unit Testing
      1. State vs Interaction
      2. Tools
  3. Conclusions

growing object-oriented software

"Object-oriented design focuses more on the  communication between objects than
on the objects themselves"

"An object-oriented system is a web of collaborating objects"

A web of objects


An object communicates by messages: It receives messages from other objects and reacts
 by sending messages to other objects as well as, perhaps, returning a value or exception to the original sender

By having a highly cohesive and loosely coupled system
any change into the system’s behaviour it's easier because we can focus on what we want it to do, not how.

Coupling and Cohesion

Coupling and cohesion are metrics that (roughly) describe how easy it will be to
change the behaviour of some code.

Elements are coupled if a change in one forces a change in the other.
“Loosely” coupled features are easier to maintain.
An element’s cohesiveness is a measure of whether its responsibilities form a single and meaningful unit

"code must be loosely coupled and highly  cohesive—in other words, well-designed" [Uncle Bob]

CRC Cards

(Candidate, Responsibilities, Collaborators)





CRC Cards

We try to think about objects in terms of roles, responsibilities and collaborators.


"An object is an implementation of one or more roles; a role is a set of related responsibilities; and a responsibility is an obligation to perform a task or know information. A collaboration is an interaction of objects or roles (or both)."


 Example: How would you model a restaurant?

solid principles

solid principles

Robert 'Uncle Bob' Martin introduced it in 1995

What is S.O.L.I.D.?

S.O.L.I.D. is a collection of best- practice, object-oriented design principles which can be applied to your design

What is useful for?

    • loose-coupling 
    • higher maintainability 
    • intuitive location of interesting code
    • high cohesion
    • encapsulation
    • focus in what to do not how to do it



solid principles

SRP: Single Responsibility Principle



solid principles

Single Responsibility Principle (SRP)


"An object should have only one reason to change or exist"

Each complex problem cannot easily be solved as a whole.

It is much easier to first divide the problem in smaller sub-
problems.

"Divide et imperat" (Divide and Conquer)


This principle applies to classes and methods.

solid principles

Open-Closed Principle (OCP)


 "We should write our modules assuming that they can and should be extended, without requiring them to be modified"

solid principles

Liskov Substitution Principle (LSP)

aka design by contract

In a nutshell:

"If you have a base class BASE and subclasses SUB1 and SUB2, the rest of your code should always refer to BASE

and NOT SUB1 and SUB2"


"Prefer composition over inheritance whenever possible... though"

solid principles

Interface Segregation Principle (ISP)


many client-specific interfaces are better than one general purpose interface


Think … to create specialised interfaces serving specific requirements, rather than finding the mother of all interfaces, that will service the universe.


"clients shouldn't be forced to implement interfaces they don't use or even care"

solid principles

Interface Segregation Principle (ISP)

solid principles

Interface Segregation Principle (ISP)

solid principles

Dependency Inversion Principle (DIP)


depend on abstractions (interfaces), not on corrections (implementations)”


Try to get the most of IoC containers and delegate to them for the creation of the collaborators

solid principles

Conclusions and Benefits

  • Low Coupling 
    • By abstracting many of our implementation needs into various interfaces and introducing SOLID concepts, we’ve created a system that has very low coupling. Many of these individual pieces can be taken out of the system with little to no spaghetti mess trailing after it.


  • High Cohesion
    • As a result of low coupling and SRP; we have a lot of small pieces that can be stacked together to create something larger and more complex. DIP also allows to tie the various blocks together by depending on an abstraction with different implementations.

solid principles

Conclusions and Benefits


  • Encapsulation
    • True encapsulation is not just making fields private and hiding data from external objects, it’s hiding implementation details from other objects, depending only on the abstractions and expected behaviors of those abstractions.
    • LSP, DI, and SRP all work hand in hand to create true encapsulation in the new
      project structure.
    • We’ve encapsulated our behavioral implementations in many individual objects,
      preventing them from leaking into each other.

Other SD principles


  • KISS (keep it simple and stupid)
    • so we make it easy to reuse
  • DRY (don't repeat yourself), DIE (Duplication is Evil), etc..
    • interdeveloper duplication, lack of communication or knowledge of the app?
    • this is very likely to happen in multi-tier architectures.
    • SRP?
    • when applied successfully, a modification of any single element of a system does not require a change in other logically unrelated elements.

OTHER SD PRINCIPLES


  • YAGNI (You ain't gonna need it)
    • Always implement things when you actually need them, never when you just foresee that you need them
    • OCP?
    • YAGNI helps to not over engineer things.

CLEAN CODE


"Beauty of style and harmony and grace and good rhythm depends on simplicity" Plato  The Republic
“Always leave the camp ground cleaner than you found it.”  the boy scouts rule

Clean Code 

Use Intention-Revealing Names
 int d; // elapsed time in days
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
Use Pronounceable/Searchable Names
 class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
/* ... */
};
 class Customer {
private Date generationTime;
private Date modificationTime;
private final String recordId = "102";
/* ... */
};

CLEAN CODE 

Function Names Should Say What They Do
 Date newDate = date.add(5);
 //addDaysTo or increaseByDays
Encapsulate Conditionals
 if (timer.hasExpired() && !timer.isRecurrent())
if (shouldBeDeleted(timer))  //preferred
Avoid Negative Conditionals
 if (!buffer.shouldNotCompact())
 if (buffer.shouldCompact()) //preferred


CLEAN CODE

Functions Should Do One Thing
 public void pay() {
   for (Employee e : employees) {
      if (e.isPayday()) {
        Money pay = e.calculatePay();
        e.deliverPay(pay);
      }
   }
 }

//preferred
 public void pay() {
    for (Employee e : employees)
       payIfNecessary(e);
    }
 
 private void payIfNecessary(Employee e) {
    if (e.isPayday())
       calculateAndDeliverPay(e);
    }

 private void calculateAndDeliverPay(Employee e) {
    Money pay = e.calculatePay();
    e.deliverPay(pay);
 }

CLEAN CODE

Encapsulate Boundary Conditions
 if(level + 1 < tags.length)
 {
   parts = new Parse(body, tags, level + 1, offset + endTag);
   body = null;
 }

  int nextLevel = level + 1;
 if(nextLevel < tags.length)
 {
   int delay = offset + endTag;
   parts = new Parse(body, tags, nextLevel, delay);
   body = null;
 }

clean code

Keep Configurable Data at High Levels

public class AnyClass
{
  public static final String DEFAULT_PATH = ".";
  public static final String DEFAULT_ROOT = "FitNesseRoot";
  public static final int DEFAULT_PORT = 80;
  public static final int DEFAULT_VERSION_DAYS = 14;
  ...
}

CLEAN CODE - Comments


Comments Do Not Make Up for Bad Code

Explain Yourself in Code

TODO Comments are dangerous as they may stay in the code if the TODO-er doesn't pick it up..

This a topic open for discussion

CLEAN CODE - Formatting


Code formatting is important, is about communication!!

Also open for discussion within the team:
  • Vertical Formatting
    • Vertical Density
    • Vertical Distance
    • Vertical Ordering
  • Horizontal Formatting
    • Indentation
    • Line width

CLEAN CODE - Defensive Programming (JSR305)


Annotations on arguments and methods
@Nonnull
@Nullable

JSR-305 is a Java Specification Request intended to improve the effectiveness of static analysis tools.

Declare for visibility the state of an argument or possible state of a response from a method.  Will help developers read code clearly.  


For idea users: FindBugs-IDEA


CLEAN CODE - Automate Your

Coding Standard 

  • Make sure code formatting is part of the build process.
  • Use static code analysis tools to scan the code for unwanted anti-patterns.
  • Do not only measure test coverage but break the build if test coverage is too low.

Finally, the coding standard should be dynamic rather than static based the team feedback.

Clean code - takeaways

The Boy Scout Rule
Beauty Is in Simplicity
Code Is Design
Code Layout Matters
Continuous Learning
Don’t Be Afraid to Break Things
Encapsulate Behaviour, Not Just State
Improve Code by Removing It
Know Your IDE
Only the Code Tells the Truth
Prefer Domain-Specific Types to Primitive Types

refactoring

"Refactoring is the process of changing a software system in such a way that it does not alter the external behaviour of the code yet improves its internal structure"
"refactoring is to code what the gym is to a body builder == necessary" anonymous
"It is a disciplined way to clean up
code that minimizes the chances of introducing bugs"


... In essence when you refactor you are

improving the design of the code after it has been written.

The drawback of refactoring is that you have to have a solid set of tests to not introduce bugs and have problems with your boss

REFACTORING


When Should You Refactor?

  • When You Add Function
  • When You Need to Fix a Bug
  • As You Do a Code Review

  • When shouldn't you refactor?

    • When you don't have tests to support your refactoring
    • When you should rewrite from scratch instead 
    • When you are close to a deadline
    • Avoid the temptation to rewrite everything

    But these scenarios shouldn't stop you doing what you should so:
    • Create your branch
    • Ultimately create technical debt task
    • Do it in your breaks ;-)

    REFACTORING

    Bad Smells in Code

    "If it stinks, change it" .. by Kent Beck and Martin Fowler

    REFACTORING

    Bad Smells in Code
    Duplicated Code

    • The same code structure in more than one place, it's telling you that your program will be better if you find a way to unify them.
    • Having n-plicated chunks of code is likely to introduced bugs if you forget to make the changes in all of them 
    • Extract method and pull up variable/field are your best buddies here!

    REFACTORING

    Bad Smells in Code

    Train wreck

     SelectionUtils.processDisplayOdds(eachEvent.getContent().getFirstBook().getContent()
                                .getSelections());
    SelectionUtils.processDisplayOdds(eachEvent.getCouponSelections());
     if (selectionDisplayOptions.getMarketTypeIdsForSelectionOrderingByName().contains(event.getContent().getFirstBook().getContent().getMarketTypeId())) {SelectionUtils.sortSelections(event.getContent().getFirstBook().getContent().getSelections(), SelectionSortType.BY_NAME);}
    if (selectionDisplayOptions.containsCouponMarketTypeId(event.getCouponMarketTypeId())) {SelectionUtils.sortSelections(event.getCouponSelections(), SelectionSortType.BY_NAME);}



    REFACTORING

    Bad Smells in Code

    Train wreck

    Code in the language of your domain

    and make your code more readable

    tip: A train wreck access is telling you to add a method to your interface

    It's much easier to test as it just needs one stubbing

    ... And please don't break the encapsulation of your object

    REFACTORING


    Bad Smells in Code
    Long list of method params

     BetSlipUtils.addSelectionToBetSlip(quickbetSlip, user, site, betSlipServices, sbBusinessLogic, betSelectionMap.get("selectionId"), betSelectionMap.get("marketId"),
                    betSelectionMap.get("eventId"), betSelectionMap.get("priceUp"), betSelectionMap.get("priceDown"), betSelectionMap.get("americanOdds"), betSelectionMap.get("decimalOdds"), betSelectionMap.get("handicap"), betSelectionMap.get("handicapId"), betSelectionMap.get("eachWayPlaceTerm"), betSelectionMap.get("eachWayReduction"));

    REFACTORING


    Bad Smells in Code
    Long list of method params

    • One of goals in OO programming should be to encapsulate a program's data as much as possible into objects.
    • Long parameter lists are hard to understand, because they become inconsistent and difficult to use.
    • Changing them becomes a nightmare.

    REFACTORING

    Bad Smells in Code
    Long list of method params

  • Do we really need as many parameters?
      • is becoming a bad smelling symptom and needs a re-think?
      • is this going against SRP?
      • Are we using DI as we should? 

    Maybe a good idea could be to create a Object to represent the state or parameter to use??

    TESTING the web of objects

    "Object-oriented design focuses more on the communication between objects than
    on the objects themselves"

    The big idea is “messaging”....

    testing software


    types of tests

    What is the testing big picture?

    Acceptance


    Integration


    Unit







      types of tests

      • Acceptance: Does the whole system work?
        • Open discussion in testing world over the terminology

          • end-to-end
          • functional tests
          • system tests
        • We use “acceptance tests” to help us, with the domain experts, understand and agree on what we are going to build next.
          • We also use them to make sure that we haven’t broken any existing features as we continue developing.
        • Acceptance tests are a superset of all other tests.
        • They are expensive, require a significant amount of time to execute themselves (nightly builds).
       

      types of tests


      What happens when different units of work are combined into a workflow?

      Integration:
      Does our code work against code we can't change or don't have control of?

      It might be a public framework, such as a persistence mapper, or a library from another team within our organization, web service, etc..

      types of tests


      Unit test: Do our object do the right thing?

      • Focus on single classes and should exists in isolation
      • They know nothing about the external world
      • A unit test should be independent of any context
      • A unit test by definition is quick to run

       

      Verification vs design

      Different testing approaches with two opposites beliefs

      • Verifiers
        • check that their code works, that's the only goal
        • if the code is hard to test, they'll resort to any available technique to test it
          • sacrifice OOD rules
          • modify methods visibility using reflection
          • class loading hacks to deal with final of legacy stuff
        • everything count to achieve the Holy Grail of testability

      Verification vs design

      • Designers
        • believe that following OO rules is the most important thing to lead to the easily testable code.
        • treat tests as an indicator of code health.
        • easy-to-write code tests denote sound code.
        • Code difficult to test it's treated as a clear sign that the code should be refactored/redesigned.
        • these fellas particularly like TDD approach.
        • What they most like about coding is testing!
        • in case of legacy are very keen to refactor it to make it more testable.

      Verification VS design


      The terms designer and verifier have been introduced to show boundaries between testing approaches.


      What kind of developer are you?


      There is not such a 100% designer or 100% verifier thing, we all fall somewhere in between.



      Behaviour driven development



      • Programmers wanted to know where to start
      • What to test and what not to test
      • How much to test in one go 
      • What to call their tests
      • How to understand why a test fails?

        BEHAVIOUR DRIVEN DEVELOPMENT

        “a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology.” Dan North 

          • specifies that product people and developers should collaborate and should specify the behaviour of the system based on user stories and scenarios
          • is a specialized version of TDD which focuses on behavioural specifications of software units by creating boundaries (scenarios)
         

        BEHAVIOUR DRIVEN DEVELOPMENT

        • The essential idea is to break down a scenario (test in BDD) into three sections using Cucumber's DSL gherkin language:
          • The given part describes the state of the world before you begin the behaviour you're specifying in this scenario. You can think of it as the pre-conditions to the test.
          • The when section is that behaviour that you're specifying.
          • Finally the then section describes the changes you expect due to the specified behaviour (output/s).

        Testing and code coverage


        100% code coverage isn't the goal


        100% sounds awesome but...

        does not guarantee the lack of defects—it only guarantees that all of your code was executed

        is this what we want?

        So rather than obsessing about code coverage, focus your attention on making sure that the tests you do write are meaningful and test the functionality



        unit testing


        • How to approach unit testing?
          • state vs interaction
        • Tools
          • JUnit
          • Mockito
          • PowerMock
          • Matchers (assertJ)

        unit testing

        How to approach unit testing?

        This is when we start to think about

        • Architecture of my system
        • SOLID principles
        • OOD
        • black-boxes with pre/post conditions
        • test in isolation
        • Do I have collaborators/interactions? Mocking time


        UNIT TESTing

        HOW TO APPROACH UNIT TESTING?

        • Conventions that could be followed or agreed:
          • Follow BDD approach and describe specifications not a test case 
          • We are not testing methods we are testing functionality, is this clear?
          • Test method names should be sentences
          • A simple sentence template keeps test methods focused
        ClientDetailsValidatorUnitTest
        
        itShouldFailForMissingSurname
        
        testShouldFailForMissingTitle

        UNIT TESTING

        HOW TO APPROACH UNIT TESTING?


          • Conventions that could be followed or agreed:
            • An expressive test name is helpful when a test fails
            • The class under test are called instance or sut
            • Normally the returning value is called outcome

        unit test

        state vs interaction

        • state verification:
          • Assertions
            • assertEquals/NotEquals: Are identical values?
            • assertTrue/False: is the condition satisfied?
            • assertNull/NotNull: is the object reference satisfied?
            • assertSame/NotSame: same instance
            • assertArrayEquals: assert array contains same objects with same order
            •  assertThat: assertions using matchers

        UNIT TEST

        STATE vs INTERACTION

        • state verification
          • Checking expected Exceptions
          • usage of Assert.fail

        @Test(expected = LoginException.class)
        public void shouldThrowErrorExceptionWhenInvalidUser() throws LoginException {    sut.login("error", "password");
            fail("it shouldn't reach here");}

        UNIT TEST

        STATE VS INTERACTION

        • state verification
          • What do we use @Before for?
            • is executed before every test.
            • should include state shared by all tests
            • if we have specific initial state for a test should be removed from @Before and moved inside the test as a test fixture
         @Before
            public void setUp() {
                ukashDepositForm = createDummyUKashDepositForm();
                serviceCallResult = new ServiceCallResult();
            }
        @Test
        public void shouldReturnExpectedAllowedMethods() {
        // test fixtures
        List<DepositMethod> aListOfValidDepositsMethods = listOfValidDepositsMethods();
        List<DepositMethods> aListOfAllowedMethods = aListOfAllowedMethods();

        UNIT TEST

        STATE VS INTERACTION

        • behaviour verification
          • we test (verify) how our sut interacts or behaves with other collaborators (dependencies(mocks))
          • there is a general misunderstanding when referring to a mock
            • a dummy object needs to exists, no collaboration needed
            • we use test doubles to act as a collaborators
            • Mockito allows us to stub methods a.k.a stub
            • an object becomes a mock when is used to verify the interaction with the sut
        these guys are used to prepare the environment for testing

        UNIT TEST

        STATE VS INTERACTION


        • behaviour verification
          • verify: Verifies certain behaviour happened X times

          public static <T> T verify(T mock) {
                return MOCKITO_CORE.verify(mock, times(1));
            }


        verify(mockUser).getAccountId();verify(mockUser, times(0)).getCurrencyId();
        verify(model).put(eq("ukash"), eq(TRUE));

        UNIT TEST

        Tools
        • Mockito
          • Setting up:

         @RunWith(MockitoJUnitRunner.class)

          • Inject mocks over sut
         @InjectMocks
         DepositBusinessLogicImpl sut = new DepositBusinessLogicImpl();

          • Mock declaration
         @Mock
         ModelMap model

        UNIT TEST

        Tools
        Mockito and BDDMockito
        • stubbing method result
         when(site.getTimeZone()).thenReturn(A_VALID_UK_TIMEZONE);
         given(site.getTimeZone()).willReturn(A_VALID_UK_TIMEZONE);c`sdv

        • using matchers for method params

        when(mock.getTransaction(anyLong(),any(TransactionSearchType.class)).thenReturn(txList);

          • verification of params used for method invocation

          verify(model).put(eq("ukashDepositCurrencyId"), anyDouble());
          • Throwing exceptions
         doThrow(new Exception()).when(mock).method(any(UkashDepositData.class));

        UNIT TEST

        Tools

        Mockito and BDDMockito good practices

        • Don’t mix with Spring Integration Test
        • Don’t mock your model (dummies?)
        • Don’t abuse mocks.. code smell?
        • Don’t replace asserts with verify
        • stubbing section shouldn't be used as a replacement for verify section



        UNIT TEST

        Tools
        • PowerMock
          • uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
          • For TDD-ers and test lovers this is your best buddy when dealing with legacy code ;-)
          • Setting up:
         @RunWith(PowerMockRunner.class)
         @PrepareForTest(SBLoginSecurityServiceImpl.class)
        whenNew(SecurityContextLogoutHandler.class).withNoArguments().thenReturn(securityContextLogoutHandler);

        UNIT TEST

        Tools

        • Fluent assertions for java:
          • assertJ is a Java library that provides a fluent interface for writing assertions

        assertTrue(yoda is instanceof Jedi.class);assertEquals(foundJedi, yoda);assertNotEquals(foundSith, yoda);

        vs
         assertThat(yoda).isInstanceOf(Jedi.class)
                        .isEqualTo(foundJedi)
                        .isNotEqualTo(foundSith);
         assertThat(newHires).containsOnly("Gandalf", "Arwen", "Gimli");
         assertThat(outcome).includes(
                           entry("stakeMultiplier", new Double(1.0)),
                           entry("taxType", TOTALSTAKE),
                           entry("numberOfBets", 1L),
                           entry("betType", SINGLE),
                           entry("taxRate", 5.0));


        conclusions

        • There is  no de-facto way of doing things in SD, but some discipline always helps.
        • The goal of these best practices or principles is to help you communicate your intentions through your code.
        • Self-explaining code is key in our sector as people are very likely to change of companies.... but the code stays.
        • Remember: 
          • If it’s hard to read… it’s hard to test.
          • If it’s hard to test… it’s hard to use.
          • If it’s hard to test… you’re probably doing it wrong.
          • If it’s hard to test… take a look at the design and test it again!

        References

        • Growing Object-Oriented Software, Guided by Tests - Steve Freeman and Nat Pryce
        • Practical Unit Testing - Tomek Kaczanowski
        • Refactoring - Martin Fowler
        • 97 Things every programmer should now - Kevlin Henney
        • Implementation Patterns - Ken Beck
        • The Pragmatic Programmer - Dave Thomas and Andy Hunt
        • Michael Feathers, Martin Fowler, Uncle Bob Martin, Kent Beck, Dan North, Ward Cunningham
        • etc..

        future topics

        1. TDD
        2. Custom Matchers and Argument Captor
        3. Spring Servlet API mock package
        4. Power Mock advanced
        5. Mockito Answers

        SOFTWARE CRAFTSMANSHIP LESSONS

        By Carlos María Cornejo Crespo

        SOFTWARE CRAFTSMANSHIP LESSONS

        Software craftsmanship experiences and techniques

        • 1,151