0

I often find myself ovewhelmed by questions, I'll explain my self in a practical example detailing how I think about my tasks.

I'm often critized on how I approach the problems, and the general consesus in my area is to program first and ship the product, if it fails, it failed, back to square one. By the way I wrote a simple example on how I think about stuff, consider that I often only receive tasks but I don't know what these tasks are attached to or more info about the project (documentation\analysis\pair programming) so I'm often "blind".

Example

TASK: Create a interface for a user, let's make it simple, it has to have a first name, a last name and a username which is firstname.lastname.

  • Okay, let's start, well obviously the class has to look like this:

from dataclasses import dataclass

@dataclass
class User:
    firstname: str
    lastname : str
    username : str
  • Seems good but aren't the first and last name part of a class Name? That would look neat

from dataclasses import dataclass

@dataclass
class Name:
    first: str
    last : str

@dataclass
class User:
    name: Name
    username : str
  • Wait, first name and last name must be capitalized in order to avoid people inputing data with random formats and the representation of them should be a display name, that would look better...

from dataclasses import dataclass

@dataclass
class Name:
    first: str
    last : str
    
    def __post_init__(self):
        for key, value in self.__dict__.items():
            self.__dict__[key] = value.strip().title()

    def _repr__(self):
        return f"{self.first} {self.last}"

@dataclass
class User:
    name: Name
    username : str
  • Hmm, the user could've also add more than one space in it's name, I should avoid that ...

from re import sub
from dataclasses import dataclass

@dataclass
class Name:
    first: str
    last : str
    
    def __post_init__(self):
        for key, value in self.__dict__.items():
            self.__dict__[key] = sub(r'(\s)+',' ',value.strip().title())

    def _repr__(self):
        return f"{self.first} {self.last}"

@dataclass
class User:
    name: Name
    username : str
  • Hmm, what if a norwegian guy comes to work with it's weird letters, or a guy from the emirates decides to join...

As you can see, I'm still working for good, but I'm stuck on the Name class for the eternity... When I get to the username class it will be too late and the problems will be even more... What about two people with the same name? What about the limits charachter for the given platform? What about...

6 Answers 6

4

I think the problem is in your definition of the task.

It's one of the hardest things to do when coming up with a new system - the "specifications", or "task" as you call it.

TASK: Create a interface for a user, let's make it simple, it has to have a first name, a last name and a username which is firstname.lastname.

This is unclear. For example: what is "simple"? why username = first.last? What will you do will all of this?

Let me offer you a better task definition:

Create an interface that allows to:

  1. sign up users (with username and password. username length should be between 3-256 chars)
  2. sign in - accept username and password and return a boolean
  3. delete user - user can delete itself from the db. the user must pass the username and password in order to delete itself.

And that's it. After you implement this basic thing, you have something in your hands.

Generally speaking, if you're practicing, go and borrow other people's task definitions. It's not easy to define a task properly, imo it actually requires to have the solution in your head.

Also, I think that learning about Agile development practices might help you create a better process of development. Agile is a more iterative approach, which basically comes to solve your problem, which is called "Waterfall".

Edit: In response to your clarification:

In the workplace, I would not do a bit more than what specified. At least when I start.

Reminder:

TASK: Create a interface for a user, let's make it simple, it has to have a first name, a last name and a username which is firstname.lastname.

I don't know python, so I'll try my best:

class User:
 first: str
 last: str

 def username(self): 
   return f"{self.first}.{self.last}"

That's it. Task is delivered! Wait for the problems to come, and when they do, DON'T change the code. Go the the task definition (which you saved for this moment!) and update it. Then, and only then, make the feature.

Now you might ask - "What about all the bad usernames I already have in my db?" Well, it will be probably be a simple fix - like running a one-off script.

The main idea here is to solve problems when they come - you can't prepare for everything, so don't.

This approach is radical, and in real life you do want to cover your ass a bit. For example, you would probably want to encrypt passwords in your database even though no one specifically said it was a requirement.

But limit this kinda of thinking to things with REAL consequences. For example, think about the consequences of what you said here:

