lines of code?

J

Jared Dykstra

Andrew Thompson said:
If you could reduce a 100,000 line program to 5,000
lines without losing clarity in the code or introducing bugs..

_That_ shows proficiency.. ;-)


Not necessarly...

You get into the picky points of
if (condition) do something;
vs.
if (condition)
do something;
vs.
if (condition) {
do something;
}


It may seem like making a mountain out of a mole-hill, but these
styles are going to affect Lines of Code (LOC) A key aspect of
proficiency is not about how much code someone can write, or how
crafty the algorithms, and not always about how best to implement a
given algorithm.

A good developer understands the entire software development process
and knows that a project never entirely belongs to just one person
forever. Maintainable code speaks volumes about a developers
real-world experience. Along with a good design, comments, (use a
system like Doxygen or Javadoc if possible) variable/function naming,
and consistency (indentation, scoping, syntax, etc) are the small
things that create maintainable code. look at the following as an
example:

while (ctr < 10000) ctr++;
{
do = some stuff
}

If looking through thousands of lines of code to find a bug, it is
incredibly easy to miss the fact that this is a one line loop.
However, I do admit my example is contrived.

Of course if you're fearing for your job, then follow the "how to
write unmaintainable guide" found here:
http://www.strauss.za.com/sla/code_std.html
 
B

Bent C Dalager

You get into the picky points of
if (condition) do something;
vs.
if (condition)
do something;
vs.
if (condition) {
do something;
}

That just brings us back to the question of _how_ to count kloc. As
was mentioned previously, the naïveapproach would be to use "wc -l",
but noone who was intending to use the result for anything other than
amusement would do that.

Briefly put, a line consisting of only "{" or only "}" is not a line
of code because curly braces aren't code.

The alternative to this approach would be, in the "reduce 100kloc to
5kloc" challenge, to start by eliminating all inline documentation and
non-significant whitespace. This is clearly not desirable.

Cheers
Bent D
 
P

Programmer Dude

goose said:
[...snip much that was interesting and agreeable...]

I sometimes think that teachers should be emphasising, at
the start of every lecture, "use the right tool for the right
job";

I'd agree. Big part of the problem is that there is as much
variance among those that teach programming as there is among
those that practice it.

sounds like a shell of some type.

Not as I define shell, but in a sense, sure. It was more of what
I'd call an "automation". It monitored a shared directory for
incoming "jobs", read them, fired off the machining process (with
parameters from the "job request"), monitored that process to
check for lockups, failures or crashes, and--upon completion--
wrote a "job complete" file to that shared directory.
aha, a watchdog timer.

Yes, that was a big part of its task.
of course, if you had fork(), you would've been on a unix
machine, in which case you would have had mkfifo, and then simply
treated each communication as reading/writing files :)

Maybe. I didn't have control over the scanning and milling apps,
and THEY communicated by reading input files and writing output
files. And, sadly, the *filename* was a part of the required info.

No, they *weren't* well-designed.

Here's a horror story for you. Guy with a small start up company
my company took on as a business partner. Pity the managers didn't
involve any technical people in that decision. EVERY technically
trained person I met who met this guy almost instantly realized
he was a snake oil salesman. Managers ... took the hook, the lure
and a great deal of line.

After two+ years, millions of dollars (with literally ZERO return),
two contract failures-to-deliver, we did a "technology handoff"
(read: we own you and all that work--give it to us and go away).

During this time, going over their code, I asked this guy--who
claimed to Be A Longtime C Programmer--why he hadn't just used
break to get out of a for() loop.

"You can use break to get out of a loop?"

Aye-yi-yi.
 
P

Programmer Dude

goose said:
lets pretend that I did say "cars dont actually buy you
anything [as opposed to some other method of travel]".

you respond with "nonsense". the implication here is that
cars /do/ buy you something [as opposed to some other method
of travel].

I realize we're not talking about cars, but I'd argue that they
do indeed "buy you something" over other methods. You get speed,
cargo capacity and an enclosed environment that you control.

And I think--off the top of my head--that this combination of
things is unique. Other modes can, e.g., haul more cargo, but
I don't have control over them. Bikes lack shelter and cargo
capacity.
I then respond with "these here are the examples where using
a car instead of [some other method of travel] /does/ /not/
buy you anything".

So long as you remain in THAT problem domain, fine. But once you
consider all domains, I think a difference does emerge.

I've gotten the sense from this thread, that the real issue is
you just prefer other modes of transportation than auto. (-:

state-machines are nice. you *know* where you are with them.

I LOVE FSMs!
state-machines are as close to self-documenting code as
one can get.

But I'm not sure I agree with that! (At least, not the way I make
them.) State machines can actually be a little HARDER to figure
out (sans additional documentation), because they are a more abstract
representation of the problem.
a simple state-machine of the type:

state = start_state;
while (state!=end_state) {
switch (state) {
case state1: /* do state1, set next state depending */
case state2: /* do state2, set next state depending */
case state3: /* do state3, set next state depending */
case state4: /* do state4, set next state depending */
case state5: /* do state5, set next state depending */
case state6: /* do state6, set next state depending */
}
}

is all on one page/screen;

In a real one, only if you call functions in each state. IME, if
you keep all the code in the SM, it can be pages and pages long.

...can be used to "count" instructions to know exactly
*how* *long* the machine will execute for,...

What if the state is dependent on input? (Or do you mean in the
abstract sense that--given this input, this will happen.)
 
A

Alex Hunsley

I would say it was more a case that _that_ shows how bad the original
coding and design was...

Imagine how bad some (original) code would have to be if you could
reduce if from 100,000 to 5,000 lines with losing clarity of introducing
bugs...

alex
 
A

Alex Hunsley

Chris said:
I'd be inclined to agree in the general case, really... except that
we're talking about loop constructs, for goodness sake. If you want to
argue that everyone from the fair lady of Lovelace onward has been wrong
about programming languages, I'm afraid you're going to have to come up
with something substantial to say about it. Sure, presumption from
experience only goes so far; but it goes much farther when experience is
so universal as the dominating trend in programming language design over
the past 10 to 15 decades (approximately... forgive me if I don't have
exact dates for Ms. Ada's work on the Difference Engine).




The problem with the phrase "use the right tool for the job" is that
it's circular, and therefore meaningless.

Not sure I can see the circularity there... it's advice, not an inference.
Certainly, no one's going to
argue that, in fact, we ought to prefer the wrong tool for the job!

I founded the Foundation for the Misapplication of Computer Languages
(FoMCoL) back in the 90's for this exact aim. It'll have a new home on
the web sometime soon... the first project was a raytracer written in
prolog.
As
such, it gets somewhat tiresome to hear people always repeating it, as
if it had some meaning. You see, that's the problem with the right tool
for the job: everyone knows we ought to use it, but no one quite knows
what it is.

Exactly, and I think that's what people mean (in an unspoken way) when
they say "use the right tool": they mean, "be sure the tool you think is
right, is right!" or "be aware of the options".

alex
 
A

Andrew Thompson

....
Imagine how bad some (original) code would have to be if you could
reduce if from 100,000 to 5,000 lines with
'without'

..losing clarity of
'or'

...introducing
bugs...

...or typo's ;-)
 
J

Jared Dykstra

Alex Hunsley said:
I would say it was more a case that _that_ shows how bad the original
coding and design was...

Imagine how bad some (original) code would have to be if you could
reduce if from 100,000 to 5,000 lines with losing clarity of introducing
bugs...

alex


Why not remove all those pesky newlines and reduce it to one line?
;-)

Proficiency is not tersness, rather understandability; on rare
occasions the two are one.
 
G

goose

Programmer Dude said:
goose said:
[...snip much that was interesting and agreeable...]

I sometimes think that teachers should be emphasising, at
the start of every lecture, "use the right tool for the right
job";

I'd agree. Big part of the problem is that there is as much
variance among those that teach programming as there is among
those that practice it.

cause and effect ?

Here's a horror story for you. Guy with a small start up company
my company took on as a business partner. Pity the managers didn't
involve any technical people in that decision. EVERY technically
trained person I met who met this guy almost instantly realized
he was a snake oil salesman. Managers ... took the hook, the lure
and a great deal of line.

After two+ years, millions of dollars (with literally ZERO return),
two contract failures-to-deliver, we did a "technology handoff"
(read: we own you and all that work--give it to us and go away).

During this time, going over their code, I asked this guy--who
claimed to Be A Longtime C Programmer--why he hadn't just used
break to get out of a for() loop.

"You can use break to get out of a loop?"


<grin> sounds like someone on this group, doesn't it ?

goose,
mewwy chwistmas evewyone :)
 
R

Richard Heathfield

goose said:
<grin> sounds like someone on this group, doesn't it ?

Actually, it sounds a lot like me. :)

(In my case, it's through choice rather than ignorance, I assure you!)


[followups set]
 
G

goose

Chris Smith said:
I'm going to try to shorten this again to the core issues to avoid an
ever-growing thread that I have no time to answer. Let me know if I
leave out something that you think is important.

I know what you mean. this is a busy time of year for me too :)
Do you really mean that high-level languages with looping constructs are
a mistake?

No. I mean that 'trivial loops will always look like trivial loops
and complex loops which are implemented in some haphazard way
would be better off as a state-diagram'.
'while' considered harmful?
Nope.

Or, in any case, it sounds like
you're saying that at worst a state diagram of a loop is just as good as
the loop itself.

not that either.
I'm afraid you're going to have to make a very good
case for that one. Decades of empirical evidence demonstrate that
programmers prefer to work with normal loops and conditional statements.

yes, when they *are* normal loops and conditional statements. when
the body of the loop contains many conditional clauses which either
break, continue or set some flag and *then* break/continue, then
I would think that it wuold be better as a state machine.
And then I've spent five minutes trying to understand a piece of code,
only to find it doesn't do what I was expecting anyway! Wouldn't it be
easier if I knew this at a glance from the code itself?

if the programmer named his states, his routines and his variables
nicely, then you would have no problem knowing what the code
is *supposed* to do. its perfectly possible for a well-meaning
programmer to write code which is obfuscated by naming conventions.

e.g: you find a state machine called "sio_service". is it not obvious
that that state-machine is supposed to /service/ the serial port ?

It may not do what you are expecting (service the serial port) because
of a bug; but it is very clear what it is *supposed* to be doing.
Sure, but you can find out what you really need to know.

you agree then that its mightily difficult to draw diagrams to
check the flow of execution in a multi-threaded proggy ?

How else will I know where a/the bug might possibly be ? how else
am I supposed to figure out what the code is *supposed* to do ?

at least with state-machines, even if the original programmer
named everything in tamil, I can draw a state-machine and figure-out
exactly what it does in a few minutes for each machine.
That's the
point: you don't need to see the whole state of an application at once,
and threads give you the tools you need to separate concerns based on
process distinctions, without chaining yourself to a sequential form. I
just have to ensure that shared state is modified atomically to avoid
race conditions (which, incidentally, I also have to do when deciding
when it's appropriate to interrupt one task and resume another under
*any* approach to such a problem).


That's odd, because 1 and 3 seem to me exactly like *clear* advantages
of separating unrelated processing into multiple threads instead of
multiplexing state machines on a single thread.

ok. we have a processor that executes *exactly* 4 million clock
cycles per second. this processor is controlling a life-support
system that needs servicing *at* *least* 100 times a second.
Our processor has instructions that execute in mostly 4 clock cycles,
some in 8 clock cycles and a few in 12 clock cycles. lets also
assume that the life-support system communicates at 9600 bits per
second, that the code to take a full byte out of the incoming
register and place it elsewhere takes 8 - 80 clock cycles, and the code
to place a full byte into the tx IO register takes 8 - 80 clock cycles.
the "logic" thread can take between 80 and 800 clock cycles.

the rudimentry OS that you have allows thread creation, thread
deletion and the setting of thread priorities. however, like every
threaded environment that exists, you cannot tell how many instructions
of a thread will execute before being preempted. lets also assume
that context switching takes no more than 80 clock cycles

that leaves us with a worse case scenario of using 960 clock cycles
to use for a single recieve byte, process it and transmit byte, out
of a possible 4 million without threading, and 960 + 240 with threading
if we assume that we use threads.

lets look at point 1, real-time reactions.
you create a thread to tx data to the life-support hardware (from
now on the IO), another to rx data from the IO, and the last one
to do the processing (make the decisions).

a byte comes in from the IO. the rx-thread collects it and stores it
somewhere where the logic-thread can read it. the logic thread then
starts processing it, but at this point at least 80 + 80 cycles have
occurred. while the logic-thread is executing it is preempted, and the
tx-thread runs, finds that there is nothing to tx, so yields the
execution with only 8 clock cycles used, the thread-manager then runs
the rx-thread, which finds no byte in the rx holdnig register, and yields
the execution once again, then the logic-thread runs again for a specified
number of cycles, and the whole process is repeated.

after 1 full-second, it is not possible to know *exactly* how long
(how many micro-seconds) the logic-thread has been running for, *or*
*exactly* when the tx-thread will run. if the IO needs to get a byte
within, say, 8 microseconds, the preemption may not occur fast enough,
or may occur /just/ /before/ the byte is ready to be transmitted. i.e.
the logic-thread is preempted 1 clock cycle before the byte is ready to
be transmitted, the tx-thread finds nothing to transmit, the rx-thread
runs and recovers a byte, then logic-thread then runs and makes a byte
available to transmission, /then/ the tx-thread runs.

the life-support may have by then gone over the 8 microsecond barrier,
and something evil happens.

that is real-time with threads. you cannot foretell when anything
will run, so you cannot say with certainty that you application
can respond within a very tight timescale.

lets use the same example for point 2. if you stop the application
at *exactly* x clock cycles from the start, how do you know which
thread is executing, if you know the input that the program has had ?

it is almost impossible without tediously working out all possible
thread preemptions.

with a state-machine, you *know* for certain when something will
run. an interrupt routine will run *only* when the interrupt is
generated, not when a thread-manager decides to give it time.

there is also the problem that you may *overrun* a byte, due to
the thread-manager running some other thread when two bytes in
quick succession come in.
I don't even understand
what you mean by item 2.


Errr... well, that's because it doesn't actually *do* anything; you
haven't written any functional code, because all the functional bits
(that is, basically the whole application) go in the place of those
short comments. Besides that, there are only six states there. Try
implementing an actual application that way, even a trivial one, and let
me know if it fits on one page.

yes, theres six states. the thread example you gave had only three
threads.
On the other hand, I can write some trivial procedural applications
using loops that fit on one page.

And then, to get back to the original problem, show me the code for
putting together multiple state machines that can interrupt each other,

state-machines dont need to interrupt each other, only threads do.
telling me that threads are better because state-machines cannot
interrupt each other is kinda like telling me that submarines
are better than cars and asking me to show you how cars can "dive".

cars dont need to.

dont snip the following 4 lines
which use some shared data; and show me your strategy for arranging
exclusive access to that shared data, especially when some state
machines sometimes have to wait for data to be made available by other
state machines or from unpredictable external sources like keyboards.

keyboards are interrupt-driven, not thread-driven. keypads need to
be debounced, so a thread there does not make any sense, states do.
When you've actually taken difficult tasks that cause the now-famous
problems in multithreading and solved them with state machines,

like what ? all the famous multi-threading problems were *first*
solved with state-machines, not threads.
then you
can tell me about how the state machine solution is always better than
threads on a uniprocessor.

(once again, you use the word "always", not me).

ok, since you asked so nicely:
(i assume you wont understand mpasm assembly, so i'll use
a rough explanation + pseudocode).

I have an LCD module, a keypad module and a "main program" module.
after the appropriate setup routines have been run (lcd_init and
keypad_init), I only ever run lcd_state_machine and
keypad_state_machine (from the main program.

to display a character, I copy it into a buffer that can be
read by the lcd_module. the keypad module places the input
into a buffer that can be read from my main program.

main:
call lcd_state_machine
call keypad_state_machine
if (keypad_data) {
; process data state
}
bra main

now, the maximum time (from the main label) that it will take
to reach "process data state" is the worst-case-state-for-lcd +
the worst-case-state-for-keypad. if lcd needs to be serviced
*at* *least* every x microseconds, I can guarantee it so by
creating more states for keypad/process data with fewer instructions
in each state.

please dont snip this bit:
show me how threads can give this guarantee.
Oh yeah, then you can go about explaining how you plan to use third-
party libraries that are not aware of your radical plan for handling
concurrent tasks.

what radical plan? which third-party library cannot work with the
above? if real-time is needed, most real-time libraries come
/with/ guarantees about their execution. a few come with callbacks
instead, so you can supply you own IO code for some of it.
What if one of them spends too much time doing some
calculation and doesn't return to your control routine so as to let
another more important task run.

that is a problem in your states, split them up.
Which, it seems obvious, is only necessary because it's *not*
immediately clear from the code what the programmer had in mind.

it depends on the programmer who wrote the original. a state-machine
called "uart_service" is very obvious.
A
state diagram is no easier to understand than high-level code in most
languages, if that high-level code is written naturally using block-
style flow control.


Not bloody likely.

why not ?
most real-time environments *demands* it.
Are you still writing code using non-optimizing
compilers for 6052 processors?

no. i *do* write code for a few microcontrollers, and
a lot of the code is written in assembly. one can usually
persuade a c compiler to generate an assembly listing at the
drop of a command-line flag.
Modern environments include multiple
levels of data caches, very complex pipelining, and smart optimizing
compilers that reorder and rearrange most operations anyway.

no, only the more powerfull processors. you are possibly thinking
only in terms of desktop/server computers ?

your microwave does not possibly have anything more substantial
than an 8-bitter. these low cast chips *dont* have all those things.
Simply
put, except in hard real-time environments where you disable most all
features of modern computing environments, benchmarking is the way to
measure performance.

very true, but I *am* talking hard real-time environments.
Is this a problem in your code?

no. but you *did* mention writing a protocol stack that was
/recursive/. how can you easily guarantee that the thread does
not hang forever on malformed input ?

(the recursive bit, istr, was to show why it *had* to be a
seperate thread).
Most people have no problem writing
for/while loops that finish either. Threads don't make that appreciably
harder.

no, they dont, but neither to they make it any easier.
Basically, I think you're taking some problems that arise from very
complex applications written using threads, and then pointing out that
it's easier to write very simple state machine apps than to solve those
hard problems.

ok. wrt to simple problems: they are easier to write *without* threads.
wrt to complex problems: they *may* be easier to write without threads.

the main problem that I see here is that you think only in terms
of threads : "show me how you can do X without threads" have been
the tone of some of your posts, nevermind the fact that X is not
an issue if you dont use threads.

(please do not snip this either, respond to it).
as an example, consider your request for me to show you exclusive
access to shared data without threads. it has not even occurred
to you that without threads, *all* accesses are exclusive.

goose,
 
G

goose

Programmer Dude said:
goose said:
lets pretend that I did say "cars dont actually buy you
anything [as opposed to some other method of travel]".

you respond with "nonsense". the implication here is that
cars /do/ buy you something [as opposed to some other method
of travel].

I realize we're not talking about cars, but I'd argue that they
do indeed "buy you something" over other methods. You get speed,
cargo capacity and an enclosed environment that you control.

And I think--off the top of my head--that this combination of
things is unique. Other modes can, e.g., haul more cargo, but
I don't have control over them. Bikes lack shelter and cargo
capacity.

fair enough. I suppose that threads do indeed buy you
something, but it is normal to see them used in situations
where they *dont* buy you anything.

you dont see the average commuter getting an 18-wheeler
Mack to use to work, do you? threads are the code equivalent,
I should think, where constraints demand it. unluckily for
the maintainer, most programmers seem to be clueless as to
when they should use a particular paradigm/programming language/
method/design/etc.

I've always (in this newsgroup, at any rate) maintained
that X[1] can not always solve every problem, but I've come
across many people who believe that their X can solve
perhaps /most/ problems.

In fact, I doubt that there is or ever will be a single X
out there that can solve 75% of problems elegantly, or
45% of problems neatly, or 5% of problems at all.

[1] insert your favourite language/paradigm/etc here
I then respond with "these here are the examples where using
a car instead of [some other method of travel] /does/ /not/
buy you anything".

So long as you remain in THAT problem domain, fine. But once you
consider all domains, I think a difference does emerge.

of course; I assume computer science + embedded dev. as
my domain. I never intended to say that my arguments are
the same when the domain involves desktop/server machines.

I've also been very carefull wrt assuming the OS on the hardware
(never assumed linux, or windows); sometimes I even assumed that
there *was* no OS.
I've gotten the sense from this thread, that the real issue is
you just prefer other modes of transportation than auto. (-:

not really :) I'm just on my life mission again: to question
anyone who thinks that there X can do it all :)

(which is why, i suspect, that I may come across as a bit of a
troll).

with EGN, i just gave up. some people *dont* want to be educated
any further.
I LOVE FSMs!


But I'm not sure I agree with that! (At least, not the way I make
them.) State machines can actually be a little HARDER to figure
out (sans additional documentation), because they are a more abstract
representation of the problem.

but you blindly follow the states in the code and draw out
the machine on paper. no thought required ... and voila!!!
at the end, you have a pretty fine idea of what the code
does :)
In a real one, only if you call functions in each state. IME, if
you keep all the code in the SM, it can be pages and pages long.

in a small one, I might do it as above (so that it at least
fits in a single function. with a larger state-machine, I'd
use function pointers, with all the state functions in a single
file. either way, the logic behind the code is easy to get at.
What if the state is dependent on input? (Or do you mean in the
abstract sense that--given this input, this will happen.)

yes. given input XYZ to state-machine SM which is currently at state
A, it is possible to foretell how many machine instructions will
execute before reaching state C, or if it will ever reach state C.

I must say that I /am/ surprised that, until reading this thread,
I had no idea that professional programmers implemented higher-level
protocol stacks in a manner other than a state-machine. I've only
ever seen that in junior programmers.

goose,
merry christmas
 
G

goose

Richard Heathfield said:
Actually, it sounds a lot like me. :)

_Actually_, I meant the "longtime c programmer who is clueless", but
of course has written a c compiler himself :)

(now that I think about it, the "longtime programmer who is clueless"
syndrome is digustingly widespread).
(In my case, it's through choice rather than ignorance, I assure you!)

and thats a rather big difference :)

goose,
merry christmas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,122
Latest member
VinayKumarNevatia_
Top