A couple of months ago I shared some tips & tricks to help you prevent ending up in NuGet dependency hell. As a big fan of the SOLID principles, I’ve always wondered why nobody thought of applying these principles on the package level. If SOLID can help you to build cohesive, loosely coupled components which do one thing only and do that well, why can’t we do the same thing on the package level. As it happens, my colleague Jonne enthousiastically referred me to the book Principles of Package Design by Matthias Noback. It’s available from Leanpub and does exactly that, offering a couple of well-named guidelines inspired by SOLID that will help you design better NuGet, NPM or whatever your package management solution of choice uses.
The first half of the 268 pages provide an excellent refresh of the SOLID principles. He even does a decent job of explaining the inversion of control principle (although I would still refer to the original to really grasp that often misunderstood principle). After that he carefully dives into the subtleties of cohesion as a guiding principles before he commences on the actual package design principles. The examples are all in PHP (yeah, really), but the author clearly explains how these would apply to other platforms. Notice that this post is mostly an exercise for me to see if I got the principles right, so I would highly recommend buying the .epub, .mobi or PDF from Leanpub. It’s only 25 USD and well worth your money. So let’s briefly discuss the actual principles.
The Release/Reuse Equivalency Principle
IMHO, the first principle has a rather peculiar name. Considering its purpose, it could have been called The Ship a Great Package Principle. The gist of this principle is that you should not ship a package if you don’t have the infrastructure in place to properly support that. This means that the package should follow some kind of clear (semantic) versioning strategy, has proper documentation, a well-defined license, proper release notes, and is covered by unit tests. The book goes into great lengths to help you with techniques and guidance on ensuring backwards compatibility. Considering the recentness of the book and the fact it mentions Semantic Versioning, I would expected some coverage of GitFlow and GitHubFlow. Nonetheless, most of the stuff mentioned here should be obvious, but you’ll be surprised how often I run into a unmaintainable and undocumented package.
The Common Reuse Principle
The purpose of the second principle is much clearer. It states that classes and interfaces that are almost always used together should be packaged together. Consequently, classes and interfaces that don’t meet that criteria don’t have a place in that package. This has a couple of implications. Users of your package shouldn’t need to take the entire package if they just need a couple of classes. Even worse, if they use a subset of the package’s contents, there must not be a need to get confronted with additional package dependencies that have nothing to do with the original package. And if that specific package has a dependency, then it’s an explicit dependency. A nice side-effect of this principle is that it makes packages Open for Extension and Closed for Modification.
I’ve seen packages that don’t seem to have any dependencies until you use certain classes that employ dynamic loading. NHibernate is clear violator of this principle in contrast to the well-defined purpose of the Owin NuGet package. My own open-source library, Fluent Assertions also seems to comply. When a contributor proposed to build a Json extension to my library, I offered to take in the code and ship the two NuGet packages from the same repository. So if somebody doesn’t care about Json, it can use the core package only, without any unexpected dependencies on NewtonSoft.Json.
The Common Closure Principle
The third principle is another one that needs examples to really grasp its meaning. Even the definition doesn’t help that much:
The classes in a package should be closed against the same kinds of changes. A change that affects a package affects all the classes in that package.
According to many examples in the book, the idea is that packages should not require changes (and thus a new release) for unrelated changes. Any change should affect the smallest number of packages possible, preferably only one. Alternatively, a change to a particular package is very likely to affect all classes in that package. If it only affects a small portion of the package, or it affects more than one package, chances are you have your boundaries wrong. Applying this principle might help you decide on which class belongs in which package. Reflecting on Fluent Assertions again, made me realize that even though I managed to follow the Common Reuse Principle, I can’t release the core and Json packages independently. A fix in the Json package means that I also need to release the core package.
The Acyclic Dependencies Principle
For once, the fourth principle discussed in this book is well described by its definition:
The dependency structure between packages must be a directed acyclic graph, that is, there must be no cycles in the dependency structure.
In other words, your package should not depend on a package which dependencies would eventually result in cyclic dependency. At first thought, this looks like an open door. Of course you don’t want to have a dependency like that! However, that cyclic dependency might not be visible at all. Maybe your dependency depends on something else that ultimately depends on a package that is hidden in the obscurity of all the other indirect dependencies. In such case, the only way to detect that, is to carefully analyze each dependency and create a visual dependency graph.
Another type of dependencies that the book doesn’t really cover are diamond dependencies (named for the visual dependency graph). Within the .NET realm this is a quite a common thing. Just consider the enormous amount of NuGet packages that depend on NewtonSoft’s Json .NET. So for any non-trivial package, it’s quite likely that more than one dependency eventually depends on that infamous Json library. Now consider what happens if those dependencies depend on different versions.
The book offers a couple of in-depth approaches and solutions to get yourself out of this mess. Extracting an adapter or mediator interface to hide an external dependency behind is one. Using inversion-of-control so that your packages only depend on abstract constructs is another. Since the book is written by a PHP developer, it’s no surprise that it doesn’t talk about ILMerge or its open-source alternative ILRepack. Both are solutions that will merge an external .NET library into the main DLL of your own package. This essentially allows you to treat that dependency as internal code without any visible or invisible DLL dependencies. An alternative to merging your .NET libraries is to use a source-only NuGet package. This increasingly popular technique allows you to take a dependency on a NuGet package that only contains, surprise, source code that is compiled into your main package. LibLog, TinyIoc and even my own caching library FluidCaching uses this approach. It greatly reduces the dependency chain of your package.
The Stable Dependencies Principle
The name of the principle is quite self-explanatory, but the definition is even clearer.
The dependencies between packages in a design should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable than it is.
In other words, you need to make sure you only depend on stable packages. The more stable your dependency, the more stable your package is going to look to your consumers. Determining whether a package is stable or not isn’t exact science. You need to do a bit of digging for that. For instance, try to figure out how often a dependency introduced a breaking change? And if they did, did they use Semantic Versioning to make that clear? How many other public packages depend on that package? The more dependents, the higher the chance that the package owners will try to honor the existing API contracts. And how many dependencies does that package have? The more dependencies, the higher the chance some of those dependencies introduce breaking changes or instability. And finally, check out its code and judge how well that package follow the principles mentioned in this post? The book doesn’t mention this, but my personal rule-of-thumb to decide on whether I will use a package as a dependency is to consider the circumstances when the main author abandons the project. The code should either be good enough for me to maintain it myself/ourselves, or the project should be backed by a large group of people that can ensure continuity.
The Stable Abstractions Principle
Now if you understand (and agree) with the Stable Dependencies principle, you’ll most definitely understand and agree with the Stable Abstractions Principle. After all, what’s more stable? An interface, an abstract type or a concrete implementation? An interface does not have any behavior that can change, so it is the most stable type you can depend on. That’s why a well-designed library often uses interfaces to connect many components together and quite often provides you would with an interface-only package. For the same reason, the Inversion of Control principle tries to nudge you in the same direction. In fact, in the .NET world even interfaces are being frowned on and are being replaced with old-fashioned delegate types. These represent a very tiny and very focused interface so it doesn’t get any more stable than that. And because of their compatibility with C#’s lambda statements you don’t even need to using a mocking library.
So what about you?
The names are not always that catchy and easy to remember, mostly because they use the same wording, but the underlying philosophy makes a lot of sense to me. I’ve already started to re-evaluate the design decisions of my projects. The only thing I was hoping to read more about is the explicit consequence of building a component or package as a library versus building it as a framework. This is something that heavily influences the way I’m building LiquidProjections, my next open-source project.
So what do you think? Do you see merits in these principles? Do they feel as helpful as the original SOLID principles? I’ve love to know what you think by commenting below. Oh, and follow me at @ddoomen to get regular updates on my everlasting quest for better designs.
TL;DR In this post I will explain the issue that can happen during the importing django fixture files into testing database. Django fixture files enable developer to prepare testing data. We usually put in those files data that is static and essential for data model. For example, list of countries. The problem is that developer needs … Continue reading Be careful with django fixture files →
Earlier this week I was a co-presenter for a 2 day workshop on SBTM (Session Based Test Management) at Unity. While I have a solid amount of relevant experience (speaking at conferences, organising and speaking at meet-ups, being a co-instructor f…
The latest The Testing Show has been released. Some interesting thoughts and comments have been spinning through my head since we recorded this episode. For a number of organizations, the “tester” as we have long identified them, is going away. In this…
This month’s Lean Coffee was hosted by us at Linguamatics. Here’s some brief, aggregated comments and questions on topics covered by the group I was in.How important is exploratory testing?When interviewing tester candidates, many have …
(Reaction to an English speaking source, so Hebrew will come later)
I listened to the Gem Hill’s latest episode of “let’s talk about tests baby” (Ep. 62), where she interviewed Neil Studd and they spoke about some very interesting topics – from motivation, to mental health, working 9 to 5 and coping & promoting change. It was a great episode that I will have to listen to again at least a couple of times to process everything that went there.
As usual, Neil is is always quicker than I am in posting something related, so you can read some background to this interview in his blog.
While I listened to the discussion I re-thought my views on 9 to 5 testers, and despite initially being pretty much in favor of the idea, and that there wasn’t a single argument voiced against this approach, I started wondering whether 9 to 5 really is a valid choice. Each and every argument for not doing anything work-related after work is sound and solid, yet somehow each such argument just enforced my gut feeling that it is only a valid reason to completely avoid participation if you don’t care.
But before I start, I just want to make sure that I’m clear on what I call 9 to 5 testers, since while I was writing this post I found that it’s not the hour cap that bothers me, but what I associate with this term. For me, a 9 to 5 tester is someone who comes to work every morning, leaves somewhere in the evening or even late at night, and have exactly zero interaction with a testing community. They might work 14 hours a day, but if they know only what they see in their own work, I call them 9 to 5 testers.
Another assumption I am making and don’t really feel the need to justify, is that testing is an intellectual work – which means that one must take interest in it in order to become really good. I’m not sure I would say that al 9 to 5 testers are bad testers (though I am quite tempted to say that), but they sure can be much better.
I have mainly the projection of how I feel about my profession – I like being a tester. I think that when you do something you like, you cannot simply stop thinking about it when your shift is over. Just like any other subject – if you invest time thinking about it, you start seeing and interpreting other matters from that unique perspective – football (or soccer, as some of you might call this game) fans, for instance, will often borrow football terms to describe events or ideas that have nothing to do with football since the terms and thought patterns are readily available in their mind. This way, testing, if you care about it, doesn’t stop when we’re not at the office – we will still smile when we’ll see this car and still use insights we learned as testers, or use what we experience outside of work to improve our testing skills. When I can put something aside and say “I don’t do anything about it outside of the time I have to”, it means that I don’t care. Putting aside something I care about is a gradual process – I decide to do something else, then, after the third time I decide it’s time to wrap things up, I actually do that, and I will still occasionally think about it.
Neil & Gem mentioned some good and valid reasons for testers not to participate, but while each such reason sounds convincing, I found that I don’t see them as good enough to completely avoid participating. There were two distinct reasons I could identify: Having other commitments (such as family or other interests) and Being an introvert, which means one feels drained when socializing.
When facing those reasons as binary questions – there’s a clear cut: Work stuff should not trump one’s personal life, and forcing someone to overcome their discomforts and fears just because I say so is quite inappropriate. But the question at hand is not Boolean – it’s a scale, and there’s a world of difference between turning down the dial to a comfortable level and switching it off. I came to this understanding when I’ve heard Neil describing himself as an introvert, and mentioning that his way of coping with the massive energy drain at CAST was being the first one leaving in order to crash at the hotel (which, at least from my perspective, was completely invisible. I think I recall at least one evening where I left before him, simply since I wanted to get five or six hours of sleep). While I can’t really imagine how does being an introvert feels, since I tend to take energy out of interaction (which makes me an extrovert, I think) – but unless we take the extreme case of a person left in a state of acute lethargy or anxiety – Neil describes the perfect solution: Moderate your participation level. One does not have to attend each and every event, and it’s perfectly fine to leave a meetup after an hour or so. It’s also ok to prefer small events where you can get to know people. And even if participating in any sort of event is extremely difficult, there are ways to participate online – Writing a blog, or commenting in a web discussion. You gain a bit less from written discussions, but it’s still a way to keep track on what’s going. People can just share something interesting they read with their team.
Having other interests that take time is a great reason to skip a specific event, or avoid taking on big commitments, but given enough time ahead and high enough priority, scheduling an evening event once every six monts or so is feasible. If someone says “I don’t mind going, it’s only that I can’t fit my schedule”, that person is saying “I don’t care enough to make time for it”. Someone with a tight schedule can still find time to do things that are important enough – it might not be as often as desired, but aiming for an evening once or twice a year is not impossible. There are also some events that take place during work hours – it will take a bit more effort to get permission to attend such an event, but it’s doable.
You might have noticed that despite my claim of not approving the “9 to 5” choice, I don’t expect everyone to start investing heavily outside of work – There will always be different levels of involvement between people, and that’s fine. I get to work every day on my bicycle, and I even enjoy riding a bit in the countryside in weekends. despite that, I wouldn’t call myself a bicycle enthusiast – I don’t own a 10,000$ bike, have no idea what’s the difference between the different brands and part names and I don’t spend my time in any biking forum looking for my next trail. Still, since it’s something I enjoy – I invest in it a bit. I own a nice pair of bike, I join a riding event once a year and siphon some knowledge about bicycle maintenance and stuff from my local experts. It’s a nice thing to talk about with others who bike. Similarly, a tester who has this amount of interest in testing is perfectly fine. I just find it really difficult to imagine such a tester remaining invisible – even such level of care should be visible at least to some of the co-workers around.
ניל וג’ם העלו כמה סיבות לא רעות בכלל להיות לא מעורבים יותר בקהילת הבודקים (יש יותר מקהילה אחת, אבל זה פחות חשוב לענייננו), ובפרט, אני חושב שאפשר לבודד את הטיעונים שלהם לשני טיעונים מרכזיים – חיים מחוץ לעבודה, והיות האדם מופנם (יש לציין, “מופנם” אינו תרגום מדוייק של introvert במקרה הזה, שכן לא מדובר בביישנות, אלא באנשים שאינטראקציה חברתית שואבת מהם אנרגיה, בניגוד לטיפוס המוחצן שעבורו מפגשים כאלה הם זריקת מרץ של ממש). אם מסתכלים על השאלות האלו כעל שאלות בינאריות, אין ספק שכל אחת מהן בפני עצמה היא סיבה מצויינת לא להשתתף. זה ברור לגמרי שאנשים צריכים לעבוד כדי לחיות ולא לחיות כדי לעבוד, ולהכריח מישהו להתגבר על חרדות, או לשנות את האופי שלו רק כי אני אומר שצריך זה מאוד לא לעניין.
אלא שלא מדובר פה בשחור ולבן, לא נכון להציב “לא משתתף” לעומת “משתתף”, כי השתתפות היא סקאלה די רחבה. אם מסתכלים על מידת ההשתתפות, יש הבדל של שמיים וארץ בין “משתתף, אבל רק מעט במידה שנוח לי” ובין “לא משתתף”. מבחינתי, רגע ההבנה היה כששמעתי את ניל מגדיר את עצמו כמופנם ומספר על החוייה שלו בCAST, בה הוא מצד אחד נהנה מאוד, מצד שני היה הראשון לצאת בכל ערב כדי לקרוס תשוש בחדרו (לי זכור לפחות ערב אחד בו עזבתי לפניו פשוט כי רציתי להספיק לישון חמש-שש שעות בלילה, כך שמבחינתי המופנמות שלו הייתה שקופה לחלוטין). תיאור הבעייה, למעשה, מכיל גם את תיאור הפיתרון – צריך למצוא את מידת ההשתתפות הנוחה, שלא יוצרת עומס אישי מוגזם. לא חייבים להגיע לכל אירוע קיקיוני שיש בסביבה, ולא חייבים לצאת לכנסים רב-יומיים. זה גם בסדר גמור להגיע למיטאפ ולצאת אחרי שעה-שעה וחצי. ואם המצב באמת קשה – אפשר להשתתף בדיונים אונליין – אפשר לכתוב בבלוג, או להגיב בדיוני פורום כאלה או אחרים (יש גם פייסבוק, אבל אני מתעלם ממנו בכוונה). כן, מקבלים קצת פחות מדיונים כתובים, אבל גם זה משהו. אפשר גם לחלוק עם החב’רה במשרד משהו מעניין שקראתם ולקשקש על זה כמה דקות – מעורבות בקהילת בודקים לא חייבת להיות מעורבות בקהילת בודקים מחוץ לעבודה.
מחויבויות אישיות הן סיבה מצויינת לא להגיע לאירוע ספציפי, או לא להתחייב לשום דבר ארוך טווח או גוזל זמן, אבל בהינתן התראה ארוכה מספיק מראש – אפשר בהחלט לפנות קצת זמן לכל דבר חשוב מספיק, כך שאם מישהו לא מתערב בקהילת בודקים – לא מגיע לאף אירוע, לא משתתף באף דיון כתוב ולא מוציא את האף מחוץ למשרד והסיבה לכך היא “זה פשוט לא מסתדר לי בלו”ז “, המסקנה היחידה שאני יכול להגיע אליה היא שלא אכפת לו מספיק כדי למצוא לזה זמן. כי אם קידום מקצועי בתחום הבדיקות היה מעניין מספיק, אפשר היה לדחוס הגעה למיטאפ פעם בחצי שנה, או לשכנע את ההנהלה לוותר על בוקר אחד וללכת לאירוע שמתרחש בשעות היום (היה אחד שמטריקס ארגנו לא מזמן).
בטח שמתם לב שלמרות שאני מוחה בתוקף נגד בודקי תשע עד חמש, אני לא ממש מצפה מכולם להפוך סדרי עולם ולהשקיע שעות על גבי שעות מחוץ לזמן העבודה, או לבזבז חצי מיום העבודה על דברים לא קשורים – תמיד יש רמות מעורבות שונות, וזה בסדר גמור. אני, למשל, מגיע לעבודה לא מעט על אופניים, וגם נהנה לרכוב לטיולים מדי פעם. עדיין, לא הייתי מגדיר את עצמי כחובב אופניים – אין לי אופניים בשווי עשרת אלפים דולר, אני לא מכיר את כל השמות המשונים שיש לחלקי האופניים (עשר נקודות למי שיודע לומר מה זה “נאבה” בלי לבדוק) ואני לא מבלה בפורומים של רוכבי אופניים בחיפוש אחרי המסלול הבא. למרות זאת – כיוון שזה משהו שאני נהנה ממנו, כן השקעתי קצת מאמץ ולמדתי איך לתחזק את האופניים, יש לי זוג אופניים נחמד ואפילו השתתפתי בסובב ירושלים. מדי פעם אני שואב קצת מידע ממומחי האופניים שיש בסביבתי, וזה נושא נחמד לשיחת חולין עם רוכבי אופניים אחרים. בעיקר – כל מי שמכיר אותי יודע שאני רוכב על אופניים. באופן דומה – נראה לי סביר לצפות שאנשים סביב בודק תוכנה ידעו שבדיקות תוכנה זה משהו שמעניין אותו – לא בהכרח הקדימות העליונה, אבל משהו שהוא מתעניין בו.
TL;DR This is third part in series how to kill UI regression testing. It is about git source control system and its web application part, github, bitbucket or gitlab. I have already wrote about this topic in Product moving parts as a source for test strategy, and Micro tracking changes for regression test. In this post, … Continue reading How to kill UI regression testing: git source control →
The first post on Hiccupps was published five years ago this week. It’s called Sign Language and, reading it back now, although I might not write it the same way today, I’m not especially unhappy with it. The closing sentence still feels like a us…
A few months ago, as I was walking my two daughters to school, one of their classmates gave me the thumbs up and shouted “heeeyyy, Captain!”Young as the lad was, I congratulated myself that someone had clearly recognised my innate leadership capabiliti…
Olof Svedström has worked as an engineering lead within software testing and quality at Spotify for 5 years, during a period when he has been part of the journey where they have grown from 5 to 100 million active users and from 150 to 2000+ employees. Before Spotify he spent some years as a tester in a spectrum of companies, ranging from small product ones to international giants.
Spotify engineering model is fairly well known in the tech community, what’s it like, working as a tester, under this model?
Did joining Spotify change your perspective of testing in terms of how it can be done?
Spotify is one of the most used apps I’ve seen here in Sweden, seems like everyone has an account. Does being an actual user of Spotify change how you test? If so, how?
What advice would you give to someone who is starting out their testing career?