Better Software: an introduction to good code

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    2 Favorites

    Better Software: an introduction to good code - Presentation Transcript

    1. Better Software An introduction to good code Giordano Scalzo, 06/05/2009
      • Why code matters (10 min)
          • Disclaimer
          • Good and Bad Code
          • The Broken Window Theory
          • The Grand Redesign in the Sky
          • The Boy Scout Rule
      • OOP Patterns and Principles (30 min)
          • SOLID Principles
          • The Others Principles
      • Good code: Smells and heuristics (30 min)
          • Comments
          • Functions
          • General
          • Names
          • Test
        • Conclusion (5 min)
      • Q&A? (15 min)
    2. Disclaimer
    3. I’m not here to preach
    4. Ward Cunningham 40 years experience Wiki inventor Extreme Programming pioneer Director of Eclipse
    5. Kent Beck Extreme Programming inventor JUnit inventor Tdd inventor
    6. Robert C. Martin Extreme Programming pioneer Uncle Bob 40 years experience
    7.  
    8.  
    9.  
    10. What is Good Code?
    11. Bad Code Can make scared!
    12. while ((! found ) && ( pos < ( fileContent . Length - 6 ))) { byteData = new byte [ 6 ]; Array . Copy ( fileContent , pos , byteData , 0 , 6 ); pos = pos + 6 ; str_byteData = enc . GetString ( byteData ); if ( str_byteData . Contains ( &quot;s&quot; )) { posE_byteData = str_byteData . IndexOf ( &quot;s&quot; ); pos = pos + ( posE_byteData - 6 ); Array . Copy ( fileContent , pos , byteData , 0 , 6 ); pos = pos + 6 ; if ( byteData [ 0 ] == 0x73 ) // 's' { if ( byteData [ 1 ] == 0x74 ) // 't' { if ( byteData [ 2 ] == 0x72 ) // 'r' { if ( byteData [ 3 ] == 0x65 ) // 'e' { if ( byteData [ 4 ] == 0x61 ) // 'a' { if ( byteData [ 5 ] == 0x6D ) // 'm' { found = true ; break ; } else { if ( byteData [ 5 ] == 0x73 ) { pos = pos - 1 ; } } }
    13.  
    14. Theory of Broken Window
    15. Big Redesign in the Sky
    16. Netscape rewrote Netscape 4.0 and released it after three years as Netscape 6.0
    17. Borland rewrote dBase and Quattro Pro
    18. Microsoft rewrote Word
    19. The Boy Scout Rule Leave the campground cleaner than you found it
    20. OOP Principles
    21. Solid Principles S.o.l.i.d. Principles
    22. Single Responsibility Principle Only one reason to change Robustness Focus
    23. public class PrintServerImpl extends ServiceAdvanced implements PrintServer , JobListener { public synchronized String createJob ( Object data ) { //... } public int getStatus ( String jobId ) { //... } public void print ( String jobId , int startPage , int endPage ) { //... } public byte [] getPreview ( String jobId , int pageNum ) { //... } public IRawData getData ( String jobId ) { //... } public void abortAction ( String jobId ) { //... } public Vector getPrinterList () { //... } public synchronized void setPrinterList ( Vector printerList ) { //... } public void statusChanged ( JobEvent jobEvent ) { //... } public void pageComputed ( JobEvent jobEvent ) { //... } // ... }
    24. public class PrinterServerJob { public synchronized String createJob ( Object data ) { //... } public int getStatus () { //... } public void addDataToJob () { //... } public void print (){ //... } public void print ( int startPage , int endPage ){ //... } public byte [] getPreview ( int pageNum ){ //... } // ... } public class PrinterList { public Vector getPrinterList (){ //... } public synchronized void setPrinterList ( Vector printerList ){ //... } } public class JobEventListener { public void statusChanged ( JobEvent jobEvent ){ //... } public void pageComputed ( JobEvent jobEvent ){ //... } }
    25. public class PrintServerImpl extends ServiceAdvanced implements PrintServer , JobListener { private Map < String , PrinterServerJob > printerServerJob ; private PrinterList printerList ; private JobEventListener jobEventListener ; public PrintServerJob getJob ( String jobId ) { return printerServerJob . get ( jobId ); } public Vector getPrinterList (){ return printerList . getPrinterList (); } public void setPrinterList ( Vector printerList ){ return printerList . setPrinterList ( printerList ); } public void statusChanged ( JobEvent jobEvent ){ jobEventListener . statusChanged ( jobEvent ); } public void pageComputed ( JobEvent jobEvent ){ jobEventListener . pageComputed ( jobEvent ); } //... }
    26. OpenClose Principle open for extension close for modification abstraction
    27. public static final int TYPE_UNDEFINED = 0 ; public static final int TYPE_LEGAL_AG = 1 ; public static final int TYPE_LEGAL_PG = 2 ; public static final int TYPE_TEMPORARY = 3 ; //... boolean ok = false ; String buildType = m_cdInfo . buildType . toUpperCase (); String prefix = &quot;&quot; ; switch ( archType ) { case TYPE_LEGAL_AG : if ( buildType . equals ( &quot;LEGAL_AG&quot; ) || buildType . equals ( &quot;LEGAL_AGPG&quot; )){ ok = true ; } break ; case TYPE_LEGAL_PG : if ( buildType . equals ( &quot;LEGAL_PG&quot; ) || buildType . equals ( &quot;LEGAL_AGPG&quot; )){ ok = true ; } break ; case TYPE_TEMPORARY : if ( buildType . equals ( &quot;TEMPORARY&quot; ) || buildType . equals ( &quot;PRV&quot; )){ ok = true ; } prefix = &quot;AP &quot; ; break ; } if (! ok ) { BurnerHelper . showError (...); }
    28. public interface ArchiveType { public boolean isOk ( String buildType ); public String getPrefix (); } public class Undefined implements ArchiveType { public boolean isOk ( String buildType ){ return false ; } public String getPrefix () { return &quot;&quot; ; } } public class LegalAg implements ArchiveType { public boolean isOk ( String buildType ){ return buildType . equals ( &quot;LEGAL_AG&quot; ) || buildType . equals ( &quot;LEGAL_AGPG&quot; ) } public String getPrefix () { return &quot;&quot; ; } }
    29. public class LegalPg implements ArchiveType { public boolean isOk ( String buildType ){ return buildType . equals ( &quot;LEGAL_PG&quot; ) || buildType . equals ( &quot;LEGAL_AGPG&quot; ) } public String getPrefix () { return &quot;&quot; ; } } public class Temporary implements ArchiveType { public boolean isOk ( String buildType ){ return buildType . equals ( &quot;TEMPORARY&quot; ) || buildType . equals ( &quot;PRV&quot; ) } public String getPrefix () { return &quot;AP&quot; ; } }
    30. //... archTypes . put ( 0 , new Undefined ()); archTypes . put ( 1 , new LegalAg ()); archTypes . put ( 2 , new LegalPg ()); archTypes . put ( 3 , new Temporary ()); //... String buildType = m_cdInfo . buildType . toUpperCase (); boolean ok = archTypes . get ( archType ). isOk ( buildType ); String prefix = archTypes . get ( archType ). getPrefix (); if (! ok ) { BurnerHelper . showError (...); } //...
    31. Liskov Substitution Principle If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T
    32. Liskov Substitution Principle Subtypes must be substitutable for their base types Inheritance and polymorphism
    33. public class Rectangle { protected int _width ; protected int _height ; public int Width { get { return _width ; } } public int Height { get { return _height ; } } public virtual void SetWidth ( int width ){ _width = width ; } public virtual void SetHeight ( int height ){ _height = height ; } } public class Square : Rectangle { public override void SetWidth ( int width ){ _width = width ; _height = width ; } public override void SetHeight ( int height ){ _height = height ; _width = height ; } }
    34. [ TestFixture ] public class RectangleTests { private void CheckAreaOfRectangle ( Rectangle r ){ r . SetWidth ( 5 ); r . SetHeight ( 2 ); Assert . IsEqual ( r . Width * r . Height , 10 ); } [ Test ] public void PassingTest (){ Rectangle r = new Rectangle (); CheckAreaOfRectangle ( r ); } [ Test ] public void FailingTest (){ Rectangle r = new Square (); CheckAreaOfRectangle ( r ); } }
    35. public class Rectangle { protected int _width ; protected int _height ; public int Width { get { return _width ; } } public int Height { get { return _height ; } } public virtual void SetWidth ( int width ){ _width = width ; } public virtual void SetHeight ( int height ){ _height = height ; } } public class Square { protected int _side ; public int Side { get { return _side ; } } public void SetSide ( int side ){ _side = side ; } }
    36. Interface Segregation Principle Don’t be force to implement unused methods Avoid “Fat Interfaces” High cohesion - better understandability, robustness Low coupling - better maintainability, high resistance to changes
    37. public interface CartographyListener { public void poisChanged ( Locations pois ); public void cellsChanged ( Locations cells ); public void mapChanged ( ImageIcon map ); public void updateZoomLevel ( int level ); public void updateGeoArea ( GeoArea ga ); public void updateGridPosition ( Point2D . Double gridPosition ); public void updateMousePosition ( Point position ); } public class CellLayer extends Layer { /* Methods from CartographyListener interface */ public void cellsChanged ( Locations cells ) { setLocations ( cells ); } //..... } public class PoiLayer extends Layer { /* Methods from CartographyListener interface */ public void poisChanged ( Locations locations ) { setLocations ( locations ); } //..... }
    38. public abstract class Layer implements CartographyListener , DrawingInterface { /* Methods from CartographyListener interface */ // Metto qui un'implementazione vuota (una sorta di adapter) così // non sono costretta a sovrascrivere i metodi in tutte le specializzazioni. public void poisChanged ( Locations pois ) {} public void cellsChanged ( Locations cells ) {} public void mapChanged ( ImageIcon map ) {} public void updateZoomLevel ( int level ) { m_zoomLevel = level ; } public void updateGeoArea ( GeoArea ga ) { m_geoArea = ga ; } public void updateGridPosition ( Point2D . Double gridPosition ) {} public void updateMousePosition ( Point position ) {} /* End of methods from CartographyListener interface */ //..... }
    39. public class CartographyUI extends JPanel { public void addCartographyListener ( CartographyListener listener ) { if ( m_listeners == null ) { m_listeners = new ArrayList (); } m_listeners . add ( listener ); } public void setCelles ( Locations celles ) { Iterator listeners = m_listeners . iterator (); while ( listeners . hasNext ()) { CartographyListener listener = ( CartographyListener ) listeners . next (); listener . cellsChanged ( celles ); } updateViewFromLocations (); } public void setPois ( Locations pois ) { Iterator listeners = m_listeners . iterator (); while ( listeners . hasNext ()) { CartographyListener listener = ( CartographyListener ) listeners . next (); listener . poisChanged ( pois ); } updateViewFromLocations (); } //..... }
    40. public interface CartographyListener { } public interface CellListener extends CartographyListener { public void cellsChanged ( Locations cells ); } public interface PoiListener extends CartographyListener { public void poisChanged ( Locations locations ); }
    41. public class CartographyUI extends JPanel { public void setCelles ( Locations celles ) { Iterator listeners = m_listeners . iterator (); while ( listeners . hasNext ()) { CellListener listener = ( CellListener ) listeners . next (); listener . cellsChanged ( celles ); } updateViewFromLocations (); } public void setPois ( Locations pois ) { Iterator listeners = m_listeners . iterator (); while ( listeners . hasNext ()) { PoiListener listener = ( PoiListener ) listeners . next (); listener . poisChanged ( pois ); } updateViewFromLocations (); } // ... } public void addCartographyListener ( CartographyListener listener ) { Class < ? > c = genericObj . getClass (); Class < ? > interfaces [] = c . getInterfaces (); for ( Class < ? > implementedIntf : interfaces ) { if ( implementedIntf . getName (). equals ( urmetcns.mito.ui.cartography.ui_components.PoiListener&quot; )) poiListeners . add (( PoiListener ) listener ); if ( implementedIntf . getName (). equals ( &quot;urmetcns.mito.ui.cartography.ui_components.CellListener&quot; )) cellListeners . add (( CellListener ) listener ); // ... } }
    42. Dependency Injection Principle Hollywood Principle: Inversion of Control &quot;don't call us, we will call you&quot; Dip <> Spring
    43. private boolean retriveCallSideInfo ( String Side ) { //... DeterminationMethod = getXmlOption ( &quot;Method&quot; ); // specify which method to be used //... if ( DeterminationMethod . equals ( &quot;PhoneMatch&quot; )) { //... } if ( DeterminationMethod . equals ( &quot;Exist&quot; )) { //Query to che the existence of a specified dictionary element sqlString = &quot;SELECT count(*) AS Cnt FROM iri_dictionary &quot; &quot; WHERE iri_id = ? and key_dictionary = ?&quot; ; pstmt = ( OraclePreparedStatement ) assocInfo . conn . prepareStatement ( sqlString ); pstmt . setLong ( 1 , assocInfo . myIRIId ); pstmt . setString ( 2 , Dictionary ); } if ( DeterminationMethod . equals ( &quot;Compare&quot; )) { //... } if ( DeterminationMethod . equals ( &quot;InOnly&quot; )) { //Query alwais true for the //provider Telecom Internazionale sqlString = &quot;SELECT 1 As Cnt FROM Dual&quot; ; //... } //... //return true if the info has been found return ( itemFound == 1 ); }
    44. public abstract class CallSideDeterminator { public abstract boolean findItem (); //... } public class CallSideDeterminatorCompare extends CallSideDeterminator { @Override public boolean findItem (){ //... } } public class CallSideDeterminatorDFDM extends CallSideDeterminator { @Override public boolean findItem (){ //... } } public class CallSideDeterminatorPhoneMatch extends CallSideDeterminator { @Override public boolean findItem (){ //... } }
    45. public class AsExecFindCallSide extends AsCommandExec { HashMap < String , CallSideDeterminator > strategies = new HashMap < String , CallSideDeterminator >(); private void init () { strategies = new HashMap < String , CallSideDeterminator >(); strategies . put ( &quot;PhoneMatch&quot; , new CallSideDeterminatorPhoneMatch ()); strategies . put ( &quot;Compare&quot; , new CallSideDeterminatorCompare ()); strategies . put ( &quot;DFDM&quot; , new CallSideDeterminatorDFDM ()); //... } protected boolean retrieveCallSideInfo ( String side ) { CallSideDeterminator determinator = null ; if (( determinator = strategies . get ( getXmlOption ( &quot;Method&quot; ))) != null ) { determinator . initDeterminator ( assocInfo , side ); if ( determinator . findItem ()) { return determinator . storeCIN ( side ); } } return false ; } //... }
    46. The Others Principles
    47. Reuse Release Equivalency Principle The granule of reuse is the granule of release A package can be considered unit of distribution A release should have a version number Black-box, package that is to be used but not changed
    48. Common Closure Principle Maintainability is more important than reusability If code must change, all changes should be in the same package Common changing classes, should be in the same package
    49. Common Reuse Principle The classes in a package are reused together If you reuse one of the classes in a package, you reuse them all
    50. Acyclic Dependencies Principle Avoid cyclic dependencies Nightmare to compile Nightmare to deploy
    51. Least Astonishment Principle The result of some operation should be obvious, consistent, predictable Occam’s Razor: The simplest answer is usually the correct answer
    52. int multiply ( int a , int b ) { return a + b ; } int write_to_file ( const char * filename , const char * text ){ printf ( &quot;[%s] &quot; , text ); /* Note that 'filename' is unused */ }
    53. Law of Demeter Encapsulation An object should avoid invoking methods of a member object returned by another method “ Don’t talk to stranger&quot; An object A can request a service (call a method) of an object instance B, but object A cannot “ reach through” object B to access yet another object, C, to request its services “ Use only one dot&quot;
    54. Inventory . SalesInfo . Items . Count = 2500 ; Room . getPlan (). canCustomizeWindow () Room . getPlan (). canSelectStyle () Room . getPlan (). hasCeilingFan ()
    55. Inventory . SetSalesItemsCount ( 2500 ); Room . canCustomizeWindow () Room . canSelectStyle () Room . hasCeilingFan ()
    56. Smells and Heuristics
    57. Comments
    58. Obsolete Comments Old comments that have lost their meaning
    59. //*********************************************************************************** //! Initalize procedure /*! * This methos is called from the main in order to initialize all the thinks<br> * that the plugin need. * * param inLog log that the plugin can use for its own purpose * eturn true = all ok false = intialization failed */ //*********************************************************************************** public bool init ( log4net . ILog inLog ) { this . log = inLog ; //log.Debug(&quot;=======================================================&quot;); log . Debug ( &quot;============ INIT Module &quot; + getModuleName () + &quot; =========&quot; ); return true ; }
    60. public void initLog ( log4net . ILog inLog ){ log = inLog ; log . Debug ( &quot;============ INIT Module &quot; + getModuleName () + &quot; =========&quot; ); }
    61. Redundant Comments Version History
    62. /** * * * 03 Oct 2005 - AB - Added the isSameCIDinSameLiuID() function to avoid different CID in the same LIU (Ticket#2564) * 09 Sep 2005 - AB - fixed the retriveCallSideInfo() for the PhoneMatch method (Ticket#2381) * 06 Sep 2005 - AB - Fixed the SearchProviderDate() to properly work with the 'DATA' association technique * 01 Sep 2005 - AB - Added the dupval index exception handling in saveInHiddenJournal() function * 27 Jul 2005 - AB - changed the isInformationInDb() to avoid exiting with assocInfo.lemfList == null * 27 Jul 2005 - AB - removed the updateJournal() function because not needed * 26 Jul 2005 - AB - Now mergeJournal() saves a copy of the two lius ti be merged in the hidden_journal table * 26 Jul 2005 - AB - Added the saveInHiddenJournal() function to enhance the mergeJournal() function * 05 Jul 2005 - AB - Changed the retriveCallSideInfo queries to select the correct liu_id in every situation. … * 23 Mar 2005 - AB - Added the ORA-00001 error handling in the AddIRI2Journal * 9 Mar 2005 - AB - moved the queryExec body function to a generic queryExec function in the IRITools * 11 May 2004 - AB - Started **/
    63. svn ci -m ‘Added the isSameCIDinSameLiuID() (Ticket#2564)’ AssociationFunction.java
    64. Redundant Comments Repeating the variable name or condition in the comment
    65. // // list on a file all the Extractors extensions // if ( param == &quot;-LISTEXTRACTORS&quot; ) //...
    66. Redundant Comments Repeating the called method name in a comment after the call
    67. int abs = x . abs (); // Get the absolute value of x int x = point . getX (); // Get the value of x
    68. int abs = x . abs (); int x = point . getX ();
    69. Redundant Comments Commented Out Code
    70. pos = pos + 9 ; //byteData[0] = (byte)fstr.ReadByte(); if ( byteData [ 0 ] == 0x65 ) // 'e' { //byteData[1] = (byte)fstr.ReadByte(); if ( byteData [ 1 ] == 0x6E ) // 'n' { //yteData[2] = (byte)fstr.ReadByte(); if ( byteData [ 2 ] == 0x64 ) // 'd' { //... } // 'e' else { //if (byteData[6] == 0x65) //{ // dataIn.Add(byteData[0]); // dataIn.Add(byteData[1]); // dataIn.Add(byteData[2]); // dataIn.Add(byteData[3]); // dataIn.Add(byteData[4]); // dataIn.Add(byteData[5]); // fstr.Seek(-3, SeekOrigin.Current); //} //else { dataIn . Add ( byteData [ 0 ]); //...
    71. pos = pos + 9 ; if ( byteData [ 0 ] == 0x65 ) // 'e' { if ( byteData [ 1 ] == 0x6E ) // 'n' { if ( byteData [ 2 ] == 0x64 ) // 'd' { //... } // 'e' else { dataIn . Add ( byteData [ 0 ]); //...
    72. Redundant Comments Comments related to structure
    73. // // Upgrade section // if ( param == &quot;-GENERATEUPDATE&quot; || param == &quot;-DOWNLOADUPDATE&quot; || param == &quot;-CHECKUPDATE&quot; ) { Int32 retVal = ALLOK ; // .... // .... // .... // .... // .... // .... //after 336 more lines of code... } // End of Upgrade section
    74. manageUpdate ( param );
    75. Functions
    76. Functions Long Methods
    77. protected void build ( DynamicView view , File baseTemplate , File outTemplate ) throws ArchiverException , WrEntsException { //Create required data and column description List colNames = normalize ( view . getDynamicColumnSet ()); HashMap lines = new HashMap (); List leftNames = new ArrayList (); List rightNames = new ArrayList (); //Start reading input template and create output copy BufferedReader r = null ; FileWriter w = null ; if ( outTemplate . exists ()) { outTemplate . delete (); } try { r = new BufferedReader ( new FileReader ( baseTemplate )); w = new FileWriter ( outTemplate ); String record = null ; boolean sortedBlock = false ; while (( record = r . readLine ()) != null ) { if ( sortedBlock ) { if ( record . toUpperCase (). indexOf ( &quot;{END_SORTED_RECS}&quot; ) >= 0 ) { sortedBlock = false ; //Writes required records String line = null ; //Static first line (if any)... for ( int j = 0 ; j < leftNames . size (); j ++) { line = ( String ) lines . get ( leftNames . get ( j )); if ( line != null ) { w . write ( line + &quot; &quot; ); } }
    78. //Sorted lines for ( int j = 0 ; j < colNames . size (); j ++) { line = ( String ) lines . get ( colNames . get ( j )); if ( line != null ) { w . write ( line + &quot; &quot; ); } } w . write ( record + &quot; &quot; ); //Static last line (if any)... for ( int j = 0 ; j < rightNames . size (); j ++) { line = ( String ) lines . get ( rightNames . get ( j )); if ( line != null ) { w . write ( line + &quot; &quot; ); } } } else { int index = record . indexOf ( &quot;{META_REC:&quot; ); if ( index >= 0 ) { String key = record . substring ( index + 10 , record . indexOf ( '}' , index )); if ( key . indexOf ( &quot;:&quot; ) >= 0 ) { String values [] = key . split ( &quot;:&quot; ); if ( values [ 1 ]. equals ( &quot;L&quot; )) { leftNames . add ( key ); } else if ( values [ 1 ]. equals ( &quot;R&quot; )) { rightNames . add ( key ); } } lines . put ( key , new String ( record )); } } }
    79. else { if ( record . toUpperCase (). indexOf ( &quot;{START_SORTED_RECS}&quot; ) >= 0 ) { sortedBlock = true ; lines . clear (); leftNames . clear (); rightNames . clear (); } w . write ( record + &quot; &quot; ); } } } catch ( Exception e ) { WrCheck . logError ( &quot;Error build template: &quot; + e . getMessage ()); throw new ArchiverException ( e ); } finally { try { if ( w != null ) w . close (); if ( r != null ) r . close (); } catch ( Exception e ) {} } }
    80. Functions Deeply nested methods
    81. //From TE-PDF exctractor if ( str_byteData . Contains ( &quot;s&quot; )) { posE_byteData = str_byteData . IndexOf ( &quot;s&quot; ); pos = pos + ( posE_byteData - 6 ); Array . Copy ( fileContent , pos , byteData , 0 , 6 ); pos = pos + 6 ; if ( byteData [ 0 ] == 0x73 ) // 's' { if ( byteData [ 1 ] == 0x74 ) // 't' { if ( byteData [ 2 ] == 0x72 ) // 'r' { if ( byteData [ 3 ] == 0x65 ) // 'e' { if ( byteData [ 4 ] == 0x61 ) // 'a' { if ( byteData [ 5 ] == 0x6D ) // 'm' { found = true ; break ; } else { if ( byteData [ 5 ] == 0x73 ) { pos = pos - 1 ; } } }
    82. else { if ( byteData [ 4 ] == 0x73 ) { pos = pos - 2 ; } else { pos = pos - 1 ; } } } else { if ( byteData [ 3 ] == 0x73 ) { pos = pos - 3 ; } else { pos = pos - 2 ; } } } else { if ( byteData [ 2 ] == 0x73 ) { pos = pos - 4 ; } else { pos = pos - 3 ; } } }
    83. else { if ( byteData [ 1 ] == 0x73 ) { pos = pos - 5 ; } else { pos = pos - 4 ; } } } else { pos = pos - 5 ; } }
    84. Functions Different abstraction level Composed method Divide your program into methods that perform one identifiable task
    85. public void service ( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException { /////si aggancia al file salvato nella mappa dell'oggetto application String fileId = request . getParameter ( &quot;FILEID&quot; ); if ( fileId == null ) { throw new ServletException ( &quot;Invalid FileId&quot; ); } String partNum = request . getParameter ( &quot;PART&quot; ); int part = 1 ; if ( partNum != null ) { part = Integer . valueOf ( partNum ). intValue (); } boolean isLast = &quot;Y&quot; . equals ( request . getParameter ( &quot;LAST&quot; )); boolean getName = &quot;Y&quot; . equals ( request . getParameter ( &quot;GETNAME&quot; )); String fileName = MitoDownloadCache . INSTANCE . getFileName ( fileId , part ); if ( fileName == null ) { throw new ServletException ( &quot;Invalid FileName&quot; ); } MitoConfig mitoCfg = new MitoConfig (); File file = new File ( mitoCfg . getPrintClientDataPath ()+ &quot;/&quot; + fileName ); if (! file . exists ()) { throw new ServletException ( &quot;File &quot; + file . getAbsolutePath () + &quot; not found&quot; ); } if ( getName ) { doDownloadFilename ( request , response , file . getName ()); } else { if ( isLast ) { MitoDownloadCache . INSTANCE . removeFileList ( fileId ); } doDownload ( request , response , file ); file . delete (); } }
    86. public void service ( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException { File file = fileToDownLoad ( request ); if ( downloadByName ( request )) { doDownloadFilename ( request , response , file . getName ()); } else { removeFromCacheIfLast ( request ); doDownload ( request , response , fileToDownLoad ( request )); file . delete (); } }
    87. private boolean downloadByName ( HttpServletRequest request ) { boolean getName = &quot;Y&quot; . equals ( request . getParameter ( &quot;GETNAME&quot; )); return getName ; } private void removeFromCacheIfLast ( HttpServletRequest request ) throws ServletException { boolean isLast = &quot;Y&quot; . equals ( request . getParameter ( &quot;LAST&quot; )); if ( isLast ) { MitoDownloadCache . INSTANCE . removeFileList ( fileId ( request )); } } private File fileToDownLoad ( HttpServletRequest request ) throws ServletException { File file ; String fileName = MitoDownloadCache . INSTANCE . getFileName ( fileId ( request ), part ( request )); if ( fileName == null ) { throw new ServletException ( &quot;Invalid FileName&quot; ); } MitoConfig mitoCfg = new MitoConfig (); file = new File ( mitoCfg . getPrintClientDataPath () + &quot;/&quot; + fileName ); if (! file . exists ()) { throw new ServletException ( &quot;File &quot; + file . getAbsolutePath () + &quot; not found&quot; ); } return file ; }
    88. private int part ( HttpServletRequest request ) { String partNum = request . getParameter ( &quot;PART&quot; ); int part = 1 ; if ( partNum != null ) { part = Integer . valueOf ( partNum ). intValue (); } return part ; } private String fileId ( HttpServletRequest request ) throws ServletException { String fileId = request . getParameter ( &quot;FILEID&quot; ); if ( fileId == null ) { throw new ServletException ( &quot;Invalid FileId&quot; ); } return fileId ; }
    89. General
    90. Duplication Dry “ Once, and only once” Duplication is a missed opportunity for abstraction
    91. Dead Code Code that isn’t executed if statement that checks for a condition that can’t happen Private method never called switch / case conditions that never occur Do the right thing: give it a decent burial
    92. Vertical Separation Variables and function should be defined close to where they are used Local variables should be declared just above their first usage
    93. public void service ( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException { /////si aggancia al file salvato nella mappa dell'oggetto application String fileId = request . getParameter ( &quot;FILEID&quot; ); if ( fileId == null ) { throw new ServletException ( &quot;Invalid FileId&quot; ); } String partNum = request . getParameter ( &quot;PART&quot; ); int part = 1 ; if ( partNum != null ) { part = Integer . valueOf ( partNum ). intValue (); } boolean isLast = &quot;Y&quot; . equals ( request . getParameter ( &quot;LAST&quot; )); boolean getName = &quot;Y&quot; . equals ( request . getParameter ( &quot;GETNAME&quot; )); String fileName = MitoDownloadCache . INSTANCE . getFileName ( fileId , part ); if ( fileName == null ) { throw new ServletException ( &quot;Invalid FileName&quot; ); } MitoConfig mitoCfg = new MitoConfig (); File file = new File ( mitoCfg . getPrintClientDataPath ()+ &quot;/&quot; + fileName ); if (! file . exists ()) { throw new ServletException ( &quot;File &quot; + file . getAbsolutePath () + &quot; not found&quot; ); } if ( getName ) { doDownloadFilename ( request , response , file . getName ()); } else { if ( isLast ) { MitoDownloadCache . INSTANCE . removeFileList ( fileId ); } doDownload ( request , response , file ); file . delete (); } }
    94. public void service ( HttpServletRequest request , HttpServletResponse response ) throws ServletException , IOException { /////si aggancia al file salvato nella mappa dell'oggetto application String fileId = request . getParameter ( &quot;FILEID&quot; ); if ( fileId == null ) { throw new ServletException ( &quot;Invalid FileId&quot; ); } String partNum = request . getParameter ( &quot;PART&quot; ); int part = 1 ; if ( partNum != null ) { part = Integer . valueOf ( partNum ). intValue (); } String fileName = MitoDownloadCache . INSTANCE . getFileName ( fileId , part ); if ( fileName == null ) { throw new ServletException ( &quot;Invalid FileName&quot; ); } MitoConfig mitoCfg = new MitoConfig (); File file = new File ( mitoCfg . getPrintClientDataPath ()+ &quot;/&quot; + fileName ); if (! file . exists ()) { throw new ServletException ( &quot;File &quot; + file . getAbsolutePath () + &quot; not found&quot; ); } boolean getName = &quot;Y&quot; . equals ( request . getParameter ( &quot;GETNAME&quot; )); if ( getName ) { doDownloadFilename ( request , response , file . getName ()); } else { boolean isLast = &quot;Y&quot; . equals ( request . getParameter ( &quot;LAST&quot; )); if ( isLast ) { MitoDownloadCache . INSTANCE . removeFileList ( fileId ); } doDownload ( request , response , file ); file . delete (); } }
    95. Clutter Default constructor without implementation Variables not used Functions never called Useless comments Kill’em all!
    96. Selector Arguments Avoid boolean arguments Breaks SRP Split method in two methods
    97. getLocalPrintService ( jobId , data , false ); public static PrintServiceInterface getLocalPrintService ( String jobId , IRawData data , boolean isStandAlone ) throws Exception { //... }
    98. public static PrintServiceInterface getEmbeddedLocalPrintService ( String jobId , IRawData data ) throws Exception { //... } public static PrintServiceInterface getStandAloneLocalPrintService ( String jobId , IRawData data ) throws Exception { //... }
    99. Explanatory Vars Avoid ‘artistic’ programming Break the calculations up
    100. Matcher match = headerPattern . matcher ( line ); if ( match . find ()) headers . put ( match . group ( 1 ), match . group ( 2 ));
    101. Matcher match = headerPattern . matcher ( line ); if ( match . find ()){ String key = match . group ( 1 ); String value = match . group ( 2 ); headers . put ( key . toLowerCase (), value ); }
    102. Magic Numbers Replace Magic Numbers with Named Constants
    103. m_tx1 . setPageHeight ( 16837 ); m_tx1 . setPageWidth ( 11906 ); m_tx1 . setPageMarginB (( int )( 0.35 * 1440 )); m_tx1 . setPageMarginL (( int )( 0.35 * 1440 )); m_tx1 . setPageMarginR (( int )( 0.35 * 1440 )); m_tx1 . setPageMarginT (( int )( 0.35 * 1440 )); m_tx2 . setPageMarginB (( int )( 0.35 * 1440 )); m_tx2 . setPageMarginL (( int )( 0.35 * 1440 )); m_tx2 . setPageMarginR (( int )( 0.35 * 1440 )); m_tx2 . setPageMarginT (( int )( 0.35 * 1440 ));
    104. final static double PAGE_HEIGHT = 16837 ; final static double PAGE_WIDTH = 11906 ; final static int MARGIN = ( int )( 0.35 * 1440 ;) m_tx1 . setPageHeight ( PAGE_HEIGHT ); m_tx1 . setPageWidth ( PAGE_WIDTH ); m_tx1 . setPageMarginB ( MARGIN ); m_tx1 . setPageMarginL ( MARGIN ); m_tx1 . setPageMarginR ( MARGIN ); m_tx1 . setPageMarginT ( MARGIN ); m_tx2 . setPageMarginB ( MARGIN ); m_tx2 . setPageMarginL ( MARGIN ); m_tx2 . setPageMarginR ( MARGIN ); m_tx2 . setPageMarginT ( MARGIN );
    105. Negative Conditionals Negatives is harder to understand than positives Avoid negatives Conditionals
    106. if (! buffer . shouldNotCompact ()) { //... } if (! envWarrantsEnabled ) sqlSelect . addWhere ( new SqlNot ( new SqlEq ( &quot;LI_TYPE&quot; , &quot;ENV&quot; )));
    107. if ( buffer . shouldCompact ()) { //... } if ( envWarrantsDisabled ) sqlSelect . addWhere ( new SqlNot ( new SqlEq ( &quot;LI_TYPE&quot; , &quot;ENV&quot; )));
    108. Names
    109. Descriptive Names Choice descriptive names Reevaluate the appropriateness of the names
    110. public int x () { int q = 0 ; int z = 0 ; for ( int kk = 0 ; kk < 10 ; kk ++) { if ( l [ z ] == 10 ) { q += 10 + ( l [ z + 1 ] + l [ z + 2 ]); z += 1 ; } else if ( l [ z ] + l [ z + 1 ] == 10 ) { q += 10 + l [ z + 2 ]; z += 2 ; } else { q += l [ z ] + l [ z + 1 ]; z += 2 ; } } return q ; }
    111. public int score () { int score = 0 ; int frame = 0 ; for ( int frameNumber = 0 ; frameNumber < 10 ; frameNumber ++) { if ( isStrike ( frame )) { score += 10 + nextTwoBallsForStrike ( frame ); frame += 1 ; } else if ( isSpare ( frame )) { score += 10 + nextBallForSpare ( frame ); frame += 2 ; } else { score += twoBallsInFrame ( frame ); frame += 2 ; } } return score ; }
    112. Unambiguous Names Choose names that make the workings of a function or variable unambiguous
    113. public boolean stateMachine ( int smStatus ) { //... } public boolean doAction () { //... }
    114. public boolean moveStateMachineToStatus ( int smStatus ) { //... } public boolean doNextStepInProviderTechnique () { //... }
    115. Avoid Encodings Names should not be encoded with type or scope information Hungarian Notation as obsolete legacy
    116. protected int m_FilesCount ; // Numero files contenuti nel job protected int m_VolumesCount ; // Numero dischi richiesti dal job (1 sola copia) protected long m_TotalSize ; // Size totale in byte del job protected int m_VolumesDone ; // Numero dischi completati protected String m_VolDoneList ; // Lista dischi completati (durante esecuzione) protected ArrayList m_labelFields ; // Nomi/valori campi da utilizzare in label private long m_LastModTime ; // Data/ora modifica file informativo del job protected boolean isOnDisk ;
    117. protected int filesCount ; // Numero files contenuti nel job protected int volumesCount ; // Numero dischi richiesti dal job (1 sola copia) protected long totalSize ; // Size totale in byte del job protected int volumesDone ; // Numero dischi completati protected String volDoneList ; // Lista dischi completati (durante esecuzione) protected ArrayList labelFields ; // Nomi/valori campi da utilizzare in label private long lastModTime ; // Data/ora modifica file informativo del job protected boolean isOnDisk ;
    118. Describe Side Effects Names should describe everything that a function, variable, or class is or does
    119. public DiskWriterJobs getJobs () { if ( m_Jobs == null ) { m_Jobs = new DiskWriterJobs ( this ); } return m_Jobs ; }
    120. public DiskWriterJobs createOrReturnJobs () { if ( m_Jobs == null ) { m_Jobs = new DiskWriterJobs ( this ); } return m_Jobs ; }
    121. Tests
    122. Insufficient Tests How many tests? A test suite should test everything that could possibly break Use a Coverage Tool:
      • Java
        • EMMA
        • Cobertura
        • Clover
      .NET PartCover C/C++ BullseyeCoverage gcov Beware of Coverage Results
    123. Don’t Skip Trivial Tests They are better than documentation Easy today, maybe hard tomorrow
    124. Exhaustively Test Near Bug Bugs tend to congregate
    125. Tests Should Be Fast If slow, launched less frequentely If launched less frequentely, big change between launches and difficult to know where and when an error was introduced
    126. Conclusions?
    127. Readable Code
    128. Test
    129. Avoid Duplication
    130. Readable Code Test Avoid Duplication
    131. Q&A?
    132. http://creativecommons.org/licenses/by-nc-sa/3.0/
    SlideShare Zeitgeist 2009

    + giordano scalzogiordano scalzo Nominate

    custom

    314 views, 2 favs, 0 embeds more stats

    Good code is a golden treasure often buried under a more

    More info about this document

    CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

    Go to text version

    • Total Views 314
      • 314 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 2
    • Downloads 19
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories