Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Friday, March 20, 2020

Parsing SVG documents into useful layout specifications

In a previous post, I discussed using SVG documents to specify layouts in a Unity app. More recently, I started delving into that subject and laid out a list of things to cover:

  1. How to make the SVG easy to interpret visually.
  2. How to convert the SVG into a set of rules.
  3. How to select the right rules given a query string.
  4. Generating an SVG that explains what went wrong when a test fails.

Among the many things I deferred was how to actually parse the SVG into a set of layout constraints.

Both #2 and #3 are pretty simple and they are strongly related, so I'll handle them in this text.

Wednesday, January 16, 2019

The Ring

Yesterday I refactored some hokey index-based logic into a circular linked list. It spans two videos: My evening ride home and a late-night coding session.


Monday, January 14, 2019

It's Going to Be what It's Going to Be

Last week, I had a vision of how I was going to design the networking part of the game I'm writing. This morning, I was all set to execute on that vision.

As I was reviewing the code, before the change, I discovered some things that needed to change. So, instead of doing what I planned, I did what was right. I cleaned up the code.

In the course of my cleanup, I uncovered a better design for the networking part of the game.

There's an important lesson, here. The forces acting on your code are going to be what they are going to be. So let the code be what the forces want it to be.

It probably won't cost you anything and, every once in a while, it grants you an insight of incalculable value.

Literally.

The value of a little discovery like that cannot be calculated because you can't tell how much its absence would have cost you.

Experience, however, allows me to estimate the cost as "a lot".

Tuesday, January 1, 2019

Interesting Trick I'm Trying

I saw a tweet titled something like "TDD as if you mean it". I'm sorry to whoever posted it. I can't find the link, now. The gist was that you start with only your tests and extrude a design from passing tests.

I'm experimenting with it and it's kind of interesting.

I think it might seem even less comfortable for someone who hasn't made the TDD mindset shift than "regular" TDD.

I'm digging it, though.

Tuesday, December 25, 2018

For Encapsulation, Ask "What's the Cost of Changing Visibility Later?"

Santa taking a selfie with the caption "once it's out there it's out there."

Most languages give you a choice regarding how visible a member of a class will be. The choices vary from language to language but, typically, they range from more-widely exposed options to those granting narrower visibility.

Every time you define a member, you are making this choice. Even if you take the default level of visibility, you are still making the choice to accept the implicit level of visibility.

One thing you can do to inexpensively start improving the level of encapsulation in your system is to start asking a simple question:
What's the cost of changing visibility later?
Generally, all levels of visibility have the same cost, initially. You aren't going to choose an access-modifier that prevents something from being used the first time you write it.

What really matters is how the level of visibility will interact with change. If you make something too private, now, how hard will it be to make it more public, later? If you make it too public, now, how hard will it be to change it to be more private, later?

In a lot of cases, it's pretty straightforward but it isn't always obvious. That's why it's worth asking the question.

Thursday, December 20, 2018

Does It Matter if You Mock?

Part of me thinks this is a continuation of this post.

I love mocking and experience none of the problems purported by people who seem to hate it. I also recently tried an experiment of writing tests with minimal (so far, no) mocking.


Guess what. I'm experiencing none of the problems purported by people (such as myself) who prefer to writing code with mocking.

What gives?

I've known that whether or not you use a mocking tool, like Moq, doesn't matter. Hand-rolling a mock or writing a test-double with widely-understood behavior works just as well as using a dynamic mocking tool.

Now, I'm beginning to think that whether or not you mock at all isn't really that impactful at all. I think that, when we measure an impact, what we are really measuring is a correlation with something else; something that does matter.

I think what we are measuring is the degree to which a test specifies a single behavior and is insulated from implementation details. I don't know why, but I'm guessing we blame our tools for the success we've experienced.

More on this as I continue to experiment.

Monday, December 10, 2018

Simple Is as Simple Does

Two panes. On the left: a circuit board with the word "SIMPLE" superimposed. On the right: An eye with the word "COMPLEX" superimposed.

Simplicity has no relationship to how many code structures are written or boxes are drawn. It has nothing to do with whether or not a particular person can understand some code. There is no relationship between how many "things" you can count in a system and how complex it is because it all depends on what you decide counts as a discrete "thing".

