You can use the BNDDIR keyword in the Header specification section of your program and use the CRTBNDRPG command to compile. Otherwise, you are required to use a two-step compile in order to bind the service program to your program object.
The question implies that one or the other is to be used, and that isn’t quite correct. If you use binding directories, you should probably still use service programs.
The question might be better as “When I use service programs and modules, should I use binding directories to locate them?”
A binding directory is little more than a list of objects. The objects are identified by their names, libraries and types. The types can be *SRVPGM and *MODULE. (That’s the basic level. More detail can be used.)
For basic usage, that’s about all there is to it. Add entries to a binding directory with the ADDBNDDIRE (Add Binding Directory Entry) command. Then when you create a program, you don’t list the modules and service programs on the CRTPGM command. Instead, you just name the binding directory. The compiler will find the names in the directory and then be able to grab the objects.
You might create a personal binding directory for yourself. You’d add entries to it that named objects in your own development libraries instead of production libraries. Those might all have full debug included or might even have calls to special logging modules that aren’t used in production. When you create a program with your binding directory, it could have all the extra added stuff that you need for testing. You could list every module and service program in one binding directory — if your program only uses one or a few of the objects, it doesn’t matter.
When you wanted a production version of the program, you would replace the name of your binding directory with one that referenced objects with all debug removed and with no extra calls to developer routines. That would create a version of the program that only referenced production-level service programs and modules.
Essentially, just by changing the CRTPGM BNDDIR() parameter, you would create a very different version of the program.
Using a binding directory also allows you to hide some of your service program exports.
You might have a *SRVPGM with three modules — ModA, ModB and ModC. ModC has an exported procedure — ProcC — that is intended only for the use of other modules in the same *SRVPGM and not for public users of the *SRVPGM. ProcC must be set to EXPORT in order for procs in ModA and ModB to see it. But you need a way to limit the export just inside the *SRVPGM itself.
You do that be leaving ProcC off of the list of EXPORTs in the STRPGMEXP entry in the binding directory. The binding directory entry is then what you make available as the public interface to your service program.
You can create one binding directory for your system. You can create a binding directory for each application. You can create multiple binding directories for each application, if different directories serve different purposes. You can even create a binding directory for each program just so you don’t have to remember which modules and service programs to include the next time you compile it. (Maybe even name the binding directory the same as the program.)
Nobody can really tell you what the advantages are. The advantages are always only those characteristics that you use. Next time you create a program that references a bunch of modules and/or service programs, simply create the directory, populate it with entries and see how it affects program creation. It will either work well for you or it won’t.