From 05eb8571621e1fa488db4c0d569fd83e86259ed1 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Sat, 14 Aug 2021 13:06:41 +1000 Subject: [PATCH 1/2] Track newly generated --- 2013/01/05/cocoapods.html | 53 ++- .../cocoapods-how-to-create-your-own-pod.html | 72 ++-- ...builds-of-the-same-app-and-testflight.html | 20 +- ...or-facebook-integration-on-ios-part-1.html | 28 +- 2013/07/06/things-learned-in-june.html | 6 +- 2013/07/09/cocoapods-the-inherited-flag.html | 5 +- 2013/07/26/what-i-did-in-a-week.html | 6 +- 2013/08/01/things-learned-in-july.html | 20 +- 2013/09/03/things-learned-in-august.html | 12 +- 2013/09/16/xcode5-crash-on-submission.html | 32 +- 2013/09/17/mtfonticon.html | 10 +- 2013/09/23/setup-a-dev-machine.html | 37 +- 2013/09/24/ios7-ux-designers-verdict.html | 10 + 2013/10/02/things-learned-in-september.html | 18 +- 2013/10/06/october-questions.html | 10 +- 2013/10/31/Xcode-projects-and-workspaces.html | 33 +- 2013/11/12/things-learned-in-october.html | 8 +- ...as_many-association-to-existing-model.html | 56 ++- 2013/11/20/podcasts.html | 14 +- archive.html | 2 +- .../index.html | 58 +-- blog/2014-resolutions-review/index.html | 4 +- .../index.html | 12 +- blog/a-world-without-slack/index.html | 4 +- .../index.html | 43 +-- blog/apps-and-tools-i-use/index.html | 28 +- .../index.html | 25 +- .../index.html | 5 +- .../index.html | 34 +- blog/automating-mokacoding-weekly/index.html | 19 +- blog/better-build-phase-scripts/index.html | 26 +- .../index.html | 22 +- .../index.html | 30 +- blog/better-tests-for-delegates/index.html | 75 ++-- blog/better-tests-with-specta/index.html | 15 +- .../bitbucket-pr-from-command-line/index.html | 5 +- blog/books-to-start-2018/index.html | 8 +- .../index.html | 21 +- blog/carthage-no-build/index.html | 7 +- blog/circle-ci-ios-testing/index.html | 17 +- blog/cloud-66-postfix-deploy-hook/index.html | 14 +- blog/clutter-and-optimization/index.html | 2 +- .../index.html | 16 +- blog/cocoapods-ci-setup/index.html | 32 +- .../index.html | 72 ++-- blog/cocoapods-the-inherited-flag/index.html | 5 +- blog/cocoapods/index.html | 53 ++- blog/code-coverage-is-broken/index.html | 21 +- blog/code-like-a-chef/index.html | 2 +- .../index.html | 10 +- blog/demistifying-swift-functor/index.html | 178 ++++------ .../index.html | 37 +- .../index.html | 8 +- .../index.html | 2 +- blog/double-slash-xcconfig/index.html | 5 +- blog/env-xargs/index.html | 13 +- blog/expecta-custom-matchers/index.html | 34 +- blog/expecta/index.html | 5 +- blog/explicit-dependencies-swift/index.html | 28 +- blog/explicit-dependencies/index.html | 25 +- .../index.html | 24 +- .../functional-core-reactive-shell/index.html | 35 +- .../index.html | 171 +++++---- blog/gitiquette/index.html | 10 +- blog/gradient-backgrounds-studio/index.html | 47 ++- blog/hacker-news-button/index.html | 16 +- blog/homebrew-in-ci-script/index.html | 24 +- blog/honesty-oriented-programming/index.html | 2 +- .../index.html | 3 +- .../index.html | 5 +- .../index.html | 5 +- .../index.html | 12 +- .../how-to-choose-what-to-refactor/index.html | 2 +- .../index.html | 40 +-- .../index.html | 5 +- .../index.html | 5 +- .../index.html | 14 +- .../index.html | 69 ++-- .../index.html | 76 ++-- .../index.html | 10 +- .../index.html | 28 +- .../index.html | 64 ++-- .../index.html | 52 ++- blog/how-to-test-swiftui-apps/index.html | 197 +++++++++++ .../how-to-verify-ssh-key-password/index.html | 3 +- .../index.html | 173 +++++---- .../index.html | 17 +- .../index.html | 6 +- .../index.html | 5 +- blog/ios-testing-in-2015/index.html | 49 ++- blog/ios7-ux-designers-verdict/index.html | 10 + .../index.html | 2 +- .../index.html | 30 +- .../index.html | 15 +- blog/main-vs-master-xcode-12/index.html | 3 +- .../index.html | 9 +- .../index.html | 28 +- blog/mtfonticon/index.html | 10 +- .../index.html | 20 +- blog/navigation-delegate-pattern/index.html | 66 ++-- blog/nerdtree-relative-numbers/index.html | 5 +- blog/nested-type-view-models/index.html | 15 +- blog/nsdateformatter-json-date/index.html | 29 +- blog/october-questions/index.html | 10 +- blog/ohhttpstubs/index.html | 51 ++- blog/packaging-swift-ipa/index.html | 5 +- blog/pipe-wrench/index.html | 32 +- blog/podcasts/index.html | 14 +- blog/pre-commit-hooks/index.html | 37 +- .../index.html | 26 +- .../index.html | 9 +- .../index.html | 12 +- .../index.html | 21 +- .../index.html | 56 ++- .../index.html | 4 +- .../index.html | 34 +- .../index.html | 3 +- .../index.html | 24 +- .../index.html | 17 +- blog/ruby-for-ios-developers/index.html | 17 +- blog/running-one-test-in-xcode/index.html | 10 +- .../index.html | 35 +- blog/scenario-builders-in-swift/index.html | 49 ++- .../index.html | 3 +- .../index.html | 22 +- .../index.html | 17 +- .../index.html | 38 +- blog/setup-a-dev-machine/index.html | 37 +- .../index.html | 15 +- .../index.html | 54 ++- .../index.html | 15 +- .../index.html | 22 +- .../index.html | 331 ++++++++---------- .../index.html | 2 + .../index.html | 83 ++--- blog/swift-array-string-characters/index.html | 9 +- blog/swift-either/index.html | 30 +- blog/swift-test-doubles/index.html | 72 ++-- blog/swift-unavailable-how-to/index.html | 20 +- blog/swiftui-dependency-injection/index.html | 126 ++++--- blog/symliks-in-git/index.html | 5 +- blog/tdd-and-ydniy/index.html | 16 +- blog/tdd-in-swift-book-launch/index.html | 3 + blog/terminal-aliases/index.html | 9 +- .../index.html | 15 +- .../index.html | 29 +- .../index.html | 91 +++-- .../index.html | 68 ++-- blog/testing-realm-apps/index.html | 69 ++-- .../index.html | 28 +- .../the-productivity-project-notes/index.html | 26 +- .../index.html | 6 +- blog/things-learned-in-august/index.html | 12 +- blog/things-learned-in-july/index.html | 20 +- blog/things-learned-in-june/index.html | 6 +- blog/things-learned-in-october/index.html | 8 +- blog/things-learned-in-september/index.html | 18 +- blog/top-10-productivity-books/index.html | 22 +- blog/travis-ci-ios-testing/index.html | 17 +- blog/unless-swift/index.html | 17 +- blog/upgrading-podfile/index.html | 27 +- .../index.html | 57 ++- blog/vim-rename-file/index.html | 5 +- blog/waituntil-vs-toeventually/index.html | 75 ++-- blog/what-i-did-in-a-week/index.html | 6 +- .../index.html | 19 +- .../index.html | 6 +- blog/when-to-use-map-flatmap-for/index.html | 38 +- .../index.html | 17 +- blog/why-i-dont-work-on-friday/index.html | 12 +- .../index.html | 44 +-- .../index.html | 4 +- .../index.html | 38 +- blog/writing-your-own-swift-if-let/index.html | 69 ++-- blog/wwdc21-whats-new-in-testing/index.html | 4 +- blog/xcode-7-ui-testing/index.html | 50 ++- blog/xcode-plugins-update/index.html | 3 +- blog/xcode-projects-and-workspaces/index.html | 33 +- blog/xcode-testing-shortcuts/index.html | 6 +- blog/xcode-ui-test-view-changes/index.html | 22 +- blog/xcode5-crash-on-submission/index.html | 32 +- .../xcodebuild-destination-options/index.html | 52 ++- .../index.html | 36 +- blog/xctest-nimble/index.html | 51 ++- blog/xunique/index.html | 13 +- blog/xvim/index.html | 2 +- .../index.html | 28 +- espresso.html | 2 +- feed.xml | 2 +- index.html | 3 +- tag/swift/index.html | 2 +- tag/swiftui/index.html | 2 +- tag/tdd/index.html | 2 +- tag/testing/index.html | 2 +- tags.html | 2 +- xcode-heart-vim/index.html | 27 -- 196 files changed, 2615 insertions(+), 2908 deletions(-) create mode 100644 blog/how-to-test-swiftui-apps/index.html delete mode 100644 xcode-heart-vim/index.html diff --git a/2013/01/05/cocoapods.html b/2013/01/05/cocoapods.html index 2aa7464..0f78cdc 100644 --- a/2013/01/05/cocoapods.html +++ b/2013/01/05/cocoapods.html @@ -1,6 +1,6 @@ CocoaPods! | mokacoding

mokacoding

unit and acceptance testing, automation, productivity

CocoaPods!

What is CocoaPods?

+

mokacoding

unit and acceptance testing, automation, productivity

CocoaPods!

What is CocoaPods?

CocoaPods: The best way to manage library dependencies in Objective-C projects.

@@ -11,72 +11,67 @@
  • Smart and safe version management, specially when we're working on a project with other people, which is 90% of the time.
  • To "get my hands dirty" with CocoaPods I made this little project called JustNineGags, feel free to check it out on GitHub.

    -

    Why should I use it?

    -

    Because it's awesome! It makes development faster and easier, and also safer! It easier to work in teams and keep the libraries versions even. Should I go on? Ok! Just think about this: you won't download and move in your project a library anymore, pod will do it all for you!

    +

    Why should I use it?

    +

    Because it's awesome! It makes development faster and easier, and also safer! It easier to work in teams and keep the libraries versions even. Should I go on? Ok! Just think about this: you won't download and move in your project a library anymore, pod will do it all for you!

    Installing CocoaPods

    -

    Installing CocoaPods is as simple as installing all the other Ruby Gems, I shouldn't even writing this, as what's written in the install section is more than enough, anyway:

    +

    Installing CocoaPods is as simple as installing all the other Ruby Gems, I shouldn't even writing this, as what's written in the install section is more than enough, anyway:

    -
    gem install cocoapods
    -

    Once the installation is completed run:

    +
    gem install cocoapods

    Once the installation is completed run:

    -
    pod setup
    -

    This will, guess what, setup everything CocoaPods needs on your system. You should see an output like this:

    +
    pod setup

    This will, guess what, setup everything CocoaPods needs on your system. You should see an output like this:

    -
    Setting up CocoaPods master repo
    +
    Setting up CocoaPods master repo
     Cloning spec repo 'master' from '<a href='https://github.com/CocoaPods/Specs.git'>https://github.com/CocoaPods/Specs.git</a>' (branch 'master')
    -Setup completed (read-only access)
    -

    Done! :)

    +Setup completed (read-only access)

    Done! :)

    -

    You should avoid using sudo otherwise everything else you'll do with pod will need to use sudo as well. And this mean that the folders and file that are gonna be created will be owend by root instead that by you.

    +

    You should avoid using sudo otherwise everything else you'll do with pod will need to use sudo as well. And this mean that the folders and file that are gonna be created will be owend by root instead that by you.

    Using CocoaPods

    Again, everything written on the website is pretty straightforward.

    -

    Go in the root folder of your Objective-C project and create a file named Podfile, with whatever editor you like. We'll use this file to list all the libraries, pods, we need in the project. The JustNineGags Podfile content is:

    +

    Go in the root folder of your Objective-C project and create a file named Podfile, with whatever editor you like. We'll use this file to list all the libraries, pods, we need in the project. The JustNineGags Podfile content is:

    -
    platform :ios
    +
    platform :ios
     pod 'MBProgressHUD', '~> 0.5'
    -pod 'Reachability',  '~> 3.1.0'
    -
    +pod 'Reachability', '~> 3.1.0'

    Adding a Pod

    -

    As you can see adding a Pod is really easy, just go on CocoaPods website, look for the it, and then add it to the Podfile using it's name and the version you need.

    +

    As you can see adding a Pod is really easy, just go on CocoaPods website, look for the it, and then add it to the Podfile using it's name and the version you need.

    Installing the Pods

    -

    Right now we've told CocoaPods the Pods we need but they aren't yet in out project. So let's run

    +

    Right now we've told CocoaPods the Pods we need but they aren't yet in out project. So let's run

    -
    pod install
    -

    This will download all the libraries we've asked for, and all their dependencies. Sweet!

    +
    pod install

    This will download all the libraries we've asked for, and all their dependencies. Sweet!

    The first time we run pod install something else will happen, a Pods/ folder, a Podfile.lock, and a YourProjectName.xcworkspace will be created.

    -

    Important! From now on remember to open your project through the YourProjectName.xcworkspace file, otherwise the pods won't be loaded by Xcode.

    +

    Important! From now on remember to open your project through the YourProjectName.xcworkspace file, otherwise the pods won't be loaded by Xcode.

    -

    That's all folks! :)

    +

    That's all folks! :)

    What should we track?

    -

    Using CocoaPods adds some files and folders to our project, which of those should we track in our repo, and which should be left aside, adding them to the .gitignore? That of course assuming you're using git, and you definitely should. Let's have a look at the new stuff:

    +

    Using CocoaPods adds some files and folders to our project, which of those should we track in our repo, and which should be left aside, adding them to the .gitignore? That of course assuming you're using git, and you definitely should. Let's have a look at the new stuff:

    • Podfile, we definitely need this one, as all the pods we need are listed in it.
    • -
    • Podfile.lock, as for all the other library management systems, we need this one too, because it's used to assure all the developers are using the same versions of the pods and their dependencies.
    • -
    • Pods/, we don't need to track this folder, it's created by pod install, and all it's content is downloaded for us from other repos.
    • -
    • YourProjectName.xcworkspace, we don't need this one either, because it's generated by pod install too.
    • +
    • Podfile.lock, as for all the other library management systems, we need this one too, because it's used to assure all the developers are using the same versions of the pods and their dependencies.
    • +
    • Pods/, we don't need to track this folder, it's created by pod install, and all it's content is downloaded for us from other repos.
    • +
    • YourProjectName.xcworkspace, we don't need this one either, because it's generated by pod install too.
    -

    What's coming next?

    +

    What's coming next?

    -

    How to setup our own pods. I'll probably write a little and simple Category to add other colors to the UIColor factories, stay tuned!

    +

    How to setup our own pods. I'll probably write a little and simple Category to add other colors to the UIColor factories, stay tuned!


    Update 2013-01-06

    -

    To implement HTTP requests in JustNineGags I used SMWebRequest because I'm too lazy to write everything by myself. SMWebRequest wasn't a Pod yet so I opened an issue asking good guy nfarina to add it. In less than 12 hours the Pod was added! :D

    +

    To implement HTTP requests in JustNineGags I used SMWebRequest because I'm too lazy to write everything by myself. SMWebRequest wasn't a Pod yet so I opened an issue asking good guy nfarina to add it. In less than 12 hours the Pod was added! :D

    Want more of these posts?

    diff --git a/2013/01/21/cocoapods-how-to-create-your-own-pod.html b/2013/01/21/cocoapods-how-to-create-your-own-pod.html index 129b4b7..184b470 100644 --- a/2013/01/21/cocoapods-how-to-create-your-own-pod.html +++ b/2013/01/21/cocoapods-how-to-create-your-own-pod.html @@ -2,48 +2,48 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    CocoaPods - How to create your own Pod

    Like I said in the first part of my exploration of CocoaPods, using this iOS dependencies management is freaking easy, and reading what's on the homepage is more than enough to get started. Anyway let's see how we can create our how Pods.

    To learn how to do it I started the development of a little "framework" I called MGCraftman, where I'll put some utils methods I sometimes write to speed up UI development when I'm not using Interface Builder. But let's stop the chitchat and let's code!

    -

    Step 1 - Code the Library!

    -The first step is to have something to make a pod of, I guess every developer has his own little set of smart methods that make his life easier. Don't be greedy, share them with the community!

    -

    Step 2 - Tag your pod properly

    -Since we're gonna work with a dependency manager we need to take care of the version number of our pod.

    -
    git tag -a 1.0.0 -m "Tag release 1.0.0"
    -

    Take a couple of minutes to read through the Semantic Versioning to learn how to use tagging for version numbers properly and in a way that allows for resolution of cross-dependencies.

    -

    Step 3 - The podspec

    -Once our project is tagged properly we can create the .podspec file. The extension name explains that it will contain the "specs" of our "pod".

    -
    pod spec create Donut
    -

    This will generate the Donut.podspec file.

    +

    Step 1 - Code the Library!

    +The first step is to have something to make a pod of, I guess every developer has his own little set of smart methods that make his life easier. Don't be greedy, share them with the community! +

    Step 2 - Tag your pod properly

    +Since we're gonna work with a dependency manager we need to take care of the version number of our pod. + +
    git tag -a 1.0.0 -m "Tag release 1.0.0"

    Take a couple of minutes to read through the Semantic Versioning to learn how to use tagging for version numbers properly and in a way that allows for resolution of cross-dependencies.

    +

    Step 3 - The podspec

    +Once our project is tagged properly we can create the .podspec file. The extension name explains that it will contain the "specs" of our "pod". + +
    pod spec create Donut

    This will generate the Donut.podspec file.

    You can also generate the podspec from a GitHub repo using the GitHub url instead of the name.

    -

    Step 4 - Leave your mark on the podspec

    -If you open the freshly generated Donut.podspec you'll find a lot of comments explaining the information you need to provide. There are a lot of options, but you don't need to set them all. You'll also notice that its nothing more that a Ruby file.

    +

    Step 4 - Leave your mark on the podspec

    +If you open the freshly generated Donut.podspec you'll find a lot of comments explaining the information you need to provide. There are a lot of options, but you don't need to set them all. You'll also notice that its nothing more that a Ruby file. +

    Here's how the podspec of my toy framework, looks like.

    -
    {% highlight objective-c %}
    -Pod::Spec.new do |s|
    -  s.name         = "MGCraftman"
    -  s.version      = "0.1.0"
    -  s.summary      = "A framework to speedup development when you can't (or don't want to) use Interface Builder."
    -  s.homepage     = "https://github.com/mokagio/MGCraftman"
    +
    {% highlight objective-c %}
    +Pod::Spec.new do |s|
    +  s.name         = "MGCraftman"
    +  s.version      = "0.1.0"
    +  s.summary      = "A framework to speedup development when you can't (or don't want to) use Interface Builder."
    +  s.homepage     = "https://github.com/mokagio/MGCraftman"
    +
    +  s.license      = { :type =&gt; 'MIT', :file =&gt; 'LICENSE' }
    +
    +  s.author       = { "Giovanni Lodi" =&gt; "mokagio42@gmail.com" }
     
    -  s.license      = { :type =&gt; 'MIT', :file =&gt; 'LICENSE' }
    +  s.source       = { :git =&gt; "https://github.com/mokagio/MGCraftman.git", :tag =&gt; "0.1.0" }
    +  s.source_files = 'MGCraftman/*.{h,m}'
     
    -  s.author       = { "Giovanni Lodi" =&gt; "mokagio42@gmail.com" }
    +  s.platform     = :ios
    +end
    +{% endhighlight %}

    Step 5 - Is my podspec ok?

    +Once your podspec its ready validate it running - s.source = { :git =&gt; "https://github.com/mokagio/MGCraftman.git", :tag =&gt; "0.1.0" } - s.source_files = 'MGCraftman/*.{h,m}' +
    pod spec lint Peanut.podspec

    If everything is fine you'll read

    +
    pod spec lint Peanut.podspec 
    +-> Peanut (1.0.0)
    +Analyzed 1 podspec.
    +Peanut.podspec passed validation.

    Otherwise pod spec will explain the error or warning, as everything is so simple also fixing the problems will be. Anyway the error report is already formatted in Markdown so you can copy it and paste it in an issue on the CocoaPods Issues page.

    +

    Step 6 - Let your pod fly

    +We're almost done here. Now to make our pod available to the community, or just to ourselves and feel cool, we have two options. The rookie way is open an issue, but we've just coded an iOS library, with it's own repo on GitHub, and generated the podspec fetching the data from there, so we're not rookies. The second option is to fork the Specs repo, add our pod, submit the PR and wait. - s.platform = :ios -end -{% endhighlight %} -

    Step 5 - Is my podspec ok?

    -Once your podspec its ready validate it running

    -
    pod spec lint Peanut.podspec
    -

    If everything is fine you'll read

    -
    pod spec lint Peanut.podspec 
    --> Peanut (1.0.0)
    -Analyzed 1 podspec.
    -Peanut.podspec passed validation.
    -

    Otherwise pod spec will explain the error or warning, as everything is so simple also fixing the problems will be. Anyway the error report is already formatted in Markdown so you can copy it and paste it in an issue on the CocoaPods Issues page.

    -

    Step 6 - Let your pod fly

    -We're almost done here. Now to make our pod available to the community, or just to ourselves and feel cool, we have two options. The rookie way is open an issue, but we've just coded an iOS library, with it's own repo on GitHub, and generated the podspec fetching the data from there, so we're not rookies. The second option is to fork the Specs repo, add our pod, submit the PR and wait.

    I submitted my PR at 8:44 GTM+0 on a Sunday, let's see how long it takes to merge it. The PR approved and merged in less that 2 hours. That's what I call efficiency. Also you can ask for push rights, in order to maintain your pod without submitting a pull request every time.

    And here we are. My MGCraftman framework is ready to be imported via CocoaPods, and all the world will be happy to use it, or not.

    diff --git a/2013/05/29/multiple-builds-of-the-same-app-and-testflight.html b/2013/05/29/multiple-builds-of-the-same-app-and-testflight.html index 81db82e..287e2ee 100644 --- a/2013/05/29/multiple-builds-of-the-same-app-and-testflight.html +++ b/2013/05/29/multiple-builds-of-the-same-app-and-testflight.html @@ -2,36 +2,36 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    Multiple builds of the same app and TestFlight

    The Multiple Builds Dream

    -

    Working in Memrise on CatAcademy I've been massively using TestFlight to test new features before releasing the next versions of the app. One thing that always annoyed me was the fact that my development version overrode the release one, or that I couldn't keep a "stable" build and a "development" build on my device at the same time.

    +

    Working in Memrise on CatAcademy I've been massively using TestFlight to test new features before releasing the next versions of the app. One thing that always annoyed me was the fact that my development version overrode the release one, or that I couldn't keep a "stable" build and a "development" build on my device at the same time.

    After attending the Facebook Mobile DevCon 2013 in London, where the talk from Alan Cannistraro on how Facebook made their iOS app I realized that having multiple builds of the same app was possible. But how to do it?

    -

    I did some research and found this post, which had almost all the info I need on how to setup my multiple builds infrastructure. There's no point in me copy-pasting what's written there, besides I'm sure 99.9% of you readers already opened the link in a new tab.

    +

    I did some research and found this post, which had almost all the info I need on how to setup my multiple builds infrastructure. There's no point in me copy-pasting what's written there, besides I'm sure 99.9% of you readers already opened the link in a new tab.

    -

    The post is pretty old, so here's an updated screenshot of the Build Settings editor.

    +

    The post is pretty old, so here's an updated screenshot of the Build Settings editor.

    Screen Shot 2013-05-29 at 22.05.48

    -

    If you follow the instructions and run the app on the simulator or on the device, you'll see the new development app appearing next to the release one, as expected.

    +

    If you follow the instructions and run the app on the simulator or on the device, you'll see the new development app appearing next to the release one, as expected.

    -

    This is pretty handy to go around with the two versions of the app and to some user testing with the friends, but guess what? It doesn't work with TestFlight! But fear not, there are only two other steps to make before reaching the goal.

    +

    This is pretty handy to go around with the two versions of the app and to some user testing with the friends, but guess what? It doesn't work with TestFlight! But fear not, there are only two other steps to make before reaching the goal.

    Making a Development Archive

    -

    First problem: when we archive the app the Release configuration is used. Changing this option is pretty easy through the "Edit Scheme…" menu, but wait a second! If we change now the Build Configuration for the archive action from Release to Debug, we'll have to change it back once we're going to publish on the App Store. +

    First problem: when we archive the app the Release configuration is used. Changing this option is pretty easy through the "Edit Scheme…" menu, but wait a second! If we change now the Build Configuration for the archive action from Release to Debug, we'll have to change it back once we're going to publish on the App Store. Better creating a new Scheme and change the configuration in that one.

    -

    "Changing the Scheme every time we want to submit it just as annoying as editing it". Fair enough. But not really… Switching Scheme requires 2 clicks, while editing it at least 6. :P No, seriously switching Scheme is something we can easily automate, using xcodebuild or xctool and a couple of lines in your favourite scripting language.

    +

    "Changing the Scheme every time we want to submit it just as annoying as editing it". Fair enough. But not really… Switching Scheme requires 2 clicks, while editing it at least 6. :P No, seriously switching Scheme is something we can easily automate, using xcodebuild or xctool and a couple of lines in your favourite scripting language.

    Making it work on TestFlight

    -

    All right! Now we're finally able to archive our development version of the app and upload it on TestFlight, maybe through the TestFlight App which is nice and fast. But if we try to do it this is the result:

    +

    All right! Now we're finally able to archive our development version of the app and upload it on TestFlight, maybe through the TestFlight App which is nice and fast. But if we try to do it this is the result:

    The provisioning profile is made for distribution builds but your app is built for development. Please select a valid development identity to continue.

    -

    Don't panic! The message gives us a tip already on how to solve the issue, we just need another Provisioning Profile! Select Development when creating the new profile and use the AppID of the "original" app. This last point surprised me, but I think it may have something to do with the sort of hierarchy structure the bundle ids have.

    +

    Don't panic! The message gives us a tip already on how to solve the issue, we just need another Provisioning Profile! Select Development when creating the new profile and use the AppID of the "original" app. This last point surprised me, but I think it may have something to do with the sort of hierarchy structure the bundle ids have.

    -

    Once your Provisioning Profile is ready update the certificates list in Xcode, through the Organizer window, and proceed to Archive the app. Now when you'll upload the archive with the TestFlight App the new development certificate will appear.

    +

    Once your Provisioning Profile is ready update the certificates list in Xcode, through the Organizer window, and proceed to Archive the app. Now when you'll upload the archive with the TestFlight App the new development certificate will appear.

    Here we go!

    diff --git a/2013/06/25/mokagios-self-memo-for-facebook-integration-on-ios-part-1.html b/2013/06/25/mokagios-self-memo-for-facebook-integration-on-ios-part-1.html index 9a6c964..8b858f2 100644 --- a/2013/06/25/mokagios-self-memo-for-facebook-integration-on-ios-part-1.html +++ b/2013/06/25/mokagios-self-memo-for-facebook-integration-on-ios-part-1.html @@ -1,20 +1,20 @@ mokagio's self memo for Facebook Integration on iOS - Part 1 | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    mokagio's self memo for Facebook Integration on iOS - Part 1

    Part 1 - Facebook Login

    -

    0 - Create a Facebook App

    +

    mokacoding

    unit and acceptance testing, automation, productivity

    mokagio's self memo for Facebook Integration on iOS - Part 1

    ##Part 1 - Facebook Login

    +

    ###0 - Create a Facebook App

    Create an app on the Facebook App Dashboard, what are you gonna integrate otherwise?!

    -

    1 - Add the Facebook SDK Pod

    +

    ###1 - Add the Facebook SDK Pod

    Given that you have already setup your libraries management with CocoaPods, and you should have, add to your Podfile the line

    pod "Facebook-iOS-SDK", "~> 3.5.2"

    Then run pod install.

    For more info about how to use CocoaPods check out this post of mine.

    -

    2 - Add some Facebook data to the Info.plist

    +

    ###2 - Add some Facebook data to the Info.plist

    Facebook requires you to add two fields to your Info.plist file:

    • FacebookAppID: a 15 digits number you can find in the Settings page of your app on your Facebook developer page.
    • FacebookDisplayName: how to comment, the display name of your app?
    -

    3 - A basic login flow

    +

    ###3 - A basic login flow

    The tutorial tells us to put all the Facebook login in the AppDelegate. I don't like this approach, because I don't want to make the delegate dirty with code related only to Facebook. I prefer to create a FacebookProxy class, with class methods to call to interact with Facebook.

    Whatever solution you prefer the steps for the login are the same anyway:

      @@ -24,9 +24,9 @@

      3 - A basic login flow

    1. Let the SDK do it's job.
    2. Come back to the app and handle the result.
    -

    Check if the user is logged in

    +

    ####Check if the user is logged in

    To get the current Facebook session we use FBSession.activeSession. To see if the session is active, and therefore the user is already logged in, we need to check the state property: FBSession.activeSession.state. A quick look to the typedef enum of the FBSessionState and:

    -
    {% highlight objective-c %}
    +
    {% highlight objective-c %}
     + (BOOL)isUserLoggedInFacebook
     {
         if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded
    @@ -37,21 +37,19 @@ 

    Check if the user is logged in

    return NO; } } -{% endhighlight %} -

    Call the Facebook SDK method to login

    +{% endhighlight %}

    ####Call the Facebook SDK method to login

    Easy peasy:

    -
    {% highlight objective-c %}
    +
    {% highlight objective-c %}
     [FBSession openActiveSessionWithReadPermissions:nil
                                        allowLoginUI:YES
                                   completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
          // handle stuff here
      }];
    - {% endhighlight %}
    -

    In the completion handler we should… handle the result of the open active session. I think that this really depends on what our app will do, so I'm not gonna write any snippet here.

    -

    Come back to the app and handle the result

    + {% endhighlight %}

    In the completion handler we should… handle the result of the open active session. I think that this really depends on what our app will do, so I'm not gonna write any snippet here.

    +

    ####Come back to the app and handle the result

    If you're user's are using iOS 5 -I hope they're not-, or if they're so dumb they haven't installed the native Facebook app for iOS, the login will occur with a sort of modal window in your app. In all the rest of the cases the

    -

    Frameworks needed in the Test Bundle

    -

    TDD is the way. Full stop. I noticed that adding the Facebook-iOS-SDK pod to my project wasn't enough for my test bundle to run, there were some framework dependencies missing:

    +

    ###Frameworks needed in the Test Bundle +TDD is the way. Full stop. I noticed that adding the Facebook-iOS-SDK pod to my project wasn't enough for my test bundle to run, there were some framework dependencies missing:

    • AdSupport.framework
    • Social.framework
    • diff --git a/2013/07/06/things-learned-in-june.html b/2013/07/06/things-learned-in-june.html index 4b6a2ac..b492927 100644 --- a/2013/07/06/things-learned-in-june.html +++ b/2013/07/06/things-learned-in-june.html @@ -1,14 +1,14 @@ Some things I learned in June | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in June

      Last month I decided to start keeping track of the things learned along the way. This list at the moment seems kinda short, let's say that's because I didn't start keeping track of the stuff from the beginning of the month.

      -

      Coding

      +

      ###Coding

      Testing Objective-C classes equality: http://stackoverflow.com/questions/10944460/testing-class-equality-in-objective-c

      Objective-C _cmd returns the method name within a method: http://stackoverflow.com/questions/2770307/nslog-the-method-name-with-objective-c-in-iphone

      You can use a Pod locally: https://github.com/CocoaPods/CocoaPods/wiki/Working-on-a-pod

      -

      Systems and Tools

      +

      ###Systems and Tools

      How to stop autocorrect in zsh: http://yountlabs.com/blog/2010/11/06/disable-autocorrect-in-zsh/

      -

      Trivia

      +

      ###Trivia

      Where does the Logarithm name come from: "Napier first called L an "artificial number", but later introduced the word "logarithm" to mean a number that indicates a ratio: λόγος (logos) meaning proportion, and ἀριθμός (arithmos) meaning number." http://en.wikipedia.org/wiki/Logarithm

      diff --git a/2013/07/09/cocoapods-the-inherited-flag.html b/2013/07/09/cocoapods-the-inherited-flag.html index c6f84d0..36411c3 100644 --- a/2013/07/09/cocoapods-the-inherited-flag.html +++ b/2013/07/09/cocoapods-the-inherited-flag.html @@ -2,10 +2,9 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

      Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

      mokacoding

      unit and acceptance testing, automation, productivity

      CocoaPods: the $(inherited) flag

      I've done it a lot of times by now, but I keep forgetting it. So here's a quick post to commit it to memory!

      If we have a project with the Tests target it can happen that after running pod install we get this message:

      -
      [!] The target `MyProjectTests [Debug]` overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Pods-MyProjectTests.xcconfig'.
      +
      [!] The target `MyProjectTests [Debug]` overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Pods-MyProjectTests.xcconfig'.
       - Use the `$(inherited)` flag, or
      -- Remove the build settings from the target.
      -

      How can we "use the $(inherited) flag"? Where should we add it?

      +- Remove the build settings from the target.

      How can we "use the $(inherited) flag"? Where should we add it?

      The $(inherited) flag is an flag we can pass to the linker and that does some magic.... I haven't been able to find a proper explanation for how $(inherited) works, although it's easy to guess from the name.

      Being a linker flag we can add it in our target Build Settings > Other Linker Flags section.

      Screen Shot 2013-07-10 at 00.16.36

      diff --git a/2013/07/26/what-i-did-in-a-week.html b/2013/07/26/what-i-did-in-a-week.html index efb2d61..a0f084c 100644 --- a/2013/07/26/what-i-did-in-a-week.html +++ b/2013/07/26/what-i-did-in-a-week.html @@ -3,11 +3,11 @@

      mokacoding

      unit and acceptance testing, automation, productivity

      What I did in a week...

      As promised one week ago, here's a report of what I managed to do in this unusually full of free time week.

      I've caught up with Arrow and Game of Thrones. The Red Wedding was better in the book, in my opinion.

      Oh! Yes... I did some coding as well :D I've completed the MVP of my iOS app, and I have a working and tweeting setup of the Twitter based Rails App.

      -

      iOS

      +

      ###iOS

      I've built a simple app using CoreData and MagicalRecod for the data storage, focusing on a simple gesture based UX, powered by JTGestureBasedTableView, with an iOS7ish look. The idea was to roll it out on TestFlight for a week or two and then submit, but the recent cracker attack at Apple have delayed plans. I also used my two WIP pods MGCraftman and MGObjectiveUtils, but the project is simple so I didn't have the occasion to add stuff to them.

      -

      Rails

      +

      ###Rails

      To implement my Twitter based web app I've relied on the twitter gem, which does all the dirty work for me. I'm using Haml for the templates, I love it, so minimal and clear. I'm also gonna use SASS for the styling. So far I've only been using LESS, so I decided to give it a twist.

      -

      Good Practices

      +

      ###Good Practices

      Both the projects are obviously being implemented in a as much test driven way as possible! rspec and webmock on the Ruby side, Kiwi on the Objective-C one. Neat!

      Finally my simple PR on xctool has been merged, and I'm proud of it. And surprised no one thought about coloring the result output before...

      That's all. I'm overall satisfied of what I managed to build. Although I could have avoided watching half a season of Arrow in two days while coding and focusing more... -.-

      diff --git a/2013/08/01/things-learned-in-july.html b/2013/08/01/things-learned-in-july.html index 6318c6a..632826c 100644 --- a/2013/08/01/things-learned-in-july.html +++ b/2013/08/01/things-learned-in-july.html @@ -1,38 +1,38 @@ Some things I learned in July | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in July

      July has been a month dense of learning and (re)discoveries! First of all Rails 4, which I come to love back in the day, when I was working with my friends on the first prototype of Kunerango

      -

      Objective-C and iOS Development

      +

      ###Objective-C and iOS Development

      http://rentzsch.github.io/mogenerator/

      Guess what? CoreData doesn't make your life easy when you're seriously working with test, http://stackoverflow.com/questions/1876568/ocmock-with-core-data-dynamic-properties-problem. I like the protocol approach, even if it adds a some "boilerplate code" to maintain.

      nomad a set of useful tools to automate the every-day development. Another gift from mister Mattt.

      -

      Ruby on Rails

      +

      ###Ruby on Rails

      Rails 4 finally out! http://weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

      Nice and clear guide to testing with RSpec on Rails http://everydayrails.com/2012/03/12/testing-series-rspec-setup.html

      Binstubs, because the less we type, the better! http://blog.barbershoplabs.com/blog/2013/03/01/upgrading-to-rails-40-binstubs, http://mislav.uniqpath.com/2013/01/understanding-binstubs/, http://robots.thoughtbot.com/post/15346721484/use-bundlers-binstubs

      The haml-rails gem integrates with the template generators, out of the box!

      -

      How cool are named routes? post 'items/move_down/:id' => 'items#move_down', as: :move_down ), look at the routes.rb comments to know more about them.

      +

      How cool are named routes? post 'items/move_down/:id' => 'items#move_down', as: :move_down ), look at the routes.rb comments to know more about them.

      Amazon AWS S3 gem http://amazon.rubyforge.org

      I found a nice gem to add enumeration type to the ActiveRecord models: active_enum, but is it compatible with Rails 4? Here's a link on how to use it.

      -

      Ruby

      +

      ###Ruby

      I wrote some scripts to speed up some of my daily task at work, and used some nice gems in the meantime: nokogiri, to parse HTML using CSS selectors rest-client, fetching pages from the web with one line of code json, to parse JSON diffy, comparing strings has never been so easy mail, sending emails from your scripts

      -

      Coding Recipes

      +

      ###Coding Recipes

      http://codeartists.com/post/36892733572/how-to-directly-upload-files-to-amazon-s3-from-your

      http://quickleft.com/blog/keeping-your-json-response-lean-in-rails

      Several ways to run a command line command from a Ruby script.

      -

      Sysadmin

      +

      ###Sysadmin

      Fixing Postgres connection error on OS X Mountain Lion http://jaygoldman.com/2012/11/fixing-postgres-connection-errors-on-mountain-lion/ (funny because with Node there were no problems)

      -

      Javascript

      +

      ###Javascript

      I looked into a bunch of Javasciprt techs: Underscore.js, Jade, Handlebars, Stylus, Express

      -

      Tools

      +

      ###Tools

      http://imageoptim.com/

      -

      Software Engineering Good Practices

      +

      ###Software Engineering Good Practices

      Coupled dependencies, I found one of those monsters in a colleague's code. It took a lot of self-control to avoid being a prick and pointing it out on GitHub.

      -

      Interesting readings

      +

      ###Interesting readings

      How Basecamp Next got to be so damn fast without using much client-side UI

      diff --git a/2013/09/03/things-learned-in-august.html b/2013/09/03/things-learned-in-august.html index 47a462e..3bd1f32 100644 --- a/2013/09/03/things-learned-in-august.html +++ b/2013/09/03/things-learned-in-august.html @@ -1,19 +1,19 @@ Some things I learned in August | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in August

      iOS and Objective-C

      +

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in August

      ###iOS and Objective-C

      Since NSDecimalNumber can be init from a string there's the risk it's gonna produce a NaN. To avoid this check for [myDecimalNumber isEqualToNumber:[NSDecimalNumber notANumber]]

      xcoder a Ruby gem to automate our Xcode project management.

      -

      Ruby

      +

      ###Ruby

      As you know I have the -really good- habit of writing scripts to automate routine tasks in my work, mostly in Ruby. I naively used to check for arguments with ARGV.include? "--some-option", until a workmate had a look at my code and surprisedly asked why Ruby didn't had an option parser library like argparse module in Python. Turns out it does. Meet the OptionParser class.

      Configure URI.extract to avoid unexpected surpirses. http://blog.apptamers.com/post/48613650042/uri-extract-incorrect-in-ruby-1-9-3

      colorize, gem to add color to Ruby scripts.

      -

      Javascript

      +

      ###Javascript

      timeago, quick jQuery library to format datetimes in "xxx ago" strings.

      -

      Layout and CSS

      +

      ###Layout and CSS

      FlatUI framework

      Their slow in definig standards, but sometimes the W3C is a good place where to find resources. Fonts usable in CSS.

      Font Custom and IcoMoon, resources to aggregate icons in a font file, to use as font icons. Or, why not, to speedup iOS development, as I'm doing in one project of mine I may write about soon: MTFontIcon.

      -

      Interesting Readings

      +

      ###Interesting Readings

      -

      Tools

      +

      ###Tools

      waffle.io, a shared kanban board for your projects on GitHub.

      My workmates Adam Chainz introduced me to the Colemak keyboard layout.

      diff --git a/2013/09/16/xcode5-crash-on-submission.html b/2013/09/16/xcode5-crash-on-submission.html index f4314a0..05eddde 100644 --- a/2013/09/16/xcode5-crash-on-submission.html +++ b/2013/09/16/xcode5-crash-on-submission.html @@ -3,49 +3,47 @@

      mokacoding

      unit and acceptance testing, automation, productivity

      A workaround to Xcode 5 GM crash on app submission

      I just finished writing this post, and I realized is just about me complaining trying to sound funny. So here's, frontloaded, the important stuff.

      Apparently Xcode 5 GM crashed on some of us during the App Store submission process. Before even starting it. How annoying.

      The workaround I found relies on bypassing Xcode for the submission process.

      -

      Step 1

      +

      ####Step 1

      Make sure all the provisioning profiles and code signing are set properly

      -

      Step 2

      +

      ####Step 2

      Open your Terminal and generate the .ipa yourself, with the help of shenzhen.

      -
      cd my/ready/to/be/submitter/ios/project
      -ipa build -c Release
      -

      Step 3

      +
      cd my/ready/to/be/submitter/ios/project
      +ipa build -c Release

      ####Step 3

      Upload the app through Application Loader.

      -

      Step 4

      +

      ####Step 4

      Find a tv series to start watching while waiting for your app to be reviewed.

      That's all. It took me an embarrassing long while to figure this out, I hope to be helping some fellow developer with this post.

      Below the full thing.


      Every now and then in the lifecycle of an iOS project it comes the day when you have to submit an update, or even worst touch the provisioning profiles. When that day comes, it's better if it's a Monday, because you don't want to ruin yourself the weekend. And it's also better if you have chamomile in your cup instead of coffee.

      -

      Submit your iOS7 apps today

      +

      ###Submit your iOS7 apps today

      Submit today

      On the 10th of September Apple sent an email to their developers, "Submit your iOS7 apps today" they said. Up to that point we couldn't submit apps made with the iOS7 SDK, as written somewhere in the Xcode 5 Developer Preview release notes. But that day the iOS7 GM and Xcode 5 GM where released, and the run to submit started.

      Use Xcode 5 GM

      In their beautiful styled iOS7 developer page they explained everything. If you follow the link to the App Distribution Guide in the bottom of the page you will have a funny surprise. The link goes to the previous version documentation, and our Apple engineers forgot to add a link to the new version.

      Missing link

      I'm sure everything is gonna be fine, Xcode is such a reliable IDE, and the Apple guys are known for the quality of the products they give to their developers. Let's go!

      -

      The tragic message

      +

      ###The tragic message

      When clicking on "Validate" or "Distribute" from the organizer, no matter how may times I refreshed my Accounts in the Preferences menu this is what I got

      The terrible dialog

      And guess what? Both those buttons resulted in Xcode crashing, right there, with no explanation, no progress bar, nothing, Boom!

      Out of curiosity I opened the crash log that got generated and…

      -
      Crashed Thread:  0  Dispatch queue: com.apple.main-thread
      +
      Crashed Thread:  0  Dispatch queue: com.apple.main-thread
       
      -Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
      -Exception Codes: EXC_I386_GPFLT
      -

      Whenever I get an EXC_BAD_ACCESS (SIGSEGV) I feel like punching myself in the face, it's a memory issue, and I must have been really dumb to produce something like that in the ARC era.

      +Exception Type: EXC_BAD_ACCESS (SIGSEGV) +Exception Codes: EXC_I386_GPFLT

      Whenever I get an EXC_BAD_ACCESS (SIGSEGV) I feel like punching myself in the face, it's a memory issue, and I must have been really dumb to produce something like that in the ARC era.

      But let's not waste time complaining about those things, risking to be kicked out of the dev program, and look for a solution.

      -

      The workaround

      +

      ###The workaround

      What's the place where all the developers go when in trouble? No it's not church, it's StackOverflow! There I found someone with the same problem, suggesting to use Application Loader to upload the app.

      I never used it before, but I was faced with a problem straightaway. Application Loader need an .ipa, which we can generate only through the Organizer in Xcode.

      "which we can generate only through the Organizer in Xcode.". Are you sure about it?

      Actually xcodebuild, Xcode CLI, let us build ipas, in a very complex way. xctool buy the Facebook iOS team makes the task easier, but it the usual suspect, good guy Mattt that has the real solution for that. With his gem shenzhen we can build an ipa from command line without spending too much time specifing options or reading through the --help guide.

      -
      ipa build -c Release
      -

      That's all we need to generate our .ipa.

      +
      ipa build -c Release

      That's all we need to generate our .ipa.

      Once we have our package we can send it to the Apples servers through Application Loader, bypassing Organizer and the frustrating crash. Smart!

      -


      -That's all folks. I'm a bit disappointed by the fact that such an issue is leaked on a GM, when we, some of us at least, spend so much time unit testing our apps, being patient with the QA guys, and taking all the possible measures to make sure everything works as expected. But nobody's perfect, and every now and then hacking stuff is fun, so no big deal.

      +
      +That's all folks. I'm a bit disappointed by the fact that such an issue is leaked on a GM, when we, some of us at least, spend so much time unit testing our apps, being patient with the QA guys, and taking all the possible measures to make sure everything works as expected. But nobody's perfect, and every now and then hacking stuff is fun, so no big deal. +

      Happy coding!

      diff --git a/2013/09/17/mtfonticon.html b/2013/09/17/mtfonticon.html index d19f360..7c764b1 100644 --- a/2013/09/17/mtfonticon.html +++ b/2013/09/17/mtfonticon.html @@ -1,15 +1,15 @@ Bringing font icons in iOS with MTFontIcon | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      Bringing font icons in iOS with MTFontIcon

      Let me introduce you one of my latests projects, on which I worked almost a month ago, but I'm both lazy and hyperactive when it comes to projects, so the blog post arrives only now...

      -

      MTFontIcon

      +

      ###MTFontIcon

      MTFontIcons, available as a CocoaPod and on GitHub, is a library that let's us use font-based icons in iOS application, speeding up the development and helping those poor developers that don't even know how to select the pen tool in Adobe Illustrator.

      -

      The problem

      +

      ###The problem

      Few people in our world are both great developers and skilled artist, my friend and ex-colleague Tancredi is one of those. For the rest of us mere mortals finding building a well crafted app is already a big task, and we don't have time to go through the Nettus+ Illustrator and Photoshop tutorials to learn how to make a nice icon set for our apps. We only speak code.

      It would be really nice to have a way to iterate on the attributes of our icons and images quickly and without losing quality. Changing the color from #f0f0f0 to #f0dff1, making it 2pts wider, increasing the alpha of the shadow, without opening Illustrator, or worst waiting for the designer to put the assets on Dropobox. It would be nice to code all those things.

      -

      The solution

      +

      ###The solution

      The fact is our cousins from the web world already faced this problem, and solved in a really nice way! They've been using Icon Fonts for a while, and they're really happy about them. This technique is so powerful and popular that even the famous framework Bootstrap made by the guys at Twitter is using it. And there are plenty of resources only to get ready made stets of icons, or roll out our own font uploading the SVGs.

      -

      How does it work?

      +

      ###How does it work?

      Then why not using the same smartness in Objective-C? The MTFontIcon idea was born from the above mentioned rebel genious of Tancredi, while working on a prototype for a new concept at Memrise. Unfortunately the idea protoyped wasn't that good, unlike the tech behind it.

      The usage is simple:

        @@ -19,7 +19,7 @@

        How does it work?

      1. Get an instance of MTFontIconFactory and use it to get as many MTFontIconViews as you want :)

      Two minutes setup, two lines of code usage, twice as fast app UI development and polishing!

      -

      Current problems and roadmap

      +

      ###Current problems and roadmap

      Despite the 1.0.0 tag, MTFontIcon has still a long way to go before considering itself a mature and really useful project. Here's a list of things we could improve:

      • Issues with ascendant and descendants, if you ever tried to use a custom font on iOS you know what I'm talking about. Otherwise read this and this.
      • diff --git a/2013/09/23/setup-a-dev-machine.html b/2013/09/23/setup-a-dev-machine.html index 4e49273..e049c81 100644 --- a/2013/09/23/setup-a-dev-machine.html +++ b/2013/09/23/setup-a-dev-machine.html @@ -3,40 +3,31 @@

      mokacoding

      unit and acceptance testing, automation, productivity

      Setting a Mac for Development

      Last week I setup our new office Mac Mini, that we will use as CI server for our iOS apps (finally!), and for other tasks, such as a constant view on our products analytics.

      Our machine is the workshop where we create awesomeness (or bugs). I really love setting up a machine for development, but I've always ended up mad at something, or spending ages looking how to install this or that. So this time, once and for all, I took note of every step, and here's my little checklist on how to set up a Mac for development.

      Note: the original version of this post was long and basically just me blabbering about the usual suspects, Ruby, Node, Xcode… I refactored it in a condesed version. No need to thank me.

      -

      Setup OS X for Development: the checklist

      -

      Homebrew

      +

      ###Setup OS X for Development: the checklist

      +

      ####Homebrew

      Save time, and your sanity, use homebrew!

      -
      ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
      -

      homebrew saves stuff in /usr/local/bin, so make sure it comes before the default /bin in the $PATH.

      -
      export PATH=/usr/local/bin/:$PATH
      -

      zsh

      -
      brew install zsh
      -

      Zsh is cool, and with prezto we can make it super shiny. +

      ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

      homebrew saves stuff in /usr/local/bin, so make sure it comes before the default /bin in the $PATH.

      +
      export PATH=/usr/local/bin/:$PATH

      ####zsh

      +
      brew install zsh

      Zsh is cool, and with prezto we can make it super shiny.
      Note: the following instructions are from the prezto README, check it out just to be sure they are up to date.

      -
      zsh
      +
      zsh
       git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
       setopt EXTENDED_GLOB
       for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
         ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
      -done
      -

      Finally, set zsh as the default shell

      -
      chsh -s /usr/local/bin/zsh
      -

      Ruby, of course via rvm

      -
      \curl -L https://get.rvm.io | bash -s stable
      -rvm install 2.0.0
      -

      Python, a proper one

      -
      brew install python
      -

      Node.js

      +done

      Finally, set zsh as the default shell

      +
      chsh -s /usr/local/bin/zsh

      ####Ruby, of course via rvm

      +
      \curl -L https://get.rvm.io | bash -s stable
      +rvm install 2.0.0

      ####Python, a proper one

      +
      brew install python

      ####Node.js

      Just head to the home page and hit the green "Install" button, it's the reccomened way! Or use homebrew again:

      -
      brew install node
      -

      Xcode and the Command Line Tools

      +
      brew install node

      ####Xcode and the Command Line Tools

      Get it from Apple's Developer page, and then search for "Command Line Tools" in the "Downloads" tab of the "Preferences".

      There's also an open source way, but I haven't tried it.

      -

      Java

      +

      ####Java

      Apparently OS X doesn't come with Java ready for us, but at least installing it is easy, just try to use it in the terminal, and the installation wizard will start.

      -
      java
      -

      Some useful extra stuff

      +
      java

      ####Some useful extra stuff

      • Chrome
      • Alfred
      • diff --git a/2013/09/24/ios7-ux-designers-verdict.html b/2013/09/24/ios7-ux-designers-verdict.html index 2dca715..699b40a 100644 --- a/2013/09/24/ios7-ux-designers-verdict.html +++ b/2013/09/24/ios7-ux-designers-verdict.html @@ -3,18 +3,28 @@

      mokacoding

      unit and acceptance testing, automation, productivity

      Sharing some thoughts on iOS 7

      Today I read this article I added to my reading list a couple of days ago: iOS 7: leading UX designers give their verdict. I founded some of the opinions quite interesting and worth sharing.

      The functionality at the core of iOS7 hasn’t changed much it has just been extended in a number of ways. The main deviations are from a visual perspective.

      +
      +

      The biggest change is the introduction of a brighter colour palette, which allows Apple’s LCD screens to compete with vivid OLED smartphones (suc as the Samsung Galaxy). This allows Apple to increase its appeal to the Asian market who demonstrate a preference for bright colours throughout their consumption of visual culture.

      +
      +

      This suggests a shift in focus from user experience to customer experience.

      +
      +

      Kostja Paschalidis, service designer at Fjord


      A lot of the button pushing, slide out panels and alert boxes from the previous skin were reminiscent of stale formats we are accustomed to from the 'Web 2.0' era and the lack of innovation within Windows.

      +
      +

      Andy Parker, UX designer at Clearleft


      We know when a button's a button. It doesn't need real-world lighting to trick us into tapping it. We're living in a digitally savvy world now compared to 2007 when the iPhone first launched. Therefore UI in general going forward will feel authentically digital and that's regardless of the mobile platform it's being designed for.

      +
      +

      Shaun Tollerton, Visual Designer at ustwo

      diff --git a/2013/10/02/things-learned-in-september.html b/2013/10/02/things-learned-in-september.html index 8c15183..da163eb 100644 --- a/2013/10/02/things-learned-in-september.html +++ b/2013/10/02/things-learned-in-september.html @@ -1,19 +1,19 @@ Some things I learned in September | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in September

      Javascript and Data Visualization

      +

      mokacoding

      unit and acceptance testing, automation, productivity

      Some things I learned in September

      ###Javascript and Data Visualization

      My company wanted a custom viewer for analytics data, perfect occasion for experiment with data visualization powered by Javascript. I started by taking a look at D3.js, which is the library used by the GitHub guys to draw their amazing repo graphs. It's incredibly powerful, but requires quite a bit of coding to get stuff done. I then used Chart.js for a bit. It's smaller, simpler, and faster to learn. This all comes with the downside of being less powerful, and with not enough of the features I needed out of the box. Also the development seems to be going really slow at the moment. So now I'm working with gRaphaël, it's built on top of Raphaël and has more of the things I was looking for ready made.

      -

      Node, node, node!

      +

      ###Node, node, node!

      With the project I mentioned above I finally had the occasion to spend company time working on Node.js. I like how lighter it is compared to Rails, and I'm definitely gonna keep experimenting with it.

      In fact I used Node + Heroku to setup my personal landing page.

      Sneak peek: having setup an Node + Express + Coffeescript task more than two times, and being DRY, or lazy, I've decided to put it in a repo. Stay tuned!

      -

      Bower

      +

      ###Bower

      They've done it again! After Bootstrap the Twitter team has released Bower "A package manager for the web". It's the bundler or npm of your web packages. Smart! One of those things you say "How could I've lived without it?"

      -

      Other Javascript stuff

      +

      ###Other Javascript stuff

      • Moment.js, a slim yet powerful library to manipulate time.
      • I've played quite a lot with Jade, it's really cool, but not as flexible as I hope, or maybe I need to dig more in the documentation…. Anyway, I found this nice Javascript Template Chooser.
      -

      CSS Frameworks

      +

      ###CSS Frameworks

      I looked into alternatives to Bootstrap. Here's what I found:

      -

      Jenkins

      +

      ###Jenkins

      I've finally been able to plant the seed of the TDD and CI culture in my company. They bought me a Mac Mini, and I've set it up with Jenkins. It's been a bit painful, but really fun! And now we have the tests running at every push and two nightly builds, development and qa, distributed via TestFlight. It's a shame I'm the only iOS dev who writes tests :(

      -

      Ruby

      +

      ###Ruby

      I had a quick, and not finished yet, blast at making a ruby gem. Enter Swagify a gem to add some your commands and scripts outputs. I'm not gonna talk too much about it here, as I don't consider the learning experience over (it never is btw).

      -

      Readings

      +

      ###Readings

      -

      Something funny

      +

      ###Something funny

      • Sloppy UI - It's all about the flaws in iOS 7 design
      • the_coding_love(); - Funny gifs to ease the dev life
      • diff --git a/2013/10/06/october-questions.html b/2013/10/06/october-questions.html index 17a6a75..2881f1f 100644 --- a/2013/10/06/october-questions.html +++ b/2013/10/06/october-questions.html @@ -10,16 +10,16 @@

        You can ask yourself two extremely useful questions about any given area to drill down into the murky layer: How does it work? and Why does this (have to) happen?

        So this is what I'm gonna do (more) from now on. Spending time asking myself this type of questions around the technologies I use. And, inspired a bit by Jennifer Dewalt (180 websites im 180 days), I'm gonna track everything here. Let's get started!

        -

        October's Questions

        +

        ##October's Questions

        I'll start by trying understand better the tools I use in my daily job. At the moment I'm working as an iOS developer and next to the classic iOS SDK, Objective-C, Xcode and the iPhone Simulator, I'm making massive use of CocoaPods, AFNetworking, and xctool.

        I already have many questions on those technologies and tools, but one thing I've learned about propositions is start small!. So I'll start with only four questions. One per week, this shouldn't be hard to accomplish.

        -

        1 - Xcode

        +

        ###1 - Xcode

        How does it... stores the informations about project and workspace?

        -

        2 - Objective-C

        +

        ###2 - Objective-C

        Why does it... allow us to use the messages syntax AND the dot notation to call methods?

        -

        3 - CocoaPods

        +

        ###3 - CocoaPods

        How does it... generate the workspace and manage the pods in it?

        -

        4 - AFNetworking

        +

        ###4 - AFNetworking

        How does it... wrap Apple's newtworking classes?

      diff --git a/2013/10/31/Xcode-projects-and-workspaces.html b/2013/10/31/Xcode-projects-and-workspaces.html index 1eec957..9ec4172 100644 --- a/2013/10/31/Xcode-projects-and-workspaces.html +++ b/2013/10/31/Xcode-projects-and-workspaces.html @@ -10,7 +10,7 @@

      Cool, I got that, but what about the file itself? Let's open one with a text editor. I've used the project.pbxproj from KZPropertyMapper a smart and timesaving library that you should all checkout.

      It appears as a sort of JSON, written in C, as it as a {} hierarchy, with inside =, ; and /* inline comments */.

      The top level is something like

      -
      // !$*UTF8*$!
      +
      // !$*UTF8*$!
       {
           archiveVersion = 1;
           classes = {
      @@ -20,31 +20,28 @@
               ...
           };
           rootObject = CDAC62FA17A0EF1A00F5452A /* Project object */;
      -}
      -

      The objects part is the real deal. Everything about the project is in there. All stored again in a dictionary fashion, with hexadecimal identifiers. A common parameter is the isa key. Here's an example:

      -
      CDAC634017A0EF4C00F5452A /* KZPropertyMapper.m in Sources */ = {
      +}

      The objects part is the real deal. Everything about the project is in there. All stored again in a dictionary fashion, with hexadecimal identifiers. A common parameter is the isa key. Here's an example:

      +
      CDAC634017A0EF4C00F5452A /* KZPropertyMapper.m in Sources */ = {
           isa = PBXBuildFile;
           fileRef = CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */;
      -};
      -

      Lucky for us Xcode adds some comments to make the things a bit more readable for humans. Note: I'm sure they're comment and not part of the way stuff is written because I actually tried changing one and everything run fine.

      +};

      Lucky for us Xcode adds some comments to make the things a bit more readable for humans. Note: I'm sure they're comment and not part of the way stuff is written because I actually tried changing one and everything run fine.

      The objects has many sections, each wrapped between /* Begin SectionName section */ and /* End SectionName section */ comments.

      Here's the ones I found more interesting, the xcodeproj gem documentation used by CocoaPods has been really helpful in understanding what some sections were about:

      -

      PBXFileReference

      +

      ####PBXFileReference

      All the files in the project are in this list.

      -
      CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */ = {
      +
      CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */ = {
           isa = PBXFileReference;
           fileEncoding = 4;
           lastKnownFileType = sourcecode.c.objc;
           path = KZPropertyMapper.m;
           sourceTree = "<group>";
      -};
      -

      PBXGroup

      +};

      ####PBXGroup

      This section has the groups tree. The groups are those fake folders that are useful only to create confusion on how the filesystem is oraganized. A PBXGroup can contain PBXFirleReferences, as well as other PBXGroups.

      -

      PBXNativeTarget

      +

      ####PBXNativeTarget

      In this section we have the settings of the Targets of the project, in particular there's references to buildPhases and buildRules, like in the UI.

      -

      PBXShellScriptBuildPhase

      +

      ####PBXShellScriptBuildPhase

      Here we have the settings for a Build Phase of type Run Script. The funny thing about this part is that the script you insterted in the text box is stored as a one string…

      -

      PBXVariantGroup

      +

      ####PBXVariantGroup

      I found it hard to guess from the name, but here we have the information about the localized files.

      That's it, more or less… The project.pbxproj file stores all the informations regarding the project we're working on, and it's organized in a lot of meaningful sections related together by keeping track of the objects identifiers in form of hex hashes. Let's move on to the workspace then.

      I first came across an Xcode workspace when I used Kobold2d to develop a simple and unsuccesful game of iOS. It's easy to guess what a workspace might be.

      @@ -53,7 +50,7 @@

      PBXVariantGroup

      A workspace is an Xcode document that groups projects and other documents so you can work on them together. A workspace can contain any number of Xcode projects, plus any other files you want to include. In addition to organizing all the files in each Xcode project, a workspace provides implicit and explicit relationships among the included projects and their targets.

      The .xcworkspace from KZPropertyMapper is too tiny, so let's take a look at another one, AFNetworking. As for the project the workspace is nothing but a folder, grouping configuration files. The interesting file here is contents.xcworkspacedata. Let's open it… Surprise! Unlike the project file this one is a more readable XML. Inside there's a list of the workspace components.

      -
      <?xml version="1.0" encoding="UTF-8"?>
      +
      <?xml version="1.0" encoding="UTF-8"?>
       <Workspace
           version = "1.0">
           <Group
      @@ -82,15 +79,15 @@ 

      PBXVariantGroup

      location = "group:Tests/AFNetworking Tests.xcodeproj">
      </FileRef> ... -</Workspace> -
      +</Workspace>

      If you open the AFNetworking.xcworkspace you'll see this

      -

      AFNetworking Workspace

      +AFNetworking Workspace +

      It all then comes together. It works more or less as the project.pbxproj does. The Group tag contains other Groups or FileRef tags, which represent where the file is in the filesystem related to the location of the workspace.

      This is it. Of course there could be, and may be there will be, a lot more to dig and look into, but for tonight I'm fine with this. I now have a clearer picture of what happens when I add a new file to a project or I use the GUI to edit the configurations of a target. I can't say this is gonna make my everyday battle with Xcode easier, but definitely knowing more of how it works makes me feel smarted.

      Happy coding.

      -

      References

      +

      ###References

      The script

      -
      #!/bin/bash
      +
      #!/bin/bash
       
       git=$(sh /etc/profile; which git)
       number_of_commits=$("$git" rev-list HEAD --count)
      @@ -25,8 +25,7 @@ 

      The script

      /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $number_of_commits" "$plist" /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${git_release_version#*v}" "$plist" fi -done -
      +done

      You should save this script as set_build_number.sh, in a folder named Scripts in the root of your project.

      How to set this up

      The best way to assure the script is run automatically is to execute it as a Run Script Build Phase. To do so in Xcode 7:

      diff --git a/blog/automating-ios-enterprise-deployment/index.html b/blog/automating-ios-enterprise-deployment/index.html index 2fe149f..31b1e2d 100644 --- a/blog/automating-ios-enterprise-deployment/index.html +++ b/blog/automating-ios-enterprise-deployment/index.html @@ -2,32 +2,30 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

      Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

      mokacoding

      unit and acceptance testing, automation, productivity

      Automating iOS Enterprise Deployment with shenzhen

      In this short post I'm gonna have a look at how to use the splendid shenzhen gem by Mattt to automate the process of building an .ipa for enterprise distribution and shipping it.

      Here's the code for the build phase:

      -
      ipa build \
      -  --workspace MyAwesomeApp.xcworkspace \
      -  --configuration MyAwesomeAppEnterpriseConfiguration \
      -  --scheme MyAwesomeAppEnterpriseScheme \
      -  --embed MyAweseomAppEnterpriseDistribution.mobileprovision \
      -  --clean \
      -  --archive"
      -

      or the shorter version:

      -
      ipa build \
      -  -w MyAwesomeApp.xcworkspace \
      -  -c MyAwesomeAppEnterpriseConfiguration \
      -  -s MyAwesomeAppEnterpriseScheme \
      -  -m MyAweseomAppEnterpriseDistribution.mobileprovision \
      -  --clean \
      -  --archive"
      -

      How does it work?

      +
      ipa build \
      +  --workspace MyAwesomeApp.xcworkspace \
      +  --configuration MyAwesomeAppEnterpriseConfiguration \
      +  --scheme MyAwesomeAppEnterpriseScheme \
      +  --embed MyAweseomAppEnterpriseDistribution.mobileprovision \
      +  --clean \
      +  --archive"

      or the shorter version:

      +
      ipa build \
      +  -w MyAwesomeApp.xcworkspace \
      +  -c MyAwesomeAppEnterpriseConfiguration \
      +  -s MyAwesomeAppEnterpriseScheme \
      +  -m MyAweseomAppEnterpriseDistribution.mobileprovision \
      +  --clean \
      +  --archive"

      How does it work?

      What shenzhen does is calling xcodebuild for us using the proper arguments and avoiding the unreadable output. Speaking of which, take a look at what xcpretty does to help us.

      As you can see from the code above there are quite a few options to specify. In particular in my experience I saw that to build properly we need both --scheme and --configuration. If you are reading this article you're probably already managing your enterprise build with a different pair of Build Configuration and Scheme, in order to change the Bundle Id and the other configurations, so those parameters will surely make sense to you. But why both?

      As far as I can see after 10 minutes of hacking this is due to the fact that shenzen looks for the configuration parameter if this is not specified, source here), and passes it to xcodebuild. What happens in my case is that shenzhen guesses the wrong configuration, and this is why I have to specify it in the parameters. No big deals anyway ;)

      Another thing we notice in the parameters is the --embed XXX.mobileprovision one. This is used to sign the build with the certificate specified for the enterprise distribution. You can download the Provisioning Profile you need from the Member Center in the Apple Developer Portal. Keep it in a safe place! Everything will work fine as long as you have the private key for that.

      A tip I have regarding the Provisioning Profile is to be sure that the keychain where its keys are is unlocked, unless you want to the OS to pop you a dialog asking for the keychain credentials at some point. The keychain can be unlocked from the Keychain Access app.

      -

      Time to distribute!

      +

      Time to distribute!

      shenzhen's distribute command lets us distribute our freshly built .ipa through 4 different channels, HockeyApp, TestFlight, upload to S3, or simple FTP.

      Take a look at the README for the details of the single channels, or just type ipa distribute:XXX --help to find out about the parameter.

      It's super simple!

      -

      Where to go from here?

      +

      Where to go from here?

      • Is it possible to unlock the keychain from the script, maybe just for its execution, in order to have more protections?
      • Dig better into the scheme and configuration issue, and maybe submit a PR.
      • diff --git a/blog/automating-mokacoding-weekly/index.html b/blog/automating-mokacoding-weekly/index.html index 4527cf7..4daaeae 100644 --- a/blog/automating-mokacoding-weekly/index.html +++ b/blog/automating-mokacoding-weekly/index.html @@ -4,36 +4,31 @@

        At the end of March 2015 "mokacoding weekly" issue 1 was sent to 49 subscribers.

        The newsletter is sent with MailChimp, which has a WYSIWYG/HTML editor for the email content.

        Issue number 2 was sent out by duplicating the campaign made for the previous one, and by changing the content.

        -

        That wasn't a fun experience, the format kept changing for no reason, and it was hard to set it back to the original one. Even after discovering that you can write raw HTML in the editor, the situation didn't improve. After working with haml or jade old school HTML is too cumbersome.

        +

        That wasn't a fun experience, the format kept changing for no reason, and it was hard to set it back to the original one. Even after discovering that you can write raw HTML in the editor, the situation didn't improve. After working with haml or jade old school HTML is too cumbersome.

        A good automation rule of thumb is "three strikes and you automate", if you have to do something that you already did two times, automate it. And that's why before it was time to send out issue number 3 an automated workflow was put in place. You can have a look at it on GitHub.

        Taking care of the layout being the bigger pain point at the time, that's the first issue that this automate workflow tries to solve, or at least smooth. The question was how can we avoid writing HTML, but still have good formatting?

        The answer was easy, it'd be great to write in Markdown the same way I can do forthis blog.

        The redcarpet gem allows you to parse .md files in valid HTML ones, and it also comes with a command line interface.

        -
        redcarpet mokacoding-weekly-003.md mokacoding-weekly-003.html
        -

        To keep the amount of editing as little as possible I extracted the header and footer common to every issue in two files. These can be appended and prepended to the one with the real content, which is the only one that changes.

        -
        redcarpet header.md mokacoding-weekly-003.md footer.md
        -

        To avoid typing that long command every week there is a Rake task, rake build, that does it for us.

        +
        redcarpet mokacoding-weekly-003.md mokacoding-weekly-003.html

        To keep the amount of editing as little as possible I extracted the header and footer common to every issue in two files. These can be appended and prepended to the one with the real content, which is the only one that changes.

        +
        redcarpet header.md mokacoding-weekly-003.md footer.md

        To avoid typing that long command every week there is a Rake task, rake build, that does it for us.

        Now to we can simply write the new issue content with the comfort of the markdown syntax, type rake build, and paste the output into MailChimp.

        Even more automation

        This workflow is already better that doing everything manually... but it can still be improved!

        One point that can could be talked is the copy-paste of the content. Why should one select and copy the generated HTML output manually? Let's make it automatic.

        Mac OS X provides a nice command, pbcopy to copy text input to the Clipboard.

        -
        redcarpet ... | pbcopy
        -
        +
        redcarpet ... | pbcopy

        That's better 😎

        Another manual task is the numbering. Is it really necessary to remember the number of the previous issue, or have to look it up? Let's make it automatic.

        -
        task :new do
        +
        task :new do
           # count how many issuse we have already and increment by 1
           next_number = '%03d' % (Dir["#{issues_folder}/*.md"].length + 1)
         
           path = "#{issues_folder}/mokacoding-weekly-#{next_number}.md"
           sh "touch #{path}"
        -end
        -
        +end

        Done, no need to count any more, simply type rake new.

        We can go even further! Why should one open the text editor? Let's make is automatic! The Rake task can be modified by adding the following line after the file has been generated.

        -
        sh "#{ENV['VISUAL']} #{path}"
        -
        +
        sh "#{ENV['VISUAL']} #{path}"

        Which will open the newly created markdown file using the text editor set in the VISUAL environment variable.

        Using the env var is cool, it makes the workflow agnostic of the text editor.

        That's more or less it. The workflow consist in only two shell command and a Cmd-V, plus all the MailChimp release steps.

        diff --git a/blog/better-build-phase-scripts/index.html b/blog/better-build-phase-scripts/index.html index fb208b4..1ab8596 100644 --- a/blog/better-build-phase-scripts/index.html +++ b/blog/better-build-phase-scripts/index.html @@ -3,7 +3,8 @@

      mokacoding

      unit and acceptance testing, automation, productivity

      Better Xcode Run Script Build Phases

      Xcode offers the possibility to run user defined code as part of the build process using the "Run Script Phase" in the "Build Phases" section.

      -

      Build Phase Menu to add a Run Script Phase

      +Build Phase Menu to add a Run Script Phase +

      This is a very handy feature as it allows us to do things like:

      • Dynamically set the version and build number based on external parameters, e.g. commits count
      • @@ -41,8 +42,7 @@

        Extract the script

        You can then make your script executable by changing its permission using this command in the terminal:

        -
        chmod u+x Build-Phases/my-script.sh
        -

        Finally you can replace the script content in the Xcode build phase editor with +

        chmod u+x Build-Phases/my-script.sh

        Finally you can replace the script content in the Xcode build phase editor with a command to execute your script:

        $SRCROOT/Build-Phases/set-build-number

        Extracted run script

        @@ -68,39 +68,35 @@

        Report errors and warnings

        You can make your scripts output compilation errors or warnings the same way Xcode does. I learnt this a while ago from this post.

        -
        echo "error: Your error message"
        -echo "warning: Your warning message"
        -

        This ability is quite handy, it allows you to communicate with the other +

        echo "error: Your error message"
        +echo "warning: Your warning message"

        This ability is quite handy, it allows you to communicate with the other developers using the script. You can use this for example to fail the build when required software is missing.

        Ensure required tools are available

        A common use of run script build phases is to integrate third party tools into the build process, but what happens when such tools are not present in the developer's machine? It's a good idea to fail the build and inform them that their setup is incomplete. This is how you can do it:

        -
        set -e
        +
        set -e
         
         if ! which <your tool> > /dev/null; then
           echo "error: <your tool> is missing"
           exit 1
        -fi
        -
        +fi

        For example if you want to make sure new developers have SwiftLint installed, you can use this script:

        -
        set -e
        +
        set -e
         
         if ! which swiftlint > /dev/null; then
           echo "error: SwiftLint is not installed. Vistit http://github.com/realm/SwiftLint to learn more."
           exit 1
         fi
         
        -swiftlint
        -
        +swiftlint

        Or if you feel that failing the build is too harsh, you can just throw a warning:

        -
        set -e
        +
        set -e
         
         if ! which swiftlint > /dev/null; then
           echo "warning: SwiftLint is not installed. Vistit http://github.com/realm/SwiftLint to learn more."
         else
           swiftlint
        -fi
        -
        +fi

        Debug tips

        As with all software, run scripts phases don't usually come out right at the first try (at least not for me). Here's two debugging tips:

        diff --git a/blog/better-merging-for-github-pull-requests/index.html b/blog/better-merging-for-github-pull-requests/index.html index 6fe4fa2..c6a2991 100644 --- a/blog/better-merging-for-github-pull-requests/index.html +++ b/blog/better-merging-for-github-pull-requests/index.html @@ -11,13 +11,11 @@ Obvious, yes, but sometimes not desirable and other times not possible because of established team conventions. This post doesn't want to be an argument for merging vs. squashing. The idea of keeping a clear and informative Git history is valid regardless of how we get our changes into it.

        -

        Why does the merge commit title matter?

        +

        Why does the merge commit title matter?

        Imagine someone offered you a million dollars if you can guess what the latest commit on a repository does by only reading its title. Would you rather the commit title was this:

        -
        Merge pull request #123 from add-author-label
        -

        or this:

        -
        Add author label to blogpost description view (#123)
        -

        Obviously, no one will ever ask you to guess what a commit does only by reading its title – let alone offer you a million dollars. +

        Merge pull request #123 from add-author-label

        or this:

        +
        Add author label to blogpost description view (#123)

        Obviously, no one will ever ask you to guess what a commit does only by reading its title – let alone offer you a million dollars. Still, understanding what code does and working with it is something you are being paid for. The easier you can do that the more value you can bring to the table.

        It's true that the GitHub UI makes it easy to bring up extra information for a commit, as well as the PR it belongs to. @@ -35,19 +33,17 @@

        Turn your Git log into a readab

        The git log command has an option called --first-parents to follow only the first parent commit upon seeing a merge commit. When applied to the log on the main branch of a repository, where all the PRs get merged, the result is a list of merge commits only.

        Compare the output when using a descriptive title to the PR merge commit vs. the default one:

        -
        $ git log --pretty=oneline --abbrev-commit --first-parent
        +
        $ git log --pretty=oneline --abbrev-commit --first-parent
         
        -a2055b7 (HEAD -> trunk, origin/trunk) Merge pull request #4 from mokagio/feature-author-label
        -64344e0 Merge pull request #3 from mokagio/improve-mobile-layout
        -70ba8ac Merge pull request #2 from mokagio/feature-more-negative-space
        -7d5c9da Merge pull request #1 from mokagio/feature-dark-mode-css-support
        -
        git log --pretty=oneline --abbrev-commit --first-parent
        +a2055b7 (HEAD -> trunk, origin/trunk) Merge pull request #4 from mokagio/feature-author-label
        +64344e0 Merge pull request #3 from mokagio/improve-mobile-layout
        +70ba8ac Merge pull request #2 from mokagio/feature-more-negative-space
        +7d5c9da Merge pull request #1 from mokagio/feature-dark-mode-css-support
        git log --pretty=oneline --abbrev-commit --first-parent
         
         a2055b7 (HEAD -> trunk, origin/trunk) Add author label to post metadata component (#4)
         64344e0 Improve layout on mobile devices (#3)
         70ba8ac Use more negative space (#2)
        -7d5c9da Support dark mode via CSS media query (#1)
        -

        The second log reads like a story. +7d5c9da Support dark mode via CSS media query (#1)

        The second log reads like a story. The first has little information to offer other than the fact that stuff got merge in this branch.

        When you pull the latest changes from your main branch, you can run this filtered git log to get an idea of the recent changes. Tip: define an alias for it to make it easier to call it; mine is glgf.

        diff --git a/blog/better-swift-date-compare-tests/index.html b/blog/better-swift-date-compare-tests/index.html index 701097e..c1db1f9 100644 --- a/blog/better-swift-date-compare-tests/index.html +++ b/blog/better-swift-date-compare-tests/index.html @@ -5,27 +5,26 @@ On top of that, there is the unstoppable passage of time, which can result in code that works in the present not working in the future.

        xkcd reference: Supervillain Plan

        -Source: xkcd – Supervillain Plan. +_Source: [xkcd – Supervillain Plan](https://xkcd.com/1883/)._

        Here's a simplified version of code I've seen out in the wild more than once:

        -
        // PromoCode.swift
        +
        // PromoCode.swift
         struct PromoCode {
             let createdAt: Date
             // Expire after one year (without accounting for leap year)
        -    private let expiry: TimeInterval = 365 * 24 * 60 * 60
        +    private let expiry: TimeInterval = 365 * 24 * 60 * 60
         
        -    func isExpired() -> Bool {
        -        return Date().timeIntervalSince(createdAt) > expiry
        +    func isExpired() -> Bool {
        +        return Date().timeIntervalSince(createdAt) > expiry
             }
         }
         
         // PromoCodeTests.swift
        -func testIsExpiredFalseBeforeOneYear() {
        -    let promoCode = PromoCode(createdAt: Date.with(year: 2020, month: 6, day: 7))
        +func testIsExpiredFalseBeforeOneYear() {
        +    let promoCode = PromoCode(createdAt: Date.with(year: 2020, month: 6, day: 7))
             XCTAssertFalse(promoCode.isExpired())
        -}
        -
        +}

        Note: Date.with(year:, month:, day:) is a syntax sugar method, not part of the standard library. You can find its source here.

        If you are reading this post after June 7th, 2021, you probably spotted the issue. When the author wrote the test, it passed, but they didn't realize it would start failing once the clock reached June 7th, 2021.

        @@ -34,17 +33,16 @@

        When testing Swift code that compares dates, it's essential to remove the influence of the passage of time to avoid unexpected failures in the future.

        There is a simple refactor we can make to avoid this issue once and for all. We can decouple the test from the system clock by injecting the reference date for the comparison operation.

        -
        // PromoCode.swift
        -func isExpired(at referenceDate: Date = Date()) -> Bool {
        -    return referenceDate.timeIntervalSince(createdAt) > expiry
        +
        // PromoCode.swift
        +func isExpired(at referenceDate: Date = Date()) -> Bool {
        +    return referenceDate.timeIntervalSince(createdAt) > expiry
         }
         
         // PromoCodeTests.swift
        -func testIsExpiredFalseBeforeOneYear() {
        -    let promoCode = PromoCode(createdAt: Date.with(year: 2020, month: 6, day: 3))
        +func testIsExpiredFalseBeforeOneYear() {
        +    let promoCode = PromoCode(createdAt: Date.with(year: 2020, month: 6, day: 3))
             XCTAssertFalse(promoCode.isExpired(at: Date.with(year: 2021, month: 6, day: 3)))
        -}
        -
        +}

        Relying on Date() makes your non-deterministic because it produces a different value literally every time you run the tests. Non-deterministic tests, that is, tests that don't behave in the same way every time you run them, cannot be trusted. They may fail at any time and distract developers who experience them while working on unrelated parts of the codebase.

        diff --git a/blog/better-tests-for-delegates/index.html b/blog/better-tests-for-delegates/index.html index d7a5bad..cabd78e 100644 --- a/blog/better-tests-for-delegates/index.html +++ b/blog/better-tests-for-delegates/index.html @@ -10,53 +10,52 @@ assert the behavior you are expecting by looking into the state of the spy.

        For example, we can test how a ResourceFetcher type calls its delegate upon a successful fetch like this.

        -
        import XCTest
        +
        import XCTest
         import Nimble
         
         class ResourceFetcherTests: XCTestCase {
         
        -  func testCallsDelegateOnSuccess() {
        -    let resourceFecther = ResourceFetcher()
        -    let delegateSpy = ResourceFetcherDelegateSpy()
        -    resourceFecther.delegate = delegateSpy
        +  func testCallsDelegateOnSuccess() {
        +    let resourceFecther = ResourceFetcher()
        +    let delegateSpy = ResourceFetcherDelegateSpy()
        +    resourceFecther.delegate = delegateSpy
         
             resourceFecther.fetch()
         
             expect(delegateSpy.didCallResourceFetched).toEventually(beTrue())
        -    expect(delegateSpy.didCallResourceFetchedValue).toEventually(equal(Resource(id: 1)))
        +    expect(delegateSpy.didCallResourceFetchedValue).toEventually(equal(Resource(id: 1)))
           }
         }
         
         protocol ResourceFetcherDelegate: class {
         
        -  func resourceFetcher(_ resourceFetcher: ResourceFetcher, fetched resource: Resource)
        +  func resourceFetcher(_ resourceFetcher: ResourceFetcher, fetched resource: Resource)
         }
         
         class ResourceFetcher {
         
        -  weak var delegate: ResourceFetcherDelegate?
        +  weak var delegate: ResourceFetcherDelegate?
         
        -  func fetch() {
        +  func fetch() {
             // In a real system, you would have something like a network request here.
        -    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) { [weak self] in
        -      guard let self = self else { return }
        +    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) { [weak self] in
        +      guard let self = self else { return }
         
        -      self.delegate?.resourceFetcher(self, didFetch: Resource(id: 1))
        +      self.delegate?.resourceFetcher(self, didFetch: Resource(id: 1))
             }
           }
         }
         
         lass ResourceFetcherDelegateSpy: ResourceFetcherDelegate {
         
        -  private(set) var didCallResourceFetched = false
        -  private(set) var didCallResourceFetchedValue: Resource?
        +  private(set) var didCallResourceFetched = false
        +  private(set) var didCallResourceFetchedValue: Resource?
         
        -  func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource) {
        -    didCallResourceFetched = true
        -    didCallResourceFetchedValue = resource
        +  func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource) {
        +    didCallResourceFetched = true
        +    didCallResourceFetchedValue = resource
           }
        -}
        -
        +}

        I talk more about this testing tactic here.

        Behaviour vs. Implementation

        I want my test suites to help developers as their codebase evolves. @@ -84,11 +83,10 @@

        Behaviour vs. Implementation

        (tableView(_:didSelectRowAt:), urlSession(_:didReceive:completionHandler:) etc.)

        -
        - func resourceFetcher(_ resourceFetcher: ResourceFetcher, fetched resource: Resource)
        -+ func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource)
        -
        +
        - func resourceFetcher(_ resourceFetcher: ResourceFetcher, fetched resource: Resource)
        ++ func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource)

        To make our test read consistently, we would have to update them:

        -
          // ResourceFetcherTests.swift
        +
          // ResourceFetcherTests.swift
         - expect(delegateSpy.didCallResourceFetched).toEventually(beTrue())
         - expect(delegateSpy.didCallResourceFetchedValue).toEventually(equal(Resource(id: 1)))
         + expect(delegateSpy.didFetchResourceCalled).toEventually(beTrue())
        @@ -107,8 +105,7 @@ 

        Behaviour vs. Implementation

        - didCallResourceFetchedValue = resource + didFetchResourceCalled = true + didFetchResourceValue = resource - } -
        + }

        I know, it's a small thing. However, small things matter, and they do add up. @@ -131,11 +128,11 @@

        A behavior-oriented delegate test

        In the ResourceFetcher example above we could use something like this:

        -
        // ResourceFetcherTests.swift
        -func testCallsDelegateOnSuccess() {
        -  let resourceFecther = ResourceFetcher()
        -  let delegateSpy = ResourceFetcherDelegateSpy()
        -  resourceFecther.delegate = delegateSpy
        +
        // ResourceFetcherTests.swift
        +func testCallsDelegateOnSuccess() {
        +  let resourceFecther = ResourceFetcher()
        +  let delegateSpy = ResourceFetcherDelegateSpy()
        +  resourceFecther.delegate = delegateSpy
         
           resourceFecther.fetch()
         
        @@ -146,17 +143,16 @@ 

        A behavior-oriented delegate test

        // ResourceFetcherDelegateSpy.swift class ResourceFetcherDelegateSpy: ResourceFetcherDelegate { - private var fetchedResource: Resource? + private var fetchedResource: Resource? - func wasCalledForSuccessfulFetch(of resource: Resource) -> Bool { - return fetchedResource == resource + func wasCalledForSuccessfulFetch(of resource: Resource) -> Bool { + return fetchedResource == resource } - func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource) { - fetchedResource = resource + func resourceFetcher(_ resourceFetcher: ResourceFetcher, didFetch resource: Resource) { + fetchedResource = resource } -} -
        +}

        When reading the test, we don't focus on the implementation details of the method name and its parameters, @@ -164,7 +160,7 @@

        A behavior-oriented delegate test

        wasCalledForSuccessfulFetch(of:) method in the Spy.

        Notice as well how the diff for a change in the delegate method name looks like this time:

        -
          class ResourceFetcherDelegateSpy: ResourceFetcherDelegate {
        +
          class ResourceFetcherDelegateSpy: ResourceFetcherDelegate {
         
             private var fetchedResource: Resource?
         
        @@ -176,8 +172,7 @@ 

        A behavior-oriented delegate test

        + func resourceFetcher(_ resourceFetcher: ResourceFetcher, fetched resource: Resource) { fetchedResource = resource } - } -
        + }

        Because of the abstraction layer between how the delegate works and how we check if it's consumed properly, diff --git a/blog/better-tests-with-specta/index.html b/blog/better-tests-with-specta/index.html index 058ff0c..5fd7c56 100644 --- a/blog/better-tests-with-specta/index.html +++ b/blog/better-tests-with-specta/index.html @@ -26,7 +26,7 @@

        The task

        Given this very simple specification we can make and ElementFormatter class, with a formattedStringForElement: method.

        The XCTest way

        The test for this class, written using XCTest would look something like this:

        -
        #import <UIKit/UIKit.h>
        +
        #import <UIKit/UIKit.h>
         #import <XCTest/XCTest.h>
         #import "ElementFormatter.h"
         
        @@ -67,12 +67,11 @@ 

        The XCTest way

        XCTAssertEqualObjects([self.formatter formattedElementString:data], @"[E] element (42)", @"ElementFormatter did not format valid element data as expected"); } -@end -
        +@end

        The Specta way

        Now let's add Specta and its expectation and matching library Expecta to our project and write a test, actually a spec using the xSpec terminology, for ElementFormatter.

        Note: I don't know why the text highlighting is not working properly. This blog is open source though, so if you have a suggestion on how to fix it I'd love a PR.

        -
        #import <Specta.h>
        +
        #import <Specta.h>
         #import <Expecta.h>
         #import "ElementFormatter.h"
         
        @@ -122,19 +121,17 @@ 

        The Specta way

        }); }); -SpecEnd -
        +SpecEnd

        What do you think about it?

        In my opinion the Specta version explains what the system under test is supposed to do better, and is more readable.

        Thanks to the context and describe blocks (they are aliases) we can organize the spec like a book, with chapter and paragraphs. Using the it block we can focus only on the expected result, moving any clutter due to setup code in the context block. The only way to achieve a similar result with XCTest is to use comments, or multiple files, with Specta we have built in support for clarity.

        The fact that it and context take as their first argument the description of the block itself results in a clearer test. The reader reads what is expected first, and then sees the assertion code.

        -
        // XCTest
        +
        // XCTest
         XCTAssertNil([self.formatter formattedElementString:data], @"ElementFormatter did not return nil when given element data missing the symbol");
         
         // Specta
         NSDictionary *data = @{ @"symbol": @"E", @"atomic_number": @"42" };
        -expect([formatter formattedElementString:data]).to.beNil();
        -
        +expect([formatter formattedElementString:data]).to.beNil();

        Thanks to Expecta even the syntax used for the assertion is more human readable, expect().to.equal() instead of XCTAssertEqual().

        I think that these details all sum up together to produce tests that are easy to read, understand and write. These test could serve as a first form of documentation, that doesn't take extra time to be written, because it's developed together with the code.

        All this is not to say that XCTest is not a good framework. Actually without XCTest Specta couldn't even run! The point is that because code should be written thinking about who will read it using an xSpec approach, that shifts the focus on describing the behaviour rather than just testing a list of expectations, can make working with the tests easier and more productive.

        diff --git a/blog/bitbucket-pr-from-command-line/index.html b/blog/bitbucket-pr-from-command-line/index.html index 4a95ce9..b90c1bc 100644 --- a/blog/bitbucket-pr-from-command-line/index.html +++ b/blog/bitbucket-pr-from-command-line/index.html @@ -4,14 +4,13 @@

        One thing I love about GitHub is how easy it is to create a pull request. You can go on the project's repo and see the button to do it if you recently pushed on a branch that is not the main one, or use the hub gem and do it from the terminal.

        Once you get used to this convenience switching to BitBucket can be quite annoying.

        I wrote a simple little script to open a PR to a BitBucket repo from the terminal:

        -
        #!/bin/bash
        +
        #!/bin/bash
         
         org=YOUR_ORG
         project=PROJECT_NAME
         branch=$(git rev-parse --abbrev-ref HEAD)
         
        -open "https://bitbucket.org/${org}/${project}/pull-request/new?source=${branch}&t=1"
        -
        +open "https://bitbucket.org/${org}/${project}/pull-request/new?source=${branch}&t=1"

        Running this script, which I usually call pr.sh, will open your browser on a configured page to create a pull request on BitBucket.

        Unfortunately you have to specify the organization and the project name in the script. This is quite annoying, but is a one off operation.

        If you use this script, or have a better solution to suggest, please hit me up on Twitter @mokagio, I'd love to hear your opinion.

        diff --git a/blog/books-to-start-2018/index.html b/blog/books-to-start-2018/index.html index 879accd..08443d9 100644 --- a/blog/books-to-start-2018/index.html +++ b/blog/books-to-start-2018/index.html @@ -2,19 +2,19 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

        Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

      mokacoding

      unit and acceptance testing, automation, productivity

      4 books to kick start 2018

      Over the past year I read a lot of books for my standards. That was in part due to getting into Audible and making the most of commute and housework times. I'd like to recommend the following 4 to kick start your 2018 in the best possible way.

      Note. The links below point to Amazon.com, but are not referrals. These are 100% genuine recommendations. I'm not trying to get a few dollar out of you buying any of them. These books have inspired me and helped me grow. I truly hope will do the same for you.

      -

      1. Deep Work

      +

      1. Deep Work

      In our economy, in particular for software developers and other knowledge workers, the ability to focus without distraction on a cognitively demanding task is the key to succeed.

      Unfortunately we live in a world of continuous distractions. Push notifications, social media, infotainment websites, Slack, and a work culture of "being busy" make it harder and harder to stay focused. Worse, this lifestyle is literally rewiring our brains to keep seeking distractions, making it harder and harder to focus.

      In this book Cal Newport argues why the ability to focus and to work deeply is important, and defines a framework to reach and maintain the level of focus required for it.

      For me it was an eye opener on many toxic habits I had, like checking Twitter while waiting for Xcode to build. It set me on a path not only to be more effective at work, but also more present with my family.

      -

      2. The Obstacle Is The Way

      +

      2. The Obstacle Is The Way

      This is a book about philosophy. Don't close this email yet! It's not a pointless rant on the essence of humanity, but rather a down to earth and practical guide to building a mindset that will allow you to thrive in front of adversities.

      Ryan Holiday looks at the teachings of the Roman Stoics through the lives and achievements of more recent important figures like John D. Rockefeller, Steve Jobs, Ulysses S. Grant.

      This book changed my mindset towards a number of things in my personal and professional life. It gave me the tools to make the most out of any situation and challenge.

      -

      3. Extreme Ownership

      +

      3. Extreme Ownership

      "How U.S. Navy SEALs Lead and Win". In this book two ex Navy SEALs leaders, now working as business leadership consultants, share the 12 most important lessons they learnt through their deployment in Iraq.

      The great things about it is that you don't have to be a team lead or a manager to apply these lessons. Everyone can, from C level executives to junior team members.

      -

      4. The Inevitable

      +

      4. The Inevitable

      Kevin Kelly has been around the block. In this book he share the 12 deep trends that will shape our economy and society in the near future.

      Only time will tell how accurate these predictions are. Regardless, they provide a lot of food for though, and are definitely worth reading. Start the year by opening your horizons and keeping some things on the radar.

      I hope reading these 4 books will help you build a positive mindset and effective lifestyle to achieve your goals in 2018. If after reading them you'd like to chat about them, or if you have read books that have been insightful and valuable and would like to share them write me a line at gio@mokacoding.com. I'd love to hear from you.

      diff --git a/blog/calabash-ios-with-cocoapods-and-build-configurations/index.html b/blog/calabash-ios-with-cocoapods-and-build-configurations/index.html index ee8d32e..08c9383 100644 --- a/blog/calabash-ios-with-cocoapods-and-build-configurations/index.html +++ b/blog/calabash-ios-with-cocoapods-and-build-configurations/index.html @@ -7,37 +7,36 @@
    • Having a second target means that when adding a new file the developers need to add it to both targets, every time. This is quite error prone...
    • There is no automated way to track new versions of the binary.
    • -

      Build Configuration + CocoaPods based setup

      +

      Build Configuration + CocoaPods based setup

      The solution I propose removes both the upgrade automation problem, and the annoyance of having to add files to multiple targets.

      By using CocoaPods we can automate the version updates, and by using a custom Build Configuration we can use the main Target, and new files will always be there.

      The setup process is quite straightforward, and you can follow it on this example repo while reading along.

      1. Get Calabash

      Calabash is distributed via RubyGems, so getting it is as easy as running:

      -
      gem install calabash-cucumber
      -

      To verify that the installation has been successful type calabash-ios, you should see a print of all the possible commands.

      +
      gem install calabash-cucumber

      To verify that the installation has been successful type calabash-ios, you should see a print of all the possible commands.

      2. Create a new Build Configuration

      Adding a new Build Configuration to an Xcode project is done by going to the Project > Info tab, mind Project not Target, going to the Configurations section and pressing the plus button. Adding a new Configuration is actually nothing more than duplicating an existing one.

      -

      Setup Calabash for iOS with CocoaPods and Build Configurations - Add new Build Configuration

      +Setup Calabash for iOS with CocoaPods and Build Configurations - Add new Build Configuration +

      3. Add Calabash through CocoaPods

      Calabash works by connecting to the app in the Simulator or device via HTTP. To make this happen we need to add a binary to our app, which will start the server that we'll connect to.

      The Calabash CocoaPods takes care of all the setup operations for us, but we don't want the Calabash binary to be in the ipa we'll submit to the store.

      Since version 0.34 CocoaPods allows us to install pods with a configuration granularity, which is awesome. This is why we added a dedicated configuration, to leverage on this feature and avoid Calabash leaking into production.

      -
      target 'MyAwesomeApp' do
      +
      target 'MyAwesomeApp' do
         pod 'Calabash', :configurations => ['Calabash']
      -end
      -
      +end

      Now simply pod install and Calabash will be integrated in your project.

      4. Create a Calabash scheme

      The final piece of the puzzle is to have a way to run our app in the Calabash configuration, so that the local server will be started and the calabash cli will be able to contact the app to run the automation tests.

      To do this just create a new Scheme, and set the Run > Build Configuration option to Calabash.

      -

      Setup Calabash for iOS with CocoaPods and Build Configurations - Edit Scheme

      +Setup Calabash for iOS with CocoaPods and Build Configurations - Edit Scheme +

      Now select the new Scheme and Run. If everything has been successful you'll see an output similar to this:

      -
      2015-01-25 21:20:35.693 CalabashSetup[33579:257892] Creating the server: <LPHTTPServer: 0x7fa4fbc07940>
      +
      2015-01-25 21:20:35.693 CalabashSetup[33579:257892] Creating the server: <LPHTTPServer: 0x7fa4fbc07940>
       2015-01-25 21:20:35.693 CalabashSetup[33579:257892] Calabash iOS server version: CALABASH VERSION: 0.12.0
       2015-01-25 21:20:35.694 CalabashSetup[33579:257892] simroot: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
       2015-01-25 21:20:35.697 CalabashSetup[33579:257892] Started LPHTTP server on port 37265
      -2015-01-25 21:20:35.876 CalabashSetup[33579:257972] Bonjour Service Published: domain(local.) type(_http._tcp.) name(Calabash Server)
      -

      Congratulations! You're Calabash setup with CocoaPods and Build Configurations is completed!

      +2015-01-25 21:20:35.876 CalabashSetup[33579:257972] Bonjour Service Published: domain(local.) type(_http._tcp.) name(Calabash Server)

      Congratulations! You're Calabash setup with CocoaPods and Build Configurations is completed!

      If you had any problems during the setup tweet me for help @mokagio, or check the example repo.

      Happy acceptance testing with Calabash

      diff --git a/blog/carthage-no-build/index.html b/blog/carthage-no-build/index.html index 010d75a..33655ba 100644 --- a/blog/carthage-no-build/index.html +++ b/blog/carthage-no-build/index.html @@ -10,9 +10,10 @@
    • CI boxes will have to install the dependencies at every run which takes more time, or have caching systems which increases complexity.

    I tweeted in this regard, and Tony Arnold replied to me suggesting a different approach than usual:

    -

    -

    -

    --no-build

    + + + +

    --no-build

    The description of the --no-build option for the update command says, very straightforwardly: skip the building of dependencies after updating. This means that after running carthage update --no-build we won't have any Carthage/Build folder.

    How to integrate the dependencies then?

    The answer is in Tony's tweet: just integrate the projects directly 😎. To recap:

    diff --git a/blog/circle-ci-ios-testing/index.html b/blog/circle-ci-ios-testing/index.html index 69e97b9..a4008b4 100644 --- a/blog/circle-ci-ios-testing/index.html +++ b/blog/circle-ci-ios-testing/index.html @@ -3,24 +3,23 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to configure CircleCI for iOS testing

    Whether you are using Swift or Objective-C, developing a little open source framework or the next App Store hit, having a solid CI setup is very important to guarantee a fast feedback loop, and a reliable development pipeline.

    In this article we are going to see how to use CircleCI to test iOS, and OS X applications. Oh! And watchOS and tvOS as well.

    Note: Before configuring CircleCI you'll need to make sure that the Xcode Scheme used to run the test is shared, so that it will be downloaded as part of the repo checkout and Circle will find it when attempting to run the tests.

    -

    circle.yml

    +

    circle.yml

    CircleCI offers multiple options to configure the CI job. The best one in my opinion is to use a circle.yml file in the root of your project.

    In case you are not familiar with it, a .yml file is a file written in YAML, a very simple data serialization language, and a JSON subset.

    Here's the one of simplest circle.yml you could write:

    -
    machine:
    +
    machine:
       xcode:
         version: "7.0"
     
     test:
       override:
    -    - ./bin/tests
    -
    + - ./bin/tests

    That's it. This configuration file will make sure that your build will run on a machine with Xcode 7.0, the run the executable script located at bin/tests.

    Using a script file where the test commands are rather than letting CircleCI guess how to run them itself has a number of advantages. First and foremost, it makes it so that you can run the same command the CI will use on your machine, which is important because you want to personally test your CI setup. On top of that it keeps the configuration file decoupled by the implementation details how the tests should run, and makes it more readable.

    Checkout this post for a closer look on how to write such a script.

    Other configurations

    The circle.yml of Bench, one of the example projects used to in posts like "Xcode 7 UI testing, a first look" and "Job stories acceptance tests using KIF and Specta", adds is similar to the one above, but with an extra section:

    -
    machine:
    +
    machine:
       xcode:
         version: "7.0"
     
    @@ -30,12 +29,11 @@ 

    Other configurations

    test: override: - - ./bin/unit-tests -
    + - ./bin/unit-tests

    Bench uses xcpretty to format the tests' output. The tool is installed as a Ruby gem, using Bundler.

    What the circle.yml does is overriding the dependencies step, to run bundle install.

    In this circle.yml from the Quick project we do two extra things, update the git submodules, and make sure the xctool version brew is up to date.

    -
    machine:
    +
    machine:
       xcode:
         version: "7.0"
     
    @@ -52,8 +50,7 @@ 

    Other configurations

    override: - rake test:ios - rake test:osx - - rake test:xctool_ios -
    + - rake test:xctool_ios

    A note on dependencies

    You might have noticed that I have made no mention yet to pod install or carthage bootstrap. That is because I've found that is way better to check in your projects dependencies under version control rather than having the CI downloading every time. Not only you will get a faster build, but also remove the network as a possible point of failure. For example GitHub being offline would not prevent the dependencies to being downloaded, resulting in the build failing.


    diff --git a/blog/cloud-66-postfix-deploy-hook/index.html b/blog/cloud-66-postfix-deploy-hook/index.html index 44ae439..399210c 100644 --- a/blog/cloud-66-postfix-deploy-hook/index.html +++ b/blog/cloud-66-postfix-deploy-hook/index.html @@ -5,8 +5,8 @@ is excellent and easy to follow, but glosses over how to write a deploy hook to automate the process.

    This is my take on a deploy hook to install SMPT through Postfix.

    -

    deploy_hooks.yml

    -
    ---
    +

    deploy_hooks.yml

    +
    ---
     production:
       first_thing:
         - source: /.cloud66/postfix_setup.sh
    @@ -14,10 +14,9 @@ 

    deploy_hooks.yml

    target: any apply_during: build_only execute: true - sudo: true -
    -

    postfix_setup.sh

    -
    #!/bin/bash
    +      sudo: true
    +

    postfix_setup.sh

    +
    #!/bin/bash
     
     set -e
     
    @@ -28,8 +27,7 @@ 

    postfix_setup.sh

    sudo echo "myhostname = yourdomain.com" >> /etc/postfix/main.cf # Apply configurations -sudo /etc/init.d/postfix reload -
    +sudo /etc/init.d/postfix reload

    This is the first deploy hook that I've ever written for Cloud 66, so if you think there's a better way to achieve the result please get in touch through Twitter @mokagio, or leave a comment below.

    diff --git a/blog/clutter-and-optimization/index.html b/blog/clutter-and-optimization/index.html index bfb2cf2..729161e 100644 --- a/blog/clutter-and-optimization/index.html +++ b/blog/clutter-and-optimization/index.html @@ -15,7 +15,7 @@

    Optimization is important

    IDEs and text editors are not the only tools of a software developer. Become intimate with the standard library of the programming languages you use, as well as the documentation of the frameworks on top of them. Never assume that the way you are doing something is the best one. You don't know what you don't know, so take the time to dig deeper. A great way to ramp up your knowledge of any given language or framework is to read the documentation for every class or method you haven't used yet. This practice is admittedly time-consuming at first, but as time goes, you'll become familiar with it and need to do this less often. You'll learn a lot along the way. With open source libraries, you can also look at how they implemented things to learn tricks and best practices.

    Aim to master version control as well. Learning to use Git will make it much easier for you to write software in incremental stages, without ever fearing to miss your work in progress. Because we collaborate on the code being able to make collaboration easier by having small commits and pull requests will optimize the speed at which you can get feedback on your work and eventually merge it.

    Tune your compilation and test phases, so they are as fast as possible. You want to the feedback tests and compiler provide to be timely. Staring at a progress bar is a challenge to anyone's self-control to stay focused on the task at hand instead of going off to social media. So don't make it harder on yourself to do your best work, don't let your builds and tests become slow.

    -

    *

    +

    ***

    Take a leaf from the digital minimalist playbook. Reduce clutter to avoid paying its mental overhead price. Optimize how you use your tools and workflows to get feedback fast, and get things done even faster. Less is more, aim to be better, not bigger.

    diff --git a/blog/cocoapods-and-custom-build-configurations/index.html b/blog/cocoapods-and-custom-build-configurations/index.html index 2d7fe4a..1159b44 100644 --- a/blog/cocoapods-and-custom-build-configurations/index.html +++ b/blog/cocoapods-and-custom-build-configurations/index.html @@ -5,11 +5,10 @@

    Thanks to that issue I now have a better understanding of what CocoaPods does, and some tips to share on how to handle build configurations like a pro.

    The custom build configuration issue

    The problem: when trying to use Tweaks with a build configuration in a project the linking phase was failing. Apparently some symbols used by the pod didn't exist.

    -
    Undefined symbols for architecture i386:
    +
    Undefined symbols for architecture i386:
       "__FBTweakIdentifier", referenced from: ...
     ld: symbol(s) not found for architecture i386
    -clang: error: linker command failed with exit code 1 (use -v to see invocation)
    -

    Tweaks is built in a way that allows developers to turn it off for production builds, collapsing the tweakable values into their defaults. The way they made this possible is through preprocessor macros; if FB_TWEAK_ENABLED is 0 than the macro functions used for the tweakable values are redefined into their default values. One of the places were this happens is FBTweakInlineInternal.h.

    +clang: error: linker command failed with exit code 1 (use -v to see invocation)

    Tweaks is built in a way that allows developers to turn it off for production builds, collapsing the tweakable values into their defaults. The way they made this possible is through preprocessor macros; if FB_TWEAK_ENABLED is 0 than the macro functions used for the tweakable values are redefined into their default values. One of the places were this happens is FBTweakInlineInternal.h.

    FB_TWEAK_ENABLED itself is defined in FBTweakEnabled.h and its behaviour maps the DEBUG macro, if not set otherwise.

    With this understanding of how Tweaks works the error message now suggests us that there's some problem with FB_TWEAK_ENABLED and DEBUG. The linker must be getting values different by the ones I set. But how?

    How CocoaPods does its magic

    @@ -23,8 +22,7 @@

    How CocoaPods does its magic

    How to use CocoaPods and build configurations like a pro

    The rule of thumb is that the Pods and our target have to have the same preprocessor macro settings.

    Whenever you create a custom build configuration Xcode asks if you want to duplicate Debug or Release. The Podfile DSL has a way to tell CocoaPods which build configuration was duplicated from which, it's the second argument of the xcodeproj setting.

    -
    xcodeproj `MyProject`, 'QA' => :release, 'Beta' => :debug
    -
    +
    xcodeproj `MyProject`, 'QA' => :release, 'Beta' => :debug

    If some of your pods requires you to set preprocessor macros then remember what @alloy says:

    The important thing to remember here is that you cannot conditionally compile stuff by setting CPP flags from your app target only.

    @@ -32,11 +30,12 @@

    How to use Coc

    We need to make the Pods aware of what we set in our target. There are two ways to do this.

    With a Version-Controlled Pods Folder

    If your Pods folder is under version control just set them in the Pods target that uses them in the same way you did for your target.

    -

    + +

    Git (your using git right?!) will remember the settings forever.

    Without a Pods Folder

    If the Pods are not versioned every time pod install or pod update run the Pods project is regenerated. The way to automate setting the preprocessor macro is through a post_install hook.

    -
    post_install do |installer_representation|
    +
    post_install do |installer_representation|
       installer_representation.project.targets.each do |target|
         if target.name == "Pods-TweaksBuildConfigurationsDemo-Tweaks"
           target.build_configurations.each do |config|
    @@ -46,8 +45,7 @@ 

    Without a Pods Folder

    end end end -end -
    +end

    This one sets FB_TWEAK_ENABLED=1 in the 'QA' build configuration for the Tweak's target of the Pods project.


    There are few things as rewarding as solving a problem by understanding all the pieces of the puzzle, looking back at it and suddenly seeing everything clearly. It is something that is possible only when using open source tools.

    diff --git a/blog/cocoapods-ci-setup/index.html b/blog/cocoapods-ci-setup/index.html index df0a067..3b50aec 100644 --- a/blog/cocoapods-ci-setup/index.html +++ b/blog/cocoapods-ci-setup/index.html @@ -2,15 +2,14 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    How to use CocoaPods as a CLI tools manager

    TL;DR You can configure CocoaPods to not integrate with your Xcode project and use it to only resolve and fetch your dependencies. This is handy to control the version of the CLI tools you use in an iOS project that already has a Ruby setup but that uses Carthage or SPM for dependency management.

    -

    Gemfile

    -
    # frozen_string_literal: true
    +

    Gemfile

    +
    # frozen_string_literal: true
     
     source 'https://rubygems.org'
     
    -gem 'cocoapods', '~> 1.9.0'
    -
    -

    Podfile

    -
    # This Podfile is configured to not integrate with an xcproject, because the
    +gem 'cocoapods', '~> 1.9.0'
    +

    Podfile

    +
    # This Podfile is configured to not integrate with an xcproject, because the
     # only thing we are interested in is fetching CLI tools
     install! 'cocoapods',
       integrate_targets: false,
    @@ -19,35 +18,30 @@ 

    Podfile

    platform :ios, '13.0' pod 'SwiftFormat/CLI', '~> 0.40' -pod 'SwiftLint', '~> 0.38' -
    +pod 'SwiftLint', '~> 0.38'

    Then, you can use the tools via the binaries pulled by CocoaPods, like:

    -
    ./Pods/SwiftLint/swiftlint
    -

    You can see the full setup in action in this example repo.

    +
    ./Pods/SwiftLint/swiftlint

    You can see the full setup in action in this example repo.


    Whether you like CocoaPods or not, there's little arguing about how refined of a dependency manager it is.

    I know a lot of people don't like to use CocoaPods because it adds a lot of stuff to a project and it's a rather opinionated tool.

    Recently, I discovered you can use CocoaPods to manage the version of the CLI tools you use in your projects, as long as they are distributed via CocoaPods.

    -

    Why bother?

    +

    Why bother?

    Strictly controlling the tools the project uses ensures every developer and machine working with the repo will use the same versions and get the same behaviour. This provides a more consistent experience, reducing the occurrence of "but it works on my machine" kind of issues.

    How do do it

    In order to use CocoaPods to only resolve and fetch dependencies, you need to configure it to avoid the creation of dedicated targets, workspace, and integration in your project.

    -
    install! 'cocoapods',
    +
    install! 'cocoapods',
       integrate_targets: false,
    -  skip_pods_project_generation: true
    -
    + skip_pods_project_generation: true

    Once your Podfile is setup, you'll need to run pod install as usual. You'll get a warning message like:

    -
    [!] The abstract target Pods is not inherited by a concrete target, so the following dependencies won't make it into any targets in your project:
    +
    [!] The abstract target Pods is not inherited by a concrete target, so the following dependencies won't make it into any targets in your project:
     Skipping User Project Integration
         - SwiftFormat/CLI (~> 0.40)
    -    - SwiftLint (~> 0.38)
    -

    That shouldn't be surprising, we intentionally told CocoaPods we don't want those pods to make it into any of our project's targets.

    + - SwiftLint (~> 0.38)

    That shouldn't be surprising, we intentionally told CocoaPods we don't want those pods to make it into any of our project's targets.

    Now you have those CLI tools at your disposal in the repo, each located in the Pods folder. For example, to run the downloaded version of SwiftLint, you should use:

    -
    ./Pods/SwiftLint/swiftlint
    -

    You can see this setup in action in this example repo which uses a GitHub workflow to run SwiftLint and SwiftFormat fetched via CocoaPods.

    +
    ./Pods/SwiftLint/swiftlint

    You can see this setup in action in this example repo which uses a GitHub workflow to run SwiftLint and SwiftFormat fetched via CocoaPods.

    A note on version control

    The CLI tools you can download via CocoaPods come in the form of binary files. Git is designed to manage changes in text files, not binaries. diff --git a/blog/cocoapods-how-to-create-your-own-pod/index.html b/blog/cocoapods-how-to-create-your-own-pod/index.html index 129b4b7..184b470 100644 --- a/blog/cocoapods-how-to-create-your-own-pod/index.html +++ b/blog/cocoapods-how-to-create-your-own-pod/index.html @@ -2,48 +2,48 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    CocoaPods - How to create your own Pod

    Like I said in the first part of my exploration of CocoaPods, using this iOS dependencies management is freaking easy, and reading what's on the homepage is more than enough to get started. Anyway let's see how we can create our how Pods.

    To learn how to do it I started the development of a little "framework" I called MGCraftman, where I'll put some utils methods I sometimes write to speed up UI development when I'm not using Interface Builder. But let's stop the chitchat and let's code!

    -

    Step 1 - Code the Library!

    -The first step is to have something to make a pod of, I guess every developer has his own little set of smart methods that make his life easier. Don't be greedy, share them with the community!

    -

    Step 2 - Tag your pod properly

    -Since we're gonna work with a dependency manager we need to take care of the version number of our pod.

    -
    git tag -a 1.0.0 -m "Tag release 1.0.0"
    -

    Take a couple of minutes to read through the Semantic Versioning to learn how to use tagging for version numbers properly and in a way that allows for resolution of cross-dependencies.

    -

    Step 3 - The podspec

    -Once our project is tagged properly we can create the .podspec file. The extension name explains that it will contain the "specs" of our "pod".

    -
    pod spec create Donut
    -

    This will generate the Donut.podspec file.

    +

    Step 1 - Code the Library!

    +The first step is to have something to make a pod of, I guess every developer has his own little set of smart methods that make his life easier. Don't be greedy, share them with the community! +

    Step 2 - Tag your pod properly

    +Since we're gonna work with a dependency manager we need to take care of the version number of our pod. + +
    git tag -a 1.0.0 -m "Tag release 1.0.0"

    Take a couple of minutes to read through the Semantic Versioning to learn how to use tagging for version numbers properly and in a way that allows for resolution of cross-dependencies.

    +

    Step 3 - The podspec

    +Once our project is tagged properly we can create the .podspec file. The extension name explains that it will contain the "specs" of our "pod". + +
    pod spec create Donut

    This will generate the Donut.podspec file.

    You can also generate the podspec from a GitHub repo using the GitHub url instead of the name.

    -

    Step 4 - Leave your mark on the podspec

    -If you open the freshly generated Donut.podspec you'll find a lot of comments explaining the information you need to provide. There are a lot of options, but you don't need to set them all. You'll also notice that its nothing more that a Ruby file.

    +

    Step 4 - Leave your mark on the podspec

    +If you open the freshly generated Donut.podspec you'll find a lot of comments explaining the information you need to provide. There are a lot of options, but you don't need to set them all. You'll also notice that its nothing more that a Ruby file. +

    Here's how the podspec of my toy framework, looks like.

    -
    {% highlight objective-c %}
    -Pod::Spec.new do |s|
    -  s.name         = "MGCraftman"
    -  s.version      = "0.1.0"
    -  s.summary      = "A framework to speedup development when you can't (or don't want to) use Interface Builder."
    -  s.homepage     = "https://github.com/mokagio/MGCraftman"
    +
    {% highlight objective-c %}
    +Pod::Spec.new do |s|
    +  s.name         = "MGCraftman"
    +  s.version      = "0.1.0"
    +  s.summary      = "A framework to speedup development when you can't (or don't want to) use Interface Builder."
    +  s.homepage     = "https://github.com/mokagio/MGCraftman"
    +
    +  s.license      = { :type =&gt; 'MIT', :file =&gt; 'LICENSE' }
    +
    +  s.author       = { "Giovanni Lodi" =&gt; "mokagio42@gmail.com" }
     
    -  s.license      = { :type =&gt; 'MIT', :file =&gt; 'LICENSE' }
    +  s.source       = { :git =&gt; "https://github.com/mokagio/MGCraftman.git", :tag =&gt; "0.1.0" }
    +  s.source_files = 'MGCraftman/*.{h,m}'
     
    -  s.author       = { "Giovanni Lodi" =&gt; "mokagio42@gmail.com" }
    +  s.platform     = :ios
    +end
    +{% endhighlight %}

    Step 5 - Is my podspec ok?

    +Once your podspec its ready validate it running - s.source = { :git =&gt; "https://github.com/mokagio/MGCraftman.git", :tag =&gt; "0.1.0" } - s.source_files = 'MGCraftman/*.{h,m}' +
    pod spec lint Peanut.podspec

    If everything is fine you'll read

    +
    pod spec lint Peanut.podspec 
    +-> Peanut (1.0.0)
    +Analyzed 1 podspec.
    +Peanut.podspec passed validation.

    Otherwise pod spec will explain the error or warning, as everything is so simple also fixing the problems will be. Anyway the error report is already formatted in Markdown so you can copy it and paste it in an issue on the CocoaPods Issues page.

    +

    Step 6 - Let your pod fly

    +We're almost done here. Now to make our pod available to the community, or just to ourselves and feel cool, we have two options. The rookie way is open an issue, but we've just coded an iOS library, with it's own repo on GitHub, and generated the podspec fetching the data from there, so we're not rookies. The second option is to fork the Specs repo, add our pod, submit the PR and wait. - s.platform = :ios -end -{% endhighlight %} -

    Step 5 - Is my podspec ok?

    -Once your podspec its ready validate it running

    -
    pod spec lint Peanut.podspec
    -

    If everything is fine you'll read

    -
    pod spec lint Peanut.podspec 
    --> Peanut (1.0.0)
    -Analyzed 1 podspec.
    -Peanut.podspec passed validation.
    -

    Otherwise pod spec will explain the error or warning, as everything is so simple also fixing the problems will be. Anyway the error report is already formatted in Markdown so you can copy it and paste it in an issue on the CocoaPods Issues page.

    -

    Step 6 - Let your pod fly

    -We're almost done here. Now to make our pod available to the community, or just to ourselves and feel cool, we have two options. The rookie way is open an issue, but we've just coded an iOS library, with it's own repo on GitHub, and generated the podspec fetching the data from there, so we're not rookies. The second option is to fork the Specs repo, add our pod, submit the PR and wait.

    I submitted my PR at 8:44 GTM+0 on a Sunday, let's see how long it takes to merge it. The PR approved and merged in less that 2 hours. That's what I call efficiency. Also you can ask for push rights, in order to maintain your pod without submitting a pull request every time.

    And here we are. My MGCraftman framework is ready to be imported via CocoaPods, and all the world will be happy to use it, or not.

    diff --git a/blog/cocoapods-the-inherited-flag/index.html b/blog/cocoapods-the-inherited-flag/index.html index c6f84d0..36411c3 100644 --- a/blog/cocoapods-the-inherited-flag/index.html +++ b/blog/cocoapods-the-inherited-flag/index.html @@ -2,10 +2,9 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    CocoaPods: the $(inherited) flag

    I've done it a lot of times by now, but I keep forgetting it. So here's a quick post to commit it to memory!

    If we have a project with the Tests target it can happen that after running pod install we get this message:

    -
    [!] The target `MyProjectTests [Debug]` overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Pods-MyProjectTests.xcconfig'.
    +
    [!] The target `MyProjectTests [Debug]` overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Pods-MyProjectTests.xcconfig'.
     - Use the `$(inherited)` flag, or
    -- Remove the build settings from the target.
    -

    How can we "use the $(inherited) flag"? Where should we add it?

    +- Remove the build settings from the target.

    How can we "use the $(inherited) flag"? Where should we add it?

    The $(inherited) flag is an flag we can pass to the linker and that does some magic.... I haven't been able to find a proper explanation for how $(inherited) works, although it's easy to guess from the name.

    Being a linker flag we can add it in our target Build Settings > Other Linker Flags section.

    Screen Shot 2013-07-10 at 00.16.36

    diff --git a/blog/cocoapods/index.html b/blog/cocoapods/index.html index 2aa7464..0f78cdc 100644 --- a/blog/cocoapods/index.html +++ b/blog/cocoapods/index.html @@ -1,6 +1,6 @@ CocoaPods! | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    CocoaPods!

    What is CocoaPods?

    +

    mokacoding

    unit and acceptance testing, automation, productivity

    CocoaPods!

    What is CocoaPods?

    CocoaPods: The best way to manage library dependencies in Objective-C projects.

    @@ -11,72 +11,67 @@
  • Smart and safe version management, specially when we're working on a project with other people, which is 90% of the time.
  • To "get my hands dirty" with CocoaPods I made this little project called JustNineGags, feel free to check it out on GitHub.

    -

    Why should I use it?

    -

    Because it's awesome! It makes development faster and easier, and also safer! It easier to work in teams and keep the libraries versions even. Should I go on? Ok! Just think about this: you won't download and move in your project a library anymore, pod will do it all for you!

    +

    Why should I use it?

    +

    Because it's awesome! It makes development faster and easier, and also safer! It easier to work in teams and keep the libraries versions even. Should I go on? Ok! Just think about this: you won't download and move in your project a library anymore, pod will do it all for you!

    Installing CocoaPods

    -

    Installing CocoaPods is as simple as installing all the other Ruby Gems, I shouldn't even writing this, as what's written in the install section is more than enough, anyway:

    +

    Installing CocoaPods is as simple as installing all the other Ruby Gems, I shouldn't even writing this, as what's written in the install section is more than enough, anyway:

    -
    gem install cocoapods
    -

    Once the installation is completed run:

    +
    gem install cocoapods

    Once the installation is completed run:

    -
    pod setup
    -

    This will, guess what, setup everything CocoaPods needs on your system. You should see an output like this:

    +
    pod setup

    This will, guess what, setup everything CocoaPods needs on your system. You should see an output like this:

    -
    Setting up CocoaPods master repo
    +
    Setting up CocoaPods master repo
     Cloning spec repo 'master' from '<a href='https://github.com/CocoaPods/Specs.git'>https://github.com/CocoaPods/Specs.git</a>' (branch 'master')
    -Setup completed (read-only access)
    -

    Done! :)

    +Setup completed (read-only access)

    Done! :)

    -

    You should avoid using sudo otherwise everything else you'll do with pod will need to use sudo as well. And this mean that the folders and file that are gonna be created will be owend by root instead that by you.

    +

    You should avoid using sudo otherwise everything else you'll do with pod will need to use sudo as well. And this mean that the folders and file that are gonna be created will be owend by root instead that by you.

    Using CocoaPods

    Again, everything written on the website is pretty straightforward.

    -

    Go in the root folder of your Objective-C project and create a file named Podfile, with whatever editor you like. We'll use this file to list all the libraries, pods, we need in the project. The JustNineGags Podfile content is:

    +

    Go in the root folder of your Objective-C project and create a file named Podfile, with whatever editor you like. We'll use this file to list all the libraries, pods, we need in the project. The JustNineGags Podfile content is:

    -
    platform :ios
    +
    platform :ios
     pod 'MBProgressHUD', '~> 0.5'
    -pod 'Reachability',  '~> 3.1.0'
    -
    +pod 'Reachability', '~> 3.1.0'

    Adding a Pod

    -

    As you can see adding a Pod is really easy, just go on CocoaPods website, look for the it, and then add it to the Podfile using it's name and the version you need.

    +

    As you can see adding a Pod is really easy, just go on CocoaPods website, look for the it, and then add it to the Podfile using it's name and the version you need.

    Installing the Pods

    -

    Right now we've told CocoaPods the Pods we need but they aren't yet in out project. So let's run

    +

    Right now we've told CocoaPods the Pods we need but they aren't yet in out project. So let's run

    -
    pod install
    -

    This will download all the libraries we've asked for, and all their dependencies. Sweet!

    +
    pod install

    This will download all the libraries we've asked for, and all their dependencies. Sweet!

    The first time we run pod install something else will happen, a Pods/ folder, a Podfile.lock, and a YourProjectName.xcworkspace will be created.

    -

    Important! From now on remember to open your project through the YourProjectName.xcworkspace file, otherwise the pods won't be loaded by Xcode.

    +

    Important! From now on remember to open your project through the YourProjectName.xcworkspace file, otherwise the pods won't be loaded by Xcode.

    -

    That's all folks! :)

    +

    That's all folks! :)

    What should we track?

    -

    Using CocoaPods adds some files and folders to our project, which of those should we track in our repo, and which should be left aside, adding them to the .gitignore? That of course assuming you're using git, and you definitely should. Let's have a look at the new stuff:

    +

    Using CocoaPods adds some files and folders to our project, which of those should we track in our repo, and which should be left aside, adding them to the .gitignore? That of course assuming you're using git, and you definitely should. Let's have a look at the new stuff:

    • Podfile, we definitely need this one, as all the pods we need are listed in it.
    • -
    • Podfile.lock, as for all the other library management systems, we need this one too, because it's used to assure all the developers are using the same versions of the pods and their dependencies.
    • -
    • Pods/, we don't need to track this folder, it's created by pod install, and all it's content is downloaded for us from other repos.
    • -
    • YourProjectName.xcworkspace, we don't need this one either, because it's generated by pod install too.
    • +
    • Podfile.lock, as for all the other library management systems, we need this one too, because it's used to assure all the developers are using the same versions of the pods and their dependencies.
    • +
    • Pods/, we don't need to track this folder, it's created by pod install, and all it's content is downloaded for us from other repos.
    • +
    • YourProjectName.xcworkspace, we don't need this one either, because it's generated by pod install too.
    -

    What's coming next?

    +

    What's coming next?

    -

    How to setup our own pods. I'll probably write a little and simple Category to add other colors to the UIColor factories, stay tuned!

    +

    How to setup our own pods. I'll probably write a little and simple Category to add other colors to the UIColor factories, stay tuned!


    Update 2013-01-06

    -

    To implement HTTP requests in JustNineGags I used SMWebRequest because I'm too lazy to write everything by myself. SMWebRequest wasn't a Pod yet so I opened an issue asking good guy nfarina to add it. In less than 12 hours the Pod was added! :D

    +

    To implement HTTP requests in JustNineGags I used SMWebRequest because I'm too lazy to write everything by myself. SMWebRequest wasn't a Pod yet so I opened an issue asking good guy nfarina to add it. In less than 12 hours the Pod was added! :D

    Want more of these posts?

    diff --git a/blog/code-coverage-is-broken/index.html b/blog/code-coverage-is-broken/index.html index 1624810..f94f4e2 100644 --- a/blog/code-coverage-is-broken/index.html +++ b/blog/code-coverage-is-broken/index.html @@ -6,20 +6,19 @@

    The correlation between IQ and performance at school or on the job is visible, but not that strong. "Sometimes IQ scores are described as the 'best available predictor' of that performance. It is worth noting, however, that such tests predict considerably less than half the variance of job-related measures [emphasis mine]" researchers say1.

    A question I often get asked is "what code coverage value should we use?". Code coverage is like IQ, it's an incomplete metric for how good a codebase and its test suite actually are.

    Here's an example of code coverage false positives:

    -
    // Source.swift
    -func element(atIndex index: Int, of array: [Int]) -> Int {
    +
    // Source.swift
    +func element(atIndex index: Int, of array: [Int]) -> Int {
         return array[index]
     }
     
     // Tests.swift
    -func testArrayAccess() {
    +func testArrayAccess() {
         XCTAssertEqual(element(atIndex: 0, of: [1, 2, 3]), 1)
    -}
    -
    +}

    The code has 100% code coverage, yet calling element(atIndex: 3, of: [1, 2, 3]) will result in a crash. When writing tests is not enough to cover the happy path, you also need to verify how the code behaves in the failure and edge cases.

    screenshot of Xcode showing 100% code coverage on a bugged function

    Another example:

    -
    // Source.swift
    +
    // Source.swift
     struct Post {
     
         let title: String
    @@ -28,16 +27,16 @@
     
     extension Post {
     
    -    init?(fromJSON json: String) {
    +    init?(fromJSON json: String) {
             // TODO: remove dummy implementation
    -        self.title = "dummy"
    -        self.body = "lorem ipsum"
    +        self.title = "dummy"
    +        self.body = "lorem ipsum"
         }
     }
     
     // Tests.swift
    -func testPostFromJSON() {
    -  let post = Post(fromJSON: loadJSONFixture())
    +func testPostFromJSON() {
    +  let post = Post(fromJSON: loadJSONFixture())
       XCTAssertNotNil(post)
     }
     
    diff --git a/blog/code-like-a-chef/index.html b/blog/code-like-a-chef/index.html index a75fcc0..6d3ac41 100644 --- a/blog/code-like-a-chef/index.html +++ b/blog/code-like-a-chef/index.html @@ -27,7 +27,7 @@

    A messy codebase is like a dirty bench

    Compare Fiona and Georgia with chef and MasterChef judge Gary Mehigan. When Gary cooks in one of the show master classes you can see him almost compulsively wiping up the bench, keeping it spotless.

    -

    Keep your bench clean!

    +

    Keep your bench clean!

    The keep your bench clean rule is as valid when building software as it is when cooking dishes.

    If your codebase is messy and cluttered, getting stuff done will be harder and harder. You'll spend time deciphering unreadable code, scrolling through endless files, browsing deep folder hierarchies. diff --git a/blog/custom-afnetworking-response-serializer-for-errors/index.html b/blog/custom-afnetworking-response-serializer-for-errors/index.html index 69f0273..7e8956c 100644 --- a/blog/custom-afnetworking-response-serializer-for-errors/index.html +++ b/blog/custom-afnetworking-response-serializer-for-errors/index.html @@ -1,10 +1,9 @@ AFNetworking custom response serializer to add error information | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    AFNetworking custom response serializer to add error information

    Good network APIs add helpful messages to failing responses. For example:

    -
    {
    +
    {
       "error": "You are not authorized to access this resource."
    -}
    -

    A possible approach to notify the user of an iOS app consuming network APIs that an error has been returned by the server is to show such error data in some way.

    +}

    A possible approach to notify the user of an iOS app consuming network APIs that an error has been returned by the server is to show such error data in some way.

    When using AFNetworking the first thought that might come to mind is: I'll read the response data in the failure callback. But that is not possible, unlike the success callback the failure one doesn't have a responseObject parameter.

    This issue is relevant to the topic, and in particular Mattt's comment.

    @@ -14,7 +13,7 @@

    That makes sense. So how to create a custom response serializer?

    Since our example talks of JSON APIs the simplest thing to do is to subclass AFJSONResponseSerializer. Another option would be to roll out our own NSObject conforming to AFURLResponseSerialization, which is the protocol all serializers need to conform to.

    A serializer object needs to conform to AFURLResponseSerialization. So one option is to use a PONSO, plain old NSObject, and make it conform to the protocol. On the other hand what we are trying to achieve is adding a bit of functionality, adding info from the response to the failure callback error, to the standard JSON serialiation. So let's simply subclass AFJSONResponseSerializer.

    -
    @interface CustomJSONSerializer: AFJSONResponseSerializer
    +
    @interface CustomJSONSerializer: AFJSONResponseSerializer
     @end
     
     @implementation CustomJSONSerializer
    @@ -49,8 +48,7 @@
       return responseToReturn;
     }
     
    -@end
    -
    +@end

    That's it 👌.

    Note how the error is managed. Because it is a NSError *__autoreleasing * instance we need to access is like this: (*error).

    Food for Thought

    diff --git a/blog/demistifying-swift-functor/index.html b/blog/demistifying-swift-functor/index.html index cc99f15..4d49de7 100644 --- a/blog/demistifying-swift-functor/index.html +++ b/blog/demistifying-swift-functor/index.html @@ -7,54 +7,51 @@

    Nasty if let

    Probably one of the most disruptive features of Swift compared to Objective-C is the presence of optionals. Having a type wrapped in an optional adds an extra layer of context. A constant or variable of type Something? could be nil, and consumers have to account for that.

    The most common way to deal with optionals is by using an if let:

    -
    var input: String? = "foo bar"
    +
    var input: String? = "foo bar"
     var output: String
     
    -if let someInput = input {
    -    output = "🐷 " + someInput
    +if let someInput = input {
    +    output = "🐷 " + someInput
     } else {
    -    output = "😔"
    -}
    -
    + output = "😔" +}

    This construct can lead to a nasty nested indentation spiral of doom:

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
         // currentUser: -> User?
    -    if let actuallyAUser = currentUser() {
    +    if let actuallyAUser = currentUser() {
             // joinedNameForUser: User -> String
    -        let joinedUserName = joinedNameForUser(actuallyAUser)
    +        let joinedUserName = joinedNameForUser(actuallyAUser)
     
             // emojiFromString: String -> Emoji?
    -        if let emojiForUser = emojiFromString(joinedUserName) {
    +        if let emojiForUser = emojiFromString(joinedUserName) {
                 // fancifyEmoji: Emoji -> Emoji
                 return fancifyEmoji(emojiForUser)
             }
         }
     
         return .None
    -}
    -
    +}

    In my opinion the code above, while being simple, is not easy to digest.

    Swift 2 added the guard statement, which allows us to rewrite our example like this:

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
         // currentUser: -> User?
    -    guard let actuallyAUser = currentUser() else {
    +    guard let actuallyAUser = currentUser() else {
           return .None
         }
     
         // joinedNameForUser: User -> String
    -    let joinedUserName = joinedNameForUser(actuallyAUser)
    +    let joinedUserName = joinedNameForUser(actuallyAUser)
     
         // emojiFromString: String -> Emoji?
    -    guard let emojiForUser = emojiFromString(joinedUserName) {
    +    guard let emojiForUser = emojiFromString(joinedUserName) {
           return .None
         }
     
         // fancifyEmoji: Emoji -> Emoji
         return fancifyEmoji(emojiForUser)
    -}
    -
    +}

    This version is a bit nicer, and does good use of the early return pattern, but I still find it hard to grasp at first sight.

    Let's see how we can pick some pages from the functional programming book and make that code leaner.

    What Functional Programming Is All About

    @@ -62,64 +59,55 @@

    What Functional Programming Is

    Then cryptic words like functors and monads started to appear in my Twitter feed, and the cool kids started making jokes I couldn't understand.

    Good news everybody, functional programming is not about academia, abstract programs, or monadic laws. It is all about functions. For a programming language to be functional, or at least functional friendly, it simply needs to treat functions as first class citizens.

    In Swift we can define a function like this:

    -
    func plusOne(addend: Int) -> Int {
    -  return addend + 1
    -}
    -
    +
    func plusOne(addend: Int) -> Int {
    +  return addend + 1
    +}

    The first class citizen requirements mean that we can treat functions the same way we'd do for any other value. For example we can assign a function to a constant:

    -
    let plusTwo: Int -> Int = { $0 + 2 }
    +
    let plusTwo: Int -> Int = { $0 + 2 }
     
    -let four = plusTwo(2) // => 4
    -
    +let four = plusTwo(2) // => 4

    The code above defines a constant of type Int -> Int, or (Int) -> Int if you prefer, and assigns it a closure.

    Functions as input

    The ability of assigning functions to variables and constants means that we can also pass them as arguments to other functions. For example:

    -
    func sumTwice(addend: Int, f: Int -> Int) -> Int {
    -  return f(addend) + f(addend)
    +
    func sumTwice(addend: Int, f: Int -> Int) -> Int {
    +  return f(addend) + f(addend)
     }
     
    -let x = sumTwice(addend: 1, f: { $0 + 1 })
    +let x = sumTwice(addend: 1, f: { $0 + 1 })
     // => (1 + 1) + (1 + 1)
    -// => 4
    -
    +// => 4

    Functions as output

    The same holds true for functions that return other functions:

    -
    func multiplier(base: Int) -> (Int -> Int) {
    +
    func multiplier(base: Int) -> (Int -> Int) {
       return { x in
    -    return base * x
    +    return base * x
       }
     }
     
    -let timesThree = multiplier(3)
    -
    +let timesThree = multiplier(3)

    timesThree is now a function that multiplies the given parameter by three.

    -
    let x = timesThree(2) // => 6
    -
    +
    let x = timesThree(2) // => 6

    Higher Order Functions

    Here's the first demystification of a functional programming term. What we have seen above are example of "Higher Order Functions".

    The working definition for the everyday Swift development of Higher Order Functions is simply: functions take other functions as input and/or output.

    But what does this have to do with optionals? Let me introduce you to a very famous higher order function: map.

    map

    Let's say you have an array of, for example, Int, and a certain transformation function that takes Int as input and return any other type, for example String. And let's say that you need to apply the given transformation function to each element of the array, and collect the result into another array. One option you have is to use an ugly for each loop, a more concise option is to use map.

    -
    let numbers = [1, 2, 3]
    -let toString: Int -> String = { "\$0" }
    +
    let numbers = [1, 2, 3]
    +let toString: Int -> String = { "\$0" }
     
    -let strings = numbers.map(toString) // => ["1", "2", "3"]
    -
    +let strings = numbers.map(toString) // => ["1", "2", "3"]

    Or for the one liner fans:

    -
    let strings = numbers.map { "\$0" }
    -
    +
    let strings = numbers.map { "\$0" }

    map is pretty cool, but also a bit picky. The example below won't compile, can you guess why?

    -
    let getLength: String -> Int = { $0.characters.count }
    +
    let getLength: String -> Int = { $0.characters.count }
     
    -let lenghts = numbers.map(getLength) // [!] won't compile
    -
    +let lenghts = numbers.map(getLength) // [!] won't compile

    We will come back to this in a moment.

    The Array type

    Something that we might forget due to the [] convenience is that an array constant or variable actually has type Array<T>, where the generic T is the type of the elements the array is allowed to contain.

    We could rewrite the definition of numbers from the example above as:

    -
    let numbers: Array<Int> = [1, 2, 3]
    -
    +
    let numbers: Array<Int> = [1, 2, 3]

    Looking at arrays through their type definition makes it clearer to understand why numbers.map(getLenght) doesn't compile.

    Given an array Array<T> map expects a function T -> U.

    In the example numbers is has type Array<Int>, and toString is Int -> String which matches the expected type signature for map. On the other hand getLenght is a String -> Int which is not compatible with map on an array of Int.

    @@ -127,32 +115,28 @@

    The Array type

    The Optional type

    Like for Array it might be easy to overlook the fact that optionals variable and constants actually have type Optional<T>, where T is the type of the value wrapped by the optional.

    These definitions are equivalent:

    -
    let x: String? = "an optional string"
    +
    let x: String? = "an optional string"
     
    -let y: Optional<String> = "another optional string"
    +let y: Optional<String> = "another optional string"
     
    -let z = Opional.Some("yet another optional string")
    -
    +let z = Opional.Some("yet another optional string")

    As you might have notice the definition of optional and array variables are quite similar.

    -
    let a: Array<Int> = [1, 2, 3]
    -let b: Optional<Int> = Optional.Some(42)
    -
    +
    let a: Array<Int> = [1, 2, 3]
    +let b: Optional<Int> = Optional.Some(42)

    Optional is similar to Array. Array has map. Can you guess what comes next?

    Optional map

    Yes, you guessed right! The Optional type implements map as well.

    -
    Optional.Some(42).map { $0 / 2 } // => Optional.Some(24)
    +
    Optional.Some(42).map { $0 / 2 } // => Optional.Some(24)
     
    -Optional.None.map { $0 / 2 } // => Optional.None
    -
    +Optional.None.map { $0 / 2 } // => Optional.None

    In the case of optionals, if there is a wrapped value map applies the function to the value, and returns the result wrapped in a new optional, otherwise simply returns .None.

    The considerations regarding the type signatures made for Array map are valid for Optional too.

    -
    let x: Optional<Int> = 42
    -let f: Int -> Int = { $0 * 2 }
    -let q: String -> Int = { $0.characters.count  }
    +
    let x: Optional<Int> = 42
    +let f: Int -> Int = { $0 * 2 }
    +let q: String -> Int = { $0.characters.count  }
     
    -x.map(f) // compiles
    -x.map(q) // [!] does not compile
    -
    +x.map(f) // compiles +x.map(q) // [!] does not compile

    q has type String -> Int, but x is Optional<Int>. Their types don't match for map.

    Functor

    The definition of functor for the everyday Swift developer is a type that implements map.

    @@ -160,34 +144,32 @@

    Functor

    Like for higher order functions, once you look into it there is nothing daunting about functor at all. It is just the name for a type that respect certain laws, with the practical result of exposing map.

    Better if let

    Let's look back at fancifiedEmojiForCurrentUser.

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
       // currentUser: -> User?
    -  if let actuallyAUser = currentUser() {
    +  if let actuallyAUser = currentUser() {
         // joinedNameForUser: User -> String
    -    let joinedUserName = joinedNameForUser(actuallyAUser)
    +    let joinedUserName = joinedNameForUser(actuallyAUser)
     
         // emojiFromString: String -> Emoji?
    -    if let emojiForUser = emojiFromString(joinedUserName) {
    +    if let emojiForUser = emojiFromString(joinedUserName) {
           // fancifyEmoji: Emoji -> Emoji
           return fancifyEmoji(emojiForUser)
         }
       }
     
       return .None
    -}
    -
    +}

    The currentUser function returns a User?, as there migth not be a logged user, and joinedNameForUser gets a User as input, and returns a String. We can use map there.

    emojyFromString as type signature String -> Emoji?, apparently not all the strings can be converted into emojis, and fancifyEmoji expects an input of type Emoji. We can use map on them too.

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
    -  if let joinedUserName = currentUser.map(joinedNameForUser) {
    -    return emojiFromString(joinedUserName).map(fancifyEmoji)
    +  if let joinedUserName = currentUser.map(joinedNameForUser) {
    +    return emojiFromString(joinedUserName).map(fancifyEmoji)
       }
     
       return .None
    -}
    -
    +}

    Now, wouldn't it be nice to chain everything together using map?

    Unfortunately this is not possible. Why? Let's follow the types.

    currentUser.map(joinedNameForUser) is a map on a User? of a User -> String function, which from what we saw above returns a String?.

    @@ -197,67 +179,59 @@

    Better if let

    To solve this mystery let's go back to Array.

    Nested arrays

    What would happen if we mapped a function Int -> [Int] on an array of Int?

    -
    [1, 2, 3].map { [ $0, $0 ] } // => [ [1, 1], [2, 2], [3, 3] ]
    -
    +
    [1, 2, 3].map { [ $0, $0 ] } // => [ [1, 1], [2, 2], [3, 3] ]

    What we get is an array of arrays, or nested array.

    Sometimes nested arrays are the data structure we need in our code, other times they are not an what we need is a linear array. The operation of converting a nested array into a linear one is called flattening.

    -
    func flat<T>(array nestedArray: [ [T] ]) -> [T] {
    -  var linearArray: [T] = []
    +
    func flat<T>(array nestedArray: [ [T] ]) -> [T] {
    +  var linearArray: [T] = []
       for array in nestedArray {
         for element in array {
           linearArray.append(element)
         }
       }
    -}
    -
    +}

    In the example above we can use flat to get a linear array:

    -
    flat([1, 2, 3].map { [ $0, $0 ] }) // => [ 1, 1, 2, 2, 3, 3 ]
    -
    +
    flat([1, 2, 3].map { [ $0, $0 ] }) // => [ 1, 1, 2, 2, 3, 3 ]

    flat, map... Array has a flatMap method that does exactly that.

    flatMap

    -
    [1, 2, 3].flatMap { [ $0, $0 ] }) // => [ 1, 1, 2, 2, 3, 3 ]
    -
    +
    [1, 2, 3].flatMap { [ $0, $0 ] }) // => [ 1, 1, 2, 2, 3, 3 ]

    flatMap on an Array<T> expects a function T -> Array<U> and returns Array<U>. It maps then flats. Note that in our examples U is equal to T.

    Before we saw that Array is similar to Optional, and that in fact they are both functors and have map. It won't surprise you to know then that Optional has a flatMap implementation itself.

    flatMap on optionals

    Given an Optional<T>, flatMap expects a T -> Optional<U> as input, and has output of type Optional<U>

    For example, consider this function half that returns an Int? because it attempts to divide by to only if the number parameter is even:

    -
    func half(number: Int) -> Int? {
    -  switch number % 2 {
    -  case 0: return number / 2
    +
    func half(number: Int) -> Int? {
    +  switch number % 2 {
    +  case 0: return number / 2
       default: return .None
       }
    -}
    -
    +}

    We can do:

    -
    Optional<Int>.Some(4).flatMap(half)   // => Optional.Some(2)
    +
    Optional<Int>.Some(4).flatMap(half)   // => Optional.Some(2)
     Optional<Int>.Some(3).flatMap(half)   // => Optional.None
    -Optional<Int>.None                    // => Optional.None
    -
    +Optional<Int>.None // => Optional.None

    Monad

    Here is demystified our third and final functional programming term. A Monad is a type that allows map and flatMap.

    Like for functors, there is actually a very solid mathematical definition behind monads, with a set of monadic laws governing them. For the everyday Swift developer like you and me though, a monad is a type on which we can map and flatMap, like Array and Optional.

    Even better if let

    We left our fancifiedEmojiForCurrentUser for current user in this state:

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
    -  if let joinedUserName = currentUser.map(joinedNameForUser) {
    -    return emojiFromString(joinedUserName).map(fancifyEmoji)
    +  if let joinedUserName = currentUser.map(joinedNameForUser) {
    +    return emojiFromString(joinedUserName).map(fancifyEmoji)
       }
     
       return .None
    -}
    -
    +}

    We tried to chain everything together with map but got stuck when we got a nested optional Emoji. Now that we know flatMap we can achieve that result, in fact currentUser.map(joinedNameForUser) returns String? and emojiFromString has type signature String -> Emoji?, this looks like a good use case for flatMap.

    -
    func fancifiedEmojiForCurrentUser() -> String? {
    +
    func fancifiedEmojiForCurrentUser() -> String? {
     
       return currentUser
    -    .map(joinedNameForUser)
    +    .map(joinedNameForUser)
         .flatMap(emojiFromString)
    -    .map(fancifyEmoji)
    +    .map(fancifyEmoji)
     
    -}
    -
    +}

    There you go. Isn't that code nice?

    To a reader familiar with map and flatMap this final example appear very clear, and is arguably easier on the eye then the version using if let or guard.

    Wrapping Up

    diff --git a/blog/dependency-injection-for-classes-in-swift/index.html b/blog/dependency-injection-for-classes-in-swift/index.html index eefdd76..2d979b0 100644 --- a/blog/dependency-injection-for-classes-in-swift/index.html +++ b/blog/dependency-injection-for-classes-in-swift/index.html @@ -1,38 +1,36 @@ How to use dependency injection for classes in Swift | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to use dependency injection for classes in Swift

    When working with legacy code, or rather code that has not been designed for testability, we often encounter components that provide static methods. Things like:

    -
    Helper.converValue(foo)
    +
    Helper.converValue(foo)
     
     GlobalCounter.increase()
     
    -CustomLogger.logError(error)
    -
    +CustomLogger.logError(error)

    These tools might seem advantageous because they can be easily used without the need for initialization, or for the consumer to retain them. On the other hand they are hard to test. The classic dependency injection pattern that we normally use doesn't apply here, we can't inject classes, or can we?

    In Swift it is actually possible to define a reference to an actual type, rather than to an instance.

    -
    //...
    +
    //...
     class Foo {
    -  static func bar()
    +  static func bar()
     }
     
    -func f(fooClass: Foo.Type = Foo.self) {
    +func f(fooClass: Foo.Type = Foo.self) {
       fooClass.bar()
    -}
    -
    +}

    This technique doesn't only work with classes. For Swift a type is a type, doesn't matter if class, struct, enum or protocol. You can use this example Playground to verify it.

    Once we know how to refer to actual types, we can apply the same "protocol-inject-mock" pattern that we're already familiar with to add test coverage to legacy code that we're not able to restructure at this point.

    -
    // GlobalHelper.swift
    +
    // GlobalHelper.swift
     protocol GlobalHelper {
    -    static func someSideEffect()
    +    static func someSideEffect()
     }
     
     // LegacyGlobalHelper.swift
     class LegacyGlobalHelper: GlobalHelper {
    -    static func someSideEffect() { }
    +    static func someSideEffect() { }
     }
     
     // MyService.swift
     class MyService {
    -    func doStuffWithSideEffect(globalHelper: GlobalHelper.Type = LegacyGlobalHelper.self) {
    +    func doStuffWithSideEffect(globalHelper: GlobalHelper.Type = LegacyGlobalHelper.self) {
             // ...
             globalHelper.someSideEffect()
             // ...
    @@ -41,10 +39,10 @@
     
     // MyServiceSpec.swift
     class GlobalHelperMock: GlobalHelper {
    -    static var someSideEffectCalled = false
    +    static var someSideEffectCalled = false
     
    -    static func someSideEffect() {
    -        someSideEffectCalled = true
    +    static func someSideEffect() {
    +        someSideEffectCalled = true
         }
     }
     
    @@ -52,16 +50,15 @@
     describe("MyService") {
       context("when doing stuff") {
         it("performs a side effect") {
    -      let service = MyService()
    -      let mockHelper = GlobalHelperMock.self
    +      let service = MyService()
    +      let mockHelper = GlobalHelperMock.self
     
           service.doStuffWithSideEffect(globalHelper: mockHelper)
     
    -      expect(mockHelper.someSideEffectCalled) == true
    +      expect(mockHelper.someSideEffectCalled) == true
         }
       }
    -}
    -
    +}

    Note, testing for methods to have been called is not a good way to write tests. We should always try to assert behaviour rather than implementation details. Having tests that focus on behaviour rather than implementation enables us to change the inner workings of our software and still be confident that it performs as expected, that's what refactoring is all about.

    The technique shown in this post is more of a workaround that you can use while dealing with legacy code that you can't easily refactor, but for which you need to have more confidence.

    If you have any questions on injecting classes for the purpose of testing legacy code, or anything else testing related leave a comment below or get in touch on Twitter @mokagio.

    diff --git a/blog/devworld2015-notes-of-a-testing-fanboy/index.html b/blog/devworld2015-notes-of-a-testing-fanboy/index.html index 122e27a..f1f4efe 100644 --- a/blog/devworld2015-notes-of-a-testing-fanboy/index.html +++ b/blog/devworld2015-notes-of-a-testing-fanboy/index.html @@ -8,7 +8,7 @@

    Software Architecture

    The way we architect our application matters because otherwise we risk code becoming unmanageable as the codebase grows, and different developers touch it.

    But how to do it? As usual there is no silver bullet, but a good rule of thumb Bogo shared is to blackbox as much as the architecture as possible.

    -

    +

    Black-boxing means having well defined boundaries with between the objects in the system, and only use those boundaries as the interfaces for objects communication.

    @@ -34,7 +34,7 @@

    Process

  • Running tests on every push on every related branch with BuildKite
  • and finally build an ipa, take screenshots, and submit to TestFlight with fastlane
  • -

    +

    To the question from cheeky guy from the audience (me) on whether he tests the scripts for the pipelines he builds, Matt replied that the best way to test them is to run them.

    @@ -42,7 +42,7 @@

    Process

    Testing your code is important because it can prevent regression, and find bugs systematically. This results in higher quality apps, which make their users happy. And since your app's users are actually your customers, that means that they are going to be more likely to give you money.

    The talk finished with a discussion with the audience on what's the first thing that you should be testing when working on an existing app that doesn't have tests. One answer was to start with the most unpredictable things, like user interaction, make sure that all the components related to the user interaction are robust. Another answer was to pick the first bug in the backlog, and write a test for the expected behaviour. The test will be failing, because the bug is there. Then fix the bug an see the test pass.

    As I side note, I really enjoyed Tim's talk Pokémons theme.

    -

    +

    Tooling

    @@ -56,7 +56,7 @@

    Tooling

    Andrew's point was that getting the client's feedback early to know if the product is in line with their expectation, and if it actually works, is much more valuable that having a nice and tidy codebase. By working directly in Xcode with Swift Andrew can deliver prototypes in less than a week, instead of the usual 3-4 weeks, and collect important information for the proper development stage.


    Two talks, unrelated to the testing and automation topic, but still great have been "Social Interaction Over Shared Devices:
Designing Interactive Story Apps for Children" by Betty Seargent sharing her experience making interactive books for kids and rediscovering the importance of having adults and child read books together, and finally Paul Fenwick on the future of technology.

    -

    +

    This was my first /dev/world, but it is certainly not going to be the last. I had such a great time, met awesome people, and learnt a lot.

    diff --git a/blog/does-software-understand-complexity-m-feathers/index.html b/blog/does-software-understand-complexity-m-feathers/index.html index 80f9262..0f9c0a0 100644 --- a/blog/does-software-understand-complexity-m-feathers/index.html +++ b/blog/does-software-understand-complexity-m-feathers/index.html @@ -6,7 +6,7 @@

    There's a lot of knowledge outside our field that could be applicable to us - different ways of seeing problems and different frames we can apply to them.

    -

    I ask software developers I meet "what is your biggest struggle with building software right now?". An answer I often get is "managing complexity".

    +

    I ask software developers I meet "[what is your biggest struggle with building software right now?](mailto:gio+struggle@mokacoding.com?subject=My biggest struggle with building software&body=My biggest struggle with building software right now is...)". An answer I often get is "managing complexity".

    Complexity keeps creeping in every system we build, we seem unable to keep it at bait. I share Michael Feathers' hope that as an industry we'll start learning from other fields and develop a body of research based approaches to deal with complexity.

    I can't help but being a bit cynical about it though. While preparing a refactoring workshop for /dev/world/2018 I've gone through Working Effectively with Legacy Code one more time. A passage from the introduction caught my attention.

    diff --git a/blog/double-slash-xcconfig/index.html b/blog/double-slash-xcconfig/index.html index f2641a1..fd297f4 100644 --- a/blog/double-slash-xcconfig/index.html +++ b/blog/double-slash-xcconfig/index.html @@ -5,9 +5,8 @@

    There is a problem though, the syntax in which to write xcconfigs files is not very powerful.

    A common issue is being unable to write URLs due to the double slash in "http://" being interpreted as a comment.

    This is my solution:

    -
    SLASH = /
    -URL = https:$(SLASH)/mokacoding.com
    -

    It looks ugly and silly, but it does work.

    +
    SLASH = /
    +URL = https:$(SLASH)/mokacoding.com

    It looks ugly and silly, but it does work.

    Let me know if you have better options, or how this approach works out for you.

    Leave the codebase better than you found it.

    diff --git a/blog/env-xargs/index.html b/blog/env-xargs/index.html index c63663c..4cfa1ec 100644 --- a/blog/env-xargs/index.html +++ b/blog/env-xargs/index.html @@ -1,25 +1,22 @@ Injecting environment variables from a file with xargs | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    mokacoding

    unit and acceptance testing, automation, productivity

    Injecting environment variables from a file with xargs

    TL;DR

    You can use

    -
    env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_vars
    -
    +
    env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_vars

    to run your_command_expecting_env_vars providing it the content of .env like you would do when running FOO=1 BAR=2 your_command_expecting_env_vars.

    -

    TS;WR

    +

    TS;WR

    Many command lines tool can read, or even expect, values set in environment variables.

    It is a common practice to place environment variables contextual to a project in a .env file in the project root, and there are tools like dotenv that allow you to load those variables into your application.

    Sometimes thought you just need to set a handful of values and cannot be bothered typing FOO=1 BAR=2 BAZ=3 bundle exec foobarbaz. Or maybe your cli tool expects a token that you don't want to store in the repo, but at the same time cannot type every time.

    In such cases it might be useful to place those environment variables in a .env file, but how to load them?

    This is one possible way:

    -
    env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_var
    -

    Let's disassemble this long command, shall we?

    +
    env $(cat .env | grep -v "#" | xargs) your_command_expecting_env_var

    Let's disassemble this long command, shall we?

    $(...) will be evaluate it's content before the command is interpreted and run, and replaced with the result, so that what actually is run will be env result your_command_expecting_env_var.

    cat .env will put the content of the .env file into the standard output. This would normally be the screen, but in this case there is a pipe operator.

    grep -v "#" is an inverted match grep. By default grep selects lines containing the given pattern, the string # in our case, from its standard input. With the -v, or --invert-match it will select the lines not matching the given string.

    So cat .env | grep -v "#" results in the content of .env apart from comment lines sent to the standard output, where xargs is there to wait for it. xargs builds an argument list out of its standard input.

    This argument list is fed to env. The synopsis of this command is:

    -
    env [-i] [name=value ...] [utility [argument ...]]
    -
    +
    env [-i] [name=value ...] [utility [argument ...]]

    What env does is executing utility after modifying the environment as specified by the name=value ... list. And that is exactly the end result that we are looking for 😎

    A nice thing to notice is that env doesn't export the name=value inputs, so that the environment is not polluted.

    Hope you found this article useful, this is the SO answer that inspired and helped me with this approach.

    diff --git a/blog/expecta-custom-matchers/index.html b/blog/expecta-custom-matchers/index.html index e5959a8..39ae507 100644 --- a/blog/expecta-custom-matchers/index.html +++ b/blog/expecta-custom-matchers/index.html @@ -13,32 +13,27 @@

    How to write a custom matcher

    The first step is creating an EXPMatchers category named after the new matcher: EXPMatchers+beAFruit.

    We are now going to look at the code step by step, you can always check the example repo to see the entire header and implementation.

    In the .h we'll define the signature of our matcher using the EXPMatcherInterface macro, which expects the matcher name and a list of arguments.

    -
    #import "Expecta.h"
    +
    #import "Expecta.h"
     
    -EXPMatcherInterface(beAFruit, (void))
    -
    +EXPMatcherInterface(beAFruit, (void))

    Notice the (void) as the second argument to state that our matcher is not using any parameters.

    Than we are going to write the matcher's implementation, by providing code to run for the blocks making up the matcher.

    -
    #import "EXPMatchers+beAFruit.h"
    +
    #import "EXPMatchers+beAFruit.h"
     #import "Fruit.h"
     
    -EXPMatcherImplementationBegin(beAFruit, (void)) {
    -
    +EXPMatcherImplementationBegin(beAFruit, (void)) {

    The matcher has access to the object in the expect( ) through actual. Since we're going to need to check for it's nil state more than once in the implementation we should put that value in a variable.

    -
      BOOL actualIsNil = actual == nil;
    -
    +
      BOOL actualIsNil = actual == nil;

    The first block to implement is prerequisite, this can be used to perform pre-checks and make the test fail. In the library's beCloseTo if actual is not an NSNumber there is no point in comparing it, so the test can fail already. In our case if actual is nil the is certainly not a Fruit, so we can fail straightaway.

    -
      prerequisite(^BOOL {
    +
      prerequisite(^BOOL {
         return !actualIsNil;
    -  });
    -
    + });

    Then there is match, which is where we can perform all the logic to determine whether our expectation is met.

    -
      match(^BOOL {
    +
      match(^BOOL {
         return [actual isKindOfClass:[Fruit class]];
    -  });
    -
    + });

    Finally there are two blocks that print the error message for the normal and negated (.toNot) failure scenarios.

    -
      failureMessageForTo(^NSString * {
    +
      failureMessageForTo(^NSString * {
         if (actualIsNil) {
           return @"the actual value in nil/null";
         }
    @@ -52,15 +47,12 @@ 

    How to write a custom matcher

    } return [NSString stringWithFormat:@"expected: not kind of %@, got: an instance of %@", [Fruit class], [actual class]]; - }); -
    + });

    The last thing left to do is do declare that the implementation is finished.

    -
    EXPMatcherImplementationEnd
    -
    +
    EXPMatcherImplementationEnd

    You can see beAFruit implementation all in one file, as well as it's usage in a test case, in the example repo.

    In case you want to write a matcher that uses an argument, like expect(@42).to.beLessThan(@100), you can specify it in the matcher interface and implementation definition blocks like this:

    -
    EXPMatcherInterface(beLessThan, (id expected));
    -
    +
    EXPMatcherInterface(beLessThan, (id expected));

    Note that expected is the naming convention used by all the matcher in the library, so you should use it too.

    Custom matchers in the wild

    So nice people in the open source community have already written some custom matchers for Expecta. The most interesting ones are:

    diff --git a/blog/expecta/index.html b/blog/expecta/index.html index 549443a..ed6480b 100644 --- a/blog/expecta/index.html +++ b/blog/expecta/index.html @@ -4,7 +4,7 @@

    We've recently seen how using Specta can help us writing better unit, and acceptance tests for our Objective-C projects, but we can go one step further.

    The Specta team built a matcher library called Expecta. Expecta comes a number of expectation methods that provide developer writing tests the syntax and vocabulary they need to achieve the clarity they strive for so much.

    I am so confident in the readability of tests written with Specta and Expecta that I'm gonna write the rest of this post as a spec:

    -
    SpecBegin(ExpectaPost)
    +
    SpecBegin(ExpectaPost)
     
     describe(@"The expecta matcher libray", ^{
         context(@"has all the matchers you would expect", ^{
    @@ -79,8 +79,7 @@
         });
     });
     
    -SpecEnd
    -
    +SpecEnd

    What we just saw is only a subset of the matchers available with Expecta, you can find the full list on the project's README.

    Expecta is a very nice library, and I hope this post triggered some interest in you towards unit testing and the art of readable code, but it does not end here! You can actually extent Expecta by providing custom matchers. We are going to look at those next week, so don't forget to subscribe. If you're interested check out the next post: "How to write an Expecta custom matcher", and don't forget to subscribe to be notified when new posts about Expecta and the world of iOS unit testing are published.

    diff --git a/blog/explicit-dependencies-swift/index.html b/blog/explicit-dependencies-swift/index.html index 16828b1..b6ef6ce 100644 --- a/blog/explicit-dependencies-swift/index.html +++ b/blog/explicit-dependencies-swift/index.html @@ -5,18 +5,18 @@

    The post is written in Objective-C to stress the separation between interface and implementation. It is easier to visualise when they are in two different files!

    Unlike Objective-C, Swift's code is all in one file, interfaces and implementation are merged together, except when looking at a compiled framework. Nevertheless everything we said for Objective-C explicit dependencies is true for Swift as well.

    Here's how a class that exposes its dependencies might look like in Swift:

    -
    class ProductService {
    +
    class ProductService {
         let parser: Parser
         let appStateService: AppStateService
         let networkService: NetworkService
     
    -    init(appStateService: AppStateService, networkService: NetworkService, parser: Parser) {
    -        self.parser = parser
    -        self.networkService = networkService
    -        self.appStateService = appStateService
    +    init(appStateService: AppStateService, networkService: NetworkService, parser: Parser) {
    +        self.parser = parser
    +        self.networkService = networkService
    +        self.appStateService = appStateService
         }
     
    -    convenience init() {
    +    convenience init() {
             self.init(appStateService: AppStateService.sharedInstance(),
                 networkService: NetworkService.sharedInstance(),
                 parser: Parser())
    @@ -24,27 +24,25 @@
     
         // MARK: -
     
    -    func allProducts(completion: ([Product]?, ErrorType?) -> ()) {
    -        let currentUser = appStateService.currentUser()
    -        let success: ([String: AnyObject]) -> () = { response in
    +    func allProducts(completion: ([Product]?, ErrorType?) -> ()) {
    +        let currentUser = appStateService.currentUser()
    +        let success: ([String: AnyObject]) -> () = { response in
                 completion(self.parser.parseProducts(response), .None)
             }
    -        let failure: (ErrorType) -> () = { error in
    +        let failure: (ErrorType) -> () = { error in
                 completion(.None, error)
             }
             networkService.getAllProducts(currentUser, success: success, failure: failure)
         }
    -}
    -
    +}

    Let's appreciate the fact that by declaring parser, appStateService, and networkService as class properties we see them at the very top of the code. This is just a convention, the same code with the properties defiend at the very bottom would sitll compile.

    Another little detail to underline is the use of the convenience keyword. That make is clear to the reader, and the compiler, that that initializer is not the proper one, but a more convenient one to use.

    I am a bit conflicted on the use of that one in place of a convenience factory method:

    -
    static func configuredService() -> ProductService {
    +
    static func configuredService() -> ProductService {
         return ProcutService(appStateService: AppStateService.sharedInstance(),
             networkService: NetworkService.sharedInstance(),
             parser: Parser())
    -}
    -
    +}

    What do you think about it? Convenience initializer or factory method? Hit me up on Twitter @mokagio, or leave a comment below.

    Leave the codebase better that you found it.

    diff --git a/blog/explicit-dependencies/index.html b/blog/explicit-dependencies/index.html index 22d2ac7..84f7042 100644 --- a/blog/explicit-dependencies/index.html +++ b/blog/explicit-dependencies/index.html @@ -5,16 +5,15 @@

    What lies under the hood of your interface

    In this post we are going to see how to make an object's dependencies explicit, why it is a good idea, and the trade-offs we make when choosing such a design.

    Consider this interface:

    -
    typedef void (^Completion)(NSArray *products, NSError *error);
    +
    typedef void (^Completion)(NSArray *products, NSError *error);
     
     @interface ProductsService: NSObject
     
     - (void)allProducts:(Completion)completion;
     
    -@end
    -
    +@end

    It looks fairly simple, right? Let's have a look at the implementation:

    -
    @implementation ProductsService
    +
    @implementation ProductsService
     
     - (void)allProducts:(Completion)completion {
         User *user = [[AppStateService sharedInstance] currentUser];
    @@ -27,14 +26,13 @@
         }];
     }
     
    -@end
    -
    +@end

    See what's going on in there? Apart from the disgusting sharedInstances, the -allProducts: method is using other three objects in its internals: AppStateService, Parser and NetworkService.

    Now, there is conceptually nothing wrong with this. You could say that ProductsService is acting as a facade and that is the embodiment of the information hiding principle. And you would be right.

    However, there is a high surprise effect between what the interface exposes and what the implementation does. Hiding all the components involved in the process can make it harder to see all the moving parts of the system, reason about it, and understand how to make changes safely.

    How to make dependencies explicit

    Making a class's dependencies explicit is quite simple. Let's look at the ProductService from above.

    -
    @interface ProductsService: NSObject
    +
    @interface ProductsService: NSObject
     
     - (instancetype)initWithParser:(Parser *)parser
                       stateService:(AppStateService *)stateService
    @@ -61,10 +59,9 @@ 

    How to make dependencies explicit

    //... -@end -
    +@end

    And we can then rewrite allProducts like this:

    -
    - (void)allProducts:(Completion)completion {
    +
    - (void)allProducts:(Completion)completion {
         User *user = [self.stateService currentUser];
         [self.networkService getAllProductsForUser:user withSuccess:^(NSDictionary *responseDictionary) {
           NSArray *products = [self.parser parseProducts:responseDictionary];
    @@ -72,8 +69,7 @@ 

    How to make dependencies explicit

    NSError *error) { completion(nil, error); }]; -} -
    +}

    The idea is simple, instead of instantiating the objects used in the method's internals, we simply pass them as init arguments, that will be stored in instance properties.

    The benefits of explicit dependencies

    Dependencies are clear in the interface. By exposing all the objects our class needs in its internals either in the init or as method parameters we provide readers of the interfaces all the information and all the context around the class.

    @@ -88,7 +84,7 @@

    When to use this approach

    There is a middle ground

    Turns out you can have your pie and eat it too when it comes to explicit dependencies and simple interfaces.

    For example you can make the dependencies explicit in the designated initializer, and provide a convenience factory method that does all the hard work for you.

    -
    @interface ProductsService: NSObject
    +
    @interface ProductsService: NSObject
     
     - (instancetype)initWithParser:(Parser *)parser
                       stateService:(AppStateService *)stateService
    @@ -102,8 +98,7 @@ 

    There is a middle ground

    + (instanceType)productsService; -@end -
    +@end

    I personally like to put factory methods in a category extension, just to make the separation from the core code of the class clearer.

    When designing code is important to remember that being too smart is not a clever idea. Code that does too much, with side effects, or with implementations that don't behave as one would expect when looking at the interface are dangerous. When writing code we should think of our readers and apply the principle of least astonishment, everything should behave as the they would expect. Making the dependencies of your classes explicit is one good technique to make sure that once the interface lid is lifted and we take a look at the implementation there are no surprises.

    Leave the codebase better than you found it.

    diff --git a/blog/fixing-bugs-driven-by-tests-in-swift/index.html b/blog/fixing-bugs-driven-by-tests-in-swift/index.html index 53fe5ef..812ac06 100644 --- a/blog/fixing-bugs-driven-by-tests-in-swift/index.html +++ b/blog/fixing-bugs-driven-by-tests-in-swift/index.html @@ -15,34 +15,33 @@

    Fix a bug with an unit test

    Let's write a unit test that we'll have to make green in order to fix this bug. But how?

    Well first of all we need to find the code responsible for providing the data to the note table view. Turns out that there is a NotesListDataSource object that NotesListViewController uses in its implementation of the UITableViewDataSource methods.

    There are many ways to write the test for this bug, here's one:

    -
    class NotesDataSourceTest: XCTestCase {
    +
    class NotesDataSourceTest: XCTestCase {
     
       // it sorts the notes by updated date
    -  func testSortsNotesByUpdatesDate() {
    -    let firstNote = Note(name: "any name", content: "any content", lastUpdated: NSDate().dateByAddingTimeInterval(60))
    -    let secondNote = Note(name: "any other name", content: "any content", lastUpdated: NSDate())
    -    let thirdNote = Note(name: "yet another name", content: "any content", lastUpdated: NSDate().dateByAddingTimeInterval(-60))
    +  func testSortsNotesByUpdatesDate() {
    +    let firstNote = Note(name: "any name", content: "any content", lastUpdated: NSDate().dateByAddingTimeInterval(60))
    +    let secondNote = Note(name: "any other name", content: "any content", lastUpdated: NSDate())
    +    let thirdNote = Note(name: "yet another name", content: "any content", lastUpdated: NSDate().dateByAddingTimeInterval(-60))
     
    -    let sut = NotesDataSource(notes: [thirdNote, firstNote, secondNote])
    +    let sut = NotesDataSource(notes: [thirdNote, firstNote, secondNote])
     
         assert(sut.noteAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)), isEqualTo: firstNote)
         assert(sut.noteAtIndexPath(NSIndexPath(forRow: 1, inSection: 0)), isEqualTo: secondNote)
         assert(sut.noteAtIndexPath(NSIndexPath(forRow: 2, inSection: 0)), isEqualTo: thirdNote)
       }
     
    -  private func assert(note: Note, isEqualTo otherNote: Note) {
    +  private func assert(note: Note, isEqualTo otherNote: Note) {
         XCTAssertEqual(note.name, otherNote.name)
       }
    -}
    -
    +}

    Now if you run the tests, or got to this commit, you'll see that they fail.

    Making the test pass, and therefore fixing the bug is as easy as adding a sort step when initializing the data source.

    Fix a bug with an acceptance test

    If you run Simple Notes you'll notice that nothing happens when selecting a note. That is outrageous! The expected behaviour is for the app to transition to a screen showing the details of the note.

    This kind of bug is related to the navigation of the application rather that its logic, and we can easily write an acceptance test. For example:

    -
    func testShowsNotesDetails() {
    +
    func testShowsNotesDetails() {
       // From the notes list screen
    -  let app = XCUIApplication()
    +  let app = XCUIApplication()
     
       XCTAssertTrue(app.anyViewWithIdentifier("notes_list_screen").exists)
     
    @@ -55,8 +54,7 @@ 

    Fix a bug with an acceptance test

    // Go back app.backButton().tap() -} -
    +}

    Note that because the app is currently broken I had to write that test manually, rather then recording it. But that's ok, after playing around with the UI testing APIs you will get familiar with them and writing acceptance test will be a smooth experience.

    Also note that the approach used in that test is to assert the presence of an accessibility element with a certain identifier. That is a simple trick I use that decouples tests for the user navigation in the app from the content on UI itself. In fact, the accessibility identifier is set on the view controller's main view.

    In my opinion this approach is better that, for example, asserting the presence of views containing the title and content of a note because:

    diff --git a/blog/functional-core-reactive-shell/index.html b/blog/functional-core-reactive-shell/index.html index aaf1e35..e53a865 100644 --- a/blog/functional-core-reactive-shell/index.html +++ b/blog/functional-core-reactive-shell/index.html @@ -7,7 +7,8 @@ software architecture and how manage its complexity.

    You can see the video from one of the talks here. And these are the slides:

    -

    + +

    Spaghetti, Lasagna and Pizza

    We're all too familiar with so called spaghetti code, source code so entangled and messy to remind of a bowl of spaghetti, minus the deliciousness.

    @@ -74,8 +75,7 @@

    The issue with Mocks

    Isn't one of the points of tests to enable us to change the implementation of our components without changing the system's behaviour?

    If you were to test a method with this signature:

    -
    func sum(a: Int, b: Int) -> Int
    -
    +
    func sum(a: Int, b: Int) -> Int

    Would you assert that + is called, or that given 1 and 2 the result is 3?

    Smarter people than me have tackled the issue of mocking, one of those is Ken Scambler in his post "To Kill a @@ -118,7 +118,7 @@

    Decision and Actions

    from the code taking action, what actually performs the effect.

    For example when storing some data in the database we could have a DatabaseAction value:

    -
    enum DatabaseActionMode {
    +
    enum DatabaseActionMode {
       case Delete
       case Insert
       case Update
    @@ -127,22 +127,20 @@ 

    Decision and Actions

    struct DatabaseAction { let objects: [Persistable] let mode: DatabaseActionMode -} -
    +}

    Testing code that interacts with the database would then become a matter of testing the logic, pure functions, producing DatabaseAction values.

    The action can then be performed by something like this:

    -
    class DatabaseService {
    +
    class DatabaseService {
     
    -  func performAction(action: DatabaseAction) {
    +  func performAction(action: DatabaseAction) {
         switch action.mode {
         case .Delete: // ...
         case .Insert: // ...
         case .Update: // ...
         }
       }
    -}
    -
    +}

    Testing DatabaseService would be easy as well, just create a simple DatabaseAction and verify that the objects it carries are modified in database according to the value of its mode property.

    @@ -183,7 +181,7 @@

    Functional Core, Reactive Shell

    quite easily too, just provide our own source of input signals to the shell, and subscribe to them to assert the side effect values are configured as expected.

    -

    Is this pizza actually edible?

    +

    Is this pizza actually edible?

    While there's little doubt that real Italian food, and Pizza in particular, is delicious, you might be wondering if the "Functional Core, Reactive Shell" is actually a good idea.

    @@ -196,12 +194,12 @@

    Is this pizza actually edible?

    familiar with FRP.

    Finally, another considerable disadvantage is that the reactive shell code, the crust of the pizza, will look long and odd. Like this:

    -
    SignalProducer(values: [
    +
    SignalProducer(values: [
         //
         // Input sources
         //
         databaseService.allStuff()
    -        .map { $0.map { Stuff(realmObject: $0) } },
    +        .map { $0.map { Stuff(realmObject: $0) } },
     
         networkService.performRequest(toEndpoint: .GetStuff)
             .flatMap(.Latest) { JSON in
    @@ -212,22 +210,21 @@ 

    Is this pizza actually edible?

    // // Data transformations // - .map { stuffArray in stuffArray.map { CellViewModel(stuff: $0) } } - .map { viewModels in Effect.UpdateView(viewModels: viewModels) } + .map { stuffArray in stuffArray.map { CellViewModel(stuff: $0) } } + .map { viewModels in Effect.UpdateView(viewModels: viewModels) } // // Collect and perform side effects // .observeOn(UIScheduler()) .on( failed: { [weak self] error in - self?.performEffect(Effect.PresentAlert(error: error)) + self?.performEffect(Effect.PresentAlert(error: error)) }, next: { [weak self] effect in - self?.performEffect(effect) + self?.performEffect(effect) } ) - .start() -
    + .start()

    You can see more code here.

    My personal opinion is that these issues are balanced up by what you get out of diff --git a/blog/functor-applicative-monads-in-pictures/index.html b/blog/functor-applicative-monads-in-pictures/index.html index 7bf3e89..e164e72 100644 --- a/blog/functor-applicative-monads-in-pictures/index.html +++ b/blog/functor-applicative-monads-in-pictures/index.html @@ -2,10 +2,20 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    Swift Functors, Applicatives, and Monads in Pictures

    This is a translation of Functors, Applicatives, And Monads In Pictures from Haskell into Swift.

    +
    +

    I don't want to take any merit for writing this, I only went through the fun exercise of translating the code snippets in Swift.

    +
    +

    If you enjoy this post be sure to say thanks to the author of the original version: Aditya Bhargava, @_egonschiele on Twitter.

    +
    +

    Despite all the hype about it, Swift is not a functional language. This means that we need to write a bit of extra code to achieve the same results that language like Haskell have with built-in operators.

    +
    +

    You can find a Playground with all the code from the article on GitHub.

    +
    +

    Finally, don't worry if you find the content hard to grasp. I had to read the original version a number of times to wrap my head around it, plus a lot of mess around with the Swift code.

    Here’s a simple value:

    @@ -19,73 +29,64 @@

    Note: the pictures use Maybe (Just | None) from Haskell, which correspond to Swift's Optional .Some and .None.

    -
    enum Optional<T> {
    +
    enum Optional<T> {
       case None
       case Some(T)
    -}
    -
    +}

    In a second we will see how function application is different when something is a .Some(T) versus a .None. First let’s talk about Functors!

    Functors

    When a value is wrapped in a context, you can’t apply a normal function to it:

    This is where map comes in (fmap in Haskell). map is from the street, map is hip to contexts. map knows how to apply functions to values that are wrapped in a context. For example, suppose you want to apply a function that adds 3 to .Some(2). Use map:

    -
    func plusThree(addend: Int) -> Int {
    -  return addend + 3
    +
    func plusThree(addend: Int) -> Int {
    +  return addend + 3
     }
     
    -Optional.Some(2).map(plusThree)
    -// => .Some(5)
    -
    +Optional.Some(2).map(plusThree) +// => .Some(5)

    or with a simple syntax using Swift's autoclosure:

    -
    Optional.Some(2).map { $0 + 3 }
    -// => .Some(5)
    -
    +
    Optional.Some(2).map { $0 + 3 }
    +// => .Some(5)

    Bam! map shows us how it’s done! But how does map know how to apply the function?

    -

    Just what is a Functor, really?

    +

    Just what is a Functor, really?

    A Functor is any type that defines how map (fmap in Haskell) applies to it. Here’s how map works:

    So we can do this:

    -
    Optional.Some(2).map { $0 + 3 }
    -// => .Some(5)
    -
    +
    Optional.Some(2).map { $0 + 3 }
    +// => .Some(5)

    And map magically applies this function, because Optional is a Functor. It specifies how map applies to Somes and Nones:

    -
    func map<U>(f: T -> U) -> U? {
    +
    func map<U>(f: T -> U) -> U? {
       switch self {
       case .Some(let x): return f(x)
       case .None: return .None
    -}
    -
    +}

    Here’s what is happening behind the scenes when we write Optional.Some(2).map { $0 + 3 }:

    So then you’re like, alright map, please apply { $0 + 3 } to a .None?

    -
    Optional.None.map { $0 + 3 }
    -// => .None
    -
    +
    Optional.None.map { $0 + 3 }
    +// => .None

    Bill O’Reilly being totally ignorant about the Maybe functor

    Like Morpheus in the Matrix, map knows just what to do; you start with None, and you end up with None! map is zen. Now it makes sense why the Optional type exists. For example, here’s how you work with a database record in a language without Optional, like Ruby:

    -
    let post = Post.findByID(1)
    +
    let post = Post.findByID(1)
     if post != nil {
       return post.title
     } else {
       return nil
    -}
    -
    +}

    But in with Swift using the Optional functor:

    -
    findPost(1).map(getPostTitle)
    -
    +
    findPost(1).map(getPostTitle)

    If findPost(1) returns a post, we will get the title with getPostTitle. If it returns None, we will return None!

    We can even define an infix operator for map, <^> (<$> in Haskell), and do this instead:

    -
    infix operator <^> { associativity left }
    +
    infix operator <^> { associativity left }
     
    -func <^><T, U>(f: T -> U, a: T?) -> U? {
    -  return a.map(f)
    +func <^><T, U>(f: T -> U, a: T?) -> U? {
    +  return a.map(f)
     }
     
    -getPostTitle <^> findPost(1)
    -
    +getPostTitle <^> findPost(1)

    Note: we have to use <^> because <$> wouldn't compile.

    @@ -93,24 +94,22 @@

    Just what is a Functor, really?

    Arrays are functors too!

    Okay, okay, one last example: what happens when you apply a function to another function?

    -
    map({ $0 + 2 }, { $0 + 3 })
    -// => ???
    -
    +
    map({ $0 + 2 }, { $0 + 3 })
    +// => ???

    Here's a function:

    Here’s a function applied to another function:

    The result is just another function!

    -
    typealias IntFunction = Int -> Int
    +
    typealias IntFunction = Int -> Int
     
    -func map(f: IntFunction, _ g: IntFunction) -> IntFunction {
    +func map(f: IntFunction, _ g: IntFunction) -> IntFunction {
       return { x in f(g(x)) }
     }
     
    -let foo = map({ $0 + 2 }, { $0 + 3 })
    +let foo = map({ $0 + 2 }, { $0 + 3 })
     foo(10)
    -// => 15
    -
    +// => 15

    So functions are Functors too! When you use fmap on a function, you’re just doing function composition!

    Applicatives

    Applicatives take it to the next level. With an applicative, our values are wrapped in a context, just like Functors:

    @@ -118,71 +117,64 @@

    Applicatives

    But our functions are wrapped in a context too!

    Yeah. Let that sink in. Applicatives don’t kid around. Unlike Haskell, Swift doesn't have yet a built-in way to deal with Applicative. But it is very easy to add one! We can define an apply function for every type supporting Applicative, which knows how to apply a function wrapped in the context of the type to a value wrapped in the same context:

    -
    extension Optional {
    -  func apply<U>(f: (T -> U)?) -> U? {
    +
    extension Optional {
    +  func apply<U>(f: (T -> U)?) -> U? {
         switch f {
    -      case .Some(let someF): return self.map(someF)
    +      case .Some(let someF): return self.map(someF)
           case .None: return .None
         }
       }
     }
     
     extension Array {
    -  func apply<U>(fs: [Element -> U]) -> [U] {
    -    var result = [U]()
    +  func apply<U>(fs: [Element -> U]) -> [U] {
    +    var result = [U]()
           for f in fs {
    -        for element in self.map(f) {
    +        for element in self.map(f) {
               result.append(element)
             }
           }
           return result
         }
    -}
    -
    +}

    If both self and the function are .Some, then the function is applied to the unwrapped option, otherwise .None is returned. Also note that because the optional type is defined in terms of Optional<T> we only need to specify the generic type U in applys signature.

    We can also define <*>, to do the same thing:

    -
    infix operator <*> { associativity left }
    +
    infix operator <*> { associativity left }
     
    -func <*><T, U>(f: (T -> U)?, a: T?) -> U? {
    +func <*><T, U>(f: (T -> U)?, a: T?) -> U? {
       return a.apply(f)
     }
     
    -func <*><T, U>(f: [T -> U], a: [T]) -> [U] {
    +func <*><T, U>(f: [T -> U], a: [T]) -> [U] {
       return a.apply(f)
    -}
    -
    +}

    i.e:

    -
    Optional.Some({ $0 + 3 }) <*> Optional.Some(2)
    -// => 5
    -
    +
    Optional.Some({ $0 + 3 }) <*> Optional.Some(2)
    +// => 5

    Using <*> can lead to some interesting situations. For example:

    -
    
    -[ { $0 + 3 }, { $0 * 2 } ] <*> [1, 2, 3]
    -// => [ 4, 5, 6, 2, 4, 6 ]
    -
    +
    
    +[ { $0 + 3 }, { $0 * 2 } ] <*> [1, 2, 3]
    +// => [ 4, 5, 6, 2, 4, 6 ]

    Note: the original article now shows how Applicatives are more powerful than Functors in that they allow function application with multiple parameters. Again this is not feasible in vanilla Swift, but we can work around it by defining the function we want to handle in a curried way.

    Here’s something you can do with Applicatives that you can’t do with Functors. How do you apply a function that takes two arguments to two wrapped values?

    -
    func curriedAddition(a: Int)(b: Int) -> Int {
    -  return a + b
    +
    func curriedAddition(a: Int)(b: Int) -> Int {
    +  return a + b
     }
     
    -curriedAddition <^> Optional(2) <^> Optional(3)
    -// => COMPILER ERROR: Value of optional type '(Int -> Int)? not unwrapped; did you mean to use '!' or '??'
    -
    +curriedAddition <^> Optional(2) <^> Optional(3) +// => COMPILER ERROR: Value of optional type '(Int -> Int)? not unwrapped; did you mean to use '!' or '??'

    Applicatives:

    -
    curriedAddition <^> Optional(2) <*> Optional(3)
    -
    +
    curriedAddition <^> Optional(2) <*> Optional(3)

    Applicative pushes Functor aside. “Big boys can use functions with any number of arguments,” it says. “Armed with <^> and <*>, I can take any function that expects any number of unwrapped values. Then I pass it all wrapped values, and I get a wrapped value out! AHAHAHAHAH!”

    -
    func curriedTimes(a: Int)(b: Int) -> Int {
    -  return a * b
    +
    func curriedTimes(a: Int)(b: Int) -> Int {
    +  return a * b
     }
     
    -curriedTimes <^> Optional(5) <*> Optional(3)
    -
    +curriedTimes <^> Optional(5) <*> Optional(3)

    Monads

    How to learn about Monads:

      @@ -196,12 +188,11 @@

      Monads

      Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function | (>>= in Haskell) (pronounced “bind”) to do this.

      Monads have a function flatMap (liftM in Haskell) to do this. And we can define an infix operator >>- (>>= in Haskell) for it.

      -
      infix operator >>- { associativity left }
      +
      infix operator >>- { associativity left }
       
      -func >>-<T, U>(a: T?, f: T -> U?) -> U? {
      +func >>-<T, U>(a: T?, f: T -> U?) -> U? {
         return a.flatMap(f)
      -}
      -
      +}

      Note: Unlike <$>, >>= would compile. I decided to use >>- to be in line with the library Runes which provides "Infix operators for monadic functions in Swift", and it's hopefully going to become the standard for this sort of things.

      @@ -209,39 +200,35 @@

      Monads

      Just a monad hanging out

      Suppose half is a function that only works on even numbers:

      -
      func half(a: Int) -> Int? {
      -  return a % 2 == 0 ? a / 2 : .None
      -}
      -
      +
      func half(a: Int) -> Int? {
      +  return a % 2 == 0 ? a / 2 : .None
      +}

      What if we feed it a wrapped value?

      We need to use >>- (>>= in Haskell) to shove our wrapped value into the function. Here’s a photo of >>-:

      Here’s how it works:

      -
      Optional(3) >>- half
      +
      Optional(3) >>- half
       // .None
      -Optional(4) >>- half
      +Optional(4) >>- half
       // 2
      -Optional.None >>- half
      -// .None
      -
      +Optional.None >>- half +// .None

      What's happening inside? Let's look at >>-'s (>>= in Haskell) signature again:

      -
      // For Optional
      -func >>-<T, U>(a: T?, f: T -> U?) -> U?
      +
      // For Optional
      +func >>-<T, U>(a: T?, f: T -> U?) -> U?
       
       // For Array
      -func >>-<T, U>(a: [T], f: T -> [U]) -> [U]
      -
      +func >>-<T, U>(a: [T], f: T -> [U]) -> [U]

      So Optional is a Monad. Here it is in action with a .Some(3)!

      And if you pass in a .None it’s even simpler:

      You can also chain these calls:

      -
      Optional(20) >>- half >>- half >>- half
      -// => .None
      -
      +
      Optional(20) >>- half >>- half >>- half
      +// => .None

      NOte: the original article now describes Haskell's IO Monad. Swift doesn't have anything like that so this translation skips it.

      @@ -263,7 +250,11 @@

      Conclusion

      So, dear friend (I think we are friends by this point), I think we both agree that monads are easy and a SMART IDEA(tm). Now that you’ve wet your whistle on this guide, why not pull a Mel Gibson and grab the whole bottle. Check out LYAH’s section on Monads. There’s a lot of things I’ve glossed over because Miran does a great job going in-depth with this stuff.

      Thanks for reading through this article, if you have any feedback, suggestion, or error to report please tweet me @mokagio, or leave a comment below.

      +
      +

      If you want to play around with the code head over to GitHub and clone the Playground

      +
      +

      Once again, thanks Adit for the wonderful post, and for all the other great ones on the blog.

      Happy coding, and leave the codebase better than you found it

      diff --git a/blog/gitiquette/index.html b/blog/gitiquette/index.html index 269e958..efa6dbb 100644 --- a/blog/gitiquette/index.html +++ b/blog/gitiquette/index.html @@ -8,12 +8,11 @@

      In his article "Every line of code is always documented" Mislav Marohnić shows how by using git blame and git show he understood the reasons behind a cryptic line of code, and how important it was for the behaviour of the software.

      The repository is the history of the codebase. Some TV shows have a "previously on ...", that's the same when we read the git log after a pull, we get up to date with the latest developments of the project.

      What we don't want is a summary of the changes happened while we were away written like this:

      -
      Doesn't work!
      +
      Doesn't work!
       
       End of day commit
       
      -Checking this in because it's time for a beer
      -

      Equally bad is getting a single gianormous commit that adds a bug fix, three feature, and removes a bunch of unused files.

      +Checking this in because it's time for a beer

      Equally bad is getting a single gianormous commit that adds a bug fix, three feature, and removes a bunch of unused files.

      So here's some starting points to use when writing a project's Git-iquette.

      How to write a Git-iquette

      Short commits

      @@ -25,12 +24,11 @@

      Title and description

      Commit title style

      Given for granted that we all agree on the fact commits should be small and atomic, we need some rules on how to write the commit message.

      First of all, which verb to use? When reading a book it'd be confusing if the author kept changing the verbs tense, and the same stands for our git log. Choose a style:

      -
      Add awesome feature
      +
      Add awesome feature
       
       Adds awesome feature
       
      -Added awesome feature
      -

      They're all legit and reasonable, the important thing is to be consistent. My preference is to use imperative verbs, because it's the same thing git does in it's generated commit messages.

      +Added awesome feature

      They're all legit and reasonable, the important thing is to be consistent. My preference is to use imperative verbs, because it's the same thing git does in it's generated commit messages.

      Merge vs Rebase

      Merge vs rebase is an open discussion in the community, and both options have their pros and cons. Again the important thing is to be consistent, and to provide rules on when it's acceptable to merge instead of reabsing, or vice versa.

      Special workflows

      diff --git a/blog/gradient-backgrounds-studio/index.html b/blog/gradient-backgrounds-studio/index.html index ce25fc6..c69e66d 100644 --- a/blog/gradient-backgrounds-studio/index.html +++ b/blog/gradient-backgrounds-studio/index.html @@ -1,16 +1,17 @@ Gradient Backgrounds Studio: Lessons Learned | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      mokacoding

      unit and acceptance testing, automation, productivity

      Gradient Backgrounds Studio: Lessons Learned

      Gradient Backgrounds Studio Icon +

      At the beginning of March I released Gradient Backgrounds Studio, app born from a simple need my girlfriend had to add a gradient on top of an image to make a better background. It was one of those ideas that hit you and no matter if it's 1 o'clock in the morning you have to code them.

      Gradient Backgrounds Studio is a very simple app with a very simple implementation, but it gave me an excuse to play with some components of the framework I didn't know about.

      -

      CGGradientLayer

      +

      CGGradientLayer

      Guess what? The app is all about gradients. The first thing I had to learn was how to create and manipulate gradients.

      When it comes down to graphic staff Quartz is the framework we need to look at, and it has exactly the class we're looking for: CAGradientLayer.

      The CAGradientLayer class draws a color gradient over its background color, filling the shape of the layer (including rounded corners)

      Creating the layer is simple:

      -
      CAGradientLayer *gradientLayer = [CAGradientLayer layer];
      +
      CAGradientLayer *gradientLayer = [CAGradientLayer layer];
       gradientLayer.backgroundColor = [UIColor clearColor].CGColor;
       
       CGRect frame = CGRectMake(0, 0, 100, 100);
      @@ -19,11 +20,11 @@ 

      CGGradientLayer

      UIColor *endColor = [UIColor orangeColor]; gradientLayer.frame = frame; -gradientLayer.colors = @[ (id)starColor.CGColor, (id)endColor.CGColor ]; -
      -

      Simple CAGradientLayer

      +gradientLayer.colors = @[ (id)starColor.CGColor, (id)endColor.CGColor ];
      +Simple CAGradientLayer +

      There are cool things we can do, like having more colors and configuring how the gradient is rendered through its start and end point.

      -
      CAGradientLayer *gradientLayer = [CAGradientLayer layer];
      +
      CAGradientLayer *gradientLayer = [CAGradientLayer layer];
       gradientLayer.backgroundColor = [UIColor clearColor].CGColor;
       
       CGRect frame = CGRectMake(20, 20, 200, 200);
      @@ -35,14 +36,14 @@ 

      CGGradientLayer

      gradientLayer.frame = frame; gradientLayer.colors = @[ (id)startColor.CGColor, (id)middleColor.CGColor, (id)endColor.CGColor ]; -gradientLayer.endPoint = CGPointMake(1.0, 0.5); -
      -

      More customized CAGradientLayer

      +gradientLayer.endPoint = CGPointMake(1.0, 0.5);
      +More customized CAGradientLayer +

      UIImage from a gradient

      Gradient Backgrounds Studio generates an image out of the one you pick and the gradient you configure. So the next thing I had to do was merging those images.

      As with most things, there are multiple ways to achieve that result. The one I choose was to make an image out of the gradient layer, and then merge the two images into one.

      The code to do it may look mysterious, but I added comments to explain it.

      -
      CGRect frame = CGRectMake(20, 20, 200, 200);
      +
      CGRect frame = CGRectMake(20, 20, 200, 200);
       UIColor *startColor = [UIColor orangeColor];
       UIColor *endColor = [UIColor purpleColor];
       
      @@ -90,12 +91,11 @@ 

      UIImage from a gradient

      // CGGradientRelease(gradient); CGColorSpaceRelease(colorspace); -UIGraphicsEndImageContext(); -
      +UIGraphicsEndImageContext();

      If you have been reading other articles from my blog you know by now I'm not clever, the credits for this code goes to this question on SO.

      UIImage merging images

      Now that we have the image with the gradient we can merge it with the background image. The code to do that is simpler than the one above, but based on the same principle; create a context, draw in it, and get an UIImage from it with what's drawn in it.

      -
      UIImage *image = ...
      +
      UIImage *image = ...
       UIImage *gradientImage = ...
       CGRect size = ...
       
      @@ -106,16 +106,17 @@ 

      UIImage merging images

      [gradient drawInRect:imageRect]; UIImage *combinedImage = UIGraphicsGetImageFromCurrentImageContext(); -UIGraphicsEndImageContext(); -
      -

      Gradient and background images overlapped

      +UIGraphicsEndImageContext();
      +Gradient and background images overlapped +

      Note that the image is deformed, this is the original, the reason is that it's drawn in a rect that has a different ratio.

      Blurring: UIToolbar does the job

      The buttons of Gradient Backgrounds Studio are blurred because... iOS 7.

      -

      The round blurred buttons

      +The round blurred buttons +

      When I started reading about how to blur stuff I almost laughed at people suggesting to use UIToolbar, and looked into solutions like FXBlurView but the performance on live blurring were horrible. UIToolbar won it in the end.

      A funny thing I bumped into when making the buttons rounded is that if I used exactly half of the frame side to set the corner radius, as you would normally do, the view disappeared! The solution I found to that was to set the corner radius to almost half the frame side, where almost = 0.999.

      -
      CGRect frame = ...
      +
      CGRect frame = ...
       
       UIToolbar *blurredView = [[UIToolbar alloc] initWithFrame:frame];
       
      @@ -128,21 +129,19 @@ 

      Blurring: UIToolbar does t // this makes the toolbar invisible! o.O blurredView.layer.cornerRadius = frame.size.width / 2; // this works! -blurredView.layer.cornerRadius = frame.size.width / 2 * 0.999; -

      +blurredView.layer.cornerRadius = frame.size.width / 2 * 0.999;

      One other important thing is that the toolbar blurs the background of it's superview, keep this in mind in case you have overlapping view.

      Justify

      The final thing I'd like to share is how to justify the text in a UILabel. Despite the fact that the textAlignement property accepts NSTextAlignmentJustified as an option I wasn't able to make my multiline label justify just like that.

      I was finally able to achieve the result by using NSAttributedString and a NSMutableParagraphStyle.

      -
      NSString *message = ...
      +
      NSString *message = ...
       
       NSMutableParagraphStyle *justifiedParagraph = [[NSMutableParagraphStyle alloc] init];
       justifiedParagraph.alignment = NSTextAlignmentJustified;
       
       NSDictionary *attributes = @{ NSParagraphStyleAttributeName: justifiedParagraph, NSBaselineOffsetAttributeName: @0 };
       
      -NSAttributedString *justifiedMessage = [[NSAttributedString alloc] initWithString:message attributes:attributes];
      -
      +NSAttributedString *justifiedMessage = [[NSAttributedString alloc] initWithString:message attributes:attributes];

      Market-wise Gradient Backgrounds Studio is a failure, no more that an handful of downloads a day. But it was fun to make, and gave me a chance to learn new things, try out new designs patterns, and experiment. At the end of the day this is what matters, being able to always learn something new, and having fun!

      If you have better solutions for the problems I faced I'd really like to hear them please tweet me @mokagio

      diff --git a/blog/hacker-news-button/index.html b/blog/hacker-news-button/index.html index aa77e0b..392f59f 100644 --- a/blog/hacker-news-button/index.html +++ b/blog/hacker-news-button/index.html @@ -4,18 +4,17 @@

      Adding a share to Hacker News button to your blog is super easy thanks to the work of the guys at Segment.io.

      You can go to their Hacker News Button website to use a wizard to configure the button and get the code, or use the same one I use for mokacoding.

      Jade version:

      -
      script.
      -  !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
      +
      script.
      +  !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
       
       a.hn-button(href="https://news.ycombinator.com/submit",
      -  'data-title'="#{post.title}",
      -  'data-url'="#{post.url}",
      +  'data-title'="#{post.title}",
      +  'data-url'="#{post.url}",
         'data-count'="horizontal",
         'data-style'="twitter").
      -      Vote on Hacker News
      -
      + Vote on Hacker News

      HTML version:

      -
      <script>
      +
      <script>
         !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
       </script>
       
      @@ -26,8 +25,7 @@
         data-count="horizontal",
         data-style="twitter">
         Vote on Hacker News
      -</a>
      -
      +</a>

      There you go. If you found this post useful I would really appreciate if you could hit my Hacker News button, and the ones next to it too 😎.

      Happy coding, and leave the codebase better than you found it.

      diff --git a/blog/homebrew-in-ci-script/index.html b/blog/homebrew-in-ci-script/index.html index 67cb3a0..4ba582d 100644 --- a/blog/homebrew-in-ci-script/index.html +++ b/blog/homebrew-in-ci-script/index.html @@ -1,26 +1,20 @@ How to use Homebrew in CI | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      mokacoding

      unit and acceptance testing, automation, productivity

      How to use Homebrew in CI

      TL;DR

      If your CI has <tool_name> installed already:

      -
      brew update || brew update
      -brew outdated <tool_name> || brew upgrade <tool_name>
      -

      otherwise:

      -
      brew update || brew update
      -brew install <tool_name>
      -

      TS;WR

      +
      brew update || brew update
      +brew outdated <tool_name> || brew upgrade <tool_name>

      otherwise:

      +
      brew update || brew update
      +brew install <tool_name>

      TS;WR

      Ideally you would have everything your scripts depend upon checked in with the repo, but let's be honest, this is sometimes not practical.

      Some tools, for example xctool, can either be fetched as a git submodule, with all the problems coming with this approach, or via Homebrew in a simpler way.

      What the two lines at the start of the post do is downloading the latest version of <tool_name>. Let's look at them in more detail.

      -
      brew update
      -

      brew update will fetch the latest formulae, making sure that if you are running on the latest version of a tool, but your CI isn't, the latest version will be the one downloaded by the upgrade command later.

      -
      brew update || brew update
      -

      We are doing brew update || brew update because sometimes a formula might break the first run of the update command, but running it a second time will succeed. More on this issue here.

      +
      brew update

      brew update will fetch the latest formulae, making sure that if you are running on the latest version of a tool, but your CI isn't, the latest version will be the one downloaded by the upgrade command later.

      +
      brew update || brew update

      We are doing brew update || brew update because sometimes a formula might break the first run of the update command, but running it a second time will succeed. More on this issue here.

      || is the logical OR that we use in everyday programming as well. Every command line operation has a return code of 0 if everything went fine, non 0 otherwise. This means that if your execute command a || command b and command a returns fails returning something that is not 0 then command b is executed. If instead command a succeeds then the OR is already true, and command b will not run. This is quite a neat trick.

      Using || in the first line makes sure that if the first update fails, then a second attempt will be made.

      -
      brew install <tool_name>
      -

      The second line differs depending on whether your CI provider gives you a box with the tool you are after already installed. If that's not the case then you'll simply have to install it yourself with brew install, otherwise you will need to update it, or in Homebrew terminology upgrade.

      -
      brew outdated <tool_name> || brew upgrade <tool_name>
      -

      Since attempting to upgrade and up to date formula would result in a failure, you'll have to check if the local version is outdated. This can be done using the same || expedient. If brew outdated doesn't return 0 then it means that the tool is not up to date, and should be updates using brew upgrade.

      +
      brew install <tool_name>

      The second line differs depending on whether your CI provider gives you a box with the tool you are after already installed. If that's not the case then you'll simply have to install it yourself with brew install, otherwise you will need to update it, or in Homebrew terminology upgrade.

      +
      brew outdated <tool_name> || brew upgrade <tool_name>

      Since attempting to upgrade and up to date formula would result in a failure, you'll have to check if the local version is outdated. This can be done using the same || expedient. If brew outdated doesn't return 0 then it means that the tool is not up to date, and should be updates using brew upgrade.

      That's all folks. If you have any questions please do leave a comment below, or even better, reach me out on Twitter @mokagio.

      Happy coding, and leave the codebase better than you found it.

      diff --git a/blog/honesty-oriented-programming/index.html b/blog/honesty-oriented-programming/index.html index 08b4b40..a08020b 100644 --- a/blog/honesty-oriented-programming/index.html +++ b/blog/honesty-oriented-programming/index.html @@ -19,7 +19,7 @@

      That’s the goal, really. Simplify understanding. No surprises. Honest code.

      It's time to end the paradigms war, set aside language preferences, and focus on practicing Honesty-Oriented Programming instead.

      -
    +

    Want more of these posts?

    Subscribe to receive new posts in your inbox.

    diff --git a/blog/how-to-add-coauthors-to-a-git-commit/index.html b/blog/how-to-add-coauthors-to-a-git-commit/index.html index ccdf603..968cce1 100644 --- a/blog/how-to-add-coauthors-to-a-git-commit/index.html +++ b/blog/how-to-add-coauthors-to-a-git-commit/index.html @@ -2,8 +2,7 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    How to add co-authors to a Git commit

    When pairing on code, it's great to make commits that are marked as authored by both delevopers. There is a Git convention to do so, you can add the co-author(s) information in the commit message like this:

    -
    Co-authored-by: name <name@example.com>
    -

    GitHub and GitLab both support this syntax.

    +
    Co-authored-by: name <name@example.com>

    GitHub and GitLab both support this syntax.

    This is also handy when people open pull requests on your projects that you'd like to merge, but that need some extra work. In those cases, I often start from scratch to ensure atomic commits and be able to run as many interactive rebases as I need. To give credit to the original author, I use the co-author annotation in my commits.

    diff --git a/blog/how-to-always-run-latest-simulator-cli/index.html b/blog/how-to-always-run-latest-simulator-cli/index.html index 1301775..121d103 100644 --- a/blog/how-to-always-run-latest-simulator-cli/index.html +++ b/blog/how-to-always-run-latest-simulator-cli/index.html @@ -1,13 +1,12 @@ How to always use the latest Simulator with Xcodebuild | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to always use the latest Simulator with Xcodebuild

    Does your script running xcodebuild break every time you update Xcode because the Simulator version you were pointing at is not there anymore? No worries, there is a simple keyword you can use in the destination option to always run the most recent Simulator version.

    -
    xcrun xcodebuild \
    +
    xcrun xcodebuild \
       -workspace Bench.xcworkspace \
       -scheme BenchUITests \
       -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' \
       -sdk iphonesimulator \
    -  test
    -

    OS=latest does the trick 👍.

    + test

    OS=latest does the trick 👍.

    Happy coding, and leave the codebase better than you found it.

    diff --git a/blog/how-to-check-if-app-is-notarized/index.html b/blog/how-to-check-if-app-is-notarized/index.html index 52e20ed..918e83e 100644 --- a/blog/how-to-check-if-app-is-notarized/index.html +++ b/blog/how-to-check-if-app-is-notarized/index.html @@ -2,12 +2,11 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    How to check if macOS app is notarized

    Today I was wondering wheter a .app I uploaded to a third-party distribution provider was notarized due to an error I saw when launching it.

    Me being me, I naturally checked for a Terminal option, and I stumbled upon this post from the developers forum which suggests to use spctl:

    -
    spctl -a -t exec -v /path/to/notarised.app
    +
    spctl -a -t exec -v /path/to/notarised.app
     source=Notarized Developer ID
     
     spctl -a -t exec -v /path/to/not_notarised.app
    -source=Developer ID
    -

    The command is a "subsystem maintains and evaluates rules that determine whether the system allows the installation, execution, and other operations on files on the system."

    +source=Developer ID

    The command is a "subsystem maintains and evaluates rules that determine whether the system allows the installation, execution, and other operations on files on the system."

    -a requests an assessment on the given file, -t execute specifies the assessment is for code execution, -v makes the output verbose (the more vs you add the more verbose it gets, but I haven't seen any difference between -vv and -vvv, and the only really useful information was already part of -v)

    Something else I notices was that the .app in the .xcarchive stored in /Library/Developer/Xcode/Archives was not stapled despite having gon through notarization successfully.

    diff --git a/blog/how-to-check-if-ruby-array-contains-element/index.html b/blog/how-to-check-if-ruby-array-contains-element/index.html index 40f38ba..0df224d 100644 --- a/blog/how-to-check-if-ruby-array-contains-element/index.html +++ b/blog/how-to-check-if-ruby-array-contains-element/index.html @@ -1,14 +1,12 @@ How to check if array contains element with block in Ruby | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to check if array contains element with block in Ruby

    Sometimes, you want to know if an array contains one or more elements based on a test function.

    -
    [1,2,3,4].any? { |n| n > 2 }
    -# => true
    -
    +
    [1,2,3,4].any? { |n| n > 2 }
    +# => true

    If you need to get the first object that matches your criteria, you can use find.

    -
    [1,2,3,4].find { |n| n > 2 }
    -# => 3
    -
    -
    +
    [1,2,3,4].find { |n| n > 2 }
    +# => 3
    +

    Want more of these posts?

    Subscribe to receive new posts in your inbox.

    diff --git a/blog/how-to-choose-what-to-refactor/index.html b/blog/how-to-choose-what-to-refactor/index.html index 2825f45..359369b 100644 --- a/blog/how-to-choose-what-to-refactor/index.html +++ b/blog/how-to-choose-what-to-refactor/index.html @@ -18,7 +18,7 @@

    I'm not trying to discourage you from improving your codebase. "Leave the codebase better then you found it", right? I want you to stay focused on the job ahead though. Don't write code for code sake, there needs to be purpose behind what you do. You can collect all the other improvement ideas in your project's issue tracker or in a Trello board.

    Once you have implemented the changes identified with the focusing question, submit them in a dedicated PR. It will help your team review them, and ensure they are real refactors, that is, changes to the code implementation that don't affect its behaviour.

    Remember Kent Beck's advice: first make the change easy (warning: this might be hard), then make the easy change.

    -

    +
    diff --git a/blog/how-to-decouple-tests-from-frequently-changing-values/index.html b/blog/how-to-decouple-tests-from-frequently-changing-values/index.html index 012a470..643ea4a 100644 --- a/blog/how-to-decouple-tests-from-frequently-changing-values/index.html +++ b/blog/how-to-decouple-tests-from-frequently-changing-values/index.html @@ -1,7 +1,8 @@ How to decouple unit tests from values that change frequently | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to decouple unit tests from values that change frequently

    Justin Stanley started this interesting thread on Twitter:

    -

    + +

    The answer Justin got was to use literals, hard-coded strings for the expected output.

    Using literals in your tests makes them more straightforward. In Justin's case, it also hides the implementation detail of using R.swift so that if one day the code generation tooling will change, the tests won't need updating.

    @@ -9,73 +10,70 @@ a scenario in which using the R.swift generated value directly might be better is if the copy changes often and you don't want to have to update both localizations and tests every time.

    There is another option to avoid updating the tests for every little copy change, one which doesn't require surfacing implementation details: decouple the code making decisions on which value to use from the code defining the values.

    Let's imagine we're writing an app that speaks to the user the way a caring granny would: "it's sunny; you should wear a hat dear, so you don't get sunburned."

    -
    enum Weather {
    +
    enum Weather {
         case sunny, windy, rainy
     }
     
     class GrannyMessageTests: XCTestCase {
     
    -    func testWhenWeatherIsRainyMessageIsGetUmbrella() {
    +    func testWhenWeatherIsRainyMessageIsGetUmbrella() {
             XCTAssertEqual(getMessage(weather: .rainy), "Don't forget the umbrella")
         }
     
    -    func testWhenWeatherIsSunnyMessageIsGetHat() {
    +    func testWhenWeatherIsSunnyMessageIsGetHat() {
             XCTAssertEqual(getMessage(weather: .sunny), "You should wear a hat")
         }
     
    -    func testWhenWeatherIsWindyMessageIsGetJacket() {
    +    func testWhenWeatherIsWindyMessageIsGetJacket() {
             XCTAssertEqual(getMessage(weather: .windy), "Wear a jacket or you'll catch a cold")
         }
     }
     
    -func getMessage(weather: Weather) -> String {
    +func getMessage(weather: Weather) -> String {
         switch weather {
         case .rainy: return "Don't forget the umbrella"
         case .sunny: return "You should wear a hat"
         case .windy: return "Wear your jacket or you'll catch a cold"
         }
    -}
    -
    +}

    What's interesting about getMessage(weather:) is not the content of the message but whether it is the appropriate one for the weather condition; that's where the actual logic is. In a sense, the message content is the end product of choosing the right message state for the given input.

    We can split the code deciding what's the appropriate message from the code defining the different messages for each weather condition.

    -
    struct Messages {
    +
    struct Messages {
         let rainy: String
         let sunny: String
         let windy: String
     
    -    static let `default` = Messages(
    +    static let `default` = Messages(
             rainy: "Don't forget the umbrella",
             sunny: "You should wear a hat",
             windy: "Wear a jacket or you'll catch a cold"
         )
     }
     
    -func getMessage(weather: Weather, greetings: Messages = .default) -> String {
    +func getMessage(weather: Weather, greetings: Messages = .default) -> String {
         switch weather {
         case .rainy: return greetings.rainy
         case .sunny: return greetings.sunny
         case .windy: return greetings.windy
         }
    -}
    -
    +}

    The call site for getMessage(weather:) doesn't need to change, because we have extracted the existing messages in the default instance of Messages. In the tests, can now focus on the matching rather than the content of the messages by passing a dummy instance of Messages.

    -
    func testWhenWeatherIsRainyUsesCopyForRainyState() {
    -    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
    +
    func testWhenWeatherIsRainyUsesCopyForRainyState() {
    +    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
         XCTAssertEqual(getMessage(weather: .rainy, messages: dummyMessages), "rainy")
     }
     
    -func testWhenWeatherIsSunnyUsesCopyForSunnyState() {
    -    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
    +func testWhenWeatherIsSunnyUsesCopyForSunnyState() {
    +    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
         XCTAssertEqual(getMessage(weather: .sunny, messages: dummyMessages), "sunny")
     }
     
    -func testWhenWeatherIsWindyUsesCopyForWindyState() {
    -    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
    +func testWhenWeatherIsWindyUsesCopyForWindyState() {
    +    let dummyMessages = Messages(rainy: "rainy", sunny: "sunny", windy: "windy")
         XCTAssertEqual(getMessage(weather: .windy, messages: dummyMessages), "windy")
    -}
    -
    +}

    With the separation layer provided by Messages, when the copy changes, only the default instance needs to change, with no need to update the tests.

    Imagine if we had more inputs alongside the weather condition, like the time of the day and day of the week. In the afternoon the message could be "did you have lunch?", on a Thursday evening "have you got plans for the weekend?" diff --git a/blog/how-to-fix-fabric-startup-crash/index.html b/blog/how-to-fix-fabric-startup-crash/index.html index 3e4fda4..73a0b18 100644 --- a/blog/how-to-fix-fabric-startup-crash/index.html +++ b/blog/how-to-fix-fabric-startup-crash/index.html @@ -6,7 +6,7 @@

    Screenshot of the crash from within Xcode

    Then chances are you forgot to add the information Fabric needs to your app's Info.plist.

    Add this code to your Info.plist, clean and run again.

    -
    <key>Fabric</key>
    +
    <key>Fabric</key>
     <dict>
         <key>APIKey</key>
         <string>YOUR_API_KEY</string>
    @@ -19,8 +19,7 @@
                 <string>Crashlytics</string>
             </dict>
         </array>
    -</dict>
    -
    +</dict>

    The Fabric section of the Info.plist from the editor in Xcode

    TS;WR

    I recently spent a too long amount of time puzzled by the Fabric diff --git a/blog/how-to-install-xcode-cli-tools-without-gui/index.html b/blog/how-to-install-xcode-cli-tools-without-gui/index.html index b8cc339..595fe91 100644 --- a/blog/how-to-install-xcode-cli-tools-without-gui/index.html +++ b/blog/how-to-install-xcode-cli-tools-without-gui/index.html @@ -6,7 +6,7 @@

    Another option is to open a Terminal and type xcode-select --install.

    Both the options above have a flaw: they require a GUI. That is not optimal when trying to setup a VM in an automated way.

    In this AskDifferent answer a solution without GUI is proposed, and here you can find my spin on it:

    -
    #!/bin/bash
    +
    #!/bin/bash
     
     # See http://apple.stackexchange.com/questions/107307/how-can-i-install-the-command-line-tools-completely-from-the-command-line
     
    @@ -25,8 +25,7 @@
       softwareupdate -i "$PROD" -v;
     else
       echo "Xcode CLI tools OK"
    -fi
    -

    Easy peasy ☺️ I also made a gist with this, which you can download here.

    +fi

    Easy peasy ☺️ I also made a gist with this, which you can download here.

    Happy coding, and leave the codebase better than you found it

    diff --git a/blog/how-to-manually-generate-devise-reset-password-link/index.html b/blog/how-to-manually-generate-devise-reset-password-link/index.html index 04469fa..862b581 100644 --- a/blog/how-to-manually-generate-devise-reset-password-link/index.html +++ b/blog/how-to-manually-generate-devise-reset-password-link/index.html @@ -6,18 +6,14 @@

    I use Ruby on Rails for my backend, with as little custom logic as possible. Naturally, the authentication layer is taken care of by devise.

    To manually generate a reset password link using devise, the first step is to log in your server and launch the Rails console.

    -
    bundle exec rails c
    -

    Once in there, ask devise for a new reset password token. +

    bundle exec rails c

    Once in there, ask devise for a new reset password token. The call returns two values. The first is the raw token to use in the reset password URL query string, and the second is a hashed version of the token.

    -
    raw, hashed = Devise.token_generator.generate(User, :reset_password_token)
    -

    For the reset password to work, you need to associate the token to the user that will use it.

    -
    user = User.find_by(email: 'john.doe@mysaas.com')
    +
    raw, hashed = Devise.token_generator.generate(User, :reset_password_token)

    For the reset password to work, you need to associate the token to the user that will use it.

    +
    user = User.find_by(email: 'john.doe@mysaas.com')
     user.reset_password_token = hashed
     user.reset_password_sent_at = Time.now.utc
    -user.save
    -

    Finally, you can share the URL. Unless you have customized your routes, it'll look like this:

    -
    https://mysaas.com/users/password/edit?reset_password_token=raw
    -

    Full credits for these steps to this StackOverflow answer.

    +user.save

    Finally, you can share the URL. Unless you have customized your routes, it'll look like this:

    +
    https://mysaas.com/users/password/edit?reset_password_token=raw

    Full credits for these steps to this StackOverflow answer.

    Want more of these posts?

    diff --git a/blog/how-to-migrate-from-swiftui-to-uikit-life-cycle/index.html b/blog/how-to-migrate-from-swiftui-to-uikit-life-cycle/index.html index 07d4dc9..093631e 100644 --- a/blog/how-to-migrate-from-swiftui-to-uikit-life-cycle/index.html +++ b/blog/how-to-migrate-from-swiftui-to-uikit-life-cycle/index.html @@ -5,13 +5,13 @@ Still, the process is straightforward – once you know which files to update.

    You can find the sample project for this tutorial on GitHub. The commits history shows the diff for each step.

    -

    Step 0 - Extract root view from SwiftUI App

    +

    Step 0 - Extract root view from SwiftUI App

    All the layout configuration from your SwiftUI App will be lost once UIKit manages the life cycle. Before we begin, extract your current root view in a dedicated View, so you'll have all your existing UI ready to go after the conversion.

    For example, let's say your App looks like this:

    -
    struct ExampleApp: App {
    +
    struct ExampleApp: App {
     
    -    var body: some Scene {
    +    var body: some Scene {
             WindowGroup {
                 VStack(alignment: .center, spacing: 8) {
                     Text("Lorem")
    @@ -19,12 +19,11 @@ 

    Step 0 - Extract root view f } } } -} -

    +}

    To retain all the existing root view SwiftUI, extract the VStack into a dedicated View:

    -
    struct RootView: View {
    +
    struct RootView: View {
     
    -    var body: some View {
    +    var body: some View {
             VStack(alignment: .center, spacing: 8) {
                 Text("Lorem")
                 Text("Ipsum")
    @@ -34,70 +33,66 @@ 

    Step 0 - Extract root view f struct ExampleApp: App { - var body: some Scene { WindowGroup { RootView() } } -} -

    -

    Step 1 - Create a UIApplicationDelegate

    + var body: some Scene { WindowGroup { RootView() } } +}
    +

    Step 1 - Create a UIApplicationDelegate

    If you want to use the UIKit App Delegate life cycle, you'll need a UIApplicationDelegate to begin with. Here's a template for a minimal one you can use as your starting point:

    -
    // AppDelegate.swift
    +
    // AppDelegate.swift
     import UIKit
     
     class AppDelegate: UIResponder, UIApplicationDelegate {
     
    -    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    +    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
             return true
         }
     
         // MARK: - UISceneSession Lifecycle
     
    -    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    +    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
             return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
         }
    -}
    -
    +}

    If you build your app now, you won't see any difference because AppDelegate is unused.

    -

    Step 2 - Create a UIWindowSceneDelegate

    +

    Step 2 - Create a UIWindowSceneDelegate

    As per Apple's documentation, UIWindowSceneDelegate is where you "manage the life cycle of one instance of your app's user interface" and "receive notifications when its scene connects to the app, enters the foreground, and so on." It's where you instantiate your UI.

    Here's a template for a minimal one you can use as your starting point:

    -
    // SceneDelegate.swift
    +
    // SceneDelegate.swift
     import SwiftUI
     import UIKit
     
     class SceneDelegate: UIResponder, UIWindowSceneDelegate {
     
    -    var window: UIWindow?
    +    var window: UIWindow?
     
    -    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    -        guard let windowScene = scene as? UIWindowScene else { return }
    +    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    +        guard let windowScene = scene as? UIWindowScene else { return }
     
    -        let rootView = RootView()
    +        let rootView = RootView()
     
    -        let window = UIWindow(windowScene: windowScene)
    -        window.rootViewController = UIHostingController(rootView: rootView)
    -        self.window = window
    +        let window = UIWindow(windowScene: windowScene)
    +        window.rootViewController = UIHostingController(rootView: rootView)
    +        self.window = window
             window.makeKeyAndVisible()
         }
    -}
    -
    +}

    Like AppDelegate, this code is currently unused. We'll take care of this in the next step.

    -

    Step 3 - Update Info.plist UIApplicationSceneManifest & @main

    +

    Step 3 - Update Info.plist UIApplicationSceneManifest & @main

    With a UIApplicationDelegate and UIWindowSceneDelegate in place, it's finally time to tell Xcode to use them for the app's life cycle.

    Got in your app target "Info" section and update the "Application Scene Manifest" from this:

    screenshot of Application Scene Manifest for SwiftUI life cycle app

    To this:

    screenshot of Application Scene Manifest for UIKit App Delegate life cycle app

    If you're like me and like to work with text files instead of GUIs, you can edit the Info.plist directly. From this:

    -
    <key>UIApplicationSceneManifest</key>
    +
    <key>UIApplicationSceneManifest</key>
     <dict>
       <key>UIApplicationSupportsMultipleScenes</key>
       <true/>
    -</dict>
    -
    +</dict>

    To this:

    -
    <key>UIApplicationSceneManifest</key>
    +
    <key>UIApplicationSceneManifest</key>
     <dict>
       <key>UIApplicationSupportsMultipleScenes</key>
       <false/>
    @@ -113,18 +108,16 @@ 

    Step 3 - Upda </dict> </array> </dict> -</dict> -

    +</dict>

    Updating the Info.plist will get the OS to load the correct object at runtime, but the app is still configured to use the SwiftUI App implementation as the main entry point.

    You can make your new AppDelegate the app's entry point by moving the @main annotation to it.

    -
    // AppDelegate.swift
    +
    // AppDelegate.swift
     import UIKit
     
    -@main
    +@main
     class AppDelegate: UIResponder, UIApplicationDelegate {
         // ...
    -}
    -
    +}

    That's it.

    To verify the setup works, add a breakpoint to application(_:, didFinishLaunchingWithOptions:) or scene(_:, willConnectTo:, options:) and launch the app, the execution should pause there.

    Enjoy your UIKit App Delegate life cycle.

    diff --git a/blog/how-to-remove-duplication-from-swift-tests-with-helper-functions/index.html b/blog/how-to-remove-duplication-from-swift-tests-with-helper-functions/index.html index 3dbf87a..270fe52 100644 --- a/blog/how-to-remove-duplication-from-swift-tests-with-helper-functions/index.html +++ b/blog/how-to-remove-duplication-from-swift-tests-with-helper-functions/index.html @@ -3,103 +3,97 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to remove duplication from Swift tests with helper functions

    As your codebase grows so will your test suite. Production code is often refactored to stay simple to work with. The same care should be applied to the test code.

    Your unit test suite should be kept as tidy as your production code. Let's see how to remove duplication from tests using helper functions.

    Imagine you have a logging component and you want to ensure it logs the expected message for the given inputs to the provided storage layer.

    -
    func testLoggerLogsMessageWithPizza() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +
    func testLoggerLogsMessageWithPizza() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(Pizza())
     
       XCTAssert(storageMock.hasBeenLogged("Pizza is delicious"))
    -}
    -
    +}

    This code is also available on GitHub.

    Now, let's say in this system it's important to ensure the logger behaves as expected with inputs of type Pasta, Gelato, and Cappuccino.

    One way to do it is to duplicate the test for Pizza for each of those inputs.

    -
    func testLoggerLogsMessageWithPasta() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +
    func testLoggerLogsMessageWithPasta() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(Pasta())
     
       XCTAssert(storageMock.hasBeenLogged("There's nothing like home made pasta"))
     }
     
    -func testLoggerLogsMessageWithGelato() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +func testLoggerLogsMessageWithGelato() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(Gelato())
     
       XCTAssert(storageMock.hasBeenLogged("I love gelato any time of the year"))
     }
     
    -// etc...
    -
    +// etc...

    While there's nothing bad with a bit of duplication in the case of a mechanical behaviour like this one you could do worst than spending a bit of time to remove those duplicated test code.

    This is worth doing. You'll end up with code that is easier to read and change in the future. All with little time investment upfront. Bargain!

    Extracting expectation from tests

    Have a look at those three tests, you'll see they all look the same. The only differences are the input of the system under test and its expected behaviour.

    You can extract the test in a function of those parameters:

    -
    func expectLogger(toLog output: String, forInput input: Any) {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +
    func expectLogger(toLog output: String, forInput input: Any) {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(input)
     
    -  XCTAssert(storageMock.hasStored(output), "\"\(output)\" was not logged.")
    -}
    -
    + XCTAssert(storageMock.hasStored(output), "\"\(output)\" was not logged.") +}

    You can then write a single test in which to call the encapsulated expectation for each of the inputs you care about.

    -
    func testLoggerLogsMessageBehaviour() {
    +
    func testLoggerLogsMessageBehaviour() {
       expectLogger(toLog: "There's nothing like home made pasta", forInput: Pasta())
       expectLogger(toLog: "Pizza is awesome!", forInput: Pizza())
       expectLogger(toLog: "I love gelato any time of the year", forInput: Gelato())
       expectLogger(toLog: "Cappuccino warms and delights me", forInput: Cappuccino())
    -}
    -
    +}

    Nice. There's a little problem though. If the test fails Xcode will show the failure in the expectation function body, not at the call site.

    📸 Screenshot of a test failure reported in the helper function body

    Even worse if you have more than one failure, it requires you to click on the message to expand it an learn which tests failed.

    📸 Screenshot of multiple test failures reported in the helper function body

    When writing unit tests the easier you make failures to be discovered the better off you'll be.

    -

    Accurate failures with #file and #line

    +

    Accurate failures with #file and #line

    Not having duplicated code is great, but not knowing which of the expectLogger(toLog:, forInput:) calls failed makes understanding -and eventually fixing- the test failures harder.

    Wouldn't it be great if the failures were reported at the call site of the test helper method?

    The documentation for the XCTAsser- family of methods shows how to do it. Xcode's code completion when calling an XCTAssert- method shows this:

    📸 Screenshot of multiple test failures reported in the helper function body

    There are other two input parameters the functions can accept. They don't come up in the autocompletion view because they have a default value.

    -
    func XCTAssert(
    -  _ expression: @autoclosure () throws -> Bool,
    -  _ message: @autoclosure () -> String = default,
    -  file: StaticString = #file,
    -  line: UInt = #line
    -)
    -
    +
    func XCTAssert(
    +  _ expression: @autoclosure () throws -> Bool,
    +  _ message: @autoclosure () -> String = default,
    +  file: StaticString = #file,
    +  line: UInt = #line
    +)

    The documentation reads:

    file The file in which failure occurred. Defaults to the file name of the test case in which this function was called.

    line The line number on which failure occurred. Defaults to the line number on which this function was called.

    Armed with this knowledge you can pass the call site details to the test helper, so it can relay that information when calling an XCTAssert- or XCTFail.

    -
    private func expectLogger(
    -  toLog output: String,
    -  forInput input: Any,
    -  file: StaticString = #file,
    -  line: UInt = #line
    -) {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock)
    +
    private func expectLogger(
    +  toLog output: String,
    +  forInput input: Any,
    +  file: StaticString = #file,
    +  line: UInt = #line
    +) {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock)
     
       logger.log(input)
     
       XCTAssert(
         storageMock.hasStored(output),
    -    "\"\(output)\" was not logged.",
    +    "\"\(output)\" was not logged.",
         file: file,
         line: line
       )
    -}
    -
    +}

    Now the test failures are reported where expectLogger(toLog:, forInput:) is called. This makes it clearer where to start looking for the issue.

    📸 Screenshot of multiple test failures reported in the helper function body


    diff --git a/blog/how-to-reverse-a-file-in-the-terminal/index.html b/blog/how-to-reverse-a-file-in-the-terminal/index.html index ea934cc..75b4985 100644 --- a/blog/how-to-reverse-a-file-in-the-terminal/index.html +++ b/blog/how-to-reverse-a-file-in-the-terminal/index.html @@ -3,7 +3,7 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to reverse a file in the terminal

    Today, I used grep to filter the git log output to only get the changes made on a certain value holding the version number for an app.

    The git log output is sorted newest to oldest, but I was interested in how the changes progressed, that is, oldest to newest.

    You can use tac to reverse a file or the standard input.

    -
    $ cat file.txt
    +
    $ cat file.txt
     a
     b
     c
    @@ -11,13 +11,11 @@
     $ tac file.txt
     c
     b
    -a
    -

    Here's how it works when used with a pipe.

    -
    echo "a\nb\nc" | tac
    +a

    Here's how it works when used with a pipe.

    +
    echo "a\nb\nc" | tac
     c
     b
    -a
    -
    +a

    Want more of these posts?

    Subscribe to receive new posts in your inbox.

    diff --git a/blog/how-to-set-default-values-in-swift-compiler-generate-init/index.html b/blog/how-to-set-default-values-in-swift-compiler-generate-init/index.html index 54d236c..471efe3 100644 --- a/blog/how-to-set-default-values-in-swift-compiler-generate-init/index.html +++ b/blog/how-to-set-default-values-in-swift-compiler-generate-init/index.html @@ -5,39 +5,35 @@

    One of the many cool Swift compiler features that save development time is the compiler-generate initializer for structs. Unless you explicitly define an init method, the compiler will generate one for you based on the properties of your struct.

    Consider this Pizza struct:

    -
    struct Pizza {
    +
    struct Pizza {
     
       let name: String
       let ingredients: [Ingredient]
    -}
    -
    +}

    The compiler will generate an init method for it with the parameters in the same order as the properties definition.

    -
    let pizza = Pizza(name: "Margherita", ingredients: [.tomatoSauce, .mozzarella])
    -

    Now, imagine we want to add extras to our Pizza. +

    let pizza = Pizza(name: "Margherita", ingredients: [.tomatoSauce, .mozzarella])

    Now, imagine we want to add extras to our Pizza. By default, a pizza should not have extras, but consumers can decide to add some – I like my Margherita extra cheesy, so I always ask for double mozzarella.

    One way to do that is to define an init with the default value:

    -
    struct Pizza {
    +
    struct Pizza {
     
       let name: String
       let ingredients: [Ingredient]
       let extra: [Ingredient]
     
    -  init(name: String, ingredients: [Ingredient], extras: [Ingredient] = []) {
    -    self.name = name
    -    self.ingredients = ingredients
    -    self.extras = extras
    +  init(name: String, ingredients: [Ingredient], extras: [Ingredient] = []) {
    +    self.name = name
    +    self.ingredients = ingredients
    +    self.extras = extras
       }
    -}
    -
    +}

    Unfortunately, by providing our own init, we take responsibility of updating it every time the shape of the struct changes.

    A different way to have a default value while also leveraging the compiler-generated init is to set it as part of the property definition.

    -
    struct Pizza {
    +
    struct Pizza {
     
       let name: String
       let ingredients: [Ingredient]
    -  private(set) var extras: [Ingredient] = []
    -}
    -
    + private(set) var extras: [Ingredient] = [] +}

    It never occurred to me to do this because I try to keep my code as immutable as I can; using a var leaves the door open for mutations.

    On the other hand, the private(set) access control mitigates the mutable state risk: only the code internal to the struct can change the value of extras.

    That seems like a good tradeoff. diff --git a/blog/how-to-split-decision-and-action-logic-with-the-swift-type-system/index.html b/blog/how-to-split-decision-and-action-logic-with-the-swift-type-system/index.html index b723089..215e681 100644 --- a/blog/how-to-split-decision-and-action-logic-with-the-swift-type-system/index.html +++ b/blog/how-to-split-decision-and-action-logic-with-the-swift-type-system/index.html @@ -6,38 +6,36 @@

    Still, tests are a feedback on how our software is designed. Having to do a lot of work to test a component is usually a signal the its design can be improved.

    Split decision logic from action logic

    Let's pick up the test for the Logger component of the test helper example.

    -
    func testLoggerLogsMessageWithPizza() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +
    func testLoggerLogsMessageWithPizza() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(Pizza())
     
       XCTAssert(storageMock.hasBeenLogged("Pizza is delicious")
    -}
    -
    +}

    The test is verifying calling log(_:) writes the expected value using the storage component given to Logger.

    You could argue there are two behaviours being tested here. The act of logging, and the decision on what to log.

    A good rule of thumb to build systems simple to work with is to have components do only one thing. Let's rewrite Logger so the only thing it does is logging, leaving the responsibility to decide what to log to some other component.

    -
    class Logger {
    +
    class Logger {
     
    -  let transformation: (Any) -> String
    +  let transformation: (Any) -> String
       let storage: StorageService
     
    -  init(transformation: (Any) -> String, storage: StorageService) {
    -    self.transformation = transformation
    -    self.storage = storage
    +  init(transformation: (Any) -> String, storage: StorageService) {
    +    self.transformation = transformation
    +    self.storage = storage
       }
     
    -  func log(_ input: Any) {
    +  func log(_ input: Any) {
         storage.perist(transformation(input))
       }
    -}
    -
    +}

    The new Logger expects an input (Any) -> String function to use to get the String to log for the given input.

    The only thing to do to test Logger is to pass an arbitrary transformation and verify it uses it properly1.

    -
    func testLoggerLogsMessageBehaviour() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(
    +
    func testLoggerLogsMessageBehaviour() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(
         transformation: { return "something" },
         storage: storageMock()
       )
    @@ -45,26 +43,25 @@ 

    Split decision logic from action logger.log("any input") XCTAssert(storageMock.hasBeenLogged("something")) -} -

    +}

    Notice how Logger is now not only simpler to test but also simpler to maintain. Logger itself needs to change only if the mechanic of logging changes, e.g. from one storage to two. Adding support for a new log input can be done in the transformation function.

    Ease of testability and maintainability go hand in hand.

    Splitting decision from action using a Swift protocol

    Splitting the code performing the action from the one making the decision on what the output should be is neat, simplifies the testing, and makes the design of our component easier to scale.

    Speaking of scaling, if we expect to have many different types of input being logged with our Logger we'll also see the transformation function growing in length and complexity.

    -
    func extractLogMessage(fromInput input: Any) -> String {
    +
    func extractLogMessage(fromInput input: Any) -> String {
       switch input {
       case is Pasta:
         return "There's nothing like home made pasta"
       case is Pizza:
         return "Pizza is awesome!"
       // more and more cases here...
    -  case _:
    -    return "\(input)"
    +  case _:
    +    return "\(input)"
       }
     }
     
    -func testTransformation() {
    +func testTransformation() {
       XCTAssertEqual(
         extractLogMessage(fromInput: Pasta()), "There's nothing like home made pasta"
       )
    @@ -72,37 +69,34 @@ 

    Splitting decisio extractLogMessage(fromInput: Pizza()), "Pizza is awesome!" ) // more and more of the assertions like the ones above here... -} -

    +}

    We have moved the long test from Logger where it originally was in the first example to transformation.

    Moreover, the fact it accepts Any as its input leaves the door open for future developers using log(_:) without adding support for the input type to the transformation.

    Swift offers a way to clean all this up by using a protocol.

    We can make log(_:) accept inputs conforming to a protocol describing the ability of generating a log message.

    -
    protocol Loggable {
    +
    protocol Loggable {
       var message: String { get }
     }
     
     class Logger {
     
    -  func log(_ input: Loggable) {
    +  func log(_ input: Loggable) {
         storage.persist(input.message)
       }
    -}
    -
    +}

    Now our test for Logger can become

    -
    func testLoggerLogsMessageBehaviour() {
    -  let storageMock = StorageMock()
    -  let logger = Logger(storage: storageMock())
    +
    func testLoggerLogsMessageBehaviour() {
    +  let storageMock = StorageMock()
    +  let logger = Logger(storage: storageMock())
     
       logger.log(DummyLoggable())
     
    -  expect(storageMock.hasBeenLogged("a message")) == true
    +  expect(storageMock.hasBeenLogged("a message")) == true
     }
     
     struct DummyLoggable: Loggable {
       var message { "a message" }
    -}
    -
    +}

    This approach decentralizes the knowledge of the input-output conversion by encapsulating it in a protocol.

    Using a protocol also ensures the compiler will enforce that any input provided to log(_:) has logic to generate its message because it needs to conform to Loggable.

    As Manuel Chakravarty argues in his excellent talk A Type is Worth a Thousand Tests we should leverage the type system and the compiler whenever possible. We can forget to write a test, or write a buggy test resulting in a false positive. The compiler is harder to fool.

    @@ -111,7 +105,7 @@

    Splitting decisio

    Each is valuable, and each comes with different trade-offs. That's the beauty of software development, multiple solutions for the same problem, which one to pick is up to us.

    If you ask my opinion, when using a language like Swift relying on the type system is your best option.

    Have you got other approaches to suggest to remove duplication in this example? Or have you got tests with duplication and would like to chat about ways to remove it? Leave a comment below, get in touch on Twitter at @mokagio, or write to gio@mokacoding.com.

    -

    1: One could argue the test in the example could tricked by making the log(:) body return "something", the value returned by the test transformation function. While that's true it leads us into a spiral of more and more refined tests which might eventually turn into the need for generative testing. Let's just assume no one is trying to intentionally trick the tests and compromise using this single simpler one.

    +

    1: One could argue the test in the example could tricked by making the `log(:)` body return `"something"`, the value returned by the test `transformation` function. While that's true it leads us into a spiral of more and more refined tests which might eventually turn into the need for generative testing. Let's just assume no one is trying to intentionally trick the tests and compromise using this single simpler one.

    Want more of these posts?

    diff --git a/blog/how-to-test-async-await-code-in-swift/index.html b/blog/how-to-test-async-await-code-in-swift/index.html index 39d5e61..c26f1ec 100644 --- a/blog/how-to-test-async-await-code-in-swift/index.html +++ b/blog/how-to-test-async-await-code-in-swift/index.html @@ -8,61 +8,57 @@ Swift now supports the async/await pattern, first introduced in F# in the late 2000s and then adopted in other languages including JavaScript, TypeScript, and Rust.

    This is a huge improvement for developers and it will help describe the code in a way that is easier to reason about and safer to update.

    Let's look at how to write unit tests for code using async await in Xcode 13 with XCTest.

    -

    How to unit test async/await code

    +

    How to unit test async/await code

    I'm a sucker for culinary examples, my book Test-Driven Development in Swift uses a restaurant menu ordering app to teach TDD, and I was delighted to see Apple introduce async/await in the Xcode 13.0 beta 1 release notes using asynchronous functions to prepare dinner. Let's stick with Apple's examples and write a test for the asynchronous chopVegetables method to ensure the vegetables are properly chopped by checking that the returning array has more than one element.

    Because async/await is a feature at the Swift language level, to test an async function we can use the same approach we'd use to consume that code in production: call it with await.

    -
    func chopVegetables() async throws -> [Vegetable]
    +
    func chopVegetables() async throws -> [Vegetable]
     
    -func testChoppingVegetablesReturnsManyVegetables() async throws {
    -    let vegetables = try await chopVegetables()
    -    XCTAssertGreaterThan(vegetables.count, 1)
    -}
    -
    +func testChoppingVegetablesReturnsManyVegetables() async throws { + let vegetables = try await chopVegetables() + XCTAssertGreaterThan(vegetables.count, 1) +}

    That's it.

    To appreciate how neater this is than the approach we used before the introduction of async await, let me show you the same test but for a chopVegetables version using callbacks and Result.

    -
    func chopVegetables(completion: @escaping (Result<[Vegetable], CookingError>) -> Void) { ... }
    +
    func chopVegetables(completion: @escaping (Result<[Vegetable], CookingError>) -> Void) { ... }
     
    -func testChoppingVegetablesReturnsManyVegetables() {
    -    let expectation = XCTestExpectation(description: "Chops the vegetables")
    +func testChoppingVegetablesReturnsManyVegetables() {
    +    let expectation = XCTestExpectation(description: "Chops the vegetables")
     
         chopVegetables { result in
    -        guard case .success(let vegetables) = result else { return }
    -        XCTAssertGreaterThan(vegetables.count, 1)
    +        guard case .success(let vegetables) = result else { return }
    +        XCTAssertGreaterThan(vegetables.count, 1)
             expectation.fulfill()
         }
     
    -    wait(for: [expectation], timeout: 1)
    -}
    -
    + wait(for: [expectation], timeout: 1) +}

    The contrast is striking. asycn/await is certainly a welcome change on the testing side of the codebase, too!

    -

    How do async/await tests fail?

    +

    How do async/await tests fail?

    If the code we're awaiting throws, the test will fail like any other test that throws.

    screenshot of test failure

    If you want to have more refined error handling, you can wrap the try await call in a do catch.

    -
    func testChoppingVegetablesReturnsManyVegetables() async {
    +
    func testChoppingVegetablesReturnsManyVegetables() async {
         do {
    -        let vegetables = try await chopVegetables(using: Knife(sharpness: .low))
    -        XCTAssertGreaterThan(vegetables.count, 1)
    +        let vegetables = try await chopVegetables(using: Knife(sharpness: .low))
    +        XCTAssertGreaterThan(vegetables.count, 1)
         } catch {
    -        XCTFail("Expected chopped vegetables, but failed \(error).")
    +        XCTFail("Expected chopped vegetables, but failed \(error).")
         }
    -}
    -
    +}

    Using do catch, you can generate more informative failures messages, which will help you triage and fix failed tests in the future.

    -

    How to test the failure path in async/await code

    +

    How to test the failure path in async/await code

    You can use the do catch approach to verify how async/await code fails.

    Let's extend the Apple examples by adding a Knife parameter to the chopping function and expecting an error to be thrown if the knife is blunt.

    -
    func testChoppingVegetablesThrowsWhenKnifeBlunt() {
    +
    func testChoppingVegetablesThrowsWhenKnifeBlunt() {
         do {
    -        _ = try await chopVegetables(using: Knife(sharpness: .low))
    +        _ = try await chopVegetables(using: Knife(sharpness: .low))
             XCTFail("Expected to throw while awaiting, but succeeded")
         } catch {
    -        XCTAssertEqual(error as? CookingError, .knifeTooBlunt)
    +        XCTAssertEqual(error as? CookingError, .knifeTooBlunt)
         }
    -}
    -
    +}

    Unfortunately the XCTAssertThorwsError and the other assertion APIs don't support concurrency yet, so do catch is the only option to test the error path of async code.

    screenshot of unsupported concurrency error


    diff --git a/blog/how-to-test-swiftui-apps/index.html b/blog/how-to-test-swiftui-apps/index.html new file mode 100644 index 0000000..2bb76f1 --- /dev/null +++ b/blog/how-to-test-swiftui-apps/index.html @@ -0,0 +1,197 @@ +How to write unit tests for SwiftUI apps | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to write unit tests for SwiftUI apps

    How do you write unit tests for a SwiftUI application?

    +

    SwiftUI, with its declarative approach to UI development and its opaque types, doesn't lend itself to writing unit tests. +Are UI and snapshot tests our only option? +Should we generate multiple Previews for every behavior permutation of our views?

    +

    The answer is simpler and doesn't require any extra tool, only good software design:

    +

    To test SwiftUI applications, don't test SwiftUI code.

    +

    Let me show you how to write unit tests for the actual logic behind a SwiftUI app by decoupling layout declaration from content generation.

    +

    The template Xcode uses to generate a SwiftUI app for us includes a View printing the classic "Hello, world!" message.

    +
    import SwiftUI
    +
    +struct ContentView: View {
    +    var body: some View {
    +        Text("Hello, world!")
    +            .padding()
    +    }
    +}
    +
    +struct ContentView_Previews: PreviewProvider {
    +    static var previews: some View {
    +        ContentView()
    +    }
    +}
    +

    Let's make it a bit more interesting by adding a subject. +The app should say "Hello, <user>!" when given a user and fallback to "Hello, world!" otherwise.

    +

    Quick & dirty implementation: All in the view

    +

    Given the template code, a natural approach to implement this new behavior would be to write the code inline in the ContentView body and use different Previews to verify the behavior.

    +
    struct ContentView: View {
    +
    +    let userName: String?
    +
    +    var body: some View {
    +        if let userName = userName {
    +            Text("Hello, \(userName)!").padding()
    +        } else {
    +            Text("Hello, world!").padding()
    +        }
    +    }
    +}
    +
    +struct ContentView_Previews: PreviewProvider {
    +    static var previews: some View {
    +        ContentView(userName: "Ada")
    +        ContentView(userName: .none)
    +    }
    +}
    +

    This approach gets the job done in a trivial scenario such as this hello world example but doesn't scale well because of two issues.

    +

    From a practical point of view, both our brain and the screen size limit how effective Previews are to verify behavior. +As you can see in the image below, two different previews make the canvas crowded and the details hard to see. +If we were to add more, they'd end up too small to see, and we'd have to zoom in a scroll through the canvas to check all of them.

    +

    image showing the two previews

    +

    Moreover, using Previews relies on our eyes and brain to verify the behavior. +Unfortunately, this biological hardware of ours is slow and bug-ridden. +It is a suboptimal tool to verify the code's behavior.

    +

    There are also software designs considerations. +In a small dumb view like the ContentView from the Xcode template, mixing content generation logic with the layout declaration doesn't affect maintainability that much. +But, as your app grows, mixing layout with content code will make it increasingly difficult to make changes to your views because of the amount of code you'll have to navigate before being able to find what you are looking for.

    +

    SwiftUI views are for declaring layout, not implementing content generation.

    +

    The approach I advocate for is to use automated unit tests to verify the code's behavior. +Automated tests are faster than our eyes and more reliable than our easy to distract brains. +To write a test for the content generation logic, it's necessary to extract it in a way that makes it easier to call. +The need to write tests nudges us towards a design with a better separation of concerns.

    +

    The Test-Driven approach

    +

    As I argue in my book Test-Driven Development in Swift, if you want to add tests to your code, particularly to new code, writing the tests first is the best approach. +Writing tests first puts a helpful pressure on the design, nudging you towards implementations made up of loosely coupled, highly cohesive pieces.

    +

    Let's see how to apply TDD to implementing the new hello world behavior.

    +

    Step 1: Test List

    +

    The first step is to write a Test List, a list of the different behaviors our hello world implementation should have.

    +
    class HelloWorldTests: XCTestCase {
    +
    +    func testHelloWorldWithNoNameReturnsHelloWorld() {}
    +
    +    func testHellowWorldWithNameReturnsHelloUser() {}
    +}
    +
    +

    Writing a Test List instead of jumping headfirst into coding gives us a 30,000 feet view of the work ahead and lets us be strategic with where to start.

    +

    Test-Driven Development aims to maximize learning through fast, continuous feedback. +Each iteration of writing a test, seeing it fail, and finding the code that makes it pass teaches us something about the system we're building.

    +

    With all the scenarios to test in front of you, you can choose the one that can teach you something the fastest.

    +

    Step 2: Test the simplest behavior

    +

    In _Test-Driven Development: By Example, Kent Beck recommends starting with a test you know you can make pass. +By starting from a low-hanging fruit, you can do the work of putting in place the bulk of the coding structure without the overhead of complex behavior implementation.

    +

    In our hello world Test List, I feel like the simplest test to implement is for the fallback behavior because it doesn't require any string interpolation to generate the return value.

    +

    Let's build an empty version of the hello world, just enough to call in the test without the compiler complaining at us, then use it to write the test.

    +
    func hello(name: String?) -> String { "" }
    +
    func testHelloWorldWithNoNameReturnsHelloWorld() {
    +    XCTAssertEqual(hello(name: .none), "Hello, world!")
    +}
    +

    If you run the test now, it will fail:

    +
    XCTAssertEqual failed: ("") is not equal to ("Hello, world!")

    We can make the test pass by returning the value the test expects.

    +
    func hello(name: String?) -> String { "Hello, world!" }
    +

    With the test now passing, we have two options in front of us. +We could refactor the implementation to add a check to return the fallback message only if the input is nil, or leave it untouched and move with the next test.

    +

    I choose to move on with the next test, confident that it will show us when to add extra logic in the implementation.

    +

    Step 3: Test remaining behavior

    +
    func testHellowWorldWithNameReturnsHelloUser() {
    +    XCTAssertEqual(hello(name: "Ada"), "Hello, Ada!")
    +}
    +

    The new tests, unsurprisingly, fails:

    +
    XCTAssertEqual failed: ("Hello, world!") is not equal to ("Hello, Ada!")

    To make it pass, we need to write the conditional logic that inspects the input value.

    +
    func hello(name: String?) -> String {
    +  if let name = name {
    +      return "Hello, \(name)!"
    +  } else {
    +      return "Hello, world!"
    +  }
    +}
    +

    Both tests pass. +Let's pat ourselves on the back, take a deep breath, and ask, "Is there any improvement we can make to the code?"

    +

    Step 4: Refactor

    +

    Unit tests make it easier to change code because they allow you to verify its behavior faster and more thoroughly than running the app manually.

    +

    In fact, at the core of the Test-Driven Development workflow, there is a refactoring step. +First, you write a test, then you make it pass with the first solution that comes to mind, and, finally, you can take a step back and improve your code. +The tests make the refactoring step possible because they give you the confidence to change your code as many times as you like, always knowing they will verify its correct behavior.

    +

    When looking at my implementation, something that catches my eyes is that there's a bit of duplication in the string structure. +Just for fun, let's apply DRY and remove it:

    +
    func hello(name: String?) -> String {
    +    let receiver: String
    +    if let name = name {
    +        receiver = name
    +    } else {
    +        receiver = "world"
    +    }
    +
    +    return "Hello, \(receiver)!"
    +}
    +

    The tests still pass after this change, which shows us it was correct.

    +

    I'm still unhappy with this implementation. +It looks clunky, unnecessarily long.

    +

    The fast feedback loop from the tests makes it cheap to keep experimenting with different code versions.

    +

    Here's the one I settled for:

    +
    func hello(name: String?) -> String {
    +    "Hello, \(name.map { $0 } ?? "world")!"
    +}
    +

    Step 5: Inject in the view

    +

    To finish our work, we need to make the app UI use the new code. +Integrating hello(name:) in the UI merely requires calling it from within ContentView's body.

    +
    +

    Unlike the quick and dirty implementation that didn't rely on tests, we don't need to generate two Previews to verify the conditional hello world behavior because that's already done in the unit tests. +If that seems like a marginal gain, it's only because of how trivial this example is. +Take a moment to picture a real-world application, where you have a combinatorial explosion of possible scenarios to render, and imagine if your only tool to verify them was to manually add and maintain multiple previews. +To me, it's clear how faster and easier to work with delegating the responsibility to verify code's behavior to automated tests is.

    +

    Conclusion

    +

    If all code was as straightforward to test as the hello world algorithm, and if all apps were as simple as the updated template app we worked on in this tutorial, we wouldn't need Test-Driven Development — but our jobs would be pretty dull.

    +

    In this tutorial, I worked with trivial code to give you an end-to-end overview of the TDD workflow and how it fits in SwiftUI application development. +In the real world, you'll be working with much more complex views, need to implement behavior with more facets, and navigate apps made of a multitude of screens. +It's then that Test-Driven Development becomes a productivity multiplier because it will let you work in isolation and verify every change without spinning up the whole application and go through the motions of its UI.

    +

    If you enjoyed this introduction to TDD with SwiftUI, you'll like my book Test-Driven Development in Swift where we build a real-world application using TDD, SwiftUI, and Combine.

    +
    +
    +

    Want more of these posts?

    +

    Subscribe to receive new posts in your inbox.

    +
    +

    + + +
    +
    + +
    + +
    \ No newline at end of file diff --git a/blog/how-to-verify-ssh-key-password/index.html b/blog/how-to-verify-ssh-key-password/index.html index 8e7111e..0b35f0d 100644 --- a/blog/how-to-verify-ssh-key-password/index.html +++ b/blog/how-to-verify-ssh-key-password/index.html @@ -5,8 +5,7 @@

    There were no useful logs so I wondered if I used the wrong password. I had the password for that key in 1Password (after years of creating SSH keys with fancy passwords only to forget about them), so I was positive the it was correct, but there was a chance I was using the wrong key file.

    To verify my password, I used this command:

    -
    ssh-keygen -y -f /path/to/ssh_key
    -

    The -y option "will read a private OpenSSH format file and print an OpenSSH public key to stdout". +

    ssh-keygen -y -f /path/to/ssh_key

    The -y option "will read a private OpenSSH format file and print an OpenSSH public key to stdout". The -f option specifies the path to the private key.

    If the private key is password protected, ssh-keygen will ask for the password.

    diff --git a/blog/how-to-write-tests-for-swift-result/index.html b/blog/how-to-write-tests-for-swift-result/index.html index aecc9eb..a46cbae 100644 --- a/blog/how-to-write-tests-for-swift-result/index.html +++ b/blog/how-to-write-tests-for-swift-result/index.html @@ -3,155 +3,147 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to write unit test assertions for Swift Result values

    Result is one of my favorite things about the Swift standard library.

    If you're not familiar with it, here's a quick overview. Result is an enum defined as:

    -
    @frozen enum Result<Success, Failure> where Failure : Error
    -
    +
    @frozen enum Result<Success, Failure> where Failure : Error

    There are two cases in Result:

    -
    case success(Success)
    -case failure(Failure)
    -
    +
    case success(Success)
    +case failure(Failure)

    Because it uses generics, you can use it do describe any kind of operation that can succeed or fail. On top of that, it simplifies manipulating the wrapped Success and Failure values thanks to its functional transformations methods like .map and .flatMap.

    Being an enum, though, it can be cumbersome to assert Result values in the unit tests. In this tutorial, we'll look at a few ways to test Result values in Xcode with XCTest.

    All the code in this post is also available in this example project on GitHub.

    -

    Asserting Result when Equatable

    +

    Asserting Result when Equatable

    If both the Success and Failure types in your Result conform to Equatable, you can assert the value using XCTAssertEqual.

    -
    import XCTest
    +
    import XCTest
     
     class EquatableResultTests: XCTestCase {
     
         struct Foo: Equatable { let id: Int }
         struct EquatableError: Equatable, Error { let message: String }
     
    -    func testSuccess() {
    -        let result: Result<Foo, EquatableError> = .success(Foo(id: 123))
    +    func testSuccess() {
    +        let result: Result<Foo, EquatableError> = .success(Foo(id: 123))
     
             XCTAssertEqual(result, .success(Foo(id: 123)))
         }
     
    -    func testFailure() {
    -        let result: Result<Foo, EquatableError> = .failure(EquatableError(message: "abc"))
    +    func testFailure() {
    +        let result: Result<Foo, EquatableError> = .failure(EquatableError(message: "abc"))
     
             XCTAssertEqual(result, .failure(EquatableError(message: "abc")))
         }
    -}
    -
    +}

    This is by far the simplest way to verify code using Result in your unit tests. If you can make the Success and Failure types of your Result Equatable, even just in the test target, then I'd recommend using this concise approach.

    If either one or both the types wrapped in the Result cannot be made Equatable, there are more verbose but equally effective ways write tests for Result.

    -

    Asserting a Result value is successful when not Equatable

    +

    Asserting a Result value is successful when not Equatable

    The simplest way to check if a Result value is in the success case, is to use the handy get() method which returns the associated value if the instance is a success and throws otherwise.

    -
    func testResultSuccessGet() throws {
    -    let result = Result<Int, Error>.success(42)
    +
    func testResultSuccessGet() throws {
    +    let result = Result<Int, Error>.success(42)
     
    -    let value = try result.get()
    +    let value = try result.get()
     
         XCTAssertEqual(value, 42)
    -}
    -
    +}

    If the instance is a failure, get() will throw and the test will fail with the associated Failure error value.

    Sometimes, you can't use a throwing function in your tests, so get() is out of the picture. This is the case for example when you are inside a non-throwing closure.

    In those cases, you can either use guard case or a plain switch.

    -
    func testResultSuccessExampleGuard() {
    -    let result = Result<Int, Error>.success(42)
    +
    func testResultSuccessExampleGuard() {
    +    let result = Result<Int, Error>.success(42)
     
    -    guard case .success(let value) = result else {
    -        return XCTFail("Expected to be a success but got a failure with \(result)")
    +    guard case .success(let value) = result else {
    +        return XCTFail("Expected to be a success but got a failure with \(result)")
         }
     
         XCTAssertEqual(value, 42)
     }
     
    -func testResultSuccessExampleSwitch() {
    -    let result = Result<Int, Error>.success(42)
    +func testResultSuccessExampleSwitch() {
    +    let result = Result<Int, Error>.success(42)
     
         switch result {
         case .failure(let error):
    -        XCTFail("Expected to be a success but got a failure with \(error)")
    +        XCTFail("Expected to be a success but got a failure with \(error)")
         case .success(let value):
             XCTAssertEqual(value, 42)
         }
    -}
    -
    -

    Asserting a Result value is a failure when not Equatable

    +}
    +

    Asserting a Result value is a failure when not Equatable

    The same strategy for the success case applies for failure, with the difference that there is no get() equivalent, so we're left with only guard case or switch.

    -
    func testResultFailureExampleGuard() {
    -    let result = ...
    +
    func testResultFailureExampleGuard() {
    +    let result = ...
     
    -    guard case .failure(let error) = result else {
    -        return XCTFail("Expected to be a failure but got a success with \(result)")
    +    guard case .failure(let error) = result else {
    +        return XCTFail("Expected to be a failure but got a success with \(result)")
         }
     
         // Run your assertions on the expected value of error here
     }
     
    -func testResultFailureExampleSwitch() {
    -    let result = ...
    +func testResultFailureExampleSwitch() {
    +    let result = ...
     
         switch result {
         case .success(let value):
    -        XCTFail("Expected to be a failure but got a success with \(value)")
    +        XCTFail("Expected to be a failure but got a success with \(value)")
         case .failure(let error):
             // Run your assertions on the expected value of error here
         }
    -}
    -
    +}

    Both guard case and switch add clutter to the tests with their syntax. To make the code easier to read, there are some helpful test helpers you can build.

    -

    Result test helpers when either Success or Failure are Equatable

    +

    Result test helpers when either Success or Failure are Equatable

    If only one of the types making up the Result can be Equatable, then you can leverage XCTAssertEqual with a reusable test helper method.

    -
    import XCTest
    +
    import XCTest
     
     extension XCTestCase {
     
    -    func assert<T, E>(
    -        _ result: Result<T, E>,
    -        isSuccessWith value: T
    -    ) where E: Error, T: Equatable {
    +    func assert<T, E>(
    +        _ result: Result<T, E>,
    +        isSuccessWith value: T
    +    ) where E: Error, T: Equatable {
             switch result {
             case .failure(let error):
    -            XCTFail("Expected to be a success but got a failure with \(error)")
    +            XCTFail("Expected to be a success but got a failure with \(error)")
             case .success(let resultValue):
                 XCTAssertEqual(resultValue, value)
             }
         }
     
    -    func assert<T, E>(
    -        _ result: Result<T, E>,
    -        isFailureWith error: E
    -    ) where E: Equatable & Error {
    +    func assert<T, E>(
    +        _ result: Result<T, E>,
    +        isFailureWith error: E
    +    ) where E: Equatable & Error {
             switch result {
             case .failure(let resultError):
                 XCTAssertEqual(resultError, error)
             case .success(let value):
    -            XCTFail("Expected to be a failure but got a success with \(value)")
    +            XCTFail("Expected to be a failure but got a success with \(value)")
             }
         }
    -}
    -
    +}

    You can use these assertions in you tests like you would any other:

    -
    let result: Result<Int, TestError> = .success(42)
    +
    let result: Result<Int, TestError> = .success(42)
     
     assert(result, isSuccessWith: 42)
    -assert(result, isFailureWith: TestError(message: "abc"))
    -
    +assert(result, isFailureWith: TestError(message: "abc"))

    If one of those assertions fail, Xcode will report the failure using the backtrace UI introduced in version 12. That's because the failure occurred in the assertion function, not in the test itself.

    Screenshot of how Xcode 12 reports a failure with backtrace

    If you prefer the standard way of seeing test failures, you can make the helpers report inline by forwarding the call site location to the XCTFail method.

    -
    import XCTest
    +
    import XCTest
     
     extension XCTestCase {
     
    -    func assert<T, E>(
    -        _ result: Result<T, E>,
    -        isSuccessWith value: T,
    -        message: (E) -> String = { "Expected to be a success but got a failure with \($0) "},
    -        file: StaticString = #filePath,
    -        line: UInt = #line
    -    ) where E: Error, T: Equatable {
    +    func assert<T, E>(
    +        _ result: Result<T, E>,
    +        isSuccessWith value: T,
    +        message: (E) -> String = { "Expected to be a success but got a failure with \($0) "},
    +        file: StaticString = #filePath,
    +        line: UInt = #line
    +    ) where E: Error, T: Equatable {
             switch result {
             case .failure(let error):
                 XCTFail(message(error), file: file, line: line)
    @@ -160,13 +152,13 @@ 

    func assert<T, E>( - _ result: Result<T, E>, - isFailureWith error: E, - message: (T) -> String = { "Expected to be a failure but got a success with \($0) "}, - file: StaticString = #filePath, - line: UInt = #line - ) where E: Equatable & Error { + func assert<T, E>( + _ result: Result<T, E>, + isFailureWith error: E, + message: (T) -> String = { "Expected to be a failure but got a success with \($0) "}, + file: StaticString = #filePath, + line: UInt = #line + ) where E: Equatable & Error { switch result { case .failure(let resultError): XCTAssertEqual(resultError, error) @@ -174,8 +166,7 @@

    XCTFail(message(value), file: file, line: line) } } -} -

    +}

    Because the file and line parameters are both set using the special #filePath and #line default values, you'll never need to define them explicitly. That means you can call the assertions exactly as you did before, only this time the failure will be inline.

    Screenshot of how Xcode 12 reports a failure inline using the helpers above

    @@ -183,13 +174,13 @@

    Screenshot of how Xcode 12 reports a failure inline using the helpers above and a custom error message

    Generic Result test helpers

    If you really like the one liner nature of the test helpers, you can use them for a generic Result.

    -
    func assertIsSuccess<T, E>(
    -    _ result: Result<T, E>,
    -    then assertions: (T) -> Void = { _ in },
    -    message: (E) -> String = { "Expected to be a success but got a failure with \($0) "},
    -    file: StaticString = #filePath,
    -    line: UInt = #line
    -) where E: Error {
    +
    func assertIsSuccess<T, E>(
    +    _ result: Result<T, E>,
    +    then assertions: (T) -> Void = { _ in },
    +    message: (E) -> String = { "Expected to be a success but got a failure with \($0) "},
    +    file: StaticString = #filePath,
    +    line: UInt = #line
    +) where E: Error {
         switch result {
         case .failure(let error):
             XCTFail(message(error), file: file, line: line)
    @@ -198,28 +189,26 @@ 

    Generic Result test helpersfunc assertIsFailure<T, E>( - _ result: Result<T, E>, - then assertions: (E) -> Void = { _ in }, - message: (T) -> String = { "Expected to be a failure but got a success with \($0) "}, - file: StaticString = #filePath, - line: UInt = #line -) where E: Equatable & Error { +func assertIsFailure<T, E>( + _ result: Result<T, E>, + then assertions: (E) -> Void = { _ in }, + message: (T) -> String = { "Expected to be a failure but got a success with \($0) "}, + file: StaticString = #filePath, + line: UInt = #line +) where E: Equatable & Error { switch result { case .failure(let error): assertions(error) case .success(let value): XCTFail(message(value), file: file, line: line) } -} -

    +}

    You can then use these helpers like this:

    -
    assertIsSuccess(result)
    -assertIsSuccess(result) { XCTAssertEqual($0, 42) }
    +
    assertIsSuccess(result)
    +assertIsSuccess(result) { XCTAssertEqual($0, 42) }
     
     assertIsFailure(result)
    -assertIsFailure(result) { XCTAssertEqual($0.message, "abc") }
    -
    +assertIsFailure(result) { XCTAssertEqual($0.message, "abc") }

    Investing in your tests' readability makes identifying failures simpler, so you'll be able to fix them sooner.

    I hope you found the this overview of the different ways to work with Result in your XCTest unit tests useful.

    diff --git a/blog/impliticly-vs-force-unwrapping-swift-optionals/index.html b/blog/impliticly-vs-force-unwrapping-swift-optionals/index.html index 26b2fe1..b8600eb 100644 --- a/blog/impliticly-vs-force-unwrapping-swift-optionals/index.html +++ b/blog/impliticly-vs-force-unwrapping-swift-optionals/index.html @@ -5,7 +5,7 @@ Daniel H Steinberg , on Twitter as @dimsumthinking, pointed out to me that the terminology used in the poost wasn't accurate:

    -

    +

    He was right. I went back on the Swift @@ -18,17 +18,15 @@

    Implicitly Unwrapping

    You define an Optional as impliticly unwrapped when you define its type like this:

    -
    let x: String!
    -
    +
    let x: String!

    This technique allows you to tell the compiler to automatically unwrap that value, as if it wasn't optional at all.

    Simlarly to Type? which is a syntactic sugar for Optional<Type>, Type! is equivalent to ImplicitlyUnwrappedOptional<Type>.

    A common example of implicitly unwrapped optionals is how view controller define their IBOutlets:

    -
    @IBOutlet var messageLabel: UILabel!
    -@IBOutlet var actionButton: UIButton!
    -
    +
    @IBOutlet var messageLabel: UILabel!
    +@IBOutlet var actionButton: UIButton!

    It makes sense to define the outlets as implicitly unwrapped optionals because their are going to be instantiated by Interface Builder. It would be cumbersome to always unwrap each view outlet inside view controllers.

    @@ -40,16 +38,15 @@

    Force Unwrap

    of
    the previous post was actually about. It consist in adding a ! after an Optional value, to automatically unwrap it, without having to check whether it is nil or not.

    -
    let strings = ["mokacoding", "is", "a", "blog"]
    -let firstLength: Int = strings.first!.length
    -
    +
    let strings = ["mokacoding", "is", "a", "blog"]
    +let firstLength: Int = strings.first!.length

    Like implicitly unwrapping, force unwrap uses a ! and makes the compiler treat an otherwise optional value as the type it wraps. Unlike implicitly unwrapping though, this technique is used on existing values.

    You define a type as implicitly unwrapped, ImplicitlyUnwrappedOptional<T>, and you force unwrap a value which has Optional type.

    They are both dangerous

    -

    +

    As said in the IBOutlet example and in the previous diff --git a/blog/in-app-purchase-debugging-lessons/index.html b/blog/in-app-purchase-debugging-lessons/index.html index 949a906..a2947c3 100644 --- a/blog/in-app-purchase-debugging-lessons/index.html +++ b/blog/in-app-purchase-debugging-lessons/index.html @@ -4,7 +4,8 @@

    Never ever quit the app while the purchase is in progress

    Let me say it again: never ever quit your app while a purchase is in progress.

    If you do, you'll see this alert popping up every time, regardless of what you do:

    -

    Item has already been purchased but it hasn't been downloaded error screenshot

    +Item has already been purchased but it hasn't been downloaded error screenshot +

    Picking from the In-App Purchase FAQ: "You are getting the "You've already purchased this In-App Purchase but it hasn't been downloaded." error message because you did not call SKPaymentQueue's finishTransaction: method in your application. "

    Looking through the In-App Purchase Programming Guide we discover that not finishing a transaction is a problem, because:

    @@ -17,7 +18,8 @@

    Log a lot

    Even more important is logging the reason a transaction has failed.

    SKPaymentTransaction has an error property which is "an object describing the error that occurred while processing the transaction".

    Test with a good connection

    -

    Cannot connect to iTunes Store error screenshot

    +Cannot connect to iTunes Store error screenshot +

    Thanks to the error property above I once found out that the failure I'd been experiencing for the past 10 minutes were due to the fact that the app wasn't able to connect to the iTunes Store because of the crappy Wi-Fi I was using.


    iOS 8 brought the possibility of testing IAP on the Simulator. I hope Apple will soon improve the IAP test accounts, giving developers the possibility to reset and remove transactions.

    diff --git a/blog/install-xcode-plugin-with-fastlane/index.html b/blog/install-xcode-plugin-with-fastlane/index.html index 7c68ebc..97e8c54 100644 --- a/blog/install-xcode-plugin-with-fastlane/index.html +++ b/blog/install-xcode-plugin-with-fastlane/index.html @@ -9,7 +9,7 @@

    Fastlane to the rescue

    One of the available actions is install_xcode_plugin, which takes the URL of a zip file containing an Xcode plugin and downloads then install it for you.

    By leveraging this action we can write a sort of rc file with the list of our favourite plugins, and automatically install them on new machines.

    Here's how mine looks like:

    -
    lane :install_xcode_plugins do
    +
    lane :install_xcode_plugins do
       [
         # The Xcode plugins manager
         'https://github.com/alcatraz/Alcatraz/archive/1.1.12.zip',
    @@ -33,8 +33,7 @@ 

    Fastlane to the rescue

    .each do |plugin_url| install_xcode_plugin(url: plugin_url) end -end -
    +end

    Gotchas

    There are two things to keep in mind when using this workflow. The first is that not all plugins unfortunately have a downloadable zip archive. The second is that there is no version update happening here, the same version is downloaded every time.

    My recommendation is to use this method of installing plugins as the starting point for getting your favourites and Alcatraz itself, then manage them with it.

    diff --git a/blog/ios-testing-in-2015/index.html b/blog/ios-testing-in-2015/index.html index da6cf71..52b6a49 100644 --- a/blog/ios-testing-in-2015/index.html +++ b/blog/ios-testing-in-2015/index.html @@ -14,12 +14,11 @@

    Where it all begins: Xcode

    While in the past two year unit testing for iOS and OS X has become better and better, the acceptance testing side of things hasn't made any improvements.

    To write UI automation test, Apple provides the UIAutomation framework. UIAutomation tests are written in Javascript, and allow us to drive the application UI and make assertion on its state. Despite how promising this all sounds, working with UIAutomation turns out to be quite tedious, and the Javascript APIs not as powerful as the unit testing native counter parts.

    Here's a snippet of UIAutomation test:

    -
    UIATarget.localTarget().frontMostApp().navigationBar().buttons()["Add"].tap();
    +
    UIATarget.localTarget().frontMostApp().navigationBar().buttons()["Add"].tap();
     
     UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].cells()[0].elements()["Chocolate Cake"];
     
    -UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].scrollToElementWithPredicate("name beginswith 'Turtle Pie'");
    -
    +UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].scrollToElementWithPredicate("name beginswith 'Turtle Pie'");

    As you can see they managed to make the Javascript APIs even more verbose than the ones in Foundation. Add to that the fact that these tests need to be run from Instruments and you'll get the idea of how unpleasant working on this framework could be.

    The last piece of the puzzle is Apple's answer to the CI question: Xcode Bots. We can configure an Xcode Bot to get triggered and do work, for example running tests, for us, and host it on an Xcode Server.

    I'll admit that I haven't done any work with Xcode Bots, but all the feedbacks I got on theme where on the lines of "I just doesn't work". 😞

    @@ -28,9 +27,9 @@

    Where it all begins: Xcode

    Open source libraries for Unit Testing

    The iOS and OS X open source community is full of nice people and interesting projects. At the time of writing pod list reports that 8625 pods were found.

    The open source libraries for unit testing show a trend in the style of the tests, they're in fact all in an xSpec style, which is taken from the RSpec Ruby testing library, and gives more relevance to the testing the behaviour of a class, rather than enumerating its methods.

    -

    Kiwi

    +

    Kiwi

    Kiwi is a drop-in full stack replacement for XCTest, that provides an xSpec syntax. A Kiwi test, or better spec, looks like this:

    -
    describe(@"Team", ^{
    +
    describe(@"Team", ^{
       context(@"when newly created", ^{
         it(@"has a name", ^{
           id team = [Team team];
    @@ -42,15 +41,14 @@ 

    11] players]; }); }); -}); -

    +});

    Kiwi specs are usually easier to read and communicate effectively what the system under test is meant to do, working as good documentation for the code.

    Kiwi comes with it's own set of expectations, mocks, and stubs, and even supports asynchronous testing.

    -

    Specta

    +

    Specta

    Specta is very similar to Kiwi, but takes a different architectural approach. Where Kiwi is a monolithic drop-in replacement, Specta values modularity and composition. The only thing the library takes care of is the framework for writing and running xSpec style tests, it's then up to the user to plug in libraries to take care of expectations, matching, mocking and stubbing.

    I personally prefer this approach to library design, little self contained pieces that can be combined together.

    Here's a Specta spec:

    -
    SpecBegin(Thing)
    +
    SpecBegin(Thing)
     
     describe(@"Thing", ^{
       it(@"should do stuff", ^{
    @@ -63,8 +61,7 @@ 

    OHTTPStubs a library to stub network requests, with block based syntax to match URLs.
  • Nocilla another library to stub network requests, with a nice chain-able API, stubRequest(@"POST", <url>).withHeaders(...).withBody(...).
  • -

    Quick

    +

    Quick

    Quick is the new kid in the block, and it's a very cool kid indeed. Quick is mainly written in Swift and it's best suited to write test components written in the new language.

    -
    import Quick
    +
    import Quick
     
     class ThingSpec: QuickSpec {
    -  override func spec() {
    +  override func spec() {
         describe("a 'Thing'") {
           it("should do stuff) {
             //
           }
         }
       }
    -}
    -
    +}

    Thanks to Swift's syntax and closures Quick specs look far more readable that Kiwi's or Specta's.

    Quick comes together with Nimble it's matchers library, which allows us to write neat things like expect(10) > 2.

    Whether is Objective-C or Swift, monolith framework or composition of your favourite libraries, the open source scene offers plenty of valuable testing libraries, specially focused on writing clearer tests thanks to expressive syntax.

    Open source libraries for Acceptance Testing

    The same discrepancy in the quality of unit versus acceptance testing tools that we see in the Apple frameworks is reflected in the open source tools. This is probably due to the fact that while XCTest provide a solid foundation for developers to build frameworks on top of, UIAutomation doesn't, and all we're left with are hacks.

    -

    KIF

    +

    KIF

    KIF, Keep It Functional, is a framework written in Objective-C that lets us write acceptance tests using XCTest and running them through Xcode in the same way we would do with unit tests.

    The KIF tester uses private APIs to gain knowledge of the view hierarchy, and lets us query and interact with it using the accessibility label value of the views.

    -
    - (void)testSuccessfulLogin {
    +
    - (void)testSuccessfulLogin {
       [tester enterText:@"user@example.com" intoViewWithAccessibilityLabel:@"Login User Name"];
       [tester enterText:@"thisismypassword" intoViewWithAccessibilityLabel:@"Login Password"];
       [tester tapViewWithAccessibilityLabel:@"Log In"];
     
       // Verify that the login succeeded
       [tester waitForTappableViewWithAccessibilityLabel:@"Welcome"];
    -}
    -
    +}

    A big downside of KIF is the slow response time of the maintainers. This doesn't want to be a critique though, in the open source world everything is done for free, and since we all need to pay the bills, the amount of time that can be spent on such projects is limited. But when mixed with an foundation hard to work with, this results in unstable tools.

    Update 2015/06/04 Since the months right after the publication of this article KIF has seen a remarkable burst in the response time of the maintainers, such that the observation above is not valid any more. Right now KIF is not only the best candidate for UI automation and acceptance testing, but also has an active community, and new version that will bring architectural and performance improvements is on its way. KIF's future is definitely bright.

    -

    Subliminal

    +

    Subliminal

    Subliminal is an Objective-C framework that, like KIF, integrates with XCTest. Unlike KIF though, Subliminal is written on top of UIAutomation itself, and aims to hide away it's complexity from the developers.

    -
    - (void)testLogInSucceedsWithUsernameAndPassword {
    +
    - (void)testLogInSucceedsWithUsernameAndPassword {
       SLTextField *usernameField = [SLTextField elementWithAccessibilityLabel:@"username field"];
       SLTextField *passwordField = [SLTextField elementWithAccessibilityLabel:@"password field" isSecure:YES];
       SLElement *submitButton = [SLElement elementWithAccessibilityLabel:@"Submit"];
    @@ -131,16 +126,15 @@ 

    // Check the internal state of the app. SLAssertTrue(SLAskAppYesNo(isUserLoggedIn), @"User is not logged in.") -} -

    +}

    Subliminal states that it can enable testing In-App Purchase alerts, and even put the app to sleep. This all sounds great, but the fact that, at the time of writing, the last commit is from September 2014, and there are 13 active PR throws a bad signal on the status of the library 😕.

    -

    Calabash

    +

    Calabash

    Of all the tools seen so far Calabash is certainly the most original one. It's a Ruby gem to write acceptance tests in full BDD style using Cucumber, and it's maintained by Xamarin, which is a framework for writing iOS and Android apps in C#. What a mix of languages!

    Unlike KIF and Subliminal, Calabash is not integrated with Xcode, at all. My setup for example uses Vim and Rake.

    We write Cucumber features, implements the step, and run the tests using a command line tool. For this to work we need to embed an HTTP server in the app, that is used by the test runner to query and drive the UI.

    Needless to say, this is all a big hack.

    A Cucumber/Calabash test looks like this

    -
    # rating_a_stand.feature
    +
    # rating_a_stand.feature
     
     Feature: Rating a stand
       Scenario: Find and rate a stand from the list
    @@ -160,8 +154,7 @@ 

    Calabash

    Given(/^I should not see "([^\"]*)"$/) do |view_label| wait_for_element_does_not_exists "view marked:'#{view_label}' -end -
    +end

    The upside of Calabash is very declarative tests, that the management will like if they'll ever read them, and the ability for a tester to port most of their know-how across the two platforms.

    On the other hand, the toolchain is not very robust. Tests run slower [quote needed], and one needs to constantly swap between Cucumber features, Ruby steps, and Objective-C view code, taking up a considerable amount of time.

    Like the unit testing scene, the open source world provides different choices that can be used to improve your workflow. The only difference here is that the tools are no way near as mature, and the interest of the community is not as active.

    diff --git a/blog/ios7-ux-designers-verdict/index.html b/blog/ios7-ux-designers-verdict/index.html index 2dca715..699b40a 100644 --- a/blog/ios7-ux-designers-verdict/index.html +++ b/blog/ios7-ux-designers-verdict/index.html @@ -3,18 +3,28 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    Sharing some thoughts on iOS 7

    Today I read this article I added to my reading list a couple of days ago: iOS 7: leading UX designers give their verdict. I founded some of the opinions quite interesting and worth sharing.

    The functionality at the core of iOS7 hasn’t changed much it has just been extended in a number of ways. The main deviations are from a visual perspective.

    +
    +

    The biggest change is the introduction of a brighter colour palette, which allows Apple’s LCD screens to compete with vivid OLED smartphones (suc as the Samsung Galaxy). This allows Apple to increase its appeal to the Asian market who demonstrate a preference for bright colours throughout their consumption of visual culture.

    +
    +

    This suggests a shift in focus from user experience to customer experience.

    +
    +

    Kostja Paschalidis, service designer at Fjord


    A lot of the button pushing, slide out panels and alert boxes from the previous skin were reminiscent of stale formats we are accustomed to from the 'Web 2.0' era and the lack of innovation within Windows.

    +
    +

    Andy Parker, UX designer at Clearleft


    We know when a button's a button. It doesn't need real-world lighting to trick us into tapping it. We're living in a digitally savvy world now compared to 2007 when the iPhone first launched. Therefore UI in general going forward will feel authentically digital and that's regardless of the mobile platform it's being designed for.

    +
    +

    Shaun Tollerton, Visual Designer at ustwo

    diff --git a/blog/itunes-connect-multiple-accounts/index.html b/blog/itunes-connect-multiple-accounts/index.html index ff31b37..591dd95 100644 --- a/blog/itunes-connect-multiple-accounts/index.html +++ b/blog/itunes-connect-multiple-accounts/index.html @@ -10,7 +10,7 @@

    Step 0: Understand the problem

  • Export the app .ipa
  • Submit it to iTunes Connect using Application Loader
  • -

    Step 1: Get an invitation to join the team's iTunes Connect

    +

    Step 1: Get an invitation to join the team's iTunes Connect

    As we said, there is no concept of multiple teams a user can belong to in iTunes Connect, so the only way to get access to the client's iTunes Connect is to create a new Apple ID.

    The best way I found to do that is:

      diff --git a/blog/job-stories-acceptance-tests-with-kif-and-specta/index.html b/blog/job-stories-acceptance-tests-with-kif-and-specta/index.html index 2445b5b..b60ed40 100644 --- a/blog/job-stories-acceptance-tests-with-kif-and-specta/index.html +++ b/blog/job-stories-acceptance-tests-with-kif-and-specta/index.html @@ -9,7 +9,7 @@ So that I can expand my knowledge

      The test we wrote was this:

      -
      /**
      +
      /**
        *  When I tap the "show elements" button, I see a listt of elements, so I can expand my knowledge
        */
       - (void)testShowElements {
      @@ -19,14 +19,12 @@
         [tester waitForViewWithAccessibilityLabel:@"[H] Hydrogen (1)" ];
         [tester waitForViewWithAccessibilityLabel:@"[Uuo] Ununoctium (118)"];
         // Code to restore the app to the default state
      -}
      -
      +}

      The only way we have to tie the test to the story is by using a comment. The terminal output for it will be:

      -
      Test Case '-[MainScreenTest testShowElements]' started.
      -Test Case '-[MainScreenTest testShowElements]' passed (1.720 seconds).
      -

      This output does not give use any information on the story.

      +
      Test Case '-[MainScreenTest testShowElements]' started.
      +Test Case '-[MainScreenTest testShowElements]' passed (1.720 seconds).

      This output does not give use any information on the story.

      Let's now see what we could do using Specta has the harness for the test. The simplest implementation we could write is be something like this:

      -
      describe(@"When I tap the 'show elements' button, I see a list of elements, so I can expand my knowledge", ^{
      +
      describe(@"When I tap the 'show elements' button, I see a list of elements, so I can expand my knowledge", ^{
         it(@"should do what's expected", ^{
           [tester tapViewWithAccessibilityLabel:@"show elements"];
       
      @@ -35,15 +33,13 @@
           [tester waitForViewWithAccessibilityLabel:@"[Uuo] Ununoctium (118)"];
           // Code to restore the app to the default state
         });
      -});
      -
      +});

      Which outputs:

      -
      Test Case '-[MainScreenSpec test_When_I_tap_the_show_elements_button_I_see_a_list_of_elements_so_that_I_can_expand_my_knowledge__should_do_whats_expected]' started.
      -Test Case '-[MainScreenSpec test_When_I_tap_the_show_elements_button_I_see_a_list_of_elements_so_that_I_can_expand_my_knowledge__should_do_whats_expected]' passed (1.703 seconds).
      -

      Now, I'm not gonna say that this console output reads better than the previous one, but you can't deny that, once you digest the snake casing, the story is expressed there.

      +
      Test Case '-[MainScreenSpec test_When_I_tap_the_show_elements_button_I_see_a_list_of_elements_so_that_I_can_expand_my_knowledge__should_do_whats_expected]' started.
      +Test Case '-[MainScreenSpec test_When_I_tap_the_show_elements_button_I_see_a_list_of_elements_so_that_I_can_expand_my_knowledge__should_do_whats_expected]' passed (1.703 seconds).

      Now, I'm not gonna say that this console output reads better than the previous one, but you can't deny that, once you digest the snake casing, the story is expressed there.

      However, there are some issues, that @"should do what's expected" is a bit out of place, and doesn't really add any value. Also, the test body is as long as its XCTest counterpart.

      When can leverage on the xSpec syntax that Specta provides use to write a test case that flows in a nicer way.

      -
      describe(@"Main screen", ^{
      +
      describe(@"Main screen", ^{
         context(@"when I tap the 'show elements' button", ^{
           before(^{
             [tester tapViewWithAccessibilityLabel:@"show elements"];
      @@ -59,14 +55,12 @@
             // Code to restore the app to the default state
           });
         });
      -});
      -
      +});

      The code of this test really reads better, what I especially like is how this syntax allows us to separate the operations that we need to perform to reach the screen or feature under test from the assertion itself. The same stands true for the code to restore the app into the default state, from which the next test, whatever it will be, can reliably start.

      Notice how we removed the useless @"should do what's exepceted" and how more horizontally compact the code is, no need to move your eyes left and right to read it, or to horizontally scroll.

      The console output is still long and with all the _, but at least it only carries useful information:

      -
      Test Case '-[MainScreenSpec test_Main_screen__when_I_tap_the_show_elements_button__I_see_a_list_of_elements_so_I_can_expand_my_knowledge]' started.
      -Test Case '-[MainScreenSpec test_Main_screen__when_I_tap_the_show_elements_button__I_see_a_list_of_elements_so_I_can_expand_my_knowledge]' passed (1.724 seconds).
      -

      You can have a look at the other tests on Bench to have a better idea of how this kind of tests look.

      +
      Test Case '-[MainScreenSpec test_Main_screen__when_I_tap_the_show_elements_button__I_see_a_list_of_elements_so_I_can_expand_my_knowledge]' started.
      +Test Case '-[MainScreenSpec test_Main_screen__when_I_tap_the_show_elements_button__I_see_a_list_of_elements_so_I_can_expand_my_knowledge]' passed (1.724 seconds).

      You can have a look at the other tests on Bench to have a better idea of how this kind of tests look.


      Acceptance testing on iOS is an field which is still evolving and taking a proper form, both the tools and the process are not yet mature and up to the task. This approach to writing acceptance tests using a job story style, with KIF and Specta as tools of choice, is only one of the possible ones, and it's not said that it's the best one. Although without experimenting and trying new approaches we risk to stagnate, and progress comes from experimentation. I've been using this approach in a handful of projects and have been quite happy with the results.

      I'd like to hear your opinion on this, or on any other styles you might be using to write your acceptance test cases. You can tweet @mokacoding, or use the comments below. And don't forget to subscribe to our newsletter.

      diff --git a/blog/lessons-learned-working-on-danger-swiftlint-selective-linting/index.html b/blog/lessons-learned-working-on-danger-swiftlint-selective-linting/index.html index 59f6eb8..10288b4 100644 --- a/blog/lessons-learned-working-on-danger-swiftlint-selective-linting/index.html +++ b/blog/lessons-learned-working-on-danger-swiftlint-selective-linting/index.html @@ -20,7 +20,7 @@

      How to mock Ruby Tempfile

      To do so we need to stub the method used to generate such temporary file, Tempfile#open.

      RSpec provides a way to stub a method call response by yelding to the caller's block:

      That's all I needed 😄.

      -
      fake_temp_file = Tempfile.new('fake.yml')
      +
      fake_temp_file = Tempfile.new('fake.yml')
       
       # Using begin-ensure-end here to avoid confusingly calling Tempfile.open and
       # stubbing it at the same time.
      @@ -30,25 +30,22 @@ 

      How to mock Ruby Tempfile ensure fake_temp_file.close fake_temp_file.unlink -end -

      +end

      How to remove keys from a Ruby hash

      Part of what the PR needed to do was to generate a new configuration YAML file that wouldn't include the node that the CLI option cannot override.

      To do so the original configuration file is read and put into an hash. The hash is then mutated removing the key corresponding to the setting that needs to be overridden via CLI. Finally the hash is converted back into YAML and wrote into the temporary file.

      I naively thought that setting its value to nil would have been enough to remove a key from an hash. I should have though about it for longer that one second.

      Setting a key's value to nil… sets it's value to nil 😅 The key is still there.

      This is usually ok in code because we usually do things like unless hash[:key].nil? do .... In the case of serialization to YAML that's no good though, as what we'd get is a YAML with an empty node corresponding to the key with nil value.

      -
      require 'yaml'
      +
      require 'yaml'
       
       hash = { foo: nil }
       
       hash.to_yaml
      -# => "---\n:foo: \n"
      -
      +# => "---\n:foo: \n"

      The correct way to remove a key from an hash is to use tap.

      -
      { foo: nil, bar: 'baz' }.tap { |hash| hash.delete(:foo) }
      -# => { :bar =>"baz" }
      -
      +
      { foo: nil, bar: 'baz' }.tap { |hash| hash.delete(:foo) }
      +# => { :bar =>"baz" }

      I love open source and being able to support the projects I use by contributing to them. Submitting pull requests is always a great occasion to learn new things and to grow as a developer. I encourage you to do the same!

      If you know of a better way of achieving the same results as I did, or if you have any other please leave a comment below or get in touch on Twitter @mokagio.

      diff --git a/blog/main-vs-master-xcode-12/index.html b/blog/main-vs-master-xcode-12/index.html index ad7a8e6..f2cec38 100644 --- a/blog/main-vs-master-xcode-12/index.html +++ b/blog/main-vs-master-xcode-12/index.html @@ -9,7 +9,8 @@

      The other night, I noticed that when the new Xcode 12 sets up the Git repo for a new project, it uses main instead of master as the branch name.

      I eagerly tweeted my discovery.

      -

      + +

      I woke up to more than a hundred mentions. People got very passionate about it, the haters and the trolls were unleashed.

      I didn't reply to the tweets. diff --git a/blog/maintaining-sanity-with-multiple-versions-of-xcode/index.html b/blog/maintaining-sanity-with-multiple-versions-of-xcode/index.html index bf14838..0def217 100644 --- a/blog/maintaining-sanity-with-multiple-versions-of-xcode/index.html +++ b/blog/maintaining-sanity-with-multiple-versions-of-xcode/index.html @@ -11,11 +11,11 @@ running is the latest or the beta, as my dock is always hidden, and CLI builds failing because they've been run with the wrong version of xcodebuild.

      In this post I've listed some tools to help make it less so.

      -

      xcode-toggle

      +

      xcode-toggle

      xcode-toggle by Jonathan Wight (@schwa) is smart wrapper around xcode-select --switch that simplifies switching between toolchain versions.

      -
      $ xcode-toggle -t
      +
      $ xcode-toggle -t
       Switching to: /Applications/Xcode-beta.app
       /Applications/Xcode-beta.app [Current]
       /Applications/Xcode.app
      @@ -23,9 +23,8 @@ 

      /Applications/Xcode.app /Applications/Xcode-beta.app -/Applications/Xcode.app [Current] -

      It's called toggle but it works with more than two versions of Xcode as well.

      -

      BetaWarpaint Xcode plugin

      +/Applications/Xcode.app [Current]

      It's called toggle but it works with more than two versions of Xcode as well.

      +

      BetaWarpaint Xcode plugin

      This simple yet brilliant plugin by Sash Zats changes the style of the Xcode-beta toolbars and alerts making it striped.

      diff --git a/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1/index.html b/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1/index.html index 9a6c964..8b858f2 100644 --- a/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1/index.html +++ b/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1/index.html @@ -1,20 +1,20 @@ mokagio's self memo for Facebook Integration on iOS - Part 1 | mokacoding

      mokacoding

      unit and acceptance testing, automation, productivity

      mokagio's self memo for Facebook Integration on iOS - Part 1

      Part 1 - Facebook Login

      -

      0 - Create a Facebook App

      +

      mokacoding

      unit and acceptance testing, automation, productivity

      mokagio's self memo for Facebook Integration on iOS - Part 1

      ##Part 1 - Facebook Login

      +

      ###0 - Create a Facebook App

      Create an app on the Facebook App Dashboard, what are you gonna integrate otherwise?!

      -

      1 - Add the Facebook SDK Pod

      +

      ###1 - Add the Facebook SDK Pod

      Given that you have already setup your libraries management with CocoaPods, and you should have, add to your Podfile the line

      pod "Facebook-iOS-SDK", "~> 3.5.2"

      Then run pod install.

      For more info about how to use CocoaPods check out this post of mine.

      -

      2 - Add some Facebook data to the Info.plist

      +

      ###2 - Add some Facebook data to the Info.plist

      Facebook requires you to add two fields to your Info.plist file:

      • FacebookAppID: a 15 digits number you can find in the Settings page of your app on your Facebook developer page.
      • FacebookDisplayName: how to comment, the display name of your app?
      -

      3 - A basic login flow

      +

      ###3 - A basic login flow

      The tutorial tells us to put all the Facebook login in the AppDelegate. I don't like this approach, because I don't want to make the delegate dirty with code related only to Facebook. I prefer to create a FacebookProxy class, with class methods to call to interact with Facebook.

      Whatever solution you prefer the steps for the login are the same anyway:

        @@ -24,9 +24,9 @@

        3 - A basic login flow

      1. Let the SDK do it's job.
      2. Come back to the app and handle the result.
      -

      Check if the user is logged in

      +

      ####Check if the user is logged in

      To get the current Facebook session we use FBSession.activeSession. To see if the session is active, and therefore the user is already logged in, we need to check the state property: FBSession.activeSession.state. A quick look to the typedef enum of the FBSessionState and:

      -
      {% highlight objective-c %}
      +
      {% highlight objective-c %}
       + (BOOL)isUserLoggedInFacebook
       {
           if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded
      @@ -37,21 +37,19 @@ 

      Check if the user is logged in

      return NO; } } -{% endhighlight %} -

      Call the Facebook SDK method to login

      +{% endhighlight %}

      ####Call the Facebook SDK method to login

      Easy peasy:

      -
      {% highlight objective-c %}
      +
      {% highlight objective-c %}
       [FBSession openActiveSessionWithReadPermissions:nil
                                          allowLoginUI:YES
                                     completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
            // handle stuff here
        }];
      - {% endhighlight %}
      -

      In the completion handler we should… handle the result of the open active session. I think that this really depends on what our app will do, so I'm not gonna write any snippet here.

      -

      Come back to the app and handle the result

      + {% endhighlight %}

      In the completion handler we should… handle the result of the open active session. I think that this really depends on what our app will do, so I'm not gonna write any snippet here.

      +

      ####Come back to the app and handle the result

      If you're user's are using iOS 5 -I hope they're not-, or if they're so dumb they haven't installed the native Facebook app for iOS, the login will occur with a sort of modal window in your app. In all the rest of the cases the

      -

      Frameworks needed in the Test Bundle

      -

      TDD is the way. Full stop. I noticed that adding the Facebook-iOS-SDK pod to my project wasn't enough for my test bundle to run, there were some framework dependencies missing:

      +

      ###Frameworks needed in the Test Bundle +TDD is the way. Full stop. I noticed that adding the Facebook-iOS-SDK pod to my project wasn't enough for my test bundle to run, there were some framework dependencies missing:

      • AdSupport.framework
      • Social.framework
      • diff --git a/blog/mtfonticon/index.html b/blog/mtfonticon/index.html index d19f360..7c764b1 100644 --- a/blog/mtfonticon/index.html +++ b/blog/mtfonticon/index.html @@ -1,15 +1,15 @@ Bringing font icons in iOS with MTFontIcon | mokacoding

        mokacoding

        unit and acceptance testing, automation, productivity

        Bringing font icons in iOS with MTFontIcon

        Let me introduce you one of my latests projects, on which I worked almost a month ago, but I'm both lazy and hyperactive when it comes to projects, so the blog post arrives only now...

        -

        MTFontIcon

        +

        ###MTFontIcon

        MTFontIcons, available as a CocoaPod and on GitHub, is a library that let's us use font-based icons in iOS application, speeding up the development and helping those poor developers that don't even know how to select the pen tool in Adobe Illustrator.

        -

        The problem

        +

        ###The problem

        Few people in our world are both great developers and skilled artist, my friend and ex-colleague Tancredi is one of those. For the rest of us mere mortals finding building a well crafted app is already a big task, and we don't have time to go through the Nettus+ Illustrator and Photoshop tutorials to learn how to make a nice icon set for our apps. We only speak code.

        It would be really nice to have a way to iterate on the attributes of our icons and images quickly and without losing quality. Changing the color from #f0f0f0 to #f0dff1, making it 2pts wider, increasing the alpha of the shadow, without opening Illustrator, or worst waiting for the designer to put the assets on Dropobox. It would be nice to code all those things.

        -

        The solution

        +

        ###The solution

        The fact is our cousins from the web world already faced this problem, and solved in a really nice way! They've been using Icon Fonts for a while, and they're really happy about them. This technique is so powerful and popular that even the famous framework Bootstrap made by the guys at Twitter is using it. And there are plenty of resources only to get ready made stets of icons, or roll out our own font uploading the SVGs.

        -

        How does it work?

        +

        ###How does it work?

        Then why not using the same smartness in Objective-C? The MTFontIcon idea was born from the above mentioned rebel genious of Tancredi, while working on a prototype for a new concept at Memrise. Unfortunately the idea protoyped wasn't that good, unlike the tech behind it.

        The usage is simple:

          @@ -19,7 +19,7 @@

          How does it work?

        1. Get an instance of MTFontIconFactory and use it to get as many MTFontIconViews as you want :)

        Two minutes setup, two lines of code usage, twice as fast app UI development and polishing!

        -

        Current problems and roadmap

        +

        ###Current problems and roadmap

        Despite the 1.0.0 tag, MTFontIcon has still a long way to go before considering itself a mature and really useful project. Here's a list of things we could improve:

        • Issues with ascendant and descendants, if you ever tried to use a custom font on iOS you know what I'm talking about. Otherwise read this and this.
        • diff --git a/blog/multiple-builds-of-the-same-app-and-testflight/index.html b/blog/multiple-builds-of-the-same-app-and-testflight/index.html index 81db82e..287e2ee 100644 --- a/blog/multiple-builds-of-the-same-app-and-testflight/index.html +++ b/blog/multiple-builds-of-the-same-app-and-testflight/index.html @@ -2,36 +2,36 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

          Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

        mokacoding

        unit and acceptance testing, automation, productivity

        Multiple builds of the same app and TestFlight

        The Multiple Builds Dream

        -

        Working in Memrise on CatAcademy I've been massively using TestFlight to test new features before releasing the next versions of the app. One thing that always annoyed me was the fact that my development version overrode the release one, or that I couldn't keep a "stable" build and a "development" build on my device at the same time.

        +

        Working in Memrise on CatAcademy I've been massively using TestFlight to test new features before releasing the next versions of the app. One thing that always annoyed me was the fact that my development version overrode the release one, or that I couldn't keep a "stable" build and a "development" build on my device at the same time.

        After attending the Facebook Mobile DevCon 2013 in London, where the talk from Alan Cannistraro on how Facebook made their iOS app I realized that having multiple builds of the same app was possible. But how to do it?

        -

        I did some research and found this post, which had almost all the info I need on how to setup my multiple builds infrastructure. There's no point in me copy-pasting what's written there, besides I'm sure 99.9% of you readers already opened the link in a new tab.

        +

        I did some research and found this post, which had almost all the info I need on how to setup my multiple builds infrastructure. There's no point in me copy-pasting what's written there, besides I'm sure 99.9% of you readers already opened the link in a new tab.

        -

        The post is pretty old, so here's an updated screenshot of the Build Settings editor.

        +

        The post is pretty old, so here's an updated screenshot of the Build Settings editor.

        Screen Shot 2013-05-29 at 22.05.48

        -

        If you follow the instructions and run the app on the simulator or on the device, you'll see the new development app appearing next to the release one, as expected.

        +

        If you follow the instructions and run the app on the simulator or on the device, you'll see the new development app appearing next to the release one, as expected.

        -

        This is pretty handy to go around with the two versions of the app and to some user testing with the friends, but guess what? It doesn't work with TestFlight! But fear not, there are only two other steps to make before reaching the goal.

        +

        This is pretty handy to go around with the two versions of the app and to some user testing with the friends, but guess what? It doesn't work with TestFlight! But fear not, there are only two other steps to make before reaching the goal.

        Making a Development Archive

        -

        First problem: when we archive the app the Release configuration is used. Changing this option is pretty easy through the "Edit Scheme…" menu, but wait a second! If we change now the Build Configuration for the archive action from Release to Debug, we'll have to change it back once we're going to publish on the App Store. +

        First problem: when we archive the app the Release configuration is used. Changing this option is pretty easy through the "Edit Scheme…" menu, but wait a second! If we change now the Build Configuration for the archive action from Release to Debug, we'll have to change it back once we're going to publish on the App Store. Better creating a new Scheme and change the configuration in that one.

        -

        "Changing the Scheme every time we want to submit it just as annoying as editing it". Fair enough. But not really… Switching Scheme requires 2 clicks, while editing it at least 6. :P No, seriously switching Scheme is something we can easily automate, using xcodebuild or xctool and a couple of lines in your favourite scripting language.

        +

        "Changing the Scheme every time we want to submit it just as annoying as editing it". Fair enough. But not really… Switching Scheme requires 2 clicks, while editing it at least 6. :P No, seriously switching Scheme is something we can easily automate, using xcodebuild or xctool and a couple of lines in your favourite scripting language.

        Making it work on TestFlight

        -

        All right! Now we're finally able to archive our development version of the app and upload it on TestFlight, maybe through the TestFlight App which is nice and fast. But if we try to do it this is the result:

        +

        All right! Now we're finally able to archive our development version of the app and upload it on TestFlight, maybe through the TestFlight App which is nice and fast. But if we try to do it this is the result:

        The provisioning profile is made for distribution builds but your app is built for development. Please select a valid development identity to continue.

        -

        Don't panic! The message gives us a tip already on how to solve the issue, we just need another Provisioning Profile! Select Development when creating the new profile and use the AppID of the "original" app. This last point surprised me, but I think it may have something to do with the sort of hierarchy structure the bundle ids have.

        +

        Don't panic! The message gives us a tip already on how to solve the issue, we just need another Provisioning Profile! Select Development when creating the new profile and use the AppID of the "original" app. This last point surprised me, but I think it may have something to do with the sort of hierarchy structure the bundle ids have.

        -

        Once your Provisioning Profile is ready update the certificates list in Xcode, through the Organizer window, and proceed to Archive the app. Now when you'll upload the archive with the TestFlight App the new development certificate will appear.

        +

        Once your Provisioning Profile is ready update the certificates list in Xcode, through the Organizer window, and proceed to Archive the app. Now when you'll upload the archive with the TestFlight App the new development certificate will appear.

        Here we go!

        diff --git a/blog/navigation-delegate-pattern/index.html b/blog/navigation-delegate-pattern/index.html index 16f154a..f9d56af 100644 --- a/blog/navigation-delegate-pattern/index.html +++ b/blog/navigation-delegate-pattern/index.html @@ -6,54 +6,51 @@ There are usually animations involved, which in turn require either your test assertions to be asynchronous or your code to allow the animated flag to be injected as false from the tests.

        Those and other little gotchas make the tests harder to write and reason about, but it doesn't have to be so.

        You can use a simple and cheap pattern to easily test how your view controllers trigger navigation, making your code easier to work with in the process.

        -

        NavigationDelegate

        +

        The key to make navigations between view controllers easy to test lies in appreciating that view controllers be responsible for presenting other view controllers.

        View controllers should only trigger the navigation and then delegate the act of performing it to another object. I like to call this kind of delegates NavigationDelegates*.

        With a NavigationDelegate in place, testing how a view controller does navigations is now a matter of testing how it interacts with its delegate. This can be done by using a spy.

        -

        NavigationDelegate in action

        +

        To test that a view controller triggers the expected navigation you can verify that it calls the appropriate method of its NavigationDelegate.

        -
        func testCallsShowRedWhenRedButtonTouched() {
        -    let viewController = loadViewController()
        -    let navigationDelegateSpy = ViewControllerNavigationDelegateSpy()
        -    viewController.navigationDelegate = navigationDelegateSpy
        +
        func testCallsShowRedWhenRedButtonTouched() {
        +    let viewController = loadViewController()
        +    let navigationDelegateSpy = ViewControllerNavigationDelegateSpy()
        +    viewController.navigationDelegate = navigationDelegateSpy
         
        -    viewController.redButton.sendActions(for: .touchUpInside)
        +    viewController.redButton.sendActions(for: .touchUpInside)
         
             XCTAssertTrue(navigationDelegateSpy.showRedCalled)
        -}
        -
        -
        protocol ViewControllerNavigationDelegate: class {
        -    func showRedViewController()
        +}
        +
        protocol ViewControllerNavigationDelegate: class {
        +    func showRedViewController()
         }
         
         class ViewController: UIViewController {
         
        -    @IBOutlet weak var redButton: UIButton!
        +    @IBOutlet weak var redButton: UIButton!
         
        -    weak var navigationDelegate: ViewControllerNavigationDelegate?
        +    weak var navigationDelegate: ViewControllerNavigationDelegate?
         
        -    override func viewDidLoad() {
        +    override func viewDidLoad() {
                 super.viewDidLoad()
         
        -        redButton.addTarget(self, action: #selector(redButtonTouched), for: .primaryActionTriggered)
        +        redButton.addTarget(self, action: #selector(redButtonTouched), for: .primaryActionTriggered)
             }
         
        -    @objc func redButtonTouched() {
        -        navigationDelegate?.showRedViewController()
        +    @objc func redButtonTouched() {
        +        navigationDelegate?.showRedViewController()
             }
        -}
        -
        -
        class ViewControllerNavigationDelegateSpy: ViewControllerNavigationDelegate {
        +}
        +
        class ViewControllerNavigationDelegateSpy: ViewControllerNavigationDelegate {
         
        -    private(set) var showRedCalled = false
        +    private(set) var showRedCalled = false
         
        -    func showRedViewController() {
        -        showRedCalled = true
        +    func showRedViewController() {
        +        showRedCalled = true
             }
        -}
        -
        +}

        All the this code is available in this GitHub repo.

        The tests above look simple, don't they? By using this pattern, you remove the need to set up the whole navigation stack containing the view controller under test to verify it's behavior. @@ -61,22 +58,21 @@

        NavigationDelegate in action

        The only downside is that you have to build a spy test double for the NavigationDelegate. Given how little code this involves, I think it's a pretty good tradeoff.

        If you want to test how the type conforming to the NavigationDelegate performs the navigation -a wise thing to do- you can do that in isolation.

        -
        func testPushesRedViewController() {
        -    let navigator = Navigator(navigationController: UINavigationController(rootViewController: UIViewController()))
        +
        func testPushesRedViewController() {
        +    let navigator = Navigator(navigationController: UINavigationController(rootViewController: UIViewController()))
         
             navigator.showRedViewController()
         
        -    _ = expectation(
        -        for: NSPredicate { input, _ in
        -            return (input as? UINavigationController)?.topViewController is RedViewController
        +    _ = expectation(
        +        for: NSPredicate { input, _ in
        +            return (input as? UINavigationController)?.topViewController is RedViewController
                 },
                 evaluatedWith: navigator.navigationController,
        -        handler: .none
        +        handler: .none
             )
        -    waitForEnavigatorpectations(timeout: 1, handler: .none)
        -}
        -
        -

        You can adopt NavigationDelegates today

        + waitForEnavigatorpectations(timeout: 1, handler: .none) +}
        +

        You can adopt NavigationDelegates today

        What I love about this idea is that it is cheap and portable. You don't have to change your application architecture to adopt it. In fact, it fits well with most architectures.

        diff --git a/blog/nerdtree-relative-numbers/index.html b/blog/nerdtree-relative-numbers/index.html index e2e6c52..017a8e1 100644 --- a/blog/nerdtree-relative-numbers/index.html +++ b/blog/nerdtree-relative-numbers/index.html @@ -1,11 +1,10 @@ How to display relative line numbers in NERDTree | mokacoding

        mokacoding

        unit and acceptance testing, automation, productivity

        How to display relative line numbers in NERDTree

        Vim's relative line numbers are great for jumpin around files, and once you get used to them you want to enable them everywhere. Here's how to have NERDTree use relative line numbers.

        -
        " enable line numbers
        +
        " enable line numbers
         let NERDTreeShowLineNumbers=1
         " make sure relative line numbers are used
        -autocmd FileType nerdtree setlocal relativenumber
        -
        +autocmd FileType nerdtree setlocal relativenumber

        There you go 😎.

        diff --git a/blog/nested-type-view-models/index.html b/blog/nested-type-view-models/index.html index b07b07e..2f24e40 100644 --- a/blog/nested-type-view-models/index.html +++ b/blog/nested-type-view-models/index.html @@ -8,25 +8,24 @@

        Nested Type View Model

        Nested types allow us to "nest supporting enumerations, classes, and structures within the definition of the type they support."

        When there is a 1-to-1 relationship between a view and view model, when the view model supports a single view, a nested type is a great way to make that relationship explicit.

        -
        struct BookDetail: View {
        +
        struct BookDetail: View {
         
        -    @ObservedObject private(set) var viewModel: ViewModel
        +    @ObservedObject private(set) var viewModel: ViewModel
         
        -    var body: some View { ... }
        +    var body: some View { ... }
         }
         
         extension BookDetail {
         
        -    class ViewModel: ObservableObject { ... }
        -}
        -
        + class ViewModel: ObservableObject { ... } +}

        You can find a working example of this code in action on GitHub.

        Thanks to the nested type, the full name of the view model is BookDetail.ViewModel. This makes it obvious at a semantic level that the view model is related to BookDetail.

        You could argue that BookDetail.ViewModel is not that different from BookDetailViewModel. Plus, since Xcode has fuzzy auto-completion – when it works, that is – there is no difference when typing the two.

        While that's all true, this approach has some advantages compared to keeping the two concepts in unrelated types.

        -

        Advantages — Clearer and less error-prone

        +

        Advantages — Clearer and less error-prone

        First of all, it's worth reiterating that using a nested type makes the relationship between the two types more evident than merely relying on their names. I feel this modeling expresses the design at a more precise level, making it easier to understand the code.

        Within the view definition, we can reference the view model just as ViewModel, which leaves the code more compact.

        @@ -53,7 +52,7 @@

        One disadvantage with Open Quickly

        Extracting the view models in dedicated files is something you'd probably want to do anyways to keep the domains separated and avoid the chance of merge conflicts when two developers are working on the view and the view model in parallel on different branches. Still, it's annoying to have to do it to find the objects efficiently.

        -

        Yay or Nay?

        +

        Yay or Nay?

        None of the advantages of using nested types for view models are life-changing. This approach won't make your app better from a functionality point of view, nor will it save you time or reduce the chance of making mistakes. It's all syntax sugar, at best.

        diff --git a/blog/nsdateformatter-json-date/index.html b/blog/nsdateformatter-json-date/index.html index bce9547..cd420b9 100644 --- a/blog/nsdateformatter-json-date/index.html +++ b/blog/nsdateformatter-json-date/index.html @@ -8,28 +8,25 @@ Javascript's Date toJSON method, whic is ISO 8601 compliant.

        -
        2016-05-11T19:02:16.238Z
        -

        Here's how to configure NSDateFormatter to handle this date format:

        -
        import Foundation
        +
        2016-05-11T19:02:16.238Z

        Here's how to configure NSDateFormatter to handle this date format:

        +
        import Foundation
         
         extension NSDateFormatter {
         
        -  static func formatterForJSONDate() -> NSDateFormatter {
        -    let formatter = NSDateFormatter()
        -    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        -    formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
        -    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
        +  static func formatterForJSONDate() -> NSDateFormatter {
        +    let formatter = NSDateFormatter()
        +    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        +    formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
        +    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
             return formatter
           }
        -}
        -
        +}

        And here's a test for it:

        -
        func testProperty() {
        -    let now = NSDate()
        -    let nowToJSON = sut.stringFromDate(now)
        -    XCTAssertEqualWithAccuracy(sut.dateFromString(nowToJSON)!.timeIntervalSince1970, now.timeIntervalSince1970, accuracy: 0.001)
        -}
        -
        +
        func testProperty() {
        +    let now = NSDate()
        +    let nowToJSON = sut.stringFromDate(now)
        +    XCTAssertEqualWithAccuracy(sut.dateFromString(nowToJSON)!.timeIntervalSince1970, now.timeIntervalSince1970, accuracy: 0.001)
        +}

        You can see this code live here.

        Leave the codebase better than you found it.

        diff --git a/blog/october-questions/index.html b/blog/october-questions/index.html index 17a6a75..2881f1f 100644 --- a/blog/october-questions/index.html +++ b/blog/october-questions/index.html @@ -10,16 +10,16 @@

        You can ask yourself two extremely useful questions about any given area to drill down into the murky layer: How does it work? and Why does this (have to) happen?

        So this is what I'm gonna do (more) from now on. Spending time asking myself this type of questions around the technologies I use. And, inspired a bit by Jennifer Dewalt (180 websites im 180 days), I'm gonna track everything here. Let's get started!

        -

        October's Questions

        +

        ##October's Questions

        I'll start by trying understand better the tools I use in my daily job. At the moment I'm working as an iOS developer and next to the classic iOS SDK, Objective-C, Xcode and the iPhone Simulator, I'm making massive use of CocoaPods, AFNetworking, and xctool.

        I already have many questions on those technologies and tools, but one thing I've learned about propositions is start small!. So I'll start with only four questions. One per week, this shouldn't be hard to accomplish.

        -

        1 - Xcode

        +

        ###1 - Xcode

        How does it... stores the informations about project and workspace?

        -

        2 - Objective-C

        +

        ###2 - Objective-C

        Why does it... allow us to use the messages syntax AND the dot notation to call methods?

        -

        3 - CocoaPods

        +

        ###3 - CocoaPods

        How does it... generate the workspace and manage the pods in it?

        -

        4 - AFNetworking

        +

        ###4 - AFNetworking

        How does it... wrap Apple's newtworking classes?

        diff --git a/blog/ohhttpstubs/index.html b/blog/ohhttpstubs/index.html index ac25b5f..cbfe15a 100644 --- a/blog/ohhttpstubs/index.html +++ b/blog/ohhttpstubs/index.html @@ -19,25 +19,23 @@ Let me know if you need help with the process.

        The API

        An OHHTTPStubs stub instruction has this structure:

        -
        stub(/* your stub criteria */) { request in
        +
        stub(/* your stub criteria */) { request in
           return /* your response */
        -}
        -
        +}

        There are two pieces that form the stub instruction, the criteria to use to evaluate whether or not a request made by the app should be hijacked, and the stubbed response to return. For example:

        -
        stub(isMethodGET()) { _ in
        +
        stub(isMethodGET()) { _ in
           return OHHTTPStubsResponse(
        -    JSONObject: ["key": "value"],
        +    JSONObject: ["key": "value"],
             statusCode: 200,
             headers: [ "Content-Type": "application/json" ]
           )
        -}
        -
        +}

        Will intercept any GET request and return a simple JSON object { "key": "value" }. Another example:

        -
        stub(isHost("api.myserver.com") && isPath("/resource")) { _ in
        -    guard let path = OHPathForFile("success_resource_response.json", self.dynamicType) else {
        +
        stub(isHost("api.myserver.com") && isPath("/resource")) { _ in
        +    guard let path = OHPathForFile("success_resource_response.json", self.dynamicType) else {
                     preconditionFailure("Could not find expected file in test bundle")
             }
         
        @@ -46,20 +44,18 @@ 

        The API

        statusCode: 200, headers: [ "Content-Type": "application/json" ] ) -} -
        +}

        Will intercept any request towards api.myserver.com/resource and return the content of the JSON file success_resource_response.json located in the test bundle.

        -
        stub(isPath("/foo/bar")) { _ in
        -    let error = NSError(
        +
        stub(isPath("/foo/bar")) { _ in
        +    let error = NSError(
                 domain: "test",
                 code: 42,
                 userInfo: [:]
             )
             return OHHTTPStubsResponse(error: error)
        -}
        -
        +}

        Will stub any request with path "/foo/bar" and make it fail returning an NSError with domain test and code 42.

        This last request is very useful when testing that our network logic handles @@ -78,27 +74,27 @@

        In Practice

        Pretty standard networking code.

        Here's a possible test for the behaviour of APIClient when the request succeeds:

        -
        func testGetResourceSuccess() {
        +
        func testGetResourceSuccess() {
           // Arrange
           //
           // Setup network stubs
        -  let testHost = "te.st"
        -  let id = "42-abc"
        -  let stubbedJSON = [
        +  let testHost = "te.st"
        +  let id = "42-abc"
        +  let stubbedJSON = [
             "id": id,
             "foo": "some text",
             "bar": "some other text",
           ]
        -  stub(isHost(testHost) && isPath("/resources/\(id)")) { _ in
        +  stub(isHost(testHost) && isPath("/resources/\(id)")) { _ in
             return OHHTTPStubsResponse(
        -      JSONObject: stubbedJSON,
        +      JSONObject: stubbedJSON,
               statusCode: 200,
               headers: .None
             )
           }
           // Setup system under test
        -  let client = APIClient(baseURL: NSURL(string: "http://\(testHost)")!)
        -  let expectation = self.expectationWithDescription("calls the callback with a resource object")
        +  let client = APIClient(baseURL: NSURL(string: "http://\(testHost)")!)
        +  let expectation = self.expectationWithDescription("calls the callback with a resource object")
         
           // Act
           //
        @@ -107,9 +103,9 @@ 

        In Practice

        // Assert // XCTAssertNil(error) - XCTAssertEqual(resource?.id, stubbedJSON["id"]) - XCTAssertEqual(resource?.aProperty, stubbedJSON["foo"]) - XCTAssertEqual(resource?.anotherPropert, stubbedJSON["bar"]) + XCTAssertEqual(resource?.id, stubbedJSON["id"]) + XCTAssertEqual(resource?.aProperty, stubbedJSON["foo"]) + XCTAssertEqual(resource?.anotherPropert, stubbedJSON["bar"]) expectation.fulfill() } @@ -119,8 +115,7 @@

        In Practice

        // Tear Down // OHHTTPStubs.removeAllStubs() -} -
        +}

        The test is split in four steps, we start by arranging the inputs for the test and configuring the system under test (sut), we then act and assert that the sut behaved as expected, and finally we tear down any kind of non transient diff --git a/blog/packaging-swift-ipa/index.html b/blog/packaging-swift-ipa/index.html index 2b223fe..3bad7e3 100644 --- a/blog/packaging-swift-ipa/index.html +++ b/blog/packaging-swift-ipa/index.html @@ -1,15 +1,14 @@ Packaging an ipa with Swift files from the terminal | mokacoding

        mokacoding

        unit and acceptance testing, automation, productivity

        Packaging an ipa with Swift files from the terminal

        One day I saw this tweet from my friend Marco Sero

        -

        +

        It looked liked something I should have take note of. So I obviously forgot about it.

        Some days ago I set up the automated build distribution pipeline for a new client, with an app using a bit of Swift. I usually use something similar to this script. It is a pretty battle tested script, but something when wrong.

        And that's when I remembered Marco's tweet and phatblat's script.

        Download the raw script from here, place it somewhere, maybe in the project's root, then simply replace the xcodebuild -exportArchive command with:

        -
        bin/package-swift-ipa.sh "$archive_path" "$(pwd)/$ipa_path"
        -

        Notice the $(pwd) in the second argument. That's because the script is expecting absolute paths, while mine uses relative ones.

        +
        bin/package-swift-ipa.sh "$archive_path" "$(pwd)/$ipa_path"

        Notice the $(pwd) in the second argument. That's because the script is expecting absolute paths, while mine uses relative ones.

        Leave the codebase better than you found it.

        diff --git a/blog/pipe-wrench/index.html b/blog/pipe-wrench/index.html index 77e17dc..c48bf59 100644 --- a/blog/pipe-wrench/index.html +++ b/blog/pipe-wrench/index.html @@ -7,7 +7,8 @@ He was also a mentor to Claude Shannon, the father of the information age.

        One anecdote of Bush's career as an instructor at MIT particularly inspired me: his pipe wrench lecture.

        Bush would greet an auditorium filled with aspiring engineers, hold up a pipe wrench, and challenge them: "Describe this".

        -

        image of a pipe wrench

        +image of a pipe wrench +

        Not the actual pipe wrench showed by Bush, I found this one on Amazon.

        One by one, they would try, and each time Bush would dissect the description, pointing out where it was vague.

        @@ -25,34 +26,29 @@

        Precision

        One way in which a domain representation can be vague is when it allows inconsistent state to occur. If you work in a language with a strong type system, like Swift, you can use precise types to make your domain modeling clearer and make undesirable state unrepresentable.

        For example, when modeling an operation that can either succeed with some data or fail with an error, you could use a type like this:

        -
        struct Operation {
        +
        struct Operation {
           let success: Bool
        -  let data: Data?
        -  let error: Error?
        -}
        -
        + let data: Data? + let error: Error? +}

        This type does the job but leaves room for errors: nothing stops you from creating an instance with success true but data nil or one with values in both data and error.

        -
        let inconsistentOperation = Operation(success: false, data: someData, error: .none)
        -
        +
        let inconsistentOperation = Operation(success: false, data: someData, error: .none)

        Using the Result enum, you can remove this ambiguity at compile time, making it impossible for both data and error to be set simultaneously.

        -
        struct Operation {
        +
        struct Operation {
           let result: Result<Data, Error>
        -}
        -
        +}

        Another useful enum, borrowed from the Elm programming language, is RemoteData: a way to encapsulate the state of a network operation.

        -
        enum RemoteData<T> {
        +
        enum RemoteData<T> {
           case notAsked
           case loading
           case loaded(T)
           case failed(Error)
        -}
        -
        +}

        enums are not the only way tool to make your domain modeling more precise. NonEmpty uses type constrained generics to represent Collections that are not empty.

        -
        // A non-empty array of integers
        -let xs = NonEmpty<[Int]>(1, 2, 3, 4)
        -xs.first + 1 // `first` is non-optional since it's guaranteed to be present
        -
        +
        // A non-empty array of integers
        +let xs = NonEmpty<[Int]>(1, 2, 3, 4)
        +xs.first + 1 // `first` is non-optional since it's guaranteed to be present

        Using NonEmpty adds clarity to the values you define, possibly avoiding runtime crashes by making it impossible to access via subscript an empty array.

        If you had to represent "a collection of unique positive integers where order matters and with at least one element," you could use [Int], or you could combine NonEmpty, OrderedSet, and UInt in NonEmpty<OrderedSet<UInt>>.

        Using [Int] might be simpler but leaves the door open for all sorts of inconsistent instances, like an empty array, an array with negative values, or one with more than one occurrences of the same value. diff --git a/blog/podcasts/index.html b/blog/podcasts/index.html index 56c8477..5765846 100644 --- a/blog/podcasts/index.html +++ b/blog/podcasts/index.html @@ -2,29 +2,29 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

        Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

        mokacoding

        unit and acceptance testing, automation, productivity

        Podcasts, grow your brain through soundwaves

        Recently I've been listening to a lot of podcasts, actually too many to keep up with. I wanted to try to to learn through soundwaves, in a sort of passive way while doing something in which my brain power -if we want to go as far as calling it power- is wasted, like washing the dishes, or walking somewhere. I found podcasts a great way to get in touch with new things that I can then come back to and look in more deeply. It's also nice to hear all the guests speaking, it's a fraction of the experience you get when going to a conference.

        These are my favourite podcasts, in random order:

        -

        Build Phase

        +

        ###Build Phase

        At the moment I'm a professional iOS developer. This podcast is a weekly source of thoughts, new things, and inspiration. Gordon and Adam always start like they don't know what they're talking about, but they quickly get back on track and keep up a rich and fun podcast.

        One thing I learned: The XVim plug-in for Xcode.

        -

        Developing Perspective

        +

        ###Developing Perspective

        This podcast is about what it's like to be a human being, not a super start. David Smith is a indie iOS developer and shares it's views and experience on this world. I like the simplicity of this podcast, and the sort of comfort I get from discovering that even successful developers have problems similar to mine.

        One thing I learned: It's fine to make mistakes, as long as you take responsibilty for them and try to learn a lesson.

        -

        RubyRouges

        +

        ###RubyRouges

        As I said I'm working as an iOS developer, but at night I like to write readable code. With Ruby and Coffeescript. The RubyRouges crew is too long to be listed. This guys know their Ruby and the usually either have a guest or a book to talk about. But don't get fouled by the name, this podcast is more about good programming techniques and mentality than Ruby as a language itself.

        One thing I learned: Getting into the habit of spending 15-20 minutes a day on "tools sharpening".

        -

        Giant Robots Smashing into other Giant Robots

        +

        ###Giant Robots Smashing into other Giant Robots

        Produced by thoughtbot, the same company behind Build Phase, this weekly podcast has a different guest everytime, covering various topics always realted to the world of development, but without being too techy.

        It's worth mentioning that the guys at thoughtbot are also the developers of two gems I can't live without when doing Rails apps: factory_girl and shoulda.

        One thing I learned: I can't recall anything tangible I learned form this podcast at the moment. Althought the episodes with Nathan Barry and Jeff Atwood have been really inspirational.

        -

        This Agile Life

        +

        ###This Agile Life

        Another weekly podcast related to the world of programming, but not too techy. Try to guess what this is about? This agile team of speakers goes deep into an agile topic every week, and it's a great source of information, specially for someone like me how's always been at the boarder line of the agile development without being really able to implement it completely.

        One thing I learned: The best estimate is no-estimate. More here.

        -

        Other podcast worth mentioning

        +

        ###Other podcast worth mentioning

        -

        And one more thing...

        +

        ###And one more thing...

        Aussie Mac Zone. This podcast is simply hilarious. I love these guys! They keep me posted on all the news in the Apple world in the most fun way ever!

        If you have any other podcast on the line of these one that you want to share, tweet me @mokagio.

        Happy coding!

        diff --git a/blog/pre-commit-hooks/index.html b/blog/pre-commit-hooks/index.html index 981d422..c5fa159 100644 --- a/blog/pre-commit-hooks/index.html +++ b/blog/pre-commit-hooks/index.html @@ -10,32 +10,30 @@

        The pre-commit hook

        The main use case for this hook is doing some validation of the changes to be committed, and failing the commit if something is not acceptable. We can fail the commit by making pre-commit return a non zero value.

        Running xUnique as a pre-commit hook

        As we just said, running code before a commit is as easy as writing the command in the pre-commit hook file.

        -
        #!/bin/sh
        +
        #!/bin/sh
         
         # uniquify and sort the Xcode projct files
        -python -mxUnique -u -s "MyAwesomeApp.xcodeproj/project.pbxproj" &> /dev/null
        -
        +python -mxUnique -u -s "MyAwesomeApp.xcodeproj/project.pbxproj" &> /dev/null

        As usual you can follow along using the example project on GitHub.

        If you try that you'll notice that the project.pbxproj that is committed is not uniquified. That is because even if xUnique runs, the changes are not automatically added to the commit. And that's a good thing! Since Git allows users to commit only a subset of the changes made to a file is better to always let the user decide what they want to commit. At least that's my opinion in most of the scenarios I've seen.

        Lucky for us xUnique has an option to return 1 if the project needed to be uniquified, and therefore fail the commit.

        -
        #!/bin/sh
        +
        #!/bin/sh
         
         # uniquify and sort the Xcode projct files
         python -mxUnique -u -s -c "xUnique.xcodeproj/project.pbxproj" &> /dev/null
         
         if [ $? -ne 0 ]; then
        -  cat <<EOF
        +  cat <<EOF
         This commit has been aborted because the project file needed to be uniquified.
         You can add those changes and commit again.
        -EOF
        +EOF
           exit 1
        -fi
        -
        +fi

        The <<EOF is called here document and it's a good way to keep shell scripts that need to output a lot of text clean.

        Running multiple scripts in a hook

        Once you'll get into pre-commit hooks you'll want to use more, you are going to want to run multiple scripts before your commits. A naive way to do this is to write all the scripts one after the other in the pre-commit, but we can do better than that, right?

        We could for example have a single file for each script, and have the hook file simply run them in sequence.

        -
        #!/bin/sh
        +
        #!/bin/sh
         
         for hook in "uniquify-hook.sh" "trailing-whitespace-hook.sh";
         do
        @@ -43,12 +41,11 @@ 

        Running multiple scripts in a hookif [ $? -ne 0 ]; then exit 1 fi -done -

        +done

        Bootstrap script

        What's the point of this setup if we are the only one that use it? In the case of running commands like xUnique or clang-format in our pre-commit hook if we are the only ones that does that in the team the result would be counter productive. We want to share the hooks, and to be sure that all the team sets them up.

        A way to achieve this is of course to simplify the setup process down to a single command, running a bootstrap script for example.

        -
        #!/bin/sh
        +
        #!/bin/sh
         
         echo "Configuring pre-commit hook..."
         
        @@ -57,11 +54,10 @@ 

        Bootstrap script

        ln git-hooks/pre-commit.sh .git/hooks/pre-commit echo "Done" else - cat <<EOF + cat <<EOF A pre-commit hook exists already. -EOF -fi -
        +EOF +fi

        The code above expects us to have a git-hooks folder tracked in the repo, and creates a symbolic link between the pre-commit file in there and the one in .git/hooks. Please remember to make your pre-commit script executable, chmod u+x git-hooks/pre-commit.

        Bonus: a touch of color

        We are all set now with our script or scripts running before every commit, keeping the codebase and the Git log cleaner and our productivity high. But there a final touch that can help us achieve an even better result, color.

        @@ -69,16 +65,15 @@

        Bonus: a touch of color

        Color is so important that some TDD practitioners believe that the "red-green-refactor" mantra should reflect in the color of the test runner output. When a test fails the output should be red, to keep the developer under pressure, and when the tests are all successful the output should be green, to relax and reward the developer. Seeing the red in the terminal, they say, makes them a little bit uncomfortable, and it works as a push to develop the implementation faster, to get back to the green relaxing state.

        The way is color our shell scripts is using the ANSII colors, see this and this.

        I would usually use the red color. \e[31m.

        -
        red="\033[31m"
        +
        red="\033[31m"
         reset="\033[m"
         
         printf "$red"
        -cat <<EOF
        +cat <<EOF
         This commit has been aborted because the project file needed to be uniquified.
         You can add those changes and commit again.
        -EOF
        -printf "$reset"
        -
        +EOF +printf "$reset"

        Notice the final usage of \e[39m, that resets the foreground color to the default one, and the ... echo option which simply makes is not print the trailing newline.

        You can find a complete example of this multiple and colored pre-commit setup in the companion project on GitHub.

        A word of caution

        diff --git a/blog/prevent-swiftui-app-loading-in-unit-tests/index.html b/blog/prevent-swiftui-app-loading-in-unit-tests/index.html index 5ce2660..a5aa2ba 100644 --- a/blog/prevent-swiftui-app-loading-in-unit-tests/index.html +++ b/blog/prevent-swiftui-app-loading-in-unit-tests/index.html @@ -6,15 +6,15 @@

        One of the first things I do when taking up a new project, whether greenfield or established, is preventing the unit tests from running the app startup flow.

        I published a post about this back in 2016, when UIKit was the only framework in town. It's now time to revisit it for SwiftUI based applications.

        -

        SwiftUI App

        -
        // AppLauncher.swift
        +

        SwiftUI App

        +
        // AppLauncher.swift
         import SwiftUI
         
        -@main
        +@main
         struct AppLauncher {
         
        -    static func main() throws {
        -        if NSClassFromString("XCTestCase") == nil {
        +    static func main() throws {
        +        if NSClassFromString("XCTestCase") == nil {
                     MyAwesomeApp.main()
                 } else {
                     TestApp.main()
        @@ -24,7 +24,7 @@ 

        SwiftUI App

        struct TestApp: App { - var body: some Scene { + var body: some Scene { WindowGroup { Text("Running Unit Tests") } } } @@ -34,9 +34,8 @@

        SwiftUI App

        struct MyAwesomeApp: App { - var body: some Scene { ... } -} -
        + var body: some Scene { ... } +}

        You can find the source code for this example on GitHub.

        Let's unpack what the code does. First of all, the top-level entry point for the program flow, marked by the @main attribute is AppLauncher. @@ -49,11 +48,11 @@

        SwiftUI App

        Finally, if AppLauncher determines that the tests are running, it returns a dummy App implementation.

        SwiftUI with UIKit App Delegate

        If you are mix-and-matching SwiftUI and UIKit, that is, if you have an app with SwiftUI interface and "UIKit App Delegate" life cycle, then you can use the same approach as a UIKit only app.

        -
        // main.swift
        +
        // main.swift
         import UIKit
         
        -private func delegateClassName() -> String? {
        -  if NSClassFromString("XCTestCase") == nil {
        +private func delegateClassName() -> String? {
        +  if NSClassFromString("XCTestCase") == nil {
             NSStringFromClass(AppDelegate.self)
           } else {
             return nil
        @@ -72,8 +71,7 @@ 

        SwiftUI with UIKit App Delegate

        class AppDelegate: UIResponder, UIApplicationDelegate { // ... -} -
        +}

        This example is also available on GitHub.

        Another option is to use an AppLauncher returning a different UIApplicationDelegate implementation for the tests, like in the SwiftUI only case. I find this approach with a dedicated main.swift file easier to discover, and I like how there is no need for a dummy app delegate when running the tests.

        diff --git a/blog/prevent-unit-tests-from-loading-app-delegate-in-swift/index.html b/blog/prevent-unit-tests-from-loading-app-delegate-in-swift/index.html index c98faba..0579eb0 100644 --- a/blog/prevent-unit-tests-from-loading-app-delegate-in-swift/index.html +++ b/blog/prevent-unit-tests-from-loading-app-delegate-in-swift/index.html @@ -4,11 +4,11 @@

        Update 2018/09/19: Updated to work with Swift 4.2. You can find the previous implementations looking at the history of the demo project on GitHub.

        Credits to Witold Skibniewski and Paul Boot who shared the Swift 2.0 implementation in Jon Reid's post "How to Easily Switch Your App Delegate for Testing", and to Jon for wirting the post that started the conversation.

        Here's how to have a dedicated AppDelegate for the unit test target in Swift:

        -
        // main.swift
        +
        // main.swift
         import UIKit
         
        -private func delegateClassName() -> String? {
        -  return NSClassFromString("XCTestCase") == nil ? NSStringFromClass(AppDelegate.self) : nil
        +private func delegateClassName() -> String? {
        +  return NSClassFromString("XCTestCase") == nil ? NSStringFromClass(AppDelegate.self) : nil
         }
         
         UIApplicationMain(
        @@ -23,8 +23,7 @@
         
         class AppDelegate: UIResponder, UIApplicationDelegate {
           // ...
        -}
        -
        +}

        Note how we have removed the @UIApplicationMain annotation from the app delegate class definition that Xcode generates for us, as that is now implemented by main.swift.

        You can checkout this example for a full project using this approach.

        I really like how leaner and faster the test target is without having to perform all the initialization code that is done in the normal AppDelegate. I encourage you to adopt this simple approach.

        diff --git a/blog/quick-beforeeach-aftereach-behaviour/index.html b/blog/quick-beforeeach-aftereach-behaviour/index.html index 812c616..5fed1cc 100644 --- a/blog/quick-beforeeach-aftereach-behaviour/index.html +++ b/blog/quick-beforeeach-aftereach-behaviour/index.html @@ -2,10 +2,10 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

        Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

        mokacoding

        unit and acceptance testing, automation, productivity

        Quick beforeEach and afterEach behaviour

        I am sometimes unsure of what to expect from nested beforeEach and/or afterEach calls in Quick.

        Luckily we can verify how they behave with a simple example spec, which you can find on GitHub:

        -
        import Quick
        +
        import Quick
         
         class Spec: QuickSpec {
        -  override func spec() {
        +  override func spec() {
             describe("beforeEach and afterEach behaviour") {
               beforeEach {
                 print("⭐️ top before each")
        @@ -46,10 +46,9 @@
               }
             }
           }
        -}
        -
        +}

        If we run this test the console output, cleared of all the test framework information, will be:

        -
        behaviour - some context - example 1
        +
        behaviour - some context - example 1
         ⭐️ top before each
         👉 context before each
         😊 example 1
        @@ -82,8 +81,7 @@
         🍎 context before each
         😜 example 2
         🍎 context after each
        -⭐️ top after each
        -

        This shows us that all and only the beforeEach and afterEach encountered in the path from the start of the spec are run before and after each it block is executed.

        +⭐️ top after each

        This shows us that all and only the beforeEach and afterEach encountered in the path from the start of the spec are run before and after each it block is executed.

        That's important to keep in mind and can open the door to some interesting simplifications of how the spec is written.


        I set out to write this post to share what I thought was a gotcha with the behaviour of beforeEach and afterEach have in Quick, but the example project that I made to verify it revealed that my mental model was incorrect. That's for the best, as the actual behaviour is better than what I thought it was.

        diff --git a/blog/quick-beforesuite-aftersuite-behaviour/index.html b/blog/quick-beforesuite-aftersuite-behaviour/index.html index 034b556..2b06f97 100644 --- a/blog/quick-beforesuite-aftersuite-behaviour/index.html +++ b/blog/quick-beforesuite-aftersuite-behaviour/index.html @@ -7,15 +7,17 @@

        beforeSuite

        Defines a closure to be run prior to any examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run.

        + +

        afterSuite

        Defines a closure to be run after all of the examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run.

        The example code from the previous example has been updated adding calls to beforeSuite and afterSuite.

        -
        import Quick
        +
        import Quick
         
         class Spec: QuickSpec {
        -  override func spec() {
        +  override func spec() {
             beforeSuite {
               print("☕️ before suite")
             }
        @@ -42,11 +44,10 @@
               print("🗑 after suite")
             }
           }
        -}
        -
        +}

        In the code above beforeSuite and afterSuite are positioned at the very top and very bottom of the test, but you can put them anywhere inside a describe or context.

        Can you guess how the console log will look like?

        -
        ☕️ before suite
        +
        ☕️ before suite
         😈 an after suite call you weren't aware of
         
         behaviour - some context - example 1
        @@ -66,9 +67,8 @@
         ⭐️ top after each
         
         🗑 after suite
        -😈 an after suite call you weren't aware of
        -

        Hang on a second, where do those 😈 logs come from?!

        -

        The danger of using beforeSuite and afterSuite

        +😈 an after suite call you weren't aware of

        Hang on a second, where do those 😈 logs come from?!

        +

        The danger of using beforeSuite and afterSuite

        Quick will look for all the beforeSuite and afterSuite calls in all your test suite, and run them respectively all at the start and all at the end.

        Those unexpected 😈 console logs are simply defined in another spec in the project.

        This is one of the danger of beforeSuite and afterSuite, there is no way other that by doing a text search to know how many such calls there are and where.

        @@ -76,13 +76,12 @@

        The danger of using The other danger is that being able to fiddle with state in the unit tests can lead us to write tests that are not as isolated and robust as they should be. If unit tests are isolated and simple to setup then the code they test will be simple and easy to setup as well.

        Yes, beforeSuite and afterSuite can be life savers when you need to get started writing test on legacy code and you really cannot take out certain assupmtions baked in it. They allow you to work around them, and get the job done.

        In such cases though, I would encourage you to leave a big FIXME note there:

        -
        // FIXME: Doing this now because the app makes assumptions that impact each
        +
        // FIXME: Doing this now because the app makes assumptions that impact each
         // unit test.
         //
         // Need to allocate proper time to refactor for isolation.
         //
        -// If you are reading this comment after <date> get in touch with <person>.
        -

        Until next time:

        +// If you are reading this comment after <date> get in touch with <person>.

        Until next time:

        👋 Leave the codebase bettern than you found it

        diff --git a/blog/rails-add-has-many-association-to-existing-model/index.html b/blog/rails-add-has-many-association-to-existing-model/index.html index 5eee748..2979d95 100644 --- a/blog/rails-add-has-many-association-to-existing-model/index.html +++ b/blog/rails-add-has-many-association-to-existing-model/index.html @@ -3,82 +3,72 @@

        mokacoding

        unit and acceptance testing, automation, productivity

        Rails: adding a new has_many association to an existing model

        This post shows how to evolve an existing schema adding new models and association in Ruby on Rails. I did this today at work, had to put together pieces from the Rails Guides and other resources.

        The starting point is a schema with a single items table. We want to have a level system, where each level is made up by a group of challenges, and each challenge contains a number of items.

        Note: I'm using rspec and shoulda to write the tests.

        -

        Step 1 - Create the Challenge model

        +

        Step 1 - Create the Challenge model

        Creating a new empty model is easy, just run

        -
        rails g model challenge
        -
        +
        rails g model challenge

        and the resulting migration

        -
        rake db:migrate RAILS_ENV=development
        -
        -

        Step 2 - Add the association "challenge has many items"

        +
        rake db:migrate RAILS_ENV=development
        +

        Step 2 - Add the association "challenge has many items"

        We want to have a model that makes these tests pass:

        -
        describe Challenge do
        +
        describe Challenge do
           it { should have_many :items }
         end
         
         describe Item do
           it { should belong_to :challenge }
        -end
        -
        +end

        The first thing would be to write a migration, but there is no way to generate a migration for an association with the rails generate migration command. So we have to do it manually, and then write the migration to update the db and schema.

        -
        class Challenge < ActiveRecord::Base
        +
        class Challenge < ActiveRecord::Base
             has_many :items
         end
         
         class Item < ActiveRecord::Base
             belongs_to :challenge
        -end
        -
        -
        rails g migration AddItemsAssociationToChallenge
        -
        +end
        +
        rails g migration AddItemsAssociationToChallenge

        This is the code to put in the resulting migartion file

        -
        class AddItemsAssociationToChallenge < ActiveRecord::Migration
        -  def self.up
        +
        class AddItemsAssociationToChallenge < ActiveRecord::Migration
        +  def self.up
             add_column :items, :challenge_id, :integer
             add_index 'items', ['challenge_id'], :name => 'index_challenge_id'
           end
         
        -  def self.down
        +  def self.down
             remove_column :items, :challenge_id
           end
        -end
        -
        +end

        Finally let's run rake db:migrate and rspec (because we're using binstub aren't we?) and everything should be fine.

        -

        Step 3 – The Levels

        +

        Step 3 – The Levels

        The process for the levels will be the same as before, a good way to commit the steps to memory. We want this specs to pass:

        -
        describe Level do
        +
        describe Level do
             it { should have_many :challenges }
         end
         
         describe Challenge do
             it { should belong_to :level }
        -end
        -
        +end

        So we generate a migration

        -
        rails g migration AddChallengesAssociationToLevel
        -
        +
        rails g migration AddChallengesAssociationToLevel

        and we write this inside it

        -
        class AddChallengeAssociationToLevel < ActiveRecord::Migration
        -  def self.up
        +
        class AddChallengeAssociationToLevel < ActiveRecord::Migration
        +  def self.up
             add_column :challenges, :level_id, :integer
             add_index 'challenges', ['level_id'], :name => 'index_level_id'
           end
         
        -  def self.down
        +  def self.down
             remove_column :challenges, :level_id
           end
        -end
        -
        +end

        finally we cannot forget to manually update our models

        -
        class Level < ActiveRecord::Base
        +
        class Level < ActiveRecord::Base
             has_many :challenges
         end
         
         class Challenge < ActiveRecord::Base
             has_many :items
             belongs_to :level
        -end
        -
        +end

        That's all. Nothing incredibly hard, but still not obvious for someone who mainly writes Objective-C. Happy coding!

        diff --git a/blog/red-green-and-dont-forget-refactor/index.html b/blog/red-green-and-dont-forget-refactor/index.html index f2ecfe3..6bdeaf3 100644 --- a/blog/red-green-and-dont-forget-refactor/index.html +++ b/blog/red-green-and-dont-forget-refactor/index.html @@ -11,7 +11,7 @@

        The good code delusion

        The TDD process as Kent Beck describes it Test Driven Development by Examples starts by writing a failing test, then "just enough code to make it pass".

        If you allow yourself to write crappy code good enough to make your test pass you split the development process in two pieces. Make it work first, make it good later.

        Here's another Kent Beck quote. "Make it work. Make it right. Make it fast."

        -

        Split "what it does" from "how it does it"

        +

        Split "what it does" from "how it does it"

        There's something to be said about this intentional split between making the test pass and cleaning up the code.

        First you focus on what the code should do, by making the test pass. Once the test is green you have the freedom to focus entirely on how the code looks and feels, and how it fits in the rest of your codebase.

        Because you have a suite of succeeding tests you can refactor and reshape your code with the confidence you won't break its behaviour.

        @@ -19,7 +19,7 @@

        Split "what it does"

        Keep up the pace

        The "red, green, refactor" dance helps you keep a steady development pace. Make a change, run the tests. Make a change, run the tests. Make a change, run the tests.

        Do this long enough without interruptions and you'll reach a state of flow. Time will fly and you'll be achieving top results. It's an addictive game, where the goal is to make tests green and keep them green while making changes.

        -

        Sofware that's easier to change

        +

        Sofware that's easier to change

        Failing to make time for refactoring is one of the reasons code quality deteriorates. Communicating the value and need for refactoring to non-tech people is hard. There's always a pressing deadline, or another important™ thing to work on.

        Practicing "red, green, refactor" makes improving the code part of the development process. It's something you do as you go, a little bit every time.

        Yes, there will be the need for big refactors from time to time. They won't be as hard to do though, as the code on which you'll have to work will be clean and tidy.

        diff --git a/blog/referential-transparency-in-swift/index.html b/blog/referential-transparency-in-swift/index.html index 0682fef..0811903 100644 --- a/blog/referential-transparency-in-swift/index.html +++ b/blog/referential-transparency-in-swift/index.html @@ -5,33 +5,27 @@

        An expression [that] can be replaced with its corresponding value without changing the program's behavior.

        Here's an example in Swift:

        -
        func rtIncrement(_ number: Int) -> Int {
        -    return number + 1
        -}
        -
        +
        func rtIncrement(_ number: Int) -> Int {
        +    return number + 1
        +}

        Functions that are not referentially transparent are referentially opaque.

        -
        var i = 0
        +
        var i = 0
         
        -func roIncrement(_ number: Int) -> Int {
        -    i += 1
        -    return number + i
        -}
        -

        Take these two expressions:

        -
        let a = rtIncrement(x) + rtIncrement(y) * (rtIncrement(x) - rtIncrement(x))
        -let b = rtIncrement(x)
        -
        +func roIncrement(_ number: Int) -> Int { + i += 1 + return number + i +}

        Take these two expressions:

        +
        let a = rtIncrement(x) + rtIncrement(y) * (rtIncrement(x) - rtIncrement(x))
        +let b = rtIncrement(x)

        Referential transparency means that we can replace an invocation of rtIncrement with its value. That way, we can simplify a into:

        -
        rtIncrement(x) + rtIncrement(y) * 0
        -
        +
        rtIncrement(x) + rtIncrement(y) * 0

        and then into:

        -
        rtIncrement(x) + 0
        -
        +
        rtIncrement(x) + 0

        Because of referential transparency, a == b is true; the two expressions are equivalent.

        The same cannot be said for the referentially opaque counterpart.

        -
        let a = roIncrement(x) + roIncrement(y) * (roIncrement(x) - roIncrement(x))
        -let b = roIncrement(x)
        -
        +
        let a = roIncrement(x) + roIncrement(y) * (roIncrement(x) - roIncrement(x))
        +let b = roIncrement(x)

        Every time roIncrement is called, the global value i changes. So, roIncrement(x) - roIncrement(x) is not equal to 0, but -1 (x + i - (x + (i + 1)) = x + i - x - i - 1).

        So what? diff --git a/blog/remove-trailing-whitespaces-in-folder-files/index.html b/blog/remove-trailing-whitespaces-in-folder-files/index.html index cc7d764..cd3a64a 100644 --- a/blog/remove-trailing-whitespaces-in-folder-files/index.html +++ b/blog/remove-trailing-whitespaces-in-folder-files/index.html @@ -1,8 +1,7 @@ How to remove trailing whitespaces from all files in a folder | mokacoding

        mokacoding

        unit and acceptance testing, automation, productivity

        How to remove trailing whitespaces from all files in a folder

        From the Terminal, cd into the root folder containing the files with trailing whitespaces, then run the following command:

        -
        find . -not \( -name .git -prune \) -type f -print0 | LANG=C LC_CTYPE=C xargs -0 sed -i '' -E "s/[[:space:]]*$//"
        -
        +
        find . -not \( -name .git -prune \) -type f -print0 | LANG=C LC_CTYPE=C xargs -0 sed -i '' -E "s/[[:space:]]*$//"

        Today I had a play around with BuildSettingsExctractor, an app that reads a project.pbxproj file from the Xcode IDE and extracts all the build settings into dedicated files.

        The app added helpful documentation comments to each setting it extracts, but the formatting was a bit off: the empty comment lines had a trailing whitespace.

        diff --git a/blog/replace-triple-boolean-with-enum/index.html b/blog/replace-triple-boolean-with-enum/index.html index 5891fe3..9fff7a9 100644 --- a/blog/replace-triple-boolean-with-enum/index.html +++ b/blog/replace-triple-boolean-with-enum/index.html @@ -8,7 +8,7 @@ As long as our ORM does its job properly, a nullable Boolean column translates to an Optional<Bool> value, and we're always forced to deal with its nullability.

        Regardless of how strong the type system is, an Optional<Bool>, or Bool?, doesn't solve the ambiguity of the null state: what should the code do when the value is neither true nor false?

        Let's make this practical; here's some code to prepare a meal:

        -
        guard let prefersVegetarian: Bool? = user.prefersVegetarian() else {
        +
        guard let prefersVegetarian: Bool? = user.prefersVegetarian() else {
           return askForVegeratarianPreference()
         }
         
        @@ -16,17 +16,15 @@
           prepareFalafel()
         } else {
           prepareSteak()
        -}
        -
        +}

        Here's a different approach:

        -
        let prefersVegetarian: user.prefersVegetarian() ?? true
        +
        let prefersVegetarian: user.prefersVegetarian() ?? true
         
         if prefersVegetarian() {
           prepareFalafel()
         } else {
           prepareSteak()
        -}
        -
        +}

        In the first case, if the Bool? value is .none, then the app should ask the user for its preference before preparing the meal. In the second, when the preference is .none, the author decided it's best to assume the user is vegetarian, to avoid presenting them with a meal they wouldn't eat.

        Yet another approach could be to default to false when there is no preference and prepare a steak, under the assumption that the majority of the users won't be vegetarian.

        @@ -37,18 +35,16 @@ Without extra context, there's a two-in-three chance of making a mistake when handling the null state.

        We could compensate for this ambiguity by adding documentation to the method, but what's the guarantee consumers are actually going to read it?

        There is a simple solution to the Three-state Boolean ambiguity, one which also makes the code clearer without leaving room for error: use an enum instead.

        -
        enum Preference {
        -  case `true`
        -  case `false`
        +
        enum Preference {
        +  case `true`
        +  case `false`
           case notAsked
        -}
        -
        -
        switch user.prefersVegetarian() {
        +}
        +
        switch user.prefersVegetarian() {
         case .notAsked: askForVegeratarianPreference()
         case .true: prepareFalafel()
         case .false: prepareSteak()
        -}
        -
        +}

        If we don't want to make an assumption on the default value when the preference is missing, then defining an enum to model the scenario removes the ambiguity. By using a more specialized type than Bool? as the return value for prefersVegetarian(), we can make it clearer for the consumers of the code what to do when there is no stored preference.

        By the way, did you know that Optional is an enum, too?

        diff --git a/blog/ruby-for-ios-developers-bundler/index.html b/blog/ruby-for-ios-developers-bundler/index.html index 5ba7b24..f1947b1 100644 --- a/blog/ruby-for-ios-developers-bundler/index.html +++ b/blog/ruby-for-ios-developers-bundler/index.html @@ -33,30 +33,26 @@

        Setting up Bundler for iOS projects using version 1.0.0.beta.3 of CocoaPods, you like leaving on the edge, and want to make sure they'll use it as well. It's time to setup Bundler!

        Bundler is a Ruby tool itself, so you can install it like this:

        -
        gem install bundler
        -

        Once installed you can setup your project to use Bundler with this command from +

        gem install bundler

        Once installed you can setup your project to use Bundler with this command from the root of your project:

        -
        bundle init
        -

        Note how the executable is called bundle while the tool is call Bundler. If +

        bundle init

        Note how the executable is called bundle while the tool is call Bundler. If you think about it it does make sense, as you us a bundler to bundle things, but we can all agree that it is a confusing name choice.

        This will generate a template Gemfile. Like a Podfile, a Gemfile is actually a Ruby file in which you can use a special DSL to specify which dependencies you are using, and their version.

        This is how a Gemfile for an iOS project might look like:

        -
        source "https://rubygems.org"
        +
        source "https://rubygems.org"
         
         gem 'cocoapods', '1.0.0.beta.3'
        -gem 'fastlane', '~> 1.57.0'
        -
        +gem 'fastlane', '~> 1.57.0'

        The string after the gem names informs Bundler on the version requirement. In our case CocoaPods should be exactly at version 1.0.0.beta.3, while Fastlane latest version that is greater or equal than 1.57.0, but less that 1.58.0.

        Fun fact: Bundler and CocoaPods share the same dependency resolution library, molinillo.

        To install your dependencies simply run:

        -
        bundle install
        -

        Bundle Exec

        +
        bundle install

        Bundle Exec

        Installing the right version of a given tool is only the start, actually using the tool is what matters.

        I can sometimes happen to be working on different projects at the same time which are using different versions of a tool. Sometimes is not wise to always @@ -66,8 +62,7 @@

        Setting up Bundler for iOS projects you can rely on Bundler to make sure you are actually using your tools in the version specified in the Gemfile. This can be done by calling them through Bundler via bundle exec, for example:

        -
        bundle exec pod install
        -

        That's quite verbose, so I'd recommend to use an alias) +

        bundle exec pod install

        That's quite verbose, so I'd recommend to use an alias for that. Mine is be, I actually have two special aliases for CocoaPods and Fastlane, bp and bf.


        diff --git a/blog/ruby-for-ios-developers/index.html b/blog/ruby-for-ios-developers/index.html index 798c1c2..c447e7b 100644 --- a/blog/ruby-for-ios-developers/index.html +++ b/blog/ruby-for-ios-developers/index.html @@ -44,24 +44,20 @@

        Not all Rubies are made equal

        harmony.

        ruby-install setup

        Both ruby-install and chruby can be easily installed via Homebrew.

        -
        brew install ruby-install
        -

        You can now easily install versions of Ruby system wise like this:

        -
        ruby-install --system ruby 2.3.0
        -

        You can leave the --system option out if want to install it only for your +

        brew install ruby-install

        You can now easily install versions of Ruby system wise like this:

        +
        ruby-install --system ruby 2.3.0

        You can leave the --system option out if want to install it only for your local user.

        Pro-tip: ruby-install --system --latest ruby will install the latest version.

        Installing Rubies is only half of our job, now we need to reliably set the proper version and swap between them. This is chruby's job.

        chruby setup

        -
        brew install chruby
        -

        Once brew has installed chruby, open your .bashrc or .zshrc and paste +

        brew install chruby

        Once brew has installed chruby, open your .bashrc or .zshrc and paste these two lines at the bottom. If you don't know what those files are you should read this first.

        -
        source /usr/local/opt/chruby/share/chruby/chruby.sh
        -source /usr/local/opt/chruby/share/chruby/auto.sh
        -

        The first line will make sure that chruby is loaded in your shell. The +

        source /usr/local/opt/chruby/share/chruby/chruby.sh
        +source /usr/local/opt/chruby/share/chruby/auto.sh

        The first line will make sure that chruby is loaded in your shell. The second makes chruby automatically switch Ruby version based on the content of the .ruby-version file in the current directory. Automatically switching is an optional feature that you might not need as an iOS developer, but I still @@ -69,8 +65,7 @@

        chruby setup

        Since you just edited the configuration of your shell you will need to open a new terminal window to load them. Alternatively you can source ~/.bashrc.

        Congratulations, you can now set and change your Ruby version using:

        -
        chruby 2.3.0
        -

        That's it.

        +
        chruby 2.3.0

        That's it.


        This post showed you how to gain control on your Ruby so that you can reliably choose which version to use, and install gems without worry. In the next post diff --git a/blog/running-one-test-in-xcode/index.html b/blog/running-one-test-in-xcode/index.html index 424ee91..db516cd 100644 --- a/blog/running-one-test-in-xcode/index.html +++ b/blog/running-one-test-in-xcode/index.html @@ -38,12 +38,11 @@

        From the scheme

        You might disable some tests and accidentally check-in the change to the scheme, and suddenly find yourself missing an important part of your unit tests suite.

        From the terminal

        If you are running your tests from the terminal, you can use the -only-testing xcodebuild flag to run a subset of tests.

        -
        xcodebuild test \
        +
        xcodebuild test \
           -scheme YourScheme \
           -project YourProject.xcodeproj \
           -destination 'platform=iOS Simulator,name=iPhone Xs' \
        -  -only-testing YourTests/YourClassTests/testSomething
        -

        You can add as many -only-testing as you want.

        + -only-testing YourTests/YourClassTests/testSomething

        You can add as many -only-testing as you want.

        The option supports different granularities of identifiers: TestTarget[/TestClass[/TestMethod]]. This means that in the example above you can run all the tests in YourClassTests by using -only-testing YourTests/YourClassTests.

        Worth noting that you can also run all the tests other than a subset, using the -skip-testing option instead.

        @@ -51,14 +50,13 @@

        Bonus: Focused tests in Quick

        If you are using the testing framework Quick to enjoy a more descriptive way of defining your tests you might notice that Xcode doesn't add the diamonds in the gutter.

        You can still run a subset of tests by focusing them. This can be done by adding an f in front of on an example or group: fit, fcontext, fdescribe.

        -
        fit("is loud") {
        +
        fit("is loud") {
           // ...only this focused example will be run.
         }
         
         it("has a high frequency") {
           // ...this example is not focused, and will not be run.
        -}
        -
        +}

        A word of caution

        Running one test or a subset of tests will make your feedback loop faster, but will also reduce the confidence in your change not breaking any part of the codebase.

        My recommendation is to run the subset of tests for the code you are working on only during the intermediate steps of development. diff --git a/blog/running-tests-from-the-terminal/index.html b/blog/running-tests-from-the-terminal/index.html index 03480e6..bef704a 100644 --- a/blog/running-tests-from-the-terminal/index.html +++ b/blog/running-tests-from-the-terminal/index.html @@ -3,68 +3,67 @@

        mokacoding

        unit and acceptance testing, automation, productivity

        How to run Xcode tests from the terminal

        This post shows how to run Xcode unit tests and UI tests from your terminal and how to format the output for readability with xcbeautify and xcpretty.

        Running the tests from the command line is a necessary step for Continuous Integration and can come in handy when working solo, too. For example, you might want to run a script to automate publishing a build to TestFlight and run the unit and UI test suites as a pre-check.

        -

        Running tests with xcodebuild

        +

        Running tests with xcodebuild

        When you need to interact with an Xcode project from the terminal, xcodebuild is the first place to look in. This command-line tool allows you to perform different actions on an Xcode project or workspace, such as building, archiving, querying information, and of course, testing.

        The test action is what you use to run tests from a certain scheme in an Xcode project:

        -
        xcodebuild \
        +
        xcodebuild \
           -project MyAwesomeApp.xcodeproj \
           -scheme MyAwesomeApp \
           -sdk iphonesimulator \
           -destination 'platform=iOS Simulator,name=iPhone 12,OS=14.3' \
        -  test
        -

        If your app uses a workspace, perhaps because of CocoaPods, you'll need to pass the -workspace option instead of -project: -workspace MyAwesomeApp.xcworkspace.

        + test

        If your app uses a workspace, perhaps because of CocoaPods, you'll need to pass the -workspace option instead of -project: -workspace MyAwesomeApp.xcworkspace.

        You can run instruments -s devices to see a list of know devices to use as the -destination option. Checkout my xcodebuild destination cheatsheet for more -destination tips & tricks.

        xcodebuild produces a dense output:

        +

        While it's great to have all of the build information at hand, most of it is irrelevant for the tests. And all of that text will make it impossible to scroll back in your terminal window and take up unnecessary space in your CI logs.

        Luckily, there are tools to format the raw xcodebuild input into something concise and informative. I have two to recommend: the Swift-based xcbeautify and the Ruby-based xcpretty.

        -

        Running tests with xcodebuild and xcbeautify

        +

        Running tests with xcodebuild and xcbeautify

        xcbeautify is a little Swift package that makes the xcodebuild output human-readable.

        There are multiple ways to install xcbeautify, the most straightforward being with Homebrew: brew install xcbeautify.

        Once installed, using xcbeautify is simply a matter of piping the xcodebuild output through it:

        -
        xcodebuild \
        +
        xcodebuild \
           -workspace MyAwesomeApp.xcworkspace \
           -scheme MyAwesomeApp \
           -sdk iphonesimulator \
           -destination 'platform=iOS Simulator,name=iPhone 12,OS=14.3' \
           test \
        -  | xcbeautify
        -
        + | xcbeautify
        +

        You can use xcbeautify the Swift Package Manager and the Bazel build system output, too.

        If you are working on a project that doesn't rely on CocoaPods or Fastlane, then xcbeautify is an excellent and lightweight tool to use.

        If, on the other hand, you already have Ruby tooling in your project setup, then it might be simpler to use xcpretty. Fastlane ships with xcpretty so you don't have to add an extra step in your CI to install it.

        Another scenario in which you might want to use xcpretty is if you want a different output format as it offers more formatters.

        -

        Running tests with xcodebuild and xcpretty

        +

        Running tests with xcodebuild and xcpretty

        To install xcpretty, add it to your Gemfile then run bundle install:

        -
        # Gemfile
        -gem "xcpretty"
        -
        +
        # Gemfile
        +gem "xcpretty"

        You can also install it globally via gem install xcpretty, but using a Gemfile to manage your Ruby tools makes it easier for a team and CI to always run on the same versions, avoiding "it works on my machine" issues.

        Once you're setup, you can format the xcodebuild output by piping it through xcpretty:

        -
        xcodebuild \
        +
        xcodebuild \
           -workspace MyAwesomeApp.xcworkspace \
           -scheme MyAwesomeApp \
           -sdk iphonesimulator \
           -destination 'platform=iOS Simulator,name=iPhone 12,OS=14.3' \
           test \
        -  | bundle exec xcpretty
        -
        + | bundle exec xcpretty
        +

        If you set up xcpretty via gem install, you don't need to call it via bundle exec.

        For a more concise output, xcpretty can use the same formatting style as RSpec, which shows a dot for each test. Optionally, you can also color the dot green if the test passed or red otherwise.

        -
        xcodebuild \
        +
        xcodebuild \
           -workspace MyAwesomeApp.xcworkspace \
           -scheme MyAwesomeApp \
           -sdk iphonesimulator \
           -destination 'platform=iOS Simulator,name=iPhone 12,OS=14.3' \
           test \
        -  | bundle exec xcpretty --test --color
        -
        + | bundle exec xcpretty --test --color
        +

        There are more formatters to choose from and other configuration options you can learn about in the project's README.


        Whether you decide to run your tests with vanilla xcodebuild or format their output with xcbeautify or xcpretty, I hope you found this tutorial useful.

        diff --git a/blog/scenario-builders-in-swift/index.html b/blog/scenario-builders-in-swift/index.html index 5a0621d..3376973 100644 --- a/blog/scenario-builders-in-swift/index.html +++ b/blog/scenario-builders-in-swift/index.html @@ -13,7 +13,7 @@

        Rich input state makes t they both need to be part of the system, and the patient needs to be over the minimum age for the drug.

        A traditional unit test would require a setup along these lines:

        -
        let medicalBackend = MedicalBackend(
        +
        let medicalBackend = MedicalBackend(
             name: "medical backend",
             registrationID: "123ABC",
             address: Address(
        @@ -24,9 +24,9 @@ 

        Rich input state makes t postCode: "2ABC" ) ) -let doctor = Doctor(name: "a name", license: "1234", specialty: .generalPractitioner) +let doctor = Doctor(name: "a name", license: "1234", specialty: .generalPractitioner) medicalBackend.employ(doctor: doctor) -let patient = Patient( +let patient = Patient( name: "another name", dateOfBirth: Date(year: 2010, month: 01, day: 01), address: Address( @@ -38,74 +38,69 @@

        Rich input state makes t ) ) medicalBackend.onboard(patient: patient) -medicalBackend.register(patient: patient, with: doctor) -

        +medicalBackend.register(patient: patient, with: doctor)

        The code in this tutorial is available on GitHub. Check it out if you want to follow along from Xcode.

        The key information affecting the system under test outcome, that is, whether the patient is under age for the medicine, is lost in the noise made by the rest of the necessary input parameters.

        As already mentioned, fixtures can help, but we're still left with extra work in the arrange phase:

        -
        let medicalBackend = MedicalBackend(
        +
        let medicalBackend = MedicalBackend(
             name: "medical backend",
             registrationID: "123ABC",
             address: .fixture()
         )
        -let doctor = Doctor.fixture()
        +let doctor = Doctor.fixture()
         medicalBackend.employ(doctor: doctor)
        -let patient = Patient.fixture(dateOfBirth: Date(year: 2010, month: 01, day: 01))
        +let patient = Patient.fixture(dateOfBirth: Date(year: 2010, month: 01, day: 01))
         medicalBackend.onboard(patient: patient)
        -medicalBackend.register(patient: patient, with: doctor)
        -
        +medicalBackend.register(patient: patient, with: doctor)

        Scenario Builders simplify the setup of networks of objects by centralizing all of the instantiation, default values, and linking logic.

        Scenario Builder

        A Scenario Builder is an object that lives in your test suite to which you ask to construct a scenario with a natural language-like API. It encapsulates all the logic to create and connect the objects that make up the input state.

        Here's the Scenario Builder for our example:

        -
        struct ScenarioBuilder {
        +
        struct ScenarioBuilder {
         
        -    private var patientAge: Int = 30
        +    private var patientAge: Int = 30
         
        -    func withPatientAge(_ age: Int) -> ScenarioBuilder {
        -        var newBuilder = self
        -        newBuilder.patientAge = age
        +    func withPatientAge(_ age: Int) -> ScenarioBuilder {
        +        var newBuilder = self
        +        newBuilder.patientAge = age
                 return newBuilder
             }
         
        -    func build(referenceDate: Date = Date()) -> (MedicalBackend, Doctor, Patient) {
        -        let medicalBackend = MedicalBackend(
        +    func build(referenceDate: Date = Date()) -> (MedicalBackend, Doctor, Patient) {
        +        let medicalBackend = MedicalBackend(
                     name: "a name",
                     registrationID: "ABC123",
                     address: .fixture()
                 )
         
        -        let doctor = Doctor.fixture()
        +        let doctor = Doctor.fixture()
         
                 medicalBackend.employ(doctor: doctor)
         
        -        let dob = Calendar.current.date(byAdding: .year, value: patientAge, to: referenceDate)!
        -        let patient = Patient.fixture(dateOfBirth: dob)
        +        let dob = Calendar.current.date(byAdding: .year, value: patientAge, to: referenceDate)!
        +        let patient = Patient.fixture(dateOfBirth: dob)
         
                 medicalBackend.onboard(patient: patient)
                 medicalBackend.register(patient: patient, with: doctor)
         
                 return (medicalBackend, doctor, patient)
             }
        -}
        -
        +}

        This pattern is similar to Test Data Builders and fixtures, but removes the need for nesting instantiation of dependent objects.

        Thanks to the Scenario Builder, the test we wrote before can become much simpler:

        -
        let (medicalBackend, doctor, patient) = ScenarioBuilder().withPatientAge(10).build()
        -
        +
        let (medicalBackend, doctor, patient) = ScenarioBuilder().withPatientAge(10).build()

        Notice the signal to noise ratio of this syntax compared to the initial example. All the irrelevant information is hidden away inside ScenarioBuilder.

        To appreciate the value of this approach, imagine how much setup work this would spare you if you had to write five, ten, thirty more tests that required a consistent starting state for the medical system.

        A key difference between this approach and extracting the logic in a dedicated function is composability. Once you've gone through the effort of setting up the Scenario Builder, adding additional variations to the scenario is relatively cheap.

        -
        ScenarioBuilder()
        +
        ScenarioBuilder()
           .withPatientAge(10)
           .withPatientAllergicTo(someActiveIngredient)
           .withPatientWithSpecialCondition(specialCondition)
           .withDoctorNotQualifiedFor(specialCondition)
        -  .build()
        -
        + .build()

        Scenario Builders are also a way to decouple the tests from the implementation detail of the state instantiation, reducing the maintenance cost. Imagine something changes in the method that links a Patient to a Doctor, if you manually create and connect patients and doctors in each test, diff --git a/blog/security-tips-for-freelance-software-developers/index.html b/blog/security-tips-for-freelance-software-developers/index.html index c6d675c..392a591 100644 --- a/blog/security-tips-for-freelance-software-developers/index.html +++ b/blog/security-tips-for-freelance-software-developers/index.html @@ -21,7 +21,8 @@

        Use multi factor authentication

        From Wikipedia.

        Once you’ll have setup a couple of accounts with MFA you’ll find yourself addicted to it. It’s gonna be a disappointment when you’ll have to sign up for a service that doesn’t offer it.

        -

        Freelance software developers should MFA all the things to keep their accounts secure

        +Freelance software developers should MFA all the things to keep their accounts secure +

        List of all the services I use supporting MFA

        • Google
        • diff --git a/blog/setting-up-firebase-without-cocoapods/index.html b/blog/setting-up-firebase-without-cocoapods/index.html index a016c11..b7ce522 100644 --- a/blog/setting-up-firebase-without-cocoapods/index.html +++ b/blog/setting-up-firebase-without-cocoapods/index.html @@ -27,7 +27,7 @@

          1. Get your Firebase copy

          to carry extra code they don't need with them.

          You'll also notice that the archive comes with a README. The file contains barebone instructions to setup the SDK manually, this post augments them.

          -

          2. Copy Firebase/Analytics into your project

          +

          2. Copy Firebase/Analytics into your project

          The analytics component of Firebase is required for the SDK to work.

          That might sound weird but is quite obvious, what did you think that Google would provide such a wonderful suite of tools that you can use for free, at @@ -77,14 +77,14 @@

          4. Import the Firebase header

        • Use the Finder window that opened to navigate to the location of your file
        • Select the file and press "OK"
    -

    5. Add the -ObjC linker flag

    +

    5. Add the -ObjC linker flag

    As mentioned above the SDK is distributed as a static Objective-C framework, and as such it requires the -ObjC linker flag.

    Go to your target's "Build Settings" and then into the "Linking" section and add -ObjC in the "Other Linker Flags" row.

    You can use the search bar in the top right corner to filter the build settings, saving a lot of scrolling time.

    -

    6. Add Firebase.h to the projects bridging header (Swift only)

    +

    6. Add Firebase.h to the projects bridging header (Swift only)

    This post has been written in the second part of 2016, so there is a good chance you're writing a Swift project. If that's not the case I'd like to know why, please hit me up on Twitter @mokagio.

    @@ -93,9 +93,8 @@

    6. Add Fir Xcode add a bridging header is to add a dummy Objective-C class and select "Create Bridging Header" in the prompt that will be presented.

    Once you have your bridging header, import the Firebase header in it like this:

    -
    #import "Firebase.h"
    -
    -

    7. Import the module map file (Swift only)

    +
    #import "Firebase.h"
    +

    7. Import the module map file (Swift only)

    To use the Firebase SDK into a Swift project the header is not enough, we also need the Swift module map file.

    Go into the downloaded Firebase folder and you'll find a module.modulemap @@ -116,20 +115,19 @@

    9. Start using Firebase

    This is it. To verify your setup is complete and start using Firebase, import the framework and call the Firebase singleton initialization method.

    For example in the AppDelegate:

    -
    import UIKit
    +
    import UIKit
     import Firebase
     
    -@UIApplicationMain
    +@UIApplicationMain
     class AppDelegate: UIResponder, UIApplicationDelegate {
     
    -    var window: UIWindow?
    +    var window: UIWindow?
     
    -    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    +    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
             FIRApp.configure()
             return true
         }
    -}
    -
    +}

    10. Add more frameworks

    You probably are not interested in Firebase just for its analytics.

    To add any other component simply:

    diff --git a/blog/setting-up-kif-for-ios-acceptance-testing/index.html b/blog/setting-up-kif-for-ios-acceptance-testing/index.html index e739850..d550721 100644 --- a/blog/setting-up-kif-for-ios-acceptance-testing/index.html +++ b/blog/setting-up-kif-for-ios-acceptance-testing/index.html @@ -33,15 +33,14 @@

    Create the scheme

    You'll probably want to share the scheme as well, in order for it to be tracked in the source control and be available by the other members of the team, and the CI machine. You can do that from the "Edit Scemes..." window.

    Add KIF with CocoaPods

    Now that the preparation work is done we can install KIF. CocoaPods is the tool of choice.

    -
    target 'BenchKIF', exclusive: true do
    +
    target 'BenchKIF', exclusive: true do
       pod 'KIF', '~> 3.2.0'
    -end
    -
    +end

    Notice the exclusive: true, KIF uses private APIs an we don't want it to leak into the production build! Also since it's not needed by the main target there's no reason to add it there.

    Now let's run pod install and get ready to write our first test.

    The first test

    The simplest thing we can test is the state of the UI, let's make sure that the elements in the view are showing the text we're expecting.

    -
    #import <UIKit/UIKit.h>
    +
    #import <UIKit/UIKit.h>
     #import <XCTest/XCTest.h>
     #import <KIF.h>
     
    @@ -58,8 +57,7 @@ 

    The first test

    [tester waitForViewWithAccessibilityLabel:@"mokacoding.com"]; } -@end -
    +@end

    Some things to note here:

    • tester is a syntactic sugar provided by KIF to access it's set of APIs to drive the UI and make assertions on it.
    • @@ -68,7 +66,7 @@

      The first test

      More useful tests

      Let's be honest, the test we just wrote is not very useful. One could actually argue that if that's what we mean with acceptance testing it's actually a waste of time. So let's try to test something that actually makes sense, let's see if the app is behaving as it should.

      Bench does two things, shows a greetings alert to the user, and a list of the elements of the periodic table.

      -
      /**
      +
      /**
        *  When I tap the "say hello" button, I see a greetings alert, so that I can be happier :)
        */
       - (void)testSayHello {
      @@ -99,11 +97,10 @@ 

      More useful tests

      [tester tapViewWithAccessibilityLabel:@"Back"]; [tester waitForAbsenceOfViewWithAccessibilityLabel:@"Elements"]; -} -
      +}

      Notice how in both tests we're bringing the app back to it's original state, that's an important thing to keep in mind when writing acceptance tests.

      You might also be saying "Why are you just testing the first and last row?". Well, it's not really the responsibility of the acceptance tests to test the business logic that generated the list of elements. It's enough for us to make sure that there is a list.

      -

      What's next

      +

      What's next

      This post was focused on how to get started with KIF, and the tests written above are very simple cases. If you'll decide to use KIF as your acceptance tests framework of choice there's gonna be other more advanced things you'll need to do, like

      • Running the tests in a CI environment.
      • diff --git a/blog/setting-up-testing-libraries-with-carthage-xcode7/index.html b/blog/setting-up-testing-libraries-with-carthage-xcode7/index.html index 9ac6322..4eb8f63 100644 --- a/blog/setting-up-testing-libraries-with-carthage-xcode7/index.html +++ b/blog/setting-up-testing-libraries-with-carthage-xcode7/index.html @@ -6,22 +6,18 @@

        Carthage

        Carthage is a very interesting dependency manager. It is written in Swift and does massive use of ReactiveCocoa, and its approach is focused on simplicity. Where CocoaPods does everything for us, Carthage only resolves, downloads, and -when necessary- builds dependencies, leaving us the responsibility of adding them to the project, using the methods and settings we find more appropriate.

        You can install Carthage using Homebrew:

        -
        brew install carthage
        -
        +
        brew install carthage

        The Cartfile

        The way to specify the dependencies in Carthage is with a Cartfile. This is how our looks like:

        -
        github "Quick/Quick" "v0.5.0"
        -github "Quick/Nimble" "v2.0.0-rc.1"
        -

        Note how we are specifying exact version numbers. This is because Swift 2 support has been added only in those version, and being all a work in progress we want to make sure we use a stable version.

        +
        github "Quick/Quick" "v0.5.0"
        +github "Quick/Nimble" "v2.0.0-rc.1"

        Note how we are specifying exact version numbers. This is because Swift 2 support has been added only in those version, and being all a work in progress we want to make sure we use a stable version.

        The Cartfile supports the usual operators for version requirements such as ~>, >=, etc. You can read more about all the valid options here

        Getting the frameworks

        Resolving the dependencies, download the right versions, and finally build them is as easy as running a single command:

        -
        carthage update
        -
        +
        carthage update

        But since we are installing frameworks using Swift 2, we need to switch the sdk used by xcodebuild, which is call by carthage update under the hood, to the Xcode 7 one, like this:

        -
        sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer
        -carthage update
        -
        +
        sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer
        +carthage update

        Once carthage update has finished you will notice a Carthage folder, and a Cathage.resolved file. Remember to check-in to version control at least the Carthage.resolved file.

        It's now time to import the frameworks into Xcode. Because we are only setting testing depencendcies we should add the to the test target only. To do that need to follow a different approach than the usual one. Quoting from Carthage's README:

        @@ -30,39 +26,37 @@

        Getting the frameworks

        Link Binaries animated screenshot

        Just another bit of setup

        When building for iOS, due to an App Store bug we need to add a "Run Script" Build Phase, that will execute a script to work around the issue. This is the Run Script's content:

        -
        /usr/local/bin/carthage copy-frameworks
        -

        And these are the paths to our frameworks:

        -
        $(SRCROOT)/Carthage/Build/iOS/Quick.framework
        -$(SRCROOT)/Carthage/Build/iOS/Nimble.framework
        -

        Run script animated screenshot

        +
        /usr/local/bin/carthage copy-frameworks

        And these are the paths to our frameworks:

        +
        $(SRCROOT)/Carthage/Build/iOS/Quick.framework
        +$(SRCROOT)/Carthage/Build/iOS/Nimble.framework

        Run script animated screenshot

        You can read more about the process here.

        After that, we need to add the Carthage's build folder ($(SRCROOT)/Carthage/Build/iOS) to Framework Search Path, in recursive mode. This is apparently due to a regression (or is it a feature?) introduced by Xcode 7, more here.

        Framework Search Path screenshot Once that is done we can happily import our testing frameworks in the test target:

        -
        import Quick
        +
        import Quick
         import Nimble
         
         class QuickNimbleCarthageSpec: QuickSpec {
        -  override func spec() {
        +  override func spec() {
             describe("Setting up Quick and Nimble for testing using Carthage") {
               it("is not very hard") {
                 expect(true).to(beTruthy())
               }
         
               it("works very well") {
        -        expect(20 * 2 + 3 - 1).to(equal(42))
        +        expect(20 * 2 + 3 - 1).to(equal(42))
               }
             }
           }
        -}
        -
        +}

        Test succeded screenshot

        Protip: Make them private

        Since the frameworks used in the testing target do not concern the main one there is no reason to make their dependencies known to the parent project. To do this we simply have to declare those dependencies in the Cartfile.private file. Quoting from Carthage's docs:

        -
        mv Cartfile Cartfile.private
        -
        +
        mv Cartfile Cartfile.private

        Frameworks that want to include dependencies via Carthage, but do not want to force those dependencies on parent projects, can list them in the optional Cartfile.private file, identically to how they would be specified in the main Cartfile.

        +
        +

        Anything listed in the private Cartfile will not be seen by dependent (parent) projects, which is useful for dependencies that may be important during development, but not when building releases—for example, test frameworks.


        diff --git a/blog/setup-a-dev-machine/index.html b/blog/setup-a-dev-machine/index.html index 4e49273..e049c81 100644 --- a/blog/setup-a-dev-machine/index.html +++ b/blog/setup-a-dev-machine/index.html @@ -3,40 +3,31 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    Setting a Mac for Development

    Last week I setup our new office Mac Mini, that we will use as CI server for our iOS apps (finally!), and for other tasks, such as a constant view on our products analytics.

    Our machine is the workshop where we create awesomeness (or bugs). I really love setting up a machine for development, but I've always ended up mad at something, or spending ages looking how to install this or that. So this time, once and for all, I took note of every step, and here's my little checklist on how to set up a Mac for development.

    Note: the original version of this post was long and basically just me blabbering about the usual suspects, Ruby, Node, Xcode… I refactored it in a condesed version. No need to thank me.

    -

    Setup OS X for Development: the checklist

    -

    Homebrew

    +

    ###Setup OS X for Development: the checklist

    +

    ####Homebrew

    Save time, and your sanity, use homebrew!

    -
    ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
    -

    homebrew saves stuff in /usr/local/bin, so make sure it comes before the default /bin in the $PATH.

    -
    export PATH=/usr/local/bin/:$PATH
    -

    zsh

    -
    brew install zsh
    -

    Zsh is cool, and with prezto we can make it super shiny. +

    ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

    homebrew saves stuff in /usr/local/bin, so make sure it comes before the default /bin in the $PATH.

    +
    export PATH=/usr/local/bin/:$PATH

    ####zsh

    +
    brew install zsh

    Zsh is cool, and with prezto we can make it super shiny.
    Note: the following instructions are from the prezto README, check it out just to be sure they are up to date.

    -
    zsh
    +
    zsh
     git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
     setopt EXTENDED_GLOB
     for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
       ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
    -done
    -

    Finally, set zsh as the default shell

    -
    chsh -s /usr/local/bin/zsh
    -

    Ruby, of course via rvm

    -
    \curl -L https://get.rvm.io | bash -s stable
    -rvm install 2.0.0
    -

    Python, a proper one

    -
    brew install python
    -

    Node.js

    +done

    Finally, set zsh as the default shell

    +
    chsh -s /usr/local/bin/zsh

    ####Ruby, of course via rvm

    +
    \curl -L https://get.rvm.io | bash -s stable
    +rvm install 2.0.0

    ####Python, a proper one

    +
    brew install python

    ####Node.js

    Just head to the home page and hit the green "Install" button, it's the reccomened way! Or use homebrew again:

    -
    brew install node
    -

    Xcode and the Command Line Tools

    +
    brew install node

    ####Xcode and the Command Line Tools

    Get it from Apple's Developer page, and then search for "Command Line Tools" in the "Downloads" tab of the "Preferences".

    There's also an open source way, but I haven't tried it.

    -

    Java

    +

    ####Java

    Apparently OS X doesn't come with Java ready for us, but at least installing it is easy, just try to use it in the terminal, and the installation wizard will start.

    -
    java
    -

    Some useful extra stuff

    +
    java

    ####Some useful extra stuff

    • Chrome
    • Alfred
    • diff --git a/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fonts/index.html b/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fonts/index.html index 8060cd1..8ca23af 100644 --- a/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fonts/index.html +++ b/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fonts/index.html @@ -15,12 +15,11 @@

      Add the assets to the pod res

      Then how do we make a bundle? Or in our case a Resource Bundle, so that we can add it in our .podspec? As you can imagine the Documentation is still not helpful...

      I spent a couple of hours messing around creating folders naming the folder.bundle, googling and stackoverflowing, but with no luck integrating it with my pod. I also found a tutorial by Matt Galloway, but it looked like a complex hack, there had to be something simpler!

      Turns out it's dead simple! Just list the resources path you want in the bundle and the pod will generate it for you. Boom. No tricks, no hacks, just a line of code.

      -
      spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
      -
      +
      spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }

      Dynamically load the fonts

      Now that the we have our Resource Bundle ready we only need to skip the annoying process of adding the fonts to the Info.plist and we're good to go.

      To do that I used the approach suggested by Marco Armet in this blog post. It's possible to dynamically load fonts and then consume them with the usual fontNamed:withSize UIFont class method.

      -
      NSData *inData = /* your decrypted font-file data */;
      +
      NSData *inData = /* your decrypted font-file data */;
       CFErrorRef error;
       CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
       CGFontRef font = CGFontCreateWithDataProvider(provider);
      @@ -30,10 +29,9 @@ 

      Dynamically load the fonts

      CFRelease(errorDescription); } CFRelease(font); -CFRelease(provider); -
      +CFRelease(provider);

      The only downside of this approach is that we need to run that code at some point. I put it into a FontsManager class, with getters for the fonts that sort of lazy loads them. Like this:

      -
      static NSString * const kBundle = @"ResourceBundle.bundle";
      +
      static NSString * const kBundle = @"ResourceBundle.bundle";
       
       + (UIFont *)openSansLightFontOfSize:(CGFloat)size
       {
      @@ -67,9 +65,8 @@ 

      Dynamically load the fonts

      CFRelease(font); CFRelease(provider); } -} -
      -

      What about the images?

      +}
      +

      What about the images?

      We can access images with the same strategy used for the fonts, a manager that lazy loads them from the bundle.


      Having a tidy project is invaluable, specially when it only needs a couple of lines of code. Plus by grouping our assets in a pod we can quickly implement other apps with a style consistent to our branding.

      diff --git a/blog/simpler-calabash-testing-with-rake/index.html b/blog/simpler-calabash-testing-with-rake/index.html index 89c2e98..e8a10fe 100644 --- a/blog/simpler-calabash-testing-with-rake/index.html +++ b/blog/simpler-calabash-testing-with-rake/index.html @@ -11,23 +11,23 @@
    • Never forget the syntax and options for a command, they are all written in the Rakefile.

    These tasks will build and run the tests on the Simulator, specifying that we want an iPhone 6 Simulator running iOS 8.1, and that it should be reset before each test case.

    -
    @build_dir = ...
    -@workspace = ...
    -@scheme = ...
    -@configuration = ...
    -@app_name = ...
    +
    @build_dir = ...
    +@workspace = ...
    +@scheme = ...
    +@configuration = ...
    +@app_name = ...
     
     desc 'Build a "calabashed" version of the app'
     task :build do
       build_fat_binary = <<COMMAND
     xcrun xcodebuild \
    --SYMROOT=#{@build_dir} \
    --derivedDataPath "#{@build_dir}" \
    +-SYMROOT=#{@build_dir} \
    +-derivedDataPath "#{@build_dir}" \
       ARCHS="i386 x86_64" \
       VALID_ARCHS="i386 x86_64" \
       ONLY_ACTIVE_ARCH=NO \
    -  -workspace #{@workspace} \
    -  -scheme #{@scheme} \
    +  -workspace #{@workspace} \
    +  -scheme #{@scheme} \
       -sdk iphonesimulator \
       clean build
     COMMAND
    @@ -37,7 +37,7 @@
     
     desc 'Run all the calabash/cucumber acceptance tests on the simulator.'
     task :simulator_tests => [:build] do
    -  app_path = "#{@build_dir}/Build/Products/#{@configuration}-iphonesimulator/#{@app_name}.app"
    +  app_path = "#{@build_dir}/Build/Products/#{@configuration}-iphonesimulator/#{@app_name}.app"
     
       run_tests = <<COMMAND
     bundle exec cucumber \
    @@ -47,32 +47,29 @@
     COMMAND
     
       sh run_tests
    -end
    -
    +end

    Now instead of typing bundle exec cucumber DEVICE_TARGET=... and all the rest, we can simply do rake simulator_tests. I consider this a huge win.

    When it comes to run tests on device you could use this task.

    -
    @ip = ...
    -@uuid = ...
    -@bundle_id = ...
    +
    @ip = ...
    +@uuid = ...
    +@bundle_id = ...
     
     desc 'Run all the calabash/cucumber acceptance tests on the connected device.'
     task :device_tests => do
       run_tests = <<COMMAND
     bundle exec cucumber \
       BUNDLE_ID="#{bundle_id} \
    -  DEVICE_ENDPOINT=http://#{@ip}:37265 \
    -  DEVICE_TARGET='#{@uuid}'
    +  DEVICE_ENDPOINT=http://#{@ip}:37265 \
    +  DEVICE_TARGET='#{@uuid}'
     COMMAND
     
       sh run_tests
    -end
    -
    +end

    The above tasks has two flaws, the device UUID and ip are hard-coded, and it assumes the app is already on the device.

    We can fix the first issue by moving the configurations in a .yml file.

    -
    uuid: "device UUID"
    -ip: "device IP when on the same network as the machine running the tests"
    -
    -
    desc 'Run all the calabash/cucumber acceptance tests on the connected device.'
    +
    uuid: "device UUID"
    +ip: "device IP when on the same network as the machine running the tests"
    +
    desc 'Run all the calabash/cucumber acceptance tests on the connected device.'
     task :device_tests => do
       settings_file = Dir.pwd + '/.calabash_device_config.yml'
       raise "Missing calabash)device_config.yml in root folder." unless File.exists? settings_file
    @@ -87,16 +84,14 @@
     COMMAND
     
       sh run_tests
    -end
    -
    +end

    To make this setup team friendly we can add the .yml file to the .gitignore of the project, and track a copy of it with dummy values and .yml.sample instead.

    We've removed the need to hardcode UUID and IP, but we're still depending on the fact that the app is already installed on the device.

    As of Xcode 6.1.1 Apple has not provided a tool to deploy an app on device from the command line Lucky enough the open source community has a solution for that. ios-deploy, previously known as fruitstrap, and maintained by the PhoneGap community, lets you deploy an ipa on a connected device as easily as ios-deploy -b MyApp.ipa.

    ios-deploy is distribute via npm, but if you'd like two add it to your project's Gemfile you can do it thanks to this gem.

    The missing piece of the puzzle is how to build the app in a format that can be deployed to the device. To keep things simple we're gonna use the shenzhen gem. The command needed to build is:

    -
    ipa build --workpace ... --configuration ... --scheme .. --archive --sdk iphoneos --ipa "MyApp.ipa"
    -

    Putting it all together:

    -
    desc 'Run all the calabash/cucumber acceptance tests on the connected device.'
    +
    ipa build --workpace ... --configuration ... --scheme .. --archive --sdk iphoneos --ipa "MyApp.ipa"

    Putting it all together:

    +
    desc 'Run all the calabash/cucumber acceptance tests on the connected device.'
     task :device_tests => do
       settings_file = Dir.pwd + '/.calabash_device_config.yml'
       raise "Missing calabash)device_config.yml in root folder." unless File.exists? settings_file
    @@ -130,8 +125,7 @@
       sh archive
       sh send_to_device
       sh run_tests
    -end
    -
    +end

    The task above is doing a lot, imagine if you had to do it every time you want to run tests on the device!

    Setting up these tasks will save you the effort of remembering all the cucumber option, save you typing, and also make the running the acceptance test easy for the team members that don't know about cucumber and calabash.

    Happy coding, and keep the codebase better than you found it

    diff --git a/blog/specta-global-before-after-each-updated/index.html b/blog/specta-global-before-after-each-updated/index.html index 14cb9e6..d75bdc3 100644 --- a/blog/specta-global-before-after-each-updated/index.html +++ b/blog/specta-global-before-after-each-updated/index.html @@ -6,7 +6,7 @@

    Say that we have a Banana class, and that we want to test it's looks yellow behaviour. We get a banana from the fruit bowl, and wherever we put it it should still look yellow.

    Unfortunately our Banana is a stateful fruit, so to make the test accurate we have to put it back in the fruit bowl every time.

    A Specta spec to describe this behaviour might look like this:

    -
    describe(@"Banana", ^{
    +
    describe(@"Banana", ^{
       it(@"should look yellow when put on the table", ^{
         [banana removeFromTheFruitBowl];
         [banana putOnTheTable];
    @@ -20,10 +20,9 @@
         expect([banana looksYellow]).to.beTruthy();
         [banana putInTheFruitBowl];
       });
    -});
    -
    +});

    This spec looks a bit dense, and wet. Thanks to the beforeEach and afterEach hooks we can write it in a clearer and drier way:

    -
    describe(@"Banana", ^{
    +
    describe(@"Banana", ^{
       beforeEach(^{
         [banana removeFromTheFruitBowl];
       });
    @@ -41,13 +40,12 @@
       afterEach(^{
         [banana putInTheFruitBowl];
       });
    -});
    -
    +});

    Configuring a global hook in Specta

    Now, not only our Banana is stateful, but also is an hidden dependency in several other pieces of the system. Let's for a moment forget that the best thing to do in this case would be to do some good old refactoring to extract that dependency, and imagine that the only thing we can do is call the removeFromTheFruitBowl and putInTheFruitBowl methods in every test.

    This option is quite annoying isn't it? Our specs shouldn't have to care about setup and tear down operations that are at the system level. Plus it's easy to forget about this step.

    Specta takes care of this problem for us. Before running the suite it will inspect the run time for classes that conform to the SPTGlobalBeforeAfterEach protocol, class methods, and run their beforeEach and afterEach methods, before and after each example in the suite.

    -
    @interface BeforeAfterEachHelper : NSObject <SPTGlobalBeforeAfterEach>
    +
    @interface BeforeAfterEachHelper : NSObject <SPTGlobalBeforeAfterEach>
     @end
     
     @implementation BeforeAfterEachHelper
    @@ -62,8 +60,7 @@ 

    Configuring a global hook in Specta //... } -@end -

    +@end

    Pretty handy, isn't it?

    The advantage of using the protocol is that if any of your classes has either a beforeEach or an afterEach method that will not be pick up by the test. This approach is called whitelisting.


    diff --git a/blog/specta-global-before-after-each/index.html b/blog/specta-global-before-after-each/index.html index 4695079..f63a921 100644 --- a/blog/specta-global-before-after-each/index.html +++ b/blog/specta-global-before-after-each/index.html @@ -1,7 +1,7 @@ Specta global before and after each hooks | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Specta global before and after each hooks

    Update on the 3rd of April 2015, Specta 0.5 has been released, making the content of this post obsolete after less then a month from it's release date.

    -

    +

    Have a look at the updated version to make sure you don't encounter any issue.

    @@ -18,7 +18,7 @@

    Before and after each hooks

    Say that we have a Banana class, and that we want to test it's looks yellow behaviour. We get a banana from the fruit bowl, and wherever we put it it should still look yellow.

    Unfortunately our Banana is a stateful fruit, so to make the test accurate we have to put it back in the fruit bowl every time.

    A Specta spec to describe this behaviour might look like this:

    -
    describe(@"Banana", ^{
    +
    describe(@"Banana", ^{
       it(@"should look yellow when put on the table", ^{
         [banana removeFromTheFruitBowl];
         [banana putOnTheTable];
    @@ -32,10 +32,9 @@ 

    Before and after each hooks

    expect([banana looksYellow]).to.beTruthy(); [banana putInTheFruitBowl]; }); -}); -
    +});

    This spec looks a bit dense, and wet. Thanks to the beforeEach and afterEach hooks we can write it in a clearer and drier way:

    -
    describe(@"Banana", ^{
    +
    describe(@"Banana", ^{
       beforeEach(^{
         [banana removeFromTheFruitBowl];
       });
    @@ -53,13 +52,12 @@ 

    Before and after each hooks

    afterEach(^{ [banana putInTheFruitBowl]; }); -}); -
    +});

    Configuring a global hook in Specta

    Now, not only our Banana is stateful, but also is an hidden dependency in several other pieces of the system. Let's for a moment forget that the best thing to do in this case would be to do some good old refactoring to extract that dependency, and imagine that the only thing we can do is call the removeFromTheFruitBowl and putInTheFruitBowl methods in every test.

    This option is quite annoying isn't it? Our specs shouldn't have to care about setup and tear down operations that are at the system level. Plus it's easy to forget about this step.

    Specta takes care of this problem for us. Before running the suite it will inspect the run time for classes with beforeEach and afterAll class methods, and run them before and after each example in the suite.

    -
    @interface BeforeAfterEachHelper : NSObject
    +
    @interface BeforeAfterEachHelper : NSObject
     @end
     
     @implementation BeforeAfterEachHelper
    @@ -74,13 +72,12 @@ 

    Configuring a global hook in Specta //... } -@end -

    +@end

    Pretty handy, isn't it?

    Disabling a global hook

    For some reason you might have a class that already has a + afterEach method, and you don't want it to run as global hook in the tests. As mentioned at the start the latest release, version 0.4, makes it easy to skip classes that have before or after each hooks.

    It's simply required to conform to the SPTExcludeGlobalBeforeAfterEach.

    -
    @interface BeforeAfterEachHelper : NSObject <SPTExcludeGlobalBeforAfterEach>`
    +
    @interface BeforeAfterEachHelper : NSObject <SPTExcludeGlobalBeforAfterEach>`
     @end
     
     @implementation BeforeAfterEachHelper
    @@ -95,8 +92,7 @@ 

    Disabling a global hook

    //... } -@end -
    +@end

    One could argue that a suite that needs to run code before and/or after each test has some intrinsic problem, and that time should be spent to improve the architecture of the system under test. Regardless of that I think this option offered by Specta is interesting and powerful.

    Have a look at the example project to see global hooks in action, or check out the video below, and feel free to leave a comment or tweet me at @mokagio.

    diff --git a/blog/step-by-step-tdd-in-swift-part-1/index.html b/blog/step-by-step-tdd-in-swift-part-1/index.html index b2b6159..3c59a66 100644 --- a/blog/step-by-step-tdd-in-swift-part-1/index.html +++ b/blog/step-by-step-tdd-in-swift-part-1/index.html @@ -10,234 +10,209 @@

    This version of the app with only pizzas is our walking skeleton, an app with only the bare minimum of functionality to make sure all the components are glued together and working end to end.

    Since the core of our business logic is the conversion of Giuseppe's menu to a format that can be displayed let's start with a component for it, let's call it MenuDataSource.

    When doing TDD we always start from the tests, so let's create one for MenuDataSource. In this post we'll use Apple's XCTest famework, but that's not the only option to write tests in Swift.

    -
    @testable import Giuseppes
    +
    @testable import Giuseppes
     import XCTest
     
     class MenuDataSourceTests: XCTestCase {
    -}
    -
    +}

    Our test should describe and verify the behaviour we want for MenuDataSource. We decided that our walking skeleton will have only pizzas, so let's make sure MenuDataSource provides only one section for the menu.

    To test this behaviour we'll first need an instance of MenuDataSource.

    -
    @testable import Giuseppes
    +
    @testable import Giuseppes
     import XCTest
     
     class MenuDataSourceTests: XCTestCase {
     
    -    func testHasOneSection() {
    -        let dataSource = MenuDataSource()
    +    func testHasOneSection() {
    +        let dataSource = MenuDataSource()
             // 🔴 Use of unresolved identifier 'MenuDataSource';
             // did you mean 'MenuDataSourceTests'?
         }
    -}
    -
    +}

    The code is not compiling, as we haven't defined MenuDataSource yet. In TDD compilation failures count as test failures, and our job is to write the simplest code that we can to make the test pass, which in this case means compile.

    To make the test compile we have to define MenuDataSource.

    -
    struct MenuDataSource { }
    -
    +
    struct MenuDataSource { }

    Notice that there are no properties or init parameters in this MenuDataSource. This is what means to write the simplest code possible, just enough code to make the test pass. We'll add properties to the type only as we'll need them to make the tests we'll write pass.

    Now that the test is compiling let's move to asserting the behaviour of MenuDataSource when asked for sections.

    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource()
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource()
         XCTAssertEqual(dataSource.numberOfSections, 1)
         // 🔴 Value of type 'MenuDataSource' has no member 'numberOfSections'
    -}
    -
    +}

    Once again we have a failing test due to a compilation error. What's the simplest code we can write to make it pass?

    -
    struct MenuDataSource {
    +
    struct MenuDataSource {
     
    -    let numberOfSections = 1
    -}
    -
    + let numberOfSections = 1 +}

    Notice once again that there is no logic here, just an hardcoded value. This is enough to make our test compile and also pass, and we're happy with it.

    -
    @testable import Giuseppes
    +
    @testable import Giuseppes
     import XCTest
     
     class MenuDataSourceTests: XCTestCase {
     
    -    func testHasOneSection() {
    -        let dataSource = MenuDataSource()
    +    func testHasOneSection() {
    +        let dataSource = MenuDataSource()
             XCTAssertEqual(dataSource.numberOfSections, 1)  // ✅
         }
    -}
    -
    +}

    A word of warning. You should never trust a test you haven't seen fail. We've seen the test fail due to a compilation error, but what about testing the actual behaviour? It wouldn't hurt to change the hardcoded 1 in MenuDataSource to another value, and verify that the test fails.

    We finally have a passing test, let's commit: Implement MenuDataSource returning number of sections.

    What's next? Let's add a way to get the number of rows in a section.

    -
    func testRowsInSection() {
    -    let dataSource = MenuDataSource()
    -    XCTAssertEqual(dataSource.numberOfRows(inSection: 0), ???)
    -}
    -
    +
    func testRowsInSection() {
    +    let dataSource = MenuDataSource()
    +    XCTAssertEqual(dataSource.numberOfRows(inSection: 0), ???)
    +}

    Hang on, how many rows should there be in a section? If our section is showing the pizzas then it should have as many rows as the pizzas to display. How can we test this behaviour? We need a way to control this input parameter, for example we can pass the array of pizzas to display to MenuDataSource at init time.

    The act of writing tests for the behaviours we want reveals the design details of our software. We didn't decide upfront that MenuDataSource should be initialized with an Array<Pizza>, we let the need for it emerge from the tests.

    Before solving that problem let's bring the test to a successful state. Let's just say number of rows should always be 3.

    -
    func testRowsInSection() {
    -    let dataSource = MenuDataSource()
    +
    func testRowsInSection() {
    +    let dataSource = MenuDataSource()
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3)
         // 🔴 Value of type 'MenuDataSource' has no member 'numberOfRows';
         // did you mean numberOfSections'?
    -}
    -
    +}

    Once again the simplest way to make the test pass it to hardcode the result to be 3.

    -
    func numberOfRows(inSection section: Int) -> Int {
    +
    func numberOfRows(inSection section: Int) -> Int {
         return 3
    -}
    -
    -
    func testRowsInSection() {
    -    let dataSource = MenuDataSource()
    +}
    +
    func testRowsInSection() {
    +    let dataSource = MenuDataSource()
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3)  // ✅
    -}
    -
    +}

    Let's commit this intermediate step. Implement dummy number of rows in section.

    Now that we have a green test let's move to initializing MenuDataSource with an array of pizzas. What's the least amount of code we can write to achieve it? We always start from the tests:

    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza()])
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza()])
         // 🔴 Use of unresolved identifier 'Pizza'
         XCTAssertEqual(dataSource.numberOfSections, 1)
     }
     
    -func testRowsInSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +func testRowsInSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         // 🔴 Use of unresolved identifier 'Pizza'
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3)
    -}
    -
    +}

    The compiler is now hinting the next step to us, define Pizza.

    -
    struct Pizza { }
    -
    +
    struct Pizza { }

    It's tempting to add properties to Pizza, like its name, price, and ingredients, but we don't need that code to make the test pass. The problem we're trying to solve is not writing a comprehensive Pizza, but making sure we can pass Pizzas to display to MenuDataSource. TDD is all about solving one very little problem after the other.

    If we try to run the tests again we'll get a new error:

    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza()])
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza()])
         // 🔴 Argument passed to call that takes no arguments
         XCTAssertEqual(dataSource.numberOfSections, 1)
     }
     
    -func testRowsInSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +func testRowsInSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         // 🔴 Argument passed to call that takes no arguments
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3)
    -}
    -
    +}

    Let's pass an array of our new Pizzas as an argument to the init method of MenuDataSource.

    -
    struct MenuDataSource {
    +
    struct MenuDataSource {
     
         let pizzas: [Pizza]
    -}
    -
    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza()])
    +}
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza()])
         XCTAssertEqual(dataSource.numberOfSections, 1)  // ✅
     }
     
    -func testRowsInSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +func testRowsInSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3)  // ✅
    -}
    -
    +}

    Now the tests are passing again, so let's commit, even if we haven't implemented the logic to read the number of Pizzas yet. Pass [Pizza] to MenuDataSource init.

    Committing often makes TDD easier. We move a little bit at a time, and if we end up with something that doesn't work we only have little code to review. You could even discard those unstaged changes and start from scratch. Don't worry about the Git history becoming long, commits are cheap to store. If you want to have a more compact history before your changes are merged you can always do an interactive rebase and tidy it up.

    Moving on, let's write the simplest code we can to read make MenuDataSource return a number of rows based on the given [Pizza].

    -
    // MenuDataSource.swift
    -func numberOfRows(inSection section: Int) -> Int {
    -    return pizzas.count
    -}
    -
    +
    // MenuDataSource.swift
    +func numberOfRows(inSection section: Int) -> Int {
    +    return pizzas.count
    +}

    Tests are still green, so our change is a valid implementation of the behaviour. Let's commit this little change: Return number of menu rows based on input [Pizza].

    What's our next step? Before moving on to implement the next behaviour let's look at how we're testing numberOfRows(inSection:). Have we considered all its possible behaviours? To answer this question we can look at its input parameter, should the method return the same output for every input? What should it do if the section index provided doesn't match any of the sections -currently just one- in the menu? Given this method is called "number of rows" a reasonable thing to do would be to return 0. Let's write a test for this scenario.

    -
    func testRowsInOutOfBoundsSectionIsZero() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +
    func testRowsInOutOfBoundsSectionIsZero() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 1), 0)
         // ❌ XCTAssertEqual failed: ("3") is not equal to ("0")
    -    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0)
    +    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0)
         // ❌ XCTAssertEqual failed: ("3") is not equal to ("0")
    -}
    -
    +}

    The tests are failing, you're not surprised by that are you? The current version of numberOfRows(inSection:) always returns the count of the pizzas. Let's write as little code as we can to make the tests pass.

    -
    func numberOfRows(inSection section: Int) -> Int {
    -    guard section == 0 else { return 0 }
    -    return pizzas.count
    -}
    -
    -
    func testRowsInOutOfBoundsSectionIsZero() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +
    func numberOfRows(inSection section: Int) -> Int {
    +    guard section == 0 else { return 0 }
    +    return pizzas.count
    +}
    +
    func testRowsInOutOfBoundsSectionIsZero() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 1), 0)  // ✅
    -    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅
    -}
    -
    + XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅ +}

    We made a change and the tests are passing, it's time to commit: Handle out of bounds sections in numberOfRows(inSection:).

    Next step, make MenuDataSource return what to display for a given a section and row. It's useful to make the return value a distinct type, let's call it MenuItem. The reason this is better than returning a Pizza is that it introduces a separation between the domain of the data, pizzas, and the domain of the UI, menu items. This separation allows us to change either of the domains without affecting the other, only the code that converts between the two.

    But how can we verify that the MenuItem returned by the method is the one we're expecting? Or rather, what's the simplest thing we can do to verify that the MenuItem returned by the method is the expected one? Using pizza name seems like a good candidate for this, if a pizza is named "Margherita" the MenuItem should have title "Margherita" as well.

    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza(), Pizza()])
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita") 
         // 🔴 Value of type 'MenuDataSource' has no member 'item'
    -}
    -
    +}

    The simplest code we can write to make this test pass is having a MenuItem with title that's always "Margherita".

    -
    // in MenuItemDataSource.swift
    -func item(forRow row: Int, inSection section: Int) -> MenuItem {
    +
    // in MenuItemDataSource.swift
    +func item(forRow row: Int, inSection section: Int) -> MenuItem {
        return MenuItem()
     }
     
     // in MenuItem.swift
     struct MenuItem {
     
    -    let title = "Margherita"
    -}
    -
    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza()])
    +    let title = "Margherita"
    +}
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(pizzas: [Pizza(), Pizza()])
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita")  // ✅
    -}
    -
    +}

    We have a green test, it's admittedly incomplete, but still enough for us to have a solid foundation to build upon. Let's commit it: Implement dummy item(forRow:, inSection:) in MenuDataSource.

    Our test is not yet testing the "if a pizza is named 'Margherita'" behaviour. To refine our test we need a way to give it Pizzas with different names. It's time to grow the definition of Pizza with a name property.

    Before making the change to the Pizza init and its consumers let's make the change easy to make. In Kent Beck's words "make the change easy, warning this might be hard, then make the easy change".

    A way to make the change easier is to reduce number of places in the code where we init Pizza directly. We can do that using a fixture extension.

    -
    @testable import Giuseppes
    +
    @testable import Giuseppes
     
     extension Pizza {
     
    -    static func fixture() -> Pizza {
    +    static func fixture() -> Pizza {
             return Pizza()
         }
    -}
    -
    +}

    The extension is not doing anything now, but it will make changing the init of Pizza easier because we'll only have to update the fixture, not all the tests.

    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture()])
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture()])
         XCTAssertEqual(dataSource.numberOfSections, 1) // ✅
     }
     
    -func testRowsInSection() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
    +func testRowsInSection() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3) // ✅
     }
     
    -func testRowsInOutOfBoundsSectionIsZero() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
    +func testRowsInOutOfBoundsSectionIsZero() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 1), 0) // ✅
    -    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅
    +    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅
     }
     
    -func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture()])
    +func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture()])
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita") // ✅
    -}
    -
    +}

    Time to commit, Use fixture extension for Pizza.

    Now that we've made the change easy, now let's make the easy change. As always, we start from the tests.

    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
             // 🔴 Argument passed to call that takes no arguments
         )
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita")
    -}
    -
    +}

    The tests are not compiling because Pizza and its fixture don't have a name. Here you can see how having a fixture makes changing tests easier. By defaulting the name parameter we make it so that all the tests calling .fixture() don't need to be updated, unless we want to test behaviour depending directly on the value by passing a custom one.

    -
    // Pizza.swift
    +
    // Pizza.swift
     struct Pizza {
     
         let name: String
    @@ -246,48 +221,45 @@
     // Pizza+Fixture.swift
     extension Pizza {
     
    -    static func fixture(name: String = "Margherita") -> Pizza {
    +    static func fixture(name: String = "Margherita") -> Pizza {
             return Pizza(name: name)
         }
    -}
    -
    -
    func testHasOneSection() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture()])
    +}
    +
    func testHasOneSection() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture()])
         XCTAssertEqual(dataSource.numberOfSections, 1) // ✅
     }
     
    -func testRowsInSection() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
    +func testRowsInSection() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 0), 3) // ✅
     }
     
    -func testRowsInOutOfBoundsSectionIsZero() {
    -    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
    +func testRowsInOutOfBoundsSectionIsZero() {
    +    let dataSource = MenuDataSource(pizzas: [.fixture(), .fixture(), .fixture()])
         XCTAssertEqual(dataSource.numberOfRows(inSection: 1), 0) // ✅
    -    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅
    +    XCTAssertEqual(dataSource.numberOfRows(inSection: -1), 0) // ✅
     }
     
    -func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita") // ✅
    -}
    -
    +}

    You know what's next right? Commit: Add name property to Pizza.

    This time, rather than replacing the dummy implementation straightaway let's add another test to prove the code we have right now is incorrect. This technique is called triangulation (even if we're using only two assertions).

    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita") // ✅
         XCTAssertEqual(dataSource.item(forRow: 1, inSection: 0).title, "Capricciosa")
         // ❌ XCTAssertEqual failed: ("Margherita") is not equal to ("Capricciosa")
    -}
    -
    +}

    Let's write a proper implementation:

    -
    // MenuDataSource.swift
    -func item(forRow row: Int, inSection section: Int) -> MenuItem {
    +
    // MenuDataSource.swift
    +func item(forRow row: Int, inSection section: Int) -> MenuItem {
        return MenuItem(pizza: pizzas[row])
     }
     
    @@ -299,40 +271,36 @@
     
     extension MenuItem {
     
    -    init(pizza: Pizza) {
    +    init(pizza: Pizza) {
             self.init(title: pizza.name)
         }
    -}
    -
    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +}
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita") // ✅
         XCTAssertEqual(dataSource.item(forRow: 1, inSection: 0).title, "Capricciosa") // ✅
    -}
    -
    +}

    Commit Provide actual implementation for item(forRow:, inSection:)

    Like we did for numbe of rows, we should ask ourselves whether we've covered the behaviour for all the possible kinds of input. What would happen if we gave a section index that doesn't match? What about a row? Given this method is called "item for row in section" if the row and section pair doesn't match the backing data then returning "nothing" seems appropriate. Swift's beautiful Optional type is the best tool to describe this scenario.

    -
    func testItemForOutOfBoundsRowAndSectionIsNil() {
    -    let dataSource = MenuDataSource(
    +
    func testItemForOutOfBoundsRowAndSectionIsNil() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 0))
         XCTAssertNil(dataSource.item(forRow: 0, inSection: 1))
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 1))
    -    XCTAssertNil(dataSource.item(forRow: -1, inSection: -1))
    -}
    -
    + XCTAssertNil(dataSource.item(forRow: -1, inSection: -1)) +}

    screenshot of tests crashing

    Running the tests now results in a crash, after all we are accessing an out of bounds array. What's the simplest way we can fix it?

    -
    func item(forRow row: Int, inSection section: Int) -> MenuItem? {
    -    guard row >= 0, pizzas.count > row else { return .none }
    +
    func item(forRow row: Int, inSection section: Int) -> MenuItem? {
    +    guard row >= 0, pizzas.count > row else { return .none }
         return MenuItem(pizza: pizzas[row])
    -}
    -
    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +}
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0).title, "Margherita")
    @@ -341,72 +309,67 @@
         XCTAssertEqual(dataSource.item(forRow: 1, inSection: 0).title, "Capricciosa")
         // 🔴 Value of optional type 'MenuItem?' must be unwrapped to refer to member 'title'
         // of wrapped base type 'MenuItem'
    -}
    -
    +}

    Notice that this change in the type signature of item(forRow:, inSection:) from -> MenuItem to -> MenuItem? broke the tests. We need to update the other calls to the methods to take into account the new optionality.

    -
    func testItemForRowAndSection() {
    -    let dataSource = MenuDataSource(
    +
    func testItemForRowAndSection() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
    -    XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0)?.title, "Margherita") // ✅
    -    XCTAssertEqual(dataSource.item(forRow: 1, inSection: 0)?.title, "Capricciosa") // ✅
    +    XCTAssertEqual(dataSource.item(forRow: 0, inSection: 0)?.title, "Margherita") // ✅
    +    XCTAssertEqual(dataSource.item(forRow: 1, inSection: 0)?.title, "Capricciosa") // ✅
     }
     
    -func testItemForOutOfBoundsRowAndSectionIsNil() {
    -    let dataSource = MenuDataSource(
    +func testItemForOutOfBoundsRowAndSectionIsNil() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 0)) // ✅
         XCTAssertNil(dataSource.item(forRow: 0, inSection: 1))
         // ❌ XCTAssertNil failed: "MenuItem(title: "Margherita")"
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 1)) // ✅
    -    XCTAssertNil(dataSource.item(forRow: -1, inSection: -1)) // ✅
    -}
    -
    + XCTAssertNil(dataSource.item(forRow: -1, inSection: -1)) // ✅ +}

    No crash, but still the test for out of bounds section is failing. That's because in the code above we only checked for the row. Let's make the check comprehensive.

    -
    func item(forRow row: Int, inSection section: Int) -> MenuItem? {
    -    guard section == 0 else { return .none }
    -    guard row >= 0, pizzas.count > row else { return .none }
    +
    func item(forRow row: Int, inSection section: Int) -> MenuItem? {
    +    guard section == 0 else { return .none }
    +    guard row >= 0, pizzas.count > row else { return .none }
     
         return MenuItem(pizza: pizzas[row])
    -}
    -
    -
    func testItemForOutOfBoundsRowAndSectionIsNil() {
    -    let dataSource = MenuDataSource(
    +}
    +
    func testItemForOutOfBoundsRowAndSectionIsNil() {
    +    let dataSource = MenuDataSource(
             pizzas: [.fixture(name: "Margherita"), .fixture(name: "Capricciosa")]
         )
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 0)) // ✅
         XCTAssertNil(dataSource.item(forRow: 0, inSection: 1)) // ✅
         XCTAssertNil(dataSource.item(forRow: 2, inSection: 1)) // ✅
    -    XCTAssertNil(dataSource.item(forRow: -1, inSection: -1)) // ✅
    -}
    -
    + XCTAssertNil(dataSource.item(forRow: -1, inSection: -1)) // ✅ +}

    All the tests are now passing, happy days. Commit: Address out of range behaviour of item(forRow:, inSection:).

    We now have a functioning data source for our menu of pizzas. 🎉. The next step would be to feed it into a view controller to show that information to a user. We can of course drive that implementation with tests too, but that's out of the scope of this post.

    Here's how MenuDataSource can be used to back a UITableView.

    -
    extension MenuViewController: UITableViewDataSource {
    +
    extension MenuViewController: UITableViewDataSource {
     
    -    func numberOfSections(in tableView: UITableView) -> Int {
    +    func numberOfSections(in tableView: UITableView) -> Int {
             return menuDataSource.numberOfSections
         }
     
    -    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    +    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
             return menuDataSource.numberOfRows(inSection: section)
         }
     
    -    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    -        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    -        guard let item = menuDataSource.item(forRow: indexPath.row, inSection: indexPath.section) else {
    +    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    +        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
    +        guard let item = menuDataSource.item(forRow: indexPath.row, inSection: indexPath.section) else {
                 return cell
             }
     
    -        cell.textLabel?.text = item.title
    +        cell.textLabel?.text = item.title
     
             return cell
         }
    -}
    -
    -

    "It's too slow"

    +}
    +

    "It's too slow"

    A common observation I get from developers and managers is that TDDing takes longer. "It would have taken me way less time to write this without tests." Sure, it would have. But building a software product is not just a matter of writing code, we also need to make sure the code behaves as expect, and be able to change the code easily.

    On top of that, when you have only one screen to work with this might seem like overkill, but most apps don't have only one screen or one feature do they? For example if we were to add a detail screen for each item in the menu to verify how that screen behaves we would have to always navigate to it. If most of the behaviour is covered by tests we can verify it simply by running the tests, and launch and navigate through the app only when necessary to verify UI details, saving a lot of time.

    When driving your implementation with tests you go a bit slower in the writing phase to go faster in all the other steps of the development process. It's also important to note that as you get more hours of TDD under your belt you'll get faster at it. The maturity of a test driven codebase helps writing tests faster too, as you'll have a lot of infrastructure already in place.

    diff --git a/blog/stephen-king-advice-to-software-developers/index.html b/blog/stephen-king-advice-to-software-developers/index.html index ef6cd8e..2275a3f 100644 --- a/blog/stephen-king-advice-to-software-developers/index.html +++ b/blog/stephen-king-advice-to-software-developers/index.html @@ -55,6 +55,8 @@

    Door shut, door open

    Writing with the door closed is the first step in the creation of every story.

    The closed door is your way of telling the world and yourself that you mean business; you have made a serious commitment to write and intend to walk the walk as well as talk the talk.

    +
    +

    With the door shut, downloading what's in my head directly in the page, I write as fast as I can and still remain comfortable.

    The safety of the door close means the author can be unrestrained, focusing only on putting words on page. With the door closed you can build the skeleton of the story and refine it till it can "stand on its own". Once this is done the office door can be opened and the story can be shown to the world.

    diff --git a/blog/streamlining-tests-setup-with-fixtures-in-swift/index.html b/blog/streamlining-tests-setup-with-fixtures-in-swift/index.html index f53dd66..ba100e9 100644 --- a/blog/streamlining-tests-setup-with-fixtures-in-swift/index.html +++ b/blog/streamlining-tests-setup-with-fixtures-in-swift/index.html @@ -5,12 +5,12 @@

    Those input values are not test doubles but actual instances of your system's types.

    To keep the tests focused and easy to write it's good to abstract their creation to another place. This will make your tests shorter and easier to read, their content focused on acting and asserting the system under test, with little distraction in the setup stage.

    For example, compare these two tests:

    -
    func testWithLongSetup() {
    -  let base = Base(flour: .00, thin: true)
    -  let toppings = [TomatoSauce(), Mozzarella(), Salami(extraSpicy: false)]
    -  let pizza = Pizza(base: base, toppings: toppings)
    +
    func testWithLongSetup() {
    +  let base = Base(flour: .00, thin: true)
    +  let toppings = [TomatoSauce(), Mozzarella(), Salami(extraSpicy: false)]
    +  let pizza = Pizza(base: base, toppings: toppings)
     
    -  let deliveryAddress = Address(
    +  let deliveryAddress = Address(
         street: "1 Infinite Loop",
         town: "Cupertino",
         state: "CA",
    @@ -18,64 +18,58 @@
         country: "USA"
       )
     
    -  let order = Order(pizzas: [pizza], deliveryAddress: deliveryAddress)
    +  let order = Order(pizzas: [pizza], deliveryAddress: deliveryAddress)
     
       XCTAssertEqual(order.itemsCount, 1)
    -}
    -
    -
    func testWithShortSetup() {
    -  let order = Order(
    +}
    +
    func testWithShortSetup() {
    +  let order = Order(
         pizzas: [salamiPizza()],
         deliveryAddress: mothershipAddress()
       )
     
       XCTAssertEqual(order.itemsCount, 1)
    -}
    -
    +}

    The second example is shorter and arguably easier to read. Having removed the long setup makes it focused only on the testing of the behaviour.

    This kind of input values for tests are called fixtures. The JUnit 4 documentation defines test fixtures as:

    a fixed state of a set of objects used as a baseline for running tests. The purpose of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable.

    A popular library in the Ruby on Rails testing community is factory_bot. It allows the creation of fixtures with a syntax like:

    -
    user = create(:user)
    -pizza = create(:pizza, :toppings: [:pepperoni, :mozzarella])
    -
    +
    user = create(:user)
    +pizza = create(:pizza, :toppings: [:pepperoni, :mozzarella])

    Using factory_bot simplifies the test code setup, while retaining the ability to set values relevant for the behaviour under test. The library is easy to use thanks to Ruby being a dynamic language and the great work of the authors, maintainers, and contributors.

    Swift is a stricter language than Ruby. I don't know of a way to pass a literal to a function and have it return an instance of a type matching that literal, pre-filled with default values like factory_bot does without having to write extra code.

    My poor man's approach to get a similar behaviour is to use an extension in the test target, and do some manual labor.

    -
    extension Pizza {
    +
    extension Pizza {
     
    -  static func fixture(
    -    name: String = "name",
    -    toppings: [Topping] = [TomatoSauce(), Mozzarella()]
    -  ) -> Pizza {
    +  static func fixture(
    +    name: String = "name",
    +    toppings: [Topping] = [TomatoSauce(), Mozzarella()]
    +  ) -> Pizza {
         return Pizza(name: name, toppings: toppings)
       }
    -}
    -
    +}

    A note on using "name" as the default value for the name: parameter. When setting default values in the tests it's tempting to get creative and smart. In the past I was proud of how many references to Marvel comics I could spread in my test suites.

    In his excellent course Refactoring Rails, Ben Orenstein recommends using boring values for all those inputs that don't matter for the outcome of the test. Ben points out that having interesting input values, code that draws the eyes, makes the reader think the inputs are important for the outcome of the test. But if that's not the case then these smart tests are subtly lying to us.

    Now let's see how to use these fixtures. If the behaviour you are testing doesn't care about how the inputs are built you can call fixture() with no argument, this will create an instance with all default values.

    -
    let order = Order(pizzas: [Pizza.fixture()], drinks: [Beverage.fixture()])
    +
    let order = Order(pizzas: [Pizza.fixture()], drinks: [Beverage.fixture()])
     
    -XCTAssertEqual(order.items, 2)
    -
    +XCTAssertEqual(order.items, 2)

    If the behaviour you are testing depends on some properties of its inputs you can set those and only those in the call to fixture().

    -
    let pizza = Pizza.fixture(toppings: [TomatoSauce(), Mozzarella()]).isVegetarian
    +
    let pizza = Pizza.fixture(toppings: [TomatoSauce(), Mozzarella()]).isVegetarian
     XCTAssertTrue(pizza.isVegetarian)
     
    -let otherPizza = Pizza.fixture(toppings: [TomatoSauce(), Mozzarella(), Salami()]).isVegetarian
    -XCTAssertFalse(pizza.isVegetarian)
    -
    +let otherPizza = Pizza.fixture(toppings: [TomatoSauce(), Mozzarella(), Salami()]).isVegetarian +XCTAssertFalse(pizza.isVegetarian)

    When working with fixtures I found it's best to violate the YAGNI principle. It's worth spending the time to build a complete fixture as soon as you need it, rather than adding functionality to it when it's required. You should build a fixture extension with all the type's init parameters in its argument list, rather than only the ones needed by your test right now.

    -
    // Incomplete fixture
    +
    // Incomplete fixture
     extension Topping {
     
    -  static func fixture(
    -    name: String = "name",
    -    isVegetarian: Bool = false
    -  ) -> Topping {
    +  static func fixture(
    +    name: String = "name",
    +    isVegetarian: Bool = false
    +  ) -> Topping {
         return Topping(
           name: name,
           sku: "12AB",
    @@ -89,13 +83,13 @@
     // Complete fixture
     extension Topping {
     
    -  static func fixture(
    -    name: String = "name",
    -    sku: String = "a-sku",
    -    isVegetarian: Bool = false,
    -    isVegan: Bool = false,
    -    isGlutenFree: Bool = false
    -  ) -> Topping {
    +  static func fixture(
    +    name: String = "name",
    +    sku: String = "a-sku",
    +    isVegetarian: Bool = false,
    +    isVegan: Bool = false,
    +    isGlutenFree: Bool = false
    +  ) -> Topping {
         return Topping(
           name: name,
           sku: sku,
    @@ -104,13 +98,12 @@
           isGlutenFree: isGlutenFree
         )
       }
    -}
    -
    +}

    The extra work you put in creating the fixture will pay off in later PRs, when you or your team mates won't have to go off track to add the support for the input value they need to test against. It'll be already there.

    -

    Why not a convenience init?

    +

    Why not a convenience init?

    The reason I'm suggesting to use a static func rather than a convenience init with all the default values is because calling .fixture() tells the reader the code is getting a test value more explicitly.

    On top of that, it's not always possible to define a convenience initializer for a type keeping the argument labels the same as the type's properties. So for consistency I prefer to always use the .fixture() approach, which can always be implemented.

    -

    Where to put the fixtures?

    +

    Where to put the fixtures?

    You can either put all the fixture extensions in a Fixtures.swift file in the test target, or used a dedicated Type+Fixture.swift file for each. I prefer the latter.

    Screenshot of the Xcode navigator showing Swift fixture files with the +Fixture suffix

    Live Demo

    diff --git a/blog/swift-array-string-characters/index.html b/blog/swift-array-string-characters/index.html index fa0a151..ae995a3 100644 --- a/blog/swift-array-string-characters/index.html +++ b/blog/swift-array-string-characters/index.html @@ -1,13 +1,10 @@ Swift array of characters from String | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Swift array of characters from String

    Sometimes you might need to get an array of characters out of a String, for example:

    -
    "foo bar" => ["f", "o", "o", " ", "b", "a", "r"]
    -

    To do so you can do:

    -
    "foo bar".map { String($0) }
    -
    +
    "foo bar" => ["f", "o", "o", " ", "b", "a", "r"]

    To do so you can do:

    +
    "foo bar".map { String($0) }

    or if you are into point free notation:

    -
    "foo bar".map(String.init)
    -
    +
    "foo bar".map(String.init)

    There you go. 😎


    For the record, this post dates back to Swift version 2. If you're into programming language archeology, checkout the original version here.

    diff --git a/blog/swift-either/index.html b/blog/swift-either/index.html index 1c15d76..98d18cc 100644 --- a/blog/swift-either/index.html +++ b/blog/swift-either/index.html @@ -15,22 +15,20 @@

    Either

    The Either type represents duality, a value that can either be of a type or another.

    This is how we can write Either:

    -
    enum Either<A, B>{
    +
    enum Either<A, B>{
       case Left(A)
       case Right(B)
    -}
    -
    +}

    Either allows us to write elegant, self explanatory, and type safe code by switching on it:

    -
    let x: Either<SomeType, AnotherType> = ...
    +
    let x: Either<SomeType, AnotherType> = ...
     
     switch x {
     case .Left(let someTypeValue):
       // do something with someTypeValue
     case .Right(let anotherTypeValue):
       // do something with anotherTypeValue
    -}
    -
    +}

    Defined like that Either might not seem very practical, but here's a great usage for either: injecting extra cells in a table or collection view.

    Injecting cells in a table view using Either

    @@ -44,25 +42,24 @@

    Injecting cells in a table already displayed.

    Or we could use Either.

    Rather than an array of cell models we could feed the data source an array of Either<CellModel, BannerModel>.

    -
    let data: [Either<CellModel, BannerModel>] = ...
    +
    let data: [Either<CellModel, BannerModel>] = ...
     
    -func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    -  return data.count
    -}
    -
    +func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return data.count +}

    In the tableView(_:cellForRowAt:) method we could then get the item for the current index path and simply switch and behave accordingly to its type.

    -
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    -    let item = data[indexPath.row]
    +
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    +    let item = data[indexPath.row]
     
    -    let identifier: String = {
    +    let identifier: String = {
             switch item {
             case .Left: return pizzaCellIdentifier
             case .Right: return adCellIdentifier
             }
         }()
     
    -    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
    +    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
     
         switch item {
         case .Left(let pizza):
    @@ -72,8 +69,7 @@ 

    Injecting cells in a table } return cell -} -

    +}

    This approach seems more solid to me. It doesn't rely on any math, making the code easier to digest, and I find the switch-case construct a very elegant and self explanatory way to describe behaviour.

    diff --git a/blog/swift-test-doubles/index.html b/blog/swift-test-doubles/index.html index 21ee59c..e550a6e 100644 --- a/blog/swift-test-doubles/index.html +++ b/blog/swift-test-doubles/index.html @@ -8,13 +8,12 @@

    Dummy

    A dummy is a test double that doesn't do anything.

    You might use this as a placeholder for an input parameter of the system under test when it doesn't interact or affect the behaviour you are testing.

    -
    struct DummyPizzaGetter: PizzaGetter {
    +
    struct DummyPizzaGetter: PizzaGetter {
     
    -    func getPizza(_ completion: (Result<[Pizza], PizzaAPIError>) -> Void) {
    +    func getPizza(_ completion: (Result<[Pizza], PizzaAPIError>) -> Void) {
           // does nothing
         }
    -}
    -
    +}

    Fake

    A fake is test double returning the same value or performing the same behaviour all the time.

    You might want to use this when the behaviour of the system under test has something your component does as a pre-requisite, regardless of its outcome.

    @@ -25,8 +24,8 @@

    Stub

    A common use case for stubs is to allow testing how objects behave depending on the success or failure of an operation.

    My favourite use case for stubs is when testing the behaviour of objects consuming a service making a request that can succeed or fail. We can write a stub in which we control whether the request succeeds or fail, and this allows us to test the behaviour of our component in both scenarios.

    Say we have a PizzaPresenter charged with providing view controllers the logic to fetch pizzas from the server and transform them into objects that can be displayed. We can test how it behaves if the request succeeds or fails using a stub.

    -
    func testSuccessfulLoad() {
    -    let presenter = PizzaPresenter(
    +
    func testSuccessfulLoad() {
    +    let presenter = PizzaPresenter(
             pizzaGetter: PizzaGetterStub(pizzas: [.margherita, .pepperoni])
         )
     
    @@ -36,14 +35,14 @@ 

    Stub

    case .success(let displayablePizzas): // expectations on the received displayable pizzas case .failure(let error): - fail("Expected to succeed, failed with \(error)") + fail("Expected to succeed, failed with \(error)") } } } } -func testFailedLoad() { - let presenter = PizzaPresenter( +func testFailedLoad() { + let presenter = PizzaPresenter( pizzaGetter: PizzaGetterStub(error: .offline) ) @@ -51,77 +50,72 @@

    Stub

    presenter.load { result in switch result { case .success(let displayablePizzas): - fail("Expected to fail, succeeded with \(dispayablePizzas)") + fail("Expected to fail, succeeded with \(dispayablePizzas)") case .failure(let error): // expectation on the received error } } } -} -
    +}

    This is how the stub looks like:

    -
    class PizzaGetterStub: PizzaGetter {
    +
    class PizzaGetterStub: PizzaGetter {
     
         private let result: Result<[Pizza], PizzaAPIError>
     
    -    init(pizzas: [Pizza]) {
    -        self.result = .success(pizzas)
    +    init(pizzas: [Pizza]) {
    +        self.result = .success(pizzas)
         }
     
    -    init(error: PizzaAPIError) {
    -        self.result = .failure(error)
    +    init(error: PizzaAPIError) {
    +        self.result = .failure(error)
         }
     
    -    func getPizzas(_ completion: (Result<[Pizza], PizzaAPIError>) -> Void) {
    +    func getPizzas(_ completion: (Result<[Pizza], PizzaAPIError>) -> Void) {
             completion(result)
         }
    -}
    -
    +}

    Spy

    A spy is a test double you can use to inspect the output produced by the system under test.

    Spies are the opposite of stubs. When the system under test performs a side effect on a dependency you can use a spy to record the effect and then verify it matches the expected behaviour.

    For example, every one is implementing Dark Mode in their iOS apps nowadays. Say you want to test SettingsController, the component which your settings view controller uses to relay the user interaction with the UI.

    -
    class SettingsController {
    +
    class SettingsController {
     
         // ...
     
    -    func set(darkModeEnabled enabled: Bool) {
    +    func set(darkModeEnabled enabled: Bool) {
             if enabled {
                 layoutManager.paintDarkMode()
             } else {
                 layoutManager.paintLightMode()
             }
     
    -        settingsStorage.set(darkModeEnabled: enabled)
    +        settingsStorage.set(darkModeEnabled: enabled)
         }
    -}
    -
    +}

    The behaviour you want to test is that SettingsController correctly stores the dark mode preference. You can provide a spy for the storage layer, and make sure the right value is put there.

    -
    class SettingsStorageSpy: SettingsStorage {
    +
    class SettingsStorageSpy: SettingsStorage {
     
    -    private(set) var darkModeEnabled: Bool?
    +    private(set) var darkModeEnabled: Bool?
     
    -    func set(darkModeEnabled enabled: Bool) {
    -        self.darkModeEnabled = enabled
    +    func set(darkModeEnabled enabled: Bool) {
    +        self.darkModeEnabled = enabled
         }
    -}
    -
    +}

    Notice how darkModeEnabled is an Optional Bool. This will allow you to test whether the value is set at all. If your test will read a .none for darkModeEnabled you'll know your code didn't call set(darkModeEnabled:).

    This is how to use the spy:

    -
    func testSettingDarkMode() {
    -    let spy = SettingsStorageSpy()
    -    let controller = SettingsController(
    +
    func testSettingDarkMode() {
    +    let spy = SettingsStorageSpy()
    +    let controller = SettingsController(
             layoutManager: LayoutManagerDummy(),
             settingsStorage: spy
         )
     
    -    controller.set(darkModeEnabled: true)
    +    controller.set(darkModeEnabled: true)
     
    -    expect(spy.darkModeEnabled) == true
    -}
    -
    + expect(spy.darkModeEnabled) == true +}

    Notice how we passed a dummy for the LayoutManager input parameter. SettingsController needs a LayoutManager value to initialize, but our test doesn't care about how it interacts with it, so we can pass a dummy.

    -

    What about mocks?

    +

    What about mocks?

    If you are reading about unit testing sooner or later you'll come across the "mock" word. Mock is a word bloated with meaning in the testing vocabulary.

    Martin Fowler refers to mocks as doubles that are "pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting."

    If you are working on a dynamic language chances are there's a mocking framework for it. Objective-C has OCMock, JavaScript has Mocha and Sinon, Ruby has rspec-mock, just to name a few. All these frameworks are powerful and flexible, they provide a way to build not only mocks, but stubs, fakes, and spies too.

    diff --git a/blog/swift-unavailable-how-to/index.html b/blog/swift-unavailable-how-to/index.html index 9e27334..fde2dfa 100644 --- a/blog/swift-unavailable-how-to/index.html +++ b/blog/swift-unavailable-how-to/index.html @@ -6,27 +6,25 @@
  • Legacy code that we need to keep in the source to keep supporting old versions or documentation.
  • In such cases we can use Swift's available declaration attribute to tell the compiler that code using the marked object or function should not compile.

    -
    // Swift 2.2
    -@available(<platform>, unavailable=<version>, message=<message>)
    +
    // Swift 2.2
    +@available(<platform>, unavailable=<version>, message=<message>)
     
     // Swift 3
    -@available(<platform>, unavailable: <version>, message: <message>)
    -
    +@available(<platform>, unavailable: <version>, message: <message>)

    For example, if you have to subclass NSObject into something that has a stored constant which needs to be passed at initialization, and don't want to allow consumers to call init because it doesn't make sense to set a default value for the constant, you can make init unavailable to its consumers:

    -
    class Dummy: NSObject {
    +
    class Dummy: NSObject {
     
       let foo: String
     
    -  init(foo: String) {
    -    self.foo = foo
    +  init(foo: String) {
    +    self.foo = foo
       }
     
    -  @available(*, unavailable)
    -  override init() {
    +  @available(*, unavailable)
    +  override init() {
         fatalError()
       }
    -}
    -
    +}

    Note how the platform parameter has * value, which means any platform, and unavailable has no version value, which means that the methods is unavailable regardless of the current version.

    Unfortunately, as of 2.2, this kind of availability declaration is not converted into an Objective-C attribute, so Objective-C consumers will still see the methods and classes as available.

    If you are reading this and know a way to make Swift code unavailable to both Swift and Objective-C callers, please let me know by leaving a comment below, or getting in touch on Twitter @mokagio. Thanks.

    diff --git a/blog/swiftui-dependency-injection/index.html b/blog/swiftui-dependency-injection/index.html index d190fb1..23bb539 100644 --- a/blog/swiftui-dependency-injection/index.html +++ b/blog/swiftui-dependency-injection/index.html @@ -8,20 +8,19 @@

    Dependency Injection

    Dependency injection, DI for short, is the practice of providing an object with the other objects it depends on rather than creating them internally.

    -
    // Without dependency injection
    +
    // Without dependency injection
     class Foo {
    -    let bar: Bar = Bar()
    +    let bar: Bar = Bar()
     }
     
     // With dependecy injection
     class Foo {
         let bar: Bar
     
    -    init(bar: Bar) {
    -        self.bar = bar
    +    init(bar: Bar) {
    +        self.bar = bar
         }
    -}
    -
    +}

    DI makes the design more flexible, keeps your code honest, and, when paired with a protocol, allows you to test the object behavior by providing test doubles.

    The challenge with dependency injection is how to provide components with the dependencies they need without manually passing them through all of their ancestors in the hierarchy. @EnvironmentObject and the View Model Factory both provide a clean solution to this.

    @@ -29,7 +28,7 @@

    Dependency Injection

    A tab view hosts two screens: one shows you all the books in the library, another your to-read list. You can select a title from the library list to see its details, then add it or remove it from your to-read list.

    The to-read list and book detail views both need access to the reading list storage; let's call it ReadingListController.

    -
    import Combine
    +
    import Combine
     
     class ReadingListController: ObservableObject {
     
    @@ -38,17 +37,16 @@ 

    Dependency Injection

    // // For the sake of this example, let's use in-memory storage. In the real // world, we'd be storing to disk and/or calling a remote API. - @Published private(set) var readingList: [Book] = [] + @Published private(set) var readingList: [Book] = [] - func isBookInList(_ book: Book) -> Bool { ... } + func isBookInList(_ book: Book) -> Bool { ... } - func add(_ book: Book) { ... } + func add(_ book: Book) { ... } - func remove(_ book: Book) { ... } -} -
    + func remove(_ book: Book) { ... } +}

    Let's have a look at the two approaches to inject this dependency.

    -

    @EnvironmentObject

    +

    @EnvironmentObject

    SwiftUI offers the @EnvironmentObject property wrapper to define "an observable object supplied by a parent or ancestor view." Every time the wrapped ObservableObject emits a change, the framework will invalidate the view, resulting in a redraw.

    @EnvironmentObject allows us to inject dependencies because it looks for its value in the SwiftUI environment. @@ -56,17 +54,17 @@

    @EnvironmentObject

    The way to add the dependency into the environment is to call the environmentObject(_:) method on any ancestor of the view that needs to access it. I find this is best done at the top level: in the App implementation or in the UIWindowSceneDelegate if you are mix-and-matching SwiftUI with UIKit.

    Let's look at some code; you can get the source for this example here.

    -
    import SwiftUI
    +
    import SwiftUI
     
    -@main
    +@main
     struct ReadingListApp: App {
     
         // The interface with the reading list storage.
         // This is the only place where we instantiate ReadingListController; no
         // singletons or static shared instances needed.
    -    let readingListController = ReadingListController()
    +    let readingListController = ReadingListController()
     
    -    var body: some Scene {
    +    var body: some Scene {
             WindowGroup {
                 TabView {
                     NavigationView {
    @@ -84,15 +82,14 @@ 

    @EnvironmentObject

    .environmentObject(readingListController) } } -} -
    +}

    The views that need access to ReadingListController can get it via @EnvironmentObject; the others don't have to know about it.

    -
    struct BookList: View {
    +
    struct BookList: View {
     
         // Let's skip how to load the library books for the sake of brevity
    -    let books: [Book] = ...
    +    let books: [Book] = ...
     
    -    var body: some View {
    +    var body: some View {
             List(books) { item in
                 // BookList defines the view where to navigate when a row is
                 // selected, but notice how it doesn't provide it with a reference
    @@ -109,9 +106,9 @@ 

    @EnvironmentObject

    let book: Book // Here, we access our injected dependency from the environment - @EnvironmentObject var readingListController: ReadingListController + @EnvironmentObject var readingListController: ReadingListController - var body: some View { + var body: some View { VStack { Text(book.title) Text(book.author) @@ -132,21 +129,20 @@

    @EnvironmentObject

    struct ToReadList: View { // Here, too, we get our ReadingListController from the environment - @EnvironmentObject var readingListController: ReadingListController + @EnvironmentObject var readingListController: ReadingListController - var body: some View { + var body: some View { List(readingListController.readingList) { item in Text(item.title) Text(item.author) } } -} -
    +}

    The code above is tidy and easy to follow once you wrap your head around how @EnvironmentObject works. Thanks to the SwiftUI framework internals, we don't have to write any code to keep the to-read list and book detail screens in sync; everything is taken care of for us.

    There's a catch, though, if you don't call environmentObject, or if someone removes it by accident, the app will crash.

    The next approach removes the risk of runtime crashes.

    -

    View Models & View Model Factory

    +

    View Models & View Model Factory

    If you use the MVVM pattern in SwiftUI, giving each view a view model containing all of the logic to present data and act on it, you can use it to inject dependencies by:

    • Moving the responsibility to build the views to show from the view layer to the view model;
    • @@ -154,13 +150,13 @@

      View Models & View Model Factory

      Creating the view models in a centralized place, which can inject the dependency as part as the view-building logic in the init.

    Views should delegate all logic to their view models, be it what view to use as the destination of a NavigationLink or what text to show in a button.

    -
    import SwiftUI
    +
    import SwiftUI
     
     struct BookList: View {
     
         let viewModel: BookListViewModel
     
    -    var body: some View {
    +    var body: some View {
             List(viewModel.books) { item in
                 // The view model tells the view what's the NavigationLink destination
                 NavigationLink(destination: viewModel.viewForSelectedBook(item)) {
    @@ -172,9 +168,9 @@ 

    View Models & View Model Factory

    struct BookDetail: View { - @ObservedObject var viewModel: BookDetailViewModel + @ObservedObject var viewModel: BookDetailViewModel - var body: some View { + var body: some View { VStack { Text(viewModel.title) Text(viewModel.author) @@ -186,14 +182,13 @@

    View Models & View Model Factory

    +}

    You can find the code sample for this approach here.

    Notice how BookDetail has no if-else conditional now. The view is humble; it does what the view model tells it without any extra logic.

    The view models themselves don't know how to build views; they ask for that knowledge in the form of a closure at init time. Have a look at BookListViewModel:

    -
    import Combine
    +
    import Combine
     
     class BookListViewModel: ObservableObject {
     
    @@ -203,9 +198,9 @@ 

    View Models & View Model Factory

    // for a given book. let viewForSelectedBook: (Book) -> BookDetail - init(books: [Book], viewForSelectedBook: @escaping (Book) -> BookDetail) { - self.books = books - self.viewForSelectedBook = viewForSelectedBook + init(books: [Book], viewForSelectedBook: @escaping (Book) -> BookDetail) { + self.books = books + self.viewForSelectedBook = viewForSelectedBook } } @@ -217,78 +212,76 @@

    View Models & View Model Factory

    let title: String { book.title } let author: String { book.author } - @Published var addOrRemoveButtonText: String + @Published var addOrRemoveButtonText: String - init(book: Book, readingListController: ReadingListController) { - self.book = book - self.readingListController = readingListController + init(book: Book, readingListController: ReadingListController) { + self.book = book + self.readingListController = readingListController // This method is defined in a private extension below to DRY the code // without having to define a static function that could be accessed // here when self is not yet available. - addOrRemoveButtonText = readingListController.textForAddOrRemoveButton(for: book) + addOrRemoveButtonText = readingListController.textForAddOrRemoveButton(for: book) } - func addOrRemoveBook() { + func addOrRemoveBook() { if readingListController.isBookInList(book) { readingListController.remove(book) } else { readingListController.add(book) } - addOrRemoveButtonText = readingListController.textForAddOrRemoveButton(for: book) + addOrRemoveButtonText = readingListController.textForAddOrRemoveButton(for: book) } } private extension ReadingListController { - func textForAddOrRemoveButton(for book: Book) -> String { - isBookInList(book) ? "Remove from reading list" : "Add to reading list" + func textForAddOrRemoveButton(for book: Book) -> String { + isBookInList(book) ? "Remove from reading list" : "Add to reading list" } -} -
    +}

    The final piece of the puzzle is the actual injection of the ReadingListController dependency from a centralized location. This object will be the only one instantiating ReadingListController and will create the view models, passing the dependency to those that need it.

    A good name for an object whose sole purpose is to create other objects is factory, a hint to the factory pattern, although stripped of the functionality to let a class defer the instantiation of its components to its subclasses.

    -
    class ViewModelFactory {
    +
    class ViewModelFactory {
     
         // Like when using the environment approach, ViewModelFactory is the only
         // point where we instantiate ReadingListController; no singletons or
         // static shared instances needed.
    -    let readingListController = ReadingListController()
    +    let readingListController = ReadingListController()
     
         // Once again, let's gloss over how to load the books for the sake of
         // brevity.
    -    let books: [Book] = ...
    +    let books: [Book] = ...
     
    -    func makeBookListViewModel() -> BookListViewModel {
    +    func makeBookListViewModel() -> BookListViewModel {
             return BookListViewModel(
                 books: books,
                 viewForSelectedBook: { [unowned self] in
    -                BookDetail(viewModel: self.makeBookDetailViewModel(for: $0))
    +                BookDetail(viewModel: self.makeBookDetailViewModel(for: $0))
                 }
             )
         }
     
    -    func makeBookDetailViewModel(for book: Book) -> BookDetailViewModel {
    +    func makeBookDetailViewModel(for book: Book) -> BookDetailViewModel {
             return BookDetailViewModel(book: book, readingListController: readingListController)
         }
     
    -    func makeToReadListViewModel() -> ToReadListViewModel {
    +    func makeToReadListViewModel() -> ToReadListViewModel {
             return ToReadListViewModel(readingListController: readingListController)
         }
    -}
    -
    +}

    This pattern removes the need to pass dependencies down each node of the hierarchy because ViewModelFactory builds all of the view models and each view model receives the logic to construct the views at init time.

    We can call ViewModelFactory at the top level of our SwiftUI application, be it the App or UIWindowSceneDelegate implementation, to get the view models for the root views.

    -
    import SwiftUI
    +
    import SwiftUI
     
    -@main
    +@main
     struct ReadingListApp: App {
     
    -    let viewModelFactory = ViewModelFactory()
    +    let viewModelFactory = ViewModelFactory()
     
    -    var body: some Scene {
    +    var body: some Scene {
             WindowGroup {
                 TabView {
                     NavigationView {
    @@ -305,9 +298,8 @@ 

    View Models & View Model Factory

    -

    Pros & Cons

    +}
    +

    Pros & Cons

    @EnvironmentObject trades runtime-safety for conciseness and is a more text-book SwiftUI approach, but it can crash your app.

    Using view models for dependency injection requires a bit more work and conventions that developers need to respect but is safe at runtime.

    Writing some extra code when what you get in return is runtime safety seems like a reasonable tradeoff; that's the approach I prefer. diff --git a/blog/symliks-in-git/index.html b/blog/symliks-in-git/index.html index 382f269..e5be8ff 100644 --- a/blog/symliks-in-git/index.html +++ b/blog/symliks-in-git/index.html @@ -5,12 +5,11 @@

    If you are not familiar with symbolic links, symlinks for short, I recommend reading the manpage for the ln command, or this post.

    Git can track symlinks as well as any other text files. After all, as the documentation says, a symbolic link is nothing but a file with special mode containing the path to the referenced file. Knowing how to handle links is the OS job.

    There is an important caveat when creating symlinks that are meant to be tracked under Git. The reference path of the source file should be relative to the repository, not absolute to the machine.

    -
    # Not good for Git repositories
    +
    # Not good for Git repositories
     ln -s /Users/gio/repo/foo.md ./bar/foo.md
     
     # Good for Git repositories
    -cd ./bar && ln -s ../foo.md foo.md
    -

    The reason for this is that given that a symlink contains the path to the referenced file, if the path is relative to a specific machine the link won't work on others. If it's relative to the repository itself on the other hand, the OS will always be able to find the source.

    +cd ./bar && ln -s ../foo.md foo.md

    The reason for this is that given that a symlink contains the path to the referenced file, if the path is relative to a specific machine the link won't work on others. If it's relative to the repository itself on the other hand, the OS will always be able to find the source.

    Have a look at this example repo to play around with these ideas.

    Leave the codebase better than you found it.

    diff --git a/blog/tdd-and-ydniy/index.html b/blog/tdd-and-ydniy/index.html index 7689606..c4a4e89 100644 --- a/blog/tdd-and-ydniy/index.html +++ b/blog/tdd-and-ydniy/index.html @@ -36,23 +36,21 @@

    The same goes for writing the code that makes the tests pass. One of the exercises in the book is adding a spiciness visual indicator when displaying the name of each spicy item2.

    Here's the test for the "adds spiciness indicator" behavior:

    -
    func testWhenItemIsSpicyDisplayNameHasSpicinessIndicator() {
    -    let item = MenuItem(name: "a name", spicy: true)
    -    let displayName = item.displayName
    +
    func testWhenItemIsSpicyDisplayNameHasSpicinessIndicator() {
    +    let item = MenuItem(name: "a name", spicy: true)
    +    let displayName = item.displayName
         XCTAssertEqual(displayName, "a name 🌶")
    -}
    -
    +}

    The implementation for displayName can be some kind of if-else conditional based on the model's spicy property. Do we need that conditional logic to make that single test pass just yet? No, we can simply hardcode the result.

    -
    struct MenuItem {
    +
    struct MenuItem {
     
         let name: String
         let spicy: Bool
     
    -    lazy private(set) var displayName: String = "\(name) 🌶"
    -}
    -
    + lazy private(set) var displayName: String = "\(name) 🌶" +}

    With a green test for this slice of behavior, we can refactor displayName to conditionally add the "🌶". Or, we could move on with the next test, which will initially fail because of the hardcode implementation and require us to implement the conditional logic.

    Regardless of the next step, having a test in place that we can trust gives us the confidence to move forward.

    diff --git a/blog/tdd-in-swift-book-launch/index.html b/blog/tdd-in-swift-book-launch/index.html index 5c75ada..a500448 100644 --- a/blog/tdd-in-swift-book-launch/index.html +++ b/blog/tdd-in-swift-book-launch/index.html @@ -9,14 +9,17 @@

    Structured in just the right way to help you grasp the complicated topic of Test-Driven Development. With detailed descriptions of concepts and ideas alongside coding examples, it gives you everything you need to grow your testing skills.

    +

    If you’re unfamiliar with Test-Driven Development, this book is a great introduction, building up one clear example at a time. If you are familiar with TDD, the book will teach you the testing toolkit you should be using in Swift.

    +

    As I was working through the book, one of the things it taught me very early on, which I realized that I had been kinda doing, but I was just failing because I wasn't thinking about it the right way, was how to break things down into small chunks of solvable problems.

    +

    What makes this book unique is that it approaches TDD in SwiftUI and Combine.

    You'll learn why the best way to test a SwiftUI app is not to test SwiftUI code and what to do instead. (Hint: put all the logic into a pure Swift object and use TDD on it).

    You'll see how to leverage the synergy between SwiftUI and Combine to offload all the heavy lifting of keeping views in sync with dynamic data, and how to test the thin code layer that transforms backend data into presentation data.

    diff --git a/blog/terminal-aliases/index.html b/blog/terminal-aliases/index.html index 68d2da7..03a0daf 100644 --- a/blog/terminal-aliases/index.html +++ b/blog/terminal-aliases/index.html @@ -22,11 +22,10 @@

    Getting started with aliases

    Notice how they are all just a few letters long. That's the power of aliases, they make running long commands a matter of typing a few keystrokes.

    My longest alias is glg. It prints the Git log formatted in a compact way which also shows branches relationship.

    -
    alias glg="git log \
    +
    alias glg="git log \
       --graph \
       --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue) %an%Creset' \
    -  --abbrev-commit"
    -

    Imaging having to write all that instead!

    + --abbrev-commit"

    Imaging having to write all that instead!

    If you're looking for inspiration to create aliases you can find all mine here.

    While working be mindful of the commands you used the most. Once you find yourself using a command a few times during the day create an alias for it. After a week or two you'll have aliases for 80% of what you do in the terminal and you'll be very drastically faster and more productive.

    Creating aliases for commands is just the beginning. You can also define custom functions for combination of commands.

    @@ -40,8 +39,8 @@

    Why aliases matter

    Having aliases and keyboard shortcuts tuned to your specific way of working is like taking notes by hand on blank paper. There is no friction, no boundaries, you can easily move from writing to drawing. Less friction means more bandwidth for your mind to do what it needs to do.

    Don't take my word for it. Try it out for yourself. No one has ever come back to me saying "Gio why did you make setup aliases, I'm saving too much time now."

    What aliases are you going to create? Let me know on Twitter @mokagio or by leaving a comment below.

    -

    1: Bash and other shells also support using an rc file. This post has a good explanation of the difference between the two, and when to use one rather than the other.

    -

    2: If like me you like to play devil's advocate you could argue using the mouse reduces the amount of typing even more. True, but doing so moves most the stress to the two fingers for left and right click of the hand you use the mouse with. That's even worse. That's the reason software like Blender 3D don't rely only on the left clicking. As Blender for Dummies explains: "The more you can spread the work across the hand, the lower the chance of RSI. By making it so that you're not doing every single operation with the left mouse button, Blender helps in this regard."

    +

    1: Bash and other shells also support using an `rc` file. This post has a good explanation of the difference between the two, and when to use one rather than the other.

    +

    2: If like me you like to play devil's advocate you could argue using the mouse reduces the amount of typing even more. True, but doing so moves most the stress to the two fingers for left and right click of the hand you use the mouse with. That's even worse. That's the reason software like Blender 3D don't rely only on the left clicking. As Blender for Dummies explains: "The more you can spread the work across the hand, the lower the chance of RSI. By making it so that you're not doing every single operation with the left mouse button, Blender helps in this regard."

    Want more of these posts?

    diff --git a/blog/terminal-reusing-last-command-parameter/index.html b/blog/terminal-reusing-last-command-parameter/index.html index 6b98ed7..cc1f735 100644 --- a/blog/terminal-reusing-last-command-parameter/index.html +++ b/blog/terminal-reusing-last-command-parameter/index.html @@ -1,22 +1,19 @@ How to reuse the last parameter in a terminal command | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to reuse the last parameter in a terminal command

    Say that you want to delete a branch both locally and remotely, the commands for that are:

    -
    git branch -d branch-name
    -git push --delete remote-name branch-name
    -
    +
    git branch -d branch-name
    +git push --delete remote-name branch-name

    But why do all that typing? It would be nice to be able to say to the second command: "use the parameter from the previous one".

    Well, Bash got you covered 😎. The $_ symbol (variable?) is substituted by the shell with the parameter from the last command.

    We can then write:

    -
    git branch -d branch-name
    -git push --delete remote-name $_
    -
    +
    git branch -d branch-name
    +git push --delete remote-name $_

    You might not be impressed by that in this scenario, but think how you could leverage this in a script or in combo with xargs.


    Another useful trick when it comes to reusing the last parameter is !$. When hitting enter on a command with !$ the shell will not execute it, but prompt the command again, with the last parameter used in place of !$. Example:

    -
    $ ls ~/Desktop
    +
    $ ls ~/Desktop
     $ ls -a !$
    -$ ls -a ~/Desktop
    -
    +$ ls -a ~/Desktop

    The simplest way to understand the difference between the two is to try them.

    Leave the codebase better than you found it.

    diff --git a/blog/testing-callbacks-in-swift-with-xctest/index.html b/blog/testing-callbacks-in-swift-with-xctest/index.html index ac1f398..ecbe8f4 100644 --- a/blog/testing-callbacks-in-swift-with-xctest/index.html +++ b/blog/testing-callbacks-in-swift-with-xctest/index.html @@ -8,15 +8,14 @@

    How do you test asynchronous code that calls a callback?

    Say that you have a class that perform an asynchronous operation and executes a closure callback closure passed as a method parameter.

    -
    class SomeService {
    -  func doSomethingAsync(completion: (success: Bool) -> ()) { ...  }
    +
    class SomeService {
    +  func doSomethingAsync(completion: (success: Bool) -> ()) { ...  }
     }
     
    -let service = SomeService()
    +let service = SomeService()
     service.doSomethingAsync { success in
       // ...
    -}
    -
    +}

    You might already have experienced that writing tests for code like doSomethingAsync in the traditional way will result in unexpected behaviours and false positives.

    @@ -30,16 +29,16 @@ code: XCTestExpectation.

    Let's have a look at how to test doSomethingAsync using XCTestExpectation. You can also follow along with the example project for this post.

    -
    import XCTest
    -@testable import MyApp
    +
    import XCTest
    +@testable import MyApp
     
     class CallbackTest: XCTestCase {
     
    -  func testAsyncCalback() {
    -    let service = SomeService()
    +  func testAsyncCalback() {
    +    let service = SomeService()
     
         // 1. Define an expectation
    -    let expectation = expectationWithDescription("SomeService does stuff and runs the callback closure")
    +    let expectation = expectationWithDescription("SomeService does stuff and runs the callback closure")
     
         // 2. Exercise the asynchronous code
         service.doSomethingAsync { success in
    @@ -51,13 +50,12 @@
     
         // 3. Wait for the expectation to be fulfilled
         waitForExpectationsWithTimeout(1) { error in
    -      if let error = error {
    -        XCTFail("waitForExpectationsWithTimeout errored: \(error)")
    +      if let error = error {
    +        XCTFail("waitForExpectationsWithTimeout errored: \(error)")
           }
         }
       }
    -}
    -
    +}

    As you can see there are three steps in the process.

    1. Define an expectation with a meaningful description.
    2. @@ -66,8 +64,7 @@

    It is important to provide a meaningful description because such description is reported in the failure message of an unfulfilled expectation:

    -
    error: -[PracticalTestingTests.CallbackTest testAsyncCalback] : Asynchronous wait failed: Exceeded timeout of 1 seconds, with unfulfilled expectations: "SomeService does stuff and succeeds".
    -

    When testing having descriptive failure messages is very important to make your +

    error: -[PracticalTestingTests.CallbackTest testAsyncCalback] : Asynchronous wait failed: Exceeded timeout of 1 seconds, with unfulfilled expectations: "SomeService does stuff and succeeds".

    When testing having descriptive failure messages is very important to make your future self and the rest of the team identify the failure reason as soon as possible.


    diff --git a/blog/testing-combine-publisher-cheatsheet/index.html b/blog/testing-combine-publisher-cheatsheet/index.html index 23c323a..93f9515 100644 --- a/blog/testing-combine-publisher-cheatsheet/index.html +++ b/blog/testing-combine-publisher-cheatsheet/index.html @@ -21,134 +21,131 @@ If necessary, you can run one or more XCTestAssert- assertions on the value and completion you receive.

    How to test Publisher publishes one value then finishes

    -
    let expectation = XCTestExpectation(description: "Publishes one value then finishes")
     
    -var values: [<# Publisher Output type #>] = []
    +
    let expectation = XCTestExpectation(description: "Publishes one value then finishes")
    +
    +var values: [<# Publisher Output type #>] = []
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .finished = completion else { return }
    +            guard case .finished = completion else { return }
                 expectation.fulfill()
             },
             receiveValue: { value in
                 guard values.isEmpty else {
    -                return XCTFail("Expected to receive only one value, got another: (\(value))")
    +                return XCTFail("Expected to receive only one value, got another: (\(value))")
                 }
    -            XCTAssertEqual(value, <# expected value #>)
    +            XCTAssertEqual(value, <# expected value #>)
                 values.append(value)
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    -
    +wait(for: [expectation], timeout: 0.5)

    How to test Publisher publishes one value then a failure

    -
    let expectation = XCTestExpectation(description: "Publishes one value then fails")
     
    -var values: [<# Publisher Output type #>] = []
    +
    let expectation = XCTestExpectation(description: "Publishes one value then fails")
    +
    +var values: [<# Publisher Output type #>] = []
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .failure(let error) = completion else { return }
    -            XCTAssertEqual(error, <# expected error #>)
    +            guard case .failure(let error) = completion else { return }
    +            XCTAssertEqual(error, <# expected error #>)
                 expectation.fulfill()
             },
             receiveValue: { value in
                 guard values.isEmpty else {
    -                return XCTFail("Expected to receive only one value, got another (\(value))")
    +                return XCTFail("Expected to receive only one value, got another (\(value))")
                 }
    -            XCTAssertEqual(value, <# expected value #>)
    +            XCTAssertEqual(value, <# expected value #>)
                 values.append(value)
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    -
    +wait(for: [expectation], timeout: 0.5)

    How to test Publisher publishes many values then finishes

    -
    let expectation = XCTestExpectation(description: "Publishes values then finishes")
    +
    let expectation = XCTestExpectation(description: "Publishes values then finishes")
     
    -var values: [<# Publisher Output type #>] = []
    +var values: [<# Publisher Output type #>] = []
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .finished = completion else { return }
    +            guard case .finished = completion else { return }
                 expectation.fulfill()
             },
             receiveValue: {
    -            values.append($0)
    +            values.append($0)
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    +wait(for: [expectation], timeout: 0.5)
     
    -XCTAssertEqual(values, <# expected values #>)
    -
    +XCTAssertEqual(values, <# expected values #>)

    How to test Publisher publishes many values then a failure

    -
    let expectation = XCTestExpectation(description: "Publishes many values then a failure")
    +
    let expectation = XCTestExpectation(description: "Publishes many values then a failure")
     
    -var values: [<# Publisher Output type #>] = []
    +var values: [<# Publisher Output type #>] = []
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .failure(let error) = completion else { return }
    -            XCTAssertEqual(error, <# expected error #>)
    +            guard case .failure(let error) = completion else { return }
    +            XCTAssertEqual(error, <# expected error #>)
                 expectation.fulfill()
             },
             receiveValue: {
    -            values.append($0)
    +            values.append($0)
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    +wait(for: [expectation], timeout: 0.5)
     
    -XCTAssertEqual(values, <# expected values #>)
    -
    +XCTAssertEqual(values, <# expected values #>)

    How to test Publisher publishes no values then finishes

    -
    let expectation = XCTestExpectation(description: "Finishes without publishing values")
    +
    let expectation = XCTestExpectation(description: "Finishes without publishing values")
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .finished = completion else { return }
    +            guard case .finished = completion else { return }
                 expectation.fulfill()
             },
             receiveValue: {
    -            XCTFail("Expected to finish without receiving any value, got \($0)")
    +            XCTFail("Expected to finish without receiving any value, got \($0)")
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    -
    +wait(for: [expectation], timeout: 0.5)

    How to test Publisher publishes no values then a failure

    -
    let expectation = XCTestExpectation(description: "Fails without publishing values")
    +
    +
    let expectation = XCTestExpectation(description: "Fails without publishing values")
     
     publisher
         .sink(
             receiveCompletion: { completion in
    -            guard case .failure(let error) = completion else { return }
    -            XCTAssertEqual(error, <# expected error #>)
    +            guard case .failure(let error) = completion else { return }
    +            XCTAssertEqual(error, <# expected error #>)
                 expectation.fulfill()
             },
             receiveValue: {
    -            XCTFail("Expected to fail without receiving any value, got \($0)")
    +            XCTFail("Expected to fail without receiving any value, got \($0)")
             }
         )
    -    .store(in: &cancellables)
    +    .store(in: &cancellables)
     
    -wait(for: [expectation], timeout: 0.5)
    -
    +wait(for: [expectation], timeout: 0.5)

    You'll find more insights on how to write tests for code using Combine in my book Test-Driven Development in Swift with SwiftUI and Combine.

    What are the most common Publisher behavior you test? diff --git a/blog/testing-delegates-in-swift-with-xctest/index.html b/blog/testing-delegates-in-swift-with-xctest/index.html index 6897e7e..6d2238b 100644 --- a/blog/testing-delegates-in-swift-with-xctest/index.html +++ b/blog/testing-delegates-in-swift-with-xctest/index.html @@ -13,20 +13,19 @@

    Testing Delegate Method Call

    that verify that an object calls its delegate as a result of an asynchronous operation.

    The object and its delegate protocol usually look something like this:

    -
    protocol Delegate: class {
    +
    protocol Delegate: class {
     
    -  func somethingWithDelegate(something: SomethingWithDelegate, didAsyncStuffWithResult result: Bool)
    +  func somethingWithDelegate(something: SomethingWithDelegate, didAsyncStuffWithResult result: Bool)
     }
     
     class SomethingWithDelegate {
    -  weak var delegate: Delegate?
    +  weak var delegate: Delegate?
     
    -  func doAsyncStuff() {
    +  func doAsyncStuff() {
             // does async operation, and when operation is completed...
    -        self.delegate?.somethingWithDelegate(self, didAsyncStuffWithResult: true)
    +        self.delegate?.somethingWithDelegate(self, didAsyncStuffWithResult: true)
       }
    -}
    -
    +}

    To test this behaviour we will need to combine the XCTestExpectation API we saw in the previous post with a test pattern called Spy.

    This pattern is defined as:

    @@ -42,47 +41,46 @@

    Testing Delegate Method Call

    not really making a double of an existing class. I still feel that the Spy name is still appropriate though, because of the capturing behaviour.

    The implementation is pretty straightforward:

    -
    class SpyDelegate: Delegate {
    +
    class SpyDelegate: Delegate {
     
       // Setting .None is unnecessary, but helps with clarity imho
    -  var somethingWithDelegateAsyncResult: Bool? = .None
    +  var somethingWithDelegateAsyncResult: Bool? = .None
     
       // Async test code needs to fulfill the XCTestExpecation used for the test
         // when all the async operations have been completed. For this reason we need
         // to store a reference to the expectation
    -  var asyncExpectation: XCTestExpectation?
    +  var asyncExpectation: XCTestExpectation?
     
    -  func somethingWithDelegate(something: SomethingWithDelegate, didAsyncStuffWithResult result: Bool) {
    -    guard let expectation = asyncExpectation else {
    +  func somethingWithDelegate(something: SomethingWithDelegate, didAsyncStuffWithResult result: Bool) {
    +    guard let expectation = asyncExpectation else {
           XCTFail("SpyDelegate was not setup correctly. Missing XCTExpectation reference")
           return
         }
     
    -    somethingWithDelegateAsyncResult = result
    +    somethingWithDelegateAsyncResult = result
         expectation.fulfill()
       }
    -}
    -
    +}

    The actual test will simply need to instantiate and configure a SpyDelegate and exercise the method under test in an asynchronous way.

    -
    class DelegateTestExample: XCTestCase {
    +
    class DelegateTestExample: XCTestCase {
     
    -  func testDelegateMethodIsCalledAsync() {
    -    let something = SomethingWithDelegate()
    -    let spyDelegate = SpyDelegate()
    -    something.delegate = spyDelegate
    +  func testDelegateMethodIsCalledAsync() {
    +    let something = SomethingWithDelegate()
    +    let spyDelegate = SpyDelegate()
    +    something.delegate = spyDelegate
     
    -    let expectation = expectationWithDescription("SomethingWithDelegate calls the delegate as the result of an async method completion")
    -    spyDelegate.asyncExpectation = expectation
    +    let expectation = expectationWithDescription("SomethingWithDelegate calls the delegate as the result of an async method completion")
    +    spyDelegate.asyncExpectation = expectation
     
         something.doAsyncStuff()
     
         waitForExpectationsWithTimeout(1) { error in
    -      if let error = error {
    -        XCTFail("waitForExpectationsWithTimeout errored: \(error)")
    +      if let error = error {
    +        XCTFail("waitForExpectationsWithTimeout errored: \(error)")
           }
     
    -      guard let result = spyDelegate.somethingWithDelegateAsyncResult else {
    +      guard let result = spyDelegate.somethingWithDelegateAsyncResult else {
             XCTFail("Expected delegate to be called")
             return
           }
    @@ -90,35 +88,33 @@ 

    Testing Delegate Method Call

    XCTAssertTrue(result) } } -} -
    +}

    That's it. The amount of setup code that we need for this test is higher than for testing async code executing a callback, but they are conceptually identical.

    Other Delegate Tests

    The same approach can be used to test that a class with a delegate properly sets the value of a property or calls a synchronous method on it.

    -
    protocol Delegate: class {
    -    var property: Int? { get set }
    +
    protocol Delegate: class {
    +    var property: Int? { get set }
     }
     
     class DelegateTestExample: XCTestCase {
     
    -    func testDelegatePropertySet() {
    -        let something = SomethingWithDelegate()
    -        let spyDelegate = SpyDelegate()
    -        something.delegate = spyDelegate
    +    func testDelegatePropertySet() {
    +        let something = SomethingWithDelegate()
    +        let spyDelegate = SpyDelegate()
    +        something.delegate = spyDelegate
     
             something.methodResultingInDelegatePropertySet()
     
    -        guard let propertyValue = spyDelegate.property else {
    +        guard let propertyValue = spyDelegate.property else {
                 XCTFail("Expected delegate to be called")
                 return
             }
     
             XCTAssertEqual(propertyValue, 42)
         }
    -}
    -
    +}

    I'll let writing a test for a synchronous method call up to you.


    With Swift and functional programming becoming more popular our applications diff --git a/blog/testing-realm-apps/index.html b/blog/testing-realm-apps/index.html index f0d69a9..4ea678b 100644 --- a/blog/testing-realm-apps/index.html +++ b/blog/testing-realm-apps/index.html @@ -7,84 +7,80 @@

    Realms, and pizza

    We won't go in the details of Realm here, but you should really have a look at their docs.

    Now, let' imagine a very simple all, PizzaApp 🍕. With PizzaApp you can track your favourite pizzas offline, so even when there's no connection you can always browse them.

    This is how a pizza model looks like:

    -
    import RealmSwift
    +
    import RealmSwift
     
     class Pizza: Object {
    -  public dynamic var name = ""
    -  public var ingredients = List<Ingredient>()
    -}
    -
    + public dynamic var name = "" + public var ingredients = List<Ingredient>() +}

    And this is how we can store a pizza in the database, or in other words adding it to the realm:

    -
    func save(pizza: Pizza) {
    -  let realm = Realm() // <- the default realm
    +
    func save(pizza: Pizza) {
    +  let realm = Realm() // <- the default realm
       realm.write {
         self.realm.add(pizza)
       }
    -}
    -
    +}

    Writing tests

    One simple way to start testing the save code is to assert that after it has been called the count of Pizza objects in the realm is increased by 1.

    -
    class PizzaControllerInMemorySpec: QuickSpec {
    -  override func spec() {
    +
    class PizzaControllerInMemorySpec: QuickSpec {
    +  override func spec() {
         describe("PizzaController") {
           beforeEach { /* code to setup a test realm */ }
     
           afterEach { /* code to tear down a test realm */ }
     
           it("adds the Pizza to the Realm") {
    -        expect(testRealm.objects(Pizza).count).to(equal(0))
    +        expect(testRealm.objects(Pizza).count).to(equal(0))
     
    -        let p = Pizza()
    -        p.name = "Margherita"
    +        let p = Pizza()
    +        p.name = "Margherita"
             sut.addPizza(p)
     
    -        expect(testRealm.objects(Pizza).count).to(equal(1))
    +        expect(testRealm.objects(Pizza).count).to(equal(1))
           }
         }
       }
    -}
    -
    +}

    The testing documentation suggests two way to test the code that interacts with a realm.

    The first is to change the Realm.defaultPath to one used only for testing. The problem with this approach is that it assumes that we are always going to use the default Realm, while this may not be the case. We might for example spin up a temporary realm, persist changes on that, and only merge on the main realm if the user confirms the changes.

    The second approach solves this issue by suggesting to pass a realm instance to every method that needs to interact with it. Our save method would then have to be changed in save(pizza: Pizza, onRealm realm: Realm). That would mean that the consumer of such API would always need to be aware of the realm. We can do better.

    A possible alternative is to have a realm manager/controller/service that can be initialized with a realm instance, and only works with it.

    -
    import RealmSwift
    +
    import RealmSwift
     
     class PizzaController {
    -  let realm: Realm!
    +  let realm: Realm!
     
    -  init(realm: Realm) {
    -    self.realm = realm
    +  init(realm: Realm) {
    +    self.realm = realm
       }
     
    -  init() {
    +  init() {
         self.init(realm: Realm())
       }
     
    -  func addPizza(pizza: Pizza) {
    +  func addPizza(pizza: Pizza) {
         realm.write {
           self.realm.add(pizza)
         }
       }
    -}
    -
    +}

    With this we have the best of both worlds. The normal consumer doesn't need to know about Realm, and can use the PizzaController(). Special consumers, like the unit tests or contexts in which a secondary realm need to be put in place, can use PizzaController(realm: Realm).

    When looking at the interface of PizzaController() we immediately see it depends on Realm, there are no hidden dependencies, no surprises. This is one of the simplest form of dependency injection.

    Let's now look at how to use an in-memory realm to speed up the unit tests.

    -
    import Quick
    +
    import Quick
     import Nimble
     import RealmSwift
     import testing_realm
     
     class PizzaControllerInMemorySpec: QuickSpec {
    -  override func spec() {
    +  override func spec() {
         describe("PizzaController") {
    -      var testRealm: Realm!
    -      var sut: PizzaController!
    +      var testRealm: Realm!
    +      var sut: PizzaController!
     
           beforeEach{
    -        testRealm = Realm(inMemoryIdentifier: "pizza-controller-spec")
    -        sut = PizzaController(realm: testRealm)
    +        testRealm = Realm(inMemoryIdentifier: "pizza-controller-spec")
    +        sut = PizzaController(realm: testRealm)
           }
     
           afterEach {
    @@ -94,18 +90,17 @@ 

    Writing tests

    } it("adds the Pizza to the Realm") { - expect(testRealm.objects(Pizza).count).to(equal(0)) + expect(testRealm.objects(Pizza).count).to(equal(0)) - let p = Pizza() - p.name = "Margherita" + let p = Pizza() + p.name = "Margherita" sut.addPizza(p) - expect(testRealm.objects(Pizza).count).to(equal(1)) + expect(testRealm.objects(Pizza).count).to(equal(1)) } } } -} -
    +}

    Note: the test above is far from being comprehensive, the point we're trying to make is on the setup.

    Benchmark: on-disk vs in-memory

    Now you could argue that there is no big difference between the test above and one using a realm on disk dedicated to testing.

    diff --git a/blog/thats-funny-moments-are-learning-opportunities/index.html b/blog/thats-funny-moments-are-learning-opportunities/index.html index 49a0014..0112567 100644 --- a/blog/thats-funny-moments-are-learning-opportunities/index.html +++ b/blog/thats-funny-moments-are-learning-opportunities/index.html @@ -12,10 +12,9 @@ A different way to look at them, though, is as an asymmetry between the desired behavior and the authors' understanding of what the code they wrote would end up doing.

    For example, you might expect that calling a view method named display(_: Bool) passing true will result in the view being displayed. But, if the method implementation is as follows, the view will be hidden instead.

    -
    func display(_ shouldHide: Bool) {
    -  shouldHide ? hide() : show()
    -}
    -
    +
    func display(_ shouldHide: Bool) {
    +  shouldHide ? hide() : show()
    +}

    The difference between the mental representation1 of what the code would do and its actual behavior is the source of the bug.

    When reading and writing software, our aim should be to build the most accurate mental representation.

    As the late Anders Ericsson points out in his book Peak, it is the quality of mental representations that sets apart the best form the rest.

    @@ -42,22 +41,19 @@ Code with no hidden dependencies, doing only one thing, made up of small components, is easier to follow and reason about. There's less room for mistakes when building a mental representation of it.

    Back to the example above, a simple way to help future readers of the code build an accurate mental representation is to avoid omitting the argument label.

    -
    func display(shouldHide: Bool) {
    -  shouldHide ? hide() : show()
    -}
    -
    +
    func display(shouldHide: Bool) {
    +  shouldHide ? hide() : show()
    +}

    We could also make the code less surprising by removing the inverse logic.

    -
    func display(shouldShow: Bool) {
    -  showShow ? show() : hide()
    -}
    -
    +
    func display(shouldShow: Bool) {
    +  showShow ? show() : hide()
    +}

    The verb display means "to make a prominent exhibition of (something) in a place that it can be easily seen". It's a bit weird to use it for a function that can hide a view, the opposite of displaying it. We could go even further to help paint an accurate mental image and use a different verb.

    -
    func updateVisibility(to visible: Bool) {
    -  visible ? show() : hide()
    -}
    -
    +
    func updateVisibility(to visible: Bool) {
    +  visible ? show() : hide()
    +}

    Reading this a call to this version of the method, updateVisibility(to: true), is less likely to result in an incorrect mental representation.


    Whether you are aware of it or not, you always build a mental representation of your software to understand it. diff --git a/blog/the-productivity-project-notes/index.html b/blog/the-productivity-project-notes/index.html index fd8e60f..b0aecb4 100644 --- a/blog/the-productivity-project-notes/index.html +++ b/blog/the-productivity-project-notes/index.html @@ -48,19 +48,31 @@

    Meet yourself, from the future

    Why the internet is killing your productivity

    It's not that I dislike the internet—just the opposite, the internet is one of my favorite things on the planet. I simply value my productivity too much to stay connected all the time, especially when I'm working on something important.

    +
    +

    The internet hijacks your limbic system by overwhelming it.

    +
    +

    The internet tempts us to work on lower-impact tasks. Though we are technically working when we do things like continually check our email, we're not as productive, because we don't accomplish as much through those tasks.

    The time economy

    [T]ime will continue to tick on at the same rate, but what actually fluctuates on a day-to-day basis is how much energy and attention you have. In the knowledge economy, that's what makes or breaks how productive you are, and more important, it's something you can actually control.

    +
    +

    Managing your time becomes important only after you understand how much energy and focus you will have throughout the day and define what you want to accomplish.

    Working less

    [I]n practice, working longer hours means having less time to refocus and recharge, which leads to more stress and lower energy.

    +
    +

    It's hard not to feel productive when you're busy all day long. But busyness does not translate into productivity if it doesn't lead you to accomplish anything.

    +
    +

    [L]earn to invest more energy and attention into your work, so you can get the same amount done in a fraction of the time.

    +
    +

    [S]tudies show that after roughly thirty-five or forty hours, your productivity begins to plummet.

    An interesting idea on the topic is Cal Newport's fixed-schedule productivity approach.

    @@ -72,6 +84,8 @@

    Energy enlightenment

    This is as much a science as it is an art. You need to be aware of your energy and focus levels and adjust accordingly.

    [T]he more I adapt what I'm working on to mesh with my energy levels, the more productive I become.

    +
    +

    If you're up on a roll on a project, with a ton of energy and focus and it's 10 p.m., why wouldn't you work a bit longer to become more productive when you have the flexibility to do so?

    See also manager schedule vs maker schedule by Paul Graham.

    @@ -85,7 +99,11 @@

    Cleaning house

    Shrinking the unimportant

    Answering email, attending meetings, and keeping up with social media are the "maintenance tasks" of work; they support the most fruitful tasks in your job, and just like doing the laundry and paying your bills, they're very hard to get rid of.

    +
    +

    The best solution I have found to shrinking mine has been to set limits, both for how much time I spend on the task, and for how often I focus on the task.

    +
    +

    [S]etting limits for support tasks in your work makes it much harder for them to expand and take up more of your time or attention than they need to.

    This could be an application of Parkinson's law: work expands so as to fill the time available for its completion.

    @@ -112,6 +130,8 @@

    Rising up

    This chapter is about how to think big picture and long term about goals and productivity.

    While no one acts in accordance with their values all the time, the most productive people act in accordance with their values in the long run

    +
    +

    [The most productive people] make course corrections every week to gradually get better at everything they do.

    A technique to look at your projects from a 30,000 ft point of view is to group them in "hot spots":

    @@ -136,7 +156,7 @@

    Making room

    People who are paid big bucks in the knowledge economy are paid to solve problems and connect dots, which makes carving out time for mind wandering that much more important—particularly after you capture the unresolved things weighing on your psyche.

    The posterior cingulate cortex is the part of the brain responsible for mind wandering.

    -

    Attention hijackers & The art of doing one thing

    +

    Attention hijackers & The art of doing one thing

    These two chapter go hand in hand and focus on the disruptive effect of distractions on productivity, making the argument for avoiding them like the plague.

    When you repeatedly move your attentional spotlight from one thing to another, your brain gets overloaded. And when your brain is overloaded, it shifts its processing from your hippocampus (responsible for memory) to the area of your brain responsible for rote tasks, making it difficult to learn a new task or recall what you were doing before you were interrupted.

    @@ -177,6 +197,8 @@

    Diet, Sleep, and Exercise

    Liquids play an important parts too. It's important to stay hydrated.

    I see drinking alcohol as a way of borrowing energy from tomorrow. But in the morning you have to pay interest on that energy loan.

    +
    +

    because you invariably crash after a caffeine high, drinking caffeine is a way of borrowing energy from later on in the day.

    The suggestion here is to be strategic with caffeine intake, drinking it before doing important focused work, and with the knowledge that there'll be an energy crash afterwards.

    @@ -193,6 +215,8 @@

    Conclusion

    Here's two final quotes from the last chapters of the book that have stuck with me.

    Productivity is often a process of understanding your constraints.

    +
    +

    Productivity techniques exist to help you work smarter. But they're only useful when you still do the work.

    The Productivity Project is a well rounded introduction to many productivity concepts and techniques, packaged in easy to digest and practical chapters.

    diff --git a/blog/the-value-of-acceptance-testing/index.html b/blog/the-value-of-acceptance-testing/index.html index b3a33f8..e0915f1 100644 --- a/blog/the-value-of-acceptance-testing/index.html +++ b/blog/the-value-of-acceptance-testing/index.html @@ -7,12 +7,12 @@

    You can see or the original web version here. The video should come out, eventually.

    Before we begin

    Before we start talking about acceptance testing there are two things that need to be made clear.

    -

    Acceptance test != Unit test

    +

    Acceptance test != Unit test

    An acceptance test asserts a specific acceptance criteria, or user story, or job story, a well defined behaviour that the app is supposed to have.

    A unit test on the other hand asserts the behaviour of a give class or module, the sut, system under test.

    The scope and the design of these two tests are completely different, and it is also important to say that they don't replace each other. A 100% coverage and green unit test suite doesn't necessarily mean that the acceptance tests will pass, and vice versa.

    Unit tests are very important, and you should write them.

    -

    Acceptance test != Automated test

    +

    Acceptance test != Automated test

    An acceptance test doesn't have to be automated by definition. Having the intern make sure that when logging in with Facebook the profile picture is set as the same on of the Facebook profile is an acceptance test. But it is definitely not automated.

    At the same time, having Travis CI running the unit tests for the project after every push to the repo is a way of running tests automatically, but those are not acceptance tests.

    This post (and talk) is about automated acceptance tests. For the rest of the post we will omit the automated part of the name.

    @@ -51,7 +51,7 @@

    Who should write acceptance tests

    The project has clear requirements and specifications. Since updating acceptance tests is painful you don't want to have to do it once a week.
  • The project doesn't have a strict deadline. If you're writing test code you are clearly not writing production code. But while in most cases writing unit tests is a good use of time because the resulting software design is better, and on the long run unit tests will allow you to make changes more quickly, the same might not be true for acceptance tests. Don't run acceptance tests if you are in a rush.
  • -

    I want to write acceptance tests, where do I begin?

    +

    I want to write acceptance tests, where do I begin?

    Where do I begin?

    Getting started with acceptance testing on iOS is becoming easier and easier. Apple just released a new UI testing framework which allows you to automagically write tests cases simply by running the app on the Simulator and interacting with it. It is fully integrated with XCTest, and being completely detached, is on another target, from your Release code, is a safe way where to write some Swift code without the problems of Objective-C interoperability.

    For the past years KIF has been one of the best open source frameworks to use to write tests for the behaviour of your apps. The community around it is pretty active, and I'm looking forward to see how we're gonna be able to leverage the new APIs provided by UI testing to make KIF an even better framework.

    diff --git a/blog/things-learned-in-august/index.html b/blog/things-learned-in-august/index.html index 47a462e..3bd1f32 100644 --- a/blog/things-learned-in-august/index.html +++ b/blog/things-learned-in-august/index.html @@ -1,19 +1,19 @@ Some things I learned in August | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in August

    iOS and Objective-C

    +

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in August

    ###iOS and Objective-C

    Since NSDecimalNumber can be init from a string there's the risk it's gonna produce a NaN. To avoid this check for [myDecimalNumber isEqualToNumber:[NSDecimalNumber notANumber]]

    xcoder a Ruby gem to automate our Xcode project management.

    -

    Ruby

    +

    ###Ruby

    As you know I have the -really good- habit of writing scripts to automate routine tasks in my work, mostly in Ruby. I naively used to check for arguments with ARGV.include? "--some-option", until a workmate had a look at my code and surprisedly asked why Ruby didn't had an option parser library like argparse module in Python. Turns out it does. Meet the OptionParser class.

    Configure URI.extract to avoid unexpected surpirses. http://blog.apptamers.com/post/48613650042/uri-extract-incorrect-in-ruby-1-9-3

    colorize, gem to add color to Ruby scripts.

    -

    Javascript

    +

    ###Javascript

    timeago, quick jQuery library to format datetimes in "xxx ago" strings.

    -

    Layout and CSS

    +

    ###Layout and CSS

    FlatUI framework

    Their slow in definig standards, but sometimes the W3C is a good place where to find resources. Fonts usable in CSS.

    Font Custom and IcoMoon, resources to aggregate icons in a font file, to use as font icons. Or, why not, to speedup iOS development, as I'm doing in one project of mine I may write about soon: MTFontIcon.

    -

    Interesting Readings

    +

    ###Interesting Readings

    -

    Tools

    +

    ###Tools

    waffle.io, a shared kanban board for your projects on GitHub.

    My workmates Adam Chainz introduced me to the Colemak keyboard layout.

    diff --git a/blog/things-learned-in-july/index.html b/blog/things-learned-in-july/index.html index 6318c6a..632826c 100644 --- a/blog/things-learned-in-july/index.html +++ b/blog/things-learned-in-july/index.html @@ -1,38 +1,38 @@ Some things I learned in July | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in July

    July has been a month dense of learning and (re)discoveries! First of all Rails 4, which I come to love back in the day, when I was working with my friends on the first prototype of Kunerango

    -

    Objective-C and iOS Development

    +

    ###Objective-C and iOS Development

    http://rentzsch.github.io/mogenerator/

    Guess what? CoreData doesn't make your life easy when you're seriously working with test, http://stackoverflow.com/questions/1876568/ocmock-with-core-data-dynamic-properties-problem. I like the protocol approach, even if it adds a some "boilerplate code" to maintain.

    nomad a set of useful tools to automate the every-day development. Another gift from mister Mattt.

    -

    Ruby on Rails

    +

    ###Ruby on Rails

    Rails 4 finally out! http://weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

    Nice and clear guide to testing with RSpec on Rails http://everydayrails.com/2012/03/12/testing-series-rspec-setup.html

    Binstubs, because the less we type, the better! http://blog.barbershoplabs.com/blog/2013/03/01/upgrading-to-rails-40-binstubs, http://mislav.uniqpath.com/2013/01/understanding-binstubs/, http://robots.thoughtbot.com/post/15346721484/use-bundlers-binstubs

    The haml-rails gem integrates with the template generators, out of the box!

    -

    How cool are named routes? post 'items/move_down/:id' => 'items#move_down', as: :move_down ), look at the routes.rb comments to know more about them.

    +

    How cool are named routes? post 'items/move_down/:id' => 'items#move_down', as: :move_down ), look at the routes.rb comments to know more about them.

    Amazon AWS S3 gem http://amazon.rubyforge.org

    I found a nice gem to add enumeration type to the ActiveRecord models: active_enum, but is it compatible with Rails 4? Here's a link on how to use it.

    -

    Ruby

    +

    ###Ruby

    I wrote some scripts to speed up some of my daily task at work, and used some nice gems in the meantime: nokogiri, to parse HTML using CSS selectors rest-client, fetching pages from the web with one line of code json, to parse JSON diffy, comparing strings has never been so easy mail, sending emails from your scripts

    -

    Coding Recipes

    +

    ###Coding Recipes

    http://codeartists.com/post/36892733572/how-to-directly-upload-files-to-amazon-s3-from-your

    http://quickleft.com/blog/keeping-your-json-response-lean-in-rails

    Several ways to run a command line command from a Ruby script.

    -

    Sysadmin

    +

    ###Sysadmin

    Fixing Postgres connection error on OS X Mountain Lion http://jaygoldman.com/2012/11/fixing-postgres-connection-errors-on-mountain-lion/ (funny because with Node there were no problems)

    -

    Javascript

    +

    ###Javascript

    I looked into a bunch of Javasciprt techs: Underscore.js, Jade, Handlebars, Stylus, Express

    -

    Tools

    +

    ###Tools

    http://imageoptim.com/

    -

    Software Engineering Good Practices

    +

    ###Software Engineering Good Practices

    Coupled dependencies, I found one of those monsters in a colleague's code. It took a lot of self-control to avoid being a prick and pointing it out on GitHub.

    -

    Interesting readings

    +

    ###Interesting readings

    How Basecamp Next got to be so damn fast without using much client-side UI

    diff --git a/blog/things-learned-in-june/index.html b/blog/things-learned-in-june/index.html index 4b6a2ac..b492927 100644 --- a/blog/things-learned-in-june/index.html +++ b/blog/things-learned-in-june/index.html @@ -1,14 +1,14 @@ Some things I learned in June | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in June

    Last month I decided to start keeping track of the things learned along the way. This list at the moment seems kinda short, let's say that's because I didn't start keeping track of the stuff from the beginning of the month.

    -

    Coding

    +

    ###Coding

    Testing Objective-C classes equality: http://stackoverflow.com/questions/10944460/testing-class-equality-in-objective-c

    Objective-C _cmd returns the method name within a method: http://stackoverflow.com/questions/2770307/nslog-the-method-name-with-objective-c-in-iphone

    You can use a Pod locally: https://github.com/CocoaPods/CocoaPods/wiki/Working-on-a-pod

    -

    Systems and Tools

    +

    ###Systems and Tools

    How to stop autocorrect in zsh: http://yountlabs.com/blog/2010/11/06/disable-autocorrect-in-zsh/

    -

    Trivia

    +

    ###Trivia

    Where does the Logarithm name come from: "Napier first called L an "artificial number", but later introduced the word "logarithm" to mean a number that indicates a ratio: λόγος (logos) meaning proportion, and ἀριθμός (arithmos) meaning number." http://en.wikipedia.org/wiki/Logarithm

    diff --git a/blog/things-learned-in-october/index.html b/blog/things-learned-in-october/index.html index 41eae7a..63f7785 100644 --- a/blog/things-learned-in-october/index.html +++ b/blog/things-learned-in-october/index.html @@ -1,17 +1,17 @@ Some things I learned in October | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in October

    The month of October has been strange. I decided to change my job, I'll write about it later, and so I spent a lot of time sorting out my websites and CV, some of my open source projects, looking for a new possible company. I also reached the final stage of the development of a new -sort of- app with my current company, in the worst possible way ever, rushing into last minue changes, UI redisigns, bugfixes. All this to say... I read and explored less than usual, and probably forgot to take record of interesting things.

    -

    iOS Simulator Screen Recording

    +

    ##iOS Simulator Screen Recording

    As I mentioned we reached the pre submit state for an app with the currently that I'm gonna leave in some days. I'm not proud of that app so I'm not gonna link it. Anyway they wanted a screencapture to show to some chinese dude. I used SimCap and Soundflower, and I've been pretty happy with the result. Everything is simple and straightforward to used. Only one note: don't panic if after enabling Soundflower the sound in your Mac doesn't work anymore, it's just going through it instead.

    -

    An HTML5 nightstand...

    +

    ##An HTML5 nightstand...

    For a sleepless night I got into HTML5 game development, part because of a talk I saw, part because of an idea I had, that I had to put aside because I needed more time to implement it. It all brought me to discover Quintus a nice HTML5 game framework. Here's an interesting tutorial I took: Create a HTML5 Mario style platformer game.

    -

    New discoveries

    +

    ##New discoveries

    Through some friends I came across these interesting websites.

    • JSDB a collection of JavaScript frameworks, plugins and tools
    • Codewars a gamified way to improve your coding. Full disclosure: that link will give me referral points. Normal one here
    -

    A final word

    +

    ##A final word

    I also failed to fullfit my commitment to answer 4 questions I asked myself. I won't make any commitment this month.

    diff --git a/blog/things-learned-in-september/index.html b/blog/things-learned-in-september/index.html index 8c15183..da163eb 100644 --- a/blog/things-learned-in-september/index.html +++ b/blog/things-learned-in-september/index.html @@ -1,19 +1,19 @@ Some things I learned in September | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in September

    Javascript and Data Visualization

    +

    mokacoding

    unit and acceptance testing, automation, productivity

    Some things I learned in September

    ###Javascript and Data Visualization

    My company wanted a custom viewer for analytics data, perfect occasion for experiment with data visualization powered by Javascript. I started by taking a look at D3.js, which is the library used by the GitHub guys to draw their amazing repo graphs. It's incredibly powerful, but requires quite a bit of coding to get stuff done. I then used Chart.js for a bit. It's smaller, simpler, and faster to learn. This all comes with the downside of being less powerful, and with not enough of the features I needed out of the box. Also the development seems to be going really slow at the moment. So now I'm working with gRaphaël, it's built on top of Raphaël and has more of the things I was looking for ready made.

    -

    Node, node, node!

    +

    ###Node, node, node!

    With the project I mentioned above I finally had the occasion to spend company time working on Node.js. I like how lighter it is compared to Rails, and I'm definitely gonna keep experimenting with it.

    In fact I used Node + Heroku to setup my personal landing page.

    Sneak peek: having setup an Node + Express + Coffeescript task more than two times, and being DRY, or lazy, I've decided to put it in a repo. Stay tuned!

    -

    Bower

    +

    ###Bower

    They've done it again! After Bootstrap the Twitter team has released Bower "A package manager for the web". It's the bundler or npm of your web packages. Smart! One of those things you say "How could I've lived without it?"

    -

    Other Javascript stuff

    +

    ###Other Javascript stuff

    • Moment.js, a slim yet powerful library to manipulate time.
    • I've played quite a lot with Jade, it's really cool, but not as flexible as I hope, or maybe I need to dig more in the documentation…. Anyway, I found this nice Javascript Template Chooser.
    -

    CSS Frameworks

    +

    ###CSS Frameworks

    I looked into alternatives to Bootstrap. Here's what I found:

    -

    Jenkins

    +

    ###Jenkins

    I've finally been able to plant the seed of the TDD and CI culture in my company. They bought me a Mac Mini, and I've set it up with Jenkins. It's been a bit painful, but really fun! And now we have the tests running at every push and two nightly builds, development and qa, distributed via TestFlight. It's a shame I'm the only iOS dev who writes tests :(

    -

    Ruby

    +

    ###Ruby

    I had a quick, and not finished yet, blast at making a ruby gem. Enter Swagify a gem to add some your commands and scripts outputs. I'm not gonna talk too much about it here, as I don't consider the learning experience over (it never is btw).

    -

    Readings

    +

    ###Readings

    -

    Something funny

    +

    ###Something funny

    • Sloppy UI - It's all about the flaws in iOS 7 design
    • the_coding_love(); - Funny gifs to ease the dev life
    • diff --git a/blog/top-10-productivity-books/index.html b/blog/top-10-productivity-books/index.html index 2998a47..cdc3a62 100644 --- a/blog/top-10-productivity-books/index.html +++ b/blog/top-10-productivity-books/index.html @@ -13,47 +13,47 @@

      Here are the 10 most useful books I read so far.

      This list is loosely ordered by how much I liked the books, but really you can't go wrong with any of them.

      Looking at the titles, you'll see that getting stuff done is only the tip of the iceberg. The more I learn about productivity, the more I think of it as the science and art of understanding our limitations, the biases that affect our reasoning, our biological need for energy and rest, and how to work within them.

      -

      1. Deep Work, by Cal Newport.

      +

      1. Deep Work, by Cal Newport.

      Probably the book that had the most impact on my career. Makes a case for the value of focus for knowledge-workers, warns about the dangers of the constant distractions we put ourselves through -email, Slack, quick social media check-ins, etc.-, and provides practices and guidelines to bring back focus and make the time for deep, uninterrupted work in our days.
      Amazon, Amazon non-affiliate.

      -

      2. Atomic Habits, by James Clear.

      +

      2. Atomic Habits, by James Clear.

      Defines a straightforward and practical four steps framework to adopt or give up any habit and behavior change. More than that, it shows the strategic value of investing in our habits to become a better version of ourselves.
      Amazon, Amazon non-affiliate.

      -

      3. Thinking Fast and Slow, by Daniel Kahneman.

      +

      3. Thinking Fast and Slow, by Daniel Kahneman.

      To get things done, we need to understand what stops us from getting things done. Sorry to break it to you but our brains are not rational, at all. This book by Nobel prize winner, psychologist Daniel Kahneman, goes in depth into how our brains work and the many flaws and biases that affect them.
      Amazon, Amazon non-affiliate.

      -

      4. How to Fail at Almost Everything and Still Win Big, by Scott Adams

      +

      4. How to Fail at Almost Everything and Still Win Big, by Scott Adams

      In this fun cross between autobiography and self-help book Dilbert's creator Scott Adams shows the power of systems against goals. If you base your success on achieving goals, you'll be in a constant state of failure until you achieve the goal, assuming you'll actually do. If you adopt a system of constant learning instead, you'll be making progress every day, and even failed ventures will provide useful learning opportunities.
      Amazon, Amazon non-affiliate.

      -

      5. Getting Things Done, by David Allen.

      +

      5. Getting Things Done, by David Allen.

      Not the most entertaining of books, but David Allen's GTD approach is the best I've found so far to keep track of all the things going on in my life, in and outside of work. Even if you don't end up implementing GTD, it's still worth reading about the open loops concept. By attempting to keep track of everything in our brains we overload them with worries and things to process in the subconscious, resulting in fatigue and inefficiency. The solution is to capture all the tasks in a system outside of our brains and identify the next action for each. Over time the brain will learn to have trust in the system and stop worrying.
      Amazon, Amazon non-affiliate.

      -

      6. Digital Minimalism, by Cal Newport.

      +

      6. Digital Minimalism, by Cal Newport.

      Digital minimalism is a philosophy of technology, a set of rules for how to use technology to enhance our lives rather than ending up being the ones used by it. Productivity is in good part about making the most of our limited time. Technology is an incredible tool to make us more productive, but it can also be our biggest time sucker. Social media companies and infotainment websites lure us into sticking to the screen because their profit is directly proportional to the time we spend with them.
      Amazon, Amazon non-affiliate.

      -

      7. Essentialism, by Greg McKeown.

      +

      7. Essentialism, by Greg McKeown.

      The book makes a case for focusing on "the vital few" and happily miss out on "the trivial many", and shares technique on how to make it possible, the simplest and most effective one is saying no more often.
      Amazon, Amazon non-affiliate.

      -

      8. So Good They Can't Ignore You, by Cal Newport.

      +

      8. So Good They Can't Ignore You, by Cal Newport.

      Talent and passion are overrated. "Follow your passion" might very well be the worst career advice ever given. A much better approach, Cal Newport argues, is to commit to being constantly learning about your field, and spend time practicing deliberatly to acquire more valuable skills to use in the market place. This pursuit of mastery is ultimately what drives real job satisfaction. Achievements and progress drive passion, not the other way around.
      Amazon, Amazon non-affiliate.

      -

      9. Thinking in Bets, by Annie Duke.

      +

      9. Thinking in Bets, by Annie Duke.

      Poker champion turned business coach Annie Duke studies the mechanics of decision making, drawing from her experience playing the game, as well as her training as a behavioral psychologist. To become better decision makers, we need to be able to analyze the outcomes we obtain and identify which were due to skill and which to luck, building a learning loop to inform our next decisions. The secret is to understand and come to terms with the fact that luck plays a big role in the outcome of our decisions.
      Amazon, Amazon non-affiliate.

      -

      10. The One Thing, by Gary Keller

      +

      10. The One Thing, by Gary Keller

      There are a lot of similarities between this book and Essentialism, but this is still worth recommending because it suggests the best prioritization technique I've seen so far. Answer the question "what is the one thing I can do in time interval for your goal that will make everything else easier or unnecessary?"
      Amazon, Amazon non-affiliate.

      -

      Bonus. The Obstacle Is The Way & Ego Is The Enemy, by Ryan Holiday

      +

      Bonus. The Obstacle Is The Way & Ego Is The Enemy, by Ryan Holiday

      What do two books about the ancient Stoic philosophy have to do with productivity? These books changed my life. If you want to get more valuable things done with your time, you could do worse than reading about Stoicism. One of the core ideas of Stoic philosophy is that we should only focus on the things that are within our control, and accept everything else that happens to us and we can't affect. Ryan Holiday does an excellent job at contextualizing the practical advice from the Ancient Greeks and Romans to our current day, and shows how to let go of believes and desires that are getting in our way. diff --git a/blog/travis-ci-ios-testing/index.html b/blog/travis-ci-ios-testing/index.html index cba645c..16d15dd 100644 --- a/blog/travis-ci-ios-testing/index.html +++ b/blog/travis-ci-ios-testing/index.html @@ -3,34 +3,32 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to configure Travis CI for iOS testing

    Whether you are using Swift or Objective-C, developing a little open source framework or the next App Store hit, having a solid CI setup is very important to guarantee a fast feedback loop, and a reliable development pipeline.

    Last week we looked at CircleCI, and today we are going to see how to use Travis CI to test iOS, and OS X applications. Oh! And watchOS and tvOS as well.

    Note: Before configuring Travis CI you'll need to make sure that the Xcode Scheme used to run the test is shared, so that it will be downloaded as part of the repo checkout so that the CI box will find it when attempting to run the tests.

    -

    .travis.yml

    +

    .travis.yml

    The best way to configure your builds on Travis CI is through the .travis.yml file.

    In case you are not familiar with it, a .yml file is a file written in YAML, a very simple data serialization language, and a JSON subset.

    Here's the one of simplest .travis.yml you could write:

    -
    language: objective-c
    +
    language: objective-c
     osx_image: xcode7.1
     
     script:
    -  - ./bin/tests
    -
    + - ./bin/tests

    That's it. This configuration file will make sure that your build will run on a machine with Xcode 7.1, the run the executable script located at bin/tests.

    Using a script file where the test commands are rather than letting Travis CI guess how to run them itself has a number of advantages. First and foremost, it makes it so that you can run the same command the CI will use on your machine, which is important because you want to personally test your CI setup. On top of that it keeps the configuration file decoupled by the implementation details how the tests should run, and makes it more readable.

    Note that the language key says objective-c, but that it enables both Swift and Objective-C builds.

    Checkout this post for a closer look on how to write such a script.

    Other configurations

    The .travis.yml of Bench, one of the example projects used to in posts like "Xcode 7 UI testing, a first look" and "Job stories acceptance tests using KIF and Specta", adds is similar to the one above, but with an extra section:

    -
    language: objective-c
    +
    language: objective-c
     osx_image: xcode7.1
     
     cache: bundler
     
     script:
    -  - ./bin/unit-tests
    -
    + - ./bin/unit-tests

    Bench uses xcpretty to format the tests' output. The tool is installed as a Ruby gem, using Bundler.

    Travis CI will automatically run bundle install on a project that uses Bundler, and the cache: bundler line in the configuration file tells it that it should in cache the dependencies installed that way, saving up some build time.

    In this .travis.yml from the Quick project we do two extra things, update the git submodules, and make sure the xctool version brew is up to date.

    -
    osx_image: xcode7
    +
    osx_image: xcode7
     language: objective-c
     
     before_install:
    @@ -41,8 +39,7 @@ 

    Other configurations

    script: - rake test:ios - rake test:osx - - rake test:xctool:ios -
    + - rake test:xctool:ios

    A note on dependencies

    You might have noticed that I have made no mention yet to pod install or carthage bootstrap. That is because I've found that is way better to check in your projects dependencies under version control rather than having the CI downloading every time. Not only you will get a faster build, but also remove the network as a possible point of failure. For example GitHub being offline would not prevent the dependencies to being downloaded, resulting in the build failing.


    diff --git a/blog/unless-swift/index.html b/blog/unless-swift/index.html index f52defb..62e97d1 100644 --- a/blog/unless-swift/index.html +++ b/blog/unless-swift/index.html @@ -2,26 +2,23 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    Unless.swift

    Ruby is a programming language that prides itself of being optimized for developer happiness. Part of this optimization is on how close to natural language, or at least natural english, you can get when writing Ruby code.

    One of my favourite features is unless.

    -
    unless condition do
    +
    unless condition do
       something()
    -end
    -
    +end

    One could be tempted to say that Swift's guard is the same thing as Ruby's unless, but that's not the case.

    -
    guard condition else {
    +
    guard condition else {
       something()
       return
    -}
    -
    +}

    guard is not simply a if condition == false, but a tool to enforce early returns. A guard statement will not compile without a return.

    For this reason I hacked together a Swift version of unless. As you can imagine the code is pretty simple:

    -
    func unless(_ condition: () -> Bool, do closure: @escaping () -> ()) {
    -  guard condition() == false else {
    +
    func unless(_ condition: () -> Bool, do closure: @escaping () -> ()) {
    +  guard condition() == false else {
         return
       }
     
       closure()
    -}
    -
    +}

    You can find the whole code on GitHub.

    I made it as a Swift Package, but I would advise against using it that way. After all, what's the point of having syntax sugar that should make your job easier if you have to import it for every file?

    Much better to simply copy the code, and its tests so that it's part of your Swift module.

    diff --git a/blog/upgrading-podfile/index.html b/blog/upgrading-podfile/index.html index 7ca2b54..b2e6a5f 100644 --- a/blog/upgrading-podfile/index.html +++ b/blog/upgrading-podfile/index.html @@ -3,41 +3,42 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    A caveat when upgrading a Podfile

    I recently went through the process of upgrading a Podfile from a legacy codebase and bumped into an issue with a very simple solution, for those who understand how CocoaPods works under the hood.

    I made an example project to show the behaviour, check it out here.

    The Podfile looked like this:

    -
    link_with ['MyProject', 'MyProjectTests']
    +
    link_with ['MyProject', 'MyProjectTests']
     
     pod 'AFNetworking'
    -pod 'Kiwi'
    -
    +pod 'Kiwi'

    (it was actually longer an messier, with random newlines a lot of pods commented out, but no need to inflict you with that)

    Apart from the obsolete Podfile style, there's one big issue; Kiwi should be linked only in the test target, as it is a testing framework.

    Updating the Podfile into a more semantic and not leaky one was simple:

    -
    target :MyProject do
    +
    target :MyProject do
       pod 'AFNetworking'
     end
     
     target :MyProjectTests, :exclusive => true do
       pod 'Kiwi'
    -end
    -
    +end

    So far so good, but at that point after running pod install the project didn't build anymore! The error was:

    -
    ld: library not found for -lPods
    -clang: error: linker command failed with exit code 1 (use -v to see invocation)
    -

    This happens to be a pretty common error, specially for newbies, and in the CocoaPods Troubleshooting page there's a solution for it...

    +
    ld: library not found for -lPods
    +clang: error: linker command failed with exit code 1 (use -v to see invocation)

    This happens to be a pretty common error, specially for newbies, and in the CocoaPods Troubleshooting page there's a solution for it...

    ...that in our case doesn't work!

    After a non irrelevant amount of time spent deleting Derived Data and googling I went back to the error and asked myself: what does library not found for -lPods mean? It means that something that should be there is not there anymore! And what's missing?__ library not found. _And where are the libraries? In the "Link Binary With Libraries" section of the target build phase. Daaah.

    So I took a look at the "Link Binary With Libraries", this is what I found:

    -

    Link Binary With Libraries for the updated project

    +Link Binary With Libraries for the updated project +

    If we'd rolled back to the previous version we'd seen this:

    -

    Link Binary With Libraries for the obsolete project

    +Link Binary With Libraries for the obsolete project +

    Mmm... what is that new libPods-MyProject static library?

    And then I looked at the Pods project:

    -

    Linked Frameworks and Libraries for the updated project

    +Linked Frameworks and Libraries for the updated project +

    Can you spot it? There is no Pods target!

    And here the solution to the problem: the linker cannot find libPods because there is no libPods at all, not anymore. It is just a memory of the previous configuration that CocoaPods didn't remove.

    I removed libPods.a from the "Linked Frameworks and Libraries" and everything was running smoothly again.

    An extra thing: the same operation needs to be done for the tests target, beacuse of the link_with ['MyProject', 'MyProjectTests'].

    Another extra thing: this memory of libPods" error happens when you change the name of the target as well.

    -

    Link Binary With Libraries after changing the target name

    +Link Binary With Libraries after changing the target name +

    As we develop advanced badass systems we rely on many tools and frameworks, to delegate work to someone that knows how to do it better. Knowing how those we rely most heavily upon work on a level that is deeper than what's written in the README is invaluable to save time debugging and to get the most out of them.

    I challenge you to spend some time reading the source code of one of the tools you use the most. Have fun!

    diff --git a/blog/using-swift-protocols-to-improve-testability/index.html b/blog/using-swift-protocols-to-improve-testability/index.html index d3587c5..9b23c99 100644 --- a/blog/using-swift-protocols-to-improve-testability/index.html +++ b/blog/using-swift-protocols-to-improve-testability/index.html @@ -16,85 +16,80 @@ is slow and error prone.

    A better option is to use a protocol to abstract the dependency and gain more control on your tests.

    -
    protocol CookieProvider {
    +
    protocol CookieProvider {
     
    -    func cookieWithName(name: String) -> NSHTTPCookie?
    +    func cookieWithName(name: String) -> NSHTTPCookie?
     
    -    func setCookie(cookie: NSHTTPCookie)
    +    func setCookie(cookie: NSHTTPCookie)
     
    -    func deleteCookieWithName(name: String)
    -}
    -
    + func deleteCookieWithName(name: String) +}

    The components depending on the cookie storage will now expect an instance conforming to the CookieProvider protocol rather that specifying and actual class.

    -
    class NetworkClient {
    +
    class NetworkClient {
     
         let cookiesProvider: CookieProvider
     
    -    init(cookiesProvider: CookieProvider) {
    -        self.cookiesProvider = cookiesProvider
    +    init(cookiesProvider: CookieProvider) {
    +        self.cookiesProvider = cookiesProvider
         }
    -}
    -
    +}

    In your tests you can implement a test double cookie provider able to return a cookie set by you, and to store a cookie in memory so that you can verify if.

    -
    class CookieProviderTestDouble: CookieProvider {
    +
    class CookieProviderTestDouble: CookieProvider {
     
    -    var cookies: [NSHTTPCookie]?
    +    var cookies: [NSHTTPCookie]?
     
    -    func cookieWithName(name: String) -> NSHTTPCookie? {
    +    func cookieWithName(name: String) -> NSHTTPCookie? {
             return cookies
    -            .filter { $0.name == name }
    +            .filter { $0.name == name }
                 .first
         }
     
    -    func setCookie(cookie: NSHTTPCookie)
    +    func setCookie(cookie: NSHTTPCookie)
             self.cookies.append(cookie)
         }
     
    -    func deleteFooBarCoockie() {
    -        guard let cookie = cookieWithName(name) else {
    +    func deleteFooBarCoockie() {
    +        guard let cookie = cookieWithName(name) else {
                 return
             }
     
             deleteCookie(cookie)
         }
    -}
    -
    +}

    You can then init the NetworkClient using the test double:

    -
    let cookiesProvider = CookieProviderTestDouble()
    -let systemUnderTest = NetworkClient(cookiesProvider: cookiesProvider)
    -
    +
    let cookiesProvider = CookieProviderTestDouble()
    +let systemUnderTest = NetworkClient(cookiesProvider: cookiesProvider)

    This will empower you to test the network client behaviour that depends on the value of a cookie by simply setting it in your CookieProviderTestDouble instance, as well as testing behaviour that results in a cookie being stored by checking the values in the .cookies property of the test double.

    In your production code you will then have to extend NSHTTPCookieStorage to conform to CookieProvider:

    -
    let apiURL: NSURL = ...
    +
    let apiURL: NSURL = ...
     
     extension NSHTTPCookieStorage: CookieProvider {
     
    -    func cookieWithName(name: String) -> NSHTTPCookie? {
    -        return cookiesForURL(apiURL)?
    -            .filter { $0.name == name }
    +    func cookieWithName(name: String) -> NSHTTPCookie? {
    +        return cookiesForURL(apiURL)?
    +            .filter { $0.name == name }
                 .first
         }
     
         // A method called setCookie is already exposed by NSHTTPCookieStorage.
         // Less work :)
     
    -    func deleteCookieWithName(name: String) {
    -        guard let cookie = cookieWithName(name) else {
    +    func deleteCookieWithName(name: String) {
    +        guard let cookie = cookieWithName(name) else {
                 return
             }
     
             deleteCookie(cookie)
         }
    -}
    -
    +}

    Pros

    This approach simplifies testability, and potentially makes your unit tests faster in case the third party code you are dealing with performs I/O operations.

    diff --git a/blog/vim-rename-file/index.html b/blog/vim-rename-file/index.html index c50f6de..38fceda 100644 --- a/blog/vim-rename-file/index.html +++ b/blog/vim-rename-file/index.html @@ -14,12 +14,11 @@

    Via NERDTree

  • m to open the NERDTree menu
  • m to move the node
  • -

    Vanilla Vim: shell out to mv

    +

    Vanilla Vim: shell out to mv

    If you are not keep on plugin, you can still trust vanilla Vim to get the job done for you.

    In Vim, you can execute commands in your shell without opening a new terminal with :!cmd. To rename a file, you'll want to execute mv:

    -
    :!mv source target
    -

    The caveat with this approach that if you rename the file in the current buffer, it won't be available anymore and Vim will give you an error. +

    :!mv source target

    The caveat with this approach that if you rename the file in the current buffer, it won't be available anymore and Vim will give you an error. You'll have to reload it from its new location to keep working on it.


    Which approach do you prefer? diff --git a/blog/waituntil-vs-toeventually/index.html b/blog/waituntil-vs-toeventually/index.html index 4926767..75d7854 100644 --- a/blog/waituntil-vs-toeventually/index.html +++ b/blog/waituntil-vs-toeventually/index.html @@ -1,116 +1,109 @@ Nimble: when to use waitUntil or toEventually | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Nimble: when to use waitUntil or toEventually

    Nimble provides two ways to assert code that runs asynchronously, toEventually and waitUntil. In this post we look at them in more details, and understand when to use one or the other.

    -

    toEventually

    +

    toEventually

    You can use toEventually to write expectations that should be tested at some point in the future.

    Its documentation reads:

    Tests the actual value using a matcher to match by checking continuously at each pollInterval until the timeout is reached.

    It can be used like:

    -
    expect(foo).toEventually(equal("something"))
    +
    expect(foo).toEventually(equal("something"))
     
    -expect(array).toEventually(beEmpty())
    -
    +expect(array).toEventually(beEmpty())

    toEventually is very nice because it allows us to write expectations that read like english. "Expect value to eventually be this".

    Having code, whether it is production or test, that reads well makes working in the codebase easy.

    -

    waitUntil

    +

    waitUntil

    waitUntil is not a matcher or an expectation, but just an utility function provided by Nimble.

    Its documentation reads:

    Wait asynchronously until the done closure is called or the timeout has been reached.

    It can be used like:

    -
    waitUntil { done in
    +
    waitUntil { done in
       service.asynMethodWithCallback { value in
         // some expectation(s)
         // ...
     
         done()
       }
    -}
    -
    +}

    If done is not called the test will fail, so remember that will ya?

    When to use which

    When testing that a certain condition should be met as a result of the invocation of async code toEventually is your go to API.

    Here's a more detailed example, which you can find in full on GitHub.

    Imagine we have an AsyncService, with a method that changes the value of a property on its delegate.

    -
    protocol AsyncServiceDelegate: class {
    +
    protocol AsyncServiceDelegate: class {
       var aProperty: String { get set }
     }
     
     class AsyncService {
     
    -  weak var delegate: AsyncServiceDelegate?
    +  weak var delegate: AsyncServiceDelegate?
     
    -  func callThatResultsInSideEffect() {
    -    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) { [weak self] in
    -      self?.delegate?.aProperty = "bazinga"
    +  func callThatResultsInSideEffect() {
    +    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) { [weak self] in
    +      self?.delegate?.aProperty = "bazinga"
         }
       }
    -}
    -
    +}

    A good way to test the implementation of callThatResultsInSideEffect is to create a fake delegate, pass it to the service, call the method, and finally verify that the value eventually matches our expectation.

    -
    class FakeDelegate: AsyncServiceDelegate {
    -  var aProperty: String = "unset"
    +
    class FakeDelegate: AsyncServiceDelegate {
    +  var aProperty: String = "unset"
     }
     
    -func testToEventually() {
    -    let delegate = FakeDelegate()
    -    let service = AsyncService()
    -    service.delegate = delegate
    +func testToEventually() {
    +    let delegate = FakeDelegate()
    +    let service = AsyncService()
    +    service.delegate = delegate
     
         service.callThatResultsInSideEffect()
     
    -    expect(delegate.aProperty).toEventually(equal("bazinga"))
    -}
    -
    + expect(delegate.aProperty).toEventually(equal("bazinga")) +}

    Let's now add a new asynchronous function to our service. One that takes a callback as input and will call it once the async work is done. For the sake of the example let's imagine that this async work is fetching a certain String, and the callback receives a Result type (have a look at this library for a proper implementation).

    -
    extension AsyncService {
    -  func doStuff(_ completion: @escaping (Result<String>) -> ()) {
    -    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) {
    +
    extension AsyncService {
    +  func doStuff(_ completion: @escaping (Result<String>) -> ()) {
    +    DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.1) {
           completion(Result<String>.success("bazinga"))
         }
       }
    -}
    -
    +}

    To test that doStuff(_ completion:) behaves properly using toEventually we could writing something like:

    -
    func testDoStuffWithToEventually() {
    -  let service = AsyncService()
    +
    func testDoStuffWithToEventually() {
    +  let service = AsyncService()
     
    -  var callbackValue: String? = .none
    +  var callbackValue: String? = .none
       service.doStuff { result in
         switch result {
    -    case .success(let value): callbackValue = value
    +    case .success(let value): callbackValue = value
         case .error(let error): fail("Expected call to doStuff to succeed.")
         }
       }
     
    -  expect(callbackValue).toEventually(equal("bazinga"))
    -}
    -
    + expect(callbackValue).toEventually(equal("bazinga")) +}

    There are two issues with this test.

    The first is that it requires a bit of extra setup, in the form of the variable callbackValue. This is not a big deal, but we should strive to keep our tests as lean as possible.

    In our case the callback has only one parameter, but it is not uncommon to have async callbacks with more than that. For example URLSession's dataTask(with:completionHandler:) has three.

    Using this technique we might have to define a number of variables to contain the values received by the callback. This extra work makes the test harder to write and maintain.

    The second problem is that the test doesn't read well. "setup, define a variable, make async call with callback that says to copy the received value, expect copy of received value to eventually equal 'bazinga'".

    In a case like this using waitUntil results in a better test, where with better we mean with less setup needed, and reading closer to natural language.

    -
    func testAsyncCallResult() {
    -  let service = AsyncService()
    +
    func testAsyncCallResult() {
    +  let service = AsyncService()
     
       waitUntil { done in
         service.doStuff { result in
           switch result {
           case .success(let value):
    -        expect(value) == "bazinga"
    +        expect(value) == "bazinga"
             done()
           case .error:
             fail("Expected call to doStuff to suceeded, but it failed")
           }
         }
       }
    -}
    -
    +}

    This code, while having a bit more indentation, reads better. "setup, wait until async call returns a result, expecting the returned value to equal 'bazinga'". More straightforward and self explanatory, and arguably cleaner than having to copy received values.


    To recap, when the behavior to test is simply the fact that the a value will change as the result of an async call, or that the given callback is actually exectuted, toEventually provides a clean API, that reads like english.

    diff --git a/blog/what-i-did-in-a-week/index.html b/blog/what-i-did-in-a-week/index.html index efb2d61..a0f084c 100644 --- a/blog/what-i-did-in-a-week/index.html +++ b/blog/what-i-did-in-a-week/index.html @@ -3,11 +3,11 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    What I did in a week...

    As promised one week ago, here's a report of what I managed to do in this unusually full of free time week.

    I've caught up with Arrow and Game of Thrones. The Red Wedding was better in the book, in my opinion.

    Oh! Yes... I did some coding as well :D I've completed the MVP of my iOS app, and I have a working and tweeting setup of the Twitter based Rails App.

    -

    iOS

    +

    ###iOS

    I've built a simple app using CoreData and MagicalRecod for the data storage, focusing on a simple gesture based UX, powered by JTGestureBasedTableView, with an iOS7ish look. The idea was to roll it out on TestFlight for a week or two and then submit, but the recent cracker attack at Apple have delayed plans. I also used my two WIP pods MGCraftman and MGObjectiveUtils, but the project is simple so I didn't have the occasion to add stuff to them.

    -

    Rails

    +

    ###Rails

    To implement my Twitter based web app I've relied on the twitter gem, which does all the dirty work for me. I'm using Haml for the templates, I love it, so minimal and clear. I'm also gonna use SASS for the styling. So far I've only been using LESS, so I decided to give it a twist.

    -

    Good Practices

    +

    ###Good Practices

    Both the projects are obviously being implemented in a as much test driven way as possible! rspec and webmock on the Ruby side, Kiwi on the Objective-C one. Neat!

    Finally my simple PR on xctool has been merged, and I'm proud of it. And surprised no one thought about coloring the result output before...

    That's all. I'm overall satisfied of what I managed to build. Although I could have avoided watching half a season of Arrow in two days while coding and focusing more... -.-

    diff --git a/blog/what-is-an-optional-value-in-swift/index.html b/blog/what-is-an-optional-value-in-swift/index.html index 02bab87..569a5f4 100644 --- a/blog/what-is-an-optional-value-in-swift/index.html +++ b/blog/what-is-an-optional-value-in-swift/index.html @@ -15,12 +15,11 @@ they're there. This is great to onboard beginners, but I feel that to fully appreciate, and leverage, optionals we need to dig a bit deeper.

    Let's have a look at this piece of code for example:

    -
    let x: String? = "Hello World"
    +
    let x: String? = "Hello World"
     
    -if let y = x {
    +if let y = x {
       print(y)
    -}
    -
    +}

    When I started looking into Swift my understanding of this code would have been something like: "there's a value x that is a String that may or may not be nil. Make sure that x is not nil, and if so print it".

    @@ -29,21 +28,19 @@ be nil", but a different type all together.

    In fact if you add a print(x.dynamicType) statement in the code above you'll see this in the console:

    -
    Optional<String>
    -

    String? is actually syntactic sugar for Optional<String>, and Optional is +

    Optional<String>

    String? is actually syntactic sugar for Optional<String>, and Optional is a type in its own right.

    Here's a simplified version of the header of Optional, which you can see by command-clicking on the word Optional in your code from Xcode:

    -
    enum Optional<Wrapped> {
    +
    enum Optional<Wrapped> {
     
       /// The absence of a value.
    -  case none
    +  case none
     
       /// The presence of a value, stored as `Wrapped`.
    -  case some(Wrapped)
    -}
    -
    + case some(Wrapped) +}

    Optional is actually an enum, defined in relation to a generic type Wrapped. It has two cases: .none to represent the absence of a value, and .some to represent the presence of a value, which is stored as its associated diff --git a/blog/what-software-developers-can-learn-from-leonardo-da-vinci/index.html b/blog/what-software-developers-can-learn-from-leonardo-da-vinci/index.html index 24a4a1d..6821cf5 100644 --- a/blog/what-software-developers-can-learn-from-leonardo-da-vinci/index.html +++ b/blog/what-software-developers-can-learn-from-leonardo-da-vinci/index.html @@ -1,7 +1,8 @@ What software developers can learn from Leonardo da Vinci | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    What software developers can learn from Leonardo da Vinci

    Leonardo da Vinci from master biographer Walter Isaacson takes a fresh look at the Renaissance icon through the lens of his many notebooks.

    -

    A portrait of Leonardo

    +A portrait of Leonardo +

    Anonymous portrait 1600. Uffizi, Florence. Source: Wikimedia Commons.

    Leonardo is one of the greatest minds humanity has ever produced. Yet he was not your usual genius. For example, despite being a great engineer he never excelled at math, as shown by some algebra mistakes in his notebooks.

    He reached extraordinary results through constant, relentless, and deliberate practice of his craft. The notebooks prove it. Countless pages in which he painstakingly practiced, studied different subjects, reflected on his experiences.

    @@ -18,7 +19,8 @@

    Collaborate

    Leonardo started his career in his early teen in the workshop Verrocchio, a famous artist in Florence, who mentored him. Most of the art pieces Leonardo worked on in Verrocchio's workshop, and later in his own, were not solo projects, but collaboration.

    It was a common practice at the time for master and students to work together. The master might work on the draft of the piece, letting the students do most of the painting, coming back only for the final touches. Or master and students could work on different subjects of the same painting.

    Leonardo collaborated with other Renaissance artists and scientists too. For example, he illustrated his friend Luca Piacioli book on geometry.

    -

    Leonardo's illustration of the Rhombicuboctahedron for Pacioli's De Divina Proportione

    +Leonardo's illustration of the Rhombicuboctahedron for Pacioli's De Divina Proportione +

    Leonardo's illustration of the Rhombicuboctahedron for Pacioli's De Divina Proportione. Source: Wikimedia Commons.

    Software development is very much the same. We work together, some times on the same piece of code, other times putting together pieces we worked on alone. Learning to collaborate effectively with others is paramount to achieve great results in building software.

    Collaboration is also a way to share knowledge. Verrocchio taught Leonardo the art of representing light of curved surfaces like draperies, which Leonardo eventually took to the next level. In the same way senior developer can teach juniors techniques they'll further develop.

    diff --git a/blog/when-to-use-map-flatmap-for/index.html b/blog/when-to-use-map-flatmap-for/index.html index 15873e5..107a8c6 100644 --- a/blog/when-to-use-map-flatmap-for/index.html +++ b/blog/when-to-use-map-flatmap-for/index.html @@ -10,42 +10,36 @@

    Why even bother having a for loop construct in the language when you can use map?!

    Once I recovered from my diseased, making arguable coding choices along the way, I realised that map and for deserve the same respect, and serve different purposes. So here's the rule of thumb on when to use map and when to use for.

    Use map when you need to transform arrays

    -
    let arrayOfNumbers = [1, 2, 3, 4]
    -let arrayOfString = arrayOfNumbers.map { "\($0)" }
    -
    +
    let arrayOfNumbers = [1, 2, 3, 4]
    +let arrayOfString = arrayOfNumbers.map { "\($0)" }

    In the context of Array map get an array, applies a transformation function to every element, and returns a new array with the resulting elements. That's the best use case for map.

    The cool thing about map is how you can chain multiple transformation together and have code that clearly express what it does.

    -
    let awesomeImages = averageImage
    -  .map(cropIntoSquare)
    -  .map(bumpContrast)
    -  .map(applySecretFilter)
    -
    -

    Use for loops when there are "side effects"

    +
    let awesomeImages = averageImage
    +  .map(cropIntoSquare)
    +  .map(bumpContrast)
    +  .map(applySecretFilter)
    +

    Use for loops when there are "side effects"

    Without going into details an operation has a side effect if it results in some kind of state changing somewhere, for example changing the value of a variable, writing to disk, or updating the UI. In such case using a for loop is more appropriate.

    -
    for number in arrayOfNumbers {
    +
    for number in arrayOfNumbers {
       print(number)
    -}
    -
    -

    And what about flatMap?

    +}
    +

    And what about flatMap?

    Everything said above stand true for flatMap as well.

    When you need to transform the contents of an array of arrays, into a linear array use flatMap:

    -
    let users: [User] = ...
    -let allEmails = users.flatMap { $0.emails }
    -
    +
    let users: [User] = ...
    +let allEmails = users.flatMap { $0.emails }

    When the code needs to perform some action that has side effects use for, and here's a nice trick to avoid nesting:

    -
    for element in nestedArray.flatten() {
    +
    for element in nestedArray.flatten() {
       updateUI(withElement: element)
    -}
    -
    -

    Performances?

    +}
    +

    Performances?

    I run some quick tests and I couldn't see any relevant performance difference between map and a for loop in Swift. The Swift compiler is probably smart enough to use the best performing loop operation regardless of the code we wrote.


    To recap, here's my rule of thumb: if there's a side effect you probably want to use for, otherwise map seems a better fit

    What is your experience with map vs for loops? Do you agree with me or have a different opinion, if so why? Get in touch on Twitter @mokagio or leave a comment below.

    Update: forEach

    Richard Fox on Twitter and on the comments below points out that Swift provides a forEach method too. The for loop above could be rewritten as:

    -
    arrayOfNumbers.forEach { print($0) }
    -
    +
    arrayOfNumbers.forEach { print($0) }

    I left out forEach because in my humble opinion the loop version reads better. For element in array do stuff seems better to me than array for each do stuff. Nevertheless forEach is as valid Swift as a for loop. You could rewrite all what we've said already using forEach instead of the loop and everything would still stand.

    It is up to you and your team to decide which convention to use, and choose the appropriate construct depending on what you are trying to achieve.

    Happy coding, and leave the codebase better than you found it.

    diff --git a/blog/why-hitting-the-network-is-bad-for-your-tests/index.html b/blog/why-hitting-the-network-is-bad-for-your-tests/index.html index 6ffb8a1..36107cd 100644 --- a/blog/why-hitting-the-network-is-bad-for-your-tests/index.html +++ b/blog/why-hitting-the-network-is-bad-for-your-tests/index.html @@ -46,15 +46,14 @@

    Use a library

    Roll your own

    Another option is to centralise all the network operations behind one single interface conforming to a protocol, for example:

    -
    protocol NetworkService {
    -  func performRequest(
    -        url: NSURL,
    -        method: Method,
    -        parameters: [String: AnyObject]?,
    -        comptletion: ([String: AnyObject]?, NSError?)
    -  )
    -}
    -
    +
    protocol NetworkService {
    +  func performRequest(
    +        url: NSURL,
    +        method: Method,
    +        parameters: [String: AnyObject]?,
    +        comptletion: ([String: AnyObject]?, NSError?)
    +  )
    +}

    All the components that need to interact with the network should be initialized with an instance of an object conforming to the NetworkService protocol to use for their requests.

    diff --git a/blog/why-i-dont-work-on-friday/index.html b/blog/why-i-dont-work-on-friday/index.html index 022c868..539ef17 100644 --- a/blog/why-i-dont-work-on-friday/index.html +++ b/blog/why-i-dont-work-on-friday/index.html @@ -4,19 +4,19 @@

    We woke up Saturday morning with 2k+ crash reports and no idea why. It took us a while to even remember about that change, figure out it was the reason of the crash, and hack around a quick fix. Everything was fixed just in time for the coffee after lunch, but we caused a severe disfunction in the service.

    None of this would have been as tragic if it'd happened one day earlier. If that change had been made on a Thursday night, we'd all been in the office when the first crashes started to pop in, and fixed it way earlier. Also the weekend is the the time in which our service is more used, so the number of crashes would have been lower.

    That was just an example, but serves well to explain why I don't work on Fridays anymore.

    -

    Why you shouldn't work on a Friday

    -

    You're tired

    +

    Why you shouldn't work on a Friday

    +

    You're tired

    Friday is the last day of the office week, and you are an hard working person. You're gonna be tired and more prone to mistakes and suboptimal choices.

    -

    You're on a rush

    +

    You're on a rush

    You are gonna be on a rush. You want to get stuff done, or even better shipped. Plus your friends are waiting for you at the pub, and are tired of you always being late. You are gonna code your way through the end of the ticket as fast as possible, maybe skipping the test for that edge case, or not running it on the device because "it's such a simple thing that's gonna work for sure". Boom! You've just created the biggest bug your company has ever seen.

    -

    You don't want to work during the weekend

    +

    You don't want to work during the weekend

    You're friends are gonna be so surprised that you were on time that they'll offer you a drink. Each one of them! You'll woke up hangover and have no idea of how to turn your laptop on, imagine trying to fix a bug on production...

    Even if you're not the pub kind of guy, the weekend is the moment to unplug, to recharge the batteries, to do something different and be ready on Monday with a refreshened creativity. You shouldn't underestimate it. It's a vicious circle.

    -

    So what to do on a Friday?

    +

    So what to do on a Friday?

    By planning your week in order to get you product or client work done between Monday and Thursday you'll have time on Friday to focus on other activities that will still bring value to your work.

    Refactor

    Refactoring, and by refactoring we mean changing entire pieces of your design, not extracting a method, is a time consuming activity that too often gets delayed because of other deadlines. Don't know where to start? Check out Refactoring: Improving the design of existing code and Working effectively with legacy code.

    -

    R&D

    +

    R&D

    The software world moves very fast. The open source world even faster. Many interesting libraries are released or updated every week. And you probably have been thinking about using that new library for the forms validation. Friday is a good time to hack around. Or maybe you could catch up with some technical reading. Or pair with the junior developer in the team and do some mentoring.

    Tool sharpening

    In this episode of Ruby Rouges Ben Orenstein talks about tool sharpening.

    diff --git a/blog/why-implicitly-unwrapping-swift-optionals-is-dangerous/index.html b/blog/why-implicitly-unwrapping-swift-optionals-is-dangerous/index.html index 4f94205..c57e746 100644 --- a/blog/why-implicitly-unwrapping-swift-optionals-is-dangerous/index.html +++ b/blog/why-implicitly-unwrapping-swift-optionals-is-dangerous/index.html @@ -30,9 +30,8 @@

    The cool thing about Swift and Optionals is that if a type is not optional, you can be sure that a value of such type won't be nil.

    This code will not compile:

    -
    let x: String = nil
    -// error: nil cannot initialize specified type 'String'
    -
    +
    let x: String = nil
    +// error: nil cannot initialize specified type 'String'

    This is pretty cool. It means that if you receive a type that is not Optional you don't have to worry about nullability. This takes away a lot of mental load when writing and reading code, and saves us from always checking for != nil @@ -41,39 +40,34 @@ post we also saw that ? is just syntactic sugar for the full Optional declaration.

    These lines do the same thing:

    -
    let a: Optional<Int> = 42
    +
    let a: Optional<Int> = 42
     
    -let b: Int? = 42
    -
    +let b: Int? = 42

    The compiler helps us out when dealing with optionals by preventing us from using an optional value as if it was an actual value:

    -
    var x: String? = "abc"
    +
    var x: String? = "abc"
     
     x.isEmpty
     // ^__ won't compile:
     //
    -// error: value of optional type 'Optional<String>' not unwrapped; did you mean to use '!' or '?'?
    -
    +// error: value of optional type 'Optional<String>' not unwrapped; did you mean to use '!' or '?'?

    We can't call isEmpty directly on our String? value, because we don't know if it's nil or not.

    To do so we need to unwrap the actual value from the Optional container, as the compiler error suggests.

    Like this:

    -
    if let someString = x {
    +
    if let someString = x {
       someString.isEmpty
     } else {
       print("Sorry mate, x is nil")
    -}
    -
    +}

    Another option is to access it like this:

    -
    someString?.isEmpty
    -
    +
    someString?.isEmpty

    The type returned by that code is Optional<Bool>, it carries the optional wrapping with it.

    What does ! mean then? The ! syntax allows us to implicitly unwrap force unwrap optional values.

    -
    someString!.isEmpty
    -
    +
    someString!.isEmpty

    The type returned by the code with ! is Bool now, the optional wrapping has been removed by the compiler.

    The important difference is that while when using if or guard we are @@ -88,19 +82,17 @@ than not proved wrong, leaving your software to deal with a nil value at runtime. And there's only one result there: it will crash.

    Consider this:

    -
    let sneakyNilValue: Optional<String> = nil
    -let x: Bool = sneakyNilValue!.isEmpty
    -
    +
    let sneakyNilValue: Optional<String> = nil
    +let x: Bool = sneakyNilValue!.isEmpty

    The compiler will consider sneakyNilValue! as unwrappable without needing to check, and compile all right. At runtime .isEmpty will be called on what is expected to be a String, but is actually nil, with this result:

    -
    fatal error: unexpectedly found nil while unwrapping an Optional value
    -Current stack trace:
    -0    libswiftCore.dylib                 0x000000010a2fd730 swift_reportError + 132
    -1    libswiftCore.dylib                 0x000000010a319cf0 _swift_stdlib_reportFatalError + 61
    -2    libswiftCore.dylib                 0x000000010a11e300 specialized specialized StaticString.withUTF8Buffer<A> (invoke : (UnsafeBufferPointer<UInt8>) -> A) -> A + 351
    -...
    -

    This is the reason I told my colleagues "The !s are very dangerous, and +

    fatal error: unexpectedly found nil while unwrapping an Optional value
    +Current stack trace:
    +0    libswiftCore.dylib                 0x000000010a2fd730 swift_reportError + 132
    +1    libswiftCore.dylib                 0x000000010a319cf0 _swift_stdlib_reportFatalError + 61
    +2    libswiftCore.dylib                 0x000000010a11e300 specialized specialized StaticString.withUTF8Buffer<A> (invoke : (UnsafeBufferPointer<UInt8>) -> A) -> A + 351
    +...

    This is the reason I told my colleagues "The !s are very dangerous, and should be used only in extreme circumstances.".

    Implicitly unwrapping Force unwrap gives you the power to treat optional values as actual values, but from great powers come great diff --git a/blog/will-ios-14-destroy-your-productivity/index.html b/blog/will-ios-14-destroy-your-productivity/index.html index a5de260..97b5279 100644 --- a/blog/will-ios-14-destroy-your-productivity/index.html +++ b/blog/will-ios-14-destroy-your-productivity/index.html @@ -7,7 +7,7 @@

    The Widgets promotional graphics from the Apple iOS 14 marketing site.

    While widgets got most of the attention, the features that go me most excited were Sleep Mode and Wind Down.

    -

    Wind Down images from the Apple website

    +Wind Down images from the Apple website

    Wind Down in action. Source: apple.com.

    When used in combination, Sleep Mode and Wind Down allow you to simplify the lock screen before it's time to go to sleep, to block out distractions and only allow those few apps you might want to use before bed, perhaps to journal or meditate.

    @@ -20,7 +20,7 @@ With widgets, not so much.

    Take the widget for Apple TV+, for example. If I were to put it in my home screen, every time I'd unlock my phone a part of my brain would get distracted by the continue watching playlist.

    -

    The Apple TV+ widget

    +The Apple TV+ widget

    The Apple TV+ widget would be a huge distraction in my home screen.

    When seeing the widget, my brain would get hijacked: "Will Alex and Bradley become friends? I wonder if Jacob actually did it... And isn't is convenient that everyone on the show has an iPhone, expect for the bad guy, who's got an older model Android device?"

    diff --git a/blog/write-better-swift-tests-with-xctest-assertions/index.html b/blog/write-better-swift-tests-with-xctest-assertions/index.html index 839d662..7fd5731 100644 --- a/blog/write-better-swift-tests-with-xctest-assertions/index.html +++ b/blog/write-better-swift-tests-with-xctest-assertions/index.html @@ -12,43 +12,39 @@

    How to write a custom XCTest assertion

    If you look under the hood of any XCTest assertion, you'll see that they are simple functions. For example, here's the signature of XCTAssertTrue:

    -
    func XCTAssertTrue(
    -    _ expression: @autoclosure () throws -> Bool,
    -    _ message: @autoclosure () -> String = "",
    -    file: StaticString = #filePath,
    -    line: UInt = #line
    -)
    -
    +
    func XCTAssertTrue(
    +    _ expression: @autoclosure () throws -> Bool,
    +    _ message: @autoclosure () -> String = "",
    +    file: StaticString = #filePath,
    +    line: UInt = #line
    +)

    Notice the file and line parameters: with their default parameters, they track the assertion call site, so Xcode can add the failure indicator and message in its UI if the test fails.

    Writing a custom assertion means building a function similar to the XCTAssert- ones: a function that performs your desired check on its input and reports failures inline using the #filePath and #line parameters.

    Here's how to build a custom assertion to verify if a Collection type (like Array) is empty.

    -
    func assertEmpty<T>(
    -    _ collection: T,
    -    message: (T) -> String = { "Collection with \($0.count) elements is not empty" },
    -    file: StaticString = #filePath,
    -    line: UInt = #line
    -) where T: Collection {
    -    guard collection.isEmpty == false else { return }
    +
    func assertEmpty<T>(
    +    _ collection: T,
    +    message: (T) -> String = { "Collection with \($0.count) elements is not empty" },
    +    file: StaticString = #filePath,
    +    line: UInt = #line
    +) where T: Collection {
    +    guard collection.isEmpty == false else { return }
     
         XCTFail(message(collection), file: file, line: line)
    -}
    -
    +}

    Let's unpack what the code does.

    func assertEmpty<T>(...) where T: Collection uses a generic type constraint to tell the compiler it expects a Collection type.

    In the body, we check whether the collection is empty, and if it isn't, we call the XCTFail XCTest method to make the test fail.

    To XCTFail, we pass the result of calling the message closure and the file and line input parameters. All parameters have default values so that consumers can call the custom assertion by passing only the collection value to check.

    Now we can express clearer intention in our tests when we check if a collection is empty:

    -
    let array = []
    -assertEmpty(array)
    -
    +
    let array = []
    +assertEmpty(array)

    With this custom assertion, we also get a more explicit failure message:

    Screenshot of the test failure reported by Xcode: "failed - Collection with 3 elements is not empty"

    Alternatively, we could have called XCTAssert which "asserts that an expression is true," making the method a one-liner.

    -
    XCTAssert(collection.isEmpty, message(collection), file: file, line: line)
    -
    +
    XCTAssert(collection.isEmpty, message(collection), file: file, line: line)

    I prefer calling XCTFail because, with XCTAssert, the failure message would be "XCTAssertTrue failed - ..." which would be confusing to see inline in Xcode as there is no clear relationship between assertEmpty and XCTAssertTrue.

    Screenshot of the test failure message when using XCTAssert

    Custom assertions can also help you to DRY your unit tests by extracting verbose checks. diff --git a/blog/writing-your-own-swift-if-let/index.html b/blog/writing-your-own-swift-if-let/index.html index d43c5fa..fc74c03 100644 --- a/blog/writing-your-own-swift-if-let/index.html +++ b/blog/writing-your-own-swift-if-let/index.html @@ -5,81 +5,74 @@ a type in its own right, defined as an enum.

    To consolidate our understanding of how optional works let's try to implement a custom version of Swift's if let ... else construct.

    -
    let optionalString: String? = ...
    -if let string = optionalString {
    +
    let optionalString: String? = ...
    +if let string = optionalString {
       print(string)
     } else {
       print("Wooops! No string")
    -}
    -
    +}

    We can imagine if let ... else as a function that takes a String? as its input, together with two other functions. One will be String -> (), the then branch of the conditional which executes if the unwrapping of the input value is successful; the other () -> (), which executes otherwise.

    -
    func ifLet(_ value: String?, then: String -> (), else elseFunc: () -> ()) {
    +
    func ifLet(_ value: String?, then: String -> (), else elseFunc: () -> ()) {
       // ...
    -}
    -
    +}

    How do we find out if value is null or not, without using if let? We could check for nullability like if (value == null), or we could remember that Optional is an enum type, and use pattern matching, which is way neater:

    -
    func ifLet(_ value: String?, then: String -> (), else elseFunc: () -> ()) {
    +
    func ifLet(_ value: String?, then: String -> (), else elseFunc: () -> ()) {
         switch value {
         case .some(let string): then(string)
    -    case .none: elseFunc()
    +    case .none: elseFunc()
         }
    -}
    -
    +}

    We can use our custom if let like this:

    -
    ifLet(optionalString,
    -    then: { print($0) },
    -    else: { print("Wooops! No string") }
    -)
    -
    +
    ifLet(optionalString,
    +    then: { print($0) },
    +    else: { print("Wooops! No string") }
    +)

    Our ifLet(value: then: else:) is restricted to String? as its input, but what if we wanted to use it with other types of optionals? Int?, Double?, NSDate?, etc.

    Let's make it generic!

    -
    func ifLet<T>(value: T?, then: T -> (), else elseFunc: () -> ()) {
    +
    func ifLet<T>(value: T?, then: T -> (), else elseFunc: () -> ()) {
         switch value {
         case .some(let x): then(x)
    -    case .none: elseFunc()
    +    case .none: elseFunc()
         }
    -}
    -
    +}

    Nice ☺️. Now we can pass any kind of inputs of our ifLet. But we're still a bit constrained, for example we couldn't replicate this behaviour:

    -
    let input: String? = "a string"
    -let output: Int = {
    -    if let string = input  {
    -    return Array(string.characters).count
    +
    let input: String? = "a string"
    +let output: Int = {
    +    if let string = input  {
    +    return Array(string.characters).count
         } else {
    -    return -1
    +    return -1
         }
    -}()
    -
    +}()

    So let's add a return value in the mix, generic of course:

    -
    func ifLet<T, U>(
    -    _ value: Optional<T>,
    -    then thenFunction: (T) -> U,
    -    else elseFunction: () -> U) -> U {
    +
    func ifLet<T, U>(
    +    _ value: Optional<T>,
    +    then thenFunction: (T) -> U,
    +    else elseFunction: () -> U) -> U {
     
         switch value {
         case .some(let x): return thenFunction(x)
    -    case .none: return elseFunction()
    +    case .none: return elseFunction()
         }
     }
     
    -let o = ifLet(
    +let o = ifLet(
         input,
         then: { x in
    -        return Array(x.characters).count
    +        return Array(x.characters).count
         },
    -    else: {
    -        return -1
    +    else: {
    +        return -1
         }
    -)
    -
    +)

    That's it. Now we have a full fledged custom if let ... else implementation... which we obviously never use because the original one is way easier to work with.

    diff --git a/blog/wwdc21-whats-new-in-testing/index.html b/blog/wwdc21-whats-new-in-testing/index.html index b11eac8..4408dc6 100644 --- a/blog/wwdc21-whats-new-in-testing/index.html +++ b/blog/wwdc21-whats-new-in-testing/index.html @@ -19,12 +19,12 @@

    Slides

    -

    What's New in Testing

    +

    What's New in Testing

    The biggest testing news was Apple's new Xcode Cloud service, a Continuous Integration service fully integrated with Xcode and App Store Connect.

    Managing CI for Swift apps has historically been tricky because of the hardware constraint that builds need to run on a Mac. There are existing products like Bitrise and TravisCI offer managed solutions, but who better than Apple to provide a managed environment on Apple hardware?

    As of this writing, Xcode Cloud is in beta, and I haven't gotten an invite yet, so it's hard to give a concrete opinion. -From what we can understand from Apple's demos at WWDC, I think this will be a solid solution for indie developers and small teams that don't have the time or know-how to manage their CI infrastructure.

    +From what we can understand from Apple's demos at WWDC, I think this will be ** a solid solution for indie developers and small teams that don't have the time or know-how to manage their CI infrastructure**.

    Another huge announcement, albeit not really a piece of news since Swift development happens in the open, was the introduction of the async/await pattern for asynchronous operations and concurrency. Not only async/await makes writing async code straightforward but also testing it. Check out this post for more details.

    diff --git a/blog/xcode-7-ui-testing/index.html b/blog/xcode-7-ui-testing/index.html index bfb6205..77f05e3 100644 --- a/blog/xcode-7-ui-testing/index.html +++ b/blog/xcode-7-ui-testing/index.html @@ -21,14 +21,13 @@

    First look at Xcode 7 UI testing

    Record UI test code animate GIF

    The first acceptance criteria we outlined for Bench is "When I tap the 'say hello' button, I see a gretings alert".

    The code that gets generated for that interaction is:

    -
    testSayHello() {
    -  let app = XCUIApplication()
    +
    testSayHello() {
    +  let app = XCUIApplication()
       app.buttons["say hello"].tap()
       app.alerts["Hello"].collectionViews.buttons["Dismiss"].tap()
    -}
    -
    +}

    As you can see the syntax is pretty straightforward. If we now run the test we'll have an output like this in the Console:

    -
    Test Case '-[BenchUITests.BenchUITests testSayHello]' started.
    +
    Test Case '-[BenchUITests.BenchUITests testSayHello]' started.
     2015-06-15 19:36:13.494 XCTRunner[3123:9611325] Continuing to run tests in the background with task ID 1
       t =     1.60s     Wait for app to idle
       t =     1.81s     Tap the "say hello" Button
    @@ -41,56 +40,49 @@ 

    First look at Xcode 7 UI testing

    t = 2.56s Find the "Dismiss" Button t = 2.57s Dispatch the event t = 2.81s Wait for app to idle -Test Case '-[BenchUITests.BenchUITests testSayHello]' passed (3.215 seconds). -

    The output reports the action taken on the UI and their time delta since the start of the test case. This could become really useful while inspecting failures in apps in which time matters, like an egg counter for example.

    +Test Case '-[BenchUITests.BenchUITests testSayHello]' passed (3.215 seconds).

    The output reports the action taken on the UI and their time delta since the start of the test case. This could become really useful while inspecting failures in apps in which time matters, like an egg counter for example.

    You can access this from the test reporter as well, and if you click on the inspector icon you'll see a screenshot of the state of the app when the test failed.

    Test reporter screenshot

    You might also have noticed that this test isn't testing anything apart from the fact that some elements are in the screen.

    Asserting the app state

    Bench's second acceptance criteria, in the form of a job story, is "When I tap the 'show elements' button, I see a list of elements".

    The recorded code for this test is:

    -
    func testShowElements() {
    -  let app = XCUIApplication()
    +
    func testShowElements() {
    +  let app = XCUIApplication()
       app.buttons["show elements"].tap()
       app.tables.staticTexts["[N] Nitrogen (7)"].swipeUp()
       app.tables.staticTexts["[Ir] Iridium (77)"].swipeUp()
       app.tables.staticTexts["[Tl] Thallium (81)"].swipeUp()
       app.tables.staticTexts["[Uut] Ununtrium (113)"].swipeUp()
    -}
    -
    +}

    This again is not very useful, and quite coupled with the formatting of the cell content.

    We can edit this test by simply making it verify that the screen presented when tapping "show elements" has one and only one table, and that the table has exactly 118 elements. Unless some major breakthrough in physics the number of elements in the period table will remain 118 for a while, which makes this test more deterministic than just relying on something as unstable as your designer or copywriter mood.

    Let's write the test again step by step. The start of the test will be the same, simply press the "show elements" button to load the next screen.

    -
    let app = XCUIApplication()
    -
    +
    let app = XCUIApplication()

    XCUIApplication is a proxy to the running app, and is what we can use to query and interact with it.

    -
    app.buttons["show elements"].tap()
    -
    +
    app.buttons["show elements"].tap()

    .buttons["show elements"] is a XCUIElementQuery provided by the XCUIApplication instance. We can combine it with subscripting to look for a button named "show elements", it will fail unless one and only one button matching that name is found. If a single button is found the query will return a XCUIElement proxy to that button. We can then tap the button through it's proxy with the tap() method.

    XCUIApplication, XCUIElementQuery, and XCUIElement are the three APIs that make UI testing possible. You can find out more about them looking at their headers through Xcode.

    What we want to do next is making sure that the screen is showing one and only one table.

    -
    XCTAssertEqual(app.tables.count, 1)
    -
    +
    XCTAssertEqual(app.tables.count, 1)

    We can combine the new UI testing APIs with the usual XCTAssert... ones.

    Having made sure that we have only one table, we can reliably move on and assert that the number of cells in the table matches the expected number of elements.

    -
    let table = app.tables.elementAtIndex(0)
    -XCTAssertEqual(table.cells.count, 118)
    -
    +
    let table = app.tables.elementAtIndex(0)
    +XCTAssertEqual(table.cells.count, 118)

    And that's it for our first UI tests with Xcode 7.

    This test function all together look like:

    -
    func testShowElements() {
    -  let app = XCUIApplication()
    +
    func testShowElements() {
    +  let app = XCUIApplication()
       app.buttons["show elements"].tap()
     
    -  XCTAssertEqual(app.tables.count, 1)
    +  XCTAssertEqual(app.tables.count, 1)
     
    -  let table = app.tables.elementAtIndex(0)
    -  let expectedNumberOfElements: UInt = 118
    -  XCTAssertEqual(table.cells.count, expectedNumberOfElements)
    -}
    -
    + let table = app.tables.elementAtIndex(0) + let expectedNumberOfElements: UInt = 118 + XCTAssertEqual(table.cells.count, expectedNumberOfElements) +}

    I'm am personally very pleased by the framework so far, and I'm looking forward to use it to test real apps. I think the message Apple is sending is very clear, they care about testing all across the spectrum, and so should we as developers!

    -

    What's next

    +

    What's next

    First of all it would be nice to try out this new framework with more complex scenarios, the acceptance criteria that we set for Bench so far are very simple, and served us only to see how to setup a testing framework, not how to harness its power.

    Tests that we could find in real world application will have to include some form of decoupling form the network, taking animations into account, handling the app state between launches, and a deeper use of assertions.

    Other interesting things to explore would be how UI testing behaves when launched from the command line, and in CI environments.

    diff --git a/blog/xcode-plugins-update/index.html b/blog/xcode-plugins-update/index.html index f39fae9..ad98123 100644 --- a/blog/xcode-plugins-update/index.html +++ b/blog/xcode-plugins-update/index.html @@ -3,8 +3,7 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    How to update an Xcode plug-in for the latest version of Xcode

    Every time a new version of Xcode is released the same drama starts to play: none of the plug-ins work.

    Most of the time this is due to the plug-in maintainer not having had the time yet to update the DVTPluginCompatibilityUUIDs array to include the DVTPluginCompatibilityUUID of the latest Xcode.

    This line of code does that for you, while you wait for a proper update to be released:

    -
    defaults write ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/XVim.xcplugin/Contents/Info  DVTPlugInCompatibilityUUIDs -array-add $(defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID)
    -

    Note that in the command above the plug-in I'm updating is XVim.xcplugin, you should replace that with the name of the plug-in you want to update.

    +
    defaults write ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins/XVim.xcplugin/Contents/Info  DVTPlugInCompatibilityUUIDs -array-add $(defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID)

    Note that in the command above the plug-in I'm updating is XVim.xcplugin, you should replace that with the name of the plug-in you want to update.

    If you need any help with this please hit me up on Twitter @mokagio, or leave a comment below.

    Happy coding, and leave the codebase better than you found it.

    diff --git a/blog/xcode-projects-and-workspaces/index.html b/blog/xcode-projects-and-workspaces/index.html index 1eec957..9ec4172 100644 --- a/blog/xcode-projects-and-workspaces/index.html +++ b/blog/xcode-projects-and-workspaces/index.html @@ -10,7 +10,7 @@

    Cool, I got that, but what about the file itself? Let's open one with a text editor. I've used the project.pbxproj from KZPropertyMapper a smart and timesaving library that you should all checkout.

    It appears as a sort of JSON, written in C, as it as a {} hierarchy, with inside =, ; and /* inline comments */.

    The top level is something like

    -
    // !$*UTF8*$!
    +
    // !$*UTF8*$!
     {
         archiveVersion = 1;
         classes = {
    @@ -20,31 +20,28 @@
             ...
         };
         rootObject = CDAC62FA17A0EF1A00F5452A /* Project object */;
    -}
    -

    The objects part is the real deal. Everything about the project is in there. All stored again in a dictionary fashion, with hexadecimal identifiers. A common parameter is the isa key. Here's an example:

    -
    CDAC634017A0EF4C00F5452A /* KZPropertyMapper.m in Sources */ = {
    +}

    The objects part is the real deal. Everything about the project is in there. All stored again in a dictionary fashion, with hexadecimal identifiers. A common parameter is the isa key. Here's an example:

    +
    CDAC634017A0EF4C00F5452A /* KZPropertyMapper.m in Sources */ = {
         isa = PBXBuildFile;
         fileRef = CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */;
    -};
    -

    Lucky for us Xcode adds some comments to make the things a bit more readable for humans. Note: I'm sure they're comment and not part of the way stuff is written because I actually tried changing one and everything run fine.

    +};

    Lucky for us Xcode adds some comments to make the things a bit more readable for humans. Note: I'm sure they're comment and not part of the way stuff is written because I actually tried changing one and everything run fine.

    The objects has many sections, each wrapped between /* Begin SectionName section */ and /* End SectionName section */ comments.

    Here's the ones I found more interesting, the xcodeproj gem documentation used by CocoaPods has been really helpful in understanding what some sections were about:

    -

    PBXFileReference

    +

    ####PBXFileReference

    All the files in the project are in this list.

    -
    CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */ = {
    +
    CDAC633F17A0EF4C00F5452A /* KZPropertyMapper.m */ = {
         isa = PBXFileReference;
         fileEncoding = 4;
         lastKnownFileType = sourcecode.c.objc;
         path = KZPropertyMapper.m;
         sourceTree = "<group>";
    -};
    -

    PBXGroup

    +};

    ####PBXGroup

    This section has the groups tree. The groups are those fake folders that are useful only to create confusion on how the filesystem is oraganized. A PBXGroup can contain PBXFirleReferences, as well as other PBXGroups.

    -

    PBXNativeTarget

    +

    ####PBXNativeTarget

    In this section we have the settings of the Targets of the project, in particular there's references to buildPhases and buildRules, like in the UI.

    -

    PBXShellScriptBuildPhase

    +

    ####PBXShellScriptBuildPhase

    Here we have the settings for a Build Phase of type Run Script. The funny thing about this part is that the script you insterted in the text box is stored as a one string…

    -

    PBXVariantGroup

    +

    ####PBXVariantGroup

    I found it hard to guess from the name, but here we have the information about the localized files.

    That's it, more or less… The project.pbxproj file stores all the informations regarding the project we're working on, and it's organized in a lot of meaningful sections related together by keeping track of the objects identifiers in form of hex hashes. Let's move on to the workspace then.

    I first came across an Xcode workspace when I used Kobold2d to develop a simple and unsuccesful game of iOS. It's easy to guess what a workspace might be.

    @@ -53,7 +50,7 @@

    PBXVariantGroup

    A workspace is an Xcode document that groups projects and other documents so you can work on them together. A workspace can contain any number of Xcode projects, plus any other files you want to include. In addition to organizing all the files in each Xcode project, a workspace provides implicit and explicit relationships among the included projects and their targets.

    The .xcworkspace from KZPropertyMapper is too tiny, so let's take a look at another one, AFNetworking. As for the project the workspace is nothing but a folder, grouping configuration files. The interesting file here is contents.xcworkspacedata. Let's open it… Surprise! Unlike the project file this one is a more readable XML. Inside there's a list of the workspace components.

    -
    <?xml version="1.0" encoding="UTF-8"?>
    +
    <?xml version="1.0" encoding="UTF-8"?>
     <Workspace
         version = "1.0">
         <Group
    @@ -82,15 +79,15 @@ 

    PBXVariantGroup

    location = "group:Tests/AFNetworking Tests.xcodeproj">
    </FileRef> ... -</Workspace> -
    +</Workspace>

    If you open the AFNetworking.xcworkspace you'll see this

    -

    AFNetworking Workspace

    +AFNetworking Workspace +

    It all then comes together. It works more or less as the project.pbxproj does. The Group tag contains other Groups or FileRef tags, which represent where the file is in the filesystem related to the location of the workspace.

    This is it. Of course there could be, and may be there will be, a lot more to dig and look into, but for tonight I'm fine with this. I now have a clearer picture of what happens when I add a new file to a project or I use the GUI to edit the configurations of a target. I can't say this is gonna make my everyday battle with Xcode easier, but definitely knowing more of how it works makes me feel smarted.

    Happy coding.

    -

    References

    +

    ###References

    • The xcodeproj gem used by CocoaPods.
    • xcoder, another gem to manipulate an Xcode project.
    • diff --git a/blog/xcode-testing-shortcuts/index.html b/blog/xcode-testing-shortcuts/index.html index b856793..4ced3a4 100644 --- a/blog/xcode-testing-shortcuts/index.html +++ b/blog/xcode-testing-shortcuts/index.html @@ -3,11 +3,11 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    Xcode keyboard shortcuts for testing

    The number one secret of productive developers is the mastery of their tools. From the text editor to the frameworks most unknown method, the more you know on a tool, the more way to use it effectively you'll find.

    Keyboard shortcuts are one of the easiest way to gain massive productivity improvements, with the least effort. I'll go as far as to say that to you should learn a keyboard shortcut a day.

    So let's see how we can be more productive when running tests from Xcode by avoiding to the mouse, ever.

    -

    Run the test - ⌘ U

    +

    Run the test - ⌘ U

    "Command-U" is the shortcut to run all the tests in the current scheme. If you need help memorizing it imagine a teenager sending a text message to Xcode saying "I command u 2 run the unit tests".

    -

    Run only one test - ctrl ⌥ ⌘ U

    +

    Run only one test - ctrl ⌥ ⌘ U

    By mashing "Control-Option-Command-U" you can run the test method in which your cursor is. This is quite useful when you're iterating on a single test and only want to run that one. You can remember it by imagining the same teenager having a control panel, with one option per test, that they can use to send Xcode a text message saying "I command u 2 run this test".

    -

    Re-run the previous set of tests - ctrl ⌥ ⌘ G

    +

    Re-run the previous set of tests - ctrl ⌥ ⌘ G

    With "Control-Opion-Command-G" you can re-run the last test method executed. That is if you run only one test, that test will run again, if you run the entire suite, all the tests will be executed again. Like "Control-Option-Command-U" this is useful when iterating on a single test. For example if you're refactoring and are in the file you're working on, instead of having to go back to the test method, or, heaven forbid, moving your hands from the keyboard to touch the mouse, you can simply re-run the last test action, and be proud of yourself.

    To remember this one think about the teenager saying Xcode "Gee Xcode, I don't remeber... just do the last thing I told you again!".

    There you go, these simple keyboard shortcut will save a lot of time over the course of the work week, and making them muscle memory will be a matter of days.

    diff --git a/blog/xcode-ui-test-view-changes/index.html b/blog/xcode-ui-test-view-changes/index.html index e1bb9c9..d2e2228 100644 --- a/blog/xcode-ui-test-view-changes/index.html +++ b/blog/xcode-ui-test-view-changes/index.html @@ -1,28 +1,27 @@ How to test UI changes in Xcode 7 | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    How to test UI changes in Xcode 7

    With Xcode 7 Apple introduced a new framework for UI testing. As with every new thing there is always room for improvement, and with Xcode 7 Beta 4, UI testing got a very useful improvement: the ability to wait asynchronously for view changes.

    -

    +

    Joar's tweet is enlightening but doesn't show any code, so let's see how to do that. You can checkout the example project as well if you want.

    -
    func expectationForPredicate(predicate: NSPredicate, evaluatedWithObject object: AnyObject, handler: XCPredicateExpectationHandler?) -> XCTestExpectation
    -
    +
    func expectationForPredicate(predicate: NSPredicate, evaluatedWithObject object: AnyObject, handler: XCPredicateExpectationHandler?) -> XCTestExpectation

    The header for this method reads: creates an expectation that is fulfilled if the predicate returns true when evaluated with the given object. The expectation periodically evaluates the predicate and also may use notifications or other events to optimistically re-evaluate. If the handler is not provided the first successful evaluation will fulfill the expectation. If provided, the handler can override that behavior which leaves the caller responsible for fulfilling the expectation.

    So what we need to do to assert the changes in our views is write a test predicate and pass it to expectationForPredicate, together with the object the predicate has to be evaluated with, and an optional handler.

    More in details here's what Joar suggests:

    -

    +

    Let's take a sample app in which we have a button that once touched triggers an delayed update in a label. This is somehow similar to an "Updated at..." label that updates its text once the app receives the response to an update request to the server. A possible UI test for it would be:

    -
    func testOtherButtonChangesFooter() {
    -  let app = XCUIApplication()
    +
    func testOtherButtonChangesFooter() {
    +  let app = XCUIApplication()
     
       // Define the expectation on the final UI state
       //
    -  let expectedText = "Oh! Did something happen?!"
    -  let labelIdentifier = "footer label"
    -  let testPredicate = NSPredicate(format: "label = '\(expectedText)'")
    -  let object = app.staticTexts.elementMatchingType(.Any, identifier: labelIdentifier)
    +  let expectedText = "Oh! Did something happen?!"
    +  let labelIdentifier = "footer label"
    +  let testPredicate = NSPredicate(format: "label = '\(expectedText)'")
    +  let object = app.staticTexts.elementMatchingType(.Any, identifier: labelIdentifier)
     
       self.expectationForPredicate(testPredicate, evaluatedWithObject: object, handler: nil)
     
    @@ -33,8 +32,7 @@
       // Wait and see...
       //
       self.waitForExpectationsWithTimeout(10, handler: nil)
    -}
    -
    +}

    That's it. I wouldn't go so far as saying as simple as that, because there is a bit of setup to do in order to run the assertion.

    If you would like to see more examples of this kind of test, or would like to share your implementations please leave a comment below, or tweet me @mokacoding.

    Leave the codebase better than you found it.

    diff --git a/blog/xcode5-crash-on-submission/index.html b/blog/xcode5-crash-on-submission/index.html index f4314a0..05eddde 100644 --- a/blog/xcode5-crash-on-submission/index.html +++ b/blog/xcode5-crash-on-submission/index.html @@ -3,49 +3,47 @@

    mokacoding

    unit and acceptance testing, automation, productivity

    A workaround to Xcode 5 GM crash on app submission

    I just finished writing this post, and I realized is just about me complaining trying to sound funny. So here's, frontloaded, the important stuff.

    Apparently Xcode 5 GM crashed on some of us during the App Store submission process. Before even starting it. How annoying.

    The workaround I found relies on bypassing Xcode for the submission process.

    -

    Step 1

    +

    ####Step 1

    Make sure all the provisioning profiles and code signing are set properly

    -

    Step 2

    +

    ####Step 2

    Open your Terminal and generate the .ipa yourself, with the help of shenzhen.

    -
    cd my/ready/to/be/submitter/ios/project
    -ipa build -c Release
    -

    Step 3

    +
    cd my/ready/to/be/submitter/ios/project
    +ipa build -c Release

    ####Step 3

    Upload the app through Application Loader.

    -

    Step 4

    +

    ####Step 4

    Find a tv series to start watching while waiting for your app to be reviewed.

    That's all. It took me an embarrassing long while to figure this out, I hope to be helping some fellow developer with this post.

    Below the full thing.


    Every now and then in the lifecycle of an iOS project it comes the day when you have to submit an update, or even worst touch the provisioning profiles. When that day comes, it's better if it's a Monday, because you don't want to ruin yourself the weekend. And it's also better if you have chamomile in your cup instead of coffee.

    -

    Submit your iOS7 apps today

    +

    ###Submit your iOS7 apps today

    Submit today

    On the 10th of September Apple sent an email to their developers, "Submit your iOS7 apps today" they said. Up to that point we couldn't submit apps made with the iOS7 SDK, as written somewhere in the Xcode 5 Developer Preview release notes. But that day the iOS7 GM and Xcode 5 GM where released, and the run to submit started.

    Use Xcode 5 GM

    In their beautiful styled iOS7 developer page they explained everything. If you follow the link to the App Distribution Guide in the bottom of the page you will have a funny surprise. The link goes to the previous version documentation, and our Apple engineers forgot to add a link to the new version.

    Missing link

    I'm sure everything is gonna be fine, Xcode is such a reliable IDE, and the Apple guys are known for the quality of the products they give to their developers. Let's go!

    -

    The tragic message

    +

    ###The tragic message

    When clicking on "Validate" or "Distribute" from the organizer, no matter how may times I refreshed my Accounts in the Preferences menu this is what I got

    The terrible dialog

    And guess what? Both those buttons resulted in Xcode crashing, right there, with no explanation, no progress bar, nothing, Boom!

    Out of curiosity I opened the crash log that got generated and…

    -
    Crashed Thread:  0  Dispatch queue: com.apple.main-thread
    +
    Crashed Thread:  0  Dispatch queue: com.apple.main-thread
     
    -Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
    -Exception Codes: EXC_I386_GPFLT
    -

    Whenever I get an EXC_BAD_ACCESS (SIGSEGV) I feel like punching myself in the face, it's a memory issue, and I must have been really dumb to produce something like that in the ARC era.

    +Exception Type: EXC_BAD_ACCESS (SIGSEGV) +Exception Codes: EXC_I386_GPFLT

    Whenever I get an EXC_BAD_ACCESS (SIGSEGV) I feel like punching myself in the face, it's a memory issue, and I must have been really dumb to produce something like that in the ARC era.

    But let's not waste time complaining about those things, risking to be kicked out of the dev program, and look for a solution.

    -

    The workaround

    +

    ###The workaround

    What's the place where all the developers go when in trouble? No it's not church, it's StackOverflow! There I found someone with the same problem, suggesting to use Application Loader to upload the app.

    I never used it before, but I was faced with a problem straightaway. Application Loader need an .ipa, which we can generate only through the Organizer in Xcode.

    "which we can generate only through the Organizer in Xcode.". Are you sure about it?

    Actually xcodebuild, Xcode CLI, let us build ipas, in a very complex way. xctool buy the Facebook iOS team makes the task easier, but it the usual suspect, good guy Mattt that has the real solution for that. With his gem shenzhen we can build an ipa from command line without spending too much time specifing options or reading through the --help guide.

    -
    ipa build -c Release
    -

    That's all we need to generate our .ipa.

    +
    ipa build -c Release

    That's all we need to generate our .ipa.

    Once we have our package we can send it to the Apples servers through Application Loader, bypassing Organizer and the frustrating crash. Smart!

    -


    -That's all folks. I'm a bit disappointed by the fact that such an issue is leaked on a GM, when we, some of us at least, spend so much time unit testing our apps, being patient with the QA guys, and taking all the possible measures to make sure everything works as expected. But nobody's perfect, and every now and then hacking stuff is fun, so no big deal.

    +
    +That's all folks. I'm a bit disappointed by the fact that such an issue is leaked on a GM, when we, some of us at least, spend so much time unit testing our apps, being patient with the QA guys, and taking all the possible measures to make sure everything works as expected. But nobody's perfect, and every now and then hacking stuff is fun, so no big deal. +

    Happy coding!

    diff --git a/blog/xcodebuild-destination-options/index.html b/blog/xcodebuild-destination-options/index.html index 6854616..cc9dde1 100644 --- a/blog/xcodebuild-destination-options/index.html +++ b/blog/xcodebuild-destination-options/index.html @@ -17,54 +17,47 @@

    Destination Specifier

    OS X

    The Mac OS X platform accepts an arch keyword, which can be either x86_64 or i386. x86_64 is the default.

    -
    xcodebuild \
    +
    xcodebuild \
       -workspace MyMacApp.xcworkspace \
       -scheme MyMacApp \
       -destination 'platform=OS X,arch=x86_64' \
    -  clean test
    -

    iOS

    + clean test

    iOS

    The iOS platform should be used when you want to run tests on a connected device. It supports two keys, id and name. Either one of the two must be provided, but not both.

    Use name to target a device using it's name, id to use its UUID.

    -
    xcodebuild \
    +
    xcodebuild \
       -workspace MyApp.xcworkspace \
       -scheme MyApp \
       -destination "platform=iOS,name=Gio's iPhone" \
    -  clean test
    -
    xcodebuild \
    +  clean test
    xcodebuild \
       -workspace MyApp.xcworkspace \
       -scheme MyApp \
       -destination 'platform=iOS,id=YOUR_PHONE_UUID' \
    -  clean test
    -

    iOS Simulator

    + clean test

    iOS Simulator

    iOS Simulator is the platform I use more often. It supports the same id and name mutually exclusive keys as iOS, plus an OS key. OS expects a target version number, like 9.1, or latest, which is the default.

    -
    xcodebuild \
    +
    xcodebuild \
       -workspace MyApp.xcworkspace \
       -scheme MyApp \
       -destination 'platform=iOS Simulator,name=iPhone 6,OS=9.1' \
    -  clean test
    -

    tvOS and tvOS Simulator

    + clean test

    tvOS and tvOS Simulator

    The tvOS and tvOS Simulator platforms expect the same parameters as their iOS counter parts.

    watchOS and watchOS Simulator

    watchOS and watchOS Simulator have a slightly different behaviour. Since a watchOS app is always build and deployed nested inside of an iOS app to use such a destination you will need to specify a scheme which is configured to run a WatchKit app, and specify the platform destination that is paired with the watchOS device you want to use.

    -
    xcodebuild \
    +
    xcodebuild \
       -workspace MyApp.xcworkspace \
       -scheme MyWatchKitApp
       -destination 'platform=iOS Simulator,name=iPhone 6,OS=9.1' \
    -  build
    -

    Unable to find destination

    + build

    Unable to find destination

    When in doubt with the destination parameter a good trick is to write some nonsense in as the destination specifier. xcodebuild will fail and then list all the available destinations for the given scheme:

    -
    xcodebuild: error: Unable to find a destination matching the provided destination specifier:
    -        { platform:jibberish }
    +
    xcodebuild: error: Unable to find a destination matching the provided destination specifier:
    +        { platform:jibberish }
     
    -    The requested device could not be found because no available devices matched the request.
    +    The requested device could not be found because no available devices matched the request.
     
    -    Available destinations for the "MyApp" scheme:
    -        { platform:iOS Simulator, id:5BBA1401-0C74-47A7-8709-9F6C1D9C9CBB, OS:9.1, name:iPhone 6s }
    -        { platform:iOS Simulator, id:28FF0903-97D6-459B-8F34-D9436AEA3B87, OS:9.1, name:iPhone 6s Plus }
    -

    Generic Platform

    + Available destinations for the "MyApp" scheme: + { platform:iOS Simulator, id:5BBA1401-0C74-47A7-8709-9F6C1D9C9CBB, OS:9.1, name:iPhone 6s } + { platform:iOS Simulator, id:28FF0903-97D6-459B-8F34-D9436AEA3B87, OS:9.1, name:iPhone 6s Plus }

    Generic Platform

    There are some xcodebuild actions, like build, that may be performed without an actual device. To target a platform generically prefix the destination specifier with generic/.

    -
    -destination generic/platform=iOS
    -

    Multiple Destinations

    +
    -destination generic/platform=iOS

    Multiple Destinations

    You can specify multiple -destination options to make xcodebuild perform the action on multiple destinations.

    Timeout

    The -destination-timeout option specifies the amount of time in seconds to wait before considering the specified destination unavailable. The default timeout is 30 seconds.

    @@ -72,14 +65,13 @@

    Default Destination

    If -destination is omitted, xcodebuild defaults to a destination compatible with the selected scheme. But, do you really trust Xcode to do the right thing for you? 😕

    List All Available Destinations

    To list all the known destination you can use instruments -s devices. The output is a list in the format name (OS) [UUID].

    -
    Giovanni’s Retina MacBook Pro [37B86DB5-FB69-56F7-A023-ECC6B90C3486]
    -Apple TV 1080p (9.0) [BCFBA897-9E8D-43BA-9EE0-A93B39615ECA]
    -Apple Watch - 38mm (2.0) [9366B46E-EB1D-4CF3-B7EE-6E1BCEE0F89E]
    +
    Giovanni’s Retina MacBook Pro [37B86DB5-FB69-56F7-A023-ECC6B90C3486]
    +Apple TV 1080p (9.0) [BCFBA897-9E8D-43BA-9EE0-A93B39615ECA]
    +Apple Watch - 38mm (2.0) [9366B46E-EB1D-4CF3-B7EE-6E1BCEE0F89E]
     ...
    -iPhone 6s (9.1) [5BBA1401-0C74-47A7-8709-9F6C1D9C9CBB]
    -iPhone 6s (9.1) + Apple Watch - 38mm (2.0) [303CB525-E04F-463D-B0E5-22E19278E88C]
    -...
    -

    +iPhone 6s (9.1) [5BBA1401-0C74-47A7-8709-9F6C1D9C9CBB] +iPhone 6s (9.1) + Apple Watch - 38mm (2.0) [303CB525-E04F-463D-B0E5-22E19278E88C] +...

    You can find more information about the -destination option and xcodebuild itself by reading the tool's manpage: man xcodebuild.

    I hope you will find these tip useful. Have you got something else to add, or a correction? What's you favourite xcodebuild combo? Leave a comment below or hit me up on Twitter @mokagio.

    Happy coding, and leave the codebase better than you found it.

    diff --git a/blog/xctest-closure-based-expectation/index.html b/blog/xctest-closure-based-expectation/index.html index f4756dd..2ea5cbc 100644 --- a/blog/xctest-closure-based-expectation/index.html +++ b/blog/xctest-closure-based-expectation/index.html @@ -6,43 +6,42 @@

    We've already seen some techniques to test asynchronous code. Here's another one useful when...

    Here's an example, which you can find in full on GitHub.

    Say we have a ProductView, and a ProductViewConfigurator service which given a product id fetches its data and configures the view with it.

    -
    class ProductView: UIView {
    -  let name: UILabel = UILabel()
    -  let price: UILabel = UILabel()
    +
    class ProductView: UIView {
    +  let name: UILabel = UILabel()
    +  let price: UILabel = UILabel()
     }
     
     class ProductViewConfigurator {
       let view: ProductView
     
    -  init(view: ProductView) {
    -    self.view = view
    +  init(view: ProductView) {
    +    self.view = view
       }
     
    -  func configure(withProductId id: Int) { ... }
    -}
    -
    + func configure(withProductId id: Int) { ... } +}

    How can we test that given a know product id the view will be configured with the expected name and price values?

    XCTest provides a method to generate an expectation that will fulfil based on the result of an NSPredicate, expectation(for:, evaluatedWith:, handler:).

    Add to that the fact that NSPredicate can be initialized with a closure to evaluate, and now you have a recipe for a closure based expectation.

    -
    // When ProductViewConfigurator configures the view with a given product id
    +
    // When ProductViewConfigurator configures the view with a given product id
     // It sets the view name with the name of the fetched product
     // It sets the view price with the formatted price of the fetched product
    -func testItConfiguresTheView() {
    -  let view = ProductView()
    -  let configurator = ProductViewConfigurator(view: view)
    +func testItConfiguresTheView() {
    +  let view = ProductView()
    +  let configurator = ProductViewConfigurator(view: view)
     
       // Create an NSPredicate with a closure describing the test condition
       //
    -  let predicate = NSPredicate(block: { any, _ in
    +  let predicate = NSPredicate(block: { any, _ in
         // Note that because the predicate receives an Any as input we need to
         // cast it.
    -    guard let view = any as? ProductView else { return false }
    -    return view.name.text == "Foo" && view.price.text == "$42"
    +    guard let view = any as? ProductView else { return false }
    +    return view.name.text == "Foo" && view.price.text == "$42"
       })
     
       // Create an expectation using the predicate
       //
    -  _ = self.expectation(for: predicate, evaluatedWith: view, handler: .none)
    +  _ = self.expectation(for: predicate, evaluatedWith: view, handler: .none)
     
       // Exercise the system under test
       //
    @@ -50,9 +49,8 @@
     
       // Wait for the expectation to fulfil
       //
    -  waitForExpectations(timeout: 1, handler: .none)
    -}
    -
    + waitForExpectations(timeout: 1, handler: .none) +}

    That's it. Create a block based NSPredicate, use it as create an XCTestExpectation, exercise the system under test, make the test wait for the expectation to be fulfilled.


    I hope you found this post useful. If you have any question or concern please do get in touch on Twitter @mokagio, or leave a comment below.

    diff --git a/blog/xctest-nimble/index.html b/blog/xctest-nimble/index.html index 6490212..937a5ac 100644 --- a/blog/xctest-nimble/index.html +++ b/blog/xctest-nimble/index.html @@ -12,53 +12,44 @@

    That's the thing, the assertion provided by XCTest are not powerful enough, and way to verbose.

    Let me introduce you to Nimble a matcher framework for Swift (and Objective-C) that you can easily integrate in your XCTestCases to have a way nicer and easy to write syntax.

    This is how some usual assertion look when written using Nimble

    -
    XCTAssertEqual(anInt, 42)
    +
    XCTAssertEqual(anInt, 42)
     
    -expect(anInt) == 42
    -
    -
    XCTAssert(aBool)
    +expect(anInt) == 42
    +
    XCTAssert(aBool)
     
    -expect(aBool).to(beTrue())
    -
    -
    XCTAssertFalse(anotherBool)
    +expect(aBool).to(beTrue())
    +
    XCTAssertFalse(anotherBool)
     
    -expect(anotherBool).to(beFalsy())
    -
    -
    XCTAssertEqual(aString, "expected value")
    +expect(anotherBool).to(beFalsy())
    +
    XCTAssertEqual(aString, "expected value")
     
    -expect(aString) == "expected value"
    -
    +expect(aString) == "expected value"

    They read quite better, and in particular the relationship between actual and expected value is explicit. Plus, how neat is it to use == to test for equality? 😎

    And it doesn't end here, Nimble provide syntactic candies like:

    Negative forms

    -
    expect(batman.name).toNot(equal("Peter Parker"))
    -expect(ironman.name).notTo(equal("Barry Allen"))
    -expect(greenArrow.name) != "Matt Murdok"
    -
    +
    expect(batman.name).toNot(equal("Peter Parker"))
    +expect(ironman.name).notTo(equal("Barry Allen"))
    +expect(greenArrow.name) != "Matt Murdok"

    Math comparisons

    -
    expect(actual).to(beLessThan(expected))
    -expect(actual) < expected
    +
    expect(actual).to(beLessThan(expected))
    +expect(actual) < expected
     
     expect(actual).to(beLessThanOrEqualTo(expected))
    -expect(actual) <= expected
    +expect(actual) <= expected
     
     expect(actual).to(beGreaterThan(expected))
    -expect(actual) > expected
    +expect(actual) > expected
     
     expect(actual).to(beGreaterThanOrEqualTo(expected))
    -expect(actual) >= expected
    -
    +expect(actual) >= expected

    Range comparisons

    -
    expect(10.01).to(beCloseTo(10, within: 0.1))
    -expect(actual) ≈ (expected, delta)
    -expect(actual) == expected ± delta
    -
    +
    expect(10.01).to(beCloseTo(10, within: 0.1))
    +expect(actual)  (expected, delta)
    +expect(actual) == expected ± delta

    Async expectations

    -
    expect(systemUnderTest.someState).toEventually(beTruthy(), timeout: 3)
    -
    +
    expect(systemUnderTest.someState).toEventually(beTruthy(), timeout: 3)

    Swift 2 error handling

    -
    expect{ try somethingThatThrows()  }.to(throwError())
    -
    +
    expect{ try somethingThatThrows()  }.to(throwError())

    You can learn about all the awesome matchers that Nimble provides out of the box in the README, and if you need more expressive power you can even write your own.

    Conclusion

    Nimble is a great Swift matcher framework. Integrating it with vanilla XCTest suites is easy and frictionless.

    diff --git a/blog/xunique/index.html b/blog/xunique/index.html index 790df98..4ab8c22 100644 --- a/blog/xunique/index.html +++ b/blog/xunique/index.html @@ -2,7 +2,7 @@ [What is your biggest struggle right now with building software?](https://goo.gl/forms/lCLlJd9hqCUYoTME2)-->

    Avilable Now: Test-Driven Development in Swift with SwiftUI and Combine

    mokacoding

    unit and acceptance testing, automation, productivity

    xUnique: a tool to avoid Xcode project merge conflicts

    How many times when working on a Mac OSX or iOS app with a team have you had a merge conflict on the project.pbxproj file? I guess more than a few, a lot more than a few.

    In this article we are going to show a way to reduce the chances of such issues using a tool called xUnique.

    -

    Xcode's project file

    +

    Xcode's project file

    Just in case you're not familiar with it, the infamous project.pbxproj is the way Xcode tracks which files are in the project, and describes the project settings, like targets and build configurations.

    At the core of the way Xcode keeps track of all these things is the fact that every entry has it's own unique identifier.

    You can read more about how the Xcode's project.pbxproj work in the Apple documentation, this old post on mokacoding, and this more recent one from Michele Titolo.

    @@ -14,12 +14,10 @@

    Enter xUnique

    Install xUnique

    xUniqe is a Python tool, a fact rather unusual for iOS/OSX utilities.

    The best way to install it is through PyPi.

    -
    pip install xUniqe
    -

    Before doing that you might want to make sure that your Python toolchain is up to date. I'd reccomend using homebrew for that.

    +
    pip install xUniqe

    Before doing that you might want to make sure that your Python toolchain is up to date. I'd reccomend using homebrew for that.

    Uniquifying the project

    With xUnique now installed you can "uniquify" the project.pbxproj like this:

    -
    python -mxUnique MyAwesomeApp.xcodeproj/project.pbxproj
    -

    The first thing you'll see is that all your groups and files in Xcode have been sorted alphabetically, and if you'll look at the git diff you'll see that all the identifiers in the project file have changed.

    +
    python -mxUnique MyAwesomeApp.xcodeproj/project.pbxproj

    The first thing you'll see is that all your groups and files in Xcode have been sorted alphabetically, and if you'll look at the git diff you'll see that all the identifiers in the project file have changed.

    And example diff can be seen here, in the example project we setup for the occasion.

    Automating the process

    You might now be saying: "But I don't want to run that command every time I touch the project!" . And you'd be right!

    @@ -28,13 +26,12 @@

    Automating the process

    We can easily automate this process by adding a Run Script Build Phase to our target and have it run xUnique for as after every build.

    I like to have my run scripts in their own file rather than in the Run Script text view, it makes it easier to edit them with your text editor of choice.

    -
    # uniquify.sh
    +
    # uniquify.sh
     
     #!/bin/bash
     
     # uniquify and sort the Xcode projct files
    -python -mxUnique "${PROJECT_FILE_PATH}/project.pbxproj"
    -
    +python -mxUnique "${PROJECT_FILE_PATH}/project.pbxproj"

    Add Run Script with xUnique

    The version of the script above uses the PROJECT_FILE_PATH environmet variable provided by Xcode to the Run Scripts. If you want to be able to run the script yourself replace it with MyAwesomeApp.xcodeproj.

    Something to keep in mind

    diff --git a/blog/xvim/index.html b/blog/xvim/index.html index a9d421b..9ed3469 100644 --- a/blog/xvim/index.html +++ b/blog/xvim/index.html @@ -19,7 +19,7 @@

    Relative line numbers

    To fully leverage the power of the motion commands you can enable relative lines numbers.

    XVim relative line numbers screenshot

    With this option the line numbers on the gutter show the relative distance from the current line. This way you can move around the file using <number>j and <number>k with great ease, no need to mentally count the distance you want to jump, or to guess it.

    -

    .xvimrc

    +

    .xvimrc

    Like Vim, you can configure XVim with an rc file, the .xvimrc. This means that you can put that file under version control, share it across your machines, and experiment on the configurations without being worried on messing them up.

    Windows

    Developers like to work on split windows. XVim allows you to open a new Assistant Editor any way you want, in normal mode type :sp to open a new horizontal window, or :vs for a vertical one.

    diff --git a/blog/your-git-log-should-tell-a-story/index.html b/blog/your-git-log-should-tell-a-story/index.html index 03fdbf9..26ea983 100644 --- a/blog/your-git-log-should-tell-a-story/index.html +++ b/blog/your-git-log-should-tell-a-story/index.html @@ -9,19 +9,18 @@

    We software developers take a lot of care in crafting readable and efficient code, but too often not enough in writing informative commits. It is not uncommon to see logs like this (fictitious) one:

    -
    $ git log --format=oneline --abbrev-commit
    +
    $ git log --format=oneline --abbrev-commit
     
    -5ab4e81 Cleanup
    -66105f6 Updated based on PR comments
    -aecb4de Forgot to add a file
    -63194e8 Tweaked custom pop animation parms
    -344eafd Implement new navigation style
    -43e06b3 Actually make status bar white
    -2e01356 Needs beer
    -aca1ff6 Not working
    -17107ab Fix status bar not being white
    -9c7f5d1 Make status bar white
    -

    While it might be funny to read that the committer felt like beer at the time +5ab4e81 Cleanup +66105f6 Updated based on PR comments +aecb4de Forgot to add a file +63194e8 Tweaked custom pop animation parms +344eafd Implement new navigation style +43e06b3 Actually make status bar white +2e01356 Needs beer +aca1ff6 Not working +17107ab Fix status bar not being white +9c7f5d1 Make status bar white

    While it might be funny to read that the committer felt like beer at the time they were writing the code, that is not very useful for someone looking at it.

    What could a commit titled "Not working" have introduced in the codebase? No idea. The only way to know is to look at the commit changes.

    @@ -29,13 +28,12 @@ PRs? In this case reading at what that commit introduced will not be enough, one would need a link to the pull request to understand the full picture.

    What I would like to see would be something more like this:

    -
    $ git log --format=oneline --abbrev-commit
    +
    $ git log --format=oneline --abbrev-commit
     
     a6104f6 Extract custom durations in constants
     63194e8 Tweak custom pop animation params
     344eafd Implement new navigation style
    -ac5f5d3 Make status bar white
    -

    This log tells a story which is straightforward and easy to follow. Any +ac5f5d3 Make status bar white

    This log tells a story which is straightforward and easy to follow. Any reader of this log, which includes future-you which will have forgotten the details of that code, will get the idea of what happened there just by reading it.

    diff --git a/espresso.html b/espresso.html index 89bd5ef..d6801ec 100644 --- a/espresso.html +++ b/espresso.html @@ -1,6 +1,6 @@ Espresso | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Espresso

    An espresso is a small coffee, sometimes taken as a quick break.

    +

    mokacoding

    unit and acceptance testing, automation, productivity

    Espresso

    An espresso is a small coffee, sometimes taken as a quick break.

    The espresso posts on mokacoding are short super focused post, mainly a way for me to share interesting little findings, and dump information I might forget.

    Enjoy ☕️.



    How to set default values in Swift compiler-generated initializers

    You can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.

    How to rename a file in Vim

    There are many ways to rename a file in Vim. Here's three.

    How to remove trailing whitespaces from all files in a folder

    Here's a shell command to trim all the trailing whitespaces in all the files of the current folder.

    How to add co-authors to a Git commit

    How to check if macOS app is notarized

    How to reverse a file in the terminal

    How to verify your SSH private key password

    How to check if array contains element with block in Ruby

    Symbolic links in Git

    Here's how to track symbolic liks in a Git repository, in a way suitable for teams.

    Quick beforeSuite and afterSuite behaviour

    A look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using them

    Quick beforeEach and afterEach behaviour

    A look at how nested beforeEach and afterEach behave in the Quick testing framework.

    Unless.swift

    Porting Ruby's unless operator into Swift via a function.

    Lessons learned working on danger-switlint selective linting

    A little post to share some things I learnt while working on a PR for danger-swiftlint to allow selective linting.

    Setting Up Firebase Without Using CocoaPods

    A guide on how to configure your Xcode project to use Google Firebase without using CocoaPods.

    Cloud 66 Postfix Deploy Hook

    A deploy hook to configure Postfix every time a Cloud 66 stack is built

    Strong Opinions Loosely Held

    Strong opinions loosely held, and other cornerstones for a winning mindset

    Writing your own Swift "if let"

    An exercise to understand Swift's optional type: reimplementing the if let functionality

    How to make Swift methods unavailable

    A quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.

    NSDateFormatter format for JSON dates

    How to configure NSDateFormatter to work with JSON API dates.

    "Functional Core, Reactive Shell" Resources

    Links from my "Functional Core, Reactive Shell" talk

    How to update all plug-ins for the latest version of Xcode and Xcode-beta

    An handy script to update all Xcode plug-ins to be compatible with the latest version of Xcode and Xcode-beta.

    How To Fix Fabric Crashing On Startup When Installed Via CocoaPods

    If you are experiencing crashes with a version of Fabric and Crashlytics installed via CocoaPods chances are you are missing required information in the Info.plist. This post shows how to solve this issue.

    How to use a double slash in xcconfig files

    A short post showing how to use a double slash in xcconfig files, for example to write URLs like https://mokacoding.com

    Opening a PR to Bitbucket from the terminal

    A simple script you can run to open a PR on BitBucket for your current branch.

    How to update an Xcode plug-in for the latest version of Xcode

    A simple command to run in your terminal to make sure you can use your favourite plugins on the latest version of Xcode

    Hacker News Button

    How to add an Hacker News button to your blog

    Injecting environment variables from a file with xargs

    How to provide environment variables stored in a .env file as an input for a command execution without having to export then, with a deep look at the shell commands used.

    How to use Homebrew in CI

    A quick guide on how to safely use Homebrew in CI.

    The best free RSS reader app ever: IFTTT + Pocket

    By using the powerful automation provided by IFTTT we can make deliver the latest posts of your favourite blogs to Pocket. This is the most powerful RSS reader ever, and it is free.

    How to display relative line numbers in NERDTree

    Vim's relative line numbers are great for jumpin around files, and once you get used to them you want to enable them everywhere. Here's how to have NERDTree use relative line numbers

    How to always use the latest Simulator with Xcodebuild

    There is a simple keyword you can use in the destination option of an xcodebuild command to always run the most recent Simulator version.

    How to install Xcode Command Line Tools without GUI or Xcode

    Here's a little script that will allow you to install the Xcode Command Line Tools without having to install Xcode, nor having a logged GUI. This can come pretty handy in automated scripts or when provisioning virtual machines.

    AFNetworking custom response serializer to add error information

    How to implement a custom AFNetworking response serializer to read the failure response data and populate the callback error with it.

    How to have multiple iTunes Connect accounts, and submit apps

    Swift array of characters from String

    How to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].

    How to reuse the last parameter in a terminal command

    When typing a shell command it is possible to reuse the last argument of the previous call without having to type it. Let's see how.

    Packaging an ipa with Swift files from the terminal

    If you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.

    mokacoding

    unit and acceptance testing, automation, productivity

    Archive



    Test-Driven Development in Swift is now available

    My book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.

    WWDC21: What's New in Testing

    A roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.

    How to test Swift async/await code with XCTest

    Swift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.

    How to write better tests for Swift date comparisons

    Testing Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.

    On the benefits of distributed work

    Working from home doesn't have to be lonely. Going from remote to distributed can bring massive benefits to employees satisfaction and company productivity.

    How to manage complex inputs in your Swift tests with Scenario Builders

    When writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.

    A World Without Slack

    How to establish a workflow that minimizes unscheduled, unstructured communication and maximizes focus and productivity.

    A distributed asynchronous release process

    My latest post on mobile.blog explores two simple conventions Automattic uses to remove the need for synchronous meetings in their app release process.

    Working Backwards

    How working your way backwards from your desired outcome can make you more productive, focused, and motivated.

    How waiting in line can improve your focus

    Embrace boredom to train your brain to sustain focus when working on demanding tasks

    Unit Testing Combine Publisher Cheatsheet

    Snippets to test the behavior of Combine Publishers in XCTest ready to copy and paste into Xcode

    Boring Iterations. Interesting Steps.

    Camille Fournier encourages us to "Make Boring Plans" and move in small iterations.

    How to migrate from SwiftUI to UIKit App Delegate Life Cycle in Xcode

    This free tutorial shows how to migrate an existing app with SwiftUI life cycle to use UIKit App Delegate instead

    How to stick with your New Year resolutions

    The start of a new year is a great time to work on self-improvement, but unless you take the right steps, your New Year resolutions might not stick.

    How to set default values in Swift compiler-generated initializers

    You can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.

    How to improve your Test-Driven Development workflow by asking "Do I need this yet?"

    The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.

    Write better Swift unit tests with custom XCTest assertions

    The XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.

    How to write unit test assertions for Swift Result values

    Result is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.

    When experiments go wrong

    Scientist can learn a lot from failed experiments. To do so, they must be methodical and collect all sorts of information. Softwar developers can learn a lot from failures, too. What are the practicies that can make learning easier?

    How to merge pull requests with a commit that improves your Git history

    When merging a pull request on GitHub, it helps to replace the default merge commit title with the PR title or an equally descriptive one. This will make your Git history more informative, and developers will understand the changes in the Git log faster.

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to rename a file in Vim

    There are many ways to rename a file in Vim. Here's three.

    How to remove trailing whitespaces from all files in a folder

    Here's a shell command to trim all the trailing whitespaces in all the files of the current folder.

    How to make the View to ViewModel relationship clear

    Using Swift's nested types helps making it clear that a view model belongs to a view.

    Dependency Injection in SwiftUI

    This post shows two ways of achieving dependency injection in SwiftUI: using @EnvironmentObject or a View Model Factory.

    What can a pipe wrench teach us about software engineering?

    With his famous pipe wrench lecture, Vannevar Bush taught young MIT engineers the value of precision. The same teaching holds true for software developers.

    Hyperfocus by Chris Bailey

    Hyperfocus will teach you how to concentrate effectively and let your mind wander to reach creative insights.

    You Don't Need It Yet

    YDNIY is a purposeful restraint of what you decide to build in the interest of delivering value to the users as soon as possible and consistently.

    "That's funny…" moments are learning opportunities

    The most exciting phrase to hear in science, and software development, the one that heralds new discoveries, is not "Eureka!" but "That's funny…"

    Will iOS 14 Destroy Your Productivity?

    iOS 14 introduces Widgets, a feature that makes it incredibly easy to get distracted.

    Replace Triple-state Boolean with Enumeration

    Triple-state Booleans can be ambiguous to work with. Replace them with an enum to make the code clearer.

    How to decouple unit tests from values that change frequently

    When the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.

    How to add co-authors to a Git commit

    How to check if macOS app is notarized

    How to reverse a file in the terminal

    How to verify your SSH private key password

    How to check if array contains element with block in Ruby

    Honesty-Oriented Programming

    If you focus on writing honest code, you'll end up with software that is easier to understand and work with.

    Referential Transparency in Swift

    An explanation of what referential transparency means with examples in Swift

    Should you change your branch name to "main"?

    In Xcode 12, the default branch name is main instead of master. This little language change has deeper implications and stirred up an hornets' nest.

    The Indistractable Developer

    The quality of your focus time is directly proportional to your value in the market. Become Indistractable to maximize it.

    How to use CocoaPods as a CLI tools manager

    CocoaPods can be configured to only resolve and download dependencies, making it a great manager for vendored CLI tools

    How to manually generate Devise reset password link

    Midwives with the Apple Watch

    How to use social media productively

    Social media can be a valuable source of news and interactions, or a disruption to our focus. The difference is in how we approach using these technologies.

    How to run a single test in Xcode

    A collection of ways to run a single test or a subset of tests using Xcode.

    How to test view controllers navigation

    The answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.

    Take care of your tools

    "You take care of your tools, your tools take care of you."

    Code Like A Chef

    Professional chefs keep their benches clean because clutter will get in the way of their work. Software developers should do the same.

    Top 10 Productivity Books

    A running list of the top 10 most impactful books on productivity I've encountered so far

    Why I'm cutting back on podcasts and audiobooks

    I realized I was on a path to remove time for reflection from my life, mainly by filling every available moment with podcasts and audiobooks. These are the steps I'm taking to cultivate more solitude, and the benefits I'm already seeing.

    Better tests for delegates

    When testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.

    3 Lessons on Software Development from the New England Patriots

    By looking at how the consistently successful New England Patriots operate we can learn useful lessons to apply to our job as software developers.

    The value of decluttering and optimizing your software

    Digital minimalists believe that clutter is costly and optimization is important. Let me show you how these ideas apply to software development as well.

    Code Coverage Is A Broken Metric

    But you should track it anyways.

    Write Less Code

    The best thing you can do as a software developer is not writing code, but removing it. Here's why.

    How to TDD in Swift, a step by step guide

    With test driven development you can write high quality software in small shippable steps. Here's how to get started.

    The Productivity Project - by Chris Bailey

    My notes and quotes from The Productivity Project by Chris Bailey

    Test doubles in Swift: dummies, fakes, stubs, and spies.

    An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.

    How to become drastically faster at using the terminal

    Using the terminal might seem slow and cumbersome because every command needs to be typed. Learn how to drastically reduce the amount of typing you have to do by configuring aliases for your most used commands, making them only a few keystrokes long.

    How to split decision and action logic with the Swift type system

    There is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.

    How to remove duplication from Swift tests with helper functions

    Some code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.

    Stephen King's Advice To Software Developers

    In "On Writing" Stephen King shares invaluable lessons for aspiring novelists which can be applied to software development too.

    Where to start to become more productive

    What does it take to be productive? What does it event mean? Here's a introduction to the pillars of productivity, with many resources to start from.

    How to write code faster using snippets

    Leveraging "snippets" is a way to get faster at writing code and free mental resources for problem solving. Most IDEs and text editor offer this feature, where you can write code scaffolding with a keyboard shortcut.

    Streamlining tests setup with fixtures in Swift

    Keeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readable

    Invest in your terminal to become a better developer

    One of the best things you could do to improve as a software developer is constantly investing in your terminal setup and skills.

    What software developers can learn from Leonardo da Vinci

    Leonardo da Vinci's life as told by Walter Isaacson in his biography is a source of inspiration for anyone working in a technical and creative field.

    Red, green, and don't forget refactor

    Test driven development works at its best when you refactor as you go. Write the failing test, write just enough code to make it pass, then and only then focus on making that code good.

    Action focused protocols enhance testability

    Using protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testability

    How to choose what to refactor

    A way to identify the areas of code to refactor with the highest return of investment using the "focusing question" technique.

    How to get better at setting priorities

    The focusing question, a tool devised by Gray W. Keller, is a simple yet effective way to identify work to focus on with the highest return of investment.

    If you're not writing tests first you're missing out

    A look at the benefits of writing unit tests before production code, in other words TDD.

    "Does Software Understand Complexity?" via Michael Feathers

    Thoughts on a Michael Feathers post on how the understanding of complexity in software development compares to other fields.

    Apps and Tools

    A list of the apps and tools I use everyday and help me getting stuff done.

    4 books to kick start 2018

    Books suggestions to start 2018 with the right mindset and tools.

    Symbolic links in Git

    Here's how to track symbolic liks in a Git repository, in a way suitable for teams.

    Quick beforeSuite and afterSuite behaviour

    A look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using them

    Quick beforeEach and afterEach behaviour

    A look at how nested beforeEach and afterEach behave in the Quick testing framework.

    Nimble: when to use waitUntil or toEventually

    The Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.

    Unless.swift

    Porting Ruby's unless operator into Swift via a function.

    XCTest closure based expectations

    Testing async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.

    How to use dependency injection for classes in Swift

    In Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.

    Lessons learned working on danger-switlint selective linting

    A little post to share some things I learnt while working on a PR for danger-swiftlint to allow selective linting.

    Your Git Log Should Tell A Story

    A look at the practical benefits of writing descriptive commits

    Better Xcode Run Script Build Phases

    Practical tips to write "Run Script" build phases in Xcode.

    Setting Up Firebase Without Using CocoaPods

    A guide on how to configure your Xcode project to use Google Firebase without using CocoaPods.

    Implicitly vs Force Unwrapping Swift Optionals

    A look at what implicitly unwrapping and force unwrap a Swift Optional mean, and how they differ from each other.

    Cloud 66 Postfix Deploy Hook

    A deploy hook to configure Postfix every time a Cloud 66 stack is built

    Why Implicitly Unwrapping Swift Optionals Is Dangerous

    A look at what implicitly unwrapping an Optional value means and why it should be avoided.

    Swift Either enum

    This post introduces the Either type and shows a practical application of it in Swift, injecting extra cells in a table view.

    Strong Opinions Loosely Held

    Strong opinions loosely held, and other cornerstones for a winning mindset

    Writing your own Swift "if let"

    An exercise to understand Swift's optional type: reimplementing the if let functionality

    What is an optional value in Swift

    This post looks into one of Swift's most powerful feature: optionals

    Maintaining Sanity with Multiple Versions of Xcode

    Working with Xcode and Xcode-beta on the same machine can sometimes be confusing, this post shares some tools to help make it less so.

    How to make Swift methods unavailable

    A quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.

    Functional Core Reactive Shell

    This is a blogpost version of the content of my talk "Functional Core, Reactive Shell"

    Language Agnostic Automation Setup

    Every project can benefit from having a set of scripts to automate tasks such as running tests or distributing to testers. When setting up automation for your projects you can use a language agnostic setup. This will make it easier for new team members to get started, and allow you to change the setup without having to change the way the scripts are invoked.

    NSDateFormatter format for JSON dates

    How to configure NSDateFormatter to work with JSON API dates.

    "Functional Core, Reactive Shell" Resources

    Links from my "Functional Core, Reactive Shell" talk

    Getting Started With Automation

    A collection of tips to get you started with workflow automation, increase productivity, and save time.

    Using Swift protocols to abstract third party dependencies and improve testability

    Third party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testability

    How to update all plug-ins for the latest version of Xcode and Xcode-beta

    An handy script to update all Xcode plug-ins to be compatible with the latest version of Xcode and Xcode-beta.

    Getting Started With OHHTTPStubs

    Good unit tests are fast and deterministic. Testing code that hits the network could undermine this goal, but using OHHTTPStubs we can take back control of our tests. This post explores the advantages of stubbing the network, and provide a guide on how to do it with OHHTTPStubs.

    Why hitting the network is bad for your test, and what to do about it

    In this post we are going to look at why hitting the network from your unit tests is a bad thing, and introduce some way to solve the problem.

    Ruby for iOS Developers - Managing Ruby Tools with Bundler

    Between CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. How can we reliably control the versions of the tools our project's automation is using in Ruby? Bundler is a simple way to specify Ruby dependencies and automate their setup.

    Ruby for iOS Developers - Managing Ruby Versions

    Between CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. Managing versions and gems can be a challenge for developers outside of the Ruby community, but it doesn't have to be. In this two parts post we will see how to simply and reliably handle our Rubies.

    How To Fix Fabric Crashing On Startup When Installed Via CocoaPods

    If you are experiencing crashes with a version of Fabric and Crashlytics installed via CocoaPods chances are you are missing required information in the Info.plist. This post shows how to solve this issue.

    Async Testing with Quick and Nimble

    A look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.

    Testing Delegates in Swift with XCTest

    In this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.

    Testing callbacks in Swift with XCTest

    Prevent Unit Tests from Loading AppDelegate in Swift

    How to prevent the unit test target from loading the AppDelegate and have faster tests execution.

    How to use a double slash in xcconfig files

    A short post showing how to use a double slash in xcconfig files, for example to write URLs like https://mokacoding.com

    2015 Retrospective

    A retrospective on my consulting business in 2015. What when well, what didn't and how to act on it, how to move forward in 2016. I think my personal experience could be valuable for every iOS freelancer, I have done a couple of things right that helped my business a lot.

    Opening a PR to Bitbucket from the terminal

    A simple script you can run to open a PR on BitBucket for your current branch.

    How to update an Xcode plug-in for the latest version of Xcode

    A simple command to run in your terminal to make sure you can use your favourite plugins on the latest version of Xcode

    Hacker News Button

    How to add an Hacker News button to your blog

    Installing Xcode plugins from the terminal with Fastlane

    How to install Xcode plugins from the terminal using Fastlane, and persist them across machines.

    Injecting environment variables from a file with xargs

    How to provide environment variables stored in a .env file as an input for a command execution without having to export then, with a deep look at the shell commands used.

    How to configure Travis CI for iOS testing

    A practical guide on how to configure Travis CI to run iOS, and OS X, tests.

    How to use Homebrew in CI

    A quick guide on how to safely use Homebrew in CI.

    How to configure CircleCI for iOS testing

    A practical guide on how to configure CircleCI for to run iOS, and OS X, tests.

    Fixing Bugs Driven By Tests in Swift

    Unit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.

    How To Sharpen Your Software Developer Tools

    Practical advices on how to keep your tools sharp, master them, and become more productive.

    Xcodebuild Destination Cheatsheet

    A collection of tips on how to configure the -destination option for the xcodebuild tool.

    The best free RSS reader app ever: IFTTT + Pocket

    By using the powerful automation provided by IFTTT we can make deliver the latest posts of your favourite blogs to Pocket. This is the most powerful RSS reader ever, and it is free.

    When to use map, flatMap, or for loops in Swift

    Swift allows us to natively iterate over arrays using map. Map could be used to replace every for loop in your code, but that's not a great idea. Map and for have different purposes and should be used appropriately

    How to display relative line numbers in NERDTree

    Vim's relative line numbers are great for jumpin around files, and once you get used to them you want to enable them everywhere. Here's how to have NERDTree use relative line numbers

    Automated Xcode version and build numbering via Git

    How to configure Xcode to automatically set the version and build number of your projects using Git.

    How to always use the latest Simulator with Xcodebuild

    There is a simple keyword you can use in the destination option of an xcodebuild command to always run the most recent Simulator version.

    Swift Optionals, Functional Programming, and You

    This is the post version of a talk I've been given in the past months. In this post we will demystify functional programming terms like monad and functor, and see how those concepts can be brought back to the every day Swift development, in particular how they can help to deal with optionals in a leaner way.

    An even lighter way to use Carthage

    Among the options Carthage, an iOS and OS X dependency manager, provides there is the --no-build one. Using this we can integrate dependencies in the form of Xcode projects rather than frameworks, keeping the repository slimmer and the CI time low. This approach is lighter than than the usual way to work with Carthage, but comes with some disadvantages too.

    How to install Xcode Command Line Tools without GUI or Xcode

    Here's a little script that will allow you to install the Xcode Command Line Tools without having to install Xcode, nor having a logged GUI. This can come pretty handy in automated scripts or when provisioning virtual machines.

    /dev/world/2015 notes of a testing fanboy

    I attended /dev/world/2015 in Melbourne this week. It has been a great conference, full of very friendly and smart people. Being a test and automation fanboy I attended as many talks related to that topic as I could. These are my notes.

    Enhancing XCTest test cases with Nimble matchers

    Nimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.

    AFNetworking custom response serializer to add error information

    How to implement a custom AFNetworking response serializer to read the failure response data and populate the callback error with it.

    Explicit Dependencies, Swift Edition

    A look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.

    How to have multiple iTunes Connect accounts, and submit apps

    Swift array of characters from String

    How to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].

    Explicit Dependencies for Code with No Surprises

    Sometimes the idea we get when reading a class interface is different from what is actually going on inside its implementation, for example there could be several hidden dependencies. Making a class dependency explicit in its interface is a useful technique to make the code simpler to understand, and easier to test.

    How to reuse the last parameter in a terminal command

    When typing a shell command it is possible to reuse the last argument of the previous call without having to type it. Let's see how.

    Keep Your Bench Clean

    Like good chefs keep their benches clean to make delicious dishes all day long in the restaurants' kitchens, so good developer keep their codebase clean. It all comes down to little habits, the result of which when summed up together is a tidy, clean and easy to maintain software.

    Packaging an ipa with Swift files from the terminal

    If you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.

    How to test UI changes in Xcode 7

    One of the characteristic of the UI is that it changes, and there are scenarios in which writing UI tests to assure that the change has happened correctly can be very valuable for the reliability of our apps. Writing such a test is a bit harder than normal, let's see how to do it.

    How to add testing dependencies using Carthage, with Swift 2 and Xcode 7

    In this little tutorial we will see how to use Cathage, an OS X and iOS depencendy manager, to install libraries written in Swift 2 and Xcode 7, with a focus on the process to get testing dependencies.

    Swift Functors, Applicatives, and Monads in Pictures

    In this port to Swift of the great of Haskell's "Functors, Applicatives, And Monads In Pictures" we are going to look at these functional programming concepts aided by some very helpful pictures.

    XVim, harnessing the king of text editor's power in Xcode

    An introduction to the XVim plugin, that adds most Vim keybindings and features to the Xcode IDE, and how this can make you more productive as a developer.

    Testing Realm apps

    Realm is a mobile database that, unlike CoreData, is easy to test. In this post we will discuss some ideas on how to test an app using Realm as its database.

    The value of acceptance testing for mobile projects

    Companion blogpost for Gio's talk "Talking myself into the value of acceptance testing" at Melbourne CocoaHeads meetup

    Xcode 7 UI testing, a first look

    How to get started with UI testing in Xcode 7, recording tests and using the new APIs to assert the state of the application under test.

    MailChimp automated workflow for mokacoding weekly

    At mokacoding we're big on automation, and we eat our own dog's food! The workflow to write and send new issues of our newsletter, mokacoding weekly, is (partially) automated thanks to some simple Ruby scripting and Mac command line utilities.

    Automation with pre-commit hooks

    Git provides a mechanism to run one or more scripts before a commit is actually added to the history called pre-commit hook. We can use this hook to run scripts that validate or sanitise the changes to be committed automatically, saving time and brain power, and assuring the quality of the codbase and git log.

    xUnique: a tool to avoid Xcode project merge conflicts

    How many times when working on a Mac OSX or iOS app with a team have you had a merge conflict on the project.pbxproj file? I guess more than a few, a lot more than a few. Lucky for you there is an handy tool called xUnique that will make the chances of this happening way smaller.

    Writing an Expecta custom matcher

    Not only Expecta is a simple to use library that allows us to write highly readable code, but it can also be extended by the users with custom matchers. Let's see how to write a custom matcher to gain readability and reuse code in our test suites.

    Expecta, a matcher library that speaks English

    A test that express is intent clearly is arguably twice as effective as one that doesn't. Writing test in an xSpec style is a good first step to express behaviour clearly, and when matched with a matcher library such as Expecta the results are test that are easy to read and reason about

    Specta global before and after each hooks (Updated)

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them. Updated for version 0.5

    Job stories acceptance tests using KIF and Specta

    When writing tests it's very important do be declarative, aiming to have tests that explain how a class is supposed to behave as good as its documentation would do. When talking about acceptance tests we can achieve this kind of clarity by having a 1:1 relationship between the tests and the acceptance criteria for the application. A very effective way to express acceptance criteria is through _job stories_. In this post we'll see how to write acceptance tests that map job stories for our iOS apps, using KIF and Specta.

    Better tests with Specta

    Writing unit tests for our iOS and OS X projects not only is important, but should be always part of the development cycle. As such the way we write the tests is as important, and having the option to write tests that easily explain their purpose can drastically increase the quality of the suite. Specta and Expecta are two libraries that provide a different way to writing tests than XCTest, let's see what we can gain by using such approach.

    Xcode keyboard shortcuts for testing

    Keyboard shortcuts are easies way to start increasing your productivity. Let's look at how to run tests in Xcode without ever touching the mouse.

    Setting up KIF for iOS acceptance testing

    A guide on install and use the KIF framework for iOS acceptance testing.

    The state of iOS testing in 2015

    In this post we'll look at the main tools and libraries available to write unit and acceptance tests for iOS and OS X applications, as well as the solutions to host Continuous Integration for our projects.

    Specta global before and after each hooks

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them.

    How to run Xcode tests from the terminal

    How to invoke xcodebuild to run the tests from the command line and how to format its output using xcbeautify or xcpretty

    How to simplify Calabash acceptance testing with Rake

    Rake, the Ruby build utility, can lift off all the typing involved in running the Cucumber/Calabash acceptance tests, saving us a lot of typing time.

    Git-iquette

    Every team and every project should have a Git-iquette: a set of common practices for managing the git repository.

    Setting up Calabash for iOS projects with Cocoapods and Build Configurations

    A simple guide that shows the simplest way to install Calabash on an iOS project, by using Build Configurations and CocoaPods.

    5 habits that will make you a better software developer

    By implementing these 5 small habits you'll kickstart your 2015 and become a better software developer.

    Security Tips for Freelance Software Developers

    Tips for freelance software developers (and non) to improve the security of laptops, smartphones and website accounts, to keep your and your clients data safe.

    Why I don't work on Fridays

    Some time ago I learned the hard way that I shouldn't work on Fridays. I've been applying an alternative schedule to my week, and it's working out pretty well.

    In-App Purchase Debugging Lessons

    A couple of tips learnt the hard way on how to develop and debug In App Purchase support in an iOS app.

    Why I (shouldn't have) stopped blogging with Jekyll

    I recently decided to move my blog from Ruby and Jekyll, to Metalsmith and Javascript. It turned out to be not as easy as I thought, and a quite stupid choice, but not because of the tech.

    CocoaPods and custom Build Configurations

    Some tips on how to use CocoaPods and customs build configurations without headaches.

    2014 resolutions review

    Gradient Backgrounds Studio: Lessons Learned

    A caveat when upgrading a Podfile

    Sharing assets across iOS projects with CocoaPods, Resource Bundle, and dynamically loaded fonts

    Automating iOS Enterprise Deployment with shenzhen

    A way of automating the deployment of an iOS app for enterprise distribution using the shenzhen gem.

    2013 retrospectives... and 2014 propositions

    Taking a look back at 2013, to find good propositions for 2014

    Podcasts, grow your brain through soundwaves

    A list of the tech podcasts I follow

    Rails: adding a new has_many association to an existing model

    A little guide on how to edit an existing model adding a new has_many association

    Some things I learned in October

    A quick summary and memo of interesting things I've learned in October - iOS screen capture, HTML5 game development, ways to improve your coding.

    A dive into Xcode projects and workspaces

    A look at how Xcode stores information about the project and the workspace

    October's Questions

    Introducing mokagio's monthly questions, related to iOS, Objective-C, Xcode, xctool, AFNetworking, CocoaPods.

    Some things I learned in September

    A quick summary and memo of interesting things I've learned in September

    Sharing some thoughts on iOS 7

    Sharing thoughts by some lead designers on iOS 7.

    Setting a Mac for Development

    A simple checklist of the basic tools to setup a Mac for development.

    Bringing font icons in iOS with MTFontIcon

    Introducing MTFontIcon, a CocoaPod library for iOS to improve application development efficiency by using font icons.

    A workaround to Xcode 5 GM crash on app submission

    A workaround for the unusual crash of Xcode 5 GM during the App Store submission process.

    Some things I learned in August

    Some things I learned in July

    A summary of the things I learned in July 2013.

    What I did in a week...

    A recap of what I developed during an unusual week left by myself without neither girlfriend nor friends.

    A week of time...

    A declaration of purposes for what I'm gonna do in the next week.

    CocoaPods: the $(inherited) flag

    A self memo on how to set the $(inherited) flag on a project using CocoaPods on Xcode.

    Some things I learned in June

    A summary of the things I learned in June 2013.

    mokagio's self memo for Facebook Integration on iOS - Part 1

    Step by step guide on how to integrate the Facebook SDK in an iOS app, the right way. Part 1: Facebook Login.

    OSX, a scanner, and the drivers drama

    The link to the Samsung Printer Drivers, enclosed in a ranting post.

    Multiple builds of the same app and TestFlight

    How to distribute multiple builds of your iOS app, such as stable, QA and development builds, via TestFlight.

    CocoaPods - How to create your own Pod

    A step by step guide to create a basic CocoaPod.

    CocoaPods!

    A brief introduction to CocoaPods, the Objective-C dependencies manager.

    mokacoding

    unit and acceptance testing, automation, productivity

    How to write unit tests for SwiftUI apps

    How do you write unit tests for a SwiftUI application?

    -

    SwiftUI, with its declarative approach to UI development and its opaque types, doesn't lend itself to writing unit tests. -Are UI and snapshot tests our only option? -Should we generate multiple Previews for every behavior permutation of our views?

    -

    The answer is simpler and doesn't require any extra tool, only good software design:

    -

    To test SwiftUI applications, don't test SwiftUI code.

    -

    Let me show you how to write unit tests for the actual logic behind a SwiftUI app by decoupling layout declaration from content generation.

    -

    The template Xcode uses to generate a SwiftUI app for us includes a View printing the classic "Hello, world!" message.

    -
    import SwiftUI
    -
    -struct ContentView: View {
    -    var body: some View {
    -        Text("Hello, world!")
    -            .padding()
    -    }
    -}
    -
    -struct ContentView_Previews: PreviewProvider {
    -    static var previews: some View {
    -        ContentView()
    -    }
    -}
    -

    Let's make it a bit more interesting by adding a subject. -The app should say "Hello, <user>!" when given a user and fallback to "Hello, world!" otherwise.

    -

    Quick & dirty implementation: All in the view

    -

    Given the template code, a natural approach to implement this new behavior would be to write the code inline in the ContentView body and use different Previews to verify the behavior.

    -
    struct ContentView: View {
    -
    -    let userName: String?
    -
    -    var body: some View {
    -        if let userName = userName {
    -            Text("Hello, \(userName)!").padding()
    -        } else {
    -            Text("Hello, world!").padding()
    -        }
    -    }
    -}
    -
    -struct ContentView_Previews: PreviewProvider {
    -    static var previews: some View {
    -        ContentView(userName: "Ada")
    -        ContentView(userName: .none)
    -    }
    -}
    -

    This approach gets the job done in a trivial scenario such as this hello world example but doesn't scale well because of two issues.

    -

    From a practical point of view, both our brain and the screen size limit how effective Previews are to verify behavior. -As you can see in the image below, two different previews make the canvas crowded and the details hard to see. -If we were to add more, they'd end up too small to see, and we'd have to zoom in a scroll through the canvas to check all of them.

    -

    image showing the two previews

    -

    Moreover, using Previews relies on our eyes and brain to verify the behavior. -Unfortunately, this biological hardware of ours is slow and bug-ridden. -It is a suboptimal tool to verify the code's behavior.

    -

    There are also software designs considerations. -In a small dumb view like the ContentView from the Xcode template, mixing content generation logic with the layout declaration doesn't affect maintainability that much. -But, as your app grows, mixing layout with content code will make it increasingly difficult to make changes to your views because of the amount of code you'll have to navigate before being able to find what you are looking for.

    -

    SwiftUI views are for declaring layout, not implementing content generation.

    -

    The approach I advocate for is to use automated unit tests to verify the code's behavior. -Automated tests are faster than our eyes and more reliable than our easy to distract brains. -To write a test for the content generation logic, it's necessary to extract it in a way that makes it easier to call. -The need to write tests nudges us towards a design with a better separation of concerns.

    -

    The Test-Driven approach

    -

    As I argue in my book Test-Driven Development in Swift, if you want to add tests to your code, particularly to new code, writing the tests first is the best approach. -Writing tests first puts a helpful pressure on the design, nudging you towards implementations made up of loosely coupled, highly cohesive pieces.

    -

    Let's see how to apply TDD to implementing the new hello world behavior.

    -

    Step 1: Test List

    -

    The first step is to write a Test List, a list of the different behaviors our hello world implementation should have.

    -
    class HelloWorldTests: XCTestCase {
    -
    -    func testHelloWorldWithNoNameReturnsHelloWorld() {}
    -
    -    func testHellowWorldWithNameReturnsHelloUser() {}
    -}
    -
    -

    Writing a Test List instead of jumping headfirst into coding gives us a 30,000 feet view of the work ahead and lets us be strategic with where to start.

    -

    Test-Driven Development aims to maximize learning through fast, continuous feedback. -Each iteration of writing a test, seeing it fail, and finding the code that makes it pass teaches us something about the system we're building.

    -

    With all the scenarios to test in front of you, you can choose the one that can teach you something the fastest.

    -

    Step 2: Test the simplest behavior

    -

    In _Test-Driven Development: By Example, Kent Beck recommends starting with a test you know you can make pass. -By starting from a low-hanging fruit, you can do the work of putting in place the bulk of the coding structure without the overhead of complex behavior implementation.

    -

    In our hello world Test List, I feel like the simplest test to implement is for the fallback behavior because it doesn't require any string interpolation to generate the return value.

    -

    Let's build an empty version of the hello world, just enough to call in the test without the compiler complaining at us, then use it to write the test.

    -
    func hello(name: String?) -> String { "" }
    -
    func testHelloWorldWithNoNameReturnsHelloWorld() {
    -    XCTAssertEqual(hello(name: .none), "Hello, world!")
    -}
    -

    If you run the test now, it will fail:

    -
    XCTAssertEqual failed: ("") is not equal to ("Hello, world!")

    We can make the test pass by returning the value the test expects.

    -
    func hello(name: String?) -> String { "Hello, world!" }
    -

    With the test now passing, we have two options in front of us. -We could refactor the implementation to add a check to return the fallback message only if the input is nil, or leave it untouched and move with the next test.

    -

    I choose to move on with the next test, confident that it will show us when to add extra logic in the implementation.

    -

    Step 3: Test remaining behavior

    -
    func testHellowWorldWithNameReturnsHelloUser() {
    -    XCTAssertEqual(hello(name: "Ada"), "Hello, Ada!")
    -}
    -

    The new tests, unsurprisingly, fails:

    -
    XCTAssertEqual failed: ("Hello, world!") is not equal to ("Hello, Ada!")

    To make it pass, we need to write the conditional logic that inspects the input value.

    -
    func hello(name: String?) -> String {
    -  if let name = name {
    -      return "Hello, \(name)!"
    -  } else {
    -      return "Hello, world!"
    -  }
    -}
    -

    Both tests pass. -Let's pat ourselves on the back, take a deep breath, and ask, "Is there any improvement we can make to the code?"

    -

    Step 4: Refactor

    -

    Unit tests make it easier to change code because they allow you to verify its behavior faster and more thoroughly than running the app manually.

    -

    In fact, at the core of the Test-Driven Development workflow, there is a refactoring step. -First, you write a test, then you make it pass with the first solution that comes to mind, and, finally, you can take a step back and improve your code. -The tests make the refactoring step possible because they give you the confidence to change your code as many times as you like, always knowing they will verify its correct behavior.

    -

    When looking at my implementation, something that catches my eyes is that there's a bit of duplication in the string structure. -Just for fun, let's apply DRY and remove it:

    -
    func hello(name: String?) -> String {
    -    let receiver: String
    -    if let name = name {
    -        receiver = name
    -    } else {
    -        receiver = "world"
    -    }
    -
    -    return "Hello, \(receiver)!"
    -}
    -

    The tests still pass after this change, which shows us it was correct.

    -

    I'm still unhappy with this implementation. -It looks clunky, unnecessarily long.

    -

    The fast feedback loop from the tests makes it cheap to keep experimenting with different code versions.

    -

    Here's the one I settled for:

    -
    func hello(name: String?) -> String {
    -    "Hello, \(name.map { $0 } ?? "world")!"
    -}
    -

    Step 5: Inject in the view

    -

    To finish our work, we need to make the app UI use the new code. -Integrating hello(name:) in the UI merely requires calling it from within ContentView's body.

    -
    -

    Unlike the quick and dirty implementation that didn't rely on tests, we don't need to generate two Previews to verify the conditional hello world behavior because that's already done in the unit tests. -If that seems like a marginal gain, it's only because of how trivial this example is. -Take a moment to picture a real-world application, where you have a combinatorial explosion of possible scenarios to render, and imagine if your only tool to verify them was to manually add and maintain multiple previews. -To me, it's clear how faster and easier to work with delegating the responsibility to verify code's behavior to automated tests is.

    -

    Conclusion

    -

    If all code was as straightforward to test as the hello world algorithm, and if all apps were as simple as the updated template app we worked on in this tutorial, we wouldn't need Test-Driven Development — but our jobs would be pretty dull.

    -

    In this tutorial, I worked with trivial code to give you an end-to-end overview of the TDD workflow and how it fits in SwiftUI application development. -In the real world, you'll be working with much more complex views, need to implement behavior with more facets, and navigate apps made of a multitude of screens. -It's then that Test-Driven Development becomes a productivity multiplier because it will let you work in isolation and verify every change without spinning up the whole application and go through the motions of its UI.

    -

    If you enjoyed this introduction to TDD with SwiftUI, you'll like my book Test-Driven Development in Swift where we build a real-world application using TDD, SwiftUI, and Combine.

    -
    -
    -

    Want more of these posts?

    -

    Subscribe to receive new posts in your inbox.

    -
    -

    - - -
    -
    - -
    - -
    \ No newline at end of file diff --git a/feed.xml b/feed.xml index 16a339c..3a87cb6 100644 --- a/feed.xml +++ b/feed.xml @@ -1 +1 @@ -mokacodingA blog about testing, iOS development, productivity, and blabber about software in general.https://mokacoding.comen-USFri, 13 Aug 2021 21:21:41 GMTFri, 13 Aug 2021 21:21:41 GMTTest-Driven Development in Swift is now availableMy book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.Thu, 15 Jul 2021 00:00:00 GMThttps://mokacoding.com/blog/tdd-in-swift-book-launchhttps://mokacoding.com/blog/tdd-in-swift-book-launchBooksTDDSwiftXCTestWWDC21: What's New in TestingA roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.Thu, 17 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/wwdc21-whats-new-in-testinghttps://mokacoding.com/blog/wwdc21-whats-new-in-testingTestingXCTestSwiftTalksHow to test Swift async/await code with XCTestSwift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.Mon, 07 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-test-async-await-code-in-swifthttps://mokacoding.com/blog/how-to-test-async-await-code-in-swiftXcodeXCTestTestingSwiftHow to write better tests for Swift date comparisonsTesting Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.Fri, 04 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/better-swift-date-compare-testshttps://mokacoding.com/blog/better-swift-date-compare-testsTestingSwiftXCTestOn the benefits of distributed workWorking from home doesn't have to be lonely. Going from remote to distributed can bring massive benefits to employees satisfaction and company productivity.Wed, 26 May 2021 00:00:00 GMThttps://mokacoding.com/blog/distributed-workinghttps://mokacoding.com/blog/distributed-workingDistributedProductivityHow to manage complex inputs in your Swift tests with Scenario BuildersWhen writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.Wed, 28 Apr 2021 20:21:00 GMThttps://mokacoding.com/blog/scenario-builders-in-swifthttps://mokacoding.com/blog/scenario-builders-in-swiftTestingSwiftA World Without SlackHow to establish a workflow that minimizes unscheduled, unstructured communication and maximizes focus and productivity.Mon, 19 Apr 2021 00:00:00 GMThttps://mokacoding.com/blog/a-world-without-slackhttps://mokacoding.com/blog/a-world-without-slackbooksproductivityprocessesA distributed asynchronous release processMy latest post on mobile.blog explores two simple conventions Automattic uses to remove the need for synchronous meetings in their app release process.Sat, 13 Mar 2021 00:00:00 GMThttps://mokacoding.com/blog/distributed-app-release-processhttps://mokacoding.com/blog/distributed-app-release-processDistributedProcessesWorking BackwardsHow working your way backwards from your desired outcome can make you more productive, focused, and motivated.Sat, 06 Mar 2021 00:00:00 GMThttps://mokacoding.com/blog/working-backwardshttps://mokacoding.com/blog/working-backwardsProductivityHow waiting in line can improve your focusEmbrace boredom to train your brain to sustain focus when working on demanding tasksTue, 16 Feb 2021 00:00:00 GMThttps://mokacoding.com/blog/how-waiting-in-line-can-improve-your-focushttps://mokacoding.com/blog/how-waiting-in-line-can-improve-your-focusBooksProductivityUnit Testing Combine Publisher CheatsheetSnippets to test the behavior of Combine Publishers in XCTest ready to copy and paste into XcodeThu, 11 Feb 2021 00:00:00 GMThttps://mokacoding.com/blog/testing-combine-publisher-cheatsheethttps://mokacoding.com/blog/testing-combine-publisher-cheatsheetTestingCombineXcodeXCTestBoring Iterations. Interesting Steps.Camille Fournier encourages us to "Make Boring Plans" and move in small iterations.Sat, 30 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/boring-iterations-interesting-stepshttps://mokacoding.com/blog/boring-iterations-interesting-stepsStrategyTDDHow to migrate from SwiftUI to UIKit App Delegate Life Cycle in XcodeThis free tutorial shows how to migrate an existing app with SwiftUI life cycle to use UIKit App Delegate insteadThu, 21 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-migrate-from-swiftui-to-uikit-life-cyclehttps://mokacoding.com/blog/how-to-migrate-from-swiftui-to-uikit-life-cycleSwiftUIXcodeHow to stick with your New Year resolutionsThe start of a new year is a great time to work on self-improvement, but unless you take the right steps, your New Year resolutions might not stick.Fri, 01 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-stick-with-your-new-year-resolutionshttps://mokacoding.com/blog/how-to-stick-with-your-new-year-resolutionsProductivityHow to set default values in Swift compiler-generated initializersYou can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.Wed, 23 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-set-default-values-in-swift-compiler-generate-inithttps://mokacoding.com/blog/how-to-set-default-values-in-swift-compiler-generate-initSwiftEspressoHow to improve your Test-Driven Development workflow by asking "Do I need this yet?"The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.Thu, 17 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/tdd-and-ydniyhttps://mokacoding.com/blog/tdd-and-ydniyTestingTDDWrite better Swift unit tests with custom XCTest assertionsThe XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.Thu, 10 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/write-better-swift-tests-with-xctest-assertionshttps://mokacoding.com/blog/write-better-swift-tests-with-xctest-assertionsXCTestXcodeSwiftTestingHow to write unit test assertions for Swift Result valuesResult is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.Wed, 02 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-write-tests-for-swift-resulthttps://mokacoding.com/blog/how-to-write-tests-for-swift-resultSwiftTestingXCTestWhen experiments go wrongScientist can learn a lot from failed experiments. To do so, they must be methodical and collect all sorts of information. Softwar developers can learn a lot from failures, too. What are the practicies that can make learning easier?Wed, 25 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/when-experiments-go-wronghttps://mokacoding.com/blog/when-experiments-go-wrongBooksTestingLearningHow to merge pull requests with a commit that improves your Git historyWhen merging a pull request on GitHub, it helps to replace the default merge commit title with the PR title or an equally descriptive one. This will make your Git history more informative, and developers will understand the changes in the Git log faster.Fri, 20 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/better-merging-for-github-pull-requestshttps://mokacoding.com/blog/better-merging-for-github-pull-requestsGitHubGitHow to bypass the SwiftUI App when running unit testsHow to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.Thu, 12 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/prevent-swiftui-app-loading-in-unit-testshttps://mokacoding.com/blog/prevent-swiftui-app-loading-in-unit-testsSwiftSwiftUIXcodeTestingHow to rename a file in VimThere are many ways to rename a file in Vim. Here's three.Fri, 06 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/vim-rename-filehttps://mokacoding.com/blog/vim-rename-fileEspressoVimHow to remove trailing whitespaces from all files in a folderHere's a shell command to trim all the trailing whitespaces in all the files of the current folder.Thu, 05 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/remove-trailing-whitespaces-in-folder-fileshttps://mokacoding.com/blog/remove-trailing-whitespaces-in-folder-filesEspressoTerminalAutomationHow to make the View to ViewModel relationship clearUsing Swift's nested types helps making it clear that a view model belongs to a view.Wed, 04 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/nested-type-view-modelshttps://mokacoding.com/blog/nested-type-view-modelsSwiftSwiftUIDependency Injection in SwiftUIThis post shows two ways of achieving dependency injection in SwiftUI: using @EnvironmentObject or a View Model Factory.Wed, 28 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/swiftui-dependency-injectionhttps://mokacoding.com/blog/swiftui-dependency-injectionWhat can a pipe wrench teach us about software engineering?With his famous pipe wrench lecture, Vannevar Bush taught young MIT engineers the value of precision. The same teaching holds true for software developers.Wed, 21 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/pipe-wrenchhttps://mokacoding.com/blog/pipe-wrenchBooksSoftware DesignSwiftHyperfocus by Chris BaileyHyperfocus will teach you how to concentrate effectively and let your mind wander to reach creative insights.Mon, 12 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/hyperfocus-reviewhttps://mokacoding.com/blog/hyperfocus-reviewProductivityBooksYou Don't Need It YetYDNIY is a purposeful restraint of what you decide to build in the interest of delivering value to the users as soon as possible and consistently.Wed, 07 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/you-dont-need-it-yethttps://mokacoding.com/blog/you-dont-need-it-yetSoftware Design"That's funny…" moments are learning opportunitiesThe most exciting phrase to hear in science, and software development, the one that heralds new discoveries, is not "Eureka!" but "That's funny…"Mon, 28 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/thats-funny-moments-are-learning-opportunitieshttps://mokacoding.com/blog/thats-funny-moments-are-learning-opportunitiesSoftware DesignQuotesWill iOS 14 Destroy Your Productivity?iOS 14 introduces Widgets, a feature that makes it incredibly easy to get distracted.Mon, 21 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/will-ios-14-destroy-your-productivityhttps://mokacoding.com/blog/will-ios-14-destroy-your-productivityProductivityReplace Triple-state Boolean with EnumerationTriple-state Booleans can be ambiguous to work with. Replace them with an enum to make the code clearer.Mon, 14 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/replace-triple-boolean-with-enumhttps://mokacoding.com/blog/replace-triple-boolean-with-enumSwiftHow to decouple unit tests from values that change frequentlyWhen the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.Tue, 01 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-decouple-tests-from-frequently-changing-valueshttps://mokacoding.com/blog/how-to-decouple-tests-from-frequently-changing-valuesSwiftXCTestTestingHow to add co-authors to a Git commitTue, 25 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-add-coauthors-to-a-git-commithttps://mokacoding.com/blog/how-to-add-coauthors-to-a-git-commitEspressoGitGitHubHow to check if macOS app is notarizedMon, 24 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-check-if-app-is-notarizedhttps://mokacoding.com/blog/how-to-check-if-app-is-notarizedEspressoHow to reverse a file in the terminalSat, 22 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-reverse-a-file-in-the-terminalhttps://mokacoding.com/blog/how-to-reverse-a-file-in-the-terminalEspressoHow to verify your SSH private key passwordThu, 20 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-verify-ssh-key-passwordhttps://mokacoding.com/blog/how-to-verify-ssh-key-passwordEspressoHow to check if array contains element with block in RubyTue, 18 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-check-if-ruby-array-contains-elementhttps://mokacoding.com/blog/how-to-check-if-ruby-array-contains-elementRubyEspressoHow to write unit tests for SwiftUI appsTo test SwiftUI applications, don't test SwiftUI code. The SwiftUI framework doesn't lend itself to writing unit tests so don't try to shoehorn views in your test harness. Instead, split layout declaration form content generation logic.Wed, 12 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-test-swiftui-appshttps://mokacoding.com/blog/how-to-test-swiftui-appsswiftswiftuitestingtddHonesty-Oriented ProgrammingIf you focus on writing honest code, you'll end up with software that is easier to understand and work with.Sun, 12 Jul 2020 15:00:00 GMThttps://mokacoding.com/blog/honesty-oriented-programminghttps://mokacoding.com/blog/honesty-oriented-programmingSoftware DesignReferential Transparency in SwiftAn explanation of what referential transparency means with examples in SwiftSun, 12 Jul 2020 14:00:00 GMThttps://mokacoding.com/blog/referential-transparency-in-swifthttps://mokacoding.com/blog/referential-transparency-in-swiftSwiftShould you change your branch name to "main"?In Xcode 12, the default branch name is main instead of master. This little language change has deeper implications and stirred up an hornets' nest.Wed, 24 Jun 2020 00:00:00 GMThttps://mokacoding.com/blog/main-vs-master-xcode-12https://mokacoding.com/blog/main-vs-master-xcode-12The Indistractable DeveloperThe quality of your focus time is directly proportional to your value in the market. Become Indistractable to maximize it.Wed, 27 May 2020 00:00:00 GMThttps://mokacoding.com/blog/the-indistractable-developerhttps://mokacoding.com/blog/the-indistractable-developerProductivityHow to use CocoaPods as a CLI tools managerCocoaPods can be configured to only resolve and download dependencies, making it a great manager for vendored CLI toolsTue, 17 Mar 2020 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-ci-setuphttps://mokacoding.com/blog/cocoapods-ci-setupiOSCocoaPodsToolingHow to manually generate Devise reset password linkSun, 28 Jul 2019 00:00:00 GMThttps://mokacoding.com/blog/how-to-manually-generate-devise-reset-password-linkhttps://mokacoding.com/blog/how-to-manually-generate-devise-reset-password-linkRuby on RailsRubyMidwives with the Apple WatchMon, 03 Jun 2019 00:00:00 GMThttps://mokacoding.com/blog/midwives-with-the-apple-watchhttps://mokacoding.com/blog/midwives-with-the-apple-watchProductivityDeep WorkHow to use social media productivelySocial media can be a valuable source of news and interactions, or a disruption to our focus. The difference is in how we approach using these technologies.Tue, 30 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/social-media-operating-procedureshttps://mokacoding.com/blog/social-media-operating-proceduresProductivityHow to run a single test in XcodeA collection of ways to run a single test or a subset of tests using Xcode.Tue, 23 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/running-one-test-in-xcodehttps://mokacoding.com/blog/running-one-test-in-xcodeXcodeTestingProductivityHow to test view controllers navigationThe answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.Tue, 16 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/navigation-delegate-patternhttps://mokacoding.com/blog/navigation-delegate-patternSwiftTestingiOSSoftware-DesignTake care of your tools"You take care of your tools, your tools take care of you."Tue, 09 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/take-care-of-your-toolshttps://mokacoding.com/blog/take-care-of-your-toolsProductivityCode Like A ChefProfessional chefs keep their benches clean because clutter will get in the way of their work. Software developers should do the same.Tue, 02 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/code-like-a-chefhttps://mokacoding.com/blog/code-like-a-chefProductivityTop 10 Productivity BooksA running list of the top 10 most impactful books on productivity I've encountered so farTue, 26 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/top-10-productivity-bookshttps://mokacoding.com/blog/top-10-productivity-booksProductivityBooksWhy I'm cutting back on podcasts and audiobooksI realized I was on a path to remove time for reflection from my life, mainly by filling every available moment with podcasts and audiobooks. These are the steps I'm taking to cultivate more solitude, and the benefits I'm already seeing.Tue, 19 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/podcast-addictionhttps://mokacoding.com/blog/podcast-addictionProductivityPodcastsBooksBetter tests for delegatesWhen testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.Tue, 12 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/better-tests-for-delegateshttps://mokacoding.com/blog/better-tests-for-delegatesSwiftTesting3 Lessons on Software Development from the New England PatriotsBy looking at how the consistently successful New England Patriots operate we can learn useful lessons to apply to our job as software developers.Tue, 05 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/3-lessons-from-new-england-patriotshttps://mokacoding.com/blog/3-lessons-from-new-england-patriotsThe value of decluttering and optimizing your softwareDigital minimalists believe that clutter is costly and optimization is important. Let me show you how these ideas apply to software development as well.Tue, 26 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/clutter-and-optimizationhttps://mokacoding.com/blog/clutter-and-optimizationBooksProductivitySoftware DesignCode Coverage Is A Broken MetricBut you should track it anyways.Tue, 19 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/code-coverage-is-brokenhttps://mokacoding.com/blog/code-coverage-is-brokenTestingRefactoringWrite Less CodeThe best thing you can do as a software developer is not writing code, but removing it. Here's why.Wed, 13 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/wirte-less-codehttps://mokacoding.com/blog/wirte-less-codeProductivityRefactoringSoftware DesignHow to TDD in Swift, a step by step guideWith test driven development you can write high quality software in small shippable steps. Here's how to get started.Fri, 08 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/step-by-step-tdd-in-swift-part-1https://mokacoding.com/blog/step-by-step-tdd-in-swift-part-1TDDSwiftThe Productivity Project - by Chris BaileyMy notes and quotes from The Productivity Project by Chris BaileyTue, 29 Jan 2019 00:00:00 GMThttps://mokacoding.com/blog/the-productivity-project-noteshttps://mokacoding.com/blog/the-productivity-project-notesProductivityBooksTest doubles in Swift: dummies, fakes, stubs, and spies.An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.Tue, 27 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/swift-test-doubleshttps://mokacoding.com/blog/swift-test-doublesTestingSwiftHow to become drastically faster at using the terminalUsing the terminal might seem slow and cumbersome because every command needs to be typed. Learn how to drastically reduce the amount of typing you have to do by configuring aliases for your most used commands, making them only a few keystrokes long.Tue, 20 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/terminal-aliaseshttps://mokacoding.com/blog/terminal-aliasesProductivityTerminalHow to split decision and action logic with the Swift type systemThere is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.Tue, 13 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-split-decision-and-action-logic-with-the-swift-type-systemhttps://mokacoding.com/blog/how-to-split-decision-and-action-logic-with-the-swift-type-systemSwiftTestingRefactoringHow to remove duplication from Swift tests with helper functionsSome code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.Tue, 06 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-remove-duplication-from-swift-tests-with-helper-functionshttps://mokacoding.com/blog/how-to-remove-duplication-from-swift-tests-with-helper-functionsTestingXcodeSwiftXCTestStephen King's Advice To Software DevelopersIn "On Writing" Stephen King shares invaluable lessons for aspiring novelists which can be applied to software development too.Tue, 30 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/stephen-king-advice-to-software-developershttps://mokacoding.com/blog/stephen-king-advice-to-software-developersBooksQuotesProductivityWhere to start to become more productiveWhat does it take to be productive? What does it event mean? Here's a introduction to the pillars of productivity, with many resources to start from.Tue, 23 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/where-to-start-to-become-more-productivehttps://mokacoding.com/blog/where-to-start-to-become-more-productiveProductivityHow to write code faster using snippetsLeveraging "snippets" is a way to get faster at writing code and free mental resources for problem solving. Most IDEs and text editor offer this feature, where you can write code scaffolding with a keyboard shortcut.Tue, 16 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-write-code-faster-using-snippetshttps://mokacoding.com/blog/how-to-write-code-faster-using-snippetsProductivityXcodeAutomationStreamlining tests setup with fixtures in SwiftKeeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readableTue, 09 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/streamlining-tests-setup-with-fixtures-in-swifthttps://mokacoding.com/blog/streamlining-tests-setup-with-fixtures-in-swiftTestingSwiftInvest in your terminal to become a better developerOne of the best things you could do to improve as a software developer is constantly investing in your terminal setup and skills.Tue, 02 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/invest-in-your-terminal-to-become-a-better-developerhttps://mokacoding.com/blog/invest-in-your-terminal-to-become-a-better-developerProductivityToolingShellWhat software developers can learn from Leonardo da VinciLeonardo da Vinci's life as told by Walter Isaacson in his biography is a source of inspiration for anyone working in a technical and creative field.Tue, 25 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/what-software-developers-can-learn-from-leonardo-da-vincihttps://mokacoding.com/blog/what-software-developers-can-learn-from-leonardo-da-vinciBooksRed, green, and don't forget refactorTest driven development works at its best when you refactor as you go. Write the failing test, write just enough code to make it pass, then and only then focus on making that code good.Tue, 18 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/red-green-and-dont-forget-refactorhttps://mokacoding.com/blog/red-green-and-dont-forget-refactorTDDAction focused protocols enhance testabilityUsing protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testabilityTue, 11 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/action-focused-protocols-enhance-testabilityhttps://mokacoding.com/blog/action-focused-protocols-enhance-testabilityTestingSwiftHow to choose what to refactorA way to identify the areas of code to refactor with the highest return of investment using the "focusing question" technique.Tue, 04 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-choose-what-to-refactorhttps://mokacoding.com/blog/how-to-choose-what-to-refactorRefactoringBooksProductivityHow to get better at setting prioritiesThe focusing question, a tool devised by Gray W. Keller, is a simple yet effective way to identify work to focus on with the highest return of investment.Sat, 25 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/the-focusing-questionhttps://mokacoding.com/blog/the-focusing-questionIf you're not writing tests first you're missing outA look at the benefits of writing unit tests before production code, in other words TDD.Fri, 17 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/if-youre-not-writing-tests-first-youre-missing-outhttps://mokacoding.com/blog/if-youre-not-writing-tests-first-youre-missing-outTestingTDD"Does Software Understand Complexity?" via Michael FeathersThoughts on a Michael Feathers post on how the understanding of complexity in software development compares to other fields.Sun, 12 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/does-software-understand-complexity-m-feathershttps://mokacoding.com/blog/does-software-understand-complexity-m-feathersApps and ToolsA list of the apps and tools I use everyday and help me getting stuff done.Sat, 28 Jul 2018 00:00:00 GMThttps://mokacoding.com/blog/apps-and-tools-i-usehttps://mokacoding.com/blog/apps-and-tools-i-useApps4 books to kick start 2018Books suggestions to start 2018 with the right mindset and tools.Mon, 01 Jan 2018 00:00:00 GMThttps://mokacoding.com/blog/books-to-start-2018https://mokacoding.com/blog/books-to-start-2018BooksSymbolic links in GitHere's how to track symbolic liks in a Git repository, in a way suitable for teams.Tue, 12 Sep 2017 00:00:00 GMThttps://mokacoding.com/blog/symliks-in-githttps://mokacoding.com/blog/symliks-in-gitEspressoGitQuick beforeSuite and afterSuite behaviourA look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using themThu, 11 May 2017 00:00:00 GMThttps://mokacoding.com/blog/quick-beforesuite-aftersuite-behaviourhttps://mokacoding.com/blog/quick-beforesuite-aftersuite-behaviourQuickEspressoTestingQuick beforeEach and afterEach behaviourA look at how nested beforeEach and afterEach behave in the Quick testing framework.Mon, 08 May 2017 00:00:00 GMThttps://mokacoding.com/blog/quick-beforeeach-aftereach-behaviourhttps://mokacoding.com/blog/quick-beforeeach-aftereach-behaviourQuickEspressoTestingNimble: when to use waitUntil or toEventuallyThe Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.Fri, 05 May 2017 00:00:00 GMThttps://mokacoding.com/blog/waituntil-vs-toeventuallyhttps://mokacoding.com/blog/waituntil-vs-toeventuallyTestingNimbleSwiftUnless.swiftPorting Ruby's unless operator into Swift via a function.Tue, 04 Apr 2017 00:00:00 GMThttps://mokacoding.com/blog/unless-swifthttps://mokacoding.com/blog/unless-swiftSwiftEspressoXCTest closure based expectationsTesting async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.Wed, 22 Mar 2017 00:00:00 GMThttps://mokacoding.com/blog/xctest-closure-based-expectationhttps://mokacoding.com/blog/xctest-closure-based-expectationSwiftXCTestTestingHow to use dependency injection for classes in SwiftIn Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.Wed, 01 Mar 2017 00:00:00 GMThttps://mokacoding.com/blog/dependency-injection-for-classes-in-swifthttps://mokacoding.com/blog/dependency-injection-for-classes-in-swiftSwiftTestingLessons learned working on danger-switlint selective lintingA little post to share some things I learnt while working on a PR for danger-swiftlint to allow selective linting.Thu, 26 Jan 2017 00:00:00 GMThttps://mokacoding.com/blog/lessons-learned-working-on-danger-swiftlint-selective-lintinghttps://mokacoding.com/blog/lessons-learned-working-on-danger-swiftlint-selective-lintingEspressoRubyOpen SourceYour Git Log Should Tell A StoryA look at the practical benefits of writing descriptive commitsMon, 19 Dec 2016 00:00:00 GMThttps://mokacoding.com/blog/your-git-log-should-tell-a-storyhttps://mokacoding.com/blog/your-git-log-should-tell-a-storyGitBetter Xcode Run Script Build PhasesPractical tips to write "Run Script" build phases in Xcode.Mon, 07 Nov 2016 00:00:00 GMThttps://mokacoding.com/blog/better-build-phase-scriptshttps://mokacoding.com/blog/better-build-phase-scriptsXcodeSetting Up Firebase Without Using CocoaPodsA guide on how to configure your Xcode project to use Google Firebase without using CocoaPods.Mon, 15 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/setting-up-firebase-without-cocoapodshttps://mokacoding.com/blog/setting-up-firebase-without-cocoapodsXcodeFirebaseEspressoImplicitly vs Force Unwrapping Swift OptionalsA look at what implicitly unwrapping and force unwrap a Swift Optional mean, and how they differ from each other.Tue, 09 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/impliticly-vs-force-unwrapping-swift-optionalshttps://mokacoding.com/blog/impliticly-vs-force-unwrapping-swift-optionalsSwiftCloud 66 Postfix Deploy HookA deploy hook to configure Postfix every time a Cloud 66 stack is builtMon, 01 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/cloud-66-postfix-deploy-hookhttps://mokacoding.com/blog/cloud-66-postfix-deploy-hookEspressoCloud 66DevOpsWhy Implicitly Unwrapping Swift Optionals Is DangerousA look at what implicitly unwrapping an Optional value means and why it should be avoided.Tue, 26 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/why-implicitly-unwrapping-swift-optionals-is-dangeroushttps://mokacoding.com/blog/why-implicitly-unwrapping-swift-optionals-is-dangerousSwiftSwift Either enumThis post introduces the Either type and shows a practical application of it in Swift, injecting extra cells in a table view.Mon, 18 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/swift-eitherhttps://mokacoding.com/blog/swift-eitherSwiftHaskellStrong Opinions Loosely HeldStrong opinions loosely held, and other cornerstones for a winning mindsetFri, 08 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/strong-opinions-loosely-heldhttps://mokacoding.com/blog/strong-opinions-loosely-heldPodcastsEspressoQuotesWriting your own Swift "if let"An exercise to understand Swift's optional type: reimplementing the if let functionalityThu, 07 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/writing-your-own-swift-if-lethttps://mokacoding.com/blog/writing-your-own-swift-if-letSwiftEspressoWhat is an optional value in SwiftThis post looks into one of Swift's most powerful feature: optionalsThu, 30 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/what-is-an-optional-value-in-swifthttps://mokacoding.com/blog/what-is-an-optional-value-in-swiftSwiftMaintaining Sanity with Multiple Versions of XcodeWorking with Xcode and Xcode-beta on the same machine can sometimes be confusing, this post shares some tools to help make it less so.Mon, 20 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/maintaining-sanity-with-multiple-versions-of-xcodehttps://mokacoding.com/blog/maintaining-sanity-with-multiple-versions-of-xcodeXcodeProductivityHow to make Swift methods unavailableA quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.Tue, 07 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/swift-unavailable-how-tohttps://mokacoding.com/blog/swift-unavailable-how-toSwiftEspressoFunctional Core Reactive ShellThis is a blogpost version of the content of my talk "Functional Core, Reactive Shell"Wed, 01 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/functional-core-reactive-shellhttps://mokacoding.com/blog/functional-core-reactive-shellFunctional ProgrammingFunctional Reactive ProgrammingTalksSwiftSoftware DesignLanguage Agnostic Automation SetupEvery project can benefit from having a set of scripts to automate tasks such as running tests or distributing to testers. When setting up automation for your projects you can use a language agnostic setup. This will make it easier for new team members to get started, and allow you to change the setup without having to change the way the scripts are invoked.Tue, 17 May 2016 00:00:00 GMThttps://mokacoding.com/blog/language-agnostic-automation-setuphttps://mokacoding.com/blog/language-agnostic-automation-setupAutomationContinuous IntegrationProductivityNSDateFormatter format for JSON datesHow to configure NSDateFormatter to work with JSON API dates.Thu, 12 May 2016 00:00:00 GMThttps://mokacoding.com/blog/nsdateformatter-json-datehttps://mokacoding.com/blog/nsdateformatter-json-dateSwiftFoundationJSONEspresso"Functional Core, Reactive Shell" ResourcesLinks from my "Functional Core, Reactive Shell" talkFri, 15 Apr 2016 00:00:00 GMThttps://mokacoding.com/blog/functional-core-reactive-shell-resourceshttps://mokacoding.com/blog/functional-core-reactive-shell-resourcesEspressoTalksGetting Started With AutomationA collection of tips to get you started with workflow automation, increase productivity, and save time.Tue, 29 Mar 2016 00:00:00 GMThttps://mokacoding.com/blog/getting-started-with-automationhttps://mokacoding.com/blog/getting-started-with-automationAutomationUsing Swift protocols to abstract third party dependencies and improve testabilityThird party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testabilityWed, 02 Mar 2016 00:00:00 GMThttps://mokacoding.com/blog/using-swift-protocols-to-improve-testabilityhttps://mokacoding.com/blog/using-swift-protocols-to-improve-testabilitytestingswiftHow to update all plug-ins for the latest version of Xcode and Xcode-betaAn handy script to update all Xcode plug-ins to be compatible with the latest version of Xcode and Xcode-beta.Wed, 24 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/update-all-xcode-plugins-for-latest-versionhttps://mokacoding.com/blog/update-all-xcode-plugins-for-latest-versionEspressoXcodeGetting Started With OHHTTPStubsGood unit tests are fast and deterministic. Testing code that hits the network could undermine this goal, but using OHHTTPStubs we can take back control of our tests. This post explores the advantages of stubbing the network, and provide a guide on how to do it with OHHTTPStubs.Tue, 23 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ohhttpstubshttps://mokacoding.com/blog/ohhttpstubsTestingiOSWhy hitting the network is bad for your test, and what to do about itIn this post we are going to look at why hitting the network from your unit tests is a bad thing, and introduce some way to solve the problem.Tue, 16 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/why-hitting-the-network-is-bad-for-your-testshttps://mokacoding.com/blog/why-hitting-the-network-is-bad-for-your-testsTestingRuby for iOS Developers - Managing Ruby Tools with BundlerBetween CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. How can we reliably control the versions of the tools our project's automation is using in Ruby? Bundler is a simple way to specify Ruby dependencies and automate their setup.Wed, 10 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ruby-for-ios-developers-bundlerhttps://mokacoding.com/blog/ruby-for-ios-developers-bundlerRubyAutomationRuby for iOS Developers - Managing Ruby VersionsBetween CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. Managing versions and gems can be a challenge for developers outside of the Ruby community, but it doesn't have to be. In this two parts post we will see how to simply and reliably handle our Rubies.Tue, 02 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ruby-for-ios-developershttps://mokacoding.com/blog/ruby-for-ios-developersRubyAutomationHow To Fix Fabric Crashing On Startup When Installed Via CocoaPodsIf you are experiencing crashes with a version of Fabric and Crashlytics installed via CocoaPods chances are you are missing required information in the Info.plist. This post shows how to solve this issue.Thu, 28 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/how-to-fix-fabric-startup-crashhttps://mokacoding.com/blog/how-to-fix-fabric-startup-crashEspressoiOSAsync Testing with Quick and NimbleA look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.Wed, 27 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/async-testing-with-quick-and-nimblehttps://mokacoding.com/blog/async-testing-with-quick-and-nimbleSwiftTestingTesting Delegates in Swift with XCTestIn this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.Tue, 19 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/testing-delegates-in-swift-with-xctesthttps://mokacoding.com/blog/testing-delegates-in-swift-with-xctestSwiftTestingXCTestTesting callbacks in Swift with XCTestTue, 12 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/testing-callbacks-in-swift-with-xctesthttps://mokacoding.com/blog/testing-callbacks-in-swift-with-xctestTestingXCTestSwiftPrevent Unit Tests from Loading AppDelegate in SwiftHow to prevent the unit test target from loading the AppDelegate and have faster tests execution.Fri, 08 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/prevent-unit-tests-from-loading-app-delegate-in-swifthttps://mokacoding.com/blog/prevent-unit-tests-from-loading-app-delegate-in-swiftXcodeSwiftTestingHow to use a double slash in xcconfig filesA short post showing how to use a double slash in xcconfig files, for example to write URLs like https://mokacoding.comSat, 02 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/double-slash-xcconfighttps://mokacoding.com/blog/double-slash-xcconfigXcodeEspresso2015 RetrospectiveA retrospective on my consulting business in 2015. What when well, what didn't and how to act on it, how to move forward in 2016. I think my personal experience could be valuable for every iOS freelancer, I have done a couple of things right that helped my business a lot.Wed, 30 Dec 2015 00:00:00 GMThttps://mokacoding.com/blog/2015-retrospectivehttps://mokacoding.com/blog/2015-retrospectiveRetrospectiveOpening a PR to Bitbucket from the terminalA simple script you can run to open a PR on BitBucket for your current branch.Thu, 26 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/bitbucket-pr-from-command-linehttps://mokacoding.com/blog/bitbucket-pr-from-command-lineEspressoAutomationBitBucketHow to update an Xcode plug-in for the latest version of XcodeA simple command to run in your terminal to make sure you can use your favourite plugins on the latest version of XcodeWed, 25 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-plugins-updatehttps://mokacoding.com/blog/xcode-plugins-updateEspressoXcodeHacker News ButtonHow to add an Hacker News button to your blogTue, 24 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/hacker-news-buttonhttps://mokacoding.com/blog/hacker-news-buttonEspressoInstalling Xcode plugins from the terminal with FastlaneHow to install Xcode plugins from the terminal using Fastlane, and persist them across machines.Tue, 17 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/install-xcode-plugin-with-fastlanehttps://mokacoding.com/blog/install-xcode-plugin-with-fastlaneXcodeFastlaneInjecting environment variables from a file with xargsHow to provide environment variables stored in a .env file as an input for a command execution without having to export then, with a deep look at the shell commands used.Fri, 13 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/env-xargshttps://mokacoding.com/blog/env-xargsEspressoShellToolingHow to configure Travis CI for iOS testingA practical guide on how to configure Travis CI to run iOS, and OS X, tests.Tue, 10 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/travis-ci-ios-testinghttps://mokacoding.com/blog/travis-ci-ios-testingContinuous IntegrationTravis CIXcodeHow to use Homebrew in CIA quick guide on how to safely use Homebrew in CI.Wed, 04 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/homebrew-in-ci-scripthttps://mokacoding.com/blog/homebrew-in-ci-scriptContinuous IntegrationHomebrewEspressoHow to configure CircleCI for iOS testingA practical guide on how to configure CircleCI for to run iOS, and OS X, tests.Tue, 03 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/circle-ci-ios-testinghttps://mokacoding.com/blog/circle-ci-ios-testingContinuous IntegrationCircleCIXcodeFixing Bugs Driven By Tests in SwiftUnit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.Wed, 28 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/fixing-bugs-driven-by-tests-in-swifthttps://mokacoding.com/blog/fixing-bugs-driven-by-tests-in-swiftTestingSwiftAcceptance TestingUI TestingHow To Sharpen Your Software Developer ToolsPractical advices on how to keep your tools sharp, master them, and become more productive.Tue, 20 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/tools-sharpeninghttps://mokacoding.com/blog/tools-sharpeningXcodebuild Destination CheatsheetA collection of tips on how to configure the -destination option for the xcodebuild tool.Tue, 13 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/xcodebuild-destination-optionshttps://mokacoding.com/blog/xcodebuild-destination-optionsXcodeThe best free RSS reader app ever: IFTTT + PocketBy using the powerful automation provided by IFTTT we can make deliver the latest posts of your favourite blogs to Pocket. This is the most powerful RSS reader ever, and it is free.Thu, 08 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/ifttt-pocket-rsshttps://mokacoding.com/blog/ifttt-pocket-rssAutomationEspressoWhen to use map, flatMap, or for loops in SwiftSwift allows us to natively iterate over arrays using map. Map could be used to replace every for loop in your code, but that's not a great idea. Map and for have different purposes and should be used appropriatelyMon, 05 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/when-to-use-map-flatmap-forhttps://mokacoding.com/blog/when-to-use-map-flatmap-forSwiftHow to display relative line numbers in NERDTreeVim's relative line numbers are great for jumpin around files, and once you get used to them you want to enable them everywhere. Here's how to have NERDTree use relative line numbersThu, 01 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/NERDTree-relative-numbershttps://mokacoding.com/blog/NERDTree-relative-numbersVimEspressoAutomated Xcode version and build numbering via GitHow to configure Xcode to automatically set the version and build number of your projects using Git.Tue, 29 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/automatic-xcode-versioning-with-githttps://mokacoding.com/blog/automatic-xcode-versioning-with-gitXcodeAutomationProductivityHow to always use the latest Simulator with XcodebuildThere is a simple keyword you can use in the destination option of an xcodebuild command to always run the most recent Simulator version.Fri, 25 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/how-to-always-run-latest-simulator-clihttps://mokacoding.com/blog/how-to-always-run-latest-simulator-cliXcodeAutomationEspressoSwift Optionals, Functional Programming, and YouThis is the post version of a talk I've been given in the past months. In this post we will demystify functional programming terms like monad and functor, and see how those concepts can be brought back to the every day Swift development, in particular how they can help to deal with optionals in a leaner way.Tue, 22 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/demistifying-swift-functorhttps://mokacoding.com/blog/demistifying-swift-functorSwiftFunctional ProgrammingAn even lighter way to use CarthageAmong the options Carthage, an iOS and OS X dependency manager, provides there is the --no-build one. Using this we can integrate dependencies in the form of Xcode projects rather than frameworks, keeping the repository slimmer and the CI time low. This approach is lighter than than the usual way to work with Carthage, but comes with some disadvantages too.Tue, 15 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/carthage-no-buildhttps://mokacoding.com/blog/carthage-no-buildCarthageXcodeHow to install Xcode Command Line Tools without GUI or XcodeHere's a little script that will allow you to install the Xcode Command Line Tools without having to install Xcode, nor having a logged GUI. This can come pretty handy in automated scripts or when provisioning virtual machines.Wed, 09 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/how-to-install-xcode-cli-tools-without-guihttps://mokacoding.com/blog/how-to-install-xcode-cli-tools-without-guiEspressoXcodeAutomation/dev/world/2015 notes of a testing fanboyI attended /dev/world/2015 in Melbourne this week. It has been a great conference, full of very friendly and smart people. Being a test and automation fanboy I attended as many talks related to that topic as I could. These are my notes.Tue, 08 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/devworld2015-notes-of-a-testing-fanboyhttps://mokacoding.com/blog/devworld2015-notes-of-a-testing-fanboyTestingToolingAutomationConferencesEnhancing XCTest test cases with Nimble matchersNimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.Tue, 25 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/xctest-nimblehttps://mokacoding.com/blog/xctest-nimbleSwiftTDDNimbleAFNetworking custom response serializer to add error informationHow to implement a custom AFNetworking response serializer to read the failure response data and populate the callback error with it.Wed, 19 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/custom-afnetworking-response-serializer-for-errorshttps://mokacoding.com/blog/custom-afnetworking-response-serializer-for-errorsEspressoiOSObjective-CExplicit Dependencies, Swift EditionA look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.Tue, 18 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/explicit-dependencies-swifthttps://mokacoding.com/blog/explicit-dependencies-swiftTestingSoftware DesignSwiftHow to have multiple iTunes Connect accounts, and submit appsSat, 15 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/itunes-connect-multiple-accountshttps://mokacoding.com/blog/itunes-connect-multiple-accountsEspressoiTunes ConnectSwift array of characters from StringHow to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].Wed, 12 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/swift-array-string-charactershttps://mokacoding.com/blog/swift-array-string-charactersSwiftEspressoExplicit Dependencies for Code with No SurprisesSometimes the idea we get when reading a class interface is different from what is actually going on inside its implementation, for example there could be several hidden dependencies. Making a class dependency explicit in its interface is a useful technique to make the code simpler to understand, and easier to test.Tue, 11 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/explicit-dependencieshttps://mokacoding.com/blog/explicit-dependenciesTestingObjective-CSoftware-DesignHow to reuse the last parameter in a terminal commandWhen typing a shell command it is possible to reuse the last argument of the previous call without having to type it. Let's see how.Wed, 05 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/terminal-reusing-last-command-parameterhttps://mokacoding.com/blog/terminal-reusing-last-command-parameterShellEspressoKeep Your Bench CleanLike good chefs keep their benches clean to make delicious dishes all day long in the restaurants' kitchens, so good developer keep their codebase clean. It all comes down to little habits, the result of which when summed up together is a tidy, clean and easy to maintain software.Tue, 04 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/keep-your-bench-cleanhttps://mokacoding.com/blog/keep-your-bench-cleanProductivityPackaging an ipa with Swift files from the terminalIf you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.Mon, 03 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/packaging-swift-ipahttps://mokacoding.com/blog/packaging-swift-ipaEspressoSwiftAutomationTestFlightHow to test UI changes in Xcode 7One of the characteristic of the UI is that it changes, and there are scenarios in which writing UI tests to assure that the change has happened correctly can be very valuable for the reliability of our apps. Writing such a test is a bit harder than normal, let's see how to do it.Sat, 25 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-ui-test-view-changeshttps://mokacoding.com/blog/xcode-ui-test-view-changesAcceptance TestingUI TestingiOSHow to add testing dependencies using Carthage, with Swift 2 and Xcode 7In this little tutorial we will see how to use Cathage, an OS X and iOS depencendy manager, to install libraries written in Swift 2 and Xcode 7, with a focus on the process to get testing dependencies.Tue, 21 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/setting-up-testing-libraries-with-carthage-xcode7https://mokacoding.com/blog/setting-up-testing-libraries-with-carthage-xcode7XcodeCarthageToolingSwift Functors, Applicatives, and Monads in PicturesIn this port to Swift of the great of Haskell's "Functors, Applicatives, And Monads In Pictures" we are going to look at these functional programming concepts aided by some very helpful pictures.Tue, 14 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/functor-applicative-monads-in-pictureshttps://mokacoding.com/blog/functor-applicative-monads-in-picturesSwiftFunctional ProgrammingXVim, harnessing the king of text editor's power in XcodeAn introduction to the XVim plugin, that adds most Vim keybindings and features to the Xcode IDE, and how this can make you more productive as a developer.Tue, 07 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/xvimhttps://mokacoding.com/blog/xvimProductivityXcodeTesting Realm appsRealm is a mobile database that, unlike CoreData, is easy to test. In this post we will discuss some ideas on how to test an app using Realm as its database.Tue, 30 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/testing-realm-appshttps://mokacoding.com/blog/testing-realm-appsTestingThe value of acceptance testing for mobile projectsCompanion blogpost for Gio's talk "Talking myself into the value of acceptance testing" at Melbourne CocoaHeads meetupTue, 23 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/the-value-of-acceptance-testinghttps://mokacoding.com/blog/the-value-of-acceptance-testingAcceptance TestingXcode 7 UI testing, a first lookHow to get started with UI testing in Xcode 7, recording tests and using the new APIs to assert the state of the application under test.Tue, 16 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-7-ui-testinghttps://mokacoding.com/blog/xcode-7-ui-testingAcceptance TestingUI TestingXcodeMailChimp automated workflow for mokacoding weeklyAt mokacoding we're big on automation, and we eat our own dog's food! The workflow to write and send new issues of our newsletter, mokacoding weekly, is (partially) automated thanks to some simple Ruby scripting and Mac command line utilities.Tue, 09 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/automating-mokacoding-weeklyhttps://mokacoding.com/blog/automating-mokacoding-weeklyAutomationProductivityAutomation with pre-commit hooksGit provides a mechanism to run one or more scripts before a commit is actually added to the history called pre-commit hook. We can use this hook to run scripts that validate or sanitise the changes to be committed automatically, saving time and brain power, and assuring the quality of the codbase and git log.Wed, 03 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/pre-commit-hookshttps://mokacoding.com/blog/pre-commit-hooksGitAutomationxUnique: a tool to avoid Xcode project merge conflictsHow many times when working on a Mac OSX or iOS app with a team have you had a merge conflict on the project.pbxproj file? I guess more than a few, a lot more than a few. Lucky for you there is an handy tool called xUnique that will make the chances of this happening way smaller.Tue, 12 May 2015 00:00:00 GMThttps://mokacoding.com/blog/xuniquehttps://mokacoding.com/blog/xuniqueXcodeAutomationProductivityWriting an Expecta custom matcherNot only Expecta is a simple to use library that allows us to write highly readable code, but it can also be extended by the users with custom matchers. Let's see how to write a custom matcher to gain readability and reuse code in our test suites.Tue, 05 May 2015 00:00:00 GMThttps://mokacoding.com/blog/expecta-custom-matchershttps://mokacoding.com/blog/expecta-custom-matchersSpectaExpectaExpecta, a matcher library that speaks EnglishA test that express is intent clearly is arguably twice as effective as one that doesn't. Writing test in an xSpec style is a good first step to express behaviour clearly, and when matched with a matcher library such as Expecta the results are test that are easy to read and reason aboutTue, 28 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/expectahttps://mokacoding.com/blog/expectaSpectaExpectaSpecta global before and after each hooks (Updated)An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them. Updated for version 0.5Fri, 24 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/specta-global-before-after-each-updatedhttps://mokacoding.com/blog/specta-global-before-after-each-updatedTestingSpectaJob stories acceptance tests using KIF and SpectaWhen writing tests it's very important do be declarative, aiming to have tests that explain how a class is supposed to behave as good as its documentation would do. When talking about acceptance tests we can achieve this kind of clarity by having a 1:1 relationship between the tests and the acceptance criteria for the application. A very effective way to express acceptance criteria is through _job stories_. In this post we'll see how to write acceptance tests that map job stories for our iOS apps, using KIF and Specta.Tue, 21 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/job-stories-acceptance-tests-with-KIF-and-spectahttps://mokacoding.com/blog/job-stories-acceptance-tests-with-KIF-and-spectaAcceptance TestingKIFSpectaBetter tests with SpectaWriting unit tests for our iOS and OS X projects not only is important, but should be always part of the development cycle. As such the way we write the tests is as important, and having the option to write tests that easily explain their purpose can drastically increase the quality of the suite. Specta and Expecta are two libraries that provide a different way to writing tests than XCTest, let's see what we can gain by using such approach.Tue, 14 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/better-tests-with-spectahttps://mokacoding.com/blog/better-tests-with-spectaTestingSpectaXCTestXcode keyboard shortcuts for testingKeyboard shortcuts are easies way to start increasing your productivity. Let's look at how to run tests in Xcode without ever touching the mouse.Tue, 07 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-testing-shortcutshttps://mokacoding.com/blog/xcode-testing-shortcutsTestingXcodeProductivitySetting up KIF for iOS acceptance testingA guide on install and use the KIF framework for iOS acceptance testing.Tue, 31 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/setting-up-KIF-for-ios-acceptance-testinghttps://mokacoding.com/blog/setting-up-KIF-for-ios-acceptance-testingAcceptance TestingKIFThe state of iOS testing in 2015In this post we'll look at the main tools and libraries available to write unit and acceptance tests for iOS and OS X applications, as well as the solutions to host Continuous Integration for our projects.Tue, 24 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/ios-testing-in-2015https://mokacoding.com/blog/ios-testing-in-2015TestingAcceptance TestingContinuous IntegrationSpecta global before and after each hooksAn interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them.Thu, 19 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/specta-global-before-after-eachhttps://mokacoding.com/blog/specta-global-before-after-eachTestingSpectaHow to run Xcode tests from the terminalHow to invoke xcodebuild to run the tests from the command line and how to format its output using xcbeautify or xcprettyMon, 09 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/running-tests-from-the-terminalhttps://mokacoding.com/blog/running-tests-from-the-terminalTestingXcodeTerminalAutomationHow to simplify Calabash acceptance testing with RakeRake, the Ruby build utility, can lift off all the typing involved in running the Cucumber/Calabash acceptance tests, saving us a lot of typing time.Wed, 25 Feb 2015 00:00:00 GMThttps://mokacoding.com/blog/simpler-calabash-testing-with-rakehttps://mokacoding.com/blog/simpler-calabash-testing-with-rakeAcceptance TestingCalabashProductivityGit-iquetteEvery team and every project should have a Git-iquette: a set of common practices for managing the git repository.Sun, 15 Feb 2015 00:00:00 GMThttps://mokacoding.com/blog/gitiquettehttps://mokacoding.com/blog/gitiquetteGitSetting up Calabash for iOS projects with Cocoapods and Build ConfigurationsA simple guide that shows the simplest way to install Calabash on an iOS project, by using Build Configurations and CocoaPods.Sun, 25 Jan 2015 00:00:00 GMThttps://mokacoding.com/blog/calabash-ios-with-cocoapods-and-build-configurationshttps://mokacoding.com/blog/calabash-ios-with-cocoapods-and-build-configurationsAcceptance TestingCalabash5 habits that will make you a better software developerBy implementing these 5 small habits you'll kickstart your 2015 and become a better software developer.Wed, 07 Jan 2015 00:00:00 GMThttps://mokacoding.com/blog/5-habits-that-will-make-you-a-better-software-developerhttps://mokacoding.com/blog/5-habits-that-will-make-you-a-better-software-developerProductivitySecurity Tips for Freelance Software DevelopersTips for freelance software developers (and non) to improve the security of laptops, smartphones and website accounts, to keep your and your clients data safe.Wed, 29 Oct 2014 00:00:00 GMThttps://mokacoding.com/blog/security-tips-for-freelance-software-developershttps://mokacoding.com/blog/security-tips-for-freelance-software-developersWhy I don't work on FridaysSome time ago I learned the hard way that I shouldn't work on Fridays. I've been applying an alternative schedule to my week, and it's working out pretty well.Fri, 29 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/why-i-dont-work-on-fridayhttps://mokacoding.com/blog/why-i-dont-work-on-fridayProductivityIn-App Purchase Debugging LessonsA couple of tips learnt the hard way on how to develop and debug In App Purchase support in an iOS app.Tue, 26 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/in-app-purchase-debugging-lessonshttps://mokacoding.com/blog/in-app-purchase-debugging-lessonsiOSWhy I (shouldn't have) stopped blogging with JekyllI recently decided to move my blog from Ruby and Jekyll, to Metalsmith and Javascript. It turned out to be not as easy as I thought, and a quite stupid choice, but not because of the tech.Fri, 08 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/why-i-shouldnt-have-stopped-blogging-with-jekyllhttps://mokacoding.com/blog/why-i-shouldnt-have-stopped-blogging-with-jekyllRubyJavascriptCocoaPods and custom Build ConfigurationsSome tips on how to use CocoaPods and customs build configurations without headaches.Wed, 16 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-and-custom-build-configurationshttps://mokacoding.com/blog/cocoapods-and-custom-build-configurationsCocoaPods2014 resolutions reviewWed, 09 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/2014-resolutions-reviewhttps://mokacoding.com/blog/2014-resolutions-reviewGradient Backgrounds Studio: Lessons LearnedThu, 03 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/gradient-backgrounds-studiohttps://mokacoding.com/blog/gradient-backgrounds-studioiOSA caveat when upgrading a PodfileFri, 28 Mar 2014 00:00:00 GMThttps://mokacoding.com/blog/upgrading-podfilehttps://mokacoding.com/blog/upgrading-podfileCocoaPodsSharing assets across iOS projects with CocoaPods, Resource Bundle, and dynamically loaded fontsThu, 13 Feb 2014 00:00:00 GMThttps://mokacoding.com/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fontshttps://mokacoding.com/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fontsiOSCocoaPodsAutomating iOS Enterprise Deployment with shenzhenA way of automating the deployment of an iOS app for enterprise distribution using the shenzhen gem.Mon, 06 Jan 2014 00:00:00 GMThttps://mokacoding.com/blog/automating-ios-enterprise-deploymenthttps://mokacoding.com/blog/automating-ios-enterprise-deploymentAutomation2013 retrospectives... and 2014 propositionsTaking a look back at 2013, to find good propositions for 2014Thu, 02 Jan 2014 00:00:00 GMThttps://mokacoding.com/blog/2013-retrospectives-and-2014-propositionshttps://mokacoding.com/blog/2013-retrospectives-and-2014-propositionsPodcasts, grow your brain through soundwavesA list of the tech podcasts I followWed, 20 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/podcastshttps://mokacoding.com/blog/podcastsRails: adding a new has_many association to an existing modelA little guide on how to edit an existing model adding a new has_many associationWed, 13 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/rails-add-has_many-association-to-existing-modelhttps://mokacoding.com/blog/rails-add-has_many-association-to-existing-modelRubyRuby on RailsSome things I learned in OctoberA quick summary and memo of interesting things I've learned in October - iOS screen capture, HTML5 game development, ways to improve your coding.Tue, 12 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-octoberhttps://mokacoding.com/blog/things-learned-in-octoberLife long learningA dive into Xcode projects and workspacesA look at how Xcode stores information about the project and the workspaceThu, 31 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/Xcode-projects-and-workspaceshttps://mokacoding.com/blog/Xcode-projects-and-workspacesXcodeOctober's QuestionsIntroducing mokagio's monthly questions, related to iOS, Objective-C, Xcode, xctool, AFNetworking, CocoaPods.Sun, 06 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/october-questionshttps://mokacoding.com/blog/october-questionsLife long learningSome things I learned in SeptemberA quick summary and memo of interesting things I've learned in SeptemberWed, 02 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-septemberhttps://mokacoding.com/blog/things-learned-in-septemberLife long learningSharing some thoughts on iOS 7Sharing thoughts by some lead designers on iOS 7.Tue, 24 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/ios7-ux-designers-verdicthttps://mokacoding.com/blog/ios7-ux-designers-verdictiOSUXSetting a Mac for DevelopmentA simple checklist of the basic tools to setup a Mac for development.Mon, 23 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/setup-a-dev-machinehttps://mokacoding.com/blog/setup-a-dev-machineOS XBringing font icons in iOS with MTFontIconIntroducing MTFontIcon, a CocoaPod library for iOS to improve application development efficiency by using font icons.Tue, 17 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/mtfonticonhttps://mokacoding.com/blog/mtfonticoniOSObjective-CRubyLayoutCSSOpen SourceA workaround to Xcode 5 GM crash on app submissionA workaround for the unusual crash of Xcode 5 GM during the App Store submission process.Mon, 16 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/xcode5-crash-on-submissionhttps://mokacoding.com/blog/xcode5-crash-on-submissionXcodeSome things I learned in AugustTue, 03 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-augusthttps://mokacoding.com/blog/things-learned-in-augustLife long learningSome things I learned in JulyA summary of the things I learned in July 2013.Thu, 01 Aug 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-julyhttps://mokacoding.com/blog/things-learned-in-julyLife long learningWhat I did in a week...A recap of what I developed during an unusual week left by myself without neither girlfriend nor friends.Fri, 26 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/what-i-did-in-a-weekhttps://mokacoding.com/blog/what-i-did-in-a-weekA week of time...A declaration of purposes for what I'm gonna do in the next week.Wed, 17 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/a-week-of-timehttps://mokacoding.com/blog/a-week-of-timeCocoaPods: the $(inherited) flagA self memo on how to set the $(inherited) flag on a project using CocoaPods on Xcode.Tue, 09 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-the-inherited-flaghttps://mokacoding.com/blog/cocoapods-the-inherited-flagCocoaPodsiOSSome things I learned in JuneA summary of the things I learned in June 2013.Sat, 06 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-junehttps://mokacoding.com/blog/things-learned-in-juneLife long learningmokagio's self memo for Facebook Integration on iOS - Part 1Step by step guide on how to integrate the Facebook SDK in an iOS app, the right way. Part 1: Facebook Login.Tue, 25 Jun 2013 00:00:00 GMThttps://mokacoding.com/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1https://mokacoding.com/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1iOSOSX, a scanner, and the drivers dramaThe link to the Samsung Printer Drivers, enclosed in a ranting post.Tue, 11 Jun 2013 00:00:00 GMThttps://mokacoding.com/blog/osx-a-scanner-and-the-drivers-dramahttps://mokacoding.com/blog/osx-a-scanner-and-the-drivers-dramaOS XMultiple builds of the same app and TestFlightHow to distribute multiple builds of your iOS app, such as stable, QA and development builds, via TestFlight.Wed, 29 May 2013 00:00:00 GMThttps://mokacoding.com/blog/multiple-builds-of-the-same-app-and-testflighthttps://mokacoding.com/blog/multiple-builds-of-the-same-app-and-testflightAutomationTestFlightCocoaPods - How to create your own PodA step by step guide to create a basic CocoaPod.Mon, 21 Jan 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-how-to-create-your-own-podhttps://mokacoding.com/blog/cocoapods-how-to-create-your-own-podCocoaPodsiOSCocoaPods!A brief introduction to CocoaPods, the Objective-C dependencies manager.Sat, 05 Jan 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapodshttps://mokacoding.com/blog/cocoapodsCocoaPodsiOS \ No newline at end of file +mokacodingA blog about testing, iOS development, productivity, and blabber about software in general.https://mokacoding.comen-USSat, 14 Aug 2021 03:16:24 GMTSat, 14 Aug 2021 03:16:24 GMTTest-Driven Development in Swift is now availableMy book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.Thu, 15 Jul 2021 00:00:00 GMThttps://mokacoding.com/blog/tdd-in-swift-book-launchhttps://mokacoding.com/blog/tdd-in-swift-book-launchBooksTDDSwiftXCTestWWDC21: What's New in TestingA roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.Thu, 17 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/wwdc21-whats-new-in-testinghttps://mokacoding.com/blog/wwdc21-whats-new-in-testingTestingXCTestSwiftTalksHow to test Swift async/await code with XCTestSwift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.Mon, 07 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-test-async-await-code-in-swifthttps://mokacoding.com/blog/how-to-test-async-await-code-in-swiftXcodeXCTestTestingSwiftHow to write better tests for Swift date comparisonsTesting Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.Fri, 04 Jun 2021 00:00:00 GMThttps://mokacoding.com/blog/better-swift-date-compare-testshttps://mokacoding.com/blog/better-swift-date-compare-testsTestingSwiftXCTestOn the benefits of distributed workWorking from home doesn't have to be lonely. Going from remote to distributed can bring massive benefits to employees satisfaction and company productivity.Wed, 26 May 2021 00:00:00 GMThttps://mokacoding.com/blog/distributed-workinghttps://mokacoding.com/blog/distributed-workingDistributedProductivityHow to manage complex inputs in your Swift tests with Scenario BuildersWhen writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.Wed, 28 Apr 2021 20:21:00 GMThttps://mokacoding.com/blog/scenario-builders-in-swifthttps://mokacoding.com/blog/scenario-builders-in-swiftTestingSwiftA World Without SlackHow to establish a workflow that minimizes unscheduled, unstructured communication and maximizes focus and productivity.Mon, 19 Apr 2021 00:00:00 GMThttps://mokacoding.com/blog/a-world-without-slackhttps://mokacoding.com/blog/a-world-without-slackbooksproductivityprocessesA distributed asynchronous release processMy latest post on mobile.blog explores two simple conventions Automattic uses to remove the need for synchronous meetings in their app release process.Sat, 13 Mar 2021 00:00:00 GMThttps://mokacoding.com/blog/distributed-app-release-processhttps://mokacoding.com/blog/distributed-app-release-processDistributedProcessesWorking BackwardsHow working your way backwards from your desired outcome can make you more productive, focused, and motivated.Sat, 06 Mar 2021 00:00:00 GMThttps://mokacoding.com/blog/working-backwardshttps://mokacoding.com/blog/working-backwardsProductivityHow waiting in line can improve your focusEmbrace boredom to train your brain to sustain focus when working on demanding tasksTue, 16 Feb 2021 00:00:00 GMThttps://mokacoding.com/blog/how-waiting-in-line-can-improve-your-focushttps://mokacoding.com/blog/how-waiting-in-line-can-improve-your-focusBooksProductivityUnit Testing Combine Publisher CheatsheetSnippets to test the behavior of Combine Publishers in XCTest ready to copy and paste into XcodeThu, 11 Feb 2021 00:00:00 GMThttps://mokacoding.com/blog/testing-combine-publisher-cheatsheethttps://mokacoding.com/blog/testing-combine-publisher-cheatsheetTestingCombineXcodeXCTestBoring Iterations. Interesting Steps.Camille Fournier encourages us to "Make Boring Plans" and move in small iterations.Sat, 30 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/boring-iterations-interesting-stepshttps://mokacoding.com/blog/boring-iterations-interesting-stepsStrategyTDDHow to migrate from SwiftUI to UIKit App Delegate Life Cycle in XcodeThis free tutorial shows how to migrate an existing app with SwiftUI life cycle to use UIKit App Delegate insteadThu, 21 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-migrate-from-swiftui-to-uikit-life-cyclehttps://mokacoding.com/blog/how-to-migrate-from-swiftui-to-uikit-life-cycleSwiftUIXcodeHow to stick with your New Year resolutionsThe start of a new year is a great time to work on self-improvement, but unless you take the right steps, your New Year resolutions might not stick.Fri, 01 Jan 2021 00:00:00 GMThttps://mokacoding.com/blog/how-to-stick-with-your-new-year-resolutionshttps://mokacoding.com/blog/how-to-stick-with-your-new-year-resolutionsProductivityHow to set default values in Swift compiler-generated initializersYou can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.Wed, 23 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-set-default-values-in-swift-compiler-generate-inithttps://mokacoding.com/blog/how-to-set-default-values-in-swift-compiler-generate-initSwiftEspressoHow to improve your Test-Driven Development workflow by asking "Do I need this yet?"The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.Thu, 17 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/tdd-and-ydniyhttps://mokacoding.com/blog/tdd-and-ydniyTestingTDDWrite better Swift unit tests with custom XCTest assertionsThe XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.Thu, 10 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/write-better-swift-tests-with-xctest-assertionshttps://mokacoding.com/blog/write-better-swift-tests-with-xctest-assertionsXCTestXcodeSwiftTestingHow to write unit test assertions for Swift Result valuesResult is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.Wed, 02 Dec 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-write-tests-for-swift-resulthttps://mokacoding.com/blog/how-to-write-tests-for-swift-resultSwiftTestingXCTestWhen experiments go wrongScientist can learn a lot from failed experiments. To do so, they must be methodical and collect all sorts of information. Softwar developers can learn a lot from failures, too. What are the practicies that can make learning easier?Wed, 25 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/when-experiments-go-wronghttps://mokacoding.com/blog/when-experiments-go-wrongBooksTestingLearningHow to merge pull requests with a commit that improves your Git historyWhen merging a pull request on GitHub, it helps to replace the default merge commit title with the PR title or an equally descriptive one. This will make your Git history more informative, and developers will understand the changes in the Git log faster.Fri, 20 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/better-merging-for-github-pull-requestshttps://mokacoding.com/blog/better-merging-for-github-pull-requestsGitHubGitHow to bypass the SwiftUI App when running unit testsHow to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.Thu, 12 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/prevent-swiftui-app-loading-in-unit-testshttps://mokacoding.com/blog/prevent-swiftui-app-loading-in-unit-testsSwiftSwiftUIXcodeTestingHow to rename a file in VimThere are many ways to rename a file in Vim. Here's three.Fri, 06 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/vim-rename-filehttps://mokacoding.com/blog/vim-rename-fileEspressoVimHow to remove trailing whitespaces from all files in a folderHere's a shell command to trim all the trailing whitespaces in all the files of the current folder.Thu, 05 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/remove-trailing-whitespaces-in-folder-fileshttps://mokacoding.com/blog/remove-trailing-whitespaces-in-folder-filesEspressoTerminalAutomationHow to make the View to ViewModel relationship clearUsing Swift's nested types helps making it clear that a view model belongs to a view.Wed, 04 Nov 2020 00:00:00 GMThttps://mokacoding.com/blog/nested-type-view-modelshttps://mokacoding.com/blog/nested-type-view-modelsSwiftSwiftUIDependency Injection in SwiftUIThis post shows two ways of achieving dependency injection in SwiftUI: using @EnvironmentObject or a View Model Factory.Wed, 28 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/swiftui-dependency-injectionhttps://mokacoding.com/blog/swiftui-dependency-injectionWhat can a pipe wrench teach us about software engineering?With his famous pipe wrench lecture, Vannevar Bush taught young MIT engineers the value of precision. The same teaching holds true for software developers.Wed, 21 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/pipe-wrenchhttps://mokacoding.com/blog/pipe-wrenchBooksSoftware DesignSwiftHyperfocus by Chris BaileyHyperfocus will teach you how to concentrate effectively and let your mind wander to reach creative insights.Mon, 12 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/hyperfocus-reviewhttps://mokacoding.com/blog/hyperfocus-reviewProductivityBooksYou Don't Need It YetYDNIY is a purposeful restraint of what you decide to build in the interest of delivering value to the users as soon as possible and consistently.Wed, 07 Oct 2020 00:00:00 GMThttps://mokacoding.com/blog/you-dont-need-it-yethttps://mokacoding.com/blog/you-dont-need-it-yetSoftware Design"That's funny…" moments are learning opportunitiesThe most exciting phrase to hear in science, and software development, the one that heralds new discoveries, is not "Eureka!" but "That's funny…"Mon, 28 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/thats-funny-moments-are-learning-opportunitieshttps://mokacoding.com/blog/thats-funny-moments-are-learning-opportunitiesSoftware DesignQuotesWill iOS 14 Destroy Your Productivity?iOS 14 introduces Widgets, a feature that makes it incredibly easy to get distracted.Mon, 21 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/will-ios-14-destroy-your-productivityhttps://mokacoding.com/blog/will-ios-14-destroy-your-productivityProductivityReplace Triple-state Boolean with EnumerationTriple-state Booleans can be ambiguous to work with. Replace them with an enum to make the code clearer.Mon, 14 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/replace-triple-boolean-with-enumhttps://mokacoding.com/blog/replace-triple-boolean-with-enumSwiftHow to decouple unit tests from values that change frequentlyWhen the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.Tue, 01 Sep 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-decouple-tests-from-frequently-changing-valueshttps://mokacoding.com/blog/how-to-decouple-tests-from-frequently-changing-valuesSwiftXCTestTestingHow to add co-authors to a Git commitTue, 25 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-add-coauthors-to-a-git-commithttps://mokacoding.com/blog/how-to-add-coauthors-to-a-git-commitEspressoGitGitHubHow to check if macOS app is notarizedMon, 24 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-check-if-app-is-notarizedhttps://mokacoding.com/blog/how-to-check-if-app-is-notarizedEspressoHow to reverse a file in the terminalSat, 22 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-reverse-a-file-in-the-terminalhttps://mokacoding.com/blog/how-to-reverse-a-file-in-the-terminalEspressoHow to verify your SSH private key passwordThu, 20 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-verify-ssh-key-passwordhttps://mokacoding.com/blog/how-to-verify-ssh-key-passwordEspressoHow to check if array contains element with block in RubyTue, 18 Aug 2020 00:00:00 GMThttps://mokacoding.com/blog/how-to-check-if-ruby-array-contains-elementhttps://mokacoding.com/blog/how-to-check-if-ruby-array-contains-elementRubyEspressoHonesty-Oriented ProgrammingIf you focus on writing honest code, you'll end up with software that is easier to understand and work with.Sun, 12 Jul 2020 15:00:00 GMThttps://mokacoding.com/blog/honesty-oriented-programminghttps://mokacoding.com/blog/honesty-oriented-programmingSoftware DesignReferential Transparency in SwiftAn explanation of what referential transparency means with examples in SwiftSun, 12 Jul 2020 14:00:00 GMThttps://mokacoding.com/blog/referential-transparency-in-swifthttps://mokacoding.com/blog/referential-transparency-in-swiftSwiftShould you change your branch name to "main"?In Xcode 12, the default branch name is main instead of master. This little language change has deeper implications and stirred up an hornets' nest.Wed, 24 Jun 2020 00:00:00 GMThttps://mokacoding.com/blog/main-vs-master-xcode-12https://mokacoding.com/blog/main-vs-master-xcode-12The Indistractable DeveloperThe quality of your focus time is directly proportional to your value in the market. Become Indistractable to maximize it.Wed, 27 May 2020 00:00:00 GMThttps://mokacoding.com/blog/the-indistractable-developerhttps://mokacoding.com/blog/the-indistractable-developerProductivityHow to use CocoaPods as a CLI tools managerCocoaPods can be configured to only resolve and download dependencies, making it a great manager for vendored CLI toolsTue, 17 Mar 2020 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-ci-setuphttps://mokacoding.com/blog/cocoapods-ci-setupiOSCocoaPodsToolingHow to manually generate Devise reset password linkSun, 28 Jul 2019 00:00:00 GMThttps://mokacoding.com/blog/how-to-manually-generate-devise-reset-password-linkhttps://mokacoding.com/blog/how-to-manually-generate-devise-reset-password-linkRuby on RailsRubyMidwives with the Apple WatchMon, 03 Jun 2019 00:00:00 GMThttps://mokacoding.com/blog/midwives-with-the-apple-watchhttps://mokacoding.com/blog/midwives-with-the-apple-watchProductivityDeep WorkHow to use social media productivelySocial media can be a valuable source of news and interactions, or a disruption to our focus. The difference is in how we approach using these technologies.Tue, 30 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/social-media-operating-procedureshttps://mokacoding.com/blog/social-media-operating-proceduresProductivityHow to run a single test in XcodeA collection of ways to run a single test or a subset of tests using Xcode.Tue, 23 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/running-one-test-in-xcodehttps://mokacoding.com/blog/running-one-test-in-xcodeXcodeTestingProductivityHow to test view controllers navigationThe answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.Tue, 16 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/navigation-delegate-patternhttps://mokacoding.com/blog/navigation-delegate-patternSwiftTestingiOSSoftware-DesignTake care of your tools"You take care of your tools, your tools take care of you."Tue, 09 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/take-care-of-your-toolshttps://mokacoding.com/blog/take-care-of-your-toolsProductivityCode Like A ChefProfessional chefs keep their benches clean because clutter will get in the way of their work. Software developers should do the same.Tue, 02 Apr 2019 00:00:00 GMThttps://mokacoding.com/blog/code-like-a-chefhttps://mokacoding.com/blog/code-like-a-chefProductivityTop 10 Productivity BooksA running list of the top 10 most impactful books on productivity I've encountered so farTue, 26 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/top-10-productivity-bookshttps://mokacoding.com/blog/top-10-productivity-booksProductivityBooksWhy I'm cutting back on podcasts and audiobooksI realized I was on a path to remove time for reflection from my life, mainly by filling every available moment with podcasts and audiobooks. These are the steps I'm taking to cultivate more solitude, and the benefits I'm already seeing.Tue, 19 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/podcast-addictionhttps://mokacoding.com/blog/podcast-addictionProductivityPodcastsBooksBetter tests for delegatesWhen testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.Tue, 12 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/better-tests-for-delegateshttps://mokacoding.com/blog/better-tests-for-delegatesSwiftTesting3 Lessons on Software Development from the New England PatriotsBy looking at how the consistently successful New England Patriots operate we can learn useful lessons to apply to our job as software developers.Tue, 05 Mar 2019 00:00:00 GMThttps://mokacoding.com/blog/3-lessons-from-new-england-patriotshttps://mokacoding.com/blog/3-lessons-from-new-england-patriotsThe value of decluttering and optimizing your softwareDigital minimalists believe that clutter is costly and optimization is important. Let me show you how these ideas apply to software development as well.Tue, 26 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/clutter-and-optimizationhttps://mokacoding.com/blog/clutter-and-optimizationBooksProductivitySoftware DesignCode Coverage Is A Broken MetricBut you should track it anyways.Tue, 19 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/code-coverage-is-brokenhttps://mokacoding.com/blog/code-coverage-is-brokenTestingRefactoringWrite Less CodeThe best thing you can do as a software developer is not writing code, but removing it. Here's why.Wed, 13 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/wirte-less-codehttps://mokacoding.com/blog/wirte-less-codeProductivityRefactoringSoftware DesignHow to TDD in Swift, a step by step guideWith test driven development you can write high quality software in small shippable steps. Here's how to get started.Fri, 08 Feb 2019 00:00:00 GMThttps://mokacoding.com/blog/step-by-step-tdd-in-swift-part-1https://mokacoding.com/blog/step-by-step-tdd-in-swift-part-1TDDSwiftThe Productivity Project - by Chris BaileyMy notes and quotes from The Productivity Project by Chris BaileyTue, 29 Jan 2019 00:00:00 GMThttps://mokacoding.com/blog/the-productivity-project-noteshttps://mokacoding.com/blog/the-productivity-project-notesProductivityBooksTest doubles in Swift: dummies, fakes, stubs, and spies.An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.Tue, 27 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/swift-test-doubleshttps://mokacoding.com/blog/swift-test-doublesTestingSwiftHow to become drastically faster at using the terminalUsing the terminal might seem slow and cumbersome because every command needs to be typed. Learn how to drastically reduce the amount of typing you have to do by configuring aliases for your most used commands, making them only a few keystrokes long.Tue, 20 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/terminal-aliaseshttps://mokacoding.com/blog/terminal-aliasesProductivityTerminalHow to split decision and action logic with the Swift type systemThere is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.Tue, 13 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-split-decision-and-action-logic-with-the-swift-type-systemhttps://mokacoding.com/blog/how-to-split-decision-and-action-logic-with-the-swift-type-systemSwiftTestingRefactoringHow to remove duplication from Swift tests with helper functionsSome code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.Tue, 06 Nov 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-remove-duplication-from-swift-tests-with-helper-functionshttps://mokacoding.com/blog/how-to-remove-duplication-from-swift-tests-with-helper-functionsTestingXcodeSwiftXCTestStephen King's Advice To Software DevelopersIn "On Writing" Stephen King shares invaluable lessons for aspiring novelists which can be applied to software development too.Tue, 30 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/stephen-king-advice-to-software-developershttps://mokacoding.com/blog/stephen-king-advice-to-software-developersBooksQuotesProductivityWhere to start to become more productiveWhat does it take to be productive? What does it event mean? Here's a introduction to the pillars of productivity, with many resources to start from.Tue, 23 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/where-to-start-to-become-more-productivehttps://mokacoding.com/blog/where-to-start-to-become-more-productiveProductivityHow to write code faster using snippetsLeveraging "snippets" is a way to get faster at writing code and free mental resources for problem solving. Most IDEs and text editor offer this feature, where you can write code scaffolding with a keyboard shortcut.Tue, 16 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-write-code-faster-using-snippetshttps://mokacoding.com/blog/how-to-write-code-faster-using-snippetsProductivityXcodeAutomationStreamlining tests setup with fixtures in SwiftKeeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readableTue, 09 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/streamlining-tests-setup-with-fixtures-in-swifthttps://mokacoding.com/blog/streamlining-tests-setup-with-fixtures-in-swiftTestingSwiftInvest in your terminal to become a better developerOne of the best things you could do to improve as a software developer is constantly investing in your terminal setup and skills.Tue, 02 Oct 2018 00:00:00 GMThttps://mokacoding.com/blog/invest-in-your-terminal-to-become-a-better-developerhttps://mokacoding.com/blog/invest-in-your-terminal-to-become-a-better-developerProductivityToolingShellWhat software developers can learn from Leonardo da VinciLeonardo da Vinci's life as told by Walter Isaacson in his biography is a source of inspiration for anyone working in a technical and creative field.Tue, 25 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/what-software-developers-can-learn-from-leonardo-da-vincihttps://mokacoding.com/blog/what-software-developers-can-learn-from-leonardo-da-vinciBooksRed, green, and don't forget refactorTest driven development works at its best when you refactor as you go. Write the failing test, write just enough code to make it pass, then and only then focus on making that code good.Tue, 18 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/red-green-and-dont-forget-refactorhttps://mokacoding.com/blog/red-green-and-dont-forget-refactorTDDAction focused protocols enhance testabilityUsing protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testabilityTue, 11 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/action-focused-protocols-enhance-testabilityhttps://mokacoding.com/blog/action-focused-protocols-enhance-testabilityTestingSwiftHow to choose what to refactorA way to identify the areas of code to refactor with the highest return of investment using the "focusing question" technique.Tue, 04 Sep 2018 00:00:00 GMThttps://mokacoding.com/blog/how-to-choose-what-to-refactorhttps://mokacoding.com/blog/how-to-choose-what-to-refactorRefactoringBooksProductivityHow to get better at setting prioritiesThe focusing question, a tool devised by Gray W. Keller, is a simple yet effective way to identify work to focus on with the highest return of investment.Sat, 25 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/the-focusing-questionhttps://mokacoding.com/blog/the-focusing-questionIf you're not writing tests first you're missing outA look at the benefits of writing unit tests before production code, in other words TDD.Fri, 17 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/if-youre-not-writing-tests-first-youre-missing-outhttps://mokacoding.com/blog/if-youre-not-writing-tests-first-youre-missing-outTestingTDD"Does Software Understand Complexity?" via Michael FeathersThoughts on a Michael Feathers post on how the understanding of complexity in software development compares to other fields.Sun, 12 Aug 2018 00:00:00 GMThttps://mokacoding.com/blog/does-software-understand-complexity-m-feathershttps://mokacoding.com/blog/does-software-understand-complexity-m-feathersApps and ToolsA list of the apps and tools I use everyday and help me getting stuff done.Sat, 28 Jul 2018 00:00:00 GMThttps://mokacoding.com/blog/apps-and-tools-i-usehttps://mokacoding.com/blog/apps-and-tools-i-useApps4 books to kick start 2018Books suggestions to start 2018 with the right mindset and tools.Mon, 01 Jan 2018 00:00:00 GMThttps://mokacoding.com/blog/books-to-start-2018https://mokacoding.com/blog/books-to-start-2018BooksSymbolic links in GitHere's how to track symbolic liks in a Git repository, in a way suitable for teams.Tue, 12 Sep 2017 00:00:00 GMThttps://mokacoding.com/blog/symliks-in-githttps://mokacoding.com/blog/symliks-in-gitEspressoGitQuick beforeSuite and afterSuite behaviourA look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using themThu, 11 May 2017 00:00:00 GMThttps://mokacoding.com/blog/quick-beforesuite-aftersuite-behaviourhttps://mokacoding.com/blog/quick-beforesuite-aftersuite-behaviourQuickEspressoTestingQuick beforeEach and afterEach behaviourA look at how nested beforeEach and afterEach behave in the Quick testing framework.Mon, 08 May 2017 00:00:00 GMThttps://mokacoding.com/blog/quick-beforeeach-aftereach-behaviourhttps://mokacoding.com/blog/quick-beforeeach-aftereach-behaviourQuickEspressoTestingNimble: when to use waitUntil or toEventuallyThe Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.Fri, 05 May 2017 00:00:00 GMThttps://mokacoding.com/blog/waituntil-vs-toeventuallyhttps://mokacoding.com/blog/waituntil-vs-toeventuallyTestingNimbleSwiftUnless.swiftPorting Ruby's unless operator into Swift via a function.Tue, 04 Apr 2017 00:00:00 GMThttps://mokacoding.com/blog/unless-swifthttps://mokacoding.com/blog/unless-swiftSwiftEspressoXCTest closure based expectationsTesting async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.Wed, 22 Mar 2017 00:00:00 GMThttps://mokacoding.com/blog/xctest-closure-based-expectationhttps://mokacoding.com/blog/xctest-closure-based-expectationSwiftXCTestTestingHow to use dependency injection for classes in SwiftIn Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.Wed, 01 Mar 2017 00:00:00 GMThttps://mokacoding.com/blog/dependency-injection-for-classes-in-swifthttps://mokacoding.com/blog/dependency-injection-for-classes-in-swiftSwiftTestingLessons learned working on danger-switlint selective lintingA little post to share some things I learnt while working on a PR for danger-swiftlint to allow selective linting.Thu, 26 Jan 2017 00:00:00 GMThttps://mokacoding.com/blog/lessons-learned-working-on-danger-swiftlint-selective-lintinghttps://mokacoding.com/blog/lessons-learned-working-on-danger-swiftlint-selective-lintingEspressoRubyOpen SourceYour Git Log Should Tell A StoryA look at the practical benefits of writing descriptive commitsMon, 19 Dec 2016 00:00:00 GMThttps://mokacoding.com/blog/your-git-log-should-tell-a-storyhttps://mokacoding.com/blog/your-git-log-should-tell-a-storyGitBetter Xcode Run Script Build PhasesPractical tips to write "Run Script" build phases in Xcode.Mon, 07 Nov 2016 00:00:00 GMThttps://mokacoding.com/blog/better-build-phase-scriptshttps://mokacoding.com/blog/better-build-phase-scriptsXcodeSetting Up Firebase Without Using CocoaPodsA guide on how to configure your Xcode project to use Google Firebase without using CocoaPods.Mon, 15 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/setting-up-firebase-without-cocoapodshttps://mokacoding.com/blog/setting-up-firebase-without-cocoapodsXcodeFirebaseEspressoImplicitly vs Force Unwrapping Swift OptionalsA look at what implicitly unwrapping and force unwrap a Swift Optional mean, and how they differ from each other.Tue, 09 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/impliticly-vs-force-unwrapping-swift-optionalshttps://mokacoding.com/blog/impliticly-vs-force-unwrapping-swift-optionalsSwiftCloud 66 Postfix Deploy HookA deploy hook to configure Postfix every time a Cloud 66 stack is builtMon, 01 Aug 2016 00:00:00 GMThttps://mokacoding.com/blog/cloud-66-postfix-deploy-hookhttps://mokacoding.com/blog/cloud-66-postfix-deploy-hookEspressoCloud 66DevOpsWhy Implicitly Unwrapping Swift Optionals Is DangerousA look at what implicitly unwrapping an Optional value means and why it should be avoided.Tue, 26 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/why-implicitly-unwrapping-swift-optionals-is-dangeroushttps://mokacoding.com/blog/why-implicitly-unwrapping-swift-optionals-is-dangerousSwiftSwift Either enumThis post introduces the Either type and shows a practical application of it in Swift, injecting extra cells in a table view.Mon, 18 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/swift-eitherhttps://mokacoding.com/blog/swift-eitherSwiftHaskellStrong Opinions Loosely HeldStrong opinions loosely held, and other cornerstones for a winning mindsetFri, 08 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/strong-opinions-loosely-heldhttps://mokacoding.com/blog/strong-opinions-loosely-heldPodcastsEspressoQuotesWriting your own Swift "if let"An exercise to understand Swift's optional type: reimplementing the if let functionalityThu, 07 Jul 2016 00:00:00 GMThttps://mokacoding.com/blog/writing-your-own-swift-if-lethttps://mokacoding.com/blog/writing-your-own-swift-if-letSwiftEspressoWhat is an optional value in SwiftThis post looks into one of Swift's most powerful feature: optionalsThu, 30 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/what-is-an-optional-value-in-swifthttps://mokacoding.com/blog/what-is-an-optional-value-in-swiftSwiftMaintaining Sanity with Multiple Versions of XcodeWorking with Xcode and Xcode-beta on the same machine can sometimes be confusing, this post shares some tools to help make it less so.Mon, 20 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/maintaining-sanity-with-multiple-versions-of-xcodehttps://mokacoding.com/blog/maintaining-sanity-with-multiple-versions-of-xcodeXcodeProductivityHow to make Swift methods unavailableA quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.Tue, 07 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/swift-unavailable-how-tohttps://mokacoding.com/blog/swift-unavailable-how-toSwiftEspressoFunctional Core Reactive ShellThis is a blogpost version of the content of my talk "Functional Core, Reactive Shell"Wed, 01 Jun 2016 00:00:00 GMThttps://mokacoding.com/blog/functional-core-reactive-shellhttps://mokacoding.com/blog/functional-core-reactive-shellFunctional ProgrammingFunctional Reactive ProgrammingTalksSwiftSoftware DesignLanguage Agnostic Automation SetupEvery project can benefit from having a set of scripts to automate tasks such as running tests or distributing to testers. When setting up automation for your projects you can use a language agnostic setup. This will make it easier for new team members to get started, and allow you to change the setup without having to change the way the scripts are invoked.Tue, 17 May 2016 00:00:00 GMThttps://mokacoding.com/blog/language-agnostic-automation-setuphttps://mokacoding.com/blog/language-agnostic-automation-setupAutomationContinuous IntegrationProductivityNSDateFormatter format for JSON datesHow to configure NSDateFormatter to work with JSON API dates.Thu, 12 May 2016 00:00:00 GMThttps://mokacoding.com/blog/nsdateformatter-json-datehttps://mokacoding.com/blog/nsdateformatter-json-dateSwiftFoundationJSONEspresso"Functional Core, Reactive Shell" ResourcesLinks from my "Functional Core, Reactive Shell" talkFri, 15 Apr 2016 00:00:00 GMThttps://mokacoding.com/blog/functional-core-reactive-shell-resourceshttps://mokacoding.com/blog/functional-core-reactive-shell-resourcesEspressoTalksGetting Started With AutomationA collection of tips to get you started with workflow automation, increase productivity, and save time.Tue, 29 Mar 2016 00:00:00 GMThttps://mokacoding.com/blog/getting-started-with-automationhttps://mokacoding.com/blog/getting-started-with-automationAutomationUsing Swift protocols to abstract third party dependencies and improve testabilityThird party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testabilityWed, 02 Mar 2016 00:00:00 GMThttps://mokacoding.com/blog/using-swift-protocols-to-improve-testabilityhttps://mokacoding.com/blog/using-swift-protocols-to-improve-testabilitytestingswiftHow to update all plug-ins for the latest version of Xcode and Xcode-betaAn handy script to update all Xcode plug-ins to be compatible with the latest version of Xcode and Xcode-beta.Wed, 24 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/update-all-xcode-plugins-for-latest-versionhttps://mokacoding.com/blog/update-all-xcode-plugins-for-latest-versionEspressoXcodeGetting Started With OHHTTPStubsGood unit tests are fast and deterministic. Testing code that hits the network could undermine this goal, but using OHHTTPStubs we can take back control of our tests. This post explores the advantages of stubbing the network, and provide a guide on how to do it with OHHTTPStubs.Tue, 23 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ohhttpstubshttps://mokacoding.com/blog/ohhttpstubsTestingiOSWhy hitting the network is bad for your test, and what to do about itIn this post we are going to look at why hitting the network from your unit tests is a bad thing, and introduce some way to solve the problem.Tue, 16 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/why-hitting-the-network-is-bad-for-your-testshttps://mokacoding.com/blog/why-hitting-the-network-is-bad-for-your-testsTestingRuby for iOS Developers - Managing Ruby Tools with BundlerBetween CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. How can we reliably control the versions of the tools our project's automation is using in Ruby? Bundler is a simple way to specify Ruby dependencies and automate their setup.Wed, 10 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ruby-for-ios-developers-bundlerhttps://mokacoding.com/blog/ruby-for-ios-developers-bundlerRubyAutomationRuby for iOS Developers - Managing Ruby VersionsBetween CocoaPods and Fastlane, Ruby is an important part of the iOS developer toolchain. Managing versions and gems can be a challenge for developers outside of the Ruby community, but it doesn't have to be. In this two parts post we will see how to simply and reliably handle our Rubies.Tue, 02 Feb 2016 00:00:00 GMThttps://mokacoding.com/blog/ruby-for-ios-developershttps://mokacoding.com/blog/ruby-for-ios-developersRubyAutomationHow To Fix Fabric Crashing On Startup When Installed Via CocoaPodsIf you are experiencing crashes with a version of Fabric and Crashlytics installed via CocoaPods chances are you are missing required information in the Info.plist. This post shows how to solve this issue.Thu, 28 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/how-to-fix-fabric-startup-crashhttps://mokacoding.com/blog/how-to-fix-fabric-startup-crashEspressoiOSAsync Testing with Quick and NimbleA look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.Wed, 27 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/async-testing-with-quick-and-nimblehttps://mokacoding.com/blog/async-testing-with-quick-and-nimbleSwiftTestingTesting Delegates in Swift with XCTestIn this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.Tue, 19 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/testing-delegates-in-swift-with-xctesthttps://mokacoding.com/blog/testing-delegates-in-swift-with-xctestSwiftTestingXCTestTesting callbacks in Swift with XCTestTue, 12 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/testing-callbacks-in-swift-with-xctesthttps://mokacoding.com/blog/testing-callbacks-in-swift-with-xctestTestingXCTestSwiftPrevent Unit Tests from Loading AppDelegate in SwiftHow to prevent the unit test target from loading the AppDelegate and have faster tests execution.Fri, 08 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/prevent-unit-tests-from-loading-app-delegate-in-swifthttps://mokacoding.com/blog/prevent-unit-tests-from-loading-app-delegate-in-swiftXcodeSwiftTestingHow to use a double slash in xcconfig filesA short post showing how to use a double slash in xcconfig files, for example to write URLs like https://mokacoding.comSat, 02 Jan 2016 00:00:00 GMThttps://mokacoding.com/blog/double-slash-xcconfighttps://mokacoding.com/blog/double-slash-xcconfigXcodeEspresso2015 RetrospectiveA retrospective on my consulting business in 2015. What when well, what didn't and how to act on it, how to move forward in 2016. I think my personal experience could be valuable for every iOS freelancer, I have done a couple of things right that helped my business a lot.Wed, 30 Dec 2015 00:00:00 GMThttps://mokacoding.com/blog/2015-retrospectivehttps://mokacoding.com/blog/2015-retrospectiveRetrospectiveOpening a PR to Bitbucket from the terminalA simple script you can run to open a PR on BitBucket for your current branch.Thu, 26 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/bitbucket-pr-from-command-linehttps://mokacoding.com/blog/bitbucket-pr-from-command-lineEspressoAutomationBitBucketHow to update an Xcode plug-in for the latest version of XcodeA simple command to run in your terminal to make sure you can use your favourite plugins on the latest version of XcodeWed, 25 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-plugins-updatehttps://mokacoding.com/blog/xcode-plugins-updateEspressoXcodeHacker News ButtonHow to add an Hacker News button to your blogTue, 24 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/hacker-news-buttonhttps://mokacoding.com/blog/hacker-news-buttonEspressoInstalling Xcode plugins from the terminal with FastlaneHow to install Xcode plugins from the terminal using Fastlane, and persist them across machines.Tue, 17 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/install-xcode-plugin-with-fastlanehttps://mokacoding.com/blog/install-xcode-plugin-with-fastlaneXcodeFastlaneInjecting environment variables from a file with xargsHow to provide environment variables stored in a .env file as an input for a command execution without having to export then, with a deep look at the shell commands used.Fri, 13 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/env-xargshttps://mokacoding.com/blog/env-xargsEspressoShellToolingHow to configure Travis CI for iOS testingA practical guide on how to configure Travis CI to run iOS, and OS X, tests.Tue, 10 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/travis-ci-ios-testinghttps://mokacoding.com/blog/travis-ci-ios-testingContinuous IntegrationTravis CIXcodeHow to use Homebrew in CIA quick guide on how to safely use Homebrew in CI.Wed, 04 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/homebrew-in-ci-scripthttps://mokacoding.com/blog/homebrew-in-ci-scriptContinuous IntegrationHomebrewEspressoHow to configure CircleCI for iOS testingA practical guide on how to configure CircleCI for to run iOS, and OS X, tests.Tue, 03 Nov 2015 00:00:00 GMThttps://mokacoding.com/blog/circle-ci-ios-testinghttps://mokacoding.com/blog/circle-ci-ios-testingContinuous IntegrationCircleCIXcodeFixing Bugs Driven By Tests in SwiftUnit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.Wed, 28 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/fixing-bugs-driven-by-tests-in-swifthttps://mokacoding.com/blog/fixing-bugs-driven-by-tests-in-swiftTestingSwiftAcceptance TestingUI TestingHow To Sharpen Your Software Developer ToolsPractical advices on how to keep your tools sharp, master them, and become more productive.Tue, 20 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/tools-sharpeninghttps://mokacoding.com/blog/tools-sharpeningXcodebuild Destination CheatsheetA collection of tips on how to configure the -destination option for the xcodebuild tool.Tue, 13 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/xcodebuild-destination-optionshttps://mokacoding.com/blog/xcodebuild-destination-optionsXcodeThe best free RSS reader app ever: IFTTT + PocketBy using the powerful automation provided by IFTTT we can make deliver the latest posts of your favourite blogs to Pocket. This is the most powerful RSS reader ever, and it is free.Thu, 08 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/ifttt-pocket-rsshttps://mokacoding.com/blog/ifttt-pocket-rssAutomationEspressoWhen to use map, flatMap, or for loops in SwiftSwift allows us to natively iterate over arrays using map. Map could be used to replace every for loop in your code, but that's not a great idea. Map and for have different purposes and should be used appropriatelyMon, 05 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/when-to-use-map-flatmap-forhttps://mokacoding.com/blog/when-to-use-map-flatmap-forSwiftHow to display relative line numbers in NERDTreeVim's relative line numbers are great for jumpin around files, and once you get used to them you want to enable them everywhere. Here's how to have NERDTree use relative line numbersThu, 01 Oct 2015 00:00:00 GMThttps://mokacoding.com/blog/NERDTree-relative-numbershttps://mokacoding.com/blog/NERDTree-relative-numbersVimEspressoAutomated Xcode version and build numbering via GitHow to configure Xcode to automatically set the version and build number of your projects using Git.Tue, 29 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/automatic-xcode-versioning-with-githttps://mokacoding.com/blog/automatic-xcode-versioning-with-gitXcodeAutomationProductivityHow to always use the latest Simulator with XcodebuildThere is a simple keyword you can use in the destination option of an xcodebuild command to always run the most recent Simulator version.Fri, 25 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/how-to-always-run-latest-simulator-clihttps://mokacoding.com/blog/how-to-always-run-latest-simulator-cliXcodeAutomationEspressoSwift Optionals, Functional Programming, and YouThis is the post version of a talk I've been given in the past months. In this post we will demystify functional programming terms like monad and functor, and see how those concepts can be brought back to the every day Swift development, in particular how they can help to deal with optionals in a leaner way.Tue, 22 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/demistifying-swift-functorhttps://mokacoding.com/blog/demistifying-swift-functorSwiftFunctional ProgrammingAn even lighter way to use CarthageAmong the options Carthage, an iOS and OS X dependency manager, provides there is the --no-build one. Using this we can integrate dependencies in the form of Xcode projects rather than frameworks, keeping the repository slimmer and the CI time low. This approach is lighter than than the usual way to work with Carthage, but comes with some disadvantages too.Tue, 15 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/carthage-no-buildhttps://mokacoding.com/blog/carthage-no-buildCarthageXcodeHow to install Xcode Command Line Tools without GUI or XcodeHere's a little script that will allow you to install the Xcode Command Line Tools without having to install Xcode, nor having a logged GUI. This can come pretty handy in automated scripts or when provisioning virtual machines.Wed, 09 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/how-to-install-xcode-cli-tools-without-guihttps://mokacoding.com/blog/how-to-install-xcode-cli-tools-without-guiEspressoXcodeAutomation/dev/world/2015 notes of a testing fanboyI attended /dev/world/2015 in Melbourne this week. It has been a great conference, full of very friendly and smart people. Being a test and automation fanboy I attended as many talks related to that topic as I could. These are my notes.Tue, 08 Sep 2015 00:00:00 GMThttps://mokacoding.com/blog/devworld2015-notes-of-a-testing-fanboyhttps://mokacoding.com/blog/devworld2015-notes-of-a-testing-fanboyTestingToolingAutomationConferencesEnhancing XCTest test cases with Nimble matchersNimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.Tue, 25 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/xctest-nimblehttps://mokacoding.com/blog/xctest-nimbleSwiftTDDNimbleAFNetworking custom response serializer to add error informationHow to implement a custom AFNetworking response serializer to read the failure response data and populate the callback error with it.Wed, 19 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/custom-afnetworking-response-serializer-for-errorshttps://mokacoding.com/blog/custom-afnetworking-response-serializer-for-errorsEspressoiOSObjective-CExplicit Dependencies, Swift EditionA look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.Tue, 18 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/explicit-dependencies-swifthttps://mokacoding.com/blog/explicit-dependencies-swiftTestingSoftware DesignSwiftHow to have multiple iTunes Connect accounts, and submit appsSat, 15 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/itunes-connect-multiple-accountshttps://mokacoding.com/blog/itunes-connect-multiple-accountsEspressoiTunes ConnectSwift array of characters from StringHow to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].Wed, 12 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/swift-array-string-charactershttps://mokacoding.com/blog/swift-array-string-charactersSwiftEspressoExplicit Dependencies for Code with No SurprisesSometimes the idea we get when reading a class interface is different from what is actually going on inside its implementation, for example there could be several hidden dependencies. Making a class dependency explicit in its interface is a useful technique to make the code simpler to understand, and easier to test.Tue, 11 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/explicit-dependencieshttps://mokacoding.com/blog/explicit-dependenciesTestingObjective-CSoftware-DesignHow to reuse the last parameter in a terminal commandWhen typing a shell command it is possible to reuse the last argument of the previous call without having to type it. Let's see how.Wed, 05 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/terminal-reusing-last-command-parameterhttps://mokacoding.com/blog/terminal-reusing-last-command-parameterShellEspressoKeep Your Bench CleanLike good chefs keep their benches clean to make delicious dishes all day long in the restaurants' kitchens, so good developer keep their codebase clean. It all comes down to little habits, the result of which when summed up together is a tidy, clean and easy to maintain software.Tue, 04 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/keep-your-bench-cleanhttps://mokacoding.com/blog/keep-your-bench-cleanProductivityPackaging an ipa with Swift files from the terminalIf you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.Mon, 03 Aug 2015 00:00:00 GMThttps://mokacoding.com/blog/packaging-swift-ipahttps://mokacoding.com/blog/packaging-swift-ipaEspressoSwiftAutomationTestFlightHow to test UI changes in Xcode 7One of the characteristic of the UI is that it changes, and there are scenarios in which writing UI tests to assure that the change has happened correctly can be very valuable for the reliability of our apps. Writing such a test is a bit harder than normal, let's see how to do it.Sat, 25 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-ui-test-view-changeshttps://mokacoding.com/blog/xcode-ui-test-view-changesAcceptance TestingUI TestingiOSHow to add testing dependencies using Carthage, with Swift 2 and Xcode 7In this little tutorial we will see how to use Cathage, an OS X and iOS depencendy manager, to install libraries written in Swift 2 and Xcode 7, with a focus on the process to get testing dependencies.Tue, 21 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/setting-up-testing-libraries-with-carthage-xcode7https://mokacoding.com/blog/setting-up-testing-libraries-with-carthage-xcode7XcodeCarthageToolingSwift Functors, Applicatives, and Monads in PicturesIn this port to Swift of the great of Haskell's "Functors, Applicatives, And Monads In Pictures" we are going to look at these functional programming concepts aided by some very helpful pictures.Tue, 14 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/functor-applicative-monads-in-pictureshttps://mokacoding.com/blog/functor-applicative-monads-in-picturesSwiftFunctional ProgrammingXVim, harnessing the king of text editor's power in XcodeAn introduction to the XVim plugin, that adds most Vim keybindings and features to the Xcode IDE, and how this can make you more productive as a developer.Tue, 07 Jul 2015 00:00:00 GMThttps://mokacoding.com/blog/xvimhttps://mokacoding.com/blog/xvimProductivityXcodeTesting Realm appsRealm is a mobile database that, unlike CoreData, is easy to test. In this post we will discuss some ideas on how to test an app using Realm as its database.Tue, 30 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/testing-realm-appshttps://mokacoding.com/blog/testing-realm-appsTestingThe value of acceptance testing for mobile projectsCompanion blogpost for Gio's talk "Talking myself into the value of acceptance testing" at Melbourne CocoaHeads meetupTue, 23 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/the-value-of-acceptance-testinghttps://mokacoding.com/blog/the-value-of-acceptance-testingAcceptance TestingXcode 7 UI testing, a first lookHow to get started with UI testing in Xcode 7, recording tests and using the new APIs to assert the state of the application under test.Tue, 16 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-7-ui-testinghttps://mokacoding.com/blog/xcode-7-ui-testingAcceptance TestingUI TestingXcodeMailChimp automated workflow for mokacoding weeklyAt mokacoding we're big on automation, and we eat our own dog's food! The workflow to write and send new issues of our newsletter, mokacoding weekly, is (partially) automated thanks to some simple Ruby scripting and Mac command line utilities.Tue, 09 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/automating-mokacoding-weeklyhttps://mokacoding.com/blog/automating-mokacoding-weeklyAutomationProductivityAutomation with pre-commit hooksGit provides a mechanism to run one or more scripts before a commit is actually added to the history called pre-commit hook. We can use this hook to run scripts that validate or sanitise the changes to be committed automatically, saving time and brain power, and assuring the quality of the codbase and git log.Wed, 03 Jun 2015 00:00:00 GMThttps://mokacoding.com/blog/pre-commit-hookshttps://mokacoding.com/blog/pre-commit-hooksGitAutomationxUnique: a tool to avoid Xcode project merge conflictsHow many times when working on a Mac OSX or iOS app with a team have you had a merge conflict on the project.pbxproj file? I guess more than a few, a lot more than a few. Lucky for you there is an handy tool called xUnique that will make the chances of this happening way smaller.Tue, 12 May 2015 00:00:00 GMThttps://mokacoding.com/blog/xuniquehttps://mokacoding.com/blog/xuniqueXcodeAutomationProductivityWriting an Expecta custom matcherNot only Expecta is a simple to use library that allows us to write highly readable code, but it can also be extended by the users with custom matchers. Let's see how to write a custom matcher to gain readability and reuse code in our test suites.Tue, 05 May 2015 00:00:00 GMThttps://mokacoding.com/blog/expecta-custom-matchershttps://mokacoding.com/blog/expecta-custom-matchersSpectaExpectaExpecta, a matcher library that speaks EnglishA test that express is intent clearly is arguably twice as effective as one that doesn't. Writing test in an xSpec style is a good first step to express behaviour clearly, and when matched with a matcher library such as Expecta the results are test that are easy to read and reason aboutTue, 28 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/expectahttps://mokacoding.com/blog/expectaSpectaExpectaSpecta global before and after each hooks (Updated)An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them. Updated for version 0.5Fri, 24 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/specta-global-before-after-each-updatedhttps://mokacoding.com/blog/specta-global-before-after-each-updatedTestingSpectaJob stories acceptance tests using KIF and SpectaWhen writing tests it's very important do be declarative, aiming to have tests that explain how a class is supposed to behave as good as its documentation would do. When talking about acceptance tests we can achieve this kind of clarity by having a 1:1 relationship between the tests and the acceptance criteria for the application. A very effective way to express acceptance criteria is through _job stories_. In this post we'll see how to write acceptance tests that map job stories for our iOS apps, using KIF and Specta.Tue, 21 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/job-stories-acceptance-tests-with-KIF-and-spectahttps://mokacoding.com/blog/job-stories-acceptance-tests-with-KIF-and-spectaAcceptance TestingKIFSpectaBetter tests with SpectaWriting unit tests for our iOS and OS X projects not only is important, but should be always part of the development cycle. As such the way we write the tests is as important, and having the option to write tests that easily explain their purpose can drastically increase the quality of the suite. Specta and Expecta are two libraries that provide a different way to writing tests than XCTest, let's see what we can gain by using such approach.Tue, 14 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/better-tests-with-spectahttps://mokacoding.com/blog/better-tests-with-spectaTestingSpectaXCTestXcode keyboard shortcuts for testingKeyboard shortcuts are easies way to start increasing your productivity. Let's look at how to run tests in Xcode without ever touching the mouse.Tue, 07 Apr 2015 00:00:00 GMThttps://mokacoding.com/blog/xcode-testing-shortcutshttps://mokacoding.com/blog/xcode-testing-shortcutsTestingXcodeProductivitySetting up KIF for iOS acceptance testingA guide on install and use the KIF framework for iOS acceptance testing.Tue, 31 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/setting-up-KIF-for-ios-acceptance-testinghttps://mokacoding.com/blog/setting-up-KIF-for-ios-acceptance-testingAcceptance TestingKIFThe state of iOS testing in 2015In this post we'll look at the main tools and libraries available to write unit and acceptance tests for iOS and OS X applications, as well as the solutions to host Continuous Integration for our projects.Tue, 24 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/ios-testing-in-2015https://mokacoding.com/blog/ios-testing-in-2015TestingAcceptance TestingContinuous IntegrationSpecta global before and after each hooksAn interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them.Thu, 19 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/specta-global-before-after-eachhttps://mokacoding.com/blog/specta-global-before-after-eachTestingSpectaHow to run Xcode tests from the terminalHow to invoke xcodebuild to run the tests from the command line and how to format its output using xcbeautify or xcprettyMon, 09 Mar 2015 00:00:00 GMThttps://mokacoding.com/blog/running-tests-from-the-terminalhttps://mokacoding.com/blog/running-tests-from-the-terminalTestingXcodeTerminalAutomationHow to simplify Calabash acceptance testing with RakeRake, the Ruby build utility, can lift off all the typing involved in running the Cucumber/Calabash acceptance tests, saving us a lot of typing time.Wed, 25 Feb 2015 00:00:00 GMThttps://mokacoding.com/blog/simpler-calabash-testing-with-rakehttps://mokacoding.com/blog/simpler-calabash-testing-with-rakeAcceptance TestingCalabashProductivityGit-iquetteEvery team and every project should have a Git-iquette: a set of common practices for managing the git repository.Sun, 15 Feb 2015 00:00:00 GMThttps://mokacoding.com/blog/gitiquettehttps://mokacoding.com/blog/gitiquetteGitSetting up Calabash for iOS projects with Cocoapods and Build ConfigurationsA simple guide that shows the simplest way to install Calabash on an iOS project, by using Build Configurations and CocoaPods.Sun, 25 Jan 2015 00:00:00 GMThttps://mokacoding.com/blog/calabash-ios-with-cocoapods-and-build-configurationshttps://mokacoding.com/blog/calabash-ios-with-cocoapods-and-build-configurationsAcceptance TestingCalabash5 habits that will make you a better software developerBy implementing these 5 small habits you'll kickstart your 2015 and become a better software developer.Wed, 07 Jan 2015 00:00:00 GMThttps://mokacoding.com/blog/5-habits-that-will-make-you-a-better-software-developerhttps://mokacoding.com/blog/5-habits-that-will-make-you-a-better-software-developerProductivitySecurity Tips for Freelance Software DevelopersTips for freelance software developers (and non) to improve the security of laptops, smartphones and website accounts, to keep your and your clients data safe.Wed, 29 Oct 2014 00:00:00 GMThttps://mokacoding.com/blog/security-tips-for-freelance-software-developershttps://mokacoding.com/blog/security-tips-for-freelance-software-developersWhy I don't work on FridaysSome time ago I learned the hard way that I shouldn't work on Fridays. I've been applying an alternative schedule to my week, and it's working out pretty well.Fri, 29 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/why-i-dont-work-on-fridayhttps://mokacoding.com/blog/why-i-dont-work-on-fridayProductivityIn-App Purchase Debugging LessonsA couple of tips learnt the hard way on how to develop and debug In App Purchase support in an iOS app.Tue, 26 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/in-app-purchase-debugging-lessonshttps://mokacoding.com/blog/in-app-purchase-debugging-lessonsiOSWhy I (shouldn't have) stopped blogging with JekyllI recently decided to move my blog from Ruby and Jekyll, to Metalsmith and Javascript. It turned out to be not as easy as I thought, and a quite stupid choice, but not because of the tech.Fri, 08 Aug 2014 00:00:00 GMThttps://mokacoding.com/blog/why-i-shouldnt-have-stopped-blogging-with-jekyllhttps://mokacoding.com/blog/why-i-shouldnt-have-stopped-blogging-with-jekyllRubyJavascriptCocoaPods and custom Build ConfigurationsSome tips on how to use CocoaPods and customs build configurations without headaches.Wed, 16 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-and-custom-build-configurationshttps://mokacoding.com/blog/cocoapods-and-custom-build-configurationsCocoaPods2014 resolutions reviewWed, 09 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/2014-resolutions-reviewhttps://mokacoding.com/blog/2014-resolutions-reviewGradient Backgrounds Studio: Lessons LearnedThu, 03 Apr 2014 00:00:00 GMThttps://mokacoding.com/blog/gradient-backgrounds-studiohttps://mokacoding.com/blog/gradient-backgrounds-studioiOSA caveat when upgrading a PodfileFri, 28 Mar 2014 00:00:00 GMThttps://mokacoding.com/blog/upgrading-podfilehttps://mokacoding.com/blog/upgrading-podfileCocoaPodsSharing assets across iOS projects with CocoaPods, Resource Bundle, and dynamically loaded fontsThu, 13 Feb 2014 00:00:00 GMThttps://mokacoding.com/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fontshttps://mokacoding.com/blog/sharing-assets-with-cocoapods-resource-bundle-and-dynamically-loaded-fontsiOSCocoaPodsAutomating iOS Enterprise Deployment with shenzhenA way of automating the deployment of an iOS app for enterprise distribution using the shenzhen gem.Mon, 06 Jan 2014 00:00:00 GMThttps://mokacoding.com/blog/automating-ios-enterprise-deploymenthttps://mokacoding.com/blog/automating-ios-enterprise-deploymentAutomation2013 retrospectives... and 2014 propositionsTaking a look back at 2013, to find good propositions for 2014Thu, 02 Jan 2014 00:00:00 GMThttps://mokacoding.com/blog/2013-retrospectives-and-2014-propositionshttps://mokacoding.com/blog/2013-retrospectives-and-2014-propositionsPodcasts, grow your brain through soundwavesA list of the tech podcasts I followWed, 20 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/podcastshttps://mokacoding.com/blog/podcastsRails: adding a new has_many association to an existing modelA little guide on how to edit an existing model adding a new has_many associationWed, 13 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/rails-add-has_many-association-to-existing-modelhttps://mokacoding.com/blog/rails-add-has_many-association-to-existing-modelRubyRuby on RailsSome things I learned in OctoberA quick summary and memo of interesting things I've learned in October - iOS screen capture, HTML5 game development, ways to improve your coding.Tue, 12 Nov 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-octoberhttps://mokacoding.com/blog/things-learned-in-octoberLife long learningA dive into Xcode projects and workspacesA look at how Xcode stores information about the project and the workspaceThu, 31 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/Xcode-projects-and-workspaceshttps://mokacoding.com/blog/Xcode-projects-and-workspacesXcodeOctober's QuestionsIntroducing mokagio's monthly questions, related to iOS, Objective-C, Xcode, xctool, AFNetworking, CocoaPods.Sun, 06 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/october-questionshttps://mokacoding.com/blog/october-questionsLife long learningSome things I learned in SeptemberA quick summary and memo of interesting things I've learned in SeptemberWed, 02 Oct 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-septemberhttps://mokacoding.com/blog/things-learned-in-septemberLife long learningSharing some thoughts on iOS 7Sharing thoughts by some lead designers on iOS 7.Tue, 24 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/ios7-ux-designers-verdicthttps://mokacoding.com/blog/ios7-ux-designers-verdictiOSUXSetting a Mac for DevelopmentA simple checklist of the basic tools to setup a Mac for development.Mon, 23 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/setup-a-dev-machinehttps://mokacoding.com/blog/setup-a-dev-machineOS XBringing font icons in iOS with MTFontIconIntroducing MTFontIcon, a CocoaPod library for iOS to improve application development efficiency by using font icons.Tue, 17 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/mtfonticonhttps://mokacoding.com/blog/mtfonticoniOSObjective-CRubyLayoutCSSOpen SourceA workaround to Xcode 5 GM crash on app submissionA workaround for the unusual crash of Xcode 5 GM during the App Store submission process.Mon, 16 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/xcode5-crash-on-submissionhttps://mokacoding.com/blog/xcode5-crash-on-submissionXcodeSome things I learned in AugustTue, 03 Sep 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-augusthttps://mokacoding.com/blog/things-learned-in-augustLife long learningSome things I learned in JulyA summary of the things I learned in July 2013.Thu, 01 Aug 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-julyhttps://mokacoding.com/blog/things-learned-in-julyLife long learningWhat I did in a week...A recap of what I developed during an unusual week left by myself without neither girlfriend nor friends.Fri, 26 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/what-i-did-in-a-weekhttps://mokacoding.com/blog/what-i-did-in-a-weekA week of time...A declaration of purposes for what I'm gonna do in the next week.Wed, 17 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/a-week-of-timehttps://mokacoding.com/blog/a-week-of-timeCocoaPods: the $(inherited) flagA self memo on how to set the $(inherited) flag on a project using CocoaPods on Xcode.Tue, 09 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-the-inherited-flaghttps://mokacoding.com/blog/cocoapods-the-inherited-flagCocoaPodsiOSSome things I learned in JuneA summary of the things I learned in June 2013.Sat, 06 Jul 2013 00:00:00 GMThttps://mokacoding.com/blog/things-learned-in-junehttps://mokacoding.com/blog/things-learned-in-juneLife long learningmokagio's self memo for Facebook Integration on iOS - Part 1Step by step guide on how to integrate the Facebook SDK in an iOS app, the right way. Part 1: Facebook Login.Tue, 25 Jun 2013 00:00:00 GMThttps://mokacoding.com/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1https://mokacoding.com/blog/mokagios-self-memo-for-facebook-integration-on-ios-part-1iOSOSX, a scanner, and the drivers dramaThe link to the Samsung Printer Drivers, enclosed in a ranting post.Tue, 11 Jun 2013 00:00:00 GMThttps://mokacoding.com/blog/osx-a-scanner-and-the-drivers-dramahttps://mokacoding.com/blog/osx-a-scanner-and-the-drivers-dramaOS XMultiple builds of the same app and TestFlightHow to distribute multiple builds of your iOS app, such as stable, QA and development builds, via TestFlight.Wed, 29 May 2013 00:00:00 GMThttps://mokacoding.com/blog/multiple-builds-of-the-same-app-and-testflighthttps://mokacoding.com/blog/multiple-builds-of-the-same-app-and-testflightAutomationTestFlightCocoaPods - How to create your own PodA step by step guide to create a basic CocoaPod.Mon, 21 Jan 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapods-how-to-create-your-own-podhttps://mokacoding.com/blog/cocoapods-how-to-create-your-own-podCocoaPodsiOSCocoaPods!A brief introduction to CocoaPods, the Objective-C dependencies manager.Sat, 05 Jan 2013 00:00:00 GMThttps://mokacoding.com/blog/cocoapodshttps://mokacoding.com/blog/cocoapodsCocoaPodsiOS \ No newline at end of file diff --git a/tag/swift/index.html b/tag/swift/index.html index 556d465..e48ab78 100644 --- a/tag/swift/index.html +++ b/tag/swift/index.html @@ -1,6 +1,6 @@ Posts tagged 'swift' | mokacoding

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "swift"

    Test-Driven Development in Swift is now available

    My book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.

    WWDC21: What's New in Testing

    A roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.

    How to test Swift async/await code with XCTest

    Swift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.

    How to write better tests for Swift date comparisons

    Testing Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.

    How to manage complex inputs in your Swift tests with Scenario Builders

    When writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.

    How to set default values in Swift compiler-generated initializers

    You can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.

    Write better Swift unit tests with custom XCTest assertions

    The XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.

    How to write unit test assertions for Swift Result values

    Result is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to make the View to ViewModel relationship clear

    Using Swift's nested types helps making it clear that a view model belongs to a view.

    What can a pipe wrench teach us about software engineering?

    With his famous pipe wrench lecture, Vannevar Bush taught young MIT engineers the value of precision. The same teaching holds true for software developers.

    Replace Triple-state Boolean with Enumeration

    Triple-state Booleans can be ambiguous to work with. Replace them with an enum to make the code clearer.

    How to decouple unit tests from values that change frequently

    When the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.

    How to write unit tests for SwiftUI apps

    To test SwiftUI applications, don't test SwiftUI code. The SwiftUI framework doesn't lend itself to writing unit tests so don't try to shoehorn views in your test harness. Instead, split layout declaration form content generation logic.

    Referential Transparency in Swift

    An explanation of what referential transparency means with examples in Swift

    How to test view controllers navigation

    The answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.

    Better tests for delegates

    When testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.

    How to TDD in Swift, a step by step guide

    With test driven development you can write high quality software in small shippable steps. Here's how to get started.

    Test doubles in Swift: dummies, fakes, stubs, and spies.

    An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.

    How to split decision and action logic with the Swift type system

    There is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.

    How to remove duplication from Swift tests with helper functions

    Some code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.

    Streamlining tests setup with fixtures in Swift

    Keeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readable

    Action focused protocols enhance testability

    Using protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testability

    Nimble: when to use waitUntil or toEventually

    The Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.

    Unless.swift

    Porting Ruby's unless operator into Swift via a function.

    XCTest closure based expectations

    Testing async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.

    How to use dependency injection for classes in Swift

    In Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.

    Implicitly vs Force Unwrapping Swift Optionals

    A look at what implicitly unwrapping and force unwrap a Swift Optional mean, and how they differ from each other.

    Why Implicitly Unwrapping Swift Optionals Is Dangerous

    A look at what implicitly unwrapping an Optional value means and why it should be avoided.

    Swift Either enum

    This post introduces the Either type and shows a practical application of it in Swift, injecting extra cells in a table view.

    Writing your own Swift "if let"

    An exercise to understand Swift's optional type: reimplementing the if let functionality

    What is an optional value in Swift

    This post looks into one of Swift's most powerful feature: optionals

    How to make Swift methods unavailable

    A quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.

    Functional Core Reactive Shell

    This is a blogpost version of the content of my talk "Functional Core, Reactive Shell"

    NSDateFormatter format for JSON dates

    How to configure NSDateFormatter to work with JSON API dates.

    Using Swift protocols to abstract third party dependencies and improve testability

    Third party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testability

    Async Testing with Quick and Nimble

    A look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.

    Testing Delegates in Swift with XCTest

    In this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.

    Testing callbacks in Swift with XCTest

    Prevent Unit Tests from Loading AppDelegate in Swift

    How to prevent the unit test target from loading the AppDelegate and have faster tests execution.

    Fixing Bugs Driven By Tests in Swift

    Unit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.

    When to use map, flatMap, or for loops in Swift

    Swift allows us to natively iterate over arrays using map. Map could be used to replace every for loop in your code, but that's not a great idea. Map and for have different purposes and should be used appropriately

    Swift Optionals, Functional Programming, and You

    This is the post version of a talk I've been given in the past months. In this post we will demystify functional programming terms like monad and functor, and see how those concepts can be brought back to the every day Swift development, in particular how they can help to deal with optionals in a leaner way.

    Enhancing XCTest test cases with Nimble matchers

    Nimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.

    Explicit Dependencies, Swift Edition

    A look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.

    Swift array of characters from String

    How to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].

    Packaging an ipa with Swift files from the terminal

    If you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.

    Swift Functors, Applicatives, and Monads in Pictures

    In this port to Swift of the great of Haskell's "Functors, Applicatives, And Monads In Pictures" we are going to look at these functional programming concepts aided by some very helpful pictures.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "swift"

    Test-Driven Development in Swift is now available

    My book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.

    WWDC21: What's New in Testing

    A roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.

    How to test Swift async/await code with XCTest

    Swift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.

    How to write better tests for Swift date comparisons

    Testing Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.

    How to manage complex inputs in your Swift tests with Scenario Builders

    When writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.

    How to set default values in Swift compiler-generated initializers

    You can get the Swift compiler to generate an initializer with default values for your structs, if you're willing to put up with a bit of mutability.

    Write better Swift unit tests with custom XCTest assertions

    The XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.

    How to write unit test assertions for Swift Result values

    Result is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to make the View to ViewModel relationship clear

    Using Swift's nested types helps making it clear that a view model belongs to a view.

    What can a pipe wrench teach us about software engineering?

    With his famous pipe wrench lecture, Vannevar Bush taught young MIT engineers the value of precision. The same teaching holds true for software developers.

    Replace Triple-state Boolean with Enumeration

    Triple-state Booleans can be ambiguous to work with. Replace them with an enum to make the code clearer.

    How to decouple unit tests from values that change frequently

    When the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.

    Referential Transparency in Swift

    An explanation of what referential transparency means with examples in Swift

    How to test view controllers navigation

    The answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.

    Better tests for delegates

    When testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.

    How to TDD in Swift, a step by step guide

    With test driven development you can write high quality software in small shippable steps. Here's how to get started.

    Test doubles in Swift: dummies, fakes, stubs, and spies.

    An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.

    How to split decision and action logic with the Swift type system

    There is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.

    How to remove duplication from Swift tests with helper functions

    Some code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.

    Streamlining tests setup with fixtures in Swift

    Keeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readable

    Action focused protocols enhance testability

    Using protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testability

    Nimble: when to use waitUntil or toEventually

    The Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.

    Unless.swift

    Porting Ruby's unless operator into Swift via a function.

    XCTest closure based expectations

    Testing async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.

    How to use dependency injection for classes in Swift

    In Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.

    Implicitly vs Force Unwrapping Swift Optionals

    A look at what implicitly unwrapping and force unwrap a Swift Optional mean, and how they differ from each other.

    Why Implicitly Unwrapping Swift Optionals Is Dangerous

    A look at what implicitly unwrapping an Optional value means and why it should be avoided.

    Swift Either enum

    This post introduces the Either type and shows a practical application of it in Swift, injecting extra cells in a table view.

    Writing your own Swift "if let"

    An exercise to understand Swift's optional type: reimplementing the if let functionality

    What is an optional value in Swift

    This post looks into one of Swift's most powerful feature: optionals

    How to make Swift methods unavailable

    A quick post showing how to use the Swift availability attribute to mark objects and functions as unavailable.

    Functional Core Reactive Shell

    This is a blogpost version of the content of my talk "Functional Core, Reactive Shell"

    NSDateFormatter format for JSON dates

    How to configure NSDateFormatter to work with JSON API dates.

    Using Swift protocols to abstract third party dependencies and improve testability

    Third party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testability

    Async Testing with Quick and Nimble

    A look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.

    Testing Delegates in Swift with XCTest

    In this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.

    Testing callbacks in Swift with XCTest

    Prevent Unit Tests from Loading AppDelegate in Swift

    How to prevent the unit test target from loading the AppDelegate and have faster tests execution.

    Fixing Bugs Driven By Tests in Swift

    Unit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.

    When to use map, flatMap, or for loops in Swift

    Swift allows us to natively iterate over arrays using map. Map could be used to replace every for loop in your code, but that's not a great idea. Map and for have different purposes and should be used appropriately

    Swift Optionals, Functional Programming, and You

    This is the post version of a talk I've been given in the past months. In this post we will demystify functional programming terms like monad and functor, and see how those concepts can be brought back to the every day Swift development, in particular how they can help to deal with optionals in a leaner way.

    Enhancing XCTest test cases with Nimble matchers

    Nimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.

    Explicit Dependencies, Swift Edition

    A look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.

    Swift array of characters from String

    How to get an array of single characters String from a multiple characters String. From foobar to [f, o, o, b, a, r].

    Packaging an ipa with Swift files from the terminal

    If you are having problems with xcodebuild failing to export your apps with either Swift or Watch Kit support here's the solution, with a handy custom script.

    Swift Functors, Applicatives, and Monads in Pictures

    In this port to Swift of the great of Haskell's "Functors, Applicatives, And Monads In Pictures" we are going to look at these functional programming concepts aided by some very helpful pictures.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "swiftui"

    How to migrate from SwiftUI to UIKit App Delegate Life Cycle in Xcode

    This free tutorial shows how to migrate an existing app with SwiftUI life cycle to use UIKit App Delegate instead

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to make the View to ViewModel relationship clear

    Using Swift's nested types helps making it clear that a view model belongs to a view.

    How to write unit tests for SwiftUI apps

    To test SwiftUI applications, don't test SwiftUI code. The SwiftUI framework doesn't lend itself to writing unit tests so don't try to shoehorn views in your test harness. Instead, split layout declaration form content generation logic.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "swiftui"

    How to migrate from SwiftUI to UIKit App Delegate Life Cycle in Xcode

    This free tutorial shows how to migrate an existing app with SwiftUI life cycle to use UIKit App Delegate instead

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to make the View to ViewModel relationship clear

    Using Swift's nested types helps making it clear that a view model belongs to a view.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "tdd"

    Test-Driven Development in Swift is now available

    My book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.

    Boring Iterations. Interesting Steps.

    Camille Fournier encourages us to "Make Boring Plans" and move in small iterations.

    How to improve your Test-Driven Development workflow by asking "Do I need this yet?"

    The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.

    How to write unit tests for SwiftUI apps

    To test SwiftUI applications, don't test SwiftUI code. The SwiftUI framework doesn't lend itself to writing unit tests so don't try to shoehorn views in your test harness. Instead, split layout declaration form content generation logic.

    How to TDD in Swift, a step by step guide

    With test driven development you can write high quality software in small shippable steps. Here's how to get started.

    Red, green, and don't forget refactor

    Test driven development works at its best when you refactor as you go. Write the failing test, write just enough code to make it pass, then and only then focus on making that code good.

    If you're not writing tests first you're missing out

    A look at the benefits of writing unit tests before production code, in other words TDD.

    Enhancing XCTest test cases with Nimble matchers

    Nimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "tdd"

    Test-Driven Development in Swift is now available

    My book, Test-Driven Development in Swift, is now available in online bookstores everywhere. You'll learn Test-Driven Development writing a real-world SwiftUI application, including events-flow management with Combine, networking, local storage, and third-party libraries.

    Boring Iterations. Interesting Steps.

    Camille Fournier encourages us to "Make Boring Plans" and move in small iterations.

    How to improve your Test-Driven Development workflow by asking "Do I need this yet?"

    The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.

    How to TDD in Swift, a step by step guide

    With test driven development you can write high quality software in small shippable steps. Here's how to get started.

    Red, green, and don't forget refactor

    Test driven development works at its best when you refactor as you go. Write the failing test, write just enough code to make it pass, then and only then focus on making that code good.

    If you're not writing tests first you're missing out

    A look at the benefits of writing unit tests before production code, in other words TDD.

    Enhancing XCTest test cases with Nimble matchers

    Nimble is a matchers framework built for Swift that provides powerful and versatile expectations. Writing test within the standard XCTest harness but using Nimble assertions is easier and productive, and a good combination of tools to introduce testing and TDD to colleagues and teams in a frictionless way.

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "testing"

    WWDC21: What's New in Testing

    A roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.

    How to test Swift async/await code with XCTest

    Swift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.

    How to write better tests for Swift date comparisons

    Testing Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.

    How to manage complex inputs in your Swift tests with Scenario Builders

    When writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.

    Unit Testing Combine Publisher Cheatsheet

    Snippets to test the behavior of Combine Publishers in XCTest ready to copy and paste into Xcode

    How to improve your Test-Driven Development workflow by asking "Do I need this yet?"

    The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.

    Write better Swift unit tests with custom XCTest assertions

    The XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.

    How to write unit test assertions for Swift Result values

    Result is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.

    When experiments go wrong

    Scientist can learn a lot from failed experiments. To do so, they must be methodical and collect all sorts of information. Softwar developers can learn a lot from failures, too. What are the practicies that can make learning easier?

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to decouple unit tests from values that change frequently

    When the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.

    How to write unit tests for SwiftUI apps

    To test SwiftUI applications, don't test SwiftUI code. The SwiftUI framework doesn't lend itself to writing unit tests so don't try to shoehorn views in your test harness. Instead, split layout declaration form content generation logic.

    How to run a single test in Xcode

    A collection of ways to run a single test or a subset of tests using Xcode.

    How to test view controllers navigation

    The answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.

    Better tests for delegates

    When testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.

    Code Coverage Is A Broken Metric

    But you should track it anyways.

    Test doubles in Swift: dummies, fakes, stubs, and spies.

    An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.

    How to split decision and action logic with the Swift type system

    There is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.

    How to remove duplication from Swift tests with helper functions

    Some code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.

    Streamlining tests setup with fixtures in Swift

    Keeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readable

    Action focused protocols enhance testability

    Using protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testability

    If you're not writing tests first you're missing out

    A look at the benefits of writing unit tests before production code, in other words TDD.

    Quick beforeSuite and afterSuite behaviour

    A look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using them

    Quick beforeEach and afterEach behaviour

    A look at how nested beforeEach and afterEach behave in the Quick testing framework.

    Nimble: when to use waitUntil or toEventually

    The Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.

    XCTest closure based expectations

    Testing async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.

    How to use dependency injection for classes in Swift

    In Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.

    Using Swift protocols to abstract third party dependencies and improve testability

    Third party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testability

    Getting Started With OHHTTPStubs

    Good unit tests are fast and deterministic. Testing code that hits the network could undermine this goal, but using OHHTTPStubs we can take back control of our tests. This post explores the advantages of stubbing the network, and provide a guide on how to do it with OHHTTPStubs.

    Why hitting the network is bad for your test, and what to do about it

    In this post we are going to look at why hitting the network from your unit tests is a bad thing, and introduce some way to solve the problem.

    Async Testing with Quick and Nimble

    A look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.

    Testing Delegates in Swift with XCTest

    In this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.

    Testing callbacks in Swift with XCTest

    Prevent Unit Tests from Loading AppDelegate in Swift

    How to prevent the unit test target from loading the AppDelegate and have faster tests execution.

    Fixing Bugs Driven By Tests in Swift

    Unit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.

    /dev/world/2015 notes of a testing fanboy

    I attended /dev/world/2015 in Melbourne this week. It has been a great conference, full of very friendly and smart people. Being a test and automation fanboy I attended as many talks related to that topic as I could. These are my notes.

    Explicit Dependencies, Swift Edition

    A look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.

    Explicit Dependencies for Code with No Surprises

    Sometimes the idea we get when reading a class interface is different from what is actually going on inside its implementation, for example there could be several hidden dependencies. Making a class dependency explicit in its interface is a useful technique to make the code simpler to understand, and easier to test.

    Testing Realm apps

    Realm is a mobile database that, unlike CoreData, is easy to test. In this post we will discuss some ideas on how to test an app using Realm as its database.

    Specta global before and after each hooks (Updated)

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them. Updated for version 0.5

    Better tests with Specta

    Writing unit tests for our iOS and OS X projects not only is important, but should be always part of the development cycle. As such the way we write the tests is as important, and having the option to write tests that easily explain their purpose can drastically increase the quality of the suite. Specta and Expecta are two libraries that provide a different way to writing tests than XCTest, let's see what we can gain by using such approach.

    Xcode keyboard shortcuts for testing

    Keyboard shortcuts are easies way to start increasing your productivity. Let's look at how to run tests in Xcode without ever touching the mouse.

    The state of iOS testing in 2015

    In this post we'll look at the main tools and libraries available to write unit and acceptance tests for iOS and OS X applications, as well as the solutions to host Continuous Integration for our projects.

    Specta global before and after each hooks

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them.

    How to run Xcode tests from the terminal

    How to invoke xcodebuild to run the tests from the command line and how to format its output using xcbeautify or xcpretty

    mokacoding

    unit and acceptance testing, automation, productivity

    Posts tagged "testing"

    WWDC21: What's New in Testing

    A roundup of the testing-related new features announced at WWDC 2021. Including Xcode Cloud, how to test code using async/await, the new XCTExpectFailure and addTearDownBlock APIs, and the new Test Repetition configuration in Test Plans.

    How to test Swift async/await code with XCTest

    Swift 5.5 and Xcode 13 introduce the async/await pattern for concurrent code. This tutorial post shows how to write unit tests for asynchronous code in Swift using the XCTest framework.

    How to write better tests for Swift date comparisons

    Testing Swift date comparison code with XCTest can result in indeterministic tests because of the passage of time. To make tests robust and deterministic, decouple them from the system clock by injecting the reference date.

    How to manage complex inputs in your Swift tests with Scenario Builders

    When writing unit tests in Swift for complex objects, you may need to write a lot of setup boilerplate code in the arrange phase. Scenario Builders are a pattern that extracts and encapsulated all that logic in a single component with an English-like API. This tutorial shows how to build a Scenario Builder in Swift and looks at its pros and cons.

    Unit Testing Combine Publisher Cheatsheet

    Snippets to test the behavior of Combine Publishers in XCTest ready to copy and paste into Xcode

    How to improve your Test-Driven Development workflow by asking "Do I need this yet?"

    The "You Don't Need It Yet" technique to ship software on a schedule results in fast real-world feeback. The same mindset can be applied with Test-Driven Development to move between the Red, Green, and Refactor stages faster.

    Write better Swift unit tests with custom XCTest assertions

    The XCTest Swift testing framework has a limited offer of assertions. There's only so much you can do with XCTAssertTrue and XCTAssertEqual. This XCTest tutorial shows how to create custom assertions to make your unit tests and UI tests shorter and clearer.

    How to write unit test assertions for Swift Result values

    Result is one of the most useful types in the Swift language. Learn how to write better unit tests using Result in this XCTest tutorial.

    When experiments go wrong

    Scientist can learn a lot from failed experiments. To do so, they must be methodical and collect all sorts of information. Softwar developers can learn a lot from failures, too. What are the practicies that can make learning easier?

    How to bypass the SwiftUI App when running unit tests

    How to make the unit tests of your SwiftUI app safer and faster by preventing them from running the program startup flow. This will avoid all of the launch operations like network requests or reads from the local storage that would affect the global state.

    How to decouple unit tests from values that change frequently

    When the output value of a function changes often but the logic to pick it doesn't, adding a separation layer will make unit tests easier to maintain.

    How to run a single test in Xcode

    A collection of ways to run a single test or a subset of tests using Xcode.

    How to test view controllers navigation

    The answer to "How can I test that a view controller presents another view controller when something happens?" is as simple as defining a delegate.

    Better tests for delegates

    When testing delegates, we are asserting rigid implementation details. Here's a way to make those tests more flexible.

    Code Coverage Is A Broken Metric

    But you should track it anyways.

    Test doubles in Swift: dummies, fakes, stubs, and spies.

    An overview of the different kind of doubles we can use in our tests, and how to write them in Swift.

    How to split decision and action logic with the Swift type system

    There is a subtle way to overload software components, by making them both take decision and act on them. We can simplify these bloated components by separating the responsibility of taking decisions from the one action on them. This will result in leaner and easier to maintain software, and is made simple by the Swift type system.

    How to remove duplication from Swift tests with helper functions

    Some code ends up requiring a lot of duplication to be tested. You can remove it by using helper functions encapsulating the shared assertion logic.

    Streamlining tests setup with fixtures in Swift

    Keeping tests short and focused is important for the health of the test suite. A fixture method to generate instances with default values in the tests helps keeping the setup code short, focused, and readable

    Action focused protocols enhance testability

    Using protocols describing a single capability or action that can be performed is a way to enhance local reasoning and facilitate testability

    If you're not writing tests first you're missing out

    A look at the benefits of writing unit tests before production code, in other words TDD.

    Quick beforeSuite and afterSuite behaviour

    A look at how beforeSuite and afterSuite behave in the Quick testing framework, and the dangers of using them

    Quick beforeEach and afterEach behaviour

    A look at how nested beforeEach and afterEach behave in the Quick testing framework.

    Nimble: when to use waitUntil or toEventually

    The Nimble matchers framework provides two ways assert expectations on asynchronous code, this post explores when to use one or the other.

    XCTest closure based expectations

    Testing async code is not simple, but XCTest provides us with all the required tool. This post shows how to wait for an expectation to be fulfilled based on a Swift closure.

    How to use dependency injection for classes in Swift

    In Swift it is possible to pass a reference to a type itself, not just to an instance of it. This post shows how to use this capability to test legacy code.

    Using Swift protocols to abstract third party dependencies and improve testability

    Third party code can be hard to test, but you can use Swift's protocols to abstract its details and improve testability

    Getting Started With OHHTTPStubs

    Good unit tests are fast and deterministic. Testing code that hits the network could undermine this goal, but using OHHTTPStubs we can take back control of our tests. This post explores the advantages of stubbing the network, and provide a guide on how to do it with OHHTTPStubs.

    Why hitting the network is bad for your test, and what to do about it

    In this post we are going to look at why hitting the network from your unit tests is a bad thing, and introduce some way to solve the problem.

    Async Testing with Quick and Nimble

    A look at how to write tests for async code when using the Quick and Nimble Swift frameworks. This post is part of the Practical Testing in Swift series.

    Testing Delegates in Swift with XCTest

    In this second post of the Practical Testing in Swift we a look at strategies to test how objects call their delegate methods or set property on them.

    Testing callbacks in Swift with XCTest

    Prevent Unit Tests from Loading AppDelegate in Swift

    How to prevent the unit test target from loading the AppDelegate and have faster tests execution.

    Fixing Bugs Driven By Tests in Swift

    Unit and acceptance test are powerful tools that can be used to identify and fix bugs. Let's see how using a bugged Swift app as an example.

    /dev/world/2015 notes of a testing fanboy

    I attended /dev/world/2015 in Melbourne this week. It has been a great conference, full of very friendly and smart people. Being a test and automation fanboy I attended as many talks related to that topic as I could. These are my notes.

    Explicit Dependencies, Swift Edition

    A look at how to write classes and structs that expose their dependencies as initialization arguments in Swift.

    Explicit Dependencies for Code with No Surprises

    Sometimes the idea we get when reading a class interface is different from what is actually going on inside its implementation, for example there could be several hidden dependencies. Making a class dependency explicit in its interface is a useful technique to make the code simpler to understand, and easier to test.

    Testing Realm apps

    Realm is a mobile database that, unlike CoreData, is easy to test. In this post we will discuss some ideas on how to test an app using Realm as its database.

    Specta global before and after each hooks (Updated)

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them. Updated for version 0.5

    Better tests with Specta

    Writing unit tests for our iOS and OS X projects not only is important, but should be always part of the development cycle. As such the way we write the tests is as important, and having the option to write tests that easily explain their purpose can drastically increase the quality of the suite. Specta and Expecta are two libraries that provide a different way to writing tests than XCTest, let's see what we can gain by using such approach.

    Xcode keyboard shortcuts for testing

    Keyboard shortcuts are easies way to start increasing your productivity. Let's look at how to run tests in Xcode without ever touching the mouse.

    The state of iOS testing in 2015

    In this post we'll look at the main tools and libraries available to write unit and acceptance tests for iOS and OS X applications, as well as the solutions to host Continuous Integration for our projects.

    Specta global before and after each hooks

    An interesting and powerful, yet not at all documented feature of Spetca are global beforeEach and afterEach hooks. In this post we'll see how to configure them, and how to blacklist classes from running them.

    How to run Xcode tests from the terminal

    How to invoke xcodebuild to run the tests from the command line and how to format its output using xcbeautify or xcpretty