A good yardstick for simplicity, in software, is sustainability. Code that stays about as easy or hard to change over a long period of time is probably simple code. Code that gets harder to work as it evolves is overly-complicated.

Code qualities are proxies for true simplicity. They guide you because they correlate strongly with sustainability. Use them. Talk about them. Weigh them when considering your design changes.

If you want to make a change to your design and it's going to make your code easier to work with over time, don't let someone complaining that it "adds complexity" dissuade you. If you're blindly following a "best practice" and someone has a compelling argument for how it's going to make things harder in the future, you're probably adding complexity.

Tuesday, November 20, 2018

For Any Pattern: Check to See if It Creates a More Needs-Oriented Interface

A person tells another person that his website, anything.biz, is so great. All you do is submit detailed manufacturing instructions and pay. The other person is not convinced.

Design patterns thinking tells us to design to interfaces. This has nothing to do with the keyword interface that is available in a lot of languages. It's about the English word "interface".

You know... the "I" in "GUI" or "API".

With few exceptions, a needs-oriented interface represents a better contract for a class than a capabilities-oriented interface would. The better-ness of this contract manifests in two ways:
  1. The coupling that forms will likely be long-lived and resilient to implementation-changes.
  2. It provides more context and drives better internal design decisions.
If you are considering whether or not a design pattern applies, try asking yourself if introducing the pattern will make the interfaces involved more about what should be accomplished or more about what should be done.

If the interfaces become more about what should be accomplished, that's a vote in favor.

If the interfaces trend toward a more imperative nature, you might want to reconsider.

Monday, November 19, 2018

Needs- and Capabilities-Oriented Interfaces

A mugger shouts "Gimme your wallet!" The victim replies "Sorry. I only carry a money-clip."

Among the many and varied ways to categorize interfaces is this one: needs-oriented and capabilities-oriented interfaces.

A needs-oriented interface is one that allows a client to ask for what they want. A real-world example of a needs-oriented interface is the mobile app for Lyft or Uber. You tell it where you want to go, negotiate and agree to terms such as cost and wait-time, and go there.

A capabilities-oriented interface is on that allows a client to ask for work to be done on its behalf. A real-world example of a capabilities-oriented interface a classic offset-barrel smoker. You control how much fire you have but adding wood, adjusting intake and exhaust vents, and leaving doors/hoods open or closed.

It's not that one is good and one is bad. They just serve different purposes.

An offset barrel smoker is part of an American tradition. There's an enormous amount of inertia around how it works. It's also very versatile. There are a lot of things you can do with an offset barrel smoker. Basically, an offset barrel smoker is part of the American Barbecue framework - it can be used in a lot of ways and it is okay - even expected - that it will not change.

Consider your programming language of choice. Can you think of a type that meets those requirements? It seems like the built-in collection types usually fit the bill.

Capabilities-oriented interfaces are really good for frameworks but they fall down when the fundamental assumption of a framework - mostly slow, primarily additive change - is violated.

Needs-oriented interfaces tend to withstand change a lot more readily. This is because a need doesn't usually transform into another need. It happens, but not often. Typically, a need either stays the same or goes away entirely.

Implementation details, on the other hand, can change on a daily basis.

What if the ride-sharing interfaces were focused on how you would arrange a ride rather than getting you where you want to go?

The moment something about fulfilling your need changed, the ride-sharing apps would have to change the interface to which you were coupled. If they brokered a sequence of text messages between you and potential drivers and suddenly text messaging was out of vogue, they'd have to change the interface and retrain a bunch of customers. If they get better technology, like driverless cars or single-passenger drones, they'd have to change the interface again.

Yet, by allowing you to express your need, the ride-sharing applications let themselves free to experiment with different processes and different means of conveyance.

The strength of a needs-oriented interface is that it will probably not change unless the associated need changes, which is rare. The weakness is that cannot typically be used by a wide audience in a large variety of ways.

If you are working on the .NET Core team or contributing to a broad-audience, low-level open source library, a capabilities-oriented interface might be the right choice. Otherwise, you probably want to focus on the needs being fulfilled when crafting a class, service, or application interface.

Thursday, November 15, 2018

For Any Pattern: "Does This Allow More Objects to Each Deal with Fewer Things?"

An expert woodsman or carpenter is better than one person who does both...at least in code.

