AK

Pragmatic Programmer - Notes

Aug 22 2020
While You Are Coding

We should avoid programming by coincidence—relying on luck and accidental successes—in favor of programming deliberately.

Always be aware of what you are doing. If you're not sure why it works, you won't know why it fails. Proceed from a plan, but be ready to change the plan if the environment changes. Prioritize your effort. Spend time on the important aspects.

Test your assumptions.

Document your assumptions, and also test your assumptions. If your assumption is right, you can make better, informed choice. If your assumption was wrong, well, be glad you tested it.

Don’t let existing code dictate future code. All code can be replaced if it is no longer appropriate. Even within one program, don’t let what you’ve already done constrain what you do next—be ready to refactor

Prioritize

If you don't have fundamentals or infrastructure correct, brilliant bells and whistles will be irrelevant. Prioritize your effort. Spend time on the important aspects.

Why Write Tests

Testing is part of programming. To write good tests, you have to understand the code you are writing the tests for. That's a huge benefit of writing tests. We usually work with a slight understanding of the code and think that we will worry about the edge cases, or error handling later, and never come to it.

Naming Things

Things should be named according to the role they play in your code. When you consider the role of a variable or function, you’re thinking about what is special about it, about what it can do, and what it interacts with. Rename and refactor when your understanding of a thing changes. Avoid misleading names.

Requirements: No one knows exactly what they want

Requirements rarely lie on the surface. Normally, they’re buried deep beneath layers of assumptions, misconceptions, and politics. Even worse, often they don’t really exist at all.

The typical client comes to us with a need. A response to a current problem. The need may be for a change to an existing system or it may ask for something new, can be either expressed in business terms or in technical ones. The mistake new developers make is to take this need and implement a solution for it. Good programmers help the clients understand what exactly they want.

Requirements are learned in a feedback loop. Your job is to help the client understand the consequences of their stated requirements. You do that by generating feedback, and letting them use that feedback to refine their thinking. 

Even at the end of a project we’re still interpreting what our client wants. In fact, by that point we’re likely to have more clients: the QA people, operations, marketing, and maybe even test groups of customers.

Maintain a glossary.

As soon as you start discussing requirements, users and domain experts will use certain terms that have specific meaning to them. Create and maintain a project glossary—one place that defines all the specific terms and vocabulary used in a project. All participants in the project, from end users to support staff, should use the glossary to ensure consistency. This implies that the glossary needs to be widely accessible—a good argument for online documentation.

Solving Impossible Puzzles

Identify the real (not imagined) constraints, and find a solution therein. Some constraints are absolute; others are merely preconceived notions. Absolute constraints must be honored, however distasteful or stupid they may appear to be.

The key to solving hard problems is both to recognize the constraints placed on you and to recognize the degrees of freedom you do have, for in those you’ll find your solution.

Go for a walk, work on something different. Let your unconscious brain work on the problem in the background. However, in order to have those eureka! moments, your nonconscious brain needs to have plenty of raw material; prior experiences that can contribute to an answer.  Or, explain the problem to someone, or even a rubber duck.

Ask questions. Why are you solving this problem? Do you really need to solve it? Has it been solved before? Is there a simpler problem you can solve, instead?  Continuously get feedback on what works and what doesn’t work as you do your daily job.

Were you handed a set of constraints when you signed on to yourcurrent project? Are they all still applicable, and is the interpretation of them still valid?

The Essence of Agile
  • Work out where you are.
  • Make the smallest meaningful step towards where you want to be. 
  • Evaluate where you end up, and fix anything you broke. 
  • Repeat until done. 

Context Matters

Have you or your team fallen in this trap? Ask yourself, why are you even using that particular development method? Or that framework? Or that testing technique? Is it actually well-suited for the job at hand? Does it work well for you? Or was it adopted just because it was being used by the latest internet-fueled success story?

Do What Works, Not What's Cool or Fashionable

There’s a current trend to adopt the policies and processes of successful companies such as Spotify, Netflix, Stripe, GitLab, and others. Each have their own unique take on software development and management. But consider the context: are you in the same market, with the same constraints and opportunities, similar expertise and organization size, similar management, and similar culture? Similar user base and requirements?

The Real Goal

The goal of course isn’t to “do Scrum,” “do agile,” “do Lean,” or what-have-you. The goal is to be in a position to deliver working software that provides value to your users by giving them more capability. 

 Civilization advances by extending the number of important operations we can perform without thinking. 

