-
12 votes
-
Lyft files first for IPO in litmus test for the industry
16 votes -
Code Quality Tip: Cyclomatic complexity in depth.
Preface Recently I briefly touched on the subject of cyclomatic complexity. This is an important concept for any programmer to understand and think about as they write their code. In order to...
Preface
Recently I briefly touched on the subject of cyclomatic complexity. This is an important concept for any programmer to understand and think about as they write their code. In order to provide a more solid understanding of the subject, however, I feel that I need to address the topic more thoroughly with a more practical example.
What is cyclomatic complexity?
The concept of "cyclomatic complexity" is simple: the more conditional branching and looping in your code, the more complex--and therefore the more difficult to maintain--that code is. We can visualize this complexity by drawing a diagram that illustrates the flow of logic in our program. For example, let's take the following toy example of a user login attempt:
<?php $login_data = getLoginCredentialsFromInput(); $login_succeeded = false; $error = ''; if(usernameExists($login_data['username'])) { $user = getUser($login_data['username']); if(!isDeleted($user)) { if(!isBanned($user)) { if(!loginRateLimitReached($user)) { if(passwordMatches($user, $login_data['password'])) { loginUser($user); $login_succeeded = true; } else { $error = getBadPasswordError(); logBadLoginAttempt(); } } else { $error = getLoginRateLimitError($user); } } else { $error = getUserBannedError($user); } } else { $error = getUserDeletedError($user); } } else { $error = getBadUsernameError($login_data['username']); } if($login_succeeded) { sendSuccessResponse(); } else { sendErrorResponse($error); } ?>A diagram for this logic might look something like this:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ +-----------------+ | | | | | Username +--->+ Set Error +--+ | Exists? | No | | | | | +-----------------+ | +--------+--------+ | | | Yes | | v | +--------+--------+ +-----------------+ | | | | | | | User Deleted? +--->+ Set Error +->+ | | Yes| | | +--------+--------+ +-----------------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | | User Banned? +--->+ Set Error +->+ | | Yes| | | +--------+--------+ +-----------------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | | Login Rate +--->+ Set Error +->+ | Limit Reached? | Yes| | | | | +-----------------+ | +--------+--------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | |Password Matches?+--->+ Set Error +->+ | | No | | | +--------+--------+ +-----------------+ | | | Yes | | v | +--------+--------+ +----------+ | | | | | | | Login User +--->+ Converge +<--------+ | | | | +-----------------+ +---+------+ | | +-----------------+ | v +--------+--------+ | | | Succeeded? +-------------+ | | No | +--------+--------+ | | | Yes | | v v +--------+--------+ +--------+--------+ | | | | | Send Success | | Send Error | | Message | | Message | | | | | +-----------------+ +-----------------+It's important to note that between nodes in this directed graph, you can find certain enclosed regions being formed. Specifically, each conditional branch that converges back into the main line of execution generates an additional region. The number of these distinct enclosed regions is directly proportional to the level of cyclomatic complexity of the system--that is, more regions means more complicated code.
Clocking out early.
There's an important piece of information I noted when describing the above example:
. . . each conditional branch that converges back into the main line of execution generates an additional region.
The above example is made complex largely due to an attempt to create a single exit point at the end of the program logic, causing these conditional branches to converge and thus generate the additional enclosed regions within our diagram.
But what if we stopped trying to converge back into the main line of execution? What if, instead, we decided to interrupt the program execution as soon as we encountered an error? Our code might look something like this:
<?php $login_data = getLoginCredentialsFromInput(); if(!usernameExists($login_data['username'])) { sendErrorResponse(getBadUsernameError($login_data['username'])); return; } $user = getUser($login_data['username']); if(isDeleted($user)) { sendErrorResponse(getUserDeletedError($user)); return; } if(isBanned($user)) { sendErrorResponse(getUserBannedError($user)); return; } if(loginRateLimitReached($user)) { logBadLoginAttempt($user); sendErrorResponse(getLoginRateLimitError($user)); return; } if(!passwordMatches($user, $login_data['password'])) { logBadLoginAttempt($user); sendErrorResponse(getBadPasswordError()); return; } loginUser($user); sendSuccessResponse(); ?>Before we've even constructed a diagram for this logic, we can already see just how much simpler this logic is. We don't need to traverse a tree of if statements to determine which error message has priority to be sent out, we don't need to attempt to follow indentation levels, and our behavior on success is right at the very end and at the lowest level of indentation, where it's easily and obviously located at a glance.
Now, however, let's verify this reduction in complexity by examining the associated diagram:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ +-----------------+ | | | | | Username +--->+ Send Error | | Exists? | No | Message | | | | | +--------+--------+ +-----------------+ | Yes | v +--------+--------+ +-----------------+ | | | | | User Deleted? +--->+ Send Error | | | Yes| Message | +--------+--------+ | | | +-----------------+ No | v +--------+--------+ +-----------------+ | | | | | User Banned? +--->+ Send Error | | | Yes| Message | +--------+--------+ | | | +-----------------+ No | v +--------+--------+ +-----------------+ | | | | | Login Rate +--->+ Send Error | | Limit Reached? | Yes| Message | | | | | +--------+--------+ +-----------------+ | No | v +--------+--------+ +-----------------+ | | | | |Password Matches?+--->+ Send Error | | | No | Message | +--------+--------+ | | | +-----------------+ Yes | v +--------+--------+ | | | Login User | | | +--------+--------+ | | v +--------+--------+ | | | Send Success | | Message | | | +-----------------+Something should immediately stand out here: there are no enclosed regions in this diagram! Furthermore, even our new diagram is much simpler to follow than the old one was.
Reality is rarely simple.
The above is a really forgiving example. It has no loops, and loops are going to create enclosed regions that can't be broken apart so easily; it has no conditional branches that are so tightly coupled with the main path of execution that they can't be broken up; and the scope of functionality and side effects are minimal. Sometimes you can't break those regions up. So what do we do when we inevitably encounter these cases?
High cyclomatic complexity in your program as a whole is inevitable for sufficiently large projects, especially in a production environment, and your efforts to reduce it can only go so far. In fact, I don't recommend trying to remove all or even most instances of cyclomatic complexity at all--instead, you should just be keeping the concept in mind to determine whether or not a function, method, class, module, or other component of your system is accumulating technical debt and therefore in need of refactoring.
At this point, astute readers might ask, "How does refactoring help if the cyclomatic complexity doesn't actually go away?", and this is a valid concern. The answer to that is simple, however: we're hiding complexity behind abstractions.
To test this, let's forget about cyclomatic complexity for a moment and instead focus on simplifying the refactored version of our toy example using abstraction:
<?php function handleLoginAttempt($login_data) { if(!usernameExists($login_data['username'])) { sendErrorResponse(getBadUsernameError($login_data['username'])); return; } $user = getUser($login_data['username']); if(isDeleted($user)) { sendErrorResponse(getUserDeletedError($user)); return; } if(isBanned($user)) { sendErrorResponse(getUserBannedError($user)); return; } if(loginRateLimitReached($user)) { logBadLoginAttempt($user); sendErrorResponse(getLoginRateLimitError($user)); return; } if(!passwordMatches($user, $login_data['password'])) { logBadLoginAttempt($user); sendErrorResponse(getBadPasswordError()); return; } loginUser($user); sendSuccessResponse(); } $login_data = getLoginCredentialsFromInput(); handleLoginAttempt($login_data); ?>The code above is functionally identical to our refactored example from earlier, but has an additional abstraction via a function. Now we can diagram this higher-level abstraction as follows:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ | | | Attempt Login | | | +-----------------+This is, of course, a pretty extreme example, but this is how we handle thinking about complex program logic. We abstract it down to the barest basics so that we can visualize, in its simplest form, what the program is supposed to do. We don't actually care about the implementation unless we're digging into that specific part of the system, because otherwise we would be so bogged down by the details that we wouldn't be able to reason about what our program is supposed to do.
Likewise, we can use these abstractions to hide away the cyclomatic complexity underlying different components of our software. This keeps everything clean and clutter-free in our head. And the more we do to keep our smaller components simple and easy to think about, the easier the larger components are to deal with, no matter how much cyclomatic complexity all of those components share as a collective.
Final Thoughts
Cyclomatic complexity isn't a bad thing to have in your code. The concept itself is only intended to be used as one of many tools to assess when your code is accumulating too much technical debt. It's a warning sign that you may need to change something, nothing more. But it's an incredibly useful tool to have available to you and you should get comfortable using it.
As a general rule of thumb, you can usually just take a glance at your code and assess whether or not there's too much cyclomatic complexity in a component by looking for either of the following:
- Too many loops and/or conditional statements nested within each other, i.e. you have a lot of indentation.
- Many loops in the same function/method.
It's not a perfect rule of thumb, but it's useful for at least 90% of your development needs, and there will inevitably be cases where you will prefer to accept some greater cyclomatic complexity because there is some benefit that makes it a better trade-off. Making that judgment is up to you as a developer.
As always, I'm more than willing to listen to feedback and answer any questions!
25 votes -
Socialists win big in Chicago
14 votes -
Memes are our generation's protest art
13 votes -
"Deep Adaptation": A paper that predicts an inevitable near-term social collapse due to climate change
26 votes -
The top six medical inventions during the American civil war
9 votes -
Inside Facebook’s war on hate speech: An exclusive embed with Facebook’s shadow government
14 votes -
Feature suggestion: Bookmark posts from front page
I'd like to be able to bookmark posts from the front page. Right now it really isn't an issue yet since posting frequency is low, but I often quickly check the front page for interesting reads,...
I'd like to be able to bookmark posts from the front page. Right now it really isn't an issue yet since posting frequency is low, but I often quickly check the front page for interesting reads, while not having the time to actually read them. I'd like to see a "Bookmark" button on front page posts that allow me to save those posts for later when I actually do have time to read the posts.
For quick scrolls over the front page, tapping the post and then bookmarking is one click too many.
You could argue I'm lazy, I call it efficiency.While on the subject, if I click "bookmark" on a topic, it'll read "bookmarked" but does not offer an "unbookmark" option until I refresh the page. Since I have big thumbs(large bones) I often tap wrong, so it could be nice if there was a quick way to undo this, similar to how we can undo votes.
Edit: this seems to be a bug: it does work for comments.
Edit2: Made this into an issue.24 votes -
Battles - Ddiamondd (2007)
9 votes -
Feature suggestion: Highlighted text in comment automatically creates quote when you respond to that comment
I'm fairly sure it's either a Reddit or RES feature, but whenever I select text in a comment and then click Reply, it'll copy that text to the comment box and add a > in front so it'll turn into a...
I'm fairly sure it's either a Reddit or RES feature, but whenever I select text in a comment and then click Reply, it'll copy that text to the comment box and add a > in front so it'll turn into a quote. It makes it a little quicker to respond to a specific part of someone's message.
I'm no IT bird and as such I don't know if this is something that can be implemented easily(if at all). It'd also require more JS, not sure if that's an issue as well.
In any case, let me know what you think.
Edit: I'd like to suggest something else, should I make a secondary post or append it to this one? I'd like to avoid cluttering up the front page.
37 votes -
Galaxy S10 Plus review
3 votes -
US President Donald Trump ordered officials to give Jared Kushner a security clearance
11 votes -
Farmers markets lies exposed
6 votes -
What are you reading these days? #14
What are you reading currently? Fiction or non-fiction, any genre, any language! Tell us what you're reading, and talk a bit about it. Notes: I could not start the thread yesterday on Friday like...
What are you reading currently? Fiction or non-fiction, any genre, any language! Tell us what you're reading, and talk a bit about it.
Notes: I could not start the thread yesterday on Friday like I used to, I'm sorry for the delay.
Past weeks: Week #1 · Week #2 · Week #3 · Week #4 · Week #5 · Week #6 · Week #7 · Week #8 · Week #9 · Week #10 · Week #11 · Week #12 · Week #13
16 votes -
Running a bakery on Emacs and PostgreSQL
4 votes -
Soy sauce is one of the most important ingredients in Japanese cooking, but chances are you've never tasted the real thing
24 votes -
Logical Consequence
4 votes -
US fake university racket: Students had no way to check Farmington's authenticity
5 votes -
Not all sleep is equal when it comes to cleaning the brain
16 votes -
I made a 2,000-word analysis of Robert Heinlein’s "All You Zombies" (with visuals!)
12 votes -
UC terminates Elsevier subscription citing unstable fees and irreconcilable differences in approach to open research
12 votes -
Shock rise in global measles outbreaks 'disastrous' for children, UN warns
8 votes -
Pedestrian deaths reach highest level in decades, US report says
8 votes -
Donald Trump and Kim Jong-un summit ends in disarray but there are lessons to be learnt, experts say
11 votes -
A sports hijab has France debating the Muslim veil, again
10 votes -
The latest diet trend is not dieting
6 votes -
Jimmy Eat World - Pol Roger
6 votes -
The yum cha (dim sum) rules you need to know
9 votes -
Amazon announces "Project Zero", a program which will allow brands to directly remove counterfeit listings
11 votes -
Momo Challenge, memes, and "Secure, Contain, Protect" (SCP)
First, I apologize if this is inappropriate. I wouldn't be surprised if some folks here saw my mention of the "Momo Challenge" and roll their eyes, but after my brother asked me about it, I looked...
First, I apologize if this is inappropriate.
I wouldn't be surprised if some folks here saw my mention of the "Momo Challenge" and roll their eyes, but after my brother asked me about it, I looked it up last night, and found some interesting stuff happening around it. I guess it's going through a second iteration right now, with supposed images of "Momo," a sculpture of a Japanese witch, and a voice saying to do really graphic stuff. The previous iteration was supposedly messaging a number via WhatsApp, and getting challenges, and threats that if you tell your parents (it's supposedly targeting kids), Momo will get you. The Guardian has a nice write up about the current issue with a picture, you have been warned if you scare easily. Now, she'll tell you to do stuff in a manipulated video. There's even themomochallenge.tk (also spooky if you're sensitive to uncanny sort of stuff like I am), which seems to exist as a way to fluff the story, and asks for what I assume is a requested cryptocurrency transaction (how a kid is going to get crypto to send, I don't know). I may seem like I'm writing something absurd, but this is not in ~creative on purpose, and I feel the propagation of this sort of thing speaks to several problems that may or may not be solvable.
My fascination is with the spread of the idea, and its possible effects. As somebody who occasionally reads the SCP Wiki (not to do with Secure Copy Protocol), I noticed something interesting in the rapid spread of this meme, and am sure sociologists would describe it differently. It behaves (insofar as a meme is an entity with a life or intelligence) in a way SCP would describe as "infohazardous" or "cognitohazardous." They don't mean the same thing: The information is a hazard (infohazard) because you know have this bomb sitting in your lap. You can warn people, but they may go out, see the supposed deaths, and believe it, or you can get a chain of people warning others. In either case, you pass the ball. The meme grows.
It is cognitohazardous for the reason that this hoax, by design, preys on fear. Just typing this, the face is burned into my vision (again, I'm sensitive), I'm home alone, and becoming rather shaky as I jump to look behind me at random noises. The chosen image of the sculpture was selected for this reason, it is deeply unsettling, shakes your rational mind, and you're potentially induced into believing it. I have, in a way, fallen victim to this.
The question comes, going back to my SCP reference: How can this be contained? I'm not looking to start a task force, or enlist people's help, but this is obviously not the first time this has happened with things from Satanic rituals and 2016(?)'s Blue Whale. My mom got swept up by the Satanic thing in the 90s, I watched a video about satanic sacrifices before Halloween 1997, I think, that she got from her church, so I have some experience from the other side. My primary concern is not that children are being compelled to kill themselves, but that the ensuing panic moral panic alone can cause psychological trauma and rampant misinformation. Is it possible to convince believers that something like this isn't real before copycat stuff comes out?
26 votes -
Decline in HIV infections stalls as Trump administration aims to end epidemic
5 votes -
Tesla launches long-awaited standard Model 3 starting at $35,000
29 votes -
Announcing Rust 1.33.0
10 votes -
Disney's Star Wars: Galaxy's Edge is a tour de force of technology and world building
11 votes -
Pac-Man: The untold story of how we really played the game
10 votes -
How blockchain is being applied to improve the world and its potential to solve major world problems
2 votes -
EFF announces "Fix It Already" campaign to demand fixes for specific issues from nine major tech companies and platforms
42 votes -
All Medium paywalled stories are now free and unmetered when you’re coming from Twitter
@ev: All @Medium paywalled stories are now free and unmetered when you're coming from Twitter.
20 votes -
Extract clean(er), readable text from web pages via the Mercury Web Parser.
8 votes -
YouTube bans comments on videos of children
35 votes -
Trying to figure out my personal craziness
I hope this is the appropriate Tilde for this. If no one has any input it will still have helped me to type this out. TL;DR In over my head with marriage, foster care, family, and work. My wife...
I hope this is the appropriate Tilde for this. If no one has any input it will still have helped me to type this out.
TL;DR In over my head with marriage, foster care, family, and work.
My wife and I became foster parents about 1.5 years ago with the intention to not adopt, but to care for children 3 and under while bio parents worked to regain custody or other permanent placements were arranged. Our first placement was two girls (7 mo and 2.5 yrs) despite wanting to do just one kid at a time (especially to start). We had them for 6 weeks and mom got them back. We had another placement (8 mo boy) for about another 6 weeks. There was a considerable lull and we were getting frustrated about not getting any new placements when the girls from our first placement were placed into custody again. So we were able to take them in again (now about 1.2 and 3.5 yrs). FF to now and we've had them for about 6 months.
We never really intended to have more than one child and for quite this long and we're struggling. My wife has always had a little less ability to weather stressful situations like this and these last 2-3 weeks I'm carrying a lot of weight. In the meantime, bio mom has gotten pregnant and there's not another hearing regarding custody for another 9 months. We fully expect that she will not be able to take them back at that time (or really realistically ever). What should probably happen would be that the county could place the kids into permanent custody (basically getting them adopted). However, from what we've heard from other foster families, temporary custody could drag on for years.
So, our main dilemma is this. We are not equipped (as a couple) to care for these kids for years. With the likely prospect of no change in custody in the near future, it feels like the best thing for these kids would be to get them into the care of someone looking to do this long-term, perhaps to eventually adopt. That being said, we absolutely love them and it feels like some kind of betrayal to force them to make yet another transition. On the other hand, with our limitations, it seems like that is inevitable anyway. Do we try to make that happen sooner?
Some other data points:
Our fostering license expires in October (about a month after the hearing is scheduled) and we don't intend to continue fostering (at least for a while, and definitely not with our current agency).
We don't have many family members close by to give us a hand with the kids, making us feel isolated and making it hard to get breaks from the kids. Our agency has not been very helpful with lining up respite care, but we're trying to be more aggressive about that now.
I've got things pretty well lined up to retire in about 5 years. My company is also just now kicking off a major project of a similar time frame and I'm in a good position to really make a mark before moving on. It will probably require some serious time commitments and effort to do it the way I want to.Thanks for listening.
12 votes -
Fossil: VCS with integrated wiki, bug tracking, forums, and technotes; by the author of SQLite
10 votes -
Animation of Earth's magnetic pole shift
7 votes -
Players who hate Overwatch's Brigitte are harassing her voice actress
14 votes -
Johnny Manziel released, barred from other CFL teams
4 votes -
Breathtaking new NASA images show Jupiter’s otherworldy storms
5 votes -
What are some things other people dislike that you quite enjoy?
Could be a game, book, movie, song, etc that is generally considered subpar. Personally, I quite like a lot of Eminem's new music, although I know it's an unpopular opinion. It certainly doesn't...
Could be a game, book, movie, song, etc that is generally considered subpar. Personally, I quite like a lot of Eminem's new music, although I know it's an unpopular opinion. It certainly doesn't hit the same highs and there are a lot of stinkers but I still think some of it is quite good and worth a listen despite the circlejerk. I've also been playing Just Cause 4 lately, and although it certainly isn't a masterpiece and I will say the story is below the others, to me Just Cause was never about the story. It's about getting in there and just having fun causing chaos and generally messing around.
37 votes -
Android is helping kill passwords on billions of devices
11 votes -
Can we make the new "Back to top" link optional?
I just noticed we got a back to top link, floating on the bottom right. It is easy to block on desktop, but on mobile, not as easy. I think it'd be great it we had an option to disable it in user...
I just noticed we got a back to top link, floating on the bottom right. It is easy to block on desktop, but on mobile, not as easy. I think it'd be great it we had an option to disable it in user settings.
11 votes