One of the principles of design patterns thinking is favoring delegation between objects over inheritance from one class to another.

I think we can actually expend that if we want to:
Favor delegation between objects over the same object doing two things.
Remember, when you inherit you end up with one object even though you wrote two classes. So the way I just wrote it still works for inheritance but it also works for, say, lumping everything together into a giant algorithm.

Note: Not more classes. More objects.

If you are considering a design pattern for your codebase and you're not certain if it applies, ask yourself this:
"Does this allow more objects to each deal with fewer things?"
If so, you may be headed in the right direction. If not, maybe consider a different approach.

Wednesday, November 14, 2018

For Any Pattern: "Does This Make Something Less Aware of a Kind of Variation?"

A car is on a road. There's a dirt road leading off to the left between some trees. A passenger says "They said turn left at the trees!" The driver says "I can't. I don't know how to turn left onto a dirt road."

If you have alternatives - different kinds of things that can be used to replace one another or, sometimes combined with one another - then you have variation.

Design patterns thinking tells us that we should encapsulate variation. That's the kind of thing that is obvious once you already understand it (the hallmark of a good idea) but turning the advice into action can be challenging for people at first.

The immediate goal isn't really to make code less aware of the fact that there is variation so much as making your code so it doesn't need to change when you add or subtract a variant.

So, it's not that we're trying to hide variation altogether. We just want to minimize its impact on most of the code. We are seeking to lessen awareness, not eliminate it altogether.

If you are considering a design pattern for your system, and you aren't really sure if it's the right way to go, ask yourself this:
"Does this make something less aware of a kind of variation?"
Or...
"Does this make something less aware of the variants in a kind of variation?"
If the answer is "no", you aren't attending to the fundamental value-proposition of design patterns thinking and there's a good chance you should be considering another path.

Tuesday, November 13, 2018

For Any Pattern: "Does This Help Me Couple to an Higher-Level Abstraction?"

A sign indicating the steps to use a gas pump: insert dinosaur, age 100,000,000 years, refine gas, fill car.

One of the things that design patterns thinking is supposed to help you do is elevate the level of abstraction in your code. That doesn't just mean "write more interfaces" or "use ore abstract classes/protocols".

What it means is try to move the points of coupling away from the metal. The more a coupling point is about implementation details, the less useful it is and the shorter is helpful life will be. That is especially true an high-traffic interface but, really, it's true for the surface area of any piece of code.

So, if you are considering a design pattern and aren't quite sure if it applies to your situation, ask yourself this question:
"Does this help me couple to an higher-level abstraction?"
If applying the design pattern will make the interfaces (not the keyword interface, the English word "interface") a little more about "what" and a little less about "how", you might be on to something. If it cuts the other way, you may want to reconsider.

Thursday, November 8, 2018

Design Patterns and Code Qualities

A friend of mine recently intimated that we don't need design patterns because all the principles and patterns can be derived from code qualities.

It's true. Patterns can be derived from the principles of code qualities...the same way aerodynamics can be derived from quantum mechanics.

Friday, November 2, 2018

Macrocosmic Code Qualities

A lattice of equilateral triangles with a glowing red line that follows this pattern: cover one line segment, turn right, cover one more, turn right, etc. Every time it turns, a green beam of light extends to meet the spiral and complete a triangular shape.


As I've mentioned before. I think all software work is design work. I also have a relatively context-insensitive definition of code quality.

The code qualities to which I (and many) subscribe can apply at any level of design.

If you're writing a method, you can ask yourself any of the following...
  • "How strongly-related are these instructions?"
  • "How will I know when this is done?"
  • "How easily will it be for my future-self to comprehend this?"

The same qualities translate into class-level design as different questions...
  • "How strongly-related are the members of this class?"
  • "How will I know that this class works as intended?"
  • "How easily can I understand how this class fits into the larger design?"

The same principles apply all the way up to the very largest scale of software design and all the way down to the lowest-level detail.

This is one of the things that is great about these code qualities. They are general rules that are aligned with effects.

Cohesion matters because it defends against a certain kind of coupling, makes testing easier, and makes code easier to understand. It matters the same amount and for the same reasons at any scale.

There's something aesthetically pleasing about that.

Thursday, November 1, 2018

