Page 1 of 1

OOP design question

Posted: Thu Jun 21, 2012 6:27 pm
by The Phoenix
I am working on revamping and recoding a web-based (PHP/MySQL driven) game. In the game, we output text as a variable string.

As an example, you might want to output to the user the phrase "Click here to return to the main menu", so we have a language variable file which has:

Code: Select all

$l_return_main = "Click here to return to the main menu";
Then when we need to output it, we do:

Code: Select all

echo $l_return_main;
This "worked" for a while. But we've gotten up to around 1400 variables now, and its starting to have some overhead. A page with just 20 strings of text suddenly has 1400 variables(!)

We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?

Any discussion would be *deeply* appreciated.

Re: OOP design question

Posted: Thu Jun 21, 2012 6:32 pm
by Benjamin
Well I think any way you look at it the complexity increases exponentially.

That being the case it would be good to store strings in the database with corresponding tokens.

The content should have tokens and be *compiled* if you will into various language templates. In other words, cache a token free version for each language.

This would reduce overhead to virtually nothing.

Off the top of my head I suppose you could have tables for languages, tokens, and token values. Token values would store the token_id, language_id and token_value.

Re: OOP design question

Posted: Thu Jun 21, 2012 10:17 pm
by Christopher
The Phoenix wrote:I am working on revamping and recoding a web-based (PHP/MySQL driven) game. In the game, we output text as a variable string.

As an example, you might want to output to the user the phrase "Click here to return to the main menu", so we have a language variable file which has:

Code: Select all

$l_return_main = "Click here to return to the main menu";
Then when we need to output it, we do:

Code: Select all

echo $l_return_main;
You might want to look at the I18N solutions from various frameworks and apps to get a survey of your options.
The Phoenix wrote:This "worked" for a while. But we've gotten up to around 1400 variables now, and its starting to have some overhead. A page with just 20 strings of text suddenly has 1400 variables(!)
What does "some overhead" mean? Do you have an actual performance problem directly attributable to this? Perhaps using APC, if you don't already, might be a better solution that recoding?
The Phoenix wrote:We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?
Not sure what "languages need to be an object" means. Obviously you want to abstract the language part so that you don't have code dealing with that spread throughout the game. There are a number of solutions to the problem of providing multi-language support -- each with different trade-offs.

Re: OOP design question

Posted: Fri Jun 22, 2012 2:00 am
by VladSun

Re: OOP design question

Posted: Fri Jun 22, 2012 10:09 am
by The Phoenix
Benjamin wrote:Well I think any way you look at it the complexity increases exponentially.

That being the case it would be good to store strings in the database with corresponding tokens.
We have been discussing "tagging" (adding tokens for variables), because some phrases are in fact used in multiple files. However, I think it might be 'cleaner' if we just avoid tags entirely, and simply do a direct call for the variable name itself ($l_return_main in the example). As an SQL stored item, it would be a table with just name/value. Then on pages that use the same tag/token, it just uses the same name.

What I'm trying to get at is whether the interface for accessing the language should be in the form of a variable, a function, or a class? My suspicion is that English is an extension of a Language object, and that I should be providing the interface that way. I'm just looking to others with more OOP experience to offer advice on whether I'm over-reaching a bit. :)

Re: OOP design question

Posted: Fri Jun 22, 2012 10:34 am
by The Phoenix
Christopher wrote:What does "some overhead" mean? Do you have an actual performance problem directly attributable to this? Perhaps using APC, if you don't already, might be a better solution that recoding?
Fair question. We have bumped into pages where we are running out of memory, as a combination of many things on the page. The languages just seemed an easy target that could improve things on every page. Most impact for the least work kind of issue.

APC is definitely an improvement, and we already encourage its use by admins. Unfortunately, some don't have that choice, and we work to optimize the game to work even without it.

As to avoiding recoding, that isn't an option. It is incredibly outdated code (we've uncovered hacks that fix PHP issues from before 4.2, that are no longer valid, for example), and that still rely on a register_globals style auto-import. We want to improve the game to add features, but to do so, we simply have to recode large portions of it to get beyond the design restrictions of the past.

Since we're already recoding, I figured it was time to rethink key design decisions (like the language design).
Christopher wrote:
The Phoenix wrote:We're pondering storing it in a database, but during that process, it occurs to me that maybe languages need to be an object. A language object, and then english would extend that. I think the language object would only have a getter and a setter (?)

Am I on the right track here, in terms of design, or am I just seeing an object because I'm tired of staring at 30k lines of procedural-only code?
Not sure what "languages need to be an object" means. Obviously you want to abstract the language part so that you don't have code dealing with that spread throughout the game. There are a number of solutions to the problem of providing multi-language support -- each with different trade-offs.
Today, the "interface" for a programmer on the game wanting to get output that is translated to match the users desire is a variable. (That the variable is actually in the global scope is just insult to injury). I'm trying to determine if that is a bad design choice, and if instead the interface should actually be an object called "language", with a property of each language variable.

The entire game already uses this "import all language variables, declare a global variable, and echo it" coding throughout the game, so there isn't really a way to avoid code spread throughout the game. I'm just trying to develop a solid alternative that doesn't require 1400 global variables for a page that will only use 5.

I could do that with just a simple function that does a look-up for a variable name in a db table, or I could make it an object. I'm hoping for advice on which is a good choice (or if there is another choice I'm not thinking of).

Re: OOP design question

Posted: Fri Jun 22, 2012 11:52 am
by Benjamin
The Phoenix wrote:What I'm trying to get at is whether the interface for accessing the language should be in the form of a variable, a function, or a class? My suspicion is that English is an extension of a Language object, and that I should be providing the interface that way. I'm just looking to others with more OOP experience to offer advice on whether I'm over-reaching a bit. :)
Well I think the better question here is what would you rather use, RAM, CPU or DISK IO? You can make the code feel pretty regardless.

Anyway, to answer your question, it would have to be an indexed array to get decent performance. You can wrap it in a class or just put it in an include file. No reason to add complexity.

Re: OOP design question

Posted: Fri Jun 22, 2012 12:03 pm
by Benjamin
Honestly I like my idea to compile versions of each file into each language.

For example this:

Code: Select all

<?php
echo "Hello {#WORLD}";
?>
<h1>{#MAIN_HEADING_HELLO_PAGE}</h1>
Would become this for the english version:

Code: Select all

<?php
echo "Hello World";
?>
<h1>This is an example</h1>
Then your template loader can just load the corresponding file and all the code remains intact. If you modify any code just recompile all the language files.

Re: OOP design question

Posted: Fri Jun 22, 2012 3:53 pm
by Christopher
The Phoenix wrote:Since we're already recoding, I figured it was time to rethink key design decisions (like the language design).

Today, the "interface" for a programmer on the game wanting to get output that is translated to match the users desire is a variable. (That the variable is actually in the global scope is just insult to injury). I'm trying to determine if that is a bad design choice, and if instead the interface should actually be an object called "language", with a property of each language variable.
I might refactor it in two steps. First I would convert all the uses of "echo $l_return_main;" to some interface like "echo language('l_return_main');" or "echo $language->get('l_return_main');". That gets you to a place where you can actually refactor, because the program no longer cares what is going on inside that function -- only that it gets a string back.

The first refactor is essentially a find and replace that you could roll-out one part of the code at a time. Initially it might just use the global strings like:

Code: Select all

class Language
{
    public function get($text)
    {
         return $GLOBALS[$id];
      }
}
Admittedly that looks silly, but it gets you from A to B. Once you get the entire app using "echo $language->get('l_return_main');" then you can do whatever you want inside the class.
The Phoenix wrote:The entire game already uses this "import all language variables, declare a global variable, and echo it" coding throughout the game, so there isn't really a way to avoid code spread throughout the game. I'm just trying to develop a solid alternative that doesn't require 1400 global variables for a page that will only use 5.

I could do that with just a simple function that does a look-up for a variable name in a db table, or I could make it an object. I'm hoping for advice on which is a good choice (or if there is another choice I'm not thinking of).
Though I don't know much about this app, but I would go with an object from what what little I know. The reason is that I would rather make the language selection in the bootstrap and create an appropriate object than have hard coded calls to a function all over the code. The function would invariably need globals inside so it could be reconfigured.

An object injected into where needed would be more flexible for me because it could not only be loaded based on the language, but you could support multiple datasources easily (e.g. MySQL, SQLite, Memcached). Sure you could do that inside a function, but it seems like it would quickly become a mess.

Re: OOP design question

Posted: Fri Jun 22, 2012 4:11 pm
by The Phoenix
Great replies everyone, exactly what I was looking for. Thanks!