Ruthless and Continuous Testing

Many developers test gently, subconsciously knowing where the code will break and avoiding the weak spots. Pragmatic Programmers are different. We are driven to find our bugs now, so we don’t have to endure the shame of others finding our bugs later. Test Early, Test Often, Test Automatically.

Testing Thoroughly

How do you know if you have tested the code base thoroughly enough? The short answer is “you don’t,’’ and you never will.

Find Bugs Once, Fix them twice

Once a human tester finds a bug, it should be the last time that bug occurs, no matter how rare you think it is. Because it will happen again. And we just don’t have the time to go chasing after bugs that the automated tests could have found for us. We have to spend our time writing new code—and new bugs. 

So fix the bug as soon as you or QA find it, and immediately put a system in place so that that bug never happens again. 

Delight Your Users

Our goal as developers is to delight users, not just delivering working software in a timely manner, but to actually make our users happy when they use our software.

Users have a problem that needs solving within the context of their objectives and budget. It’s these expectations of business value that really count—not just the software project itself. The software is only a means to these ends.

Make sure you know about your users' expectations before you start working on a project. Continue to think about them as you progress, and try to not only meet them, but exceed them when you finish.

Talk to other departments

As our knowledge of the domain increases, we’re better able to make suggestions on other things that could be done to address the underlying business issues. Developers, who are exposed to many different aspects of an organization, can often see ways of weaving different parts of the business together that aren’t always obvious to individual departments.

Sign Your Work

Take pride in your work. “I wrote this, and I stand behind my work.” Your signature should come to be recognized as an indicator of quality. People should see your name on a piece of code and expect it to be solid, well written, tested, and documented. A really professional job. Written by a professional.

A Pragmatic Programmer.

Protect Your Users

Aug 19 2020
As software developers, we have more power than we realize. Our programs directly affect people and influence their behaviour. It's a good idea to take a break from coding from time to time, and ask yourself this question.

Would I use this product myself?

Or, its corollaries:
  • Do I want my personal and sensitive info shared? 
  • Do I want my data be given to big tech companies, sold to the highest bidders? 
  • Would I be happy to be driven by this autonomous vehicle? 
  • Am I comfortable doing this? 
If the answer is no, take action. Make change in the software to protect your users.

At CityView, I am building an application that allows city inspectors to conduct virtual video inspections with the contractors, without having to drive all the way to the location. The inspector, from his home or office can talk face-to-face with the contractor, just using the browser, without having to install Skype, Zoom, or WhatsApp. It's a really useful application, and I am really having so much fun programming it, using WebRTC and Twilio Programmable Video.

The latest feature I implemented allows the inspector to record the entire virtual meeting just by clicking a button. The easier way to implement this recording feature would have been just to use a third-party library, or use a video framework from a big Silicon Valley company, record the video, and store the video on the cloud, which is just someone else's computer. I would have finished in a couple of hours and life would have been great.

Except, when it came time to testing the feature, I was hesitant. I faced the phone camera away from me, outside the window to not record myself or my personal space. I didn't even turn on the webcam on my desktop. I didn't want my video to get uploaded to cloud, no matter how safe and password protected it was. 

Which bring us back to the question in the beginning. If I am not willing to use this feature, how can I expect the poor inspectors and contractors to use it, record their homes and offices, and trust that the app is not selling the recording to the highest advertisers online, or storing it in an insecure way, vulnerable to hacking, or exposing their private lives to the world?

Once that realization set in, and I got over the shame caused by the question, I redesigned the complete recordings architecture, and re-implemented the entire workflow. Now, the entire recording is captured and stored on the inspector's computer, safe in the city's servers. Their IT staff knows which physical machine it's on, and delete it permanently if not needed. It's not getting uploaded to a cloud server farm in somewhere far away, or sitting on a cheap laptop waiting to get hacked; but it's on their machine, in their hands, and they take the responsibility for it. The contractors can ask the city to delete the recording, if it contains any sensitive information, knowing that it will be done according to the data privacy act.

Implementing the second design was much harder than the first one. I had to think hard about it, use the native apis provided by the browsers, worry about synchronizing the audio and video streams of multiple users at the same time and storing them on the inspector's machine. The design became more complex, and the code size increased by a factor of five. However, the assurance I had when testing the video was priceless. I didn't hesitate while recording, knowing that the video is going to be stored safely on my computer, and I can delete it whenever I want.

