My advice would be to think in terms of black boxes. You should couch tasks in terms of what the developer can expect to receive through an API and what their code should output. What happens in the middle shouldn't be anything you concern yourself with. When the junior developer works out a solution they can run their idea past you, and if it sounds OK then they write the code. And then you can review their code. The minutia of implementation is not your problem any more.
However, you have to understand that not all places have the luxury of their junior developers being that competent. We've tried, and we've been bitten many times. I've done it a few times myself since I started managing a team. I give them responsibility, lee-way to make their little "component" how they deem (obviously sticking to basic coding standards, at least), and ample time to complete the work. Senior developers are also at their disposal to answer questions that may arise, or even plain design advice.
And even after all of that, we're left with a steaming pile of half-copy-pasted-from-elsewhere code that's been kludged together and barely works. Some of the code is just there because it was in the sample code, others are just leftovers from failed attempts. Almost as if they kept throwing code at the problem until it "worked". They don't even bother to take a cursory look at the framework method/function that they're utilizing to maybe understand what it does, if not how or why it does so.
I don't know, perhaps we're not doing something right as well. Or maybe we're just unlucky that we have quite a string of dud junior developers. Or perhaps I'm just ranting.
When people imagine code reviews, they imagine people analyzing code and haggling about coding guidelines. They are much more than that.
Code reviews are more about the meeting point and the excuse to talk about the software than they are about actually reviewing code. For projects less sensitive to bugs, my code reviews are not about trying to spot off-by-ones or buffer overflows. They are about discussing the problem, as perceived by the developer, possible mismatches between the developer's interpretation and the actual problem, the designed solution, how it fits the problem and how it fits the overall architecture, as well as the actual code.
The actual code review style can be as informal as an end-of-day five minute talk with each developer, all the way to the formal end-of-week review of work done. Have them fit your culture.
In the end, all that it matters, is: keep your team talking.
For example, they might not realise that they should be looking into the framework. They may be scared to ask stupid questions because they don't think they deserve the job in the first place. They got a bit of harsh feedback from someone who didn't take their level into account, and mentioned a whole bunch of things they'd never heard of before, and now they're running around in circles panicking. But not saying anything about it.
Obviously a lot of this boils down to "it depends on the person" and none of this may be true. But here are a few thoughts:
Take a step back and think about what the expectations are and whether those are communicated at all. Assign a specific senior developer as an active mentor, and coach them on how to give constructive feedback if they aren't very good at it (it's a growth opportunity for them). Suggest reading lists, talks, and examples of best practices - including stuff that makes working on a team smoother, like source control, etc. Pair program for the first week or two. Code reviews (as small as possible), design reviews, and even giving them less freedom at first so they get confident rather than overwhelmed. Check in frequently so you don't get a steaming pile that could hopefully have been avoided :)
For the first problem I would consider that after you give them a problem and they solve it have them white board it for you. Ask questions about how they handle certain edge cases or problems. If they haven't have them go back and figure it out.
For the problem with sloppy code have code reviews every few days. Just keep on asking questions about special cases, and giving advice on how to better structure code.
I think a lead should care about how their team is implementing the features they are working on, because as the lead, it's crucial that you know the ins and outs of the system - where I think we agree though is that a lead shouldn't care about how the work is done, as long as it's done within the project guidelines (coding style, consistent structure, testing, etc.).
You should be holding your junior developers accountable for writing tests for their code, ensuring that the test coverage is there, ensuring they understand what problem they're solving, ensuring they understand the approach they're taking, ensuring they understand the repercussions of the decisions they're making. This is how they advance from junior to intermediate and eventually to senior.
It is your job as the senior/lead developer to groom your junior devs to make the steps forward and eventually do your job. You shouldn't be telling them how to write the code. When picking holes in their code, it should be constructive, don't just to pick holes in it to pick holes in it, making them feel bad. The goal is to help them understand what's not up to par, why it's not up to par and what approach they can take to fix it. You should neither be writing code for them, nor should you be expecting they make every decision in the same way you would.
Start by flow charting your program, divide the task into a group of single statements tasks that can be described without the words, "and", "or", "but", etc. If you need to use those words, you need to chain tasks or make decisions.
After several revisions (3-4) you should have a nice overview of what the program should do, and how it will do this.
Selected tightly interacting objects, and combine them into modules. This will be very apparently visually if you followed the first step correctly.
Now you have your scrum/agile modules which can be outlined and given to subordinates, and tracked.
:.:.:
If the whole thing is a just a big ball of spaghetti, make a another revision. If its very very small you might be glossing over the technical details.
More recently, I've fallen back to frequent meetings and a wiki as the best way to work through this kind of activity - but it feels like there should be a better way.
"Agile" micromanagement is great if you're looking to bleed talent. Highly recommended if you're looking to reduce costs and don't care who leaves.
I don't think you can successfully break up programming tasks for junior devs, who can then independently implement them. It has two problems:
1) You either get a lot of code with incompatible ideas, or you do a lot of coaching.
2) The junior devs are not learning as much as they could.
So you should not try to do this on your own, but rather involve the people who will be implementing the project in the process. You can still design the system in your head in advance, but I think the best approach is to then discuss it with the people on the project and come up with the final version together. Maybe somebody will have a better idea, or just tell you something you missed. As you go deeper and deeper, you will keep discovering problems on the lower levels. Some things will remain unknown or require experimentation, but for most you can come up with a solution. I think it's very valuable if everybody on the team understands the big picture. If the application has a few completely separate modules, then you can do the lower level design in different groups, but it's still useful if the task breakdown comes from the people who will be working on the code. Doing it in a meeting, rather than a write up and review process, gives them instant feedback.
Regarding the task breakdown itself, I try to think of how I'd implement all of the code myself. That means thinking about what data comes though the system and where it can be used to set code boundaries, which parts are more important and which can wait, what would be the smallest presentable version and how can I move it further after it's done, do I have some non-code dependencies (business decisions, dealing with external services). I like to draw diagrams (mainly the data flow). Sometimes tasks are simply large and you can't do much about that, but you can at least some milestones for them.
This makes sense to me in a smaller company when building some web application, probably does not make sense in a different situation. (Sorry for a long comment.)
Completely agree. This will allow the person working on this component to make trade-offs as necessary. They may also catch things that you didn't think of when building the system ie: Separate individuals working on subcomponent A and subcomponent B may realize they can share a lot of logic/configuration - no need to duplicate it.
i suppose usually for me one guy (say techsupp or network admin) sets up the svn/webserver/db, one guy decides on frameworks, one guy writes the skeleton, one guy starts on the interface, art guy does art stuff, typically the lead dev is watching over all this and merging stuff and when ready gives orders and access to the repo. if theres at least some structure and one template or working file/interface the juniors will have more success imo.
Feature: User can register an account
Tasks:
- Registration page markup/styles
- Registration page JavaScript (form validation/submission)
- Registration API endpoint (validate properties, ensure user doesn't already exist, persist user model, send email confirmation).
Prerequisites: - Data access layer implementation
- User model
- App layout markup/styles
- Email service implementation
I agree with the lead setting up the initial project skeleton, but I'd take it one step farther and say the lead should also document the conventions for adding new modules/etc, so that the structure doesn't start to fall apart once the lead stops being the one managing it day to day.I encourage that sort of thinking from devs I'm mentoring.
I do this by giving creating a rapport where they feel comfortable asking questions. I do by having an attitude that part of my role is to help them be more effective. When asked a question, I drop everything to help them.
I then specifically give them problems that force them to ask questions. This in turn gives me the opportunity push the envelope with their thinking by asking them to answer their own questions.
So when I get asked a question on how to do something, I will ask them if they understand the goals and constraints we need to work in. I make sure they understand that first. Then I ask them for different ways of solving their problem, the pros and cons of each and ultimately what their recommendation is considering those goals and constraints. By that time they generally end up with the "right" answer, and sometimes something I wouldn't have thought of. What I am doing with that exercise is guiding them through the process of how to think about solving the problem. Soon when they come to me, they are already giving me options, pros and cons with a recommendation.
Sometimes I'm asked to decide about a difference of opinion between two devs. Making sure both have the same view of the goals and constraints is really important and most of the time aligning these solves the dispute. If not, then I will have one or both create a minimal test/prototype, time-boxed, that explores the problem. Then we evaluate the results together against the goals and constraints.
This has worked very well for me.
As far as breaking up tasks and delegating, it all depends on their tolerance for ambiguity. I usually start more junior devs with smaller, well defined tasks that have specific acceptance criteria. I adjust the level of definition based on their ability to succeed, but always do it in such a way that it forces them to grow.
This way they don't need to know the full system or even have access to version control; they just need to get their small goal completed, I can take care of the rest.
Over time, they can earn more and greater responsibility/access.
First, how to break up tasks. I write very small user stories. I aim for things that can be accomplished in half a day. This forces me to do two things. We now have smaller tasks with tangible end goals that actually produce something for the end user. These are usually easier for everyone, from management to intern to understand and follow through to completion. We also don't overthink a task, bite sized chunks are easier to digest, after all.
Second, as a few others hand pointed out, you have to trust your junior and mid level developers to complete a task on their own. Write the story in a way that they can understand what the end goal and tangible result will be. If you keep it small and discuss these openly, this will get a lot easier in a short period of time. Don't worry about the implementation details so much, that will come more in a second.
Third, (here comes the unpopular parts!) TEST! Preferably, at least in my view, use Test Driven Development. Enforce an cultural change of moving towards testing. This will document the code as much as anything and if a refactor needs to be done after a junior or mid level developer completes a task, the tests will facilitate that. It will increase your level of trust in their work as they complete tangible user story goals.
Fourth, pair program. You don't always have to, but heck after a while you might actually like it. Pairing allows you to riff off of one another. Junior and senior level developers can get a lot out of this, far more than just the junior learning something from the senior. If you are finding that your junior developers aren't "getting your style" pair for a while. You might start to understand them as well.
Finally, all of this leads to trust. Look, code bases will need refactoring. I am quite Senior and I am sure if I sat with your code, or you with my code, we would find areas where things could have been done better. Trust that if the code works and does what it needs to do according to the small tangible goals of a user story, and that when it has accompanying tests, you and others will be able to refactor it and make it even better over time.
That's the process of thinking i usually take. First, i'm gonna need a project. Then I'm going to need to instantiate a database. Then I have to create the controlling class. then I need to create the initialization. etc.
For the juniors, it helps a lot to have things more bullet point. they should be able to fill in the more minute details on their own, but do get fairly verbose. Break the work into a small logical scope, and then bullet point what needs to happen for it to be completed. And always explain why.
For the mid-level, be more general about it and have them define the tasks that will be completed. This is to give them more say in the process, enable checks & balances, and trains them to write tasks for juniors and mid-level developers when they are one day senior devs. And that's really what your goal should be.
Everything you work on is a means to make everyone below you better. If you know how to solve a problem, let someone else take a crack at it. If they get it wrong, or need some help along the way, you've already got an answer.
And of course, code reviews are an important feedback loop. But always let them maintain ownership. Its their baby. don't fix their code for them unless its more or less an emergency. Mistakes they make can often be reflected back as a failure of process, and not of themselves.
Try thinking in terms of strategies and tactics. The overall problem can be described in one high-level sentence of "what" to do. That's the strategy. That strategy can be described in one high-level sentence of "how" to do it. That's the tactic. Then that tactic can be broken down into 2-5 slightly lower-level sentences of "what" to do, which are strategies that are sufficient to meet that tactic. You may continue this for a few strategy/tactic levels. Eventually you have some medium-level strategies you can pass on to junior/midlevel people. But trust them to determine the tactic. If you give someone else a strategy and then tell them what their tactic is, you're micro-managing.
This is also roughly what a lot of refactoring and clean code is about. In a method, you don't want to mix levels of abstraction. Instead, a parent method should call inner methods that are named by what they do, while those inner methods in turn have the logic that is how to do what the method is named. And this can also continue on down to lower levels. When developing this way, you might even mock/facade some of these higher level methods/classes/functions/whatever so you can finish implementing and testing the higher level method/function/class/whatever that calls it.
A full-stack developer that hasn't quite made the jump to "architectural" thinking will often immediately and intuitively identify the lowest-level tasks that need to be done for a project, but like you've noticed, focusing on that implementation style doesn't really scale.
I like to break up tasks into what I hope is achievable in 4 hours. Always assign yourself as much (or more) of these sized tasks than those your assigning others, if you don't want to appear that your only a manager.
Re-evaluate these sizes often. Especially with a new project, new team, or new person. Maybe due to something you did not foresee right out of the gate, this 4 hour task is really a 16 hour task. Or possibly the other developer is working hard, and learning fast, but you just misjudged how quickly they can complete it in. In this scenario, the next time it comes to split up work (or if you really over-shot, you can re-split up what you gave them) remember this metric, and size it a bit smaller.
Depending on distractions, and how well the above process is tuned, I only hope for 1 of these 4 hour issues to be completed per day, while at the same time, looking at it over a week or two average, not daily, as many programmers do not work in a predictable linear fashion.
Over time as engineers progress and grow at their craft, what they may have been able to do in 4 hours, might be 20 minutes. As you work with others you will get a feel for this, and become more tuned into other people's forte's. Not everyone is good at CSS for example, even if you know how it works. So its not just about skill. The longer you work with people, the better you will get at carving out tasks that work for you and for them, and for the team.
So in summary, experiment with it, give yourself as much work, and in the same manner you delegate tasks to others delegate tasks to yourself. Re-evaluate the size of these tasks often, and try to create tasks that others can get done in a reasonable amount of time, so that they get the feeling of completing something.
Not everyone can be given a big gigantic month long task and not get lost in it, and on the other hand, tasks smaller than 4 hours, really start to feel (and take the energy) of micro-managing. The more senior the developer that has proven they meet goals on time and communicate well, these can be relaxed a bit, and you might find someone really prefers 2-3 day sized tasks, but can also be reliable in this manner.
Finally, ask them. You might be surprised.
Delegation is a skill. Matching problems to the capabilities of team members is a skill. Accurately recognizing the capabilities of team members is a skill.
These are all skills you can acquire, but they are all skills that you will do more or less poorly on unless and until you have sufficient practice.
You will also be very slow at it until you have practiced a while and gotten better. So you must recognize that at first productivity will decline, because it will take you longer to delegate than doing it yourself.
Is your work environment reasonably "safe"? (Yes, I do mean that in the "touchy-feely" emotional sense; this is important (not trying to dismiss the idea, just using glib humour to forestall inevitable negative comments - some people are uncomfortable recognizing we have emotions and are affected by them...)).
If so, take your team out to lunch, off site. Tell them what you want to do: Delegate more. Tell them why: So the team gets more done, so there isn't a single point of failure or just one person on the critical path, so that junior members can grow into senior members, to challenge people's abilities, to make better hackers.
Next, tell them that this means you need to practice chunking, delegating, managing, etc., and it will take time for you to get better at these things.
Now ask for their help. Work as a team to do these things.
Note: You may also need buy-in from your management before you proceed. They may view this as a risky change, if they like how things are. Depends how supportive they are.
It's totally okay to just talk to a developer about the problem and start sketching out your ideas, without necessarily knowing the specific tasks that you're going to assign.
The abstraction level of the tasks that you should assign will also come out of the level of discussion you're able to have with the person. Everyone has different abilities/amounts of domain knowledge/available time/etc., so there is never "One True Task List" for implementing something; it must depend on the developer.
Finally, it is deeply motivating for the person who's going to do the work to be an involved part of the planning discussion. It's important to anyone to have a certain amount of autonomy in their work, and making them be a part of planning is a great way to do that.
Stepwise refinement: http://en.wikipedia.org/wiki/Top-down_and_bottom-up_design
Both were written about by Niklaus Wirth, (co-)inventor of Pascal, Modula, Oberon, etc.:
http://en.wikipedia.org/wiki/Niklaus_Wirth
From the above page:
http://sunnyday.mit.edu/16.355/wirth-refinement.html
Not a panacea, but useful, and can be used together with other techniques like OOP / OOAD.
For smaller features, we'll have a Dev just implement it full stack. This takes for granted that a lot of the plumbing is there, i.e. Service Layers
It helps to have these conversation during Planning Meetings. This will help the Dev's involved to get a better understanding of the Stories and Tasks needed to implement.
Generally speaking, finding a way to communicate this will depend on the engineer. Someone very junior may require much more detail both in the technical design and the feature itself. Someone more senior needs less of that.
2. Review EVERY piece of code their write. Code reviews daily.