The Why
I mentor at a few different online courses, and a common theme I've noticed across quite a few of them is an odd "gap" in the training.
Some courses are a great introduction. They tend to do a great job introducing the "Web 101" stuff, the basics of HTML, CSS and javascript, and then there are some lessons about advanced data structuring in javascript or basic DOM manipulation. Then they get into things like frameworks and libraries.
Others are a solid full-spectrum, providing a stream of resources and references, working through from introductory HTML, CSS and javascript through using them together to build small projects, and building up to those frameworks, just as above.
But both approaches, while great in terms of sheer information, lack something that strikes me as vital. I'm hoping to start addressing some of that.
The What
It seems to me that a significant missing piece is "starting to think more like a developer." We are teaching some valuable coding skills, and regardless of which approach, the technical resources are great.
But there's a difference between simply coding, and developing.
Coding is, to my mind, sitting down at the keyboard and actually writing the code. The stuff that we are teaching. It is not only teachable, but its replicable. We can guide folks through the same series of steps, and they can find a similar way through those steps each time.
Developing is a bit different. Before I sit down in front of my editor to put on my coder hat, I should already be wearing that developer hat. When I am presented a spec, thoughts should already be percolating, bubbling up, considering the best strategy to approach the problem.
Coders think in code. Developers think in patterns. And that, it seems to me, is where I want to spend some time.
The How
As a developer, I need to think about a few different things.
- I need to stay aware of the big-picture;
- I need to be aware of the moving parts;
- I need to be constantly thinking about the data my project manipulates (the state).
Let's consider a concrete example, and one common to most courses: Building a calculator in HTML, CSS and JS.
As soon as a coder sees that, they're likely to be planning out their HTML, or figuring how to fire off button events, or thinking in code.
As soon as a developer sees that, while they might be considering code at some level, they're more likely to be thinking about the parts that make up the whole, and how they interact.
Good development is about planning. I spoke last time about the three original tenets of OO, Encapsulation, Communication and Late Instantiation, and good developers think about those things first:
- how can I encapsulate my parts so they don't interfere with each other?
- how can I enable my parts to communicate with each other, so each can respond appropriately?
- how can I make my parts reusable, and create more as I need them?
Developing the Calculator.
If we look at that, there are three main bits to it:
- A display;
- A keypad;
- A container holding the parts together.
As a developer, I think about those parts. I often start with a high-level brain-dump of my ideas, and refine from there:
* Components of a calculator:
* Display
* Upper display showing entire
operation until equals?
* Lower display showing current number
* Keypad containing different types of keys
* Numbers
* Operators
* Equals (still an operator, but
special case?)
* Special Keys
(C/AC/Backspace of some sort)
* Container or Manager
* Operations Stack
Not necessarily a displayed
component, but important.
That's a birds-eye view of the components of the calculator, and really, that's about it. There isn't much to it, when you break it down. But if we were to dive in and try to code it without a starting plan, we'd likely be quickly stuck.
Next, we look at the parts. The components list above is a good representation of the encapsulation we want - the display should be self-contained, the keypad should as well, and the calculator container should encapsulate them both.
The next step is to think about communication. How can the parts talk to each other?
This is planning out an interface, and to my mind is one of the more fun parts of developing. I am creating this thing, I am defining the "language" we use to talk to it, and I can "wish-list" whatever verbs I like here!
The Display
The display is easy enough: it might maintain its own internal state or display logic, but that isn't what we should be thinking about just yet. At this point, how do we want to talk to the display, and is there anything it needs to tell us in return? We might want to tell the display to update, for example, by passing in a single character of some sort. Or we might want to tell the display to clear part or all of the display. Let's start small:
* Display interface:
* update(string)
display the given string
* reset()
clear the entire display
* value
maybe a way to get back the currently
displayed value?
I think that'll do for a start. We aren't bound to that, if later we want to modify that interface, we can, but at the planning stage, that might work well.
Let's move on to the keypad.
The Keypad
Thinking about the communication from the keypad, things are pretty simple: we want to know if a key has been pressed, maybe the type of the key, and maybe the value of it. We could easily do this with HTML, CSS and JS, and I know more than a few of you are thinking about event delegation, having the keypad container listening for clicks on the child buttons and...
And you're right. We can do that. It's easy to get excited and to think ahead, and it's totally okay. It means we might be working on a good pattern, because it's easier to see the components and how to make them go!
But still, let's slow down. We don't know what keys we might have in the keypad, and again, we might like to encapsulate the behaviors here. So we think again: How do we want to talk to this keypad? Do we have anything we need to tell it? And how does the keypad talk back to us? Let's start with the known:
* Keypad Interface
* when a key is clicked, emit a notification.
Indicate the type and value of the key.
At this point, the interface will likely be the javascript events API, but we should keep an open mind.
Note that we haven't coded anything yet. We have simply defined our components, and we have started talking about their communication paths. In the container, we might start thinking differently, and even start thinking in code.
The container.
The display and the keypad are sibling components. Usually, they wouldn't know about each other. Done well, each part will work on its own without requiring the other, but allowing communication in and out.
That matters, because the container acts as the manager of those smaller components. It can handle communication from the keypad, and can notify the display about those communications.
The manager is the consumer of those components' interfaces. It uses the defined paths to facilitate communications, and might provide an interface of its own. At this point, it won't, but it could.
What it will do, though, is contain one more piece that neither of the others have. Neither the display nor the keypad have a true "state", in that they don't really need to track anything. The keypad passes a click notification, but it doesn't keep that event. The display updates itself on command, but it likely doesn't keep data about the data its been passed.
The container acts as a manager, not only of the components, but of the state of the calculator. In the comonents list above, the only entry under the container was the Operations Stack
, which represents the state of the calculator internally.
But rather than outline the interface the container provides, now's the time to think about how the container handles internal communications:
* Container Interface
* Keypad events:
* update the Operations Stack as needed,
* notify the Display as needed.
That's really it - calculators are a largely one-directional application. A key is clicked, the internal state is updated, and we tell the display to update itself.
Some particular applications or user stories might be:
* User clicks '9','4','.','3','+'
- at each click, the Operations Stack
(the state) is updated by appending;
- and the Display is updated with each digit,
or cleared when an operator is pressed.
* User then clicks '3','='
- the Operations Stack should append the
digit, and then collapse to a single
value for the equals;
- the Display is updated with the final value.
* User clicks "AC"
- the Operations Stack should be emptied;
- the display should be cleared.
So we can see each component part, and how it encapsulates its own functionality. We can also see ways in which those parts can communicate (an interface), allowing them to interact. By taking the time to pre-plan, by moving from being a coder to a developer, we save ourselves time and aggravation later.
It is common to refactor our projects, to revisit and post-mortem after completion - but its just as important that we pre-factor our projects, designing and developing with intent.
Next time, we'll start coding our component parts, building to a completed calculator project.
Top comments (11)
This is great model for how to break down a project.
Good development is about planning
100% agree.I like to mix in a prioritization step after I've laying everything out. Some items might be more essential than other.
Thanks for the great article. :)
When I see folks going through an online curriculum, and working on some of these projects, I cringe. Diving in and coding, and when this part starts getting wonky write more code to fix, until we are back to non-supportable spaghetti code.
I've been working for some time on trying to find that middle ground - how can we take the basic language skills we have, do some funky middle magic, and return a well-crafted final project?
Suggestions on how to teach the developer mindset?
It's a good question. I think allowing a certain level of spaghetti might actually be ok to start with. What's important is that they are learning and doing. If we correct too heavily and get pedantic about style too early on, they may get discouraged, disheartened. It needs to be fun! The reward of building something and seeing it work is what matters most.
With that said, how do we mix in teaching good patterns? I'd say as a quick follow. So once something is working, no matter how messy, celebrate that win! Then we can offer "Do you want to clean this up and simplify it?"
Refactoring and cleaning up code is a great teachable moment, there is both messy working code, and then the cleaned up working code.
I think this is a natural process. Even after 9+ yrs of dev, I start out a bit messy, hacky, then pause and clean up.
What are your thoughts? What have you been trying?
I am a huge believer in "You can't refactor until there's something to factor." I believe that as we learn, we see that things aren't always ideal as we start. When they ask, I'm always going to give guidance, suggestions to simplify and clean things up.
But I'm not going to tell someone on their second week coding that they shouldn't use three loops and a switch statement, if that is working for them. I'll suggest they make the time to revisit these projects in a month or two, and look at ways of doing some of these same things differently.
I also recommend using versions. Being able to show an employer (or to look back yourself) will show an evolution and growth of skills. It is great to see where someone is, but I like seeing how they've got there.
Been coding for nearly 40 years, been teaching in one form or another for the past fifteen. I was surprised to find that the combination is my happy place.
I agree with your principles, I think they are wise.
I love this, and will be borrowing this idea. :)
Thank you for the article, although I'm late here (coming from the-odin-project discord) after suffering from direct code implementations but I'll surely try these in my next projects.
Quick suggestion
Can you change the font style of the article. It's really hard to read
Nice content BTW
Thank you for the suggestion! I'll have to look into altering fronts in markdown. Wondering what it is about this post that makes it more difficult to read than any other dev.to article.
Sorry, i just found out that it was the font setting on my account. It's strange cause I've never touched it
Fixed it
Thanks for responding
Came here from The Odin Project Discord server. This is a great article, it really helped. Thanks Toby 🙏
Excellent, glad it did. It was more of an abstract piece than some of the others, but I think we need to explore both the theoretical and the practical.