I am an amateur programmer, and I feel I am missing something. Whenever I've tried to understand certain aspects of programming, I often feel I am just "missing something." And most instruction doesn't help (usually because of overly clever examples... like: Okay class, today we are talking about classes. So we'll use this class as an example. We'll create a "class" called "class" and since classes have members we'll create a member for each member of the class. Then we'll create a variable in the class called "class" where we'll store how classy everyone in the class is. Now... how many of you wear glasses?) I really just want my programs to DO SOMETHING. And I am trying to develop a sort of automated analog synthesizer that works with files in the .wav format. So my question is... what is WRONG with something like this? #! usr/bin/env ruby require 'wavefile' include Math frames = (ARGV[0].to_f * 44100.0).to_i volume = ARGV[1].to_f freq = 44100.0 / (ARGV[2].to_f) file = ARGV[3] w = WaveFile.new(1, 44100, 16) (0..frames).each do |frame| w.sample_data[frame] = sin(frame * 2.0 * PI / freq) * volume * 32767 end w.save(file)
on 2012-11-19 16:37
on 2012-11-19 17:05
The code looks good, as a one-off quick-n-dirty get it done script If this is going to be used by others, and possibly re-used as part of a larger app than you have to think of how easy is it to integrate, and how easy is it to change? Some things to consider: How is a user to know/learn what options are required/valid when running the command? What if you decide to add a GUI? What if you wanted to process more than 1 file?
on 2012-11-19 17:27
Thanks, Chris! I have spent time thinking about ALL of those things. Your questions hit at the heart of the problem, and they hit me all at once, all the time, and I don't even know where to begin. This is a very simple version of what I am doing. I have much more functionality in other versions. You hit the nail on the head with the first question. I never know when to export details to functions. I never know when to bundle functions into classes. I can't even begin to imagine how I would do things like modules or who knows what. I have a help file that keys off of --help -h -? as an argument. That is usually in there before the requires and includes. if (ARGV[0..3] == "--help") print "bleah... bleah... bleah..." exit 0 end That's for if I want the end product to be CLI and scripty. It would work off of a file of some sort (.yaml) to feed in data. The GUI option is fun, but unnecessary for what I want to do now. I suppose I would try to link it all up with Shoes? The "processing" more than one file question hits the heart of the matter. First of all, this creates a file. The processing of files is a whole separate thing (in my way of viewing this). I want the final thing to be working on dozens, if not hundreds and thousands of objects. And that's where the "object orientation," "classes," "methods" and all that enters in and it's where I get lost. It's all so arbitrary. I can define anything to be anything. And the more I do, the more ideas I get until I end up with a great big jumble that falls off the rails. All of the stuff out there (the help stuff) is operating on presumptions... unstated presumptions about what a User is trying to do. I always get to this point and get lost, hopelessly lost. Thanks for responding.
on 2012-11-19 17:41
Am 19.11.2012 17:05, schrieb Chris Hulan: > > What if you decide to add a GUI? > > What if you wanted to process more than 1 file? and: What if you wanted to add functionality? What if you wanted to parse and validate command line options? What if you wanted to add tests for parts of your code? But: for really simple tasks I would have no problem with a script like yours.
on 2012-11-19 17:49
On Mon, Nov 19, 2012 at 5:27 PM, Ron S. <lists@ruby-forum.com> wrote: > The "processing" more than one file question hits the heart of the > matter. First of all, this creates a file. The processing of files is a > whole separate thing (in my way of viewing this). I want the final thing > to be working on dozens, if not hundreds and thousands of objects. And > that's where the "object orientation," "classes," "methods" and all that > enters in and it's where I get lost. It's all so arbitrary. I can define > anything to be anything. And the more I do, the more ideas I get until I > end up with a great big jumble that falls off the rails. I think you should go step by step, little by little. Adding functionality and looking for opportunities to reuse code. For example, if you want to generate a file, and the process it, you can start by defining a class that represents the file, so that you can create such object and pass it around. Then you start thinking what things can be responsibility of that class, things that you would tell it to do, for example: save yourself in the filesystem. Create a method for that. If you start this way, you will find yourself with little reusable things that you can compose to perform more and more complex logic. For example: class MyWaveFile def initialize frames, frequency, volume, file_name @frames, @frequency, @volume, @file_name = frames, frequency, volume, file_name @w = WaveFile.new(1, 44100, 16) # don't know what these numbers mean generate_samples end def generate_samples (0..@frames).each do |frame| @w.sample_data[frame] = sin(frame * 2.0 * PI / @freq) * @volume * 32767 end def save @w.save @file_name end end Now you can: wave_file = MyWaveFile.new frames, frequency, volume, file wave_file.save Later, for processing, you might have several different processing algorithms (I have absolutely no clue about sound processing). You can create a class for each processing: class XProcessing end clas YProcessing end ... and apply the processings in order or whatever, passing your wave_file around: wave_file = MyWaveFile.new frames, frequency, volume, file XProcessing.new.process wave_file wave_file.save If, for example, you see duplicated code in all processing classes, try to extract it to a common class (for example, a parent class of all processings). This way, reducing duplication, you end up with a design for your system. It's difficult at the beggining, and depending on the domains can be quite complex, but keep working at it and you'll see that it gets easier and easier. Good luck ! Jesus.
on 2012-11-19 19:26
Jesus - You know exactly what I am getting at. Thank you for the reply. I will keep slogging away and hoping it gets easier. I am glad to have confirmation for what I suspected: That it is possible for a program to organically develop out of a linear sort of stack-oriented approach. I still don't see the advantage to bundling methods with objects. I guess I still think Commodore 64 style! I don't see why I shouldn't keep methods and objects separate is what I am saying. Methods as functions and objects as collections of arrays. I am always doing things the hard way, knowing there is an easier way, but not quite knowing what the easier way is. I'll answer a few of your questions, if you're curious... > @w = WaveFile.new(1, 44100, 16) # don't know what these numbers mean 1 - means "mono" or one channel. 44100 - is 44,100 frames per second (that's the rate of a Compact Disc) 16 - is for 16 bit. A .wav file is like a bitmap, it's uncompressed. So they're HUGE. Basically, the file tells a speaker where to be 44,100 times a second to an accuracy of 16 bits. The resting position of the speaker is 0. Fully out is 32768 and fully in is 32767. A speaker is basically an air pump. That's it. Sound is really simple. > Later, for processing, you might have several different processing > algorithms (I have absolutely no clue about sound processing). You can > create a class for each processing: That's where things are slightly difficult. It is hard to distinguish between what is processing, what is filtering and what is generating. It's all arbitrary, actually. The great thing about doing this in software is that it's all just moving numbers around. No wires, no circuit boards, no keys, nothing. It's very pure in a way. So, one is always torn between what makes sense in the abstract, and what is familiar to the end user. Thank you for your attention and code samples, Jesus. I think this will really help me organize my thinking. - Ron
on 2012-11-19 20:03
Am 19.11.2012 19:26, schrieb Ron S.: > Jesus - > > You know exactly what I am getting at. Thank you for the reply. I will > keep slogging away and hoping it gets easier. I am glad to have > confirmation for what I suspected: That it is possible for a program to > organically develop out of a linear sort of stack-oriented approach. I Growing and restructuring / refactoring is the normal way. > still don't see the advantage to bundling methods with objects. I guess > I still think Commodore 64 style! I don't see why I shouldn't keep > methods and objects separate is what I am saying. Methods as functions > and objects as collections of arrays. One advantage: try working with functions that depend on half a dozen of parameters (and need to be called with half a dozen of arguments) and compare with a method that can simply use the instance variables. [...] Tip: for a nicer and more robust way to handle command line options have a look at the OptionParser class.
on 2012-11-19 20:09
On Mon, Nov 19, 2012 at 7:26 PM, Ron S. <lists@ruby-forum.com> wrote: > Jesus - > > You know exactly what I am getting at. Thank you for the reply. I will > keep slogging away and hoping it gets easier. I am glad to have > confirmation for what I suspected: That it is possible for a program to > organically develop out of a linear sort of stack-oriented approach. I > still don't see the advantage to bundling methods with objects. Some interesting concepts about object orientation are among other encapsulation and reusability. If you build an object with a clean interface, the clients of the object can forget about the internal implementation. The advantages of this is that everything from the outside is easier, and you are free to change the implementation without the external code noticing (or failing). When you have these objects with a defined behaviour and a clean interface, they can be reused in scenarios that not even you anticipated when you created them, and this is huge. You should also read about the SOLID design principles and clean code, which can be summarized with: a good design is one that is easy to change. Tomorrow, when you have to change some logic in your code or add some behaviour, you would prefer that everything is in a single place, in the *expected* place. You use a class, extend it or whatever in a simple way and "magically" you have changed your software. All or most of the SOLID principles involve removing duplication: when you have the same code in two different places, the risks are huge. If you need to change that piece of logic, you might forget one of the two (or many) places, leading to bugs. Objects help with this thanks to the encapsulation and reusability they provide. > I guess > I still think Commodore 64 style! I don't see why I shouldn't keep > methods and objects separate is what I am saying. Methods as functions > and objects as collections of arrays. If the functions operate over a set of data, it's better to have them bundled with the data as a unit, it's easier to reason about it, change implementation, extract common behaviour with other parts of the code, etc, etc. > I am always doing things the hard way, knowing there is an easier way, > but not quite knowing what the easier way is. Well, don't despair. These things take experience. It's important to read about this topics, and to see other's code. A book that I liked a lot was Clean Code from Robert C. Martin. > an accuracy of 16 bits. The resting position of the speaker is 0. Fully > out is 32768 and fully in is 32767. A speaker is basically an air pump. > > That's it. Sound is really simple. Yep, sounds simple (pun intended) > familiar to the end user. The idea is that you create object that represents the concepts that are in your domain: a filter chain composed of filters (two classes), a generating algorithm (a factory object), transformations, etc. > Thank you for your attention and code samples, Jesus. I think this will > really help me organize my thinking. Keep at it, and read about object oriented concepts, there are good articles and books out there. Jesus.
on 2012-11-21 09:27
Thank you so much, Jesus! You given me more practical advice AND theory in a few posts than I've gotten from dozens of sites! And now the sites are starting to make sense to boot. You've been a great help. Many blessings on your house!
on 2012-11-21 13:23
unknown wrote in post #1085232: > One advantage: try working with functions that depend on half a dozen > of parameters (and need to be called with half a dozen of arguments) > and compare with a method that can simply use the instance variables. I am already there! It's amazing how quickly the parameters list grows. Then I realize that I could use fewer parameters, but have to repeat code-snippets (let's say you have parameters: x, y, z... but z is (10 * x / y). You could pass z or just pass x and y but then you would have to pepper the method with 10 * x / y all over the place.) What I do is pass as few parameters as possible, and have local variables defined in the method. > Tip: for a nicer and more robust way to handle command line options > have a look at the OptionParser class. That is a built-in? Thank you for replying Unknown!
on 2012-11-21 22:21
Am 21.11.2012 13:23, schrieb Ron S.: >> Tip: for a nicer and more robust way to handle command line options >> have a look at the OptionParser class. > > That is a built-in? Yes, it is, see http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/r... You won't have to install a gem.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.