As software developers, we are literally building the future. Each line of code we write can have massive impact, both for good and bad. Given that responsibility, we should think about the long term effects of the code we are writing and take responsibility and ownership for it.

Here is Joel Spolsky, founder of Fog Creek, creator of Stack Overflow and Trello, and a very influential programmer that I admire and respect so much talking on this topic.

Support Calls

Aug 14 2020
One of the quirks of being an enterprise software developer is that when your users find a problem with the product, they actually call your company support. Most of the time, the support resolves the issues on their own, but sometimes, especially for complicated ones, developers have to get on the call and see what's going on.

Most of the CityView R&D team is on vacation for last couple of weeks, and I've been swamped with the requests from the support, implementation specialists and the project managers. This week alone, I have been on call with the clients three times.

I have to say, getting on call with clients and to watch them use the software that you wrote can be a humbling and very enlightening experience. You get to watch your users struggle with the software you helped create. It is very painful to see them click a button, and see "Object reference not set to an instance of an object" error slapped onto their face, just because I didn't check if a variable was null before I called a method on it.

Programmers who are two or three levels removed from the actual users of their code are unlikely to be aware of the context in which their work is used. They will not be able to make informed decisions.

Raymond Chen puts very elegantly in his 17-year old post, A day in the trenches,

Product support calls let you participate in the other end of the pipeline. The software is written, it’s out there, and now you have to pay for all your mistakes and bad designs when people call in with their problems. It’s software karma.
I think all developers should be made part of support calls, occasionally. It helps build empathy, when you are writing software. Not just for your customers, but for yourself, few months from now, facing a strange error, just because the current me didn't write a clear message indicating what and where something went wrong. 

Tactical Tornadoes

Jul 09 2020
John Ousterhout, in his talk at Google on 'A Philosophy of Software Design', talks about a special kind of programmers, called tactical tornadoes. 

Person who turns out enormous amounts of pretty shoddy code that kind of 80% works, at a huge rate, and leaves a wake of destruction behind them. In many organizations, these people are considered heroes. This is who management goes to, when they need a feature tomorrow, and they will have a feature tomorrow, that works for most of the day tomorrow..Management actually rewards tactical tornadoes. 
How many tactical tornadoes do you know at your company? 

Why We Have Bugs

Jun 25 2020
Well, one obvious reason is that of programmer incompetence. I came across a more interesting theory while reading Fred Brooks' classic book, The Mythical Man Month this morning. 

Your users get sophisticated and find new bugs. 

This is how it works. As software is built and delivered to the users, new bugs are found and solved in future releases. All goes well for a few months. Then, as we keep releasing new versions of the software, old bugs found and solved in previous releases tend to reappear. 
Bugs Climbing
The common reason for this is that as the users get more familiar with the software, they try to use the new, advanced capabilities offered by the software. This in turn finds new bugs that the developers and the QA overlooked in the initial phase of the development process.

As you keep on releasing new versions of the software, the complexity increases exponentially. The bug fixes, often done by new programmers other than the programmer who wrote the original code tend to destroy the structure of the system and add disorder. As time goes on, less and less effort is spent on fixing the bugs in the original design and more on fixing bugs added by earlier bug-fixes.

Then we call it legacy software, and hope that re-writing the software with a new technology will solve all the problems. But it won't, it will just delay them until the cycle repeats.

Finally, we have bugs because of fear. Because this information can be threatening, we all develop kind of information immunity. It protects us from all the information that we don't want to hear. No matter how well testing we do, if the people who are dealing with these test reports have developed this immunity, it's all waste.

This is how fear-driven development sounds like:

Developer: "That stupid bug shows people I'm not as good a programmer as I'd hoped to be."

QA: "The developer will get angry if I report this bug, because it makes him look bad"

Project Manager: "With all these bugs, I won't make my schedule."

Sales: "This product is so full of bugs, it isn't going to sell very well, and I won't make my numbers."

User: "It can't be a bug in the software. Definitely I am doing something stupid. I must find a workaround."

Software Design

Apr 29 2020
You have to "solve" the problem once in order to clearly define it and then solve it again create a solution that works.   

The finished software design should look well organized and clean, but the process used to develop the design isn't nearly as tidy as the end result. Design is a sloppy process, you take many false steps, and make a lot of mistakes while designing software. 

