First class developer: who ?

A

Arne Vajhøj

No argument here.

Here we diverge. Despite spending my working life in IT, I'm a scientist
by training, not a mathematician.

I work on the principle that a software design is a hypothesis from which
true and false predictions can be made. Code written to implement the
design is then exhaustively tested against the predictions to verify the
correctness of the design.

I somehow doubt that you always test and never deduct.

Arne
 
B

BGB / cr88192

Mike Schilling said:
My degree (taken many, many years ago) is in mathematics. I don't use
much of the math itself, but the discipline of writing proofs, that is,
making sure each step follows logically from the previous ones and that no
special cases are omitted, is something I still use every time I write a
piece of code..

IMO, there is a bit of a difference here...

"one step follows logically from the previous one" is a bit different than
the sort of bizarre hybrid of predicate logic and set theory I have been
faced with on several occasions... (I barely understand the notational
aspects, much less how exactly this thing is supposed to work...).

granted, this may be because I am apparently too stupid to really grasp
set-theory...


my approaches are far more informal, but tend to work well enough.
 
B

BGB / cr88192

bugbear said:
Try graphics programming (both 2D and 3D) sometime!

I have done both...

making use of vectors, matrices, and quats, is trivial vs the things I have
been faced with...

one can view the vector as a collection of values, and the operations as
operating on these values.
then they can "black box" the thing, and use these representations and
oparations as if they were basic operations.


but, I was faced with a case where vectors were defined in terms of a huge
mass of set notation and where calculations were nowhere to be found, and
this is not the math I am looking for...

one doesn't need to know much math to work with vectors, as in their basic
form, they are intuitively understandable...
 
B

BGB / cr88192

Arne Vajhøj said:
I completely disagree.

Developers that google solutions and copy paste them and generally
consider the computer a black box may not use math.

they probably don't use much of anything, FWIW...

But developers that like to understand what they are doing and
why will be thinking math every hour at work whether they
realize it or not.

the aspects of math used in computers, however, is very different from what
one typically runs into in math classes...

"subtle" connections are not usually of much particular relevance, as
usually it is the overt details which matter in this case. in many respects,
comp-sci and math differ in terms of many of these overt details.

Picking correct collection based on big O characteristics and
using relational databases are extremely common. Both build
on a strong mathematical foundation.

and neither are particularly math, FWIW...


this is about like arguing that someone has to understand convergence and
divergence to make use of things like the taylor series.

the taylor series works regardless of whether or not one understands
convergence...

one can think more simply "well, the denominator gets bigger faster, and
eventually the value of each term approaches 0", and leave it at that.


one probably doesn't really need to understand differentiation or integrals
either, FWIW...

after all, when one has a 'for' loop, it all becomes a little moot...


it is also far more useful to note that, for example, compound interest can
be implemented with a for loop, than to note that it can be modeled with an
exponential function.

....
 
B

BGB / cr88192

Tom Anderson said:
I think the person who said that is probably a prat.


Only a fool closes the door on an idea.

Mathematical concepts can be useful at times in software development, and
so the wise programmer makes them a tool in his toolbox. Your dismissal is
as misplaced as his elitism.

I guess one can clarify what they mean by "math".

there is a lot that is arguably math which I have noted is rather useful
(say: vectors, quaternions, matrices, ...).
similarly, nearly all manners of "calculating stuff" and "doing stuff" can
be useful with computers...


what is not so useful though is the sort of ultra-abstracting anti-reality
aspects of math, where one forsakes the thing being described for a big mass
of set notation or abstract logic.

IMO, this side of math is not particularly useful to the greater goods:
"make it work" and "get it done".


I would almost rather be stupid than live in that sort of "reality"...
 
A

Arved Sandstrom

Arne said:
Arne said:
On 12-03-2010 05:26, Arved Sandstrom wrote:
Both terms actually have clear English meanings - "equality" means (or
should mean) that two things *are* the same, and "equivalence" means
(or
should mean) that two things can be substituted, that they behave the
same way.

A mathematical and CS definition in fact tracks the common English
meanings of these 2 words, and the language concerning Object.equals
that Patricia quoted does say exactly this: equals is an implementation
of equivalence.

My point is that the common English, the mathematical and the CS
definitions of the two terms are pretty much the same. And programming
languages that differentiate between the two also track those
definitions. We see that Java does.

I don't think Java follow those rules.

I assume that you consider equals to be equivalence and
== to be equality.

But it is not so.

Example:

public class ZZ {
public static void main(String[] args) {
int iv = 2;
double xv = 2.0;
System.out.println(iv == xv);
}
}

I do consider == to be equality (identity). Same object for references,
same value for primitives...that's equality.

But 2 and 2.0 are not identity equals.

No, but as I indicate I don't see that we ever compared 2 and 2.0 for
identity in your example. You can't do that with direct use of ==,
because of promotion.

This is one of the C-based hiccups of Java. For primitives of different
types we shouldn't even be asking the question ==?
That promotion is done by ==.

"Done by?" I don't see that. "Done on behalf of", sure. Unless a
bytecode guru tells me otherwise I expect that == just like + is
blissfully unaware that it could ever be asked to work with two
primitives of differing types.

Now, if each binary operator duplicates all the numeric promotion logic
I could see that they are responsible for it.

AHS
 
M

Martin Gregorie

I somehow doubt that you always test and never deduct.
Probably true and the analogy is a bit stretched too, but I do write
tests from the spec (*never* from the code). I like to have some form of
spec, even if the code is for my own use, unless the requirement is
trivially simple. I usually design the test set so it can be used for
regression testing with automated results checking, even if the results
check is merely via 'diff'.

As I said: not a mathematical approach but, I hope, a reasonably
scientific one.
 
B

BGB / cr88192

Martin Gregorie said:
Probably true and the analogy is a bit stretched too, but I do write
tests from the spec (*never* from the code). I like to have some form of
spec, even if the code is for my own use, unless the requirement is
trivially simple. I usually design the test set so it can be used for
regression testing with automated results checking, even if the results
check is merely via 'diff'.

As I said: not a mathematical approach but, I hope, a reasonably
scientific one.

agreed...

yes, one does testing based mostly on the public API's and defined behavior.

however, as I see it, this isn't about either math or proof, rather about
verifying that the thing works and does about what it is said to do.


as I see it, a major part of the programming task is, in effect, defining
and implementing API's.
one decides what the code "should" do, and implements an external interface
to make it reasonably do so.

what happens internally, then, is outside the scope of concern, as the
particular code is, in itself, a black box (the code which uses it should
not know or care how it works apart from its external behavior and
characteristics).

likewise, things are specified in terms of their externalities, and not
their internal structure.


very often, code tends to be large and complicated enough that, to me,
mathematical-style proof seems almost useless here (and even then, what is
to say that the code is itself conforming to the proof and does not contain
many of the other far more common bugs, such as the sort resulting from
occasional typing errors or momentary brain-deadedness?...).

what "proof" can be meaningfully done on code is often instead implemented
within the compilers (such as type-checking, ...).


far more useful then is to test and verify that all works, and if reasonable
(or often even unreasonable) inputs are found which break the code, then one
can look into fixing these as well.
 
B

BGB / cr88192

Arved Sandstrom said:
Both terms actually have clear English meanings - "equality" means (or
should mean) that two things *are* the same, and "equivalence" means (or
should mean) that two things can be substituted, that they behave the same
way.

A mathematical and CS definition in fact tracks the common English
meanings of these 2 words, and the language concerning Object.equals that
Patricia quoted does say exactly this: equals is an implementation of
equivalence.

My point is that the common English, the mathematical and the CS
definitions of the two terms are pretty much the same. And programming
languages that differentiate between the two also track those definitions.
We see that Java does.

Having said all this I did have to do a few minutes of research to remind
myself that the way the words are used in math and in CS are also what
they mean in common speech. And I don't normally walk around thinking that
equals is an implementation of an equivalence relation. :)

I will assert here that even in English their meanings are not sufficiently
solid to make this point.
the words in natural speech tend to float all over the place, and to say
solidly that X means Y is misguided at best.

even "trivial" words, such as "the" or "an" have no clearly defined meaning,
and tend to vary from one context to the next, and depend on the words to
which they apply, ...

"logic" is then almost meaningless on natural speech, and one is probably
far better off with a probablistic interpretation.


"look, hand raised birds" vs "look, hand raised children" (or "look, hand
raised, children", ...).

the first 2 have different meanings even though the structure is about the
same, and the 3rd means something different despite using the same words in
the same order.

birds may be raised by hand, children may raise hands, and children may be
told that the proper way to ask the questions is to have hand raised. (with
awkwardities in interpretations as to confuse even native speakers...).


it is not meaningful to expect much more than this.
 
M

Martin Gregorie

yes, one does testing based mostly on the public API's and defined
behavior.
Quite, which puts many 'designers' and 'design methods' on the spot,
especially use-cases. All too frequently these are all airy-fairy
handwaving stuff that serves as the specification because anything more
rigorous in the way of specifications is entirely absent. I've even seen
cases where, when this was pointed out to the designer, he simply changed
the entire use-case to omit the problem area: if the problem isn't
mentioned in the use-case it doesn't exist. In the case I'm thinking of,
the final use-case's relationship to the client's requirements were
pretty much illusory.

Now write a set of useful regression tests from that type of
specification!
as I see it, a major part of the programming task is, in effect,
defining and implementing API's. one decides what the code "should"
do, and implements an external interface to make it reasonably do so.
I'd move that activity further up the food chain. If API specification is
left to programmers then the designers haven't thought sufficiently about
their job and you're probably on track for major problems and rewrites
during integration testing.
what happens internally, then, is outside the scope of concern, as the
particular code is, in itself, a black box (the code which uses it
should not know or care how it works apart from its external behaviour
and characteristics).
Yes. The designers must specify both the external behaviour and
appearance, i.e. both the API and the actions to be taken for or valid
inputs. The calibre of the programmers determine whether the designer can
leave sensible handling of invalid input to them or if this too must be
specified.
 
B

BGB / cr88192

Martin Gregorie said:
Quite, which puts many 'designers' and 'design methods' on the spot,
especially use-cases. All too frequently these are all airy-fairy
handwaving stuff that serves as the specification because anything more
rigorous in the way of specifications is entirely absent. I've even seen
cases where, when this was pointed out to the designer, he simply changed
the entire use-case to omit the problem area: if the problem isn't
mentioned in the use-case it doesn't exist. In the case I'm thinking of,
the final use-case's relationship to the client's requirements were
pretty much illusory.

Now write a set of useful regression tests from that type of
specification!

yep...

I think an API should handle pretty much all input that "could" be
reasonably generated, even if outside of the expected domain.

granted, edge cases are often a "try to fail gracefully" condition, rather
than something which should be "crash and burn".

I'd move that activity further up the food chain. If API specification is
left to programmers then the designers haven't thought sufficiently about
their job and you're probably on track for major problems and rewrites
during integration testing.

this of course assumes that the designers and the programmers are not the
same people.
the programmers may be left deciding on matters of API as they are the ones'
designing the API's (this being within the programmers' domain rather than
the end-user's, which is where much more "design" attention is often
directed...).

Yes. The designers must specify both the external behaviour and
appearance, i.e. both the API and the actions to be taken for or valid
inputs. The calibre of the programmers determine whether the designer can
leave sensible handling of invalid input to them or if this too must be
specified.

granted (assuming, of course, there are such designers, rather than
expecting all the programmers to be essentially self-directed and work out
the details amongst themselves).

a lot may then depend on who will use the API and for what.
since the main user is often other programmers, one could argue that it them
makes sense that the programmers should also specify matters of the API,
overall project architecture, ...
 
L

Lew

BGB said:
I guess one can clarify what they mean by "math".

Certainly not what you describe so rhetorically and prejudicially in your post.
there is a lot that is arguably math which I have noted is rather useful
(say: vectors, quaternions, matrices, ...).
similarly, nearly all manners of "calculating stuff" and "doing stuff" can
be useful with computers...


what is not so useful though is the sort of ultra-abstracting anti-reality
aspects of math, where one forsakes the thing being described for a big mass
of set notation or abstract logic.

Strip away the pejorative descriptive terms, provide evidence that anything at
all is "forsaken", and talk about things as they really are.

You make a claim that something is "not useful" by mis-characterizing it, and
using unupported claims that something is "forsaken", and depend on the
emotional connotations of "ultra-" and "anti-" and "big mass" to make your
point, thus hiding that your point is not, in fact, valid.

The reality is that there is math, and there is mathematical. Some in this
thread have tried to impose an artificial distinction between "math" and
"science". I argue that there is not so much separation; one can see
mathematics as the science of certain kinds of relationships, perhaps even
harder than "science" since in math one can actually prove things. Likewise,
science is an expansion of mathematics into the "real" world. It is
troublesome at best to draw conclusions about reality by the application of
artificial linguistic conventions.

I would agree that computer programming is not math as such, nor is it
science. It is, however, quite mathematical and scientific as a discipline,
and uses the noetic principles and practices thereof to accomplish its goals.

As to the utility of math, arguing that, say, set theory or predicate calculus
are not useful is just the sort of anti-intellectualism and prejudice that
makes education such a joke, deprives research of funding, and generally
increases the stupidity of the population. Without those two things in
particular, we would not have developed the amazingly powerful database
systems in use today, to pick one example. Those disciplines are very useful,
as anyone not too weak-egoed about their own intellectual capacity would
recognize. It's a matter of understanding that theoretical research is an end
unto itself, and that concomitant "real-world" applications emerge after that
research has borne fruit.
IMO, this side of math is not particularly useful to the greater goods:
"make it work" and "get it done".

You're absolutely right, that is opinion.
I would almost rather be stupid than live in that sort of "reality"...

Tempting, so tempting ...
 
L

Lew

BGB said:
this of course assumes that the designers and the programmers are not the
same people. ....
granted (assuming, of course, there are such designers, rather than
expecting all the programmers to be essentially self-directed and work out
the details amongst themselves).

That is a specious distinction. When the same individual dons the roles of
both designer and implementer, they are still distinct roles and carry the
same responsibilities as when carried out by different people.

This discussion woke me up to a mistake I was risking on my new project, that
of not applying good design and specification first before programming, though
I am in the roles of designer, architect and implementer on this one.

I do not exclude iterative development and convergent specification in this
model, only point out that when assuming the different roles one must still
fully fulfill their obligations.
 
B

BGB / cr88192

Lew said:
That is a specious distinction. When the same individual dons the roles
of both designer and implementer, they are still distinct roles and carry
the same responsibilities as when carried out by different people.

This discussion woke me up to a mistake I was risking on my new project,
that of not applying good design and specification first before
programming, though I am in the roles of designer, architect and
implementer on this one.

I do not exclude iterative development and convergent specification in
this model, only point out that when assuming the different roles one must
still fully fulfill their obligations.

yes, ok...

well, sometimes specs are found and implemented, other times, they are
designed and then implemented, and sometimes they develop naturally and are
codified later.

a lot depends on the particular situation.

 
B

BGB / cr88192

Lew said:
Certainly not what you describe so rhetorically and prejudicially in your
post.

it depends...

some endorse math by despising reality...

Strip away the pejorative descriptive terms, provide evidence that
anything at all is "forsaken", and talk about things as they really are.

You make a claim that something is "not useful" by mis-characterizing it,
and using unupported claims that something is "forsaken", and depend on
the emotional connotations of "ultra-" and "anti-" and "big mass" to make
your point, thus hiding that your point is not, in fact, valid.

<snip>

I think you mis my point...

I am not saying that neither set theory not predicate logic are useful (for
the things they do), rather, that it is not useful to use them and then
disregard the underlying reality of the matter...


a simple example is in talking about vectors:
one can describe (in an introductory context) vectors in terms of their
properties and their operations, and all is well.

or, one can sit around with things like:
<exists> alpha,beta <within> R^n <such-that> (alpha <circle> beta --> V)
<within> E^n, ...

this does not help, as the topic is then obscured, and for no particularly
good reason...


logic and sets can be used where they are appropriate, and IMO, this is not
necessarily in the context of describing other things which can typically be
described much more simply and much more directly within an introductory
context...

for example, if the purpose is that one will learn a topic (such as vector
math) for sake of making use of it (say, for doing something with it), then
it is not as helpful to be faced with lots of set theory, and not actually
calculating anything (and then bombing tests due to in short order having
little idea what is going on anymore...).

after all, wouldn't all the set theory have presumably been in a class about
using set theory?...


what of the stuff a programmer does in a 3D engine?...
it is almost entirely different...

similarly, most of the conventional definitions (like one finds in places
like Wikipedia or Mathworld) are based primarily on algebraic definitions,
not on set-theoretic ones...


or such...
 
M

Martin Gregorie

well, sometimes specs are found and implemented, other times, they are
designed and then implemented, and sometimes they develop naturally and
are codified later.
I'm entirely with Lew here.

Unless the application is really trivial, typically half a day or less to
design, implement and fully test, you'll probably take longer to get a
satisfactory end result by barrelling in and starting to code right away
than if you'd say down and thought the problem out fully before you start
to code. "Thinking the problem out" *may* be purely getting the design
right in your head if its the half day or less sized task but if its any
longer than that, then producing some form of documentation is usually
called for.

Examples:
(1) I designed, coded and tested a mix of awk and shell script
yesterday. Its purpose is to take an easily maintained list of words,
phrases and regexes and construct a SpamAssassin rule from them. I spent
about half the time picking a set of rules apart into lists of elements
plus a few parameters to specify features of the rule as a whole. That
was the design process. The resulting set of files, each containing a
rule's components, when combined with what I'd learnt by disassembling
them was both specification and test data. I even surprised myself by how
fast the code went together. Rigorous testing? Spamassassin took care of
that: if it successfully parsed the rule and produced the same results as
it did when running the original rules then the rule building code is OK
and I have a much easier way of maintaining these rules than I did
yesterday morning.

(2) If the task will take a few days, such as writing a non-trivial Java
library class, say for parsing or writing CSV files, My design document
is often written as an overall description of the classes purpose,
functionality and processing options followed by API definitions and
associated textual descriptions of their intended use. When I'm happy
that the requirement is complete and doable I can turn it into a class
file by making text into comments and APIs into method interfaces, add a
few curly brackets and return statements and have something that is
immediately compilable. Then I can generate javadocs to see if they are
readable and tweak the text to suit. After that I can write a test
harness, test scripts and add code into the skeleton. Just as Lew
probably does, I'll often do these three in parallel but with carefully
compartmentalised thought processes: its *much* better to write the test
script(s) and add the call to the test harness before actually coding the
content of any particular method. Additionally, you can start regression
testing long before the coding is complete.
 
L

Lew

Martin said:
(2) If the task will take a few days, such as writing a non-trivial Java
library class, say for parsing or writing CSV files, My design document
is often written as an overall description of the classes purpose,
functionality and processing options followed by API definitions and
associated textual descriptions of their intended use. When I'm happy
that the requirement is complete and doable I can turn it into a class
file by making text into comments and APIs into method interfaces, add a
few curly brackets and return statements and have something that is
immediately compilable. Then I can generate javadocs to see if they are
readable and tweak the text to suit. After that I can write a test
harness, test scripts and add code into the skeleton. Just as Lew
probably does, I'll often do these three in parallel but with carefully
compartmentalised thought processes: its *much* better to write the test
script(s) and add the call to the test harness before actually coding the
content of any particular method. Additionally, you can start regression
testing long before the coding is complete.

Place a ruler on your two extended index fingers. From in front of you, it
looks like this:

__________
O O

where the little circles represent the view of the tips of your index fingers,
and the line represents the ruler seen edge-on.

Only your two extended index fingers support the ruler.

Now slowly move your two fingers toward each other without otherwise touching
the ruler:

__________
O O
--> <--

As your fingers move together, the ruler will wobble and regain balance
repeatedly until your fingers meet.

Your fingers will meet at the exact center. As they move, the ruler's
friction will catch sometimes on the left index finger, letting the right one
progress, and sometimes on the right index finger, letting the left one move.
It's a dynamic balance that alternates movement until it meets at the
perfect center.

In software development, you go back and forth between the "left index finger"
of planning and the "right index finger" of implementation. If you follow the
correct process, some of one, then some of the other, it will converge on the
exact balance point between the two.

In my new project, I had to spend the first week putting together a sample of
the example of the proposed prototype, since the client has no specification.
This creates a working, deployable framework, upon which I can hang any
reasonable interpretation of the project's goals. There's a working database,
screens can navigate to each other, the program can access the database,
there's a mechanism in place to control the look and feel easily, but we still
don't know exactly what we want to the program to do.

Coming into the second week, I have be careful lest the client expect me to
somehow magically produce exactly the thing they imagine, even though they
have yet actually to imagine it.

That means, as architect, designer, implementer and chief bottle-washer for
this proposed prototype, I must now gently and compassionately guide the
client to reveal their hopes and dreams, and I must be the documenter, too,
writing down and editing their fantasies to realizable specifications.

Oh, yes, editing. But every change, clarification and requirement will be
provably and beyond suspicion the client's idea.
 
T

Tom Anderson

Place a ruler on your two extended index fingers. From in front of you, it
looks like this:

__________
O O

where the little circles represent the view of the tips of your index
fingers, and the line represents the ruler seen edge-on.

Only your two extended index fingers support the ruler.

Now slowly move your two fingers toward each other without otherwise touching
the ruler:

__________
O O
--> <--

As your fingers move together, the ruler will wobble and regain balance
repeatedly until your fingers meet.

Your fingers will meet at the exact center. As they move, the ruler's
friction will catch sometimes on the left index finger, letting the right one
progress, and sometimes on the right index finger, letting the left one move.
It's a dynamic balance that alternates movement until it meets at the perfect
center.

In software development, you go back and forth between the "left index
finger" of planning and the "right index finger" of implementation. If you
follow the correct process, some of one, then some of the other, it will
converge on the exact balance point between the two.

I've only got a tape measure.

tom
 
G

George Neuner

"logic" is then almost meaningless on natural speech, and one is probably
far better off with a probablistic interpretation.

You've just defined the field of "informal logic".

George
 
B

BGB / cr88192

Martin Gregorie said:
I'm entirely with Lew here.

Unless the application is really trivial, typically half a day or less to
design, implement and fully test, you'll probably take longer to get a
satisfactory end result by barrelling in and starting to code right away
than if you'd say down and thought the problem out fully before you start
to code. "Thinking the problem out" *may* be purely getting the design
right in your head if its the half day or less sized task but if its any
longer than that, then producing some form of documentation is usually
called for.

in my case, I may sometimes end up spending maybe a few days or more
considering possible options and possible designs, and then may often write
up an "idea spec" (usually a few pages or more describing the feature I am
considering).

usually, this would be used for starting on the coding, but then maybe
relevant observations are noted while implementing, and the design may be
tweaked some in the process.

another common scenario is where I really don't want to go through this much
effort, and so something "close enough" is found and used as a design
template (I just implement something according to a pre-existing spec or
standard).


othertimes, code is just left to live on over a long period of time, and may
eventually mutate some as time goes on, ...

Examples:
(1) I designed, coded and tested a mix of awk and shell script
yesterday. Its purpose is to take an easily maintained list of words,
phrases and regexes and construct a SpamAssassin rule from them. I spent
about half the time picking a set of rules apart into lists of elements
plus a few parameters to specify features of the rule as a whole. That
was the design process. The resulting set of files, each containing a
rule's components, when combined with what I'd learnt by disassembling
them was both specification and test data. I even surprised myself by how
fast the code went together. Rigorous testing? Spamassassin took care of
that: if it successfully parsed the rule and produced the same results as
it did when running the original rules then the rule building code is OK
and I have a much easier way of maintaining these rules than I did
yesterday morning.

(2) If the task will take a few days, such as writing a non-trivial Java
library class, say for parsing or writing CSV files, My design document
is often written as an overall description of the classes purpose,
functionality and processing options followed by API definitions and
associated textual descriptions of their intended use. When I'm happy
that the requirement is complete and doable I can turn it into a class
file by making text into comments and APIs into method interfaces, add a
few curly brackets and return statements and have something that is
immediately compilable. Then I can generate javadocs to see if they are
readable and tweak the text to suit. After that I can write a test
harness, test scripts and add code into the skeleton. Just as Lew
probably does, I'll often do these three in parallel but with carefully
compartmentalised thought processes: its *much* better to write the test
script(s) and add the call to the test harness before actually coding the
content of any particular method. Additionally, you can start regression
testing long before the coding is complete.

my strategy is vaguely similar, except it usually involves maybe spec'ing
out the interface, and then for the actual implementation going and finding
a lot of pre-existing code which can be used as templates to build the new
machinery (copy/paste/edit magic, ...).

yeah, getting tests working early seems to be a fairly good strategy.

often, if there is no good way to test or use a piece of code, well then
this is a bit of an issue...
 

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,780
Messages
2,569,611
Members
45,268
Latest member
AshliMacin

Latest Threads

Top