58

I'm a junior engineer, but I've worked at two companies now. In both cases I've found that my colleagues and I are assigned tasks with no thought put into the design before being told to do it.

Typically I spend about 90% of my time writing down on paper how I'm going to do the task, then the code sort of writes itself in maybe a day, sometimes two if I run into difficulties with an API.

Is there something strange about this picture? Is the design supposed to be the work? I don't really begrudge it, I quite like the designing of things.

But it seems to me it would be more productive to together as a team determine the design of everything to be done, and then everyone can go away and do it pretty quickly, this would put everyone on the wavelength, and so there would be less instances of interfaces not being as you'd like. I feel that once the design is done, the coding is essentially a series of 'write a function which takes in X and does Y', which anyone can easily do except perhaps in the case of some complex algorithm being required.

I am thinking of asking my team if we could try designing things up front, before assigning the work. But I am not sure if they will be up for this, or if it's a ridiculous idea and that's why I've not seen anyone do it.

  • 51
    It is always amusing for a graybeard like me to watch new professionals re-discover top-down design, waterfall development, and the documentation pyramid. – A. I. Breveleri Jun 6 at 18:00
  • 11
    "Designing things up front" is a trigger word for the agile zealots - Big Design Up Front (BDUF). Better avoid it. – Peter Mortensen Jun 7 at 17:40
  • 6
    @PeterMortensen avoid the phrase or avoid the action? There is nothing wrong with putting some design thought in up front, in fact I'd argue it's very necessary. Not to the nth degree that BDUF implies, but definitely figuring out the big picture and a rough outline of the system. – Paolo Jun 8 at 11:59
  • 3
    @Paolo: "zealot" implies people who overapply something as opposed to keeping things reasonable; and I suspect Peter was being hyperbolic for comedic purposes. – Flater Jun 8 at 14:19
  • 1
    You seem to be mixing two omissions in your question: the absence of prior design and the absence of prior interface agreement. Which (or both) of these are you proposing your team take on? – Eric Towers Jun 8 at 17:35

10 Answers 10

118

If you are assigned a task that has no design done for you then doing the design is part of your task.

This is not unusual. Design may have been done at some level but now the task needs it's own design.

Now please don’t take this as license to spend weeks alone doodling UML. You should create enough design so that you can see and communicate your plan. Nothing more.

You should also be prepared for the plan to fall apart. When you code and test you learn. Don’t rob yourself of that time to learn by making perfect diagrams no one asked for.

Done well, a design ensures you're pointed in the right direction before you put tons of effort into something no one wants. It's a check on how well you understood your task. Don't defeat this by putting too much effort into the design. Do just enough to show your thinking.

You know the design process is working when you’re discovering mistakes, disproving assumptions, and discovering work. If all you’re doing is making pretty pictures then it’s time to move on.

A great way to do that is to show your design to the team. Communicate well and they’ll help you find mistakes, bad assumptions, and hidden work. Listen, learn, and when needed, try again. It’s like making popcorn. When the popping stops it’s time to move on.

Presenting a design can involve the whole team but devising one is usually one or two people working on some small bit of territory that’s been carved out for them. Be sure to learn how to communicate with the other territories and you’ll find you don’t need the whole team for every detail.

Design is important regardless of the task or the teams development methodology. Even in agile. Even in chaos. It may be a screen mockup. It may be pseudo code. It may be stating your task in your own words. But, like every other development step, it must be useful, or it’s a waste of time.

| improve this answer | |
  • 7
    +1 for "hidden work" – MegaWidget Jun 6 at 15:23
  • 7
    Also just to mention: this is a good thing. Nothing more boring than to implement the design of another person. – lalala Jun 8 at 10:07
  • 4
    +1 for the popcorn analogy. nailed it. – Woodrow Barlow Jun 8 at 14:37
  • 6
    "Now please don’t take this as license to spend weeks alone doodling UML" - +1 because UML needs to be consigned to the dustheap. – Dai Jun 8 at 14:45
  • 1
    @Dai once in a while it's pretty neat, like nice as a starting point, but imho many programming courses on that topic put way too much emphasis on exactly following one of the uml diagram types and knowing by heart what what means rather than how to come up with a good visualization of the design/algorithm/user flow you need to describe. A good diagram can save a lot of words though and prevent bugs or help fix them! – Frank Hopkins Jun 8 at 17:12
31

There are parts of a design that are important to settle on early, like which library or service the change should go in, whether to create a new component or add onto an existing one, what is the interface between your code and code others will write, etc.

