Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Creating Eloquent Code

293 views

Published on

If you've been programming long, you've had the experience of looking at your own code and struggling to understand it. Worse yet is trying to understand other people's code. Every piece of code you write not only instructs the computer, it also informs human readers. What is it telling them? In this session, you will learn to listen to what your code is saying. You will see how choices about scope, visibility, coupling, and cohesion reveal themselves in your code. You will learn principles and practices for creating eloquent code. Examples will be in C#, but will be applicable to any object oriented language. You will come away with new ideas to make your code speak clearly and inspiration to be more mindful while writing code.

Published in: Software
  • Be the first to comment

Creating Eloquent Code

  1. 1. Creating Eloquent Code Joe rtley @JoeWirt| ey
  2. 2. About Me Wirtley Consulting LLC Springboro, OH Dayton . NET Developer Group C#, WPF, MVC, Web API @JoeWirt| ey
  3. 3. Hell is other people's code
  4. 4. F~-‘W. . . F i ll l". ll, "": l. l SID (SOLID) Express Intent Be Explicit Minimize Scope and Visibility Manage Dependencies Create Cohesive Abstractions
  5. 5. Single Responsibility Principle (SRP) A class (method) should have only one reason tochange Interface Segregation Principle (ISP) No client should be forced to depend on methods it does not use. Dependency Inversion Principle (DIP) Depend on abstractions, not on concretions.
  6. 6. Express Intent I Write code to be read by humans I Don't make me execute code in my head I Write more declarative code
  7. 7. foreach ( Data(o1uIn 1:01 in columns ) { if ( col. (olumnName. Equals( Datahblefiolumnuames. RouNumber-Columnflale, Stringcomparison. Invar: lant(ultureIgnor~eCase ) ) { ll Ignore the Korllumber column. continue; } if ( col. (olunnName. Equals( DatoTab1e(olumnNanes. RowStampColumnName, Stringcompar-ison. Invariantcultur-elgnorecase ) ) ( / / Ignore the Rouflumber column. continue; } if ( col. Co1umNaue. ToUpper-(). StartsH1th( Datahblecoluunuaues. Ca1culatedCo1Pr-efix. Ioupper-() ) | | ( co1.Co1umnName. ToUpper-(). EndsH: |.th( DataTable(o1umnNaues. Act1onCo1Suff1x. ToUpper() ) ) | | ( co1.Co1umnName. ToUpper(). EndsH1th( DataTab1e(o1umnNanes. CauseCo1Suff1x. ToUpper() ) ) I] ( col. Co1uiInName. ToUpper(). EndsH1th( DetaYableColumNames. NoteCo1Suff1x. ToUpper() ) ) ) I / / Ignore calculated columns, and causes, notes, and actions continue; ) / / Do something with the column here a. io; ag X= IIl‘tlC)’ ' . ;: ~ll. "‘i~_‘ _
  8. 8. foreach ( Datacolumn col in columns ) { string columnflame - col. ColumnName; if ( columnuane. IsRowNumberCo1umnName() ) { / / Ignore the Rouflumber column. continue; } if ( columnflane. IsRowStampColunnNane() ) { / / Ignore the Rowstamp column. continue; } if ( coluunflane. IsCa1cu1atedColunnName() II colunnuame. IsCauseNoteOrAction() ) { / / Ignore calculated columns, and causes, notes, and actions continue; } / / Do something here Jayv X7i rt I Cy ‘ -.1 ~l1_"'i= ,; .
  9. 9. Basics I Do not copy code I Use informative names I Not foo, bar, baz I Correct spelling and tense I Don't get stuck on names I Maximize signal to noise ratio
  10. 10. if ( Selectedltems ! = null && Se1ectedItems. Count / / Do something } if ( IsExact1y0neItemSelected ) { / / Do something } 1){ aJo, tag J3l: |.V
  11. 11. foreach ( var View in TabsRegion. Views ) { var frameworkE1ement = view as 7r5meu: --i‘ if ( frameworkE1ement ! = null ) { IH P J —+ var vm = frameworkElement. DataContext as iF: iiti~»” i4l? a 2- if ( vm ! = null ) { if ( vm. IsDirty ) { return true; } return TabsRegion. Views.0fType<l’2 V” : L+. . ‘H‘>() . Select( frameworkE1ement = > frameworkE1ement. DataContext ) . OfType<lélitv; v.“ Wv: VAw~>() . Any( vm = > vm. IsDirty ); 3JO}38 Jayv
  12. 12. Be Explicit I Code, not conventions I Don't imply usage, enforce it I Inject dependencies
  13. 13. public class Divisionsflenultenviudfloael: Ihenultenvieuflodel { private readonly DelegateCounand<object> _coanand; private readonly lkegionflanager _regionManager; private bool _yisib1e I true; aiolag public Divisionsflenultedvieuflodel( Ifiegionnanager regionflanager ) { _counand - new DelegateConnand<object>( 0nExecute, CanExecute ); _regionHanager - regionflanager; } private bool CanExecute( object arg ) { return ( _reg1onManager. Regions[ Reg1ons. Hain ]. Vieus. A1l( v -> v. GetType() ! - typeof( DivisionsL1stVieu ) ) ); } private void 0nExecute( object obj ) { _regionManager. RequestNavigate( Regions. Main, Navigat1onPath ); } public DelegateCcI-and<object> Command { get { return _conIand; } } public string Text { get { return “Divisions”; } } public string ToolTip { get { return "Divisions"; } } public int Order { get { return 2; } » xxm-tic}: ' «n . u_’vi; T.
  14. 14. public interface IMenuItemViewModel { De1egateCommand<object> Command { get; } string Text { get; } string ToolTip { get; } int Order { get; } bool SeparatorAfter { get; } string Iconflame { get; } bool Visible { get; set; } a3e; Ja1u| "' ii rt i 3'-». '
  15. 15. public class DivisionsflenuItenMiewModel: MenuItenViewMode1Base { public Divisionsflenultenvieuflodel( Ikegionanager regionflanager ): base( regionManager ) { } JBIJV protected override void Initialize() { LaunchesView<Div1sionsListView>(); Text - "Divisions"; ToolTip I "Divisions"; Order = 2; Iconflane - "divisions_sett1ngs_nenu_icon"; SeparatorAfter - true; X7i i‘t'cj, ~' ‘ ~ll. "i
  16. 16. public abstract class Menultenvieufiodelflase: menulteaviemooel { private Type _viewToLaunch I null; private bool _v1sib1e I true; protected MenuItenViemodelBase( Ikegionflanager regionnanager ) { Regionflanager I regionflanager; Separator-After - false; Collland I new DelegateConnand<object>( 0nExecute, CanExecute ); IconName I ; Initialize(); } protected abstract void Initialize(); protected virtual void 0nExecute( object obj ) { if ( _vieHToLaunch ! - null ) { Regionflanager. RequestNavigate( Regions. Main, _viewToLaunch. Ful1NaiIe ); } } protected virtual bool CanExecute( object arg ) { return ( _view‘l'oLaunch -- null II ! IsViewOpen( _vie«ToLaunch ) ); } private bool IsVieH0pen( Type viewType ) { return RegionManager. Regions[ Regions. Main ]. Views. Any( v -> v. GetType() -- viewType ); } protected bool IsVieH0pen< T >() { return RegionManager. Regions[ Regions. D-Iain ]. Views. Any( v -> v. GetType() -- typeof( T ) ); ‘X'iv l } protected Ikegionnanager Regionflanager { get; set; } SSE| :) 9528 . ’ ‘ l l
  17. 17. public interface Ivalidator { bool Validate( List<string> validationfiessages ); } public class NotEuptyValidator: IValidator { private readonly string _value; public NotEuptyValidator( string value ) { _value I value; } public bool Validate( List<string> validationflessages ) { if ( string, IsNull0rHhiteSpace( _value ) ) { validationMessages. Add( "Value cannot be empty" ); return false; } return true; } } public class Integervalidatorz Ivalidator { private readonly string _yalue; public IntegerValidator( string value ) { _value I value; } public bool Validate( List<string> validationflessages ) { int result; if ( ! int. TryParse( _ya1ue, out result ) ) { va1idationMessages. Add( "Value must be an integer" ); return false; } return true; aiolag xil'ii«xic; r ' . ;: ~ll_”‘lg _
  18. 18. public interface Ivalidator { bool Validate( Valiaationnessages validationflessages ); } public class Motfmptyvalidatorz Ivalidator { private readonly string _value; public NotEnptyValidator( string value ) { _value I value; } public bool Validate( Va1idationMessages validationflessages ) { if ( string. IsNull0rHhiteSpace( _yalue ) ) { validationMessages. Add( "Value cannot be enpty" ); return false; } return true; } } public class Integervalidetor: Ivalidator { private readonly string _value; public IntegerValidetor( string value ) { _value I value; } public bool Validate( Validationflessages validationMessages ) { int result; if ( ! int. TryParse( _value, out result ) ) { validationMessages. Add( ‘Value must be an integer” ); return false; } return true; JBJJV Xr-"'ii‘tlcy ' . ;: ~ll_”‘lg _
  19. 19. public class . ~-;1%T : 'e53:>~—: private readonly _-: :<string> _messages = new public void Add( string validationflessage ) { _messages. Add( validationMessage ); } public Ii . »;~; :: (string) GetEnumerator() { return _messages. GetEnumerator(); } J e if: if xii s: ;e. GetEnumerator() { return _messages. GetEnumerator(); } u e s, _e<String> { _, ;t<string>(); safiessai/ |uop, epg| e/
  20. 20. public class Docunentcontroller { private readonly IDocunentService _docuuentService; private readonly IUserService _userService; public DocunentController() { _docunentService I new DocunentService(); _userService I new UserService(); aJo; ag } public class Docunentcontroller { private readonly Ioocunentservice _docunentService; private readonly IUserService _userService; Jallv public DocunentController( lDocunentService documentservice, IUserService userservice ) { _docunentServ1ce I docunentservice; _userService I userservice; } “C4. Vi rt i 31'
  21. 21. Minimize Scope I Variable instead of field I Return value instead offield I Parameter instead offield I Fields are “global variables” I Minimize side effects
  22. 22. public class Rectangle { private int _area; private readonly int _length; private readonly int _width; public Rectangle( int length, int width ) { _length I length; _width I width; } public int GetArea() { CalculateArea(); return _area; } private void CalculateArea() { _area I _1ength * _width; } aJo, tag
  23. 23. public class Rectangle { private readonly int _length; private readonly int _width; Jéllv public Rectangle( int length, int width ) { _length I length; _width I width; } public int GetArea() { return CalculateArea( _length, _width ); } private int CalculateArea( int length, int width ) { return length * width; }
  24. 24. Minimize Visibility I Private, Protected, Internal, Public I Properties should be read-only if possible I Expose properties with smallest interface possible I Security Parallels I Minimize attack surface I Off by default ~ Private by default
  25. 25. public class ? ::, e‘it; e ‘.121 { public DocumentViewMode1( int id ) { Id = id; Readers = new . ;:: <string>(); } public int Id { get; set; } public _; ;t<string> Readers { get; set; } aJo, iag
  26. 26. public class fl: :. .i ; -:« T : .‘. -;L { private readonly si; :<string> _readers; public DocumentViewMode1( int id ) { Id = id; _readers = new _; :t<string>(); } public int Id { get; private set; } public IE u“: a: ;e<string> Readers { get { return _readers; } } public void AddReader( string readerName ) { _readers. Add( readerName ); } Jallv
  27. 27. Manage Dependencies I Prefer constructor injection I Depend on abstractions I Depend on individual values, smallest possible interface
  28. 28. Create Cohesive Abstractions I Create more classes and interfaces I Honorthe Single Responsibility Principle I | fyou’re doing MVC, don't stop with models, views, and controllers I Don't create god classes or helper classes
  29. 29. So much of programming comes down to micro-choices where small things that don't matter much on their own aggregate into large and consequential choices made by accident. - David Hayes Ternary Operators Considered Harmful htt : ressu inc. com blo 201 o terna -o erators-considered-harmful

×