people inputing data with random formats

What are the actual risks here? Who cares, really?

5
  • 1
    Thank you dror, as I pointed out, often the task definition isn't provided by me but from a manager that just states: do X in 1 day, for example. I'm often unaware of what's the background or if there are any specifics, I don't have control on the system as a whole, so I tend to write the code as fast as I can trying to clear up as many errors as I can. By the way, I agree and this cements my feeling that I need to have a clear path BEFORE I start coding. Apr 10 at 16:31
  • @FabioCraigWimmerFlorey I edited my answer, was a bit too long for the comments section.
    – dror
    Apr 10 at 17:29
  • 1
    You don't encrypt passwords in the DB. You salt them and hash them. That way there is no key to compromise them. Apr 11 at 4:42
  • @candied_orange is 100% correct. Lookup the "bcrypt" algorithm for a proper example implementation
    – dror
    Apr 12 at 19:15
  • 1
    "I'm often unaware of what's the background or if there are any specifics" - well, instead of asking tons of questions around several potential solutions, what you really should ask is about the background and the purpose of your task. When you understood the purpose correctly, you can probably answer most design questions by yourself.
    – Doc Brown
    Apr 13 at 21:16
1

Here's a question for you: why do you need the first name and last name?  (And why do you need a name at all?)

We should model for purpose.  Here, as yet, there's no clear purpose, just a presumption that you'll need this information.

I suggest avoiding modeling things you are thinking you might need but don't yet have any clear requirement for.

So, what is the bare minimum required?  I would submit only one thing: a unique username (but even that is a but of a presumption, since in some environments what we want is an account identifier/name and then (user) profiles associated with that).

When it comes to the requirement for having something along the lines of first name, perhaps the intended usage will make that more clear.  For example, you'd like to address them in a familiar way in the opening statement in an email marketing message.  But instead of requiring the user to separate their name into first & last, you could ask the user how they would like to be addressed in a salutation rather than presuming their first name is appropriate to use there.

Your concerns about foreign alphabets, etc.. are valid.  So, avoid customization based on culture, such as first & last name.  A simple string for the name, if you actually have a need for a name.

2
  • 1
    Hey Erik, thank you for your perspective, as I said I'm often blind to the purpose of the scripts I write, it just so happens that someone asks me to write something that does X, Y and Z, but they don't tell me why or if there's a relationship between X, Y and Z and so on. Apr 10 at 16:24
  • Not adding functionality that's not needed has a name: the YAGNI principle (You Ain't Gonna Need It).
    – Jesper
    Apr 11 at 8:37
1

You have trouble deciding when your code is "good enough" since it is always possible to introduce new abstractions and features.

The solution is to go for the simplest thing which satisfies the requirements given to you. By that measure, the first example is the best since it fulfills the requirements of the task.

1

Allow your boss to choose their own adventure.

TASK: Create a interface for a user, let's make it simple, it has to have a first name, a last name and a username which is firstname.lastname.

"Hey boss, this task will cause problems for the second guy named John Doe to sign up for the system. We need unique usernames to tell people apart. What do you want to do?"

if the boss says "Lets update this task and address this concern"  
  then work with the boss to improve the task description. 
if the boss says  "Just do what the task says. You're not paid to think"  
  then code the task, get paid, update the resume, and leave 

You have an obligation to fix this bug before it becomes code. Yes, that means you have to talk to people. No, that doesn't make you the boss. But if they can't make you understand why you're being asked to do something this silly and you can't make them understand why it's silly then someone has to go. Turning confusion into code just adds more confusion.

1

You're making incorrect assumptions about names which create work for you and frustration for the user. Some of those assumptions are in the task definition, which you might have no control over, but some are in the extra validations and clean-up you took upon yourself to add.

This is a contrived example, but it's close enough to the real world to teach us a lesson: Keep your code (and requirements) simple until you're shown that it needs to be complex.

0

You can just say "I worry about this later". You define the class Name, with the required interfaces, and a minimal implementation. You use that to finish your task. And you put another task into your backlog "collect and implement requirements for class Name".

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