Use case diagram is a diagram that describes the functional requirements of the system. It models the the external users of the system (actors) and the way the systems is used (use cases) – an actor of a system is not necessary a human being, it could be just another system.
Have you ever created an object that has over 20 fields ?, have you ever tried to create this object using it’s constructor with several lines of code ? Have you ever needed to create an object without knowing its exact number of fields ? no worries, meet the Builder design pattern.
Builder design pattern is an awesome pattern that eases the construction of complex objects.
Why Builder Patter ?
Telescoping constructor is an anti-pattern that represents an object with several constructors each with different number of parameters.
The problem with this telescoping constructor is that once constructors are 4 or 5 parameters long it becomes difficult to remember the required order of the parameters as well as what particular constructor you might want in a given situation.
Objects default Values.
Sometimes we create objects and we are concerned only with few fields, the rest is set to some default values. This pattern is most common in testing. In this case Builder design pattern helps a lot.
Creating Object in Natural Language
Builder pattern helps building objects in natural language style, which really helps understanding the object’s complex parts during creation.
Not only one way to implement builder design pattern.
As I mentioned previously, there is no one way to implement a design pattern. It is the idea behind the pattern that matters.
Builder design pattern
The above design patter is described in GoF design patterns.
The most used form of builder pattern, as some call it, the fluent builder.
Where to use Builder design pattern
When the algorithm for creating a complex object should be independent of
the parts that make up the object and how they are assembled.
When the construction process must allow different representations for the
object that is constructed.
When you want to insulate clients from the knowledge of the actual
creation process and/or resulting product.
When your object contains Telescoping constructors
When you are concerned with only few properties of the object and the rest can be set to default.
Need flexibility in creating various complex objects. Need to create complex,
It is time consuming and overhead to create builders.
In part two I introduced factory pattern, here I introduce abstract factory and most important the differences between the two patterns. Abstract factory adds one abstract level in factory patter. To put it simply, you can view abstract factory as a factory of factories.
Abstract factory is a creational design pattern, it adds another abstraction level to factory method by encapsulating a group of factory methods. Abstract factory is used to create a family of related objects – factories that create related object – without specifying their concrete implementation. One more definition, abstract factory is a super factory that creates smaller factories that create related objects.
Let me take my previous example of transportation factory and add one level of abstraction. Lets say we need to group transportation into groups. Cheap transportation, middle cost transportation, expensive transportation and let us have a company for each group that provides a certain type of transportation, CheapTrans, SeemlessTransportation, BestTrans. Our super factory will create other factories (these 3 companies) that will create transportation objects. The transportation objects are the related families of objects, the companies are the factories, the factory that will create these factories is the abstract factory.
All of these methods create concrete factories, these factories create concrete related objects.
Where to use
The pattern can be used where we need to create sets of objects that share a
common theme and where the client only needs to know how to handle the
abstract equivalence of these objects, i.e. the implementation is not
important for the client. It is often employed when there
is a need to use different sets of objects and where the objects could be
added or changed some time during the lifetime of an application.
Use of this pattern makes it possible to interchange concrete classes without
changing the code that uses them, even at runtime.
As with similar design patterns, one of the main drawbacks is the possibility
of unnecessary complexity and extra work in the initial writing of the code.
GoF Design Patterns – with examples using Java and UML2
In part one of this series of design patterns articles we introduced design patterns, here we start with the first category of design patterns, as GOF describes , creational design patterns and the first one of them, is Factory Pattern .
As the name describes, creational design patterns are about creating objects. They deal with objects creation mechanisms, trying to create objects in a way suitable to the situation. Creating objects using the basic form ( the new keyword in Java ) sometimes creates undesired designs like hard coded values, long constructors, and other complex situations. Creational design patterns tries to solve these problems in the best possible way.
Factory Pattern represents an object that creates other objects.
The factory can return an instance of one of several possible classes (in a
subclass hierarchy), depending on the data provided to it. It is the one of the most used and easiest design patterns. Keep in mind that there is no single implementation of factory pattern, there are many. The main idea is still the same !
Lets say, you want to create a transportation objects. All of them have a the same function move objects from point A to point B.
Here is a code example:
A real example:
Many articles online give only one abstract example of a design pattern that it describes. Most of these examples are abstract ones and doesn’t give a clear picture of the pattern. I am quoting a real code example here.
There are many example of Factory Pattern in Java, here I am listing some of them. It is important to keep in mind that there is not standard exact template to follow to create factory, neither there is for any Design Pattern. In other words, if some code is said to be a factory pattern, it doesn’t mean that it will implement the same number of classes and introduce the same number and type of relation. Design Patterns may vary in their implementations but the idea remains the same. In our case the idea is to create objects.
As you can see all of the methods in the list create instances, this is the main idea of the this pattern, regardless of the actual real implementation of it.
When to use Factory Pattern
When a class can’t anticipate which kind of class of object it must create.
You want to localize the knowledge of which class you create.
When you have classes that is derived from the same sub-classes, or they may in fact be unrelated classes that just share the same interface. Either way, the methods in these class instances are the same and can be used interchangeably.
When you want to insulate the client from the actual type that is being instantiated.
The client does not need to know every subclass of objects it must create. It
only need one reference to the abstract class/interface and the factory
The factory encapsulate the creation of objects. This can be useful if the
creation process is very complex.
There is no way to change an implementing class without a recompile.
GoF Design Patterns – with examples using Java and UML2
This article represents an introduction to the world of design patterns.
In my collection of design patterns articles, I try to introduce them from a different, more practical angle, than other articles I found online.
Most articles try to explain design patterns in an abstract way, and give approximate examples of them hoping they can be understood. I, on the other side, find it difficult to understand them that way. I prefer to have a real code example of each design pattern. So, let’s get started !
What is a pattern ?
Referring to google translate here is what a pattern is:
A regular and intelligible form or sequence discernible in the way in which something happens or is done.
A repeated decorative design
Simply, a pattern represents a repeated collection of actions that happen often in the same way and succession.
Going to work, school, or university represents a pattern. Waking up every morning, dressing up, using public transport, and getting to work, then leaving it, etc.
What ARE a design patterns ?
I don’t want to repeat what you can easy find online. So here are a couple of definitions of design patterns from a few references.
In software engineering, a software design pattern is a general reusable solution to a commonly occurring problem within a given context in software design
The name of the pattern. The name represents a handle that we can use to describe a design problem, its solution, and consequences in simple words.
The problem. Describes when to apply the pattern, the problem and it’s context.
The solution of the problem.
The consequences. They are the results and trade-offs of applying the pattern.
Types of Software Design Patterns
We can put design patterns into 3 groups considering the kind of problem they solve.
Creational, as the name reveals, the problem they solve is creating something. To be more concrete they create objects.
Structural, these patterns describe how we can combine objects and classes to form structures.
Behavioral patterns, they are patterns that focus on the interaction between cooperating objects.
Keep in mind
When it comes to using patterns there are several things one should keep in mind.
They are rarely used in real life situations. During my development career, which I don’t consider to be a long one (around 5 years), I don’t remember using more than 10% of the patterns and I mostly needed them during job interviews. This doesn’t mean they are not important or are inappropriate but in fact very few developers understand and use them correctly. And if they do – they don`t really do it on purpose.
Design patterns change over time. Programming languages evolve, new ones come. Many patterns were designed to solve some problem that the language itself produced. We will see examples of these when we put some design patterns in the light of Java 8.
Don’t solve problems that don’t exists. Consider if the problem really exists and if that solution is actually needed. Using design patterns in every piece of code is not a good practice, neither is their overuse.
Before we demonstrate Isolation levels, we must define transactions and what ACID model is. Isolation levels are one of ACID model properties, Isolation.
A Transaction represents a collection of operations executed sequentially as one single operation. Consider the well know example of money transfer between two bank accounts of Alice and Bon. Money transfer involves the following operations:
Read Alice’s account, by issuing a select statement, to check if Alice has X-amount or more for the transfer.
Read Bob’s account, by issuing a select statement, to check if Bob’s account can receive money.
Decrease Alice’s account by X-amount of money.
Increase Bob’s account by X-amount of money.
In RDBMS for a unit of work to qualify as transaction it must comply to ACID model. So, what is ACID model ?
ACID model represents four properties that a transaction (single unit of work) must exhibit. We are not going to dive deep into ACID model, as there are tons of documents online that does so. We are going to define them only in a nutshell.
ACID stands for:
As mentioned, a transaction is a collection of operations. Other transaction must see these operations as one atomic unit of work, as one operation. Either all operations succeeds or they all fail !
Transaction must leave the data in a consistence state, after completion of the transaction. What consistence state means data that transaction writes must not break any data structure like B-trees and indexes and data must be valid according to constrains like unique and foreign keys, cascades, triggers or any combination theory.
This property is our main focus in this article. So, what are these isolation levels ?
Isolation levels define the degree/level of isolation of work (reading/modifying) of a number of transactions. When these transaction executes in parallel and work on same set of data. In other words, let T1 and T2 are two transactions that execute in parallel. Isolation level defines what modifications T2 can T1 see, during the execution of T1 and T2.
Here are definitions from well know sources:
Transactions specify an isolation level that defines the degree to which one transaction must be isolated from resource or data modifications made by other transactions. Isolation levels are described in terms of which concurrency side-effects, such as dirty reads or phantom reads, are allowed. Miscrosoft
Transaction isolation is one of the foundations of database processing. Isolation is the I in the acronym ACID; the isolation level is the setting that fine-tunes the balance between performance and reliability, consistency, and reproducibility of results when multiple transactions are making changes and performing queries at the same time. MySQL
The SQL standard defines four levels of transaction isolation. The most strict is Serializable, which is defined by the standard in a paragraph which says that any concurrent execution of a set of Serializable transactions is guaranteed to produce the same effect as running them one at a time in some order. The other three levels are defined in terms of phenomena, resulting from interaction between concurrent transactions, which must not occur at each level. The standard notes that due to the definition of Serializable, none of these phenomena are possible at that level. (This is hardly surprising — if the effect of the transactions must be consistent with having been run one at a time, how could you see any phenomena caused by interactions?) PostgreSQL
In database systems, isolation determines how transaction integrity is visible to other users and systems. For example, when a user is creating a Purchase Order and has created the header, but not the Purchase Order lines, is the header available for other systems/users, carrying out concurrent operations (such as a report on Purchase Orders), to see? Wikipedia
SQL standard defines four isolation levels of transaction. Each level has its own characteristics. Isolation levels are derived and defined in terms of phenomena (anomaly or circumstances) caused by interaction between transactions.
Following are definition of these anomalies:
Dirty reads occur when a transaction (T1) reads/sees data that is created or deleted by another uncommitted(in progress) transaction (T2).
A nonrepeatable read represents a situation where a transaction (T1) reads (executes a select query) some data. Meanwhile another transaction (T2) modifies this same data. When (T1) reads the modified data again (executes the same previous query again) it finds out that the data had been modified. Thus the name nonrepeatable reads. You can’t repeat the same query and get the same results.
A phantom read represents a change in the number of rows returned when a transaction (T1) executes the same query twice. Due to the fact that another transaction (T2) inserted some rows and committed its execution. In other words, transaction (T1) begins and executes a search, meanwhile transaction (T2) starts and inserts some rows(records) and commits. These rows satisfies transaction (T1)’s search. When transaction (T1) executes the previous search once again, it will find that the number of rows are different.
There are four isolation levels. Each isolation level is meant to prevent one or more of the above mentioned phenomena (situation or circumstances) .
This is the lowest isolation level. It allows dirty reads. Transaction (T1) can read data that transaction (T2) has just written before transaction (T1) commits. In other words, one transaction may see changes that another one is just making before it finishes and commits its work. T1 may see not-yet-committed changes made by T2
In this isolation level, a lock-based concurrency control DBMS implementation keeps write locks (acquired on selected data) until the end of the transaction, but read locks are released as soon as the SELECT operation is performed (so the non-repeatable reads phenomenon can occur in this isolation level, as discussed below).
Read committed is an isolation level that guarantees that any data read is committed at the moment it is read. It simply restricts the reader from seeing any intermediate, uncommitted, ‘dirty’ reads. It makes no promise whatsoever that if the transaction re-issues the read, it will find the same data; data is free to change after it is read. Wikipedia
It is worth to answer a question that might come to your mind. What is the difference between dirty ready and non-repeatable read ?
Yes, both means that some transaction (T1) can read modified data by (T2). But !
In dirty read transaction (T1) can see data that transaction (T2) added or modified but transaction (T2) is still not committed !. With non-repeatable reads transaction (T1) CAN’T see any addition or modifications, made by transaction (T2) until transaction (T2) is commited !
In this isolation level, a lock-based concurrency control DBMS implementation keeps read and write locks (acquired on selected data) until the end of the transaction. However, range-locks are not managed, so phantom reads can occur.
This is the strictest isolation level. Serializable isolation level simulation a situation where transaction executes one after another, in a series. So it doesn’t allow any transaction anomaly. However, this isolation represents a performance issue and it is rarely used for this reason. It is mostly used for debugging issues.
Here is a summary by PostgreSQL:
Allowed, but not in PG
Allowed, but not in PG
The final property of ACID model is durability. Durability states that committed data is saved by the system such that, even in the event of a failure and system restart, the data is available in its correct state.
User stories describe software functionalities that are valuable to either a user or purchaser of that software. In other words, they describe what the user can do with the software.
User stories also allow business guys (product owners, stake holders, business analysts ) to describe what functionalities the software has to cover. At the same time they allow the developers to analyze, decide on how-to, and estimate time for development.
Almost every software project nowadays is developed in an agile development style. Depending on the team, each has its approach to be agile, sometimes they are truly agile more often they are not.
The two main groups that participate in project development are the tech guys (developers) and business guys. Sadly,more than often, they don’t speak the same language, though they have one goal, the success of the project in hand. User stories help the communication between the two.
One of the most common problems I observe, when working on projects, is misunderstanding the INVEST model of user stories. Failing to craft user stories following the INVEST model has many consequences. Delivering a wrong functionality, duplicating the work by two or more developers, blocking one developer during development, etc … are all examples of such consequences. But what makes a good user story?
User stories have a common form that they follow, though it is not mandatory.
As (user)/(admin)/(someone who will user the software) I want to be able to (some action), so that (the outcome value)
As a user I want to be able to store photo, so that I can view it later.
The INVEST model of user stories.
The INVEST model stands for (I)ndependent (N)egotiable (V)aluable (E)stimatable (S)mall (T)estable.
A story is independent when its implementation doesn’t depend on other stories. Consider the following stories:
As a user I want to filter books by name
As a user I want to filter books by ISBN
The first story depends, and duplicates, the second story, the path to implement the first story is pretty much similar, if not the same, to the second story.
Dependencies between stories lead to prioritization and planing problems, efforts duplication during development, and difficulties during merging codes.
Many times I have been forced to delete my code or my colleagues code because our code was 90% the same and the only thing we really needed was to parameterize some methods and refactor some classes. For each story you are writing, ask yourself if developers would block each other. if so, this two stories are highly dependent and they should be made as one. If merging these two stories seems to be impossible for some reason (like the business analyst, or any author of user stories, thinks he is the chosen one and his stories are prefect) it is highly recommended for those two stories to be linked and implemented by one developer.
Recently me and my colleagues were working on the following “user stories”:
Fetch vacation from X system to our application.
User should see fetched vacations in his calendar.
Apart from the fact that the first “story” looks like anything but a user story, they depend on each other. And here is what happened.
I implemented a service that fetches these vacations from X system and saves them to our database. We implemented saving these vacations by a Repository interface, for some reason I needed to have not only save method but fetch method, here is what happened :
When the time to merge our ‘stories’ came, we had to remove one of the repositories and it`s implementations, than refactor the remaining one. This added extra effort to our original work, which also made our original estimation of stories wrong, in the eyes of project manager and product owner. One of us implemented a repository that we later deleted. Apart from the fact that we needed additional work to finish our task, I was a bit disappointed, and demotivated when I had to delete the code I’ve written with passion and covered by tests. The team should pay extra attention to avoid user stories coupling.
Sometime, however, it is tricky to decouple user stories. If this is the case, in order to avoid code merge conflicts, it is advisable one developer to implement all dependent user stories.
Stories must be valued by users, software purchaser, or some 3rd party software. When writing user stories it is important to ask the question what value it adds for the mentioned groups.
Consider a bookstore application and the following story:
Users should store books in MySQL DB.
Now, what value does this story, for the users, have ?, no value ! First, the user, most probably, won’t know what MySQL DB is. Second, even if he knows, there is no value in merely storing books in some storage engine that is MySQL? What the user actually values (needs) is probably to be able to retrieve a stored book and explore it or download it. The story can be written as:
User should be able download a stored book.
User should be able to explore a stored book.
These two stories in them self include storing the book.
In general, avoid stories that only developers value like:
A connection pool should be used to connect to DB.
Sl4j logger should be replaced.
MySQL database should be used
At the end of the day, developers should add value to the software that solves users problems not developers problem !
Developers should be able to give time estimation for the story, or at least take a guess. A couple of reasons developers may be unable to do so.
Lack of domain knowledge. Domain knowledge is gathered from users and domain experts thus developers should sit and question.
Lack of technical knowledge.
System can authenticate users using their social profiles.
If none of the team members has ever done that before, the team should split the story into two, a spike and the actual story.Spikes represent small exploratory and research actions for gathering some technical knowledge. Developers give spikes maximum amount of time called (time-box). After the spike developers should be able to give an estimation.
The story is too big. In this case, the team should split the story into smaller stories, without introducing dependency between stories, or at least try not to.
Small may be not the so proper, in my opinion, I prefer the term moderate. If they are, developers will find them hard to use in planing and estimation.
Big stories fall into two categories, compound stories and complex stories. Consider the following story, as an example of the first type.
User can create a personal profile.
A story for a social media application. Creating a personal profile can include adding personal information, adding a photo, connecting the profile to other social media, verification via email, SMS, and so on.
An example of complex is a story that, for some reason, developers find it hard to implemented. Introducing new technologies and adding new algorithms to the projects are an example of complex stories.
User can update his membership by paying with credit card.
Maybe none of the team members have ever implemented credit card payments.This is a complex story, that the team needs to split into spike and implementation. In our case one or two team members can start a spike to learn how to implement payment via credit cards.
Sometimes things go to opposite direction. Stories become too small. Too small that developers don’t even want to estimate them or even write them down. One of the teams I was working with created stories so small that I was taking more time to go back and forth to Jira than doing real job.
User can add his birth date.
User can add his name.
User can add his hobbies.
Are very small and they actually fall under one user story.
Use can add personal information to his profile.
The most problematic issue when creating small user stories is that usually they are dependent. More frightening is distributing these stories among the team. There for sure, will be more work to resolve code merges conflicts than to implement each story.
Stories must be testable. Otherwise how can developers tell that they have done the job right?! Untestable stories commonly come from non-functional requirements.
User should find the software easy to use.
User should find the software fast to use.
Easy and fast are relative, what I find easy and fast may not be the same for you. Instead, one can reform stories to:
90% of the new users should be able to find how to do “something work” without any previous tutorial.
The UI should respond in no more than 1 second 99% of the time.
Writing user stories is not complex neither easy task to do. But at the end one should try to come as close as possible to the INVEST model. It is not always possible but at least try it.
I rarely spot well written user stories. However, what scares me the most is the fact that , most often, worst stories are written by people with at least two titles in front of their names.
Completely, or almost completely, disconnect from the word. The monastic philosophy of deep working is based on the idea of minimizing as much as possible of shallow obligations. People who practice this type of deep working are generally hard to find or connect with in some way. They are also characterized with well defined high valued and complex professions. Researchers, novelists, and scientists are examples of such people. They do one thing exceptionally well and focus only on it. They are hard to replace kind of people.
By default they are in a mode of disconnection from the outer world. For example they spend 5-6 days a week doing what they do best, without a distraction.
The Bimodal Philosophy.
When you can’t completely disconnect yourself from the out side world. This philosophy emphasizes on dividing the time between completely deep working and shallow activities. The division is strictly defined. The division can happen on multiple scales, scale of week, scale of month,or scale of year. For example, on scale of week one can dedicate 3 days a week completely disconnected and focused on his work. On scale of month, dedicating the first two weeks of work can do the job. During deep working period the worker acts monastically as if he practices the monastic philosophy. However, he is completely shallow in the rest of the time. A worker that practices this philosophy attempts to reach maximum cognitive intensity, in contrast of rhythmic philosophy. This is why the minimum unite of work is one day.
The Rhythmic Philosophy (The chain method).
The idea behind this deep working philosophy is to maintain a chain of a deep working sessions. The deep working chain can be monthly, weekly, or daily. For example, you conduct deep working every day from 5:00 – 7:00 AM. The most important thing here is trying not to break the chain. This method is widely adopted by body builders and other sportsmen, not only thinker workers.
Rhythmic deep working makes it easy to start deep working as it turns it to a regular habit. The goal in other words is to generate a rhythm for deep working, this rhythm eliminates the need to invest energy in deciding if and when to go deep. When something becomes a habit it becomes more pleasant and easy to do, enjoyable when it has been done.
This philosophy is a good fit for people who have a full-time job and can’t disconnect for a couple of days as in the bimodal philosophy. This philosophy provides an interesting contrast to the bimodal philosophy. It maybe fails to achieve the deepest, most intense, levels of concentration and deep thinking as in the day-long concentration sessions. By the time your brain goes in its deepest thinking you’ll have to finish the session. You simply don’t have all day long.
The Journalist Philosophy.
This method can be summarized as: work whenever you find some time. At first, this philosophy can look very easy to conduct. You don’t setup any schedule, or try to create an unbreakable chain of deep working sessions. Just work when you get a chance. The facts are opposite. Switching to deep working in a short period of time is not an easy task. One has to be trained to shift between deep working and regular state of mind. This philosophy is not suitable for deep working novice. With practice, being confident in what you do, and considering the fact the conducted work is important you can start implement this method.
Let me give some examples. A meeting is rescheduled, now some space of two hours is opened, grab you laptop, books, whatever tools you need to let your mind dive deep. If you are a father and your children are sleeping or doing something that frees you from babysitting them this is another chance to deep work.
Depending on what your job is, what you try to achieve, and your current experience in going deep, pick the philosophy that suits you best. You can also be creative and craft your own philosophy. The goal at the end of the day is to do the job the best way It can be done !
This article is a simple summary of most frequently performed operations over tree data structure. As an enterprise Java developer I don’t usually deal with traverse or other calculations with trees, There are already well designed and tested libraries to do the job. However, interviewers usually like to ask these questions and give you task or two – to be done on paper- that involves these operations.
This post represents a brief introduction to graph algorithms. When study I usually use to use paper and write a summary for what I read to better understand, analyze, and memorize what I am studying.
Instead of using paper, this time, I decided to use my nice little blog as someone else can benefit from it. Reference of the definitions and books are provided at the end of this post.
My mind, on the other hand, better works by visualizing things so I’ve done my best to draw pictures of the definitions mentioned in this post.
1- Graph: graph G = (V, E) consists of a set of vertices, V, and a set of edges, E.
Each edge is a pair (v, w), where v, w ∈ V. Edges are sometimes referred to as arcs.
There are two type of graphs, directed and undirected.
Directed graphs are called digraphs.
Vertex w is adjacent to v if and only if (v, w) ∈ E. In other words if the w and v are connected with only one edge. The edge E is consisted of w and v.
In an undirected graph E is represented either by (v,w) or (w,v), the direction is both ways, it is undirected right ?
In a directed graph (v,w) is a different edge than (w,v).
An edge can have a weight or sometimes called cost. In a geographical map this can represent the distance between two points, for example.
2- Path: A path in a graph is a sequence of vertices w 1 , w 2 , w 3 , . . . , w N such that (w i , w i+1 ) ∈ E for 1 ≤ i < N.
The length of such a path is the number of edges on the path, which is equal to N − 1
There is always a path from every vertex to itself and its length is 0, this is intuitive.
loop, this represents an edge (v, v) i.e a path from a vertex to itself.
A simple path is a path such that all vertices are distinct, except that the first and last could be the same. (wiki definition: a simple path is a path in a graph which does not have repeating vertices)
3- Cycle: A cycle in a directed graph is a path of length at least 1 such that w 1 = w N ; this cycle is simple if the path is simple. In other, more intuitive words a cycle is a path that ends at the same vertex that it started from.
The is no cycles in an undirected graph, why is that? well because very edge is considered as a a cycle as it has both way from v -> w and from w->v.
A directed graph is acyclic if it has no cycles
A directed acyclic graph is sometimes referred to by its abbreviation, DAG
4- Some more points :
An undirected graph is connected if there is a path from every vertex to every other vertex.
A directed graph which is connected (there is a path from every vertex to every other vertex) is called strongly connected.
If a directed graph is not strongly connected (there is NO a path from every vertex to every other vertex), but the underlying graph the one without direction to the arcs or in other words the same graph after removing directions of edges is connected, then the graph is said to be weakly connected. In other words, a directed graph is called weakly connected if replacing all of its directed edges with undirected edges produces a connected (undirected) graph.
A complete graph is a graph in which there is an edge between every pair of vertices