www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
Red
Green
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use b...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.renaissancesoftware.net
james@renaissancesoftware.net
Copyright ©2008-2013 James W. Grenning	

All Rights Reserved. Fo...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
Donald Knuth Says
12
ACCU 2014
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Right...
Martin Fowler Says
13
ACCU 2014
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Righ...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
• Once a design problem is identified, you must
envision a better solution
• Look to apply the design principles
– SOLID
–...
Refactoring
www.renaissancesoftware.net
james@renaissancesoftware.net
Copyright © 2008-2013 James W. Grenning	

All Rights...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
OS Abstraction
typedef struct ThreadStruct * Thread;	
typedef void * (*ThreadEntryFunction)(void *);	
!
Thread Thread_Crea...
OS Abstraction is Not Working
//Snip from some product code	
!
Thread thread = Thread_Create(threadEntry, 0);	
!
#if POSIX...
OCP/LSP Designs Don’t Burden the Client
//Snip from some product code	
!
Thread thread = Thread_Create(threadEntry, 0);	
T...
POSIX Version Delays Thread Creation
typedef struct ThreadStruct	
{	
ThreadEntryFunction entry;	
void * parameter;	
pthrea...
Acme Does Not Need To Delay Create
typedef struct ThreadStruct	
{	
AcmeThreadStruct acmeThread;	
} ThreadStruct;	
!
Thread...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
Third
Party
Code
Your
Code
Your
Code Your
Code
Third
Party
Code
Your
Code
Your
Code Your
Code
www.wingman-sw.com
james@win...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
www.wingman-sw.com
james@wingman-sw.com
Copyright © 2008-2014 James W. Grenning	

All Rights Reserved. For use by training...
Upcoming SlideShare
Loading in …5
×

Designing SOLID C - ACCU Conference 2014

1,756 views

Published on

C does not have to be spaghetti code. It can be modular and flexible if you apply the SOLID design principles. In this tutorial, we look at applying Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation and Dependency Inversion principles to C. SOLID gives good guidance on modularity and coupling; these principles are not just for programmers with an OO language.

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,756
On SlideShare
0
From Embeds
0
Number of Embeds
1,059
Actions
Shares
0
Downloads
34
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Designing SOLID C - ACCU Conference 2014

  1. 1. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 SOLID C James Grenning Presented at ACCU 2014 Bristol, UK 1 Talk to me on Twitter @jwgrenning ! Connect with me on linkedin.com http://www.linkedin.com/in/jwgrenning Remind me how we met. ! http://www.wingman-sw.com http://blog.wingman-sw.com http:// www.jamesgrenning.com unpappd.com jwgrenning
  2. 2. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 2 When is Software Design Finished?
  3. 3. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 3 A Complex system that works is invariably found to have evolved from a simple system that worked.
  4. 4. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 4 Red Green Refactor
  5. 5. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Rules of Simple Design In Priority Order! 1. Passes all tests 2. No duplication 3. Expresses intent 4. Fewest classes and methods (no extra stuff) 5 Kent Beck [XP, TDD]
  6. 6. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 6 Why is SoftwareValuable?
  7. 7. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 ! • Functionality ! ! ! • Malleability 7 The Two Values of Software
  8. 8. Red Green www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 8 Red Green Refactor
  9. 9. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 9
  10. 10. www.renaissancesoftware.net james@renaissancesoftware.net Copyright ©2008-2013 James W. Grenning All Rights Reserved. For use by training attendees. The End 10 Become an expert in your craft so you can advise your boss My Boss won’t let me
  11. 11. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Design for Maintenance • Systems evolve, the design is NEVER done. • Automated tests make evolution safer. ! • Key technical practices for evolving design – Test Driven development – Refactoring – Modularity, Loose Coupling, High Cohesion
 (OO Design) 11
  12. 12. Donald Knuth Says 12 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. Let us change our traditional attitude to the construction of programs. Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.
  13. 13. Martin Fowler Says 13 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. Any fool can write code that the compiler understands, but it takes real skill to write code other programmers can understand. From “Refactoring - Improving the Design of Existing Code
  14. 14. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Three Critical Skills 14 Recognize what is wrong and fix it!
  15. 15. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 ! ! SOLID 15
  16. 16. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Spaghetti Slide 16
  17. 17. • Once a design problem is identified, you must envision a better solution • Look to apply the design principles – SOLID – DRY - Don’t Repeat Yourself –from The Pragmatic Programmer – Principle of Least Knowledge. – Separation of Concerns (SoC). Refactoring www.renaissancesoftware.net james@renaissancesoftware.net Copyright © 2008-2013 James W. Grenning All Rights Reserved. For use by training attendees. Envisioning 17
  18. 18. Refactoring www.renaissancesoftware.net james@renaissancesoftware.net Copyright © 2008-2013 James W. Grenning All Rights Reserved. For use by training attendees. 18
  19. 19. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 SOLID Design Principles 19
  20. 20. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 SOLID Design Principles Single Responsibility Principle Open/Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle 20
  21. 21. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Home Automation System Light Scheduling Requirements • The light scheduler maintains a schedule for lights that can be turned on or off. Multiple schedules per light are supported for each light. • A light can be scheduled to turn on. • A light can be scheduled to turn off. • 32 lights can be addressed by their integer ID. • It must support 128 separate scheduled events • Schedules can be established by – specific day of the week (M Tu W Th F Sa Su), or everyday. • Lights can also be controlled though a UI on a front panel, iPad, iPhone, Android device, or web enabled device. 21
  22. 22. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 22
  23. 23. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Spaghetti Slide 23
  24. 24. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Single Responsibility Principle Bob Martin [AGILE] • a.k.a. Cohesion ! • A module should do one thing and do it well. • A module should have a single reason to change. ! • Test: a module can be described in 25 words or less. 24
  25. 25. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 25
  26. 26. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 A Module with Collaborators • Every minute, the RTOS wakes up the Light Scheduler. • If it is time for one of the lights to be controlled, the LightController is told to turn on/off the light. 26 Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler +ScheduleTurnOn() +RemoveSchedule() +WakeUp() Light Controller + On(id) + Off(id) Hardware RTOS <<anonymous callback>> Admin Console
  27. 27. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 27
  28. 28. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Open/Closed Principle • A module is open for extension, and closed for modification. • A design adheres to the open closed principle when it accommodates a certain kinds of changes without having to change existing code. • Changes just drop in. ! • Say “X is open for extension for new kinds of Ys, but closed for modification” 28 Thanks: Bertrand Meyers
  29. 29. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 OCP Applied LightScheduler is open for extension for new kinds of LightControllers and TimeServices. ! It is closed for modification for those extensions. 29 <<interface>> Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler + ScheduleTurnOn() + RemoveSchedule() +WakeUp() <<interface>> Light Controller + On(id) + Off(id) X10 Light Controller Acme Time Service Admin Console Model 42 Light Controller Linux Time Service <<implements>> <<implements>>
  30. 30. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 30
  31. 31. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Liskov Substitution Principle • Modules with the same interface can be substituted without the client knowing the difference. – Modules must meet the contract of the client and interface. – Preconditions cannot be strengthened in a server. – Postconditions cannot be weakened in a server. 31 Thanks: Barbara Liskov
  32. 32. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 32 © James Barrante. This file is licensed under the Creative Commons Attribution 3.0 Unported license.
  33. 33. OS Abstraction typedef struct ThreadStruct * Thread; typedef void * (*ThreadEntryFunction)(void *); ! Thread Thread_Create(ThreadEntryFunction f, void * parameter); void Thread_Start(Thread); void Thread_Destroy(Thread); void Thread_Exit(void *); void Thread_Join(Thread, void **result); void * Thread_Result(Thread); 33 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees.
  34. 34. OS Abstraction is Not Working //Snip from some product code ! Thread thread = Thread_Create(threadEntry, 0); ! #if POSIX_OS //POSIX starts thread on create #else //AcmeOS does not start thread on create Thread_Start(thread); #endif 34 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees.
  35. 35. OCP/LSP Designs Don’t Burden the Client //Snip from some product code ! Thread thread = Thread_Create(threadEntry, 0); Thread_Start(thread); 35 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees.
  36. 36. POSIX Version Delays Thread Creation typedef struct ThreadStruct { ThreadEntryFunction entry; void * parameter; pthread_t pthread; BOOL started; ! } ThreadStruct; ! Thread Thread_Create(ThreadEntryFunction f, void * parameter) { Thread self = calloc(1, sizeof(ThreadStruct)); self->entry = f; self->parameter = parameter; self->started = FALSE;; return self; } ! void Thread_Start(Thread self) { self->started = TRUE; pthread_create(&self->pthread, NULL, self->entry, self->parameter); } 36 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees.
  37. 37. Acme Does Not Need To Delay Create typedef struct ThreadStruct { AcmeThreadStruct acmeThread; } ThreadStruct; ! Thread Thread_Create(ThreadEntryFunction entry, void * parameter) { Thread self = calloc(1, sizeof(ThreadStruct)); AcmeThread_create(&self->acmeThread, entry, parameter, 5, 1000); return self; } ! void Thread_Start(Thread self) { AcmeThread_start(&self->acmeThread); } 37 ACCU 2014 www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees.
  38. 38. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Interface Segregation Principle • Don’t depend on fat interfaces. • Don’t depend on interfaces that have methods you don’t care about. • Tailor interfaces to client need. • Split fat interfaces. 38 Thanks: Robert Martin
  39. 39. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Light Scheduler Design • The TimeService limits the knowledge of the RTOS ! • Adapters are a form of Interface Segregations 39 <<interface>> Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler + AddTurnOn() + RemoveSchedule() +WakeUp() <<interface>> Light Controller + On(id) + Off(id) Model 42 Hardware RTOS <<anonymous callback>> Model 42 Light Controller RTOS Time Service <<implements>> <<implements>> Admin Console
  40. 40. Third Party Code Your Code Your Code Your Code Third Party Code Your Code Your Code Your Code www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Manage Third Party Dependenices 40 Your Tailored Service Interface Your Code Your Code Your Code Third Party Code Your adaptor
  41. 41. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Dependency Inversion Principle • Invert dependencies from high level modules to low level details. • Break problem dependencies by inserting an abstraction. – High level detail depends on an interface – Low level code depends on the interface – Interface depends on neither – Dependency cycle • a.k.a. Depend on Abstractions 41 Thanks: Robert Martin
  42. 42. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Un-Managed Dependencies • Transitive dependencies make the highest level of this design depend on the lowest level details. ! • Use DIP to break the transitive dependency chain. 42 Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler +ScheduleTurnOn() +RemoveSchedule() +WakeUp() Light Controller + On(id) + Off(id) Hardware RTOS <<anonymous callback>> Admin Console
  43. 43. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Invert Dependencies with Interfaces 43 <<interface>> Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler + ScheduleTurnOn() + RemoveSchedule() +WakeUp() <<interface>> Light Controller + On(id) + Off(id) Model 42 Hardware RTOS <<anonymous callback>> Model 42 Light Controller RTOS Time Service <<implements>> <<implements>> Admin Console
  44. 44. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Unmanaged Dependencies Lead to Manual Testing 44 The Net Core Software
  45. 45. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Substitutability Supports Testing 45 <<interface>> Time Service + GetTime() + SetPeriodicAlarm() Light Scheduler Test Light Scheduler + ScheduleTurnOn() + RemoveSchedule() +wakeUp() <<interface>> Light Controller + On(id) + Off(id) Light Controller Spy Fake Time Service <<implements>> <<implements>>
  46. 46. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Interfaces in C • Containing just what is needed to interact with the module – Function declarations – Constants needed for interacting with the module – struct forward declaration ! • Things not in the interface header file – Data structure member definitions – Data definitions – Constants needed in the implementation 46
  47. 47. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Rules of Simple Design In Priority Order! 1. Passes all tests 2. No duplication 3. Expresses intent 4. Fewest classes and methods (no extra stuff)* 47 Kent Beck [XP, TDD]
  48. 48. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 *Fewest Classes and Methods that Move You Closer to A Workable Architecture 48
  49. 49. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Architectural Vision • Have an idea where you are going. • Build slices of functionality that lets you try the architecture. • Don’t build architecture first, get features working and refactor to a great architecture. • Keep architectural view high level. 49
  50. 50. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Architectural Vision The Big Picture • Have a big picture in the developers’ minds. • The vision shows – the major boundaries – the areas of concern – the interfaces • Likely fractal in nature 50
  51. 51. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 SOLID and Testable C 51
  52. 52. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Different Design Models in C 52 Model Purpose Single-instance ! Abstract Data Type Encapsulates a module’s internal state when only a single instance of the module is needed Multiple-instance ! Abstract Data Type Encapsulates a module’s internal state and allows multiple instances of the module’s data Dynamic interface Allows a module’s interface functions to be assigned at runtime Per-type dynamic Interface Allows multiple types of modules with the same interface to have unique interface functions Barbara Liskov, Programming with abstract data types. Proceedings of the ACM SIGPLAN Symposium on Very High Level Languages, 1974.
  53. 53. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Single Instance Abstract Data Type ! 53 #ifndef D_LightScheduler_H #define D_LightScheduler_H ! #include "TimeService.h" ! enum Day { NONE=-1, EVERYDAY=10, WEEKDAY, WEEKEND, SUNDAY=1, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }; ! typedef enum Day Day; ! void LightScheduler_Create(); void LightScheduler_Destroy(); void LightScheduler_ScheduleTurnOn(int id, Day day, int minute); void LightScheduler_ScheduleTurnOff(int id, Day day, int minute); void LightScheduler_ScheduleRemove(int id, Day day, int minute); void LightScheduler_Wakeup(Time*); ! #endif // D_LightScheduler_H Data hidden in C file using file scope
  54. 54. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Multiple Instance Abstract Data Type Clients Only Interact Through the Interface 54 #ifndef D_CircularBuffer_H #define D_CircularBuffer_H ! typedef struct CircularBuffer CircularBuffer; ! CircularBuffer * CircularBuffer_Create(int capacity); void CircularBuffer_Destroy(CircularBuffer); int CircularBuffer_IsEmpty(CircularBuffer); int CircularBuffer_IsFull(CircularBuffer); int CircularBuffer_Put(CircularBuffer, int); int CircularBuffer_Get(CircularBuffer); int CircularBuffer_Capacity(CircularBuffer); #endif // D_CircularBuffer_H instance passed in Public name, hidden internals instance returned
  55. 55. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Multiple Instance ADT - .c File Structure Fields are Private 55 #include "CircularBuffer.h" #include "Utils.h" #include <stdlib.h> #include <string.h> ! typedef struct CircularBuffer { int count; int index; int outdex; int capacity; int * values; } CircularBuffer; !
  56. 56. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Multiple Instance ADT - .c File Well Defined Initialization and Cleanup 56 CircularBuffer * CircularBuffer_Create(int capacity) { CircularBuffer * self = calloc(capacity, sizeof(CircularBuffer)); self->capacity = capacity; self->values = calloc(capacity + 1, sizeof(int)); self->values[capacity] = BUFFER_GUARD; return self; } ! void CircularBuffer_Destroy(CircularBuffer * self) { free(self->values); free(self); }
  57. 57. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Simple Dynamic Implementation 57 #ifndef D_RandomMinuteGenerator_H #define D_RandomMinuteGenerator_H ! void RandomMinuteGenerator_Create(int bound); extern int (*RandomMinuteGenerator_Get)(); ! #endif // D_RandomMinuteGenerator_H function pointer interface
  58. 58. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Inverting a Dependency with a Function Pointer 58 LightScheduler Random Minute Get int (*RandomMinute_Get)() <<implements>> Random Minute Get LightScheduler
  59. 59. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 #if Abuse 59 void LightController_TurnOn(int id) { LightDriver driver = lightDrivers[id]; if (NULL == driver) return; ! #if X10_LIGHTS X10LightDriver_TurnOn(driver); #elif ACME_LIGHTS AcmeWirelessLightDriver_TurnOn(driver); #elif MEMORY_MAPPED_LIGHTS MemMappedLightDriver_TurnOn(driver); #elif TESTING LightDriverSpy_TurnOn(driver); #endif } Similar #if statements litter the code. This does not look too DRY
  60. 60. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 switch case Abuse 60 void LightController_TurnOn(int id) { LightDriver driver = lightDrivers[id]; if (NULL == driver) return; ! switch (driver->type) { case X10: X10LightDriver_TurnOn(driver); break; case AcmeWireless: AcmeWirelessLightDriver_TurnOn(driver); break; case MemoryMapped: MemMappedLightDriver_TurnOn(driver); break; case TestLightDriver: LightDriverSpy_TurnOn(driver); break; default: /* now what? */ break; } } Similar switch cases litter the code when switching on type
  61. 61. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 LightController depends on Each Specific LightDriver 61 LightScheduler LightController + TurnOn() + TurnOff() <<interface>> LightController X10 LightDriver Acme Wireless LightDriver Memory Mapped LightDriver <<implements>> LightDriver Spy
  62. 62. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 LightController Depends on the LightDriver Interface 62 LightScheduler LightController + TurnOn() + TurnOff() <<interface>> LightController + TurnOn() + TurnOff() <<interface>> LightDriver X10 LightDriver Acme Wireless LightDriver Memory Mapped LightDriver <<implements>> LightDriver Spy <<implements>>
  63. 63. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 How Much Flexibility is Needed? • Support for one LightDriver at compile time? – use the linker • Support for one LightDriver type determined at runtime? – Use a function pointer interface • Support for multiple LightDriver types determined at runtime? – Use per-type dynamic interface 63
  64. 64. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 LightDriver.h 64 typedef struct LightDriverStruct * LightDriver; ! void LightDriver_Destroy(LightDriver); void LightDriver_TurnOn(LightDriver); void LightDriver_TurnOff(LightDriver); const char * LightDriver_GetType(LightDriver driver); int LightDriver_GetId(LightDriver driver); ! ! #include "LightDriverPrivate.h"
  65. 65. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 LightDriverPrivate.h 65 typedef struct LightDriverInterfaceStruct * LightDriverInterface; ! typedef struct LightDriverStruct { LightDriverInterface vtable; const char * type; int id; } LightDriverStruct; ! typedef struct LightDriverInterfaceStruct { void (*TurnOn)(LightDriver); void (*TurnOff)(LightDriver); void (*Destroy)(LightDriver); } LightDriverInterfaceStruct; function pointer table
  66. 66. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 X10LightDriver.h 66 #include "LightDriver.h" ! typedef struct X10LightDriverStruct * X10LightDriver; ! typedef enum X10_HouseCode { X10_A,X10_B,X10_C,X10_D,X10_E,X10_F, X10_G,X10_H,X10_I,X10_J,X10_K,X10_L, X10_M,X10_N,X10_O,X10_P } X10_HouseCode; ! LightDriver X10LightDriver_Create(int id, X10_HouseCode code, int unit);
  67. 67. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Extending LightDriver struct (X10LightDriver.c) 67 //snip... ! typedef struct X10LightDriverStruct { LightDriverStruct base; X10_HouseCode house; int unit; } X10LightDriverStruct; ! //snip... All LightDriver instances must start with the base struct
  68. 68. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Initializing the vtable (X10LightDriver.c) 68 static void turnOn(LightDriver super) { X10LightDriver self = (X10LightDriver)super; formatTurnOnMessage(self); sendMessage(self); } static void turnOff(LightDriver super) { X10LightDriver self = (X10LightDriver)super; formatTurnOffMessage(self); sendMessage(self); } static LightDriverInterfaceStruct interface = { turnOn, turnOff, destroy };
  69. 69. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Initializing a Driver (X10LightDriver.c) 69 static LightDriverInterfaceStruct interface = { turnOn, turnOff, destroy }; ! LightDriver X10LightDriver_Create(int id, X10_HouseCode house, int unit) { X10LightDriver self = calloc(1, sizeof(X10LightDriverStruct)); self->base.vtable = &interface; self->base.type = "X10"; /* snip */ return (LightDriver)self; } !
  70. 70. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Simple Version of LightDriver_TurnOn() 70 void LightDriver_TurnOn(LightDriver self) { if (self) self->vtable->TurnOn(self); } The call is a bit hard to look at, so it’s hidden in delegating function behind an API.
  71. 71. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 C99 struct Initialization 71 static LightDriverInterfaceStruct interface = { .Destroy = destroy, .TurnOn = turnOn, .TurnOff = turnOff, };
  72. 72. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Really Safe Version of LightDriver_TurnOn() 72 void LightDriver_TurnOn(LightDriver self) { if (self && self->vtable && self->vtable->TurnOn) self->vtable->TurnOn(self); } Combining safe function dispatch with C99 struct initialization means that not all drivers have to support all interface functions.
  73. 73. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 LightController uses the LightDriver ! ! ! ! ! • The switch case statement is gone! As well as all its duplicates. • Code reads top to bottom • Special cases are isolated 73 void LightController_TurnOn(int id) { if (isIdInBounds(id)) LightDriver_TurnOn(lightDrivers[id]); }
  74. 74. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Creating a Specific LightDriver Using it Generically 74 LightDriver lightDriver; ! lightDriver = X10LightDriver_Create(3, X10_A, 12); ! LightDriver_TurnOn(lightDriver); LightDriver_TurnOff(lightDriver); LightDriver_Destroy(lightDriver); Create parameters are customized for the specific driver type. It returns the abstract type Clients of the driver have no dependency on the concrete type
  75. 75. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Dynamic Interfaces are Very Convenient for Inserting Test Doubles ! ! ! 75 // From LightDriverSpy.c ! static LightDriverInterfaceStruct interface = { .Destroy = LightDriverSpy_Destroy .TurnOn = LightDriverSpy_TurnOn, .TurnOff = LightDriverSpy_TurnOff, };
  76. 76. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Production Code is Unaware of the Indirection ! ! ! ! ! • LightDriver_TurnOn() indirectly calls the spy 76 TEST(LightDriverSpy, On) { LightDriver lightDriverSpy = LightDriverSpy_Create(1); LightDriver_TurnOn(lightDriverSpy); LONGS_EQUAL(LIGHT_ON, LightDriverSpy_GetState(1)); }
  77. 77. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Function Pointer APIs • One module operates on another module through a function pointer table. • Allows a whole set of functions to be swapped with a single pointer change. • Good for large systems with component variations • Also good for updating or patching single components ! • Choose the simplest approach. Keep code readable. 77
  78. 78. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 Testability • The function pointer based APIs allow test doubles to be inserted at runtime. • Legacy code that has function pointer APIs can be easier to get into a test harness. – Fill the function pointers with NULLs – Run until crash to see which functions are accessed – Add stubs as runtime dependencies are discovered ! • All these design models employ programming to interfaces and encapsulation 78
  79. 79. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 C++ • The use of function pointers and function pointer tables does lead some to look at C++. • C++ has this capability built in. • Maybe you should look at C++. ! ! • Why are you still using C? – http://renaissancesoftware.net/papers/14-papers/51-stillusingc.html 79
  80. 80. www.wingman-sw.com james@wingman-sw.com Copyright © 2008-2014 James W. Grenning All Rights Reserved. For use by training attendees. ACCU 2014 80 Talk to me on Twitter @jwgrenning ! Connect with me on linkedin.com http://www.linkedin.com/in/jwgrenning Remind me how we met. ! http://www.wingman-sw.com http://blog.wingman-sw.com http:// www.jamesgrenning.com unpappd.com jwgrenning Ask me for the pragprog.com discount code

×