
Just open sourced my 10k LOC PHP & MySQL invoicing app - renownedmedia
https://github.com/tlhunter/neoinvoice
======
swang
What exactly did you dislike about CodeIgniter? For me CodeIgniter is probably
what I'd use if I had to go back to making PHP applications so I'd like to
hear any reasons you had against it.

~~~
renownedmedia
CI was built in the PHP4 days, and for that reason it has a lot of cruft left
over. For example, there is no autoloader. Also, classes are loaded as
singletons, and are assigned to properties of the controller, which I put into
the 'magic' category, and isn't compatible with IDE autocomplete features (I'm
a VIM user, but it makes things easier for a lot of developers).

//CI Class Load Example:

$this->load->library('example'); $this->example->something();

//Raw PHP Class Load Example:

$this->example = new Example(); $this->example->something();

As you can see, the latter is a little more obvious about what is going on.

~~~
iends
What PHP framework would you use if you had to today? Kohana? Yii? Something
else?

~~~
chrismsnz
I'm not the OP but almost any PHP project these days has me reaching for
Symfony 2[0] or her little brother Silex[1] paired with Doctrine 2[2].

[0]. <http://symfony.com/> [1]. <http://silex.sensiolabs.org/> [2].
<http://www.doctrine-project.org/>

~~~
renownedmedia
Symfony is nice, Zend 2 is going to fix everything from ZF1 and is worth
keeping an eye on as well.

I've dabbled in Doctrine before, but the memory usage looked a little too high
for the convenience it offered.

~~~
lftl
Out of curiosity what are you doing in PHP where memory usage is an issue?
PHP's standard life cycle, while having numerous disadvantages, avoids a lot
of problems with memory usage.

It's a rather different beat, but you might checkout Propel
(<http://propelorm.org>) for a different take on a PHP ORM. It has a static
build phase unlike Doctrine which turns some people off, but if you can get
past that it's a rather nice ORM.

~~~
chrismsnz
If you think that your project is going to grow into a substantial code base,
I would NOT recommend Propel.

A lot about their active record implementation violates POLA with various
gotchas and code generation gets tedious and unwieldy with models that contain
many fields or relations.

~~~
lftl
Interesting, I've been using Propel for so long I've probably internalized all
the gotchas. What in particular caught you off guard?

~~~
chrismsnz
My favourite is probably:

Say you want to add a product to an existing order in the database...

$orderProduct = new OrderProduct(); $order = OrderPeer::retrieveByPK(1);

$order->addOrderProduct($orderProduct);

Now, if ANYWHERE after this point in the code, something calls
$order->getOrderProducts() before you call $order->save() (like a validation
routine or something) you will lose that new OrderProduct and it will not be
persisted.

It's bit me more than once, especially as you start to spread code around that
depends on traversing the relationships - can be a very tricky bug to spot.

~~~
lftl
Propel's implementation of related collections definitely could use some
improvement. In your example, you wouldn't necessarily lose your new object,
it just wouldn't be persisted through a call to the parent order to save. My
general habit is to call save on a newly created object directly, and as soon
as possible. Regardless, I definitely agree this is one (and there are some
other points) where Propel definitely has rough edges.

------
BjornW
Thanks for sharing! I wished more people would share code of projects they are
no longer interested in. The educational value ('how did he/she built this')
is worth a lot, regardless of the 'quality' of the code. Thank you!

~~~
renownedmedia
I have the exact same sentiment; I pretty much open source all of my old
projects for people to learn from (I taught a small meetup for a while, it was
useful to explain both the good and the bad). I add DEFUNCT to the description
if they are really old or have a lot of bad practices. Here's the rest:
<https://github.com/tlhunter>

~~~
TazeTSchnitzel
That's an excellent idea. I should go add that to some of my horrible,
horrible C code, lest someone think that 10 levels of indentation, not using
c-style strings, non-portability, architecture assumptions, lack of error
checking, and blocking sockets is a good idea...

Or that macros without bounds checking that cause segfaults unless debugging
is a good idea...

What was I thinking?

~~~
renownedmedia
Heh, I'm not well versed in C, but it sounds scary.

You can also throw comments in the code where the bad stuff is so that it has
more visibility, as well as suggestions for how to better solve the problem.
Sometimes people learn best from bad code!

~~~
TazeTSchnitzel
Good idea.

It should sound scary, it's the worst code I've ever written.

I wrote it 2 years ago with the idea "working first, correct later", but I
haven't finished the latter yet...

------
jumby
I remember writing invoicing systems like this. Then I realized I probably
shouldn't reinvent the wheel or break GAAP. :/

~~~
renownedmedia
Yeah, there is a ton of competition. I started building this without having
done proper research.

~~~
jumby
See, the thing is: creating an invoice is an 'accounting' event that needs to
be thought out a bit. Like a double entry general ledger, receiving payments,
proper audit trails, the inability to modify an invoice after 'posting' it,
batches, periods, and other goodness.

Otherwise, you get this ugly term: embezzlement.

But kudos for opensourcing it and standing up to criticism from hecklers like
me.

~~~
ericingram
I disagree, as a business should think first in the broad context of
product/market fit, which is a very dynamic issue, and not all markets need
the kind of depth in an accounting product you describe.

~~~
einhverfr
The only case where that my be true is the case where you have a sole
proprietor where the owner is the only one who touches the books. As soon as
you have a bookkeeper who is not the owner, or multiple owners you do need
that kind of depth.

~~~
ericingram
I'd bet the OP intended it for use by sole proprietors like himself, and that
he never aimed to build a product for bookkeepers. There's plenty of a market
for invoicing software that targets sole proprietors.

A product with as much depth would likely appeal to accountants or those that
assist them directly.

------
justinkelly
great to see this open sourced - sorry to hear you closed neoinvoice though

the web based invoicing market is extremely crowded and very hard to complete
against the likes of freshbooks.com

though i went the opposite route to you and its working $ for me

created the open source app <http://simpleinvoices.org> first, got large user
based, then offered premium hosting at <http://smarterinvoices.com>

~~~
einhverfr
I think at one point we had some LedgerSMB users using SimpleInvoices and
importing data into LedgerSMB.

I think the difficulty with invoicing is that it is so heavily tied to
everything else one might try to do in a business, from tracking inventory to
CRM to financial accounting. This doesn't mean that one can't do this, but the
interconnections seem to be key.

~~~
justinkelly
re ledgdersmb \- yep - the ledgersmb crew did some great work to the
SimpleInvoices code to make it work for them

re interconnections

* depending on the target market

* the people who need integration already do some form of accounting already - and a 'full stack' accounting solution like <http://xero.com> is more appropriate for this market

* simpleinvoices market is people with no accounting system or desire for debit/credit stuff so we have make no attempts to make quickbooks, etc. integration work

------
mmmooo
Just as a quick look, this thing is riddled w/ potential sql injections..a
number of unchecked/unescaped uri controlled variables. In some cases there's
validation of numerics w/ +=0, but in many cases (e.g. $sort_col) there's
none.

~~~
jumby
you mean you shouldn't trust user input?

~~~
renownedmedia
The arguments to controller methods (in CI) are passed through some regular
expressions. CI goes as far as to destroy all GET variables (which I highly
disagree with).

~~~
mmmooo
GET's are all removed (by default), but for uri segments you'll just get some
character filters, and some anti-xss attempts (assuming you have that on).
Nothing anywhere near sufficient to prevent sql injection. Again, didn't dig
too deep, but I don't see any validation that would prevent me from doing some
level of at least blindsql..

~~~
rokhayakebe
I think CI rejects anything in the URI which isn't alpha-numeric. Would that
solve the issue?

~~~
mmmooo
Kind of, anything in permited_uri_chars is allowed. This includes spaces,
slashes, commas, %, and a handful of others by default. As I said only skimmed
quickly so maybe I'm missing it. Will take a deeper look in a bit once not on
mobile.

------
obituary_latte
Is that mochaUI? Looks like it.

Tried using it recently and it actually was quite nice despite the lack of
docs and other various hiccups.

At any rate, thanks for putting it out.

~~~
renownedmedia
Yeah, it's MochaUI. About two years ago, the project was mostly un-maintained,
I haven't looked at it recently though.

------
krob
Okay, so coming from a user of CI 2.0 mind you and using integrated smarty
templates with it, I would have to say after using even a micro-framework say
silex, I could build a much better enterprise application with modern php5.3/5
features than i can with CI. The major problem is it feels really dirty to
include/require statements with CI. Also to build re-usable code within the
confines of their existing library system you have to build all your
constructors with a single $param argument. The models are junk since they are
really just a place to store organized function calls. Their database
abstraction is an abomination. Generally the only thing good about CI is that
you can break up your source into a marginally logical fashion which can it
improves maintainability.

Now as for this application being written in Code Igniter? I don't really see
it as a problem since it means it will be easier for lesser experienced dev to
pick up and run with the ball. In time they will learn it's major deficiencies
and they will move on. But i think there is room for improvement, in fact I
think this would be a great project to port to another maybe more robust
framework and is a good project for learning new framework translations.

I will say however that the author wanting to rewrite a product like this in
nodejs is really only going to make something like this more inherently
difficult to maintain since javascript code tends to get more complicated than
your typical java / php / python app as it grows. Granted you do have js at
your finger tips it is still largely un-tested on massive scale for large
application development. It however has shown great promise for handling
extreme traffic in terms of concurrency, but it handles it mostly by using
async libraries which pile everything into queues of some sort some where. So
your code is littered with async callbacks everywhere. Anyways.. Not only
that, but the biggest problem of all is the inability to intelligently step
through your code with some kind of IDE beyond using a browser-base debuger
such as webkit inspector or the online IDE cloud 9.

I don't hate nodejs. I just think people are jumping on the band wagon way too
quickly for server-side hosting. For websockets it's a great solution, I just
don't like seeing it as "the only solution" for some peoples projects. I'd
rather see a more hybrid approach.

------
jbigelow76
I'm curious, I remember a posting a while back that you were trying to sell
this app through Flippa? Any details of that experience you would mind sharing
(nothing but tire kickers, not the right market, buyer fall thru, etc...)?

~~~
renownedmedia
Long story short, not a single bid. A lot of people would ask some questions,
but would seem to ignore the info on the page. I didn't bother paying extra to
have them tweet the site on their twitter, since they tweet seemingly hundreds
of times a day and nobody seems to listen.

I'm used to selling items on the Envato marketplace, which provides all of the
'advertising' for me. But it seems that with Flippa, there is so much noise
and one has to do their own finding of buyers.

------
danso
I didn't look through the PHP or MySQL code but the front-end has a clean look
(from the video), which is more than is expected from most people who take it
upon themselves to develop an invoicing system

~~~
renownedmedia
Thanks! The public facing layout went through three major revisions and the
final one is based on 960.gs. The layout of the app is governed by MochaUI,
but it is a custom theme.

------
manelvf
How many users did you have?

~~~
renownedmedia
There was only about 120 users at its peak. I hesitated, was never ready to
make it a real money-making business, and therefor didn't really advertise it.

~~~
Alan01252
I've a few questions if you have the time.

Did you never charge? Or were you charging? What were the reasons it was / you
were not ready to make it a money making business? Any mistakes or lessons
learned while building/running the software? Where did the 120 users come
from?

As someone who is looking to create their own product soon I'd be really
grateful for any response you can give.

Thanks

Alan

~~~
renownedmedia
For a few months I had the ability for users to sign up for a paid account,
but I never pushed it. After that, I just disabled the feature altogether.

The most advertising I did do was a 125x125 ad on a website used by web
developers (DavidWalsh.name) for one month. I didn't get a single user through
that ad though.

The biggest lesson learned is that an app like this really needs someone who
is good at marketing. I'm just a programmer, but if I had found a marketer and
pursued the development of the app, I'm pretty sure it could have been
successful.

Another take away is to research competitors. I never looked them up since I
actually built this mostly for myself at first, and just kept adding new
features as it got bigger. It turned out the market was very crowded (This
page has a list of 17 competitors: [http://thomashunter.name/blog/shutting-
down-and-open-sourcin...](http://thomashunter.name/blog/shutting-down-and-
open-sourcing-neoinvoice/)).

Also, "piss or get off the pot". I spent a lot of time developing this but I
didn't devote enough of my time to it for it to be successful.

~~~
Alan01252
Thank you very much for taking the time to reply!

Also I know you're getting a lot of stick in this thread for the code which I
feel is unjustified, I just want to say I commend you for open sourcing it.

~~~
renownedmedia
Thanks for the encouragement! I get flack from everything I open, must be a
sign.

~~~
scoot
It's a sign that people are interested in,and paying attention to your code.
Take it as a compliment!

------
PleaseBeSerious
What would you do different based on what you know now?

~~~
renownedmedia
While I was at a startup recently, I did all of my frontend development in
Backbone.js, this app would do a lot better in that framework.

Also, the CI framework isn't all that great, I would have certainly used a
different framework. Perhaps even Node.js (which is what I'm doing a lot of my
development in nowadays).

I also would have looked for a marketer and devoted more time to the project.
The market for this kind of product is very crowded, but there is a lot of
room for innovation.

~~~
bdunn
I don't think anyone's ever subscribed to a SaaS product because it used X
technology over Y. I also think you're way too focused on the tech and the
list of features, instead of selling a solution.

You can say all you want about invoicing being an over saturated market, but I
launched a very successful _project management_ product a few months ago.
Focus on doing a few things very well, and you can do well in just about any
"saturated" B2B space.

~~~
shawn_smith
Spot on!

------
pdufour
This looks like you put a lot of work into this. Thanks for open sourcing it.

------
markhuus
I can't believe you hardcoded this for MySQL instead of using PHP's excellent
and versatile PDOs, and I can't believe the 10k line count. Gosh. Is "de-
engineering" a suitable term here? Thumbs up for open sourcing your work,
though.

~~~
markhuus
No I'm serious here, renownedmedia. Don't disregard my rant with a silly
downvote, but do instead indulge yourself in the PDO methods instead of
painting yourself and your projects into corners:
<http://php.net/manual/en/book.pdo.php>

~~~
rpeden
What makes you think he was the one who downvoted you? You could easily have
asked him about his technical decisions without being a jerk.

Besides, this was a personal project, probably created without the intention
of eventually open sourcing it. If he only ever intended to use MySQL, and
portability across RDBMS systems wasn't a goal, then it's fine as it is.

~~~
renownedmedia
You hit the nail on the head. I never knew I would open source this, I didn't
even plan on it getting as feature-rich as it had become.