The deeper you get into the details, the more important it is to not settle it early. That's because you can design faster at that level by coding it. You learn things like, "Oh, that returns null when I thought it returned an empty list," or "This library call requires an ACL and I hadn't even thought about the permission model," or "This resource doesn't clean itself up. I'm going to have to rearrange things in order to deal with that."

In other words, people don't think about coding as design work, but it is. You just have to do it in small increments and not be afraid to do several drafts. That doesn't mean you don't need the broader design discussions. I don't know how many times I've seen a pull request where someone spent the last two weeks trying to accomplish something that would have been much easier or much more useful in another service.

However, those broader design discussions don't need to be lengthy. Usually for me, it's throwing a paragraph or two in chat to make sure I'm not heading off in totally the wrong direction.

| improve this answer | |
  • 5
    One team that I was a tech lead on, my most valuable skill was being able to cut off premature planning. Without me, they tended towards all-day planning meetings where they insisted on pinning down little details before making an estimate or committing to a task. I honestly think that the most valuable thing I provided for them was knowing the work well enough to say "hey, it's okay, I see a few reasonable ways to do this, and none of them will take vastly more effort than the others. Let's sort it out when we get there." – hobbs Jun 8 at 5:48
  • This. When I need to design something so detailed you can just straight code it down, I can do that myself when doing the design. Unless you have code in the tickets there will always be something that needs a design decision, and if just on the very local coding level: Do we use a variable that can be null? do we log on debug or info level? what to include? You're only done with the design once the code comes out of the pipeline. However, I'd say how much time the initial design phase takes depends on the context, i.e. the top level design can sometimes take as much time as coding it out. – Frank Hopkins Jun 8 at 17:20
  • 1
    On a different question, I think on this same Stack, somebody gave an answer basically as to why estimating time for software development is such a difficult, unreliable, haphazard task, compared to the same for other forms of engineering. The answer was that, whereas civil engineering or something spends a lot of time building the desired outcome from a straightforward blueprint, in software, you only spend a few seconds up to several minutes doing so. It's literally when you hit "Build" or "Rebuild" in your IDE. With software, 99% of the effort is spent on the design. – Panzercrisis Jun 8 at 21:03
  • 1
    @Panzercrisis: When large distributed systems are developed, months or even years of design pass before a single line of production code is written. Such systems often require a lot of financial and legal planning, extensive user studies and competitive biddings for different components of the system interfacing with hardware or other external entities. All of that work is mostly done by enterprise architects, analysts, information security specialists and interaction designers before programmers become involved. Your equation may have its merits for isolated parts of the solution, though. – Christian Hackl Jun 9 at 12:01
  • @ChristianHackl That's what I mean. – Panzercrisis Jun 9 at 14:08
14

Some teams design things together upfront.

It’s a balance. If the entire team designs everything, then you’re spending ~7 people’s time doing something that can usually be done by a junior engineer well enough.

But you’re right that it can leave things disjointed, and teammates not on the same page. And it can lead to worse designs since you’re only using one person’s experience rather than ~7.

So all teams tend towards some balance.

If you’re working on nuclear reactor control code, then you spend more time to make sure it’s right. If you have more junior engineers, then you spend more time to help spread design skill. But if you’re just handling comments on cat videos, you maybe don’t need a whole team designing that. If your great engineers will likely produce the same result as the group, of if they can adapt better to slightly askew designs maybe you don’t need to spend that time.

But one important thing you’ve caught onto: the design is the work. Writing out the code isn’t really where engineers provide value. And it is fairly normal these days for tasks to be assigned without design up front.

| improve this answer | |
12

The way software development generally works in a team environment is that some aspects of the design are decided up front, at a relatively coarse level. Then the finer details are left up to the implementing engineers.

The completeness and level of detail in the up-front part varies greatly. In defense or aerospace it can be very detailed. In .com it's usually very coarse if developers are highly paid employees. Inexpensive outsourced development requires more detailed up-front design.

It can be very useful to talk though designs with the team to "get everybody on the same page", as you say... but you shouldn't do this to nail down details that really aren't significant in the grand scheme of things. You still want to leave that stuff to the implementing engineers. That's what makes their job fun. You do this to make the initial design into a collaborative process.

As a junior engineer, you should be grateful that a lot of design is left to you, because it's guaranteed that you suck at it and you can use these opportunities to get better at it. When you have doubts, talk to a senior team member 1:1. If you have doubts about big things, discuss with the whole team. Bear in mind that there are a whole lot of senior engineers that also suck at design, so choose your mentors wisely.