The purpose of design is to identify the mistakes early. It's cheaper to find mistakes during design phase and correct them, than having to correct implemented code. 

At the same time, until your software fails in production, you don't really know the true requirements. So it's a delicate balance of upfront design vs. on-demand design. 

An ideal program runs instantly, takes zero storage, use zero network bandwidth, doesn't have any errors, and costs nothing. In the real world, there are trade-offs. A good design should try to find a balance among various competing factors. 

A good design emerges out of the iterative process of thinking about the program, writing the program, and rewriting the program. 

Metaphors in Software

Apr 07 2020
By comparing a topic you understand poorly to something similar you understand better, you can come up with better insights about the poorly understood topic. Metaphors help us understand the software development process by relating it to other activities we already know about.

A metaphor is different from an algorithm in the sense that it's more like a searchlight than a road map. It doesn't tell you where to find the answer, but rather how to look for it. Metaphors give us insight into programming problems and processes, and help us imagine better ways of doing things and solving problems.

In his book Code Complete, Steve McConnell compares software development to various metaphors including writing, farming, and construction.

Software development is like writing. How do you write well? You write something and rewrite, and rewrite again. Same goes for programming. You write the first draft of the program to make it work. Then you rewrite to make it better. Then you rewrite it to optimize and make it beautiful. Like well written prose, a well written program is readable.

Software development is like farming and gardening. When we are writing code, we are planting seeds and growing crops. You design, code, test, and add it to the project a little bit at a time.

Iteration is another metaphor that applies well to software development. Incremental designing, building and testing and iterating are some of the most important activities in software development. You first make the simplest possible version of the system that will run. Then you iterate to make it better.

Finally, software development is building construction. In my opinion, this is the most apt metaphor that applies to development. Building software is similar to construction in so many ways. Many common terms in software development derive from building, such as software architecture and architect, scaffolding, construction, etc.

However, there is no one metaphor that rules them all. There is no silver bullet. Many consultants tell you to buy certain methods to the exclusion of others. This usually doesn't work because then you suffer from man with a hammer syndrome, and miss opportunities to use other methods better suited to your problem.

From: Code Complete

Design Patterns

Mar 05 2020
Motivation
Designing good, reusable object-oriented software is hard. Design patterns make it easier to reuse successful designs and architectures.

What Makes a Design Pattern?
A pattern describes a recurring problem, then describes the solution to that problem in a particular context. The solution can be used repeatedly, without ever doing it in the same way.

Elements of a Pattern
  1. Name: A word or two that's used as a handle to describe the problem and its solution. It increases our design vocabulary, lets us design at a higher level of abstraction, and aids in communication. 
  2. Problem: Describes when to apply the pattern, by explaining the problem and its context. 
  3. Solution: Elements that make up the design, their responsibilities and relationships. It's an abstract template that can be applied in many different situations. Not concrete. 
  4. Consequences: Results and trade-offs of applying each pattern. Critical for evaluating and comparing the patterns. 
Problems Patterns Solve
  1. Finding appropriate objects
  2. Determining object granularity
  3. Specifying object interfaces
  4. Specifying object implementations
  5. Programming to an interface, not an implementation
Designing For Change
A design that doesn't take change into account risks major redesign in the future. Some common causes of change include:
  1. Creating an object by concrete class, instead of interface
  2. Dependence on specific operations
  3. Dependence on hardware and software platforms
  4. Dependence on object representations/implementations 
  5. Algorithmic dependencies
  6. Tight coupling
  7. Inability to alter classes conveniently
Design patterns help us avoid this by ensuring that a system can change in specific ways. Each design pattern lets some aspect of system structure vary independently of other aspects, making a system more robust to a particular kind of change.

Consider what should be variable in the design. Instead of considering what might force a change to a design, consider what you want to be able to change without a major redesign. The focus is on encapsulating the concept that changes.

How to use a Design Pattern
  1. Read the patterns for an overview
  2. Study the structure, elements and their relationships in the pattern
  3. Look at the sample code for the pattern
  4. Define the classes and methods with meaningful names in your application context
  5. Implement the operations to carry out the functionality
How not to use a Design Pattern
Do not apply a pattern indiscriminately. Often the flexibility comes at a cost of readability, as a pattern adds more indirection in terms of delegation. Using patterns without a thought can complicate the design and make the code unreadable. 

Rethinking Agile

