Improving code quality with loose coupling
Software design
• Code organization
• Goal:
• Reduce the cost of change
• Reduce stress
• Simple guidance for 90% of the cases
Coupling
• Rigidity
• Fragility
• Immobility
Dependency injection
• ?
Dependency injection
public class Salutation
{
private readonly IMessageWriter writer;
public Salutation(IMessageWriter writer)
{
this.writer = writer ?? throw new ArgumentNullException(nameof(writer));
}
public void Salute()
{
this.writer.Write("Hello DI!");
}
}
• “The key in making great and growable systems is much more to design how its modules
communicate rather than what their internal properties and behaviors should be.”
• “I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to
focus on the lesser idea.”
• “The big idea is “messaging””
Messaging
Sending object Receiving object
Message
public class Party
{
private readonly Equipment equipment;
public Party(Equipment equipment)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
}
public void OrganizeBy(Technician technician)
{
technician.SetupSpeakers(equipment);
technician.SetupMixer(equipment);
technician.SetupLighting(equipment);
}
}
public class Party
{
private readonly Equipment equipment;
public Party(Equipment equipment)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
}
public void OrganizeBy(ITechnician technician)
{
technician.SetupSpeakers(equipment);
technician.SetupMixer(equipment);
technician.SetupLighting(equipment);
}
}
public class Party
{
private readonly Equipment equipment;
public Party(Equipment equipment)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
}
public void OrganizeBy(Technician technician)
{
technician.Setup(equipment);
}
}
public class Party
{
private readonly Equipment equipment;
private readonly IEnumerable<Guest> guests;
public Party(Equipment equipment, IEnumerable<Guest> guests)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
this.guests = guests ?? throw new ArgumentNullException("guests");
}
public void OrganizeBy(Technician technician, DiscJockey discJockey, Chef chef)
{
technician.Setup(equipment);
discJockey.CreateSongListFor(guests);
chef.PrepareFoodFor(guests);
}
}
public class Party
{
private readonly Equipment equipment;
private readonly IEnumerable<Guest> guests;
public Party(Equipment equipment, IEnumerable<Guest> guests)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
this.guests = guests ?? throw new ArgumentNullException("guests");
}
public void OrganizeBy(Technician technician, DiscJockey discJockey, Chef chef)
{
technician.Organize(equipment);
discJockey.Organize(guests);
chef.Organize(guests);
}
}
public void OrganizeBy(IEnumerable<IOrganizer> organizers)
{
foreach(var organizer in organizers)
{
switch (organizer)
{
case Technician technician:
technician.Organize(equipment);
break;
case Chef chef:
chef.Organize(guests);
break;
case DiscJockey discJockey:
discJockey.Organize(guests);
break;
default:
throw new ArgumentException(
message: "organizer not recognized",
paramName: nameof(organizer));
}
}
}
public class Party
{
private readonly Equipment equipment;
private readonly IEnumerable<Guest> guests;
public Party(Equipment equipment, IEnumerable<Guest> guests)
{
this.equipment = equipment ?? throw new ArgumentNullException("equipment");
this.guests = guests ?? throw new ArgumentNullException("guests");
}
public Equipment Equipment { get { return equipment; } }
public IEnumerable<Guest> Guests { get { return guests; } }
public void OrganizeBy(IEnumerable<IOrganizer> organizers)
{
foreach(var organizer in organizers)
{
organizer.Organize(this);
}
}
}
public class Technician: IOrganizer
{
private void SetupSpeakers(Equipment equipment)
{
//Setup speakers logic
}
private void SetupMixer(Equipment equipment)
{
//Setup mixer logic
}
private void SetupLighting(Equipment equipment)
{
//Setup lighting logic
}
public void Organize(Party party)
{
SetupSpeakers(party.Equipment);
SetupMixer(party.Equipment);
SetupLighting(party.Equipment);
}
}
Role
• Anthropomorphicrepresentation of polymorphism
Role
• Objects are more players of their roles than instances of their
classes
• I care more about role that object is playing than the type that
object is!
public class Technician
{
public void SetupSpeakers(Equipment equipment)
{//Setup speakers logic}
public void SetupMixer(Equipment equipment)
{//Setup mixer logic}
public void SetupLighting(Equipment equipment)
{//Setup lighting logic}
}
public class DiscJockey
{
public void CreateSongListFor(IEnumerable<Guest> guests)
{//Create song list logic}
}
ROLE IS IN BETWEEN OBJECTS. IT’S IN THE MESSAGES.
Conclusion
• OOP system behaviour should be changed by object
composition (as much as possible)
• OOP system should be loosely coupled
• Concentrate on communication between objects, not the types
• Properly designed messages are the key for creating flexible
systems
• Use messages to discover roles
Questions
Thank you!

Improving code quality with loose coupling

  • 1.
    Improving code qualitywith loose coupling
  • 2.
    Software design • Codeorganization • Goal: • Reduce the cost of change • Reduce stress • Simple guidance for 90% of the cases
  • 3.
  • 5.
  • 6.
    Dependency injection public classSalutation { private readonly IMessageWriter writer; public Salutation(IMessageWriter writer) { this.writer = writer ?? throw new ArgumentNullException(nameof(writer)); } public void Salute() { this.writer.Write("Hello DI!"); } }
  • 10.
    • “The keyin making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.” • “I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea.” • “The big idea is “messaging””
  • 11.
  • 12.
    public class Party { privatereadonly Equipment equipment; public Party(Equipment equipment) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); } public void OrganizeBy(Technician technician) { technician.SetupSpeakers(equipment); technician.SetupMixer(equipment); technician.SetupLighting(equipment); } }
  • 13.
    public class Party { privatereadonly Equipment equipment; public Party(Equipment equipment) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); } public void OrganizeBy(ITechnician technician) { technician.SetupSpeakers(equipment); technician.SetupMixer(equipment); technician.SetupLighting(equipment); } }
  • 14.
    public class Party { privatereadonly Equipment equipment; public Party(Equipment equipment) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); } public void OrganizeBy(Technician technician) { technician.Setup(equipment); } }
  • 15.
    public class Party { privatereadonly Equipment equipment; private readonly IEnumerable<Guest> guests; public Party(Equipment equipment, IEnumerable<Guest> guests) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); this.guests = guests ?? throw new ArgumentNullException("guests"); } public void OrganizeBy(Technician technician, DiscJockey discJockey, Chef chef) { technician.Setup(equipment); discJockey.CreateSongListFor(guests); chef.PrepareFoodFor(guests); } }
  • 16.
    public class Party { privatereadonly Equipment equipment; private readonly IEnumerable<Guest> guests; public Party(Equipment equipment, IEnumerable<Guest> guests) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); this.guests = guests ?? throw new ArgumentNullException("guests"); } public void OrganizeBy(Technician technician, DiscJockey discJockey, Chef chef) { technician.Organize(equipment); discJockey.Organize(guests); chef.Organize(guests); } }
  • 17.
    public void OrganizeBy(IEnumerable<IOrganizer>organizers) { foreach(var organizer in organizers) { switch (organizer) { case Technician technician: technician.Organize(equipment); break; case Chef chef: chef.Organize(guests); break; case DiscJockey discJockey: discJockey.Organize(guests); break; default: throw new ArgumentException( message: "organizer not recognized", paramName: nameof(organizer)); } } }
  • 18.
    public class Party { privatereadonly Equipment equipment; private readonly IEnumerable<Guest> guests; public Party(Equipment equipment, IEnumerable<Guest> guests) { this.equipment = equipment ?? throw new ArgumentNullException("equipment"); this.guests = guests ?? throw new ArgumentNullException("guests"); } public Equipment Equipment { get { return equipment; } } public IEnumerable<Guest> Guests { get { return guests; } } public void OrganizeBy(IEnumerable<IOrganizer> organizers) { foreach(var organizer in organizers) { organizer.Organize(this); } } }
  • 19.
    public class Technician:IOrganizer { private void SetupSpeakers(Equipment equipment) { //Setup speakers logic } private void SetupMixer(Equipment equipment) { //Setup mixer logic } private void SetupLighting(Equipment equipment) { //Setup lighting logic } public void Organize(Party party) { SetupSpeakers(party.Equipment); SetupMixer(party.Equipment); SetupLighting(party.Equipment); } }
  • 20.
  • 21.
    Role • Objects aremore players of their roles than instances of their classes • I care more about role that object is playing than the type that object is!
  • 22.
    public class Technician { publicvoid SetupSpeakers(Equipment equipment) {//Setup speakers logic} public void SetupMixer(Equipment equipment) {//Setup mixer logic} public void SetupLighting(Equipment equipment) {//Setup lighting logic} } public class DiscJockey { public void CreateSongListFor(IEnumerable<Guest> guests) {//Create song list logic} }
  • 23.
    ROLE IS INBETWEEN OBJECTS. IT’S IN THE MESSAGES.
  • 24.
    Conclusion • OOP systembehaviour should be changed by object composition (as much as possible) • OOP system should be loosely coupled • Concentrate on communication between objects, not the types • Properly designed messages are the key for creating flexible systems • Use messages to discover roles
  • 25.
  • 26.