As a s/w engineer in general, you should be grateful that a lot of design is left to you, because that gives you the opportunity to add more value. If some one can give you just a few words and the product comes out great, well, that makes you worth a lot of money. Of course in order for the product to "come out great", you will have to take the initiative to talk to stakeholders when necessary to make sure they're getting something they will like.

Finally, the idea that the team will be more productive if you design everything up front is absolutely false. Time you all spend making designs is time that you don't spend coding. The developers need "clarity of purpose" so they can go code. Once that is achieved, then they should go code. You seem to require a little extra effort to get to clarity of purpose right now. That's OK, but don't assume that everyone is in the same boat. Also, you probably overestimate the degree to which any detailed designs are actually followed -- most people don't read things that carefully if they're long. You probably also overestimate everybody's ability to design. Ideas you have before you write the code turn out to be wrong in many cases.

| improve this answer | |
3

At the end of the day, you are being paid to improve the status quo in some way, usually set down in tasks which have been inferred from high-level goals and split into manageable chunks. Everything you do at work should be oriented towards finishing those tasks. So if it's already clear that programming is the only way to finish some task then the code is the immediate goal, and any design needs to be done with this in mind. Balancing design and implementation is one of those tasks you can get better at for your entire career. It's like the classic maths problem of the lifeguard getting to the drowning swimmer as fast as possible: running straight to the water and then turning to swim in the direction of the beach-goer is suboptimal because running on a beach is faster than swimming. But running along the beach until the swimmer is straight out from the beach is also suboptimal. There's a middle ground which is the fastest path.

90% design could well be appropriate if the task has many variables, affect many existing parts, or involves anything unfamiliar (languages, data structures, systems, third party APIs, you name it). As an example, I'd be hard pressed to find a task in the current project where the design took less than 20% of the implementation effort, except for maybe some highly repetitive and finicky tasks which were well understood. But it sounds like your tasks are actually too big: if implementation is 1-2 days, and that is only 10% of the time it takes for you to finish the task, that means the task takes 10-20 working days total. That is a problem. On a well-managed project most tasks would be split until they can each be done in a day or two, otherwise there is just too much context, complexity and room for conflict with others' changes, all of which lead to higher risk.

| improve this answer | |
3

Your question is "is it typical?" The answer is "yes," but that's largely going to depend on the culture of the company. I've worked on teams that have been buttoned-up in terms of planning and feedback (usually via the project management method) and I've worked on teams that throw everything at the wall and see what sticks. The former is something I've learned to seek out when interviewing with companies, as companies that pursue the latter have generally been pretty rough places to work.

The Mythical Man Month by Frederick Brooks is the industry bible on what the standard supposedly should be, but in the long run it's going to be up to you to decide what style works best for you and find a team that fits with that. That's probably going to be a whole lot easier than trying to change your team's habits, in the long run.

| improve this answer | |
  • 1
    Reading "Mythical Man Month" is a must! While at it, also look up 'all' the human error / system failure literature to get a feel for the size of the tar pit.. Welcome to engineering. – Philip Oakley Jun 25 at 9:45
  • Also might be worth looking into the "Capability Maturity Model," although this doesn't apply to software development as much as it once did. – Dave Kanter Jun 28 at 1:21
  • 1
    The maturity model is a bit of a dry academic/management process model, which doesn't explain the problems it's solving, while the MMM is entertaining and illuminates where the problems come from. It's still worth readers reviewing the CMM. – Philip Oakley Jun 29 at 11:49
  • 1
    @PhilipOakley oh I agree, just trying to provide additional context. – Dave Kanter Jun 29 at 16:45
1

It's not unusual. The expectation is that you can perform all the design needed. How much design you need depends on your experience and on the size and complexity of the task. If you've done the exact same simple thing ten times before, no explicit design may be needed at all.

It is usually a good idea to figure out first how to proceed, have a plan (not quite a design) and check with someone experienced if that plan is alright. Wastes five minutes if your plan was fine, saves you many hours if there was something you didn't take into account.

Having a design is no guarantee that the design works in the end, so be prepared to through the design out.

Where you need planning ahead is when you have to agree on interfaces with colleagues. If your code produces data that your colleague's code has to process, then you better agree beforehand what exactly you produce and your colleague processes. And you better produce everything that your colleague needs.

| improve this answer | |
1

Software development is mostly communication between colleagues, including writing documentation.

You could suggest introducing literate programming techniques in your team (at least to document the API of the project) and try tools like nuweb (with LaTeX). Be also aware of Doxygen. Perhaps your team has adopted some software forge ?

Typically I spend about 90% of my time writing down on paper how I'm going to do the task, then the code sort of writes itself in maybe a day, sometimes two if I run into difficulties with an API.