Design Patterns Live in Solutions

This week, I've been talking about where Design Patterns live and where they don't.

I have a suggested model and I didn't come up with it alone. It was an accumulation of knowledge from old work and a collaboration with Eran Pe'er of DevCraft.

First, I'm going to lay out some information.

Think about all the ways a Design Pattern can impact your life as a developer...

Six pictures depicting the six things listed in the following paragraph.
A Design Pattern can be a starting point for existing code, the goal design for new code, the destination for a sequence of refactoring moves, or any combination thereof. It can be an area of study for someone attempting to advance their skills, a collection point for knowledge about how to address certain kinds of problems, and a phrase in a high-bandwidth conversation between developers.

There are more advantages but these six are really, really important.

All of those things are either directly or indirectly about solving problems. It stands to reason that design Patterns are tools we use in solving problems. They are far from the only part of solving a problem, they represent a critical aspect nevertheless.

To me, that's where Design Patterns live: in the act of solving a problem or helping someone else do the same.

I like positioning Patterns as solution elements. It connects them to problems the way they should be connected to problems. It connects them to implementations the way they should be connected to implementations. It gives us a language to describe, refine and expand them appropriately.

Is it perfect for everyone, always? Probably not.

Is it good enough for me, now? You bet it is.

Wednesday, October 31, 2018

Design Patterns Are Indicated by Problems

If patterns don't live in code, drawings, or any implementation artifacts, then where must they live.

Some have suggested that they live in problems. There is substantial evidence to support this claim.

I'm not sure if I'm totally on board with the idea that a design pattern lives in a problem but I will definitely agree that the problem you are addressing is one of the primary factors influencing which pattern applies.

In other words: problems indicate patterns.

Two kids sit on or against children's furniture, working intently on computers. Mom is holding a ghost costume and a broom with a witch's costume. She says "Have either of you heard of the Trick or Treat pattern?"

Tuesday, October 30, 2018

Design Patterns Don't Live in the Code

Two stick figures are conversing between their desks. One says "I've invented a new way to use the Strategy pattern. Look: these all implement the same interface. Each one can just call the next Strategy if it doesn't know how to do its job!

In my previous post, I wrote that design patterns don't live in the drawings. You can't just replicate a picture someone drew a bunch of times and get a good design.

A natural next conclusion is that they must live in the code. This is also not the case.

Monday, October 29, 2018

Design Patterns Aren't the Drawings

An easy, and very forgivable mistake is to think that the drawings in the original book, Design Patterns, are the essence of the patterns.

One reason someone might make the mistake is that the drawings proliferate like dandelions.

Thursday, October 25, 2018

Fundamental Tenets of Design Patterns Thinking

Four quadrants: an arrow showing pressure flow into a class from use, a switch statement with a "buster" circle, a class coupling to the top of a hierarchy, and preference of usage over inheritance

There are four basic principles of deep design thinking. These are all paraphrased to make them easier to digest in 2018.
  • Start with contracts and drive implementations to serve needs.
  • Encapsulate variation so you need only attend to it in the fewest places possible.
  • Couple to the highest abstractions possible.
  • Delegate between objects rather than inheriting between classes.
These principles underlie all the design patterns wherever they apply.

One could write a book on these four principles. In fact, a lot of people have.

I'm going to dig into each of these more deeply in subsequent posts.

Thursday, October 18, 2018

Be Careful with the Word "Just"

People cower before a giant robot, bristling with weapons. One person says "Don't worry. It's just some metal and stuff."


I hear these kinds of claims a lot...
"It's just UI logic."
"That's just database-connectivity code."
This is generally as a preamble to an argument that the code in question can't or should not be tested.

The word "just" sometimes is used in its true meaning. That is, sometimes you have a method that really does just do some small thing that's unduly expensive to test.

Most of the time, the word "just" hides something else. Often the phrase "that's just X" really means "I can't imagine how to separate everything in that method that's not X from X."

One might be tempted to call this "just"-ification.

It's okay to have some of your code not be covered in tests. You just shouldn't feel the urge to explain yourself when you do. It should be self-evident that a method or class is just glue code to some peripheral component.

If you find yourself explaining to someone else - or to yourself - that a block of code is just something, make sure you take a beat and verify. Is it really "just", or is it "just"-ification?