UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Critiques Desired on my Checkpoint 6

Forums > 100 Days of SwiftUI

@xan  

https://www.hackingwithswift.com/quick-start/beginners/checkpoint-6

I missed a week from being out sick but am back and ready to go. Just finished my Checkpoint 6 and am looking for critiques and pointers, even if its over code style, etc. Any tips appreciated!

enum Gear: Int {
    // I want these to start from 1, this seems to get the job done
    case first = 1
    case second, third, fourth, fifth
}

struct Car {
    // Because these never change once a car is manufactured
    let model: String
    let seats: Int

    // So this cannot be changed directly
    private(set) var gear: Gear

    mutating func changeGear(to gear: Gear) {
        self.gear = gear
    }

    init(model: String, seats: Int) {
        self.model = model
        self.seats = seats

        // Do cars all start in first gear?
        // I'm a dev, not a mechanic =P
        self.gear = .first
    }
}

var wrangler = Car(model: "wrangler", seats: 5)

wrangler.changeGear(to: .second)
print(wrangler.gear) // prints "second"
print(wrangler.gear.rawValue) // prints 2

Thinking about code style, do you normally put initializers before methods, or after? I'm thinking it would be...

properties initializer methods

...since the initializer is ran before any methods can ever be run? Do people have a preference for code order here?

2      

@xan asks for critique:

Checkpoint 6 and am looking for critiques and pointers, even if its over code style,

The code below is fine. But I appreciate the comments. This shows that you understand that you don't understand the entire problem being solved. It's common that your customers will assume a great deal of you. Also some requirements lead to derived requirements. They're not specifially stated, but could be assumed to be requirements.

// Do cars all start in first gear?
// I'm a dev, not a mechanic =P
  self.gear = .first

As you guessed, when a car is in gear, it is moving. So, no! Cars do not start in first gear, they start from a neutral gear. The engine is running, but not connected to the wheels! As homework, add a neutral gear to your enum.

Also, you wrote this for changing gears:

mutating func changeGear(to gear: Gear) {
        self.gear = gear
}

It would be a Very Bad Idea™️ for your gear box to change from fifth gear directly to first gear. It would be a disaster to shift from fifth gear to reverse! There would be lots of broken gear teeth. So while it's legitimate to have a method to changeGear(to gear: Gear), your inner code should shift down one gear at a time until you arrive at your selected gear. To achieve this, you may consider adding Iteratable protocol to your enum. Also, as a derived requirement, does it make sense to change gears to the gear you are already in? How would you handle this in code? Think: guard statement.

To be honest, this is out of scope for the intent of @twoStraw's challenge. But you were looking for any pointers, or comments.

Also xan writes:

Any tips appreciated!

Consider using a first person voice 😜, often referred to as the active voice:

Try instead: I'd appreciate your tips and guidance!

Keep Coding!

2      

@xan has code style question:

Thinking about code style, do you normally put initializers before methods, or after?

To be honest, I think this is typically a team decision. If you're late to a development effort, you'll be forced to use what ever the team initially decided, even if those team members have all left for other projects. You're stuck with their initial decisions.

I've not written structs so complex that I've worried about where the init() code is placed. What has been your experience, or preference?

Documentation MARKs

I would add that if you're keen to maintain structure and readability, consider adding MARK: to your code.

Like so:

// MARK: Properties
let model: String
let seats: Int
private(set) var gear: Gear = .neutral // <- Start in neutral gear for safety

// MARK: -
// MARK:  Initializers
init(model: String, seats: Int) {
    self.model = model
    self.seats = seats

    // TODO: Verify gear requirement.
    // Do cars all start in first gear?
    // I'm a dev, not a mechanic =P
    self.gear = .first
}

This adds dividers into Xcode's pull down menu that shows properties and methods in a code file like Headings in an HTML file. You can easily jump from a method to your properties by selecting the MARK in the pull down menu. The line with just a hyphen is useful because it adds a dividing line and really lets your Init() code stand apart.

Mini Map

MARKs are also quite useful if you use the Xcode's mini-map feature. The Marks are shown with a slightly larger font allowing you to have a better view of where you are in your code file.

TODO

Please note I added another MARK to your code snip: TODO. This doesn't add a divider. Instead it adds a tiny clipboard icon. It's a note to future you that something needs your attention.

Hacking With Swift Article

Of course @twoStraws already has an article about this. Grab a cuppa and give this a good read.

See -> Code MARKs

Your mileage may vary!

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.