Before knowing about higher standards
in coding lets understand the difference between programming and software development.
While programming requires a knowledge of computer languages and algorithms and
data structures, all of which are very important, software engineering also
involves knowledge of projects, maintenance requirements, documentation
standards, software design, etc. The things that are involved in successful
software projects that are NOT actual programming.
For me, a critical distinction has
always come with Software Patterns. I've never met someone who was
"just" a programmer who had a grasp on what they are, and why they're
good. Conversely, most (albeit not all) Software Engineers that I've known and
respected have had a good grasp on Software Patterns, and understand why
they're such a good idea.
In general, the way I tend to think
of it is this: programmers program solutions. Software engineers take a
problem, and (usually) use programming to solve it. The difference is that at
least part of the responsibility for figuring out WHAT the solution is going to
be falls on the Software Engineers.
This article is not related to any
programming language, though the sample is written in C#. It can be
applied to any programming language including HTML, XML, SQL, C++, Java,
Python, scripting languages,...
Introduction
The following is an explanation of
the terms "programming" and "Software Development",
as I see it. (They are not necessarily the correct language definitions.)
Programming
|
Creating applications to perform a
certain task (tools).
|
Software Development
|
Creating professional applications
that are easy to use, expandable and easy to change. IOW - well
designed.
|
That might sound a bit pretentious,
which is certainly not my intention. Let's make that clear by saying that
"programming" can be useful, and is not "stupid" IOW you
can eg. "program" a very complicated, state-of-the-art
algorithm. However, when providing an application to the public one might
think of upgrading or re-writing that programmed application to a software development.
Let me finish the introduction by
saying that we are all guilty of some form of (dirty) programming at some
point. I certainly am not a saint in this regard. We should
however, be aware of this so we can improve if necessary.
Computer
Scientist
They write code (yeah I know it's
a bit of a bombshell). It may not be the prettiest or most well-factored
code, but it gets the job done. It is not about the design of the code or
"good" practices, it is about proving what they set out to
prove. A computer scientist is as much a mathematician as they are a
technologist (they have 31337 math skills), they don't just need to
know that stuff works, they have to prove it. Communication and people skills
are desirable traits, but not emphasized. Software process and team dynamics
skills are desirable traits, but not emphasized. They have good breadth of
general knowledge of their whole field, but they deeply specialize in one or
several narrow areas. In these areas they are considered world-class experts.
They work on stuff related to their research in their personal time.
Programmer
Programmers write awesome code.
Making it clean, well-factored and error free are very important concerns, but
not at the expense of getting the job done. It is all about knowing the meaning
of "good code" within their domain. They need to have some
math skills, but this is not a paramount concern. They need to know of good
(best) solutions to problems, but they don't need to prove it is the best
solution. A good breadth of algorithmic knowledge is imperative. They
have a depth of skill in a wide area of expertise and have reasonably good
knowledge of related areas as well. Communication and people skills are
desirable traits, but not emphasized. Software process and team dynamics skills
are desirable traits, but not emphasized. They work on personal software
projects they find of interest in their off time.
Developer
They write code. Making it
well-factored and clean is important, but other factors often take priority.
Math skills are very much optional, but it does help to be aware of common
problems and solutions related to the domain they are in. Communication and
people skills are paramount. Process and team dynamics are bread and butter
skills. They are consummate generalists without any truly deep
specializations. They are expert at finding ways around problems and
plugging components together to fulfill a set of requirements. In their
personal time they are either trying to build the next Facebook, or engage in
activities that have nothing to do with programming, developing, or computer
science.
- Developer are programmers to a greater or lesser
extent.
- Computer scientists are programmers to a greater or
lesser extent.
- Enterprise software is the domain of the developer.
- The Googles and Microsoft of the world are after
programmers (and to a lesser extent computer scientists). The developers
who end up there become product managers.
- RnD and academia are the domain of the computer
scientist (and to a lesser extent the programmer)
The thing to remember here is that
none of the three is derogatory or "bad" in any way. One is
not more or less desirable than any of the others. They are simply different
dimensions (with some crossover) of the field we are all involved in.
Particular personalities will identify more with one but that does not mean
that all three can't "bleed" into each other and combine
favorably. It is entirely possible to be both an awesome developer and a great
programmer (although it is difficult with so many important things to focus
on). In rare cases you may even get an all 3 in 1 type of deal, in which
case I'd love to hear from you, cause we should start a company together, so
that I can ride your awesomeness all the way to easy-street :). But no matter
where you fall, it is entirely possible to be highly successful if you fit
snugly into just one of the three.
What about a software engineer? That's just a subset of developer.
What about an architect? They design buildings and stuff, so I am not quite sure
how that's relevant :)
Background
I started thinking about this
article when I saw some of the "applications" in our sector and also
seeing some of the code snippets. The real trigger however was when I
heard colleagues talk in the hallway, saying that they didn't like software
developers because they always work with fancy machines (which the users don't
have), they overcomplicate things, ... Needless to say I was a bit
annoyed with this statement (Software developers are obsolete?), certainly
because it are these type of people that "program".
A second trigger was when I needed
to explain myself to a manager why something took so long or a recruiter on why
I am 'better' than the next guy/girl.
The explanations on why they don't
improve the application, are things like "not important", "it
does what it's supposed to", "not many will use it",
"deadline", ...
Basic things that I see as
"programming" are:
- spaghetti code,
- no n-tier design,
- not changing default naming (button1, button1_Click,
... ),
- no thought on UI design (icons, guide text,
consistancy, control location logic ... ),
- no thought on UI logic (tab order, mouse clicks, ...
)
- no thought about extensibility, re-usability, ...
- no Exception handling, logging, ...
- ...
However, "programming"
can be very useful in prototyping or personal projects, you could
then strip that application from unnecessary bits, clean it up and incorporate
it into a larger Software Development. (The hard stuff, finding the
correct '20' lines of code that build your fancy algorithm is already done)
Using the code
To illustrate what we're trying to
clarify we define a request for an application.
Create an application that will
add 2 numbers and present the output.
|
Before you continue I propose
you build this yourself without reading further. It is a very simple application.
... building code, ..., building code, ..., building code, ...
Done? Probably you
didn't do the above. No matter, we'll still continue the article.
In this screenshot, you'll see we've
met the request. You enter two numbers and press the add button.
Then it calculates the sum of the two terms and displays it in the third
textbox.
So what's wrong with it, just by
looking at the screenshot?
- controls are not aligned (subtle enough to
be extra annoying)
- window title is "Form1"
- window icon is the standard visual studio icon
But the difference between
"Programming" and "Software Development" goes further than
the obvious:
- The tab order is all wrong
- there are no tooltips, no guide text, ...
- there's too much empty space on the window and the
controls are placed a bit "at random"
- It can just add numbers, like requested (nothing
more)
- You can change the actual sum manually
And now, just for fun, try to provide
an alphanumeric character:
Oops...
To compare, we'll check out the
"Software Development" version of the same request.
Here we see that the same request
has been met, with the differences:
- all fields are aligned
- You don't need to press a button to perform the
calculation (less user action required)
However, don't overdo this. I personally hate applications that do too much for me, because it becomes hard to determine what is actually going on. (And is the application doing it correctly? Didn't I miss something? ...) - there is less empty space on the window
- there is some guide text (and not visible, but also
tooltips)
- not visible, the tab order is logical
- not visible, added tooltips
- added icon and changed window title
- the solution textbox is read-only and calculated when
any of the other textboxes or the combobox are changed
- this example allows +, -, x, / and %. If you're
argument is, the client doesn't want this, you're right, then build it in
and hide the other options for the user. The point is, if you
foresee a future request (eg. please also add subtracting) make sure to
foresee to easily modify the code to do this.
Now let's try to break this:
The second example itself can also
be improved, we could provide textboxes that do not allow any alphanumeric
characters, we could limit the textbox contents size to a certain number of
characters, we could allow operations on currency's, we could allow decimal,
octagonal and binary operations and so on and so forth.
Now we only stated the obvious of
what we see on the screen, let's dive deeper into the trenches of our job and
have a look at the code.
The programming example's code looks
like this:
public partial class Form1 : Form
{
public
Form1()
{
InitializeComponent();
}
private
void button1_Click(object sender, EventArgs e) {
textBox3.Text = double.Parse(textBox1.Text) + double.Parse(textBox2.Text)
+ "";
}
private
void button2_Click(object sender, EventArgs e) {
this.Close();
}
}
Let's sum up what's wrong here:
- use of default naming
- no error checking
- hardcoded addition
- no comments
Now let's have a look at the
Software Development code:
The GUI class
public partial class BaseMathOperations : Form
{
public
BaseMathOperations()
{
InitializeComponent();
ToolTip
tt = new ToolTip();
tt.SetToolTip(txtbox_term1,
"fill in term 1.");
tt.SetToolTip(txtbox_term2,
"fill in term 2.");
tt.SetToolTip(txtbox_solution,
"the outcome of the math.");
tt.SetToolTip(combo_operation,
"mathematical operation");
tt.SetToolTip(btn_close,
"close this application");
tt.Active
= true;
combo_operation.SelectedIndex
= 0;
}
private
void txtbox_term_TextChanged(object sender, EventArgs e) {
Calculate();
}
private
void combo_operation_SelectedIndexChanged(object sender, EventArgs e) {
Calculate();
}
private
void btn_close_Click(object sender, EventArgs e) {
this.Close();
}
private
void Calculate(){
//check
if all three necessary fields are filled in.
if( !string.IsNullOrEmpty(txtbox_term1.Text)
&&
!string.IsNullOrEmpty(txtbox_term2.Text)
&&
combo_operation.SelectedIndex
> -1){
switch(combo_operation.Text){
case
"+": txtbox_solution.Text = SimpleMath.Add(txtbox_term1.Text,
txtbox_term2.Text);
break;
case
"-": txtbox_solution.Text = SimpleMath.Substract(txtbox_term1.Text,
txtbox_term2.Text);
break;
case
"x": txtbox_solution.Text = SimpleMath.Multiply(txtbox_term1.Text,
txtbox_term2.Text);
break;
case
"/": txtbox_solution.Text = SimpleMath.Divide(txtbox_term1.Text,
txtbox_term2.Text);
break;
case
"%": txtbox_solution.Text = SimpleMath.Mod(txtbox_term1.Text,
txtbox_term2.Text);
break;
} //end
switch
} //end
if
}
}
The SimpleMath class:
public class SimpleMath {
public
static string Add(string term1, string term2){
string
retval = "";
try{
retval
= Double2String(String2Double(term1) + String2Double(term2));
} //end
try
catch(Exception
ex){
retval
= "not a number";
} //end
catch
return
retval;
}
public
static string Substract(string term1, string term2){
string
retval = "";
try{
retval
= Double2String(String2Double(term1) - String2Double(term2));
} //end
try
catch(Exception
ex){
retval
= "not a number";
} //end
catch1
return
retval;
}
public
static string Multiply(string term1, string term2){
string
retval = "";
try{
retval
= Double2String(String2Double(term1) * String2Double(term2));
} //end
try
catch(Exception
ex){
retval
= "not a number";
} //end
catch
return
retval;
}
public
static string Divide(string term1, string term2){
string
retval = "";
try{
retval
= Double2String(String2Double(term1) / String2Double(term2));
} //end
try
catch(DivideByZeroException
dbzex){
retval
= "cannot divide by 0";
} //end
catch
catch(Exception
ex){
retval
= "not a number";
} //end
catch
return
retval;
}
public
static string Mod(string term1, string term2){
string
retval = "";
try{
retval
= Double2String(String2Double(term1) % String2Double(term2));
} //end
try
catch(Exception
ex){
retval
= "not a number";
} //end
catch
return
retval;
}
private
static double String2Double(string val){
double
retval = double.NaN;
if(!double.TryParse(val,
out retval)){
retval
= double.NaN;
} //end
if
return
retval;
}
private
static string Double2String(double val){
string
retval = "not a number";
if(val
!= double.NaN){
retval
= val.ToString("0.00", CultureInfo.InvariantCulture);
} //end
if
return
retval;
}
}
This code is certainly not
perfect, but it is certainly a lot better then the first example.
- comments - check
- error handling - check
- division of logic (the arithmetic’s are handled by
another class)
- No default naming - check
- Better logic in UI design and can handle more than just
adding numbers. it also formats the result.
If you're stating by now that I shouldn't swallow my exceptions you're right. In the source I added a comment on top of the SimpleMath class:
/*
* Remarks:
* Normally
you don't swallow the Exceptions as done here, but in order to keep the code
simple, we don't handle them perse here.
*/
So indeed, you should never swallow
exceptions, but instead write them to a log file or database and/or bubble them
up to the user (in some formatted way).
This second example is certainly
longer then the programmed version, but if you look a bit closer, you'll see it
is not complex at all. The SimpleMath class can be reused, we
successfully separated GUI and business logic. (in real applications you
would probably split that into different projects).
In the end you spend time to
win time (later on)
How to achieve higher standards ??
So here are some pointers on "Software
Development":
How to achieve higher standards ??
#1
Do not start coding directly from a requirement, you'll end up with a program. Instead take a step back and look at all the angles, design your application (and take time for it):
- Will the
requirement likely be expanded in a certain direction?
- Does it need to
plugin to another application?
- What could be
reusable?
- ...
Keep the K.I.S.S. principle. Don't overcomplicate things. If you start feeling complexity, start re-thinking. Don't be scared to re-write bits of your code to simplify the further development. If you smell trouble coming, fix it before it starts stinking further down the road.
#3
If you need to implement a difficult algorithm, or want to check some features (get to know how a certain class works) create a new project and use "programming" to create a prototype. (Although "programming" does not imply you throw all the "software development" rules overboard). Only when you’re confident in your solution should you incorporate it into the final version. Doing this directly in the final version will result in a mess rather quickly.
#4
Clean up code regularly, take time to browse all classes and remove unnecessary comments or scout for complex code that you could do better and easier. In fact, do so immediately after reading this article.
#5
Very important: dare to question the requirement and/or your boss ! If you see problems coming or have a good idea you SHOULD communicate this. (IMHO this is what they are paying you for?) The boss/client normally has the final word, but you can say no, and if they really, really want it, well, you warned them.
#6
Test. You and/or someone else. You should not test if something works (it probably will), rather try to make it break! IOW don't test expected behaviour. eg. You can do this by taking the scenario steps of a user test and modifying them slightly. That is how I find the most bugs and we all know users never follow the rules on how something should be used.
#7
I'm all for defensive programming. Don't throw try/catch blocks for fun and try to limit out input from the very start developing "safe gates" along the way. eg. Integer input can be enforced via the GUI, can be checked in the business - and data access layers and finally can be enforced on the database level.
#8
As commented below, don't allow changes moments before the deadline. Setup a proper period of "code freeze" were (almost) no changes are allowed to the code. Be rigorous about this. It is even a good period to finalize all the other stuff mostly forgotten: documentation.
#9
It is good to automate some work for the user, but never forget that a user still remains the responsible person for his/her work. Never let yourself be drawn in discussions were managers want fully automated systems. Your code becomes exponentially more complex quicker than an improbability drive can take you to the restaurant. In many cases the end-users start complaining anyway and many changes will have to be reverted.
#10
You don't need to adopt every new shiny feature that comes along.
Conclusion
#1
As explained in the background section, you could use the information of this article towards your manager or recruiter. Furthermore, you can use the information to become more aware of doing things better and certainly simpler. Finally, be aware that applications can always be approved (take time to review your work later on), it can always be better and don't be too fast on your toes when someone asks you "why didn't you do it that way?" (Probably because you don't or didn't know or there was some reason for it)
#2
Doing "programming" or "software development" can mean the difference in people using your application or not. Don't take it too lightly.
#3
You can take this concept further into research, presentations (!), documentation, etc...
No comments:
Post a Comment