Let's get this one question out of the way, right off the bat. Why RSpec? or more specifically - why RSpec instead of MiniTest?
For me, the answer was provided with a simple empirical test. One of my junior developers desperately wanted us to use RSpec on our project instead of Test::Unit (precursor of MiniTest). We decided it to give it a trial. I don't think we wrote tests faster. Or that the specs ran faster. But... my fellow developers on this project wrote better tests by far than they had been writing using Test::Unit.
Better tests in this case mean... more finely grained, better focused. Where before we wrote a single test with 15 or more asserts, now we wrote 8 or 10 specs, most with single expectations.
While I am certain that it was possible for these developers to write better, more finely grained tests using Test::Unit and a little discipline, I am also convinced that we wrote better tests by default in RSpec, because of the way in which the specs are structured, and described.
So ever since, I have advocated for RSpec on every project I work on.
Now, it does take a little longer to get up to speed using RSpec, but once you have the basics down, the rich environment of the RSpec core, combined with separate libraries for expectations & mocking provide both power and flexibility. If you don't like rspec-mock, you can go ahead and substitute the mocking/stubbing framework of your choice. And rspec-rails provides a drop-in replacement for the default Rails testing framework.
The RoR4Real Advanced Topics workshop - Better Testing with RSpec - will help you over that speed-bump of getting started using RSpec, and introduce you to the full power of the RSpec environment covering:
Setting up your project with RSpec
describe & context blocks
expectations in detail
using test doubles
More advanced concepts
writing your own matchers
the power of factories
integration testing with Capybara
So, to get back to the original question, "Why RSpec", let's see what one of the authors of The RSpec Book had to say:
RSpec is not just about RSpec. It's about BDD. It's about encouraging
conversation about testing and looking at it in different ways. It's
about illuminating the design, specification, collaboration and
documentation aspects of tests, and thinking of them as executable
examples of behaviour. -- David Chelimsky
And that's why I use RSpec. If you'd like to write better tests in RSpec like a pro, you should sign up (and get 50% off!!) for one of my Advanced Rails Workshops now:
I had the opportunity last week to teach one of the Calgary based Girls Learning Code workshops for the first time. It was quite a learning experience, for everyone, so I thought I'd write up some of the fun things we learned.
I was asked if I'd be interested in teaching this workshop back in December, and I immediately said yes. Having already taught and mentored for the Ladies Learning Code workshops, I thought teaching kids would be fun. Like the LLC workshop, I knew that this workshop had already been given in Toronto, and that the materials from that would be available.
Ksenia asked me to review the materials, so I did. It looked like a "dumbed down", shorter version of the adult workshop. In a fit of laziness, I just said it would be fine. However, when Ksenia followed up with me, and mentioned that the material was a little ... dry, and lacking in "fun factor", I had to confess to having similar thoughts. So, I started investigating ways of making the workshop "more fun".
The first thing that sprung to mind was KidsRuby.com. After a quick review of the website, and some of the training materials, I was sold, especially since KidsRuby has embedded Artoo.io, and you can program ROBOTS with it. I have a 13 year old nephew, and he absolutely loves the Sphero I got him as a Christmas present, after seeing the Artoo.io intro at RubyConf 2013.
Unfortunately, it seems that KidsRuby is in a bit of flux at the moment. The installers don't work on the most recent releases of OSes. It seemed to me that if we couldn't guarantee it would run for all the students in the class, we really couldn't use it. I did download the source materials for the installer and attempt to get the installer building/working so that I could fix it up, but I had problems with it, and no one was able to respond to my problem reports over the period of a couple of weeks), so I had to give it up. (Not throwing blame around here. Open source can be a labour of love, but sometimes real life gets in the way. I was on a schedule, however...)
So, we defaulted back to the basic RubyInstaller, the command-line, and editing files with Sublime Text. Not ideal for kids, and certainly more work for the mentors, but it was good enough.
Now, about those course materials...
I reviewed some of it, in an overview fashion, with my nephew. He agreed with my first impression that the Twitter example wouldn't be that interesting to kids. In his words... "Everyone HAS a Twitter account, but no one actually USES it." So, the Twitter example had to go.
A second issue arose from that review. The Madlibs examples are cool and a lot of fun. But the original class was presented to 13 year olds, who could all be expected to understand the parts of speech (nouns, verbs, adjectives, adverbs). In our class, we had 8-13 year olds (actually, we also had a couple 6 year olds o_O). At least some of those would need help with the parts of speech, so we added a quick little grammar review, and wrote some examples on the white boards during the workshop, so that the kids had help with their Madlib exercise. Lots of giggling involved, so I think they enjoyed it.
One thing did stick from KidsRuby - Robots. Because robots are cool. I bargained with my nephew, and he agreed to let me "borrow" his Sphero for the workshop, if he was allowed to come along. Seemed fair to me. He & I spent a fun afternoon getting everything set up to have a Robots! demo at the end of the workshop with his Sphero.
Cribbing heavily from the KidsRuby class notes, we replaced the Twitter stuff with some new basic logic material, and I introduced some basics on looping. The final version of the class material used is in this Github branch here. Once we covered all that, I was pretty sure that the students would be able to grasp the Artoo.io Sphero demo code without too much trouble.
I sent all that to Ksenia. She also suggested an "icebreaker" exercise at the beginning of the class, which was an excellent idea, and got the girls very engaged.
All in all, I was happy that we prepared so well. The workshop was well attended (most popular one so far!) with 22 students and 7 (or 8 or 9?) mentors, and went fairly smoothly. Had one hiccup, when the USB sticks I had prepared (with backup downloads and course materials) ended up formatted only for Mac #facepalm, but one of our fabulous mentors, Tim, was able to quickly re-format enough copies for all the Windows-based students to use. We did run out of time at the end, leaving the final exercise as "homework", but got our Sphero demo to run, just about the time that all the parents showed up to take the kids home.
I have to close by thanking the amazing Girls Learning Code team at @ChicGeekYYC. Ksenia, Darcie, and Jocelyn put in an amazing amount of effort to run these workshops, and to make certain that they are free. And to thank all the mentors who helped make my job as instructor pretty easy. I'm not certain if all the attendees and parents realize, but these Girls Learning Code workshops are free because of the efforts of the @ChicGeekYYC team, the instructors, and the mentors, all volunteering their time to teach coding skills to young girls. And, of course, the sponsors like @AssemblyCS, who donate their spaces to hold these workshops.
I am already looking forward to new Girl's Learning Code workshops. I hope to set up a chapter down home in Lethbridge before the year is out. I know my nephew really enjoyed the workshop and is extremely interested in attending another, so I have hopes that the rest of the students enjoyed this one as much as he and I did.
There's all sorts of stories and reasons behind the lack of women in software development, and I'm not planning on debating which or how influential any of them are. I'll just pick one to start with here. We call it "the pipeline". It's really hard to increase the percentage of women in software development jobs, when the percentage of young women entering the field remains so ridiculously low.
Why is it ridiculously low?
Young women, and really before that, young girls, are convinced that programming is boring, where you are just locked up in a room with a computer pounding out code 24/7. That is such a narrow and really misleading look at the profession that it just breaks my heart. Good programmers need to understand, deeply, the fields related to what they are programming, in order to do a good job. Good software developers need to be people-persons, to work with the users/customers of their software, to determine their needs, and to help them solve problems that they never even realized they had.
But here's a good starting place: The share of women in computer science started falling at roughly the same moment when personal computers started showing up in U.S. homes in significant numbers. -- npr.org
The simple fact is women were programming long before boys, when it was thought that programming was a "clerical" type of skill. Once the boys figured out it was more important than that, they made certain to elbow the women out of the way, quick enough. Follow that up with some really good ad campaigns that make it clear that computers are for boys, and now we have a self-fulfilling prophesy of a male-dominated profession, because there are not enough women mentors, and there is a lack of young women even wanting to enter in the pipeline into the field of software development.
So let's fix that at the very start.
Shouldn't computer science be like reading/writing/arithmetic? Get kids, really young kids, learning how to program. Have a progression of skills that are taught and practiced throughout their school years.
(Ok, there never were 3 R's so don't bug me about that 4th one, mmmk?)
We teach reading and writing and arithmetic right from the get-go in schools. But computers are part of the new literacy, so using computers, and TALKING to computers, and telling computers what to do is a basic skill that needs to be engendered right along with those other three.
Introduced at an early enough stage, it becomes "just something you do", and not something related to video games or logic skills or math skills or whatever reason people pick to assume that boys are good at it while girls are not.
I would also argue that programming is a "maker" skill, and kids love to make things. Programming is making something with your mind, in collaboration with the computer. There is a joy involved in creating something new. Kids feel that way about their art projects, why not about their programs? What I'd really love to see is Facebook and Pinterest & Instagram filling up with links to my friends' kids' programming projects, much like their art projects show up on your fridge now.
"Look at this neat thing my kid made"
Why don't we have this already?
I'm doing my part. In a couple of weeks, I'm teaching the Girls Learning Code Ruby Workshop. We can always use more mentors, which will help us get some of those girls OFF the waiting list, and into the class!
So here it is, the end of January. This marks exactly a year since my husband and I were "just checking out" the housing market in Lethbridge, Alberta and fell in love with our money-pit of a property. I have another whole post drafted on how we arrived at our decision to move, so I'll leave that to another time, and just talk about what we've discovered about our new-old home town in that year.
I grew up in Lethbridge, so I thought I knew a lot about this place. In the time since I left to go to university in Calgary, Lethbridge has grown a lot. It is over double the size it was when I left, with a population of over 93,000. It was, and remains, a university town, with both the University of Lethbridge and Lethbridge College now contributing 8600 and 4000 students respectively to the local population. That youthful influx each year gives the city a more modern vibe than I remember from my childhood.
Lethbridge also claims a more diversified economy than its' big sibling cities of Alberta. It's not as chained to the oil economy as Calgary and Red Deer, nor as government-bound as Edmonton. It is southern Alberta's commercial, distribution, financial and industrial centre. While in the past, Lethbridge's economy was primarily agricultural, the Economic Development Lethbridge (EDL) organization, created in 2002, has started to have a significant impact.
As an avid Twitter user, I started building my list of #yql people to follow after we committed to the move. In the fall, I stumbled across an EDL event called tec & mingle hosted by tecconnect. I had no idea that Lethbridge had it's own tech incubator. Nor that it was fast becoming a world-leader in geo-spatial technologies. There's even a Tier 3 data centre, owned and operated by BlackBridge Technologies.
tec & mingle was an interesting event, where we got to meet numerous members of the local tech community, and drool over interesting technologies like the UAV drones of Ventus Geospatial used to collect aerial imagery and perform 3D mapping. Spent some time chatting with Chris Rabl, a front-end developer with Autovance, and saw a demo of their interesting software product that is helping car dealerships streamline their financing options. And I got to run into old school friends, like Alan Schneider, who is now executive director of the Lethbridge Community Network, providing support for not-for-profits with IT and computer services.
While my husband and I may have had a few lingering doubts about leaving the big city, I have to say that those doubts have been completely laid to rest, and I am excited by the opportunities available in our new-old home town.
At long last, Core Data in Motion, my book that helps RubyMotion developers get up to speed with Core Data in their RubyMotion projects, is complete.
So, what is RubyMotion? RubyMotion enables you to write cross-platform applications for iOS, Android, and OS X in Ruby. Instead of using the painfully verbose syntax of Objective-C, or taking a chance on the not-quite-ready-for-production Swift language, you can use the programming language that was designed to make programming fun to develop your iOS applications.
And what is Core Data? Core Data is to iOS and OS X development what ActiveRecord is to Rails. It solves all the hard problems involved in your data stack. To quote Drew Crawford
If you are saving more than 3 objects to disk without linking to CoreData.framework, you’re doing it wrong.
This final chapter of Core Data in Motion is an epic look at the available gems and CocoaPods that can simplify and streamline your Core Data code. It weighs in at more that double the size of any of the other chapters in the book.
My reviewers have given fantastic feedback on this chapter, and I know you will find it extremely helpful, when trying to figure out which gem or CocoaPod will be most useful to speed along the development of your application.
Each gem is demonstrated, as I walk you through the process of transforming the base Core Data API's used in the book's sample project, into the gem's specific API. I also discuss the problems and issues I discovered along the way, so you can see what happens, and avoid those problems in your project.
It's been a long time coming, but Core Data in Motion will definitely give you the boost into using Core Data that you need, and save you hours and days of investigation and frustration.
Last year was just crazy. I was attempting to finish writing my book, work some contracts, speak at two conferences, teach my Rails workshop, mentor and teach at a couple of Ladies Learning Code/ChicGeekYYC events, and just for shiggles, my husband and I picked up and moved to a new (old) city - Lethbridge.
In retrospect, it isn't really surprising that I didn't actually finish primary writing on the book until Dec 31. Other than finishing the book, and planning to move out of Calgary, I didn't really have a master plan last year. And you know what they say about planning...
Failing to plan is planning to fail. - Alan Lakein
This year should be a little more sane. I'm laying out some goals, and trying to concentrate on building up my "products" business, finally making progress on my 30x500 learnings.
Before looking forward, however, I need to get an idea of where I currently stand. Taking the cue from some of my fellow 30x500 alumni, I decided I should post my product business results from last year. Got onto Stripe, downloaded my transaction history, and summed everything up:
Ok, that % increase on the book is kind of lame, since I only sold one copy in Dec 2013, but the overall revenue numbers were still a nice uptick, year over year. I guess I’m still in that constant battle with impostor syndrome, and I didn’t keep track regularly, because I didn’t think I was doing that well, considering that I was still pretty much half-assing my way along last year.
Now I have the numbers on which to base my goals for the next year. Drum roll, please...
Marketing the now-finished (just waiting for comments from one more reviewer before pushing the final) book is pretty much a no-brainer.
Creating the new workshop is one of the "brick building" exercises we learn from 30x500, and is also a no-brainer, considering how many requests I have had for it.
Obviously, I can't make any money from workshops if I don't get them scheduled. Seems like I get busy, and then forget, and then it's a bad time of year or whatever. I mean... I scheduled a workshop on Grey Cup weekend one time (#facepalm). So, we'll get those lined up, with real dates, sooner rather than later this year.
The iOS application is a bit of a soft goal. I need to finish it, because it's been languishing at the 80% finished level for too long. It's not really planned as a revenue generator, directly, but it was the spur behind my book, so there's that. And then I can say I am a published iOS developer, so there's that, too. iOS and Android developers seem to have a LOT of pains, so that is a fruitful area for future sales safaris.
I also want to continue my volunteer work in conjunction with Ladies Learning Code, to improve the levels of diversity in software development. Lethbridge may be small, but it has both a university and a college, so I fully expect to be able to host workshops here quarterly, as I get the Lethbridge Chapter ramped up. (Contact me if you are interested in helping out!)
So there we have it. Last year I had a 300% increase in revenue. I don't think it's a stretch to go for 500% this year (not a goal, but a good measuring stick of progress), since I am buckling down with these definite goals. Instead of leaving my revenue checkup for the end of the year, this year I'll be doing that at least quarterly, so I can tell what sort of progress I am making.
If you'd like to keep in touch, you can always contact me directly, or you can sign up for my mailing list, and get advance notice about workshops and special discounts for my products not offered elsewhere.
I've been a Rogers customer since my first cell phone, which was a very long time ago. Sure, every once in a while, I get this twinge because their coverage sucks in rural areas (like where all my in-laws live), but I've put up with that, because when I am visiting family I mostly don't want to be interrupted by work anyway.
I've also experienced the super extreme rip off of international roaming. But Telus does the same, and that's an easily solved problem. I got a Roam Mobility SIM for my US travels ($20 SIM + $14.95/GB), and a nice little mifi device that I can load up with 3 GB of data for 30 euro when I am in the UK, the equivalent of 10 euro/GB. That's a little better than Rogers, where I'd be spending $400/GB with one of their "special" travel packs. Ouch. So ... same shit, different provider, whatever.
But the last straw came with my most recent Rogers bill. It seemed unusually high, so I double checked with my previous bill. And yup, it was almost $50 more. After digging into the details, I discovered that I was charged $48.49 for a data overage.
Now, I get that you have a limit, and you get charged to go over. What I don't get, is the EXTREME ripoff of those overage charges. Let's review this in detail shall we?
I get charged $35/6GB right now. This is the original iPhone data plan, that I have been using since my original iPhone. Since that first, locked, phone I got from Rogers, I've never "upgraded", and I've always gotten my own unlocked phone from Apple. So they aren't subsidising my phones, either. I'll even leave out the fact that I get ripped off on my iPad data plan, since I last upgraded and the new device was "inelligible" for data sharing on that 6GB plan, so I had to get a separate plan for it.
Since I am good at the maths, let me illustrate exactly WHY I feel ripped off. On that plan, I get $35/6GB or:
$5.83 / 1 GB
I was over my 6GB (6000MB) limit by 900 MB. That would make the $48.49/0.9GB equivalent to:
$53.87 / 1 GB
Yah. That. The fuckers are charging me almost 10 times the original rate for an overage. And that is why Rogers just lost me as a customer. Not because they charge extra for going over. I would understand that. But double or triple the rate. Not 10 fucking times the rate. That's just unconscionable price gouging.
So, screw you, too, Rogers. Next week, when I have the time, I'll be hitting up the Telus store and they'll have my $150/month account from now on.
While there are a lot of great gems and tools to help us with creating great looking user interfaces in code in RubyMotion, sometimes I still like to explore how to do stuff at the iOS API level without using all the magic. Especially when just writing the code turns out to be pretty straightforward and elegant all on its own.
Creating a static table in code, to display some detail data in your application is one of these cases.
For my specific example, I have 6 items of information about a well to display, and this data logically groups into 3 sections of 2 items in each section. So, we'll set up the table view using sections like so:
class WellDetailsController < UITableViewController
SECTIONS = %w(Name Status Location)
navigationItem.title = "Well Details"
def tableView(tableView, numberOfRowsInSection:section)
def tableView(tableView, titleForHeaderInSection:section)
With this code, I have set up my 3 sections (Name, Status, and Location) as a constant array. Then we implement the necessary methods of the table view (numberOfSectionsInTableView, tableView:numberOfRowsInSection, and tableView:titleForHeaderInSection) to deal with these sections.
Next up, we need to fill the actual table cells with data:
Here, we set up the traditional tableView:cellForRowAtIndexPath. In it, we pull the data for the cell textLabel and detailTextLabel out of our @details data structure. This data structure is an array of arrays. More specifically, it is an array of sections, and each section array contains an array of rows. Each row is a hash, with a label/value pair.
The @details data structure itself gets populated with new values (the labels don't change) when a well is selected in another view (from a list of wells, or a map of wells). The showDetailsForWell gets called, and then this view is displayed.
That's all folks.
Certainly, it would be far simpler to code this up using Promotion, assuming you already knew and used Promotion. But it wasn't necessary to add another gem to my project for this. And I now understand exactly how sections and rows work in UITableViewController, so it wasn't a total loss ;-)
If you liked this post, you may find the prerelease of my Core Data in Motion book of interest. Certainly if you plan to use Core Data in your RubyMotion project it will save you many hours of head-scratching. Chapter 4 (Load Optimization) is now available. This will be the last chapter before the book goes up to full price, so get it now, and you will receive the last couple chapters (and maybe some bonus content) as they are completed, at a bargain price.
After my last post, there was an interesting side discussion on Twitter (with @macfanatic and @kastiglione) about some alternatives. It was interesting enough that I thought it would make good material for another post. So here ya go!
But you can't do that in Core Data. When you execute a Core Data fetch, you get the option of getting back object ids only or whole objects only.
Or can you?
That was the point under discussion on Twitter. There is actually another option, but it comes with its own limitations. So let's take a look at that other option, and see what it gives us, and what it takes away.
If you look at the SDK docs for NSFetchRequest, you will see a method called setPropertiesToFetch. The SDK description for this method is:
Specifies which properties should be returned by the fetch. The
property descriptions may represent attributes, one-to-one
relationships, or expressions. The name of an attribute or
relationship description must match the name of a description
on the fetch request’s entity.
values (Array) — An array of NSPropertyDescription objects that
specify which properties should be returned by the fetch.
Hey! So you can get your NSFetchRequest to return only this specified subset of properties! Isn't that just like a select?
Well, not quite. You see, when you run the NSFetchRequest with the propertiesToFetch specified, it will still ignore your propertiesToFetch, unless you have also specified a resultType of NSDictionaryResultType. This is detailed in the answer to this Stack Overflow question.
Then, when you run the NSFetchRequest with some propertiesToFetch and a resultType of NSDictionaryResultType you get back an array of NSDictionary items, NOT your NSManagedObjects. So your results won't have any of the methods you've declared on those NSManagedObjects, like, for instance, if you implemented the MKAnnotation interface so that you can drop those results on an MKMapView (which was my particular issue with this).
I will further note that the Stack Overflow post also indicates that the NSFetchedResultsController doesn't play nicely with NSDictionaryResultsType, which would limit it's usefulness with most standard UITableViewControllers implementations, too.
So... I can't use these results on my map, and it won't play nicely with my list view, either. I'm sure it's useful in some use cases, but its limitations made it useless for both of mine, so this is where NSFetchRequest.propertiesToFetch and I parted company.
Chapter 3 of Core Data in Motion (Preloading Data) is now available, and I've added the information from this post as an update to Chapter 2 as an extra bonus. As always, I welcome your feedback, especially when it helps me improve the book like this discussion has done.