Write not only on paper, but in some open format shareable with colleagues. So discuss and specify the API in written English. PDF, MarkDown, HTML5 (perhaps in an email) or some internal Wiki comes to mind for the documentation.

Is there something strange about this picture? Is the design supposed to be the work? I don't really begrudge it, I quite like the designing of things.

For large software projects such as GCC or the Linux kernel, the delays are a bit longer than a day or two for every step (they have mailing lists showing discussions). You are discovering agile programming and the V-model of software development.

Be sure to properly use a good enough version control system. I like git. And of course a good enough build automation tool (e.g. ninja).

Take some inspiration (after getting permission for that) from the source code of existing open source projects related to your tasks (you'll find some on github or gitlab).

Is the design supposed to be the work?

Be prepared to the fact that it will fail. Design bugs are the most costly ones.

The ratio design efforts vs implementation efforts is industry specific.

Safety critical software of Airbus or of SpaceX is not developed the same way as video games, or web-shopping services.

See also this draft report and the references inside it.

| improve this answer | |
  • As it turns out, coding itself is a form of communication, and code written for legibility can compete with other forms of documentation for utility. It might be hard to say that SD is anything other than 100% communication. You could even look at debugging as a form of miscommunication. – jpaugh Jun 8 at 17:32
  • While coding is a form of build documentation, it is usually rather poor at communicating design knowledge, pupose and intent, especially among the 'no-comments' coders. – Philip Oakley Jun 25 at 9:49
1

One thing I've understood years after experiencing it in real life is that the activities design -> implementation do not necessarily follow such sequence!

I've learned it during my formal studies, but never got consciousness of such reality until I've found (again) the terms "forward-design" (FD) and "backwards-design" (BD). The traditional understanding of the sequence to build a system is FD. Seems logical, obvious, inevitable. But perhaps such is appropriate just part of the time.

The rest of the time (and mostly when building large systems), FD is simply not possible. That, because our brain is not able to grasp a complex set of systems (complexity essentially means difficulty of understanding), and make them interact mentally. In such cases, one usually starts by building POCs (Proofs of Concept) in order to identify the complexities and divide the problem based on them. Building a POC usually provides the necessary inputs and understanding to proceed with... Design!

That's how Backwards-Design works. Coding something without a previous design helps identifying the elementary concepts and constraints that one should take care of during the formal design process. BD is quite common, few architects and engineers pay attention to the strategy, but if you have a previous design that you need to modify at a certain point because during the implementation you've discovered an issue, you are doing BD.

A couple of examples. We needed an overloaded communications broker, which should run in Java, c++ and python. How did we addressed the design? Just started by coding, because we had no idea of what we were facing, which was the real problem behind. As soon as we got to run our POC, then, we started the real design. Second example. We needed a tool to run tests in largely heterogeneous conditions. The process was the same. Tried a couple of solutions, investigated how other systems address such complexity and there we got it: the secret was finding the adequate layering to make the parts interact (there are hundreds of ways of diving and solving a problem, finding the right one is really an art). After that, formalizing the design was smooth sailing.

And perhaps more: for my personal experience (ymmv), design is an interactive process between the experience of the path vs. the target goal. That is, there's no pure FD or BD. They normally go together. When you design without a previous process of coding it's because you already have such experience from past implementation processes. If you can design something without coding, you are not; you are in fact basing the design on previous coding experiences.

So, independently of your position being a developer, or an architect, you will always end up making implementation and design. The only difference is who writes the document.

The main consequence I've got to experience from this learning is that the design period should not be exclusive with the implementation period in the planning document. Both should overlap. Such change has helped me relaxing about the design, and to be confident about being wrong, and helped me to make a weekly or a monthly deep revision of the design and the implementation. In addition, this approach goes perfectly with Agile!

An important note: this approach, for the construction of a complex system is not possible for someone not having strong programming AND designing skills. A lot of architects fail due to such cause. A good scrum master could compensate equivalent lacks in a team and make the members work as a single wise and experienced mind, though.

Second important note: solving a problem means essentially knowing how to divide it in parts that can be solved independently and individually. BD is the only methodical process to identify the complexities of a BIG problem and divide it in parts that can be solved independently. This seems absolutely evident, but it's not. A lot of technicians don't know how to divide a problem and make highly heterogeneous problem divisions, endind up with multiple simple parts and a few number of parts loaded with larger complexity. That is not dividing the problem: that is growing it. With the consequential budget growth.

| improve this answer | |
0

In Scrum a coarse design would normally be done in the 2nd part of the Planning meeting (Topic Two). You could propose to do this in the next Retrospective

| improve this answer | |

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