10

Writing a User object in Swift, though my question relates to any strongly typed language. A User can have a bunch of links (FacebookProfile, InstagramProfile, etc). A few questions around this.

  1. Is it good practice to wrap links in their own object?
    struct User {
       var firstName: string
       var lastName: string
       var email: string
       var links: Links
    }
    struct Links {
       var facebook: string
       var instagram: string
       var twitter: string 
    }

Or should they be loose? I know technically both ways are fine, but wondering if there is a recommended approach, in general--especially for readability.

struct User { 
   var firstName: string
   var lastName: string
   var email: string
   var facebookLink: string
   var twitterLink: string
   var instagramLink: string
}
  1. In a scenario like this, should links be a collection/list? I figured it should not be a list because there is a fixed number of link options available, and not a growing number. Is my thinking right?

  2. Is it good practice to place my networking methods inside the User object, like getUsers, getUser, updateUser?

I know these could be subjective, but I am trying to understand what the best practice around similar situations is. Would appreciate any pointers.

30

You will either need

  • zero of a thing,
  • one of a thing, or
  • an arbitrary number of the thing.

I'm shocked that your design predicts that the number of needed links will always be three and that you know what their names are forever.

What I'm preaching is called the zero one infinity rule. It might not be obvious at first but it's what tells me your design is not future tolerant.

I'd feel differently if there was something about these links that was special to them. Some special thing that I do different when accessing a facebook link that I don't do for a twitter link. That would make them different things. But that isn't indicated in this code.

That's why I'm not bothered by the email string. I know that is used in a different way then the links.

So until I see a reason to use these links differently I'm on the side of a link collection.

  • 4
    FacebookProfile, InstagramProfile, ... I think OP already answered the question. Its language is telling us that Users might have none or several profiles related to social netowrks. But the programmer inside him/her has turned this element into mere links. Why not a collection of Profiles? I agreed with CandiedOrange. You are assuming too much about the future. New social networks might appear. Actual ones might disappear. Users can go and come from one network to another. – Laiv Feb 5 '18 at 8:28
  • This is a guesswork. Say you want to use these profiles for social logins. Having the component Profile, we have where to start. Where to encapsulate information regarding the authentication and the current session with these profiles. This might be considered YAGNI or over-engineering, but worth nothing to think about it, see whether these features might be requested or whether they could provide value to our application. If not, just discard them. – Laiv Feb 5 '18 at 8:37
  • 1
    @Prabhu depends on why you're limiting it. My guess is only so many fit in the GUI. Which is fine. But don't limit the data structure because of the GUI. GUIs change on a whim. Data structures are costly to change. It really pays to get them right the first time. – candied_orange Feb 6 '18 at 17:37
  • 2
    That's the point. Just adopt those structures that will make possible future changes less painful. No more, no less. We, Candied and me say this because we (I belive) have faced similar situations often and we foresee possible features susceptible to change or evolve. Ultimately, you are the closer to the project and its future prospect. – Laiv Feb 6 '18 at 18:04
  • 1
    @Prabhu: Notice that you asked a question about good practice, not whether it is the most concise approach for your specific scenario. I'm usually on the side of avoiding over-engineering, but the cost of future maintenance (adding/removing links, updating the entity class definitions, ...) far outweighs the cost of implementing a collection of links. If you called your columns link1, link2, link3, the need for a collection would have been more obvious. However, the fact that you gave the columns a more meaningful name does not change the fact that it's a collection of repetitive data. – Flater Feb 8 '18 at 13:56
6

You are on the verge of falling into the "I see a technical possibility" trap.

Just because you see a common trait among items does not mean it makes sense to apply some aggregation on them. The aggregation should mean something. Not on a technical level but in your problem domain.

They are all links alright, but in the context of a user class, does that mean anything? No. It is just as meaningless as it would be to sub-group using classes named "strings" and "numbers".

The trouble with this kind of thing is it blurs your model. It forces the code reader to sever the meaningful from the meaningless, before having a full understanding of the domain.

No one ever talks about a user's links. It would be different if you would call your aggregation SocialNetworkIds. Because that would actually mean something, it would be a true property of User rather than an arbitrary technical collection.

  • Exactly what my doubt was that prompted me to ask this question. The only relation between the different links is that they would possibly be displayed together in the UI. So, in this case, you would suggest NOT to put them into a separate object right, but rather keep them directly under the User object? – Prabhu Feb 6 '18 at 16:56
  • 1
    I do not think it would be helpful in this case. You do not have a problem yet that justifies adding a layer of complexity. Were you to have a lot more properties, there might have been a gain in a grouping effort (with apt names for the groups). It is hard to tell what is appropriate without context though. The bottom line is it should make things easier. To understand and/or to proceed with whatever your next step in the development process is. – Martin Maat Feb 6 '18 at 19:42
  • I generally like avoiding over-engineering, but I do wonder: would you have said the same thing if OP had named his fields link1, link2, link3? The design of a data structure is independent of the name of the fields, so my example is functionally equivalent. It's a matter of futureproofing. YAGNI would generally apply, but if anything, social media has proven itself susceptible to viral popularity and changes. Avoiding redevelopment for every new popular social media site seems desirable. Otherwise, you risk falling into the "what's one more field?" trap, which can create huge debt. – Flater Feb 8 '18 at 14:02
1

In general, I think it would be reasonable to have the links be in their own struct if you are likely to apply similar operations to each of them, and particularly if you always perform the same operations on all of them. If they are for unrelated purposes in your application, then I would make them separate. For example, if they were the user's homepage, their health insurance provider's web site, and a link to their favorite news site, I probably wouldn't group them together as they seem unrelated. But for 3 social media sites, it seems like they will be treated similarly in an app, and as such should probably be grouped together. I would use a more descriptive name than Links though. (What type of links? For what purpose in your app?)

I agree with your thinking on #2. As mentioned above, if the number were to grow or become variable, a list or other collection would be a good choice, but not for the scenario you've described.

I would not place networking methods inside the objects that hold the data retrieved by the network. Where the data came from, and how to obtain it are usually irrelevant to the main purpose of a class. What if in the future you want to get some data from disk? Or want the user to enter it? Go far enough down that road and a simple User class has to have code to handle every possible method of data entry and retrieval. Just make a User class hold and maintain the data while it's in memory. Everything else can be handled by more appropriate classes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.