Jan 20 2020
Agile is the most common software development methodology used when building software. Ideally, it means that you don't do any big, upfront design. Instead, you work in sprints, and evolve your design as your understanding of the project grows. Design is part of the programming.

This sounds nice on paper, but in reality it's often a disaster. I have worked on some projects where I didn't do any design and planning before starting, and jumped straight into the code. The final design ended up being the sum of random decisions made while in the middle of programming, which don't make any sense when viewed as a whole system. It ended up in rigid code, which is hard to change and evolve, which is the essence of agile and extreme programming. As time passed, more bugs crept in, and they were almost always hard to find and fix.

In contrast, there were some projects where I did plan the design of the software I was building, in turn writing a spec, and they almost always turned out well. Planning in advance helps figuring out the big issues in advance and make changes if needed. Changes are always easy while designing, compared to coding.

Now, it's true that I can't think of all the issues that might come up while building software. But as Joel says, the goal of planning and specifying the software is not to find out all the details in advance, but to find out as many as possible to reduce the surprises when programming. 

The next question is how to plan and design software before starting coding. One way I have found really useful is to draw UML diagrams. Now, they might have been out of fashion for quite a while now, but that doesn't mean that they don't have any value. I personally, find them very useful. The important thing is to keep them simple. Draw only important classes, not all, and list only the important attributes and methods on each, and so on. 

The best thing about UML diagrams is that they allow me to capture the design. It's very hard to grasp the whole design of the system based on just looking at the code. If I come back to code I wrote last year, it might take me a day or two to find out the core design behind the system, but a UML diagram conveys that in minutes. And I can always update them, as the design changes. 

So, to summarize, I find it useful to have both waterfall and agile mindsets when developing software. Start with a design, and revise it as I am writing code. Ultimately, that results in software that solves real problems. 

Changing Software

Jan 15 2020
The only thing constant in life is change. As a software developer, around 80% of what I do is change software. There are some ways of doing that which make my life easier, and some that make it difficult.

We change software for quite a few reasons. Sometimes, it’s to add a new feature or to fix a bug which alters the behavior of the product. Other times it’s to improve the design of the codebase, while keeping it’s functionality same. Many times, code is changed to optimize the resource consumption, such as memory, space, or time.

When we change software, it impacts three things. The structure of the codebase, the functionality of the product, and the resource usage. We have to make sure how to preserve the rest of the behavior. It doesn’t mean just leaving the code alone. That means ensuring that the existing behavior isn’t changing and that can be tough. The existing behavior is usually very large, unless it’s a greenfield project, and we often don’t know how much of the existing behavior is at risk.

Questions to ask before we change code
  1. What changes do we have to make?
  2. How will we know that we’ve done them correctly?
  3. How will we know that we haven’t broken anything?
There are bad ways to deal with change and then there are good ways. It’s tempting to minimize the number of changes one has to make to the codebase. Instead of creating new methods/classes, simply add the new code to an existing method or a class. Unfortunately, it results in the bloated software. Existing classes and methods grow larger and harder to understand.

There are consequences of avoiding change. For one, you get bad at dealing with changes. Avoiding change doesn’t mean the change will go away. It will just catch up with you later, when you are least expecting it. It generates fear. Many software developers live with a fear of changing software and it gets worse every day.

What’s the alternative? Well, that’s coming in future posts as I read Michael Feathers’ Working Effectively with Legacy Code. This was the summary of the first chapter, Changing Software.

Why Refactor

Sep 15 2019
As a developer, once I get a feature working, the common impulse is to move on to a next shiny feature. However, programming is so much like writing. Getting a feature working is just a first draft. You have to come back to it and rewrite it and refactor it. Martin Fowler’s new book lists the following benefits of refactoring.

Refactoring improves the design of software. Without refactoring frequently, the internal design starts to decay. As we change code to achieve short-term goals, without grasping the overall architecture, the code loses its structure. Regular refactoring helps keep the code in shape.

Refactoring makes software easy to understand. When I am in the rush of writing code, I am not thinking about the developer who will be reading the code in the future. If I have a program that works, but is poorly structured, badly formatted, and poorly named., I am not showing empathy for that future developer, often myself. Refactoring helps to keep the code more readable.

Refactoring helps you find bugs. Once you refactor the code, you often see the hidden bugs lurking beneath the surface. Often I realize the numerous null reference exceptions once I extract a method from a bloated piece of code. To refactor code, I need to understand the code, which often helps to figure out all the ways it could go wrong.

Refactoring helps you program faster. Often, the initial investment made in refactoring code pays huge dividends in the future. It’s counterintuitive, but refactoring helps you save more time in the future. When you come back to the code after six months and you don’t have to spend few hours, trying to figure out what you meant when you wrote this piece of code, that’s where the real benefits lie.

If you don’t refactor frequently, sure, you can ship more code; but every new feature will take more and more time to understand how to fit it into the existing code, to the point where you can’t add any more code and have to throw away everything start from scratch, which is probably a very bad idea.

The bugs you didn't see

Aug 15 2019
Every successful software product is the result of the collaboration between developers and the QA team. However, it’s the developers who get the lion’s share of the praise, and the testers are mostly ignored. Devs blame the QA for finding faults in their code, and management blames them for delaying the release. I think this is unfortunate and unfair.

We usually don’t notice what’s not there. When you see a flawless software product, it’s easy to notice all the bells and whistles and admire the technology and the development efforts that went into it. However, you are not seeing all the bugs that are not there, the countless bugs that were lurking in the version 1.0, and which were only discovered by QA by testing the software repeatedly, which can be perceived as a boring, mind-numbingly repetitive job by developers who like to solve new problems and take on new challenges everyday. However, testing is a skill in itself, which needs vast reserves of patience and a Stoic attitude in a sense, to do the negative visualization to find out all the paths to failure.

Testing the software you wrote can be very frustrating for developers. If I wrote a piece of code, I am only going to test it to make sure that it works. As a result, I am only going to test the best-case scenario. The QA’s job is to find out all the ways in which the product can fail. That makes the role of the QA very valuable in any software company. Next time, if a QA finds a bug in the software I wrote, I am going to thank them, because that’s one less bug that the customer will see.

Programming by Coincidence

Mar 15 2019
I was really struggling at work this week. Spent hours banging my head to parse a simple XML document. According to pragmatic programmers, I was programming by coincidence, without any clear plan, just hoping to get the code working somehow, and failing completely.

The weary soldier advances cautiously out of the brush. There’s a clearing ahead: are there any land mines, or is it safe to cross? There aren’t any indications that it’s a minefield—no signs, barbed wire, or craters. The soldier pokes the ground ahead of him with his bayonet and winces, expecting an explosion. There isn’t one. So he proceeds painstakingly through the field for a while, prodding and poking as he goes. Eventually, convinced that the field is safe, he straightens up and marches proudly forward, only to be blown to pieces.

The soldier’s initial probes for mines revealed nothing, but this was merely lucky. He was led to a false conclusion—with disastrous results.

As developers, we also work in minefields. There are hundreds of traps just waiting to catch us each day. Remembering the soldier’s tale, we should be wary of drawing false conclusions. We should avoid programming by coincidence—relying on luck and accidental successes—in favor of programming deliberately.
Yes, I was that soldier. Finally, after confronting my ignorance and admitting my complete lack of understanding of how XML works, I decided to do a deep dive into this topic. As always, I found a few good courses on PluralSight and started with Linq to XML, by K Scott Allen. The course taught me everything I needed to know about XML and much more, in just under 30 minutes.

It was mindblowing. At work this morning, I was able to crank out beautiful C# code using Linq to get it done exactly what I wanted with the XML. Linq-to-XML is like a genie. You wish for what you want to do with the XML, and it does it for you. All I needed to do was understand a few basic concepts and classes in the System.XML.Linq namespace.

According to the docs,

Linq-to-XML is an in-memory XML programming interface that enables you to modify XML documents efficiently and easily.
So true.

Here are a few of the essential classes we need:
  1. XDocument: This represents the XML document. It derives from XContainer and hence can contain child nodes. However, it can have only one child node, to follow the XML standard that there can be only one root element in an XML document.
  2. XElement: Represents an XML element. It is one of the fundamental classes in Linq-to-XML. We can use this class to create/read/modify/delete the XML elements, add attributes to existing elements, and much more.
  3. XAttribute: Represents an XML attribute, which is simply a name-value pair associated with an XML element.
  4. XNamespace: Represents an XML namespace. The most common way to create its object is to simply assign a string to it.
There are additional classes in the namespace. However, these four classes were enough for all my practical purposes. Let’s see how to use them.

Creating XML
public static void CreateXML()
{
    var doc = new XDocument();
    XNamespace ns = "https://www.akshaykhot.com";

    var friends = new XElement(ns + "Friends");
    
    var bandya = new XElement(ns + "Friend",
        new XAttribute("Name", "Akshay Darade"),
        new XAttribute("From", "School")
        );
    var abhiyash = new XElement(ns + "Friend",
        new XAttribute("Name", "Abhiyash Jain"),
        new XAttribute("From", "College")
        );
    var kunal = new XElement(ns + "Friend",
        new XAttribute("Name", "Kunal Veera"),
        new XAttribute("From", "Building")
        );
    
    friends.Add(bandya, abhiyash, kunal);
    doc.Add(friends);
    doc.Save("friends.XML");
}
To generate this beautiful XML:

<?XML version="1.0" encoding="utf-8"?>
<Friends XMLns="https://www.akshaykhot.com">
  <Friend Name="Akshay Darade" From="School" />
  <Friend Name="Abhiyash Jain" From="College" />
  <Friend Name="Kunal Veera" From="Building" />
</Friends>
To be honest, I think the C# code is as much, if not more, readable as the XML.

Parsing XML
public static void QueryXML()
{
    XDocument doc = XDocument.Load("friends.XML");
    XNamespace ns = "https://www.akshaykhot.com";
    
    // find all school frinds
    var schoolFriends = doc.Element(ns + "Friends")
                           .Elements(ns + "Friend")
                           .Where(friend => friend
                                            .Attribute("From")
                                            .Value.Equals("School"));

    foreach (XElement friend in schoolFriends)
    {
        Console.WriteLine(friend.Attribute("Name").Value);
    }
  
}
There is a gotcha in the above code, and I got burned by it. If you are not careful, and one of the friends don’t have an attribute From, it will throw the infamous object reference not set to an instance of an object exception.

To get around this, it’s better to create a common utility method, which you can use any time you want to read the attributes on the elements.
private string GetAttribute(XElement element, string attributeName)
{
    string value = string.Empty;
    XAttribute attr = element.Attribute(attributeName);

    if (attr != null)
        value = attr.Value;

    return value;
}
The code looks cleaner and is much more concise than the traditional .net XML manipulation libraries. I was able to replace most of the spaghetti code that I wrote during the week with lesser and more powerful code.

Always better to learn a new skill which helps you to solve the problems you are facing, and it just feels so damn good. Today was one of the happiest days at work for me, compared to the frustrating week I had so far. Here are some of the lessons learned:
  1. Always be aware of what you are doing.
  2. Don’t code blindfolded.
  3. Have a plan, before you start programming.
  4. If you don’t know why your code works, you won’t understand why it fails, which it will.

Domain Driven Design

Jun 05 2018
After procrastinating for years due to its sheer size, I have finally picked up and started reading DDD. This is a must-read for developers of object-oriented software working on a complex domain. I found myself nodding on almost every sentence in this book, relating so much to my work at CityView, which has a super-complex domain of municipal software.
DDD.jpg
Software:
  • Every software program relates to some activity or interest of its user. That subject area to which the user applies the program is the domain of the software.
  • The heart of the software is its ability to solve domain-related problems for its user. All other features, vital though they may be, support this basic purpose.
  • To create software that is valuably involved in users’ activities, a development team must bring to bear a body of knowledge related to those activities. The breadth of knowledge required can be daunting. The volume and complexity of information can be overwhelming.
  • The messiness of most software domains is actually an interesting technical challenge. Creating a lucid model that cuts through the complexity is exciting.
Problems DDD solves:
  • When we set out to write software, we never know enough. Knowledge on the project is fragmented, scattered among many people and documents, and it’s mixed with other information so that we don’t even know which bits of knowledge we really need.
  • Domains that seem less technically daunting can be deceiving: we don’t realize how much we don’t know. This ignorance leads us to make false assumptions.
  • Domain experts are usually not aware of how complex their mental processes are as, in the course of their work, they navigate all these rules, reconcile contradictions, and fill in gaps with common sense. Software can’t do this. It is through knowledge crunching in close collaboration with software experts that the rules are clarified, fleshed out, reconciled, or placed out of scope.
Models:
  • Models are tools for grappling with this overload. A model is a selectively simplified and consciously structured form of knowledge. An appropriate model makes sense of information and focuses it on a problem.
  • Every model represents some aspect of reality or an idea that is of interest. A model is a simplification. It is an interpretation of reality that abstracts the aspects relevant to solving the problem at hand and ignores extraneous detail.
  • Useful models seldom lie on the surface. As we come to understand the domain and the needs of the application, we usually discard superficial model elements that seemed important in the beginning, or we shift their perspective. Subtle abstractions emerge that would not have occurred to us at the outset but that pierce to the heart of the matter.
Do we need Business Analysts?
  • In the old waterfall method, the business experts talk to the analysts, and analysts digest and abstract and pass the result along to the programmers, who code the software.
  • This approach fails because it completely lacks feedback. The analysts have full responsibility for creating the model, based only on input from the business experts. They have no opportunity to learn from the programmers or gain experience with early versions of the software. Knowledge trickles in one direction but does not accumulate.
  • A team of developers and domain experts collaborate, typically led by developers. Together they draw in information and crunch it into a useful form.
  • The constant refinement of the domain model forces the developers to learn the important principles of the business they are assisting, rather than to produce functions mechanically. The domain experts often refine their own understanding by being forced to distil what they know to essentials, and they come to understand the conceptual rigour that software projects require.
Problem
  • Domain experts have limited understanding of the technical jargon of software development, but they use the jargon of their field.
  • Developers, on the other hand, may understand and discuss the system in descriptive, functional terms, lacking the meaning carried by the experts’ language.
  • Across this linguistic divide, the domain experts vaguely describe what they want. Developers, struggling to understand a domain new to them, vaguely understand.
  • On a project without a common language, developers have to translate for domain experts. Domain experts translate between developers and still other domain experts. Developers even translate for each other. Translation muddles model concepts, which leads to destructive refactoring of code.
  • A project faces serious problems when its language is fractured. Domain experts use their jargon while technical team members have their own language tuned for discussing the domain in terms of design.
  • The terminology of day-to-day discussions is disconnected from the terminology embedded in the code.
The Solution: Ubiquitous Language
  • A project needs a common language. The domain model can provide the backbone for that common language, while connecting team communication to the software implementation.
  • The vocabulary of that UBIQUITOUS LANGUAGE includes the names of classes and prominent operations. The LANGUAGE includes terms to discuss rules that have been made explicit in the model. It is supplemented with terms from high-level organizing principles imposed on the model.
  • The model-based language should be used among developers to describe not only artifacts in the system, but tasks and functionality. This same model should supply the language for the developers and domain experts to communicate with each other, and for the domain experts to communicate among themselves about requirements, development planning, and feature.
How to Get There?
  • Initially the model may simply not be good enough to fill these roles. It may lack the semantic richness of the specialized jargons of the field. But those jargons can’t be used unadulterated because they contain ambiguities and contradictions.
  • It may lack the more subtle and active features the developers have created in the code, either because they do not think of those as part of a model, or because the coding style is procedural and only implicitly carries those concepts of the domain.
  • Persistent use of the UBIQUITOUS LANGUAGE will force the model’s weaknesses into the open. The team will experiment and find alternatives to awkward terms or combinations. As gaps are found in the language, new words will enter the discussion. These changes to the language will be recognized as changes in the domain model and will lead the team to update class diagrams and rename classes and methods in the code, or even change behavior, when the meaning of a term changes.
  • Committed to using this language in the context of implementation, the developers will point out imprecision or contradictions, engaging the domain experts in discovering workable alternatives.
  • Domain experts should object to terms or structures that are awkward or inadequate to convey domain understanding; developers should watch for ambiguity or inconsistency that will trip up design.
  • Recognize that a change in the UBIQUITOUS LANGUAGE is a change to the model.
Benefit
  • When domain experts use this LANGUAGE in discussions with developers or among themselves, they quickly discover areas where the model is inadequate for their needs or seems wrong to them.
  • The domain experts (with the help of the developers) will also find areas where the precision of the model-based language exposes contradictions or vagueness in their thinking.
  • The developers and domain experts can informally test the model by walking through scenarios, using the model objects step-by-step. Almost every discussion is an opportunity for the developers and user experts to play with the model together, deepening each other’s understanding and refining concepts as they go.
Summary: Developers and domain experts have a close relationship. Domain-driven design crunches a huge amount of knowledge into a model that reflects deep insight into the domain and a focus on the key concepts. This is a collaboration between those who know the domain and those who know how to build software. Because development is iterative, this collaboration must continue throughout the project’s life.