mirror of
https://github.com/MinimalBible/MinimalBible.github.io
synced 2024-12-21 06:08:19 -05:00
Two new posts, fixing some dead links
This commit is contained in:
parent
6182d282e8
commit
cd6237be9d
@ -1,7 +1,7 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Hold that thought..."
|
||||
modified: 2014-07-03 17:55:41 -0400
|
||||
modified: 2014-11-09 17:55:41 -0400
|
||||
tags: [delay, unit test, testing]
|
||||
image:
|
||||
feature:
|
||||
@ -13,7 +13,7 @@ share:
|
||||
|
||||
Hey all! Quick update:
|
||||
|
||||
I've been trying for the past few weeks to get unit testing enabled on the app. This unfortunately hasn't been going well, and there have been too many late nights on [StackOverflow](http://stackoverflow.com) and Google with no luck.
|
||||
I've been trying for the past few weeks to get unit testing enabled on the app. This unfortunately hasn't been going well, and there have been too many late nights on StackOverflow and Google with no luck.
|
||||
|
||||
The issues are entirely to do with Dagger and the `Application` lifecycle on Android. Currently, I need to inject mock objects into the `ObjectGraph` so that I can run the tests. Problem being, Dagger validates everything at compile time. Note that I'd have the same issues using any other dependency injection framework, it just happens that I'm using dagger right now. That being said, the only way to inject new objects is to `plus()` the original `ObjectGraph` and then store that back in the Application. I personally don't consider this acceptable - besides just being bad code (messing with the `Application` just doesn't sound like a great idea) I'm guessing I would run into issues later if multiple modules try to over-ride the inject for a class.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Replatform Retrospective"
|
||||
modified: 2014-08-02 22:11:40 -0400
|
||||
modified: 2014-11-09 22:11:40 -0400
|
||||
tags: [replatform, android studio, eclipse, hindsight, testing]
|
||||
image:
|
||||
feature:
|
||||
@ -25,7 +25,7 @@ So, MinimalBible was built from the ground-up all over again. It ended up not be
|
||||
Lesson 1: Keep testing in mind
|
||||
------------------------------
|
||||
|
||||
One of the things I was looking forward to in switching to Android Studio was getting testing working. The way I had originally structured the application, it was borderline impossible to use Mock objects. I have more of the specifics in another post **link here**, but here's the problem in a nutshell:
|
||||
One of the things I was looking forward to in switching to Android Studio was getting testing working. The way I had originally structured the application, it was borderline impossible to use Mock objects. Here's the problem in a nutshell:
|
||||
|
||||
**Problem:**
|
||||
|
||||
@ -40,7 +40,7 @@ One of the things I was looking forward to in switching to Android Studio was ge
|
||||
Lesson 2: Static objects are awful
|
||||
----------------------------------
|
||||
|
||||
Every enterprise application I've worked on, and most Android applications, all have a dependency injection system of some form. I've previously outlined a number of them **link here**, but I settled on Dagger.
|
||||
Every enterprise application I've worked on, and most Android applications, all have a dependency injection system of some form. I've previously [outlined a number of them]({% post_url 2014-05-07-framework-faceoff.md %}), but I settled on Dagger.
|
||||
|
||||
**Problem:**
|
||||
|
||||
|
50
_posts/2014-11-06-the-state-of-affairs.md
Normal file
50
_posts/2014-11-06-the-state-of-affairs.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: post
|
||||
title: "The State of Affairs"
|
||||
modified: 2014-11-09 20:18:47 -0500
|
||||
tags: [timeline, release]
|
||||
image:
|
||||
feature:
|
||||
credit:
|
||||
creditlink:
|
||||
comments:
|
||||
share:
|
||||
---
|
||||
|
||||
Well, let's get right to it! Development over the last couple of weeks has been slowing down a bit, and I wanted to give a couple of notes why, and why there's nothing to be concerned about.
|
||||
|
||||
Kotlin & Functional Programming
|
||||
-------------------------------
|
||||
|
||||
Gotta say, I've been a huge fan of Kotlin since discovering it. If I had to make a bet on where the future of Android development was going to take place, this is the language I'd stake it on. While it's not billed as a functional language, it's more than capable of being used that way. I've been doing some significant refactoring of the codebase, and it's so much cleaner not using Java.
|
||||
|
||||
But why functional programming? Recently I've been taking a couple online courses at Coursera learning about functional programming. It's seriously confusing at first (no mutable state? no loops?), but it ends up being incredibly powerful and beautiful.
|
||||
|
||||
So development has been a bit slow lately - I've been taking that class, and the homework takes a while. But, I'm becoming a better programmer, and that will make development for this app easier. And a whole lot more enjoyable. And now that the class is over
|
||||
|
||||
Going forward
|
||||
-------------
|
||||
|
||||
So, what will things look like going forward? Here's a couple of goals I'm setting for myself:
|
||||
|
||||
###Alpha release by November 30th###
|
||||
|
||||
The core of the alpha release has been done for a while now - I can download the Bible text and display it. I need to get the project roadmap updated (LINK TO PROJECT ROADMAP HERE) but it's there. There are a couple of things left that need to be addressed before I can say I've hit an Alpha point:
|
||||
|
||||
* Jump to text: Currently you can only scroll, the navigation drawer isn't functional.
|
||||
* Switch active book: You can download multiple books, but the system selects one automatically at start.
|
||||
* Startup time: If at all possible, I want to get the startup time down below 5 seconds. That will be hard, but the work needs to be done.
|
||||
* Language filter: Currently all available Bibles are displayed, switch that so only Bibles in a selected language are shown.
|
||||
|
||||
After this work is done, I will start giving the app to a couple of friends in order to make sure that it works on multiple devices.
|
||||
|
||||
###Beta Release by January 31st###
|
||||
|
||||
The Beta release will seek to be an app that I can actually functionally use on a daily basis. The only feature beyond the alpha that is absolutely critical is search functionality. After this, it will be minimal software for sure, but it will represent the core product of what I want to use!
|
||||
|
||||
Following this functionality will be a first release to the Play store. It's crazy to think that I might have an app in the store, but I'm looking forward to it.
|
||||
|
||||
Back to Work
|
||||
------------
|
||||
|
||||
So now that the online classes are over, I should be able to get some more development time in. The goals I've set for myself I believe are doable, looking forward to sharing this with the world!
|
125
_posts/2014-11-07-boundary-value-testing.md
Normal file
125
_posts/2014-11-07-boundary-value-testing.md
Normal file
@ -0,0 +1,125 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Boundary Value Testing"
|
||||
modified: 2014-11-10 20:20:43 -0500
|
||||
tags: [functional, core, shell, boundary value, testing]
|
||||
image:
|
||||
feature:
|
||||
credit:
|
||||
creditlink:
|
||||
comments:
|
||||
share:
|
||||
---
|
||||
|
||||
*Disclaimer: The ideas presented below were sparked by a presentation available [here](https://www.destroyallsoftware.com/talks/boundaries). Please, please check this out if you get the opportunity, this has been the single most influential 35 minutes in my programming life so far.*
|
||||
|
||||
Over the past couple of weeks I've been refactoring some of the MinimalBible codebase to use [Kotlin](http://kotlinlang.org/) more extensively. It's a fantastic language that I'm using to take the place of Java development. Much of the existing code is being replaced with functional programming yielding a clean codebase that integrates well with RxJava.
|
||||
|
||||
What kicked off some of this refactoring was the talk referenced above and an online class I've been taking on Scala. Functional Programming is strange at first, but I've been falling in love with it. Thinking recursively is downright weird, but the quote I found that describes functional programming best for me is [this](http://community.schemewiki.org/?scheme-fortune-cookies):
|
||||
|
||||
>Functional programming is like describing your problem to a mathematician. Imperative programming is like giving instructions to an idiot.
|
||||
|
||||
>--- arcus, #scheme on Freenode
|
||||
|
||||
So what does functional programming have to do with testing?
|
||||
|
||||
Splitting the Core
|
||||
------------------
|
||||
|
||||
At the heart of the presentation above is a distinction between what the author deems the *core* of a program as opposed to its *shell*. The idea is that a program should be constructed in such a way that its *core* is purely functional, but its *shell* can be imperative.
|
||||
|
||||
### What a program is ###
|
||||
|
||||
At the heart of a program is decision making. You have some form of inputs, whether a database, JSON stream, or hard-coded values. The goal is to produce some meaningful output, whether a database, JSON stream, HTML page, etc. How do you get from one point to the next?
|
||||
|
||||
However you do it, decisions need to be made. Maybe you only need to display the records that were created yesterday. Maybe behavior switches in a mobile application depending on whether you are connected to WiFi. All of these decision points create different possible outputs.
|
||||
|
||||
So the trick in testing code is to make sure that given the correct inputs, you get the proper outputs. This characteristically involves setting up an in-memory database instead of a real one, simulating a browser connecting to a server, and many different *mock* objects used to simulate the real things.
|
||||
|
||||
This often ends up leading to tests that take many times longer to set up the environment than to actually run your tests. Instead, what about tests that require no environment set up at all?
|
||||
|
||||
### Boundary Values ###
|
||||
|
||||
What I'm proposing sounds kind of crazy at first, but you can structure your app(lication) to need no environment setup whatsoever. **The idea is that you separate values from how you get them.** For example:
|
||||
|
||||
I have code in MinimalBible that needs to reload books from a server every 30 days, but only if you're on WiFi. If we split out the values from how they're obtained, you can do something like this:
|
||||
|
||||
{% highlight java %}
|
||||
int secondsInThirtyDays = 155520000;
|
||||
|
||||
// Functional Core
|
||||
public boolean doRefresh(Date currentDate, Date refreshDate,
|
||||
Int networkState) {
|
||||
if ((currentDate.getTime() - refreshDate.getTime())
|
||||
> secondsInThirtyDays &&
|
||||
networkState == ConnectivityManager.WIFI)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Imperative Shell
|
||||
public boolean doRefresh() {
|
||||
return doRefresh(
|
||||
new Date(),
|
||||
SharedPreferences.get("lastRefreshDate"),
|
||||
ConnectivityManager.getNetworkState());
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
The functional core is the only code we actually need to test. There are four possible branch conditions we need to test, and they're all very easy to test:
|
||||
|
||||
{% highlight java %}
|
||||
Date currentDate = new Date();
|
||||
Date shortDate = new Date(secondsInThirtyDays - 1);
|
||||
Date longDate = new Date(secondsInThirtyDays + 1);
|
||||
|
||||
int wifiState = ConnectivityManager.WIFI;
|
||||
int nonWifiState = ConnectivityManager.WIFI + 1;
|
||||
|
||||
assertFalse(currentDate, shortDate, wifiState);
|
||||
assertFalse(currentDate, shortDate, nonWifiState);
|
||||
assertFalse(currentDate, longDate, nonWifiState);
|
||||
assertTrue(currentDate, longDate, wifiState);
|
||||
{% endhighlight %}
|
||||
|
||||
So now we have a test suite that 100% covers our code and guarantees exactly what we want. We haven't had to mess with the system clock, haven't had to mess with network state, and there are exactly 0 mock objects.
|
||||
|
||||
We retain all functionality we originally intended - we can call `doRefresh()` in our application without having to worry about network state or current time. And we no longer need to write tests for `doRefresh()` - there's really not anything to go wrong, it just handles interfacing with the external API's.
|
||||
|
||||
Scaling Up
|
||||
----------
|
||||
|
||||
So far the only example of this principle I've given has been pretty trivial. The principle extends way beyond that example though. At its heart, the idea is to separate your logic from any external considerations. Then, when your logic is liberated this way, you are free to wire up the pieces however you choose.
|
||||
|
||||
For example, using the `filter()` function happens pretty often:
|
||||
|
||||
{% highlight kotlin %}
|
||||
val ints = List(1, 2, 3, 4, 5)
|
||||
val odds = ints.filter { it % 2 == 1 }
|
||||
{% endhighlight %}
|
||||
|
||||
Now all you need to test is the condition `it % 2 == 1`.
|
||||
|
||||
What I'm still working on though, is how granular to make this. The code below will yield a 100% tested solution, but is incredibly verbose:
|
||||
|
||||
{% highlight java %}
|
||||
public boolean isOdd(int value) {
|
||||
return (value % 2 == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public testIsOdd() {
|
||||
assertTrue(1);
|
||||
assertFalse(2);
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
I now have 6-8 lines of code (depending on how you count) to test 7 characters of code. This is awful. I'm working on how to scale these tests, but I really like the idea of having 100% coverage without complicated mocking.
|
||||
|
||||
Wrapping Up
|
||||
-----------
|
||||
|
||||
If you haven't watched that presentation now, do it. I'll even give you the [link](https://www.destroyallsoftware.com/talks/boundaries) again.
|
||||
|
||||
But I hope this explains some of how I'm refactoring the design of MinimalBible. I intend to take full advantage of functional programming for this app, because I think great things can come of it. I'll continue to keep everyone updated on how it's going!
|
Loading…
Reference in New Issue
Block a user