Driverless Dilemma

When applying 'the trolley problem' to driverless vehicles it is often posed that the vehicle would be in such a position where it would need to either ram through pedestrians, or drive into a wall. It is assumed that either event was assuredly result in the fatality of the pedestrians or the driver (extreme assumption given the safety inside cars and the speed the car would need to hit the wall). People can fall into the trap of forgetting how astronomically unlikely it is that such a scenario would occur. How often do you hear about the man that ran over a group of people rather than sacrifice himself? What about the other way round?

Read More

Good Practice with RxSwift & MVVM - Exposing Variables

Just a quick tip for the use of RxSwift within an MVVM architected application. Most people likely know to do this, but it never hurts to throw it out there.

In a view model, my instinct was to set it up like so:

public protocol PeopleViewModel {
    /// Drives a collection of person summaries (UITableView or UICollectionView for example).
    var personViewModels: Variable<[PersonViewModel]> { get }
    /// Whether or not the perople are people loaded.
    var isLoading: Variable<Bool>
    /// Whether there are any people.
    var isEmpty: Variable<Bool>
    /// Fetches people after a given index (useful for paginated responses).
    func fetchPeople(after index: Int)
}

Within the view, I would do the usual stuff:

private func configure(with viewModel: PeopleViewModel) {
    viewModel.personViewModels.asObservable()
        .bind(to: tableView.rx.items(cellIdentifier: cellIdentifier, cellType: PersonTableViewCell.self)) { (row: Int, cellModel: UserSummaryViewModeling, cell: UserTableViewCell) in
            cell.viewModel = cellModel
            viewModel.fetchPeople(after: row)
        }
        .disposed(by: disposeBag)

    /// etc…
}

However, this was poor enforcement of access control and from within the view, if I was evil, I could do something like this:

viewModel.personViewModels.value = []

All my people are gone!!!

What I really want is:

public protocol PeopleViewModel {
    var personViewModels: Driver<[PersonViewModel]> { get }
    var isLoading: Driver<Bool>
    var isEmpty: Driver<Bool>
    func fetchPeople(after index: Int)
}

The implementation of which would look like:

final class PeopleViewModelImp {
    let personViewModels: Driver<[PersonViewModel]> { get }
    let isLoading: Driver<Bool>
    let isEmpty: Driver<Bool>

    fileprivate let items = Variable([PersonViewModel]())
    fileprivate let isEmptyVariable = Variable(false)
    fileprivate let isLoadingVariable = Variable(false)
    fileptivate let apiClient: APIClient
    fileprivate let disposeBag: DisposeBag

    init(apiClient: APIClient) {
        personViewModels = items.asDriver()
        isEmpty = isEmptyVariable.asDriver()
        isLoading = isLoadingVariable.asDriver()
        self.apiClient = apiClient
        fetchPeople(after: 0)
    }

    func fetchPeople(after index: Int) {
        isLoadingVariable.value = true

        apiClient.fetchPeople().subscribe(onNext: { people in
            let viewModels = people.map(PersonViewModelImp.init(person:))
            items.value += viewModels
            isEmptyVariable.value = items.value.isEmpty
            isLoadingVariable.value = false
        })
        .disposed(by: disposeBag)
    }
}

Tada!

Now, in an ideal world, the fetching of the people would not be disposed of within the actual view model. The aim is to actually keep the view model free of a DisposeBag. For now, this is fine, and certainly an improvement over the original.