Data & Object Factory helps developers succeed with.NET Design Patterns through training, products, and a.NET Design Pattern and Practices community Login Join Now Products. Prepare for IBPS PO, IBPS Clerk, Bank PO, Bank Clerk exams, SSC CGL, CHSL, MTS & other SSC exams via Adda247 mock tests, video courses, e-books and more! Expedite your exam preparation with the best study material.
Table of Contents
Preface
Welcome to the first edition of A Primer on Design Patterns. Its my third book in the Primer series and I must say I amloving the experience. I hope you have an equally good time with this text. I’ve tried my best to keep it easy to read and crisp atthe same time.
This is my first text that expects a good grasp of programming before you attempt to read it. The reader is expectedto be a beginner level programmer in an object oriented language like Java or Python. The objective of the book is to introduce itsreader to the world of design patterns by working through some important ones. It is by no means an exaustive reference to all thedesign patterns out there.
Your questions, comments, criticism, encouragement and corrections are most welcome and you can e-mail me at rhlbatra[aht]hotmail[dot]com. I’ll try answering all on-topic mails and will try to include suggestions, errors and omissions in future editions.
Rahul Batra (22nd March 2016)
About the author
Rahul Batra was first introduced to programming during 1996 in GWBASIC, but he did not seriously foray into it till 2001 when hestarted learning C++. Along the way, there were dabblings in many other languages like Python, Ruby, Perl and Java. He hasworked in many domains like enterprise backup, ad-tech, financial softwares and analytics.
Rahul has been programming professionally since 2006 and currently lives and works in Gurgaon, India.
Acknowledgements
This book has been a challenge and it would not be in its present form without the support of family and friends. I would like toacknowledge my son Vedant for this - he has given me such joy, and such purpose in life that I will be forever grateful to him evenif he doesn’t know it yet. You are everything to me.
I am also eternally grateful to my parents who made many sacrifices so that I can have the best of education and resources. I owemy life’s work to them.
Introducing Design PatternsWhat are design patterns?
Experience is a great teacher. Suppose you follow this maxim and note down all the great ways you solve common problems that crop up in your day-to-day coding tasks. A decade into your programming life, you would have a neat set of solutions that fit elegantly as solutions to said problems. You have just created a set of design patterns for yourself.
It is not only easier, but also more efficient, to stand on the shoulders of giants, so to speak. Programmers have combined and collected design patterns over the decades, ready for you to consume. These solutions to everyday coding problems make your code not only elegant, extensible and readable.
History of design patterns
The first work to explicitly collect and present object oriented design patterns was a book called Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides in 1994. This book and the 23 patterns discussed therein became so popular that they are referred to as the Gang of Four (GoF) book and GoF patterns respectively.
Not all GoF patterns gained equal acceptance in the programming community. Some were used more than the others. New patterns have been created since the book was first published. However, quite a few of these patterns remain in widespread use today. We will study a subset of the most important design patterns in the chapters that follow.
The language choice
Since we are going to study object oriented design patterns, it is natural to choose a language that adheres to the OO paradigm. Dueto its popularity, I have chosen Java as one of the languages to demonstrate the principles of design patterns. However, in somecases, the verbosity of Java leads us away from the core explaination of the pattern and into the innards of language constructs. Insuch cases, I have decided to remove chunks of boilerplate code which do not illustrate the key points of the pattern beingdiscussed, while still keeping the code Java-like.
The implementation and usefullness of a design pattern varies wildly from language to language. So it would be good to compare thepatterns implementation in a contrasting language like Python whose dynamic nature and programming philosophy is quiteorthogonal to Java.
Pattern abuse
Knowing design patterns is not a substitute for programming taste. If you read this text, or any text on design patterns, as anapproach to how all code must be designed, you are likely to fall into the pattern abuse habit.
Since the GoF book came out 2 decades ago, there has been much discussion on patterns and they are now accepted as a good thing onbalance. But is has also frequently led to over-engineering of software by cramming as many design patterns as one can in the code.You must strive to avoid this trap by using design patterns judiciously and recognising them for what they are - good solutions tocommon design problems in certain but not all scenario’s.
Hey, that looks familiar!
If you are an experienced programmer, you would recognize a lot of design patterns as approaches you might have used in the past without formally attaching a name to it. This is a key point about design patterns - they are not arcane knowledge or a magic bullet, they are good solutions. They also are akin to a programming vocabulary, whereby you can describe your approach using a pattern name than by specifying it its entirety.
Strategy Pattern
In this chapter we take an example of a batch task processing system - a system where jobs or tasks are put in a queue and executedone by one. Multiple task runners may be instantiated and they pick up the next task to be completed from a queue. Selecting thenext task can be unique to each task runner. They may use a first come, first serve algorithm to pick up the task. They may also usecomplex algorithms like shortest task first or priority based tasks.
Inheritance might not be your best friend
If you emphasize on inheritance in your object oriented design, you might design an inheritance hierarchy for this as below.
If you have many such classes, you have spread your
getNextTask() algorithm over multiple generations of classes. Frequent changes to these make the patching cumbersome and the design brittle. What if you want to create two different ShortestJobRunner ’s - one that can handle task pre-emption and one that cannot. We should be looking for an alternative rather than introduce another hierarchy stemming from an abstract ShortestJobRunner class.
Composition as an alternative to inheritance
What if there was a single
TaskRunner class which contained within it an object of a type say TaskAlgorithm . This member could contain whatever algorithm we choose for getting the next task. In essence this type would be an interface which will be implemented by each of the concrete algorithm implementations.
Virtual Smart Card Drivers Drivers Download. In our share libs contains the list of Virtual Smart Card Drivers drivers available for download. To download the proper driver by vender name. If not found in our garage driver you need, please contact us, we will help you in. Feb 15, 2010 Once you have attached the smart card to the virtual machine, and let Windows 7 load the drivers for the smart card, you can switch back to integrated mode and everything will work fine. The other approach is to locate and load the drivers for your smart card manually (this will work with Windows Virtual PC or Hyper-V). Oct 25, 2009 Figure 2: Smart Card Sharing is disabled in Integration Features enabled mode. USB Smart card readers can be exclusively assigned to a Virtual machine in IF disabled mode only. Smart cards drivers need to be installed in Windows 7 as well as the Virtual machine to get smart cards working in shared mode. DameWare Development Virtual Smart Card Drivers Drivers Download. In our share libs contains the list of DameWare Development Virtual Smart Card Drivers drivers available for download. Update PC Drivers Automatically Identify & Fix Unknown Devices Designed for Windows 8, 7, Vista, XP. All of the information from the Internet and through our. Virtual smart card driver windows 7.
What is the volatile part of your code?
Think over what we acheived by making the
ITaskAlgorithm interface and keeping the algorithms separate from the main TaskRunner class. One of the key themes of design patterns is to identify what part of your code changes often, so that we can work around this variability without a redesign of the other parts. Here are take our bunch of algorithms (or strategies to use the pattern jargon), and encapsulate them as a variable concept.
Implementing the strategy pattern
We have already created the
ITaskAlgorithm interface and fleshed out some of the algorithm implementations (also known as concrete strategies). Let us now construct the single level TaskRunner class.
You can now use the strategy setter to dynamically decide which algorithm should be chosen. Since we are free to create new algorithm implementations as long as they implement
ITaskAlgorithm , we have effectively coded to an interface rather than any specific implementation.
Our strategy pattern implementation migrated to Python
Let’s see if we can write a direct translation of our above implementation in Python. We will choose a simple class to serve as thereplacement of our
ITaskAlgorithm interface.
Now we implement our various algorithm strategies as subclasses of
ITaskAlgorithm .
Our
TaskRunner class and the main script can then be written in Python as:
While we have achieved our purpose in Python too, isn’t this a long way to go about it? Can we not use Python’s features to achieve the same flexibility of the strategy pattern. After all, the way to get to a solution in Java might not be the best way to get to the same solution in Python. Turns out, there is a simpler way in Python.
We have removed the concept of the top level interface completely. While we do lose adherence to a contract of sorts, I believe we gain a shorter, cleaner solution which to me is a net-win. It is possible to do this in Python because of its feature of first class functions. It means Python allows you to pass functions as arguments and even return them as values from other functions. Notice how the strategies are effectively functions that can be passed as an argument to the
__init__ of the implementaion class.
Decorator Pattern
Consider a Find dialog in a text editor. While the basic find operation is pretty simple, there are some options (usually) available to do more advancedsearching. We see checkboxes whether or not the search pattern is a regular expression, whether we want to search in the current file or a directory andeven an option to enter the replacement text. Let us see if the decorator pattern can help us here.
Permutations and combinations
In our text editor, the
Find dialog box is a class. When we decide to support regular expression searching, we write a subclass called FindWithRegEx .
We can write another subclass of
FindDialog which handles the replace functionality. And another to search in a directory. But what if we want to have areplace functionality with regular expressions? Do we extend FindWithRegEx or the replace class? And what happens when we start dealing with the replacefunctionality in a directory supporting regular expressions? The permutations and combinations start getting out of control.
Decorating the same entity
The decorator pattern is all about keeping the same entity - the FindDialog in our case - and decorating it with additional features orresponsibilities at runtime. How do we go about keeping the same entity - by implementing the same interface for both the simple find dialog and all it’sdecorations.
Now we start constructing our decorations. Our goal is to provide such an outline for decorations that it not only adheres to the
FindDialog interface, itshould also provide a barebones structure for further decorator writers. An abstract class which implements the FindDialog interface would make a goodblueprint for concrete decorators. This class, being abstract, can bind decorator writers to implement certain methods which all decorators should share.
Using our decorators
We will now create a simple test program to see whether our decoration functionality is working.
The interesting line to note here is the construction of the
findDialog object. This object is a SimpleFind decorated with our FindWithRegEx decorator.Both the former class and the decorator share the same parent type - the FindDialog interface. When the displayHelp method is called on this object, theFindWithRegEx methos is called which calls its super class method first and then adds its own decoration. The output then is, expectedly, both the lines.
Note that there is no limit to the number of decorations you can apply. Nor are you limited by the order you apply them, because of the super parent interfaceyou created in the beginning.
The decorator stripped to its core
Before we look at the Python implementation of the decorator pattern, let us try to identify the true essence of the decoratorpattern. The entire pattern is about providing multiple optional behaviours of a kind of object, and in doing so, the decoratedobject must adhere to the contract of the original object. Put another way, the caller must not know whether it is dealing with theoriginal object or the decorated one.
Let us now try to build this in Python with minimalism in mind.
The above code works as expected by we are really playing freely here. Our assumption is that both the classes contain the
display_help method. What if we wanted to bring some type checking into play here, ensuring at a minimum that both the classesdo indeed have such a method?
Enter the Abstract Base Class of Python
We can use the module
abc to define abstract base classes in Python, which would serve our need to enforce certain contracts byemulating interface-like behavior. Have a look at the code below and notice the FindDialog class being defined as an abstract baseclass.
Since we have defined
FindDialog as an abstract class containing an astract method display_help() , we cannot instantiate theclass itself. Writing something like below will throw up an error.
We can see how we have implemented our contract and applied our decorators to the final object
f . If our decorator was not asubclass of FindDialog we would have gotten a runtime TypeError which we raised. If our decorator was a subclass of FindDialog but did not implement the abstract method display_help() , we would have gotten another error.
Factory PatternThe Limitations of Object Construction
Creation of objects using plain old constructors and the new operator is fairly constricting in many situations. Suppose youare creating an information management application which supports different note types - plain note, rich note, outline note etc. If all these notes extend from a super class Note, using new on this super class cannot return its subtype note i.e. itcannot return a specific type of note we desire.
So while you can do,
Note n = new Note();
Note m = new RichNote();
You cannot perform something like:
RichNote n = new Note('Rich');
A constructor invoked through new cannot specify a return type at all, let alone a different return type. Clearly our need tocreate different but related object types cannot be solved by constructors in an elegant manner.
Enter the Simple Factory
What if we had a method which could return objects like a constructor but not suffer from its limitations? We know somewhere downthe line we have to make a call to it using new, but can we give a uniform cover of sorts to this problem of related notetypes. This is where we encounter a factory, which is a plain old class containing a method returning our desiredsubtype note.
The
createNote() method serves as our object creator, returning the note type we desire. This is possible because the methodreturns a type Note which would serve as an ancestor to all the different note types. Since it is evident that it does not makesense to create instances of Note (what kind of note is a clearer alternative), we can go ahead and make it an abstract class.
Factory Method
The original Gang of Four book did not define the Factory pattern as shown above. Which is why programmers differentiate the twoby calling what we implemented in the previous section as a Simple Factory and the GoF way as the Factory Method pattern.
The primary difference between them is that in the latter, we specify our factory as an abstract class. It is then left forrealization by other implementers who have to make concrete factories based upon your original blueprint. This brings in anotherdimension of flexibility to the creation of objects using factories.
Software, as evidenced by modern trends, tends to suffer from featuritis - adding a slew of features in every release. And alas,our simple note taking application has also fallen prey to this. The powers that be want to see it support multimedia notes whichare treated very differently than textual notes. Besides the fact that they are created and have a title, they share little elsewith our previous note styles. The Factory Method pattern can help us out here.
The various note types can now extend
Note and yet be created by a specialized form of NoteFactory . As time goes on, and yetnewer demands are made on the categories of notes supported, we can create newer specializations of NoteFactory .
Implementing the simple factory in Python
A simple translation of the factory to Python is straightforward. We will attempt this line by line picking up the inspiration fromour Java implementation.
Pretty simple, huh? No surprises waiting for us; perhaps not the most elegant way to go about designing your Python codebase but that is another matter. What if we go back and revisit our assumption that the object construction process cannot return a different type. Does Python allow something like this? Well, we don’t really have a formal constructor but the object creation does involve calling the
__init__ function. Let us try specifying a return type there - have a look at the code below.
If we attempt to run this, Python throws back an error, a
TypeError to be precise.
Clearly this is not the way to go about things. Wading through the Python documentation, we come across a similar method called
__new__ . This allows us to return some other class’ object. Let’s try this method in our code sample.
Well, this looks promising. The
nf object turned out to be of type RichNote , completing our note factory concept.
Observer Pattern
The formal definition of the pattern is to define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
The purpose of the observer pattern is to allow the originator of an event to notify its observer(s) without the latter needing tocontinously perform any polling mechanism. Consider the analogy of Twitter - a person tweets i.e. generates an event, and his orher followers get notified of the said tweet. The followers can be thought of as observers of the tweet generation event.
Where does the Observer pattern fit?
Whenever you think of a subscription like system, consider whether your design can make use of the observer pattern. A blog enginefor example, would let fellow bloggers follow another. Whenever the blogger in question posts an entry, the very act ofpublishing can trigger notifications to his/her subscribers.
We are not limited to the concept of subscription in the context of people. Imagine a very sensitive table in a database. Certainsystems need to be notified whenever there is a new entry in the table - like a ledger entry needs to notify compliance systemsetc. in the finance world. This can also be a scenario where the observer pattern may come in handy.
Implementing the Observer pattern in Python
For our Python implementation we are going to use the blog entry subscription example. A user would register (initialize) a blogand subsequently add posts to it. Readers can subscribe to the blog and get notified whever the author puts up a new post.
Take careful note of the methods in the two classes described below. The
Blog class has methods to add new subscribers, add newposts and notify the subscribers when a new post is added. What is clearly missing here is the ability to remove a usersubscription. However, that is a matter of simply modifying the self.subscribers list and is left out for brevity. It adds littleto our purpose of seeing the observer pattern in action.
The heart of the pattern lies in the
notify_subscribers call and definition. The method goes over the list of subscribers andcalls them as functions, even though we know that these are Reader objects1.
Now note the methods of the
Reader class. Besides the usual __init__ , we have __call__ which is a special method that getsinvoked automatically when an object instance is treated like a function and called. Essentially, if o is an instance andit is called like o(params) , it will be treated like o.__call__(params) . This feature offered by Python makes ourimplementation particularly clean and easy to understand.
Complex systems as computer simulations
If you look carefully at the source code of the Python implementation, you would notice some very specifically chosen author,reader and blog post names. These are all related to the Simula programming language from the 1960s which was the first trueobject oriented language. It introduced to the world the concept of a class and thus is extremely relevant to a text ondesign patterns. Kirsten Nygaard was researching simulating complex systems when he felt the need to create an extension ofAlgol for this purpose. He was joined by Ole-Johan Dahl and they gave us Simula-67 introducing objects and classes. Robert Bemerwas the Director of systems programming at UNIVAC Corporation and was responsible for helping Nygaard and Dahl port Simula tothe UNIVAC 1107.
Java’s take on the Observer
If you read the Python implementation carefully, you would notice that except for the
notify_subscribers method and the languagespecific __call__ , there is not much to the code that cannot be directly translated to Java. And we can easily get around theaforementioned contructs by asking all observers to adhere to an interface.
Notice how we added another observer class -
Homepage adhering to the same contract. The idea being once the writer pens a newentry, the homepage should get notified and updated too.
The built-in Observer implementation in Java
Ever since Java came out in the mid-90s, it has shipped with an
Observable class and an Observer interface. While there are manyfiner points of using these, I’d best leave that to the Java standard library documentation. But here are some of the highlights tohelp you get started.
Notice I mentioned the
Observable class - to build your own subjects (the objects to be observed), you need to create asubclass of it. If you are a Java programmer you would notice that this means your subject class cannot extend any other superclasssince Java will not allow you to have multiple parent classes. The Observer is mercifully a standard interface which leaves you toimplement your own update() method.
Extending the
Observable class gives you a lot of pre-built functionality. You already get methods like addObserver() ,deleteObserver() and notifyObservers() which takes away the pain of manually writing observer management. Whether you wish touse this of roll your own Observer pattern implementation is your call.
Template Method Pattern
The template method pattern is one of those patterns that seem so obvious that many question whether it should indeed be called apattern at all. If you know what inheritance and abstract classes and methods are and what they are used for, you pretty much knowabout the template method pattern.
It is, however, a part of the original Gang of Four patterns and you don’t want to be looking clueless when somebody starts talkingabout finalizing a template method. Another reason to study it would be to understand where the pattern should not be fitted. Solet’s begin by finding a situation to put this pattern to use.
T’was a time of email clients
Long before checking emails through a web browser became all the rage, you had to install a mail client on your computer and gofrom there. And if you happen to be programming one, a big hurdle for you would be getting the mail composition bit right. You seeemail comes in two flavors - plaintext and HTML, and creating them requires different invisible headers which are important if youare creating an email client.
What is the process of sending an email? For our illustrative purposes only, let’s suppose it is as below.
In this recipe of 5 steps, only step number 2 is different for sending our different email formats. The rest of the steps prettymuch remain the same. The header field Content-Type for plaintext emails is text/plain whereas it is text/html for HTMLformatted mails.
The template method in Java
Let us suppose we are making our very own mail sending program, and that too in Java. We stick to our tried and trusted objectoriented design methodology and make a
Mail class which is the parent class of PlainTextMail and HTMLMail . Each of the stepsin our mail sending process becomes a method of the mailing classes.
Nothing too unexpected there. The abstract class defines and implements most of the methods and the concrete classes simplyoverrides the method which is specialized, saving us a ton of duplicate code. Now we piece together another method which chainsthe above methods up in sequence so that we can wrap the mail sending process in a single step.
And where should we put in this method - the abstract class, of course. The steps for sending the mail remain the same no matterwhat is the content of the mail. We have just implemented our template method, which fixes the steps for an algorithm orprocedure. If we declare this method as
final , we ensure that nobody can modify the mail sending procedure.
Hooks
What if a particular step of the algorithm can be implemented differently or even kept optional in the concrete implementations? Tocater to this need, we use hooks which are given a default implementation in the base class but the subclasses are free tooverride it. Let’s see if we can take one of our methods and make it a hook.
One of the least well-known features of email is the Reply-To field. The email format has provisions that when you hit reply toa mail, it can go to a different email address than the one that sent the mail. Let’s suppose that we want out rich interface emailcomposer (the one that makes HTML emails) to have the option to set this field.
If the abstract class
Mail sets the value of the field same as the from field, it provides a nice default implementation. Wewill hook on a new implementation of it in the HTMLMail class so that we can set a different address.
The template method in Python
Porting our template method logic to Python is fairly straightforward. To keep things really simple and minimal, let’s look at abarebones implementation of the concept.
Note how we have written the abstract method by simply raising an exception. This forces the implementor to write a concrete
apply_headers() in the derived classes.
While this is a nice, simple and clean implementation - it does suffer from a tiny flaw. We can instatiate
Mail when we reallydon’t want to give the option to create a Mail object with an undefined format. So we take the help of our trusted Abstract BaseClass of Python and specify apply_headers() as an abstract method.
Singleton Pattern
Much has been said and written about the singleton pattern. Some good and some not so complimentary. While we will discuss thereason behind the criticism the pattern has drawn in recent years, let us first focus on understanding the pattern itself.
A singleton refers to a class which can be instantiated once and only once. Every time we demand a new instance of the class,it returns the same object. Right off the bat, we can probably see where such an object instantiation strategy might come in handy- database connections, logging etc.
Implementing singletons in Java
To control how many instances of a particular class can be created, it is obvious that we would have to tinker around with theprocess of object creation and its primary player - the contructor. The constructor will always return a new object when it isauto invoked using
new , and so we must write find means to hide it.
This hiding of the constructor can be achieved by the judicious use of access modifiers - marking the constructor as private.This is reasonably simple, but we must provide another way to get an instance. Also we must control the number of instances that canbe created from this instantiation method.
We just introduced our
getDBConnection method which will serve in place of the constructor to get new DatabaseConnection objects. Here we must apply the logic to instantiate the class once and return the same instantiation on repeated calls. Anotherthing that we have to bear in mind that the getDBConnection method must be a static method. It must be callable without aninstance of its class, since its very purpose is to return an instance.
We use a static variable to hold the unique instance of our class. Thus before we create an instance, we check whether we alreadyhave another one and if so, return that. For simple scenario’s, these steps ensure that you will get one and only one instance ofthe database connection.
Complications in a multi-threaded environment
Dealing with multithreaded code is challenging, but even more so when we introduce singletons in the mix. Consider what would happenif there were two threads operating on the
getDBConnection() method.
There may arise a situation where thread 1 has performed the
dbConn null check and proceeded to start the object creationprocess. At this very moment, thread 2 could be checking the condition also and did not find the instantiated dbConn objectbecause thread 1 has not finished object creation. Thus thread 2 would also start its call to the constructor breaking our singletonpattern implementation.
Java provides us with the
synchronized keyword - a way to ensure thread safety. By simply adding this in the declaration ofgetDBConnection() we ensure that no two threads can execute this method at the same time.
The trouble with this simple fix is performance. Consider the fact that our complicated multithreading issue only arises if boththreads try for a concurrent
getDBConnection before anything else has created a unique instance. If there already existed adbConn object, it would not matter how many threads tried to run getDBConnection at the same time. But our fix added theperformance penalty of using the synchronized feature every time a database connection is requested.
Another simple fix is to eagerly create a singleton instance and let
getDBConnection() always return it.
While this approach is also pretty elegant in its simplicity, it also means that you will always have an instance of
DatabaseConnection . The instance will be eagerly created at class load time, whether or not someone calls getDBConnection() .
Implementing singletons in Python
The Python community is not very dogmatic when it comes to implementing design patterns. In fact, many Pythonistas believe that thestudy and implementation of design patterns is better suited to languages like Java and C++ and should be used in Python sparingly.
The pythonic way to implement a singleton in Python is to simply mimic it using a module level variable. Any variable defined inthe main body of a module, be it a simple variable or an object instantiation, will be executed exactly once at import time.Though there is nothing that stops the importer from reassigning the (singleton) variable to something else entirely, the Pythoncommunity takes the view that we are all consenting adults here. If someone wishes to reassign the variable, let them. Can’t say Idisagree with this pragmatic approach.
Let’s implement this as simply as possible. We create our
DBConnection class as below and instantiate it in the same module.
Effectively
dbconn has become a module level variable and thus a singleton for our purpose. Let us import this into our script.
The class is instantiated and assigned to
dbconn the moment our script processes the import statement in the very first line.Thus our output is in the sequence given below.
Other than this simple but useful technique, there are some other tangential ways to mimic singletons in Python. You have to fiddlewith the
__new__() method but I don’t particularly recommend it. There is also a related pattern called Borg which servesalmost the same purpose as a singleton by implementing shared state.
The problem with Singletons
If you really think about singletons, we essentially use them as global state holding variables which are shared across theapplication instance. Whenever you see the word global variable or shared state, take a good hard look at whether you do need adesign which promotes these. In a lot of cases, instead of rigid rules of instance creation, we should trust the programmers usingour code to do the right thing. While this does seem scary at first, more often than not, we overemphasize singletons.
Consider database connections - while it is not a great idea to flood the database server with incoming connection requests, it isequally bad to let a glitch in one part of the code affect another. What happens when say a part of code locks up the database witha long running transaction? Should everyone else wait their turn since we can only have a single database connection?
Another principle that singletons violate is single responsibility. Instead of just being good at their own purpose, they alsominutely cover their own creation. So now they have to be good at two things, one more than the ideal situation. All in all, theremay be cases you’d want to use singletons, just be sure you really need them.
Further Reading
Design patterns is a vast subject. Knowing them and using them is important, as is knowing when not to use them. Below are some ofthe texts I recommend to futher your knowledge of design patterns.
InfoQ HomepageNewsA Pattern for API Backends Serving Frontends
The web experience through a mobile device with its smaller screen, limited data plans and need for fewer requests differs in many ways from a desktop web browser. A mobile device requires less but often also different data and may provide other interactions, e.g. through a bar code reader. This means we need to add additional functionality to our API backend to support mobile devices, Sam Newman explains in a blog post describing a pattern for API backends dealing with this mismatch between devices for different types of user experiences.
One solution Newman, developer at Thoughtworks, describes is to build a general-purpose API backend serving all types of user interfaces. Due to the very different needs though this will in practice mean adding functionality and complexity to the backend. It may also become a bottleneck by slowing down the deployment process due to all the changes needed in supporting all devices. When working with a general-purpose backend sometimes a special team is created especially for the backend which in Newman’s experience can increase the problem, now a front-end team has a separate team to negotiate with, a team that has to prioritize requirements from other teams as well.
Another solution Newman have seen in use is to have one API backend for each user experience. Conceptually a user-facing application then consists of two components, one on the client side and one on the server side, a Backend For Frontend (BFF, a term coined by Phil Calçado when working for SoundCloud).
When working with a BFF it’s normally tightly coupled to a specific user interface, both maintained by the same team. When dealing with the same type of user interface but on different platforms, e.g. Android and iOS, Newman describes two approaches, with one BFF for each platform and with a BFF for each type of interface.
Newman prefers a strict model with a BFF for each platform, i.e. one for Android and one for iOS. One concern with this approach is the risk of ending up with lots of duplication between the BFFs with e.g. the same types of aggregation or similar code for interfacing with downstream services but he is not really disturbed with this duplication since it’s across process boundaries. Merging towards a general-purpose aggregating Edge API service is something he warns against noting that such a model has proven time and again to lead to highly bloated code.
Using one BFF per type of type of client, i.e. one for both Android and iOS, is an approach he has seen in use at SoundCloud. His concern with this approach is that with more types of clients the risk of bloating the BFF increases.
Lukasz Plotnicki, also working for Thoughtworks, writes in a recent blog post specifically about SoundCloud’s work with BFF during their move from a monolithic Rails application towards use of microservices.
In Thoughtworks latest Technology Radar BFF is mentioned as a technique worth pursuing.
Related Topics:
The InfoQ NewsletterPurpose Pattern And Process
A round-up of last week’s content on InfoQ sent out every Tuesday. Join a community of over 250,000 senior developers. View an example
Purpose Pattern And Process 11th Edition
2
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |