Do you use JavaScript and still write your CODE in Javascript?
There are 3 answers really..
“yes I code in JavaScript, I’m not aware of CoffeeScript yet..”
…so now you know, go and try next answer
“yes I code in JavaScript, though I am aware of CoffeeScript”
… maybe you “fear of the unknown“? I was for few months and regret now. Do not hesitate and learn CoffeeScript now, try it, spike, really.. use it
… or you think JavaScript is still better…
… do you?.. really? .. but are you sure?…
… good luck! Because it’s only luck that you need now
“no, JavaScript is unmaintainable, I love CoffeeScript”
.. and that’s good…
.. CoffeeScript code is clean and elegant ..
.. you can at last do Object Oriented programming without hacks…
.. your code is readable…
.. and hence prone to less bugs.. or bugs are easier to find..
.. and you can run it in the browser the same way as plain old javascript..
Two independent developers were trying to explain to me why their model is not readable (and maintenable) and doesn’t reflect real domain. Objects were wrongly associated together, and real world classes – were missing and not defined!
The wrong explanation of a dev was:
..because, a user using “admin UI” selects a card text and assigns bunch of NUMBERS (cell ids) it appears on .. No need for “board cell class”
Who cares how an user is using an app.. It should not have any, or minimal impact on how business domain is modelled, even db is designed..
Should it be a browser, a console app, fully dynamic Ajax website or an iPad app.. It’s only how the app looks, and how presents its information about data.
Views change, user preference change. View is a thin layer, only a presenter. Should not drive the design of domain layer.
An app was…
…I was looking at how some game was designed, a board game, and it was missing representation of a BoardCell
In this small OO world:
a game has a board
a board contains many board cells (hexes)
a board cell contains many cards, of which some give special powers
So I was expecting at least this below: (you can copy&run example)..
…But what I found something different
There was NO BOARD CELL REPRESENTED AS A CLASS.
I need real world model, close to business, close to the domain. I want ALL THE REAL CLASSES BE THERE. So I can touch them and work on them.
So, try to cut any class from above code. It will make no sense, as all the objects make sense there. It’s the pure model.
Now, based on this code you CAN start building views. Views may or may not present all the data. May only show final bonus of a player, of a whole board.. who cares.. that is what is view for.. to present,not to define!
Try to imagine your view changes, what then.. would you really want to have model not being a mirror of a real world, and change both: the view, the model … thought so :-) So don’t
As far as I remember I was always very eager on trying to transform natural world – it’s behaviour and information – into a computer. I always wanted to achieve two things:
tell the computer how real world is modelled
tell it in a way that a human can read and understand it
So the effect is
Implementing Business Logic of a domain is the most important and funny part to do
It has many impacts
what is the model?
what are the classes and how they look?
how to persist data to a storage?
how to deliver data to an app user and how to interact with the code
where business logic should be implemented
So I always wanted to be closer to the model part more than to other. It looked easy at first to create a Player class, it’s behaviour and data. And I was implementing high level business operations into the model, not the controllers layer nor the view.
class Player
constructor: (@name, @age) ->
throw_a_dice: () =>
...
pick_a_card: () =>
...
.. but something was missing.. I discovered it just lately thanks to friends and possibly by waking up from a long 4-year hibernation that I was missing a representation of use cases in the system. TA daAA!
It is very important to split your models into at least 2 parts, maybe even 3.
“use cases”: a part where high level use cases, scenarios, algorithms, business logic is implemented (SelectingFirstPlayer, RollingADice, MakingAMove, PlayingMonopolyGame, ..)
“base models”: a part where base classes are implemented with their basic methods attributes that can be reused in use cases (Game, Board, Player, Pawn, Dice, Move, ..)
“storage”: a storage part (maybe, if it’s configuration would be too tight into base model classes, that it needs a separation)
I’m not yet sure what should be the scope of a use case. Using an example of a popular Monopolyboard game, should a use case be “playing monopoly board game”, or only “throwing a dice and making a move”..
But I’m pretty sure all use cases must have a form in the system by being at least a class, that has this single responsibility: telling the whole algorithm of a use case in one place.
But there are 2 very different parts of the code where DRY might and might not be applied: programmer’s code and “high level” domain logic
A) Programmer’s code
I say, it’s a place quite deep in your code, rather related to implementation and less to design. Those are rather controllers and views, and deep parts of model implementation, every helper and utility class. Details far away from actual functional requirements, use cases, business logic.
So there – in programmer’s world – I spend lots of time thinking how not to write the same/similar code twice. Really, I can even spend 10 hours or few days of thinking and writing ZERO code..
.. because I’d rather shoot myself in a foot with a railgun than used dumb-COPY-&-PASTE. We nowadays know it’s PLAIN WRONG, do we..
copy & paste exact parts of code is lazy (“lazy” the wrong way as opposite to being positively lazy as in yagni)
copy & paste similar parts of code might look and is quick solution at first, but it’s not. Someone WILL try to understand and refactor it later and WTF you
it’s about respect to other developers
it’s about write-once, read-100-times. It’s been always this way. So why bothering people after you with your unsolved problems
copy & paste is a smell for immediate action: extract similar code into a method, pass parameters, whatever.. make duplication gone
and obviously if a change must be later done to all duplicates, it must be made in X places instead of ONE
So this is BAD code. Effect of dumb COPY&PASTE&CHANGE-ONE-VAR
B) Domain Code
.. we must make distinction on the “A)” code made for programmers and “B)” code meant to describe our natural world, our domain specific requirements.
This is a “high-level” domain code, possibly close to what customer say and do; to what their use cases describe. So it should really tell what it does.
Such code should not distract reader by forcing the reader to jump & dive around in & out of methods to see how things are implemented. I’d have all code served in front of me instead
In my opinion in domain code it is more important to see the intent of the code than to be pure DRY. I must admit I don’t make some strict rule on that yet. It’s rather my intuition today.
Applying all the fancy programming patters and refactorings just to make code few lines shorter does opposite and makes intent, the flow, the algorithm not clearly visible.
I say there are 2 cases where I’m not always fully DRY
acceptance tests – simulating user interacting directly with application (via browser mouse clicks, keyboard, triggering events, etc)
use cases – the most important domain code, domain algorigthms, business logic
So I would live with such code..
.. and I think I would also live with this one, but maybe bit less comfortable in the long term..
..although at first those 3 cases now look shorter and more readable, but they also PRETEND that they do something by a nice method naming. In fact those methods might do sth completely different. They hide details, but those details ARE IMPORTANT, so should not be hidden
PS. .. methods longer than 10-20 lines might be OK for domain code, but they’re rather on the longer side
Am I a GOOD programmer when I write A LOT of CODE?No! I’m certainly not.
Tonight I found myself again very happy because I removed a lot of lines from my code. There was really a lot of redundancy in the code. And when the moment comes that I just CTRL+Y (IDEA‘s “delete line”) then I’m happy.
I’m really, really happy.
The first such moment in life was then when Andrew and I sat down in front of the hopeless app and thrown away a lot of generic code which just existed there. That was a custom database layer, and we changed it to another one, based on Prevayler. And during one afternoon we deleted a lot of someone’s else work – I remember that was more than 120 classes. Trash.
Tonight I did once more big refactoring. I didn’t deleted so many files this time, but removed a lot of redundancy in the code. And that’s really good.
I was always wondering what is this hype about testing aspects or aspect oriented systems about? Or maybe there isn’t any..
Here you’ll find concrete examples of my JUnit tests of my Ilybra application and PAT framework.Test type no. 1: test of PAT aspect itselfWhen applying PAT to any software I have to test if PAT works correctly. To do that I need to write tests of the aspect. And PAT is a persistence aspect, so what I need to test is if the data is really stored on the disk after some persistent operation. And it means I must check if the database I use (Prevayler) behaves correctly: stores data changes on the file system, when recovering does it read files in correct order and does it restore the data after failure.
And persistent operation is PAT’s transaction invoked on business object (BO).So here is sample code, of how do I test my PAT aspect:
Test type no. 2 – testing Ilybra‘s business methods
It is trivial to test Ilybra application and its business methods. Due to the fact, any business class created with PAT is plain Java class without any dependency on external resources, I can just invoke the object’s methods without any “mocks fun”.
Below you’ll find one of my JUnit tests for testing user story: “Lend book to a reader”. The expected behaviour after invoking method lendBook is the copy must be located within reader’s current list of lend copies and the copy itself has to have a reference to the reader.
Code of the test case – again – without any cheating it is one of my original test cases. There is no external configuration to the test case. None of aspects is applied here, no custom advice here except PAT‘s annotations on transaction methods (lendCopy).
Note: I test core functionality here. And this is the most unique. PAT lets you create such simple test cases for an application
With those two examples above I think I’ve just exhausted my “AOP & testing” topic.
Things like aspect orientation and separating of concerns are really trivial for me. I mean I develop software and I write an aspect when I see there is a need for that. I use it pragmatically, and the number of my custom aspects is increasing every few days last weeks.
But as we see not for all people that’s the case. I will try to tell how it looks from my position. And I must start from the beginning: the client of application.
To familiarize with a business domain is the first and most important thing.
It is your client who drives the application, so the first thing is to dive into the client’s business and to look what’s there. But, just don’t spend too much time there. Practical way (agile?) says: it would be nice for you client to see the first version of application very soon. So I implement the domain – simple Java classes and methods and plain JUnit tests.
And in the first week of development I’m only worried about implementing first business task of my client. I don’t think about persistence (you use Prevayler for prototyping, don’t you?) or any other system “services” – it is not important right now. Client is important, and time is important.
And it happened, when I worked this way, I’ve started to see things differently. Some years ago I tried to design a whole system at once. It is impractical. Requirements will change, client will wait. It just doesn’t work.
So I try to think only about functionality of the core system and nothing more. The rest of the system are system’s services – non functional requirements like authorization or tracing support – they will come at a later stage, when need arises. Then I will take care of those services – by implementing an aspect of course.
Like Andrzej Krzywda assumes: one can practically add any orthogonal functionality to an application at any given moment of time. And that is true. It worked out for me with authorization and the rest of my aspects.
Persistence strategy as I believe was the strongest point in my developer’s history. When you choose simple persistence, then you don’t have problems others do. This is the right direction: to get rid of problems. And “simple” doesn’t mean primitive. It is the art to make complex things look simple. I found when code looks clean, many things become brighter. And it is persistence that makes your code look uglier at most of the time. But I don’t want to talk about this topic right now – have a look on PAT, and you’ll see my way..
Need the examples of the code I create? PAT provides a Forum demo ready to extends to you super-duper, enterprise solution…
Great people like Ron Bodkin talk about the pragmatic way of doing software. So why don’t me, when I have this experience and I’m just hot to tell the world to look at the other side of this matrix..
Ilybra is a battlefield when it comes to aspects. Ther first aspect was tracing of course, the rest you see below, and today I got an idea on another one to my collection. Some people will even call my aspects “enterprise”! As you wish :) I don’t know the meaning of that word. I just develop an application for my library ladies.. ;)
Like it was said in the Ilybra: introduction, Ilybra utilizes some custom made aspects. They are:
authorization and authentification
optimization of access to some sorted data collection
tracing execution of Struts actions
dirty problem with null parameters
reseting Struts’ forms
measure the action invocation time
…and will be more, when need arises
Oh my, and I’ve just forgotten about the most important one: persistence – see how invisible it is my way :)
Many! lines of code has just disappeared from my classes. This is the core value of aspects. My code is cleaner.I will demonstrate you my Struts’ action code with: tracing, authorization, persistence, returning empty String instead of null, resetting forms and measuring time of invocation of action – ufff, a lot :) :
My full, original code (without any cheating or removal lines of code for the sake of the presentation of the example) of user story: Prolong copy on reader’s account: enter new date, accept choice, view confirmation. Note: of course, there exists one, additional, global ilybra-aop.xml AOP configuration file for defining pointcuts.
Interested in library.prolongCopy(..) or library.getCopyById(..)??
..Authorization and authentification are common in applications. And so it is with Ilybra. It is 2 years now, I started to work on the application, but only from the last week the system must authorize a reader to access his account.
What is important here I’ve managed to add this concern – orthogonal concern – after the application was finished. I’ve done it with one simple aspect listening on all Struts actions, which checks if there is a User object in a session. Implementation is trivial. And aspect oriented way turned out to work. (This implementation could also be done using “servlet’s filters”, as they also crosscut expected behaviour in this particular example).
Code of the aspect on the plate:
I hope those examplets will clear your mind for a moment :)
Finally I’ll start column on Ilybra application. A lending library system for lending books to readers, managing books and copies, printing reports, keeping history of reader’s lendings and of course searching capabilities by different search categories. All based on PAT framework.
Numbers of systems’ data for your information (as of 1997 – May, 2005, data has been imported from former system):
books number is 9,530
copies: 12,500
readers: 1,750
authors of books: 10,200
history of lendings from year 1997: 10,400 records
… and 4 librarians
..and all this fits in my PC’s RAM (the small 1G). Surprising, isn’t it? ;) Note: system is ready for numbers 10 times bigger and was tested with that amount of data. And searching speed wihout optimisation rocks! You do heavy loading of your system before implementing, don’t you?This is “an enterprise-class system”.
Ilybra is entirely based on POJO model – and this is most important and unique. What’s unique that persistence is invisible. There are no mappings, no tables. The only requirement to the POJO model is to annotate transaction-methods and business objects (BO) – one line of code:
Ilybra uses Jakarta Struts for presentation layer, Log4J for logging, works on Tomcat or JBoss AS. Tests are made with plain JUnit. Regression tests and load testing are done by Jakarta JMeter. Ant helps with one-click distribution creation, iText generates PDF documents on the fly, CSS supports printing.
Custom aspects take care of:
authorization and authentification
optimization of access to some sorted data collection
tracing execution of Struts actions
dirty problem with null parameters
reseting Struts’ forms
measure the action invocation time
Oh my, and I’ve just forgotten about the most important one: persistence – see how invisible it is my way :)
And this is reality – Ilybra exists and has a good time working our Intranet in a testing and bug discovering phase (as of 30 May, 2005). As soon it will be available on-line, I’ll tell..Why aspect oriented way?
This is pragmatic way, more. I do nothing for show. I do it because simpler software means you have to look for concerns, separate them and merge together (refactor?). And you have to do it all the time – well I do it this way.
Aspects are the most suitable way for developing this kind of applications nowadays.
And application is a set of crosscutting